Skip to content

Commit

Permalink
Merge pull request #234 from advancedtelematic/feat/return-repoid-alo…
Browse files Browse the repository at this point in the history
…ng-with-root.json

Return the repoId along with the root.json
  • Loading branch information
houcros authored Jul 15, 2019
2 parents b9e6fc1 + b6f4df5 commit 5908332
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 24 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ lazy val commonSettings = Seq(
resolvers += "ATS Releases" at "http://nexus.advancedtelematic.com:8081/content/repositories/releases",
resolvers += "ATS Snapshots" at "http://nexus.advancedtelematic.com:8081/content/repositories/snapshots",
resolvers += "version99 Empty loggers" at "http://version99.qos.ch",
libatsVersion := "0.3.0-22-gcd3881e",
libatsVersion := "0.3.0-26-g5ce86ad",
licenses += ("MPL-2.0", url("http://mozilla.org/MPL/2.0/")),
buildInfoOptions += BuildInfoOption.ToMap,
buildInfoOptions += BuildInfoOption.BuildTime,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
package com.advancedtelematic.libtuf_server.reposerver

import akka.http.scaladsl.model._
import com.advancedtelematic.libtuf.data.TufDataType.{HardwareIdentifier, KeyType, RepoId, SignedPayload, TargetName, TargetVersion}
import io.circe.{Decoder, Encoder, Json}
import java.util.UUID

import akka.actor.ActorSystem
import akka.http.scaladsl.marshalling.Marshal
import akka.http.scaladsl.model.Uri.{Path, Query}
import akka.http.scaladsl.model.Uri.Path.Slash
import akka.http.scaladsl.model.Uri.{Path, Query}
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers.RawHeader
import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller
import akka.stream.Materializer
import akka.stream.scaladsl.Source
import akka.util.ByteString
import com.advancedtelematic.libats.data.DataType.{Checksum, Namespace}
import com.advancedtelematic.libats.data.ErrorCode
import com.advancedtelematic.libats.http.Errors.{RawError, RemoteServiceError}
import com.advancedtelematic.libtuf.data.TufDataType.TargetFormat.TargetFormat
import com.advancedtelematic.libtuf.data.TufCodecs._

import scala.concurrent.{ExecutionContext, Future}
import io.circe.generic.semiauto._
import com.advancedtelematic.libtuf.data.ClientCodecs._
import com.advancedtelematic.libats.http.Errors.{MissingEntity, RawError, RemoteServiceError}
import com.advancedtelematic.libats.http.HttpCodecs._
import com.advancedtelematic.libats.http.tracing.Tracing.ServerRequestTracing
import com.advancedtelematic.libats.http.tracing.TracingHttpClient
import com.advancedtelematic.libats.http.ServiceHttpClientSupport
import com.advancedtelematic.libats.http.{ServiceHttpClientSupport, UnmarshalledHttpResponse}
import com.advancedtelematic.libtuf.data.ClientCodecs._
import com.advancedtelematic.libtuf.data.ClientDataType.RootRole
import com.advancedtelematic.libtuf.data.TufCodecs._
import com.advancedtelematic.libtuf.data.TufDataType.TargetFormat.TargetFormat
import com.advancedtelematic.libtuf.data.TufDataType.{HardwareIdentifier, KeyType, RepoId, SignedPayload, TargetName, TargetVersion}
import com.advancedtelematic.libtuf_server.data.Requests.CreateRepositoryRequest
import com.advancedtelematic.libtuf_server.reposerver.ReposerverClient.{KeysNotReady, NotFound, RootNotInKeyserver}
import com.advancedtelematic.libtuf_server.reposerver.ReposerverClient.{KeysNotReady, MissingRepoIdHeader, NotFound, RootNotInKeyserver}
import io.circe.generic.semiauto._
import io.circe.{Decoder, Encoder, Json}

import scala.concurrent.{ExecutionContext, Future}
import scala.reflect.ClassTag
import scala.util.{Failure, Success}

Expand All @@ -52,6 +53,7 @@ object ReposerverClient {
val NotFound = RawError(ErrorCode("repo_resource_not_found"), StatusCodes.NotFound, "the requested repo resource was not found")
val RepoConflict = RawError(ErrorCode("repo_conflict"), StatusCodes.Conflict, "repo already exists")
val PrivateKeysNotInKeyserver = RawError(ErrorCode("private_keys_not_found"), StatusCodes.PreconditionFailed, "could not find required private keys. The repository might be using offline signing")
val MissingRepoIdHeader = MissingEntity[RepoId]
}


Expand All @@ -60,11 +62,11 @@ trait ReposerverClient {

def createRoot(namespace: Namespace, keyType: KeyType): Future[RepoId]

def fetchRoot(namespace: Namespace): Future[SignedPayload[RootRole]]
def fetchRoot(namespace: Namespace): Future[(RepoId, SignedPayload[RootRole])]

def repoExists(namespace: Namespace)(implicit ec: ExecutionContext): Future[Boolean] =
fetchRoot(namespace).transform {
case Success(_) | Failure(KeysNotReady) => Success(true)
case Success(_) | Failure(KeysNotReady) | Failure(MissingRepoIdHeader) => Success(true)
case Failure(NotFound) | Failure(RootNotInKeyserver) => Success(false)
case Failure(t) => Failure(t)
}
Expand All @@ -91,9 +93,9 @@ class ReposerverHttpClient(reposerverUri: Uri, httpClient: HttpRequest => Future
(implicit ec: ExecutionContext, system: ActorSystem, mat: Materializer, tracing: ServerRequestTracing)
extends TracingHttpClient(httpClient, "reposerver") with ReposerverClient {

import ReposerverClient._
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._
import io.circe.syntax._
import ReposerverClient._

private def apiUri(path: Path) =
reposerverUri.withPath(Path("/api") / "v1" ++ Slash(path))
Expand All @@ -109,16 +111,22 @@ class ReposerverHttpClient(reposerverUri: Uri, httpClient: HttpRequest => Future
}
}

override def fetchRoot(namespace: Namespace): Future[SignedPayload[RootRole]] = {
override def fetchRoot(namespace: Namespace): Future[(RepoId, SignedPayload[RootRole])] = {
val req = HttpRequest(HttpMethods.GET, uri = apiUri(Path("user_repo/root.json")))
execHttpWithNamespace[SignedPayload[RootRole]](namespace, req) {

val response = execHttpWithNamespace2[SignedPayload[RootRole]](namespace, req) {
case error if error.status == StatusCodes.NotFound =>
Future.failed(NotFound)
case error if error.status == StatusCodes.Locked =>
Future.failed(KeysNotReady)
case error if error.status == StatusCodes.FailedDependency =>
Future.failed(RootNotInKeyserver)
}

response.map { r =>
val repoIdHeader = r.httpResponse.headers.find(_.is("x-ats-tuf-repo-id")).getOrElse(throw MissingRepoIdHeader)
RepoId(UUID.fromString(repoIdHeader.value)) -> r.unmarshalledResponse
}
}

private def addTargetErrorHandler[T]: PartialFunction[RemoteServiceError, Future[T]] = {
Expand Down Expand Up @@ -148,15 +156,19 @@ class ReposerverHttpClient(reposerverUri: Uri, httpClient: HttpRequest => Future
}

def execHttpWithNamespace[T : ClassTag : FromEntityUnmarshaller](namespace: Namespace, request: HttpRequest)
(errorHandler: PartialFunction[RemoteServiceError, Future[T]] = PartialFunction.empty): Future[T] = {
(errorHandler: PartialFunction[RemoteServiceError, Future[T]] = PartialFunction.empty): Future[T] =
execHttpWithNamespace2[T](namespace, request)(errorHandler).map(_.unmarshalledResponse)

def execHttpWithNamespace2[T : ClassTag : FromEntityUnmarshaller](namespace: Namespace, request: HttpRequest)
(errorHandler: PartialFunction[RemoteServiceError, Future[T]] = PartialFunction.empty): Future[UnmarshalledHttpResponse[T]] = {
val req = request.addHeader(RawHeader("x-ats-namespace", namespace.get))

val authReq = authHeaders match {
case Some(a) => req.addHeader(a)
case None => req
}

execHttp[T](authReq)(errorHandler)
execHttp2[T](authReq)(errorHandler)
}

private def payloadFrom(uri: Uri, checksum: Checksum, length: Int, name: Option[TargetName],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ class ReposerverHttpClientSpec extends TufReposerverSpec
keyTypeTest("fetches a root") { keyType =>
val ns = genNs
client.createRoot(ns, keyType).futureValue
val signed = client.fetchRoot(ns).futureValue.signed
signed shouldBe a[RootRole]
signed.keys.head._2.keytype shouldBe keyType
val (repoId, signedRoot) = client.fetchRoot(ns).futureValue
repoId shouldBe a[RepoId]
signedRoot.signed shouldBe a[RootRole]
signedRoot.signed.keys.head._2.keytype shouldBe keyType
}

keyTypeTest("fails if role not on keyserver") { keyType =>
Expand Down

0 comments on commit 5908332

Please sign in to comment.