Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ecr caching #8

Merged
merged 101 commits into from
Jan 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
2af7f62
Add license file
geoffjentry May 4, 2015
df6d61a
Merge pull request #2 from broadinstitute/jg_add_license
mcovarr May 5, 2015
a5d6039
Merge branch 'sprint2'
scottfrazer May 11, 2015
2bb777d
Merge branch 'develop'
May 26, 2015
3677b05
Docker files
Jun 1, 2015
747f871
Merge branch 'develop'
Jun 10, 2015
5b08f04
Merge pull request #69 from broadinstitute/develop
mcovarr Jun 30, 2015
30da42e
Merge pull request #71 from broadinstitute/develop
mcovarr Jun 30, 2015
d69dca6
Merge pull request #86 from broadinstitute/develop
geoffjentry Jul 13, 2015
94e3e1e
Merge branch 'develop'
scottfrazer Jul 29, 2015
5b970e4
Merge branch 'develop'
scottfrazer Aug 7, 2015
033640c
Merge branch 'develop'
scottfrazer Aug 21, 2015
ead1786
Merge branch 'develop'
scottfrazer Sep 4, 2015
ec83068
Merge branch 'develop'
scottfrazer Sep 21, 2015
8be932e
Merge branch 'develop'
scottfrazer Oct 5, 2015
053c7d9
Merge branch 'develop'
scottfrazer Oct 16, 2015
05fd763
Merge branch 'develop'
scottfrazer Nov 3, 2015
3d48fde
Merge branch 'develop'
scottfrazer Dec 18, 2015
42b827e
Merge branch 'develop'
scottfrazer Jan 11, 2016
c4e4b45
adjust yaml file
Jan 26, 2016
8a48eee
Aborts jobs on shutdown.
Jan 21, 2016
42884d8
Merge branch 'release-0.17'
geoffjentry Feb 2, 2016
9f44b6d
Merge pull request #504 from broadinstitute/fix_abort
scottfrazer Mar 3, 2016
91578a9
Merge branch 'release-0.18'
scottfrazer Mar 3, 2016
fabf81d
Merge branch 'release-0.19'
Apr 1, 2016
9a56863
Merge branch '0.21'
Sep 22, 2016
d2b053d
update version to 0.21
Sep 22, 2016
6df8c3b
Merge branch 'release-0.21'
Sep 23, 2016
fac45fc
Fix incorrect URL
geoffjentry Sep 23, 2016
88ff89f
release_notes
ruchim Oct 13, 2016
06d7f33
typos and reword
ruchim Oct 13, 2016
0099816
release_candidate_0.22
ruchim Oct 13, 2016
f7f068c
Release 23 (#1735)
geoffjentry Dec 3, 2016
b71f06f
Release 24
kshakir Jan 5, 2017
31ae549
Merge branch 'develop'
ruchim Mar 3, 2017
dbde100
Merge branch 'develop'
ruchim Apr 11, 2017
22fe860
Pin release to centaur branch
ruchim Apr 11, 2017
c2451d8
Merge branch 'develop'
May 30, 2017
a6bcebb
Pin release to centaur branch
May 30, 2017
4480026
Point centaur to develop
Jun 30, 2017
48411bf
Merge branch 'develop'
Jun 30, 2017
b47feaa
Merge branch 'develop'
Aug 16, 2017
70eb8ee
Merge branch 'develop'
cjllanwarne Dec 4, 2017
710c193
Merge branch 'develop'
Mar 12, 2018
8ef1196
Merge branch 'develop'
kshakir May 25, 2018
e90c4de
Merge branch 'develop'
Jun 25, 2018
0e0b51f
Merge branch 'develop'
mcovarr Jul 19, 2018
172412c
Merge branch 'develop'
aednichols Sep 26, 2018
1e4b2c5
Merge branch 'develop'
aednichols Sep 26, 2018
fdfab9b
Merge branch 'develop'
aednichols Sep 26, 2018
4521fd4
Fix release mishap - version number
aednichols Oct 2, 2018
26ee8d8
Merge branch 'develop'
Oct 17, 2018
71debed
Merge branch 'develop'
Oct 17, 2018
9f78414
Fixed merge conflict
salonishah11 Feb 7, 2019
bf46f39
Merge branch 'develop'
kshakir Mar 7, 2019
8cf7129
Merge branch 'develop'
mcovarr Mar 28, 2019
7c3e59b
Merge branch 'develop'
mcovarr Apr 18, 2019
2754783
Merge branch 'develop'
mcovarr Apr 19, 2019
3445bfd
Merge branch 'develop'
cjllanwarne May 13, 2019
98ba596
Merge branch 'develop'
aednichols Jun 3, 2019
a52c76e
Merge branch 'develop'
Jun 26, 2019
8055dad
Merge branch 'develop'
Jul 15, 2019
d46ff9f
Merge branch 'develop'
salonishah11 Aug 19, 2019
b61c136
Merge branch 'develop'
kshakir Sep 16, 2019
1ce5bbf
Merge branch 'develop'
mcovarr Oct 7, 2019
787cf8b
Merge branch 'develop'
aednichols Jan 13, 2020
58c8443
Merge branch 'develop'
cjllanwarne Feb 27, 2020
ee8cfd4
Fix missing pig in docs (#5435) [no JIRA]
lbergelson Feb 28, 2020
c6468c0
Merge branch 'develop'
Apr 21, 2020
aecae0e
Merge branch 'develop'
mcovarr May 29, 2020
fa44f36
Update Google.md (#5529)
rpomaris Jun 3, 2020
96ea5f4
Merge branch 'develop'
cjllanwarne Jul 15, 2020
d2f506b
Merge branch 'develop'
cjllanwarne Aug 25, 2020
97597a4
Merge branch 'develop'
kshakir Nov 9, 2020
0963109
Update LanguageSupport.md
kv076 Dec 15, 2020
768221e
Merge branch 'develop'
kshakir Jan 11, 2021
5ca4099
Merge branch 'develop'
Feb 4, 2021
ae2618c
Merge branch 'develop'
mcovarr Feb 18, 2021
3675453
Merge branch 'develop'
salonishah11 Mar 4, 2021
a6bef7a
Merge branch 'develop'
kshakir Mar 25, 2021
dd4a21d
Merge branch 'develop'
kshakir Mar 31, 2021
14bb3ba
Merge branch 'develop'
cjllanwarne Apr 16, 2021
f1cd3e1
Merge branch 'develop'
kshakir May 6, 2021
60177c9
Merge branch 'develop'
cjllanwarne May 18, 2021
e90facf
Merge branch 'develop'
mcovarr Jun 11, 2021
ed067b8
Merge branch 'develop'
cjllanwarne Jun 16, 2021
ef30230
check buckets for region and ensure client has correct region
markjschreiber Jul 13, 2021
7675fd9
handle redirects and objects that don't allow read access to their ACL
markjschreiber Jul 22, 2021
08d95b8
added retry and size verification to s3 object localization
markjschreiber Jul 22, 2021
986ab31
removed need to have object acl access
markjschreiber Jul 23, 2021
e171e91
cache s3 clients and vend from S3ClientStore
markjschreiber Jul 31, 2021
48257ac
updated _s3_localize_with_retry so that the attempt to obtain the siz…
markjschreiber Aug 2, 2021
4fcc416
Increased metadata endpoint retries
markjschreiber Aug 3, 2021
2eb86cf
feat: implement aws batch retries (#1)
henriqueribeiro Aug 4, 2021
e977d08
Improved cross region object access and better handle permission rest…
markjschreiber Aug 23, 2021
155ed46
Improved testing
markjschreiber Oct 5, 2021
5ac9260
Improved testing
markjschreiber Oct 19, 2021
94a720d
remove unnecessary method
markjschreiber Oct 19, 2021
19461a3
enable hashing of ECR and ECR public
markjschreiber Oct 22, 2021
29e4039
improve test coverage for AmazonEcr and AmazonEcrPublic
markjschreiber Oct 26, 2021
53c9134
Merge branch 'caching' into bump-version
henriqueribeiro Jan 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/src/main/scala/cromwell/backend/backend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ object CommonBackendConfigurationAttributes {
"default-runtime-attributes.noAddress",
"default-runtime-attributes.docker",
"default-runtime-attributes.queueArn",
"default-runtime-attributes.awsBatchRetryAttempts",
"default-runtime-attributes.ulimits",
"default-runtime-attributes.failOnStderr",
"slow-job-warning-time",
"dockerhub",
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ docker {
dockerhub.num-threads = 10
quay.num-threads = 10
alibabacloudcr.num-threads = 10
ecr.num-threads = 10
ecr-public.num-threads = 10
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import cromwell.core.actor.StreamIntegration.{BackPressure, StreamContext}
import cromwell.core.{Dispatcher, DockerConfiguration}
import cromwell.docker.DockerInfoActor._
import cromwell.docker.registryv2.DockerRegistryV2Abstract
import cromwell.docker.registryv2.flows.aws.{AmazonEcr, AmazonEcrPublic}
import cromwell.docker.registryv2.flows.alibabacloudcrregistry._
import cromwell.docker.registryv2.flows.dockerhub.DockerHubRegistry
import cromwell.docker.registryv2.flows.google.GoogleRegistry
Expand Down Expand Up @@ -236,7 +237,9 @@ object DockerInfoActor {
("dockerhub", { c: DockerRegistryConfig => new DockerHubRegistry(c) }),
("google", { c: DockerRegistryConfig => new GoogleRegistry(c) }),
("quay", { c: DockerRegistryConfig => new QuayRegistry(c) }),
("alibabacloudcr", {c: DockerRegistryConfig => new AlibabaCloudCRRegistry(c)})
("alibabacloudcr", {c: DockerRegistryConfig => new AlibabaCloudCRRegistry(c)}),
("ecr", {c: DockerRegistryConfig => new AmazonEcr(c)}),
("ecr-public", {c: DockerRegistryConfig => new AmazonEcrPublic(c)})
).traverse[ErrorOr, DockerRegistry]({
case (configPath, constructor) => DockerRegistryConfig.fromConfig(config.as[Config](configPath)).map(constructor)
}).unsafe("Docker registry configuration")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ object DockerRegistryV2Abstract {
)
})
}

// Placeholder exceptions that can be carried through IO before being converted to a DockerInfoFailedResponse
private class Unauthorized() extends Exception
private class NotFound() extends Exception
Expand All @@ -76,6 +76,8 @@ abstract class DockerRegistryV2Abstract(override val config: DockerRegistryConfi
implicit val cs = IO.contextShift(ec)
implicit val timer = IO.timer(ec)

protected val authorizationScheme: AuthScheme = AuthScheme.Bearer

/**
* This is the main function. Given a docker context and an http client, retrieve information about the docker image.
*/
Expand Down Expand Up @@ -204,7 +206,7 @@ abstract class DockerRegistryV2Abstract(override val config: DockerRegistryConfi
* Request to get the manifest, using the auth token if provided
*/
private def manifestRequest(token: Option[String], imageId: DockerImageIdentifier): IO[Request[IO]] = {
val authorizationHeader = token.map(t => Authorization(Credentials.Token(AuthScheme.Bearer, t)))
val authorizationHeader = token.map(t => Authorization(Credentials.Token(authorizationScheme, t)))
val request = Method.GET(
buildManifestUri(imageId),
List(
Expand Down Expand Up @@ -235,13 +237,13 @@ abstract class DockerRegistryV2Abstract(override val config: DockerRegistryConfi
* The response can be of 2 sorts:
* - A manifest (https://docs.docker.com/registry/spec/manifest-v2-2/#image-manifest-field-descriptions)
* - A manifest list which contains a list of pointers to other manifests (https://docs.docker.com/registry/spec/manifest-v2-2/#manifest-list)
*
*
* When a manifest list is returned, we need to pick one of the manifest pointers and make another request for that manifest.
*
*
* Because the different manifests in the list are (supposed to be) variations of the same image over different platforms,
* we simply pick the first one here since we only care about the approximate size, and we don't expect it to change drastically
* between platforms.
* If that assumption turns out to be incorrect, a smarter decision may need to be made to choose the manifest to lookup.
* If that assumption turns out to be incorrect, a smarter decision may need to be made to choose the manifest to lookup.
*/
private def parseManifest(dockerImageIdentifier: DockerImageIdentifier, token: Option[String])(response: Response[IO])(implicit client: Client[IO]): IO[Option[DockerManifest]] = response match {
case Status.Successful(r) if r.headers.exists(_.value.equalsIgnoreCase(ManifestV2MediaType)) =>
Expand All @@ -268,14 +270,14 @@ abstract class DockerRegistryV2Abstract(override val config: DockerRegistryConfi
}
}

private def getDigestFromResponse(response: Response[IO]): IO[DockerHashResult] = response match {
protected def getDigestFromResponse(response: Response[IO]): IO[DockerHashResult] = response match {
case Status.Successful(r) => extractDigestFromHeaders(r.headers)
case Status.Unauthorized(_) => IO.raiseError(new Unauthorized)
case Status.NotFound(_) => IO.raiseError(new NotFound)
case failed => failed.as[String].flatMap(body => IO.raiseError(new Exception(s"Failed to get manifest: $body"))
)
}

private def extractDigestFromHeaders(headers: Headers) = {
headers.find(a => a.toRaw.name.equals(DigestHeaderName)) match {
case Some(digest) => IO.fromEither(DockerHashResult.fromString(digest.value).toEither)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cromwell.docker.registryv2.flows.aws

import cats.effect.IO
import cromwell.docker.{DockerImageIdentifier, DockerInfoActor, DockerRegistryConfig}
import org.http4s.AuthScheme
import org.http4s.client.Client
import software.amazon.awssdk.services.ecr.EcrClient

import scala.compat.java8.OptionConverters._
import scala.concurrent.Future

class AmazonEcr(override val config: DockerRegistryConfig, ecrClient: EcrClient = EcrClient.create()) extends AmazonEcrAbstract(config) {

override protected val authorizationScheme: AuthScheme = AuthScheme.Basic

/**
* e.g 123456789012.dkr.ecr.us-east-1.amazonaws.com
*/
override protected def registryHostName(dockerImageIdentifier: DockerImageIdentifier): String = {
var hostname = dockerImageIdentifier.hostAsString
if (hostname.lastIndexOf("/").equals(hostname.length -1)) {
hostname = hostname.substring(0, hostname.length -1)
}
hostname
}
/**
* Returns true if this flow is able to process this docker image,
* false otherwise
*/
override def accepts(dockerImageIdentifier: DockerImageIdentifier): Boolean = dockerImageIdentifier.hostAsString.contains("amazonaws.com")

override protected def getToken(dockerInfoContext: DockerInfoActor.DockerInfoContext)(implicit client: Client[IO]): IO[Option[String]] = {
val eventualMaybeToken = Future(ecrClient.getAuthorizationToken
.authorizationData()
.stream()
.findFirst()
.asScala
.map(_.authorizationToken()))

IO.fromFuture(IO(eventualMaybeToken))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cromwell.docker.registryv2.flows.aws

import cats.effect.IO
import cromwell.docker.{DockerHashResult, DockerImageIdentifier, DockerInfoActor, DockerRegistryConfig}
import cromwell.docker.registryv2.DockerRegistryV2Abstract
import cromwell.docker.registryv2.flows.aws.EcrUtils.{EcrForbidden, EcrNotFound, EcrUnauthorized}
import org.apache.commons.codec.digest.DigestUtils
import org.http4s.{Header, Response, Status}

abstract class AmazonEcrAbstract(override val config: DockerRegistryConfig) extends DockerRegistryV2Abstract(config) {

/**
* Not used as getToken is overridden
*/
override protected def authorizationServerHostName(dockerImageIdentifier: DockerImageIdentifier): String = ""

/**
* Not used as getToken is overridden
*/
override protected def buildTokenRequestHeaders(dockerInfoContext: DockerInfoActor.DockerInfoContext): List[Header] = List.empty

/**
* Amazon ECR repositories don't have a digest header in responses so we must made it from the manifest body
*/
override protected def getDigestFromResponse(response: Response[IO]): IO[DockerHashResult] = response match {
case Status.Successful(r) => digestManifest(r.bodyText)
case Status.Unauthorized(_) => IO.raiseError(new EcrUnauthorized)
case Status.NotFound(_) => IO.raiseError(new EcrNotFound)
case Status.Forbidden(_) => IO.raiseError(new EcrForbidden)
case failed => failed.as[String].flatMap(body => IO.raiseError(new Exception(s"Failed to get manifest: $body")))
}

private def digestManifest(bodyText: fs2.Stream[IO, String]): IO[DockerHashResult] = {
bodyText
.compile
.string
.map(data => "sha256:"+DigestUtils.sha256Hex(data))
.map(DockerHashResult.fromString)
.flatMap(IO.fromTry)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cromwell.docker.registryv2.flows.aws

import cats.effect.IO
import cromwell.docker.{DockerImageIdentifier, DockerInfoActor, DockerRegistryConfig}
import org.http4s.client.Client
import software.amazon.awssdk.services.ecrpublic.EcrPublicClient
import software.amazon.awssdk.services.ecrpublic.model.GetAuthorizationTokenRequest

import scala.concurrent.Future


class AmazonEcrPublic(override val config: DockerRegistryConfig, ecrClient: EcrPublicClient = EcrPublicClient.create()) extends AmazonEcrAbstract(config) {
/**
* public.ecr.aws
*/
override protected def registryHostName(dockerImageIdentifier: DockerImageIdentifier): String = "public.ecr.aws"

/**
* Returns true if this flow is able to process this docker image,
* false otherwise
*/
override def accepts(dockerImageIdentifier: DockerImageIdentifier): Boolean = dockerImageIdentifier.hostAsString.contains("public.ecr.aws")


override protected def getToken(dockerInfoContext: DockerInfoActor.DockerInfoContext)(implicit client: Client[IO]): IO[Option[String]] = {

val eventualMaybeToken: Future[Option[String]] = Future(
Option(ecrClient
.getAuthorizationToken(GetAuthorizationTokenRequest.builder().build())
.authorizationData.authorizationToken()
)
)

IO.fromFuture(IO(eventualMaybeToken))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package cromwell.docker.registryv2.flows.aws

object EcrUtils {

case class EcrUnauthorized() extends Exception
case class EcrNotFound() extends Exception
case class EcrForbidden() extends Exception

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cromwell.docker.registryv2.flows.aws

import cats.effect.{IO, Resource}
import cromwell.core.TestKitSuite
import cromwell.docker.registryv2.DockerRegistryV2Abstract
import cromwell.docker.{DockerImageIdentifier, DockerInfoActor, DockerInfoRequest, DockerRegistryConfig}
import org.http4s.{Header, Headers, MediaType, Request, Response}
import org.http4s.client.Client
import org.http4s.headers.`Content-Type`
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito._
import org.scalatest.{BeforeAndAfter, PrivateMethodTester}
import org.scalatest.flatspec.AnyFlatSpecLike
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.mockito.MockitoSugar
import software.amazon.awssdk.services.ecrpublic.model.{AuthorizationData, GetAuthorizationTokenRequest, GetAuthorizationTokenResponse}
import software.amazon.awssdk.services.ecrpublic.EcrPublicClient

class AmazonEcrPublicSpec extends TestKitSuite with AnyFlatSpecLike with Matchers with MockitoSugar with BeforeAndAfter with PrivateMethodTester {
behavior of "AmazonEcrPublic"

val goodUri = "public.ecr.aws/amazonlinux/amazonlinux:latest"
val otherUri = "ubuntu:latest"


val mediaType: MediaType = MediaType.parse(DockerRegistryV2Abstract.ManifestV2MediaType).right.get
val contentType: Header = `Content-Type`(mediaType)
val mockEcrClient: EcrPublicClient = mock[EcrPublicClient]
implicit val mockIOClient: Client[IO] = Client({ _: Request[IO] =>
// This response will have an empty body, so we need to be explicit about the typing:
Resource.pure[IO, Response[IO]](Response(headers = Headers.of(contentType))) : Resource[IO, Response[IO]]
})

val registry = new AmazonEcrPublic(DockerRegistryConfig.default, mockEcrClient)

it should "Accept good URI" in {
val dockerImageIdentifier = DockerImageIdentifier.fromString(goodUri).get
registry.accepts(dockerImageIdentifier) shouldEqual true
}

it should "NOT accept other URI" in {
val dockerImageIdentifier = DockerImageIdentifier.fromString(otherUri).get
registry.accepts(dockerImageIdentifier) shouldEqual false
}

it should "have public.ecr.aws as registryHostName" in {
val registryHostNameMethod = PrivateMethod[String]('registryHostName)
registry invokePrivate registryHostNameMethod(DockerImageIdentifier.fromString(goodUri).get) shouldEqual "public.ecr.aws"
}

it should "return expected auth token" in {
val token = "auth-token"
val imageId = DockerImageIdentifier.fromString(goodUri).get
val dockerInfoRequest = DockerInfoRequest(imageId)
val context = DockerInfoActor.DockerInfoContext(request = dockerInfoRequest, replyTo = emptyActor)

when(mockEcrClient.getAuthorizationToken(any[GetAuthorizationTokenRequest]()))
.thenReturn(GetAuthorizationTokenResponse
.builder()
.authorizationData(AuthorizationData
.builder()
.authorizationToken(token)
.build())
.build)

val getTokenMethod = PrivateMethod[IO[Option[String]]]('getToken)
registry invokePrivate getTokenMethod(context, mockIOClient) ensuring(io => io.unsafeRunSync().get == token)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package cromwell.docker.registryv2.flows.aws

import cats.effect.{IO, Resource}
import cromwell.core.TestKitSuite
import cromwell.docker.registryv2.DockerRegistryV2Abstract
import cromwell.docker.{DockerImageIdentifier, DockerInfoActor, DockerInfoRequest, DockerRegistryConfig}
import org.http4s.{AuthScheme, Header, Headers, MediaType, Request, Response}
import org.http4s.client.Client
import org.http4s.headers.`Content-Type`
import org.mockito.Mockito._
import org.scalatest.{BeforeAndAfter, PrivateMethodTester}
import org.scalatest.flatspec.AnyFlatSpecLike
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.mockito.MockitoSugar
import software.amazon.awssdk.services.ecr.EcrClient
import software.amazon.awssdk.services.ecr.model.{AuthorizationData, GetAuthorizationTokenResponse}

class AmazonEcrSpec extends TestKitSuite with AnyFlatSpecLike with Matchers with MockitoSugar with BeforeAndAfter with PrivateMethodTester{
behavior of "AmazonEcr"

val goodUri = "123456789012.dkr.ecr.us-east-1.amazonaws.com/amazonlinux/amazonlinux:latest"
val otherUri = "ubuntu:latest"

val mediaType: MediaType = MediaType.parse(DockerRegistryV2Abstract.ManifestV2MediaType).right.get
val contentType: Header = `Content-Type`(mediaType)
val mockEcrClient: EcrClient = mock[EcrClient]
implicit val mockIOClient: Client[IO] = Client({ _: Request[IO] =>
// This response will have an empty body, so we need to be explicit about the typing:
Resource.pure[IO, Response[IO]](Response(headers = Headers.of(contentType))) : Resource[IO, Response[IO]]
})

val registry = new AmazonEcr(DockerRegistryConfig.default, mockEcrClient)

it should "accept good URI" in {
val dockerImageIdentifier = DockerImageIdentifier.fromString(goodUri).get
registry.accepts(dockerImageIdentifier) shouldEqual true
}

it should "NOT accept other URI" in {
val dockerImageIdentifier = DockerImageIdentifier.fromString(otherUri).get
registry.accepts(dockerImageIdentifier) shouldEqual false
}

it should "use Basic Auth Scheme" in {
val authSchemeMethod = PrivateMethod[AuthScheme]('authorizationScheme)
registry invokePrivate authSchemeMethod() shouldEqual AuthScheme.Basic
}

it should "return 123456789012.dkr.ecr.us-east-1.amazonaws.com as registryHostName" in {
val registryHostNameMethod = PrivateMethod[String]('registryHostName)
registry invokePrivate registryHostNameMethod(DockerImageIdentifier.fromString(goodUri).get) shouldEqual "123456789012.dkr.ecr.us-east-1.amazonaws.com"
}

it should "return expected auth token" in {
val token = "auth-token"
val imageId = DockerImageIdentifier.fromString(goodUri).get
val dockerInfoRequest = DockerInfoRequest(imageId)
val context = DockerInfoActor.DockerInfoContext(request = dockerInfoRequest, replyTo = emptyActor)

when(mockEcrClient.getAuthorizationToken)
.thenReturn(GetAuthorizationTokenResponse
.builder()
.authorizationData(AuthorizationData
.builder()
.authorizationToken(token)
.build())
.build)

val getTokenMethod = PrivateMethod[IO[Option[String]]]('getToken)
registry invokePrivate getTokenMethod(context, mockIOClient) ensuring(io => io.unsafeRunSync().get == token)
}
}
2 changes: 1 addition & 1 deletion docs/LanguageSupport.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ As well as the changes to the WDL spec between draft-2 and 1.0, Cromwell also su
### CWL 1.0

Cromwell provides support for Common Workflow Language (CWL), beginning with the core spec, and most heavily used requirements.
If you spot a CWL feature that Cromwell doesn't support, please notify us using an issue on our github page!
If you spot a CWL feature that Cromwell doesn't support, please notify us using an issue on our [Jira page](https://broadworkbench.atlassian.net/secure/RapidBoard.jspa?rapidView=39&view=planning.nodetail&issueLimit=100)!


## Future Language Support
Expand Down
Loading