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

feat(artifact/decoration): Artifact decoration spinnaker/spinnaker#1348 #202

Merged
merged 1 commit into from
May 23, 2017

Conversation

brujoand
Copy link
Contributor

@brujoand brujoand commented May 9, 2017

The motivation here is to enable Artifact decoration for bakes without altering current workflow. I've tried to write this in such a way that it's easy to make the bakeprovider more generic in the future. This also means I had to take some choices so feel free to weigh in. This change gives us the following output on the bake endpoint:

curl -s http://localhost:8087/api/v1/global/bake/e2f492f2-ee4e-4bc3-b2b8-f0e8179625c7 | jq .
{
  "id": "e2f492f2-ee4e-4bc3-b2b8-f0e8179625c7",
  "ami": null,
  "image_name": "myrepo/the-team/ah4234h",
  "artifact": {
    "name": "the-team/mycontainer",
    "type": "docker",
    "version": "1494232370153",
    "reference": "containers.schibsted.io/delivery-team/delivery-dash:ah4234h",
    "metadata": {
      "build_info_url": "https://travis-ci.org/mybuild/53",
      "build_number": "53"
    }
  }
}

WDYT?

import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString

@CompileStatic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use @CompileStatic unless you really have to

def bakeRequestJson = mapper.writeValueAsString(bakeRequest)
def bakeStatusJson = mapper.writeValueAsString(bakeStatus)
def bakeLogsJson = mapper.writeValueAsString(bakeStatus.logsContent ? [logsContent: bakeStatus.logsContent] : [:])
def createdTimestampMilliseconds = timeInMilliseconds
def keyList = ["allBakes", bakeStatus.id, bakeKey, thisInstanceIncompleteBakesKey, lockKey.toString()]
def argList = [createdTimestampMilliseconds + "", region, bakeRequestJson, bakeStatusJson, bakeLogsJson, command, roscoInstanceId]
def argList = [createdTimestampMilliseconds + "", region, bakeRecipeJson, bakeRequestJson, bakeStatusJson, bakeLogsJson, command, roscoInstanceId]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is existing code, but you could probably change createdTimestampMilliseconds + "" to createdTimestampMilliseconds as String instead (if the casting/conversion is necessary at all?)

Copy link

@duftler duftler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the approach and the naming. Nice job.
Just a handful of minor comments.

BakeRequest bakeRequest = bakeStore.retrieveBakeRequestById(bakeId)
BakeRecipe bakeRecipe = bakeStore.retrieveBakeRecipeById(bakeId)

if (bakeDetails) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the retrieveBakeRequestById() and retrieveBakeRecipeById() calls should also be within this block.

@@ -34,7 +35,7 @@ interface BakeStore {
* Store the region, bakeRequest and bakeStatus in association with both the bakeKey and bakeId. If bake key
* has already been set, return a bakeStatus with that bake's id instead. None of the arguments may be null.
*/
public BakeStatus storeNewBakeStatus(String bakeKey, String region, BakeRequest bakeRequest, BakeStatus bakeStatus, String command)
public BakeStatus storeNewBakeStatus(String bakeKey, String region, BakeRecipe bakeRecipe, BakeRequest bakeRequest, BakeStatus bakeStatus, String command)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably also update the method comment.

parameterMap,
finalVarFileName,
finaltemplateFilePath)
def packerCommand = packerCommandFactory.buildPackerCommand (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could keep the formatting the same here as it was.

@@ -189,10 +214,11 @@ abstract class CloudProviderBakeHandler {
def finalVarFileName = bakeRequest.var_file_name ? "$configDir/$bakeRequest.var_file_name" : null
def baseCommand = getBaseCommand(finalTemplateFileName)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can drop this extraneous blank line now that the next statement is not a return.

@@ -129,4 +136,72 @@ class BakePollerSpec extends Specification {
1 * bakeStoreMock.retrieveBakeStatusById(JOB_ID) >> new BakeStatus()
}

void 'Decorate the bakeDetails with an artifact if bake is successfull'() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/successfull/successful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, I always turn of spellcheck when coding. Because it trips over my variables and methods. I guess it's time to put it back on.

1 * bakeStoreMock.updateBakeDetails(bakeDetails)
}

void 'Skip artifact decoration if required data is missing'() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/Skip/skip

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this test proves what it says it does. The guard on missing data in completeBake() is on bakeDetails, not bakeRecipe, and the produceArtifactDecorationFrom() method is still called. We just don't verify it here, and the cloudProviderBakeHandlerMock just returns null for it by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you're right. I struggled to get this test right, which made me pull out produceArtifactDecorationFrom from BakePoller, so that it was a simple contained method, which would be easier to test. I ment to delete this test and replace it with more accurate testing in CloudProviderBakeHandlerSpec. I'll clean this up.

* but it could be useful to override this method for specific providers.
*/
def Artifact produceArtifactDecorationFrom(BakeRequest bakeRequest, BakeRecipe bakeRecipe, Bake bakeDetails, String cloudProvider) {
Artifact bakedArtifact = new Artifact (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need the space before the opening parens for the constructor.

producedArtifact == expectedArtifact
}

void 'we should not fail if data is missing for artifact decoration'() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could break this down further and use a where: block to prove out each combination of missing data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure 👍

bakeRequest,
newBakeStatus,
jobRequest.tokenizedCommand.join(" "))
BakeStatus returnedBakeStatus = bakeStore.storeNewBakeStatus (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't see the need to reformat here if just adding the one arg. I can live with it, but leads to more reading in review. Either way, don't need the space before the opening parens.

def packerCommand = cloudProviderBakeHandler.producePackerCommand(region, bakeRequest)
def jobRequest = new JobRequest(tokenizedCommand: packerCommand, maskedPackerParameters: cloudProviderBakeHandler.maskedPackerParameters, jobId: bakeRequest.request_id)
def bakeRecipe = cloudProviderBakeHandler.produceBakeRecipe(region, bakeRequest)
def jobRequest = new JobRequest (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need the space before the opening parens.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do see that we've been inconsistent with our formatting already. I prefer this style, but can live with it either way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not a fan of the all-the-way-to-the-right indentations, so I was launching a silent rebellion in this PR to check the response. But consistency is even more important so I'll go with the flow on this one. No biggy.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were you going to undo the reformatting on this one?

@brujoand brujoand force-pushed the decorate_baked_artifacts branch 3 times, most recently from 2cd8b73 to 64fbc60 Compare May 19, 2017 08:00
@brujoand
Copy link
Contributor Author

Thanks, I've addressed the comments and gotten back in touch with master.

Copy link

@duftler duftler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fixes. Couple of remaining bits and then we'll get it merged.

1 * cloudProviderBakeHandlerRegistryMock.lookup(DOCKER_CLOUD_PROVIDER) >> cloudProviderBakeHandlerMock
1 * bakeStoreMock.retrieveRegionById(JOB_ID) >> REGION
1 * cloudProviderBakeHandlerMock.scrapeCompletedBakeResults(REGION, JOB_ID, LOGS_CONTENT) >> bakeDetails
1 * cloudProviderBakeHandlerMock.produceArtifactDecorationFrom(bakeRequest, bakeRecipe, bakeDetails, DOCKER_CLOUD_PROVIDER.toString()) >> bakedArtifact
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice.


then:
producedArtifact == expectedArtifact
producedArtifact.type == expectedArtifact.type
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these 4 assertions prove something the line just above does not?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My original comments was that you could use @unroll and where: and have one test case with request missing, one with recipe missing, one with details missing, various combinations...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, yeah. I completely misunderstood you.

def packerCommand = cloudProviderBakeHandler.producePackerCommand(region, bakeRequest)
def jobRequest = new JobRequest(tokenizedCommand: packerCommand, maskedPackerParameters: cloudProviderBakeHandler.maskedPackerParameters, jobId: bakeRequest.request_id)
def bakeRecipe = cloudProviderBakeHandler.produceBakeRecipe(region, bakeRequest)
def jobRequest = new JobRequest (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were you going to undo the reformatting on this one?

@@ -132,10 +154,13 @@ abstract class CloudProviderBakeHandler {
*/
abstract String getTemplateFileName(BakeOptions.BaseImage baseImage)


Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other methods have just one blank line separating them.

return bakedArtifact
}


Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extraneous blank line.

Copy link

@duftler duftler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@duftler duftler merged commit 072cfa3 into spinnaker:master May 23, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants