Skip to content

Commit

Permalink
feat(bakery): Clean up cached data created by Rosco. (#912) (#920)
Browse files Browse the repository at this point in the history
* feat(bakery): Clean up cached data created by Rosco.

* fix: typo.

* feat: Add unit test.

Co-authored-by: Fernando Freire <dogonthehorizon@gmail.com>
(cherry picked from commit 96cd6d2)

Co-authored-by: armory-abedonik <106548537+armory-abedonik@users.noreply.github.com>
  • Loading branch information
mergify[bot] and armory-abedonik committed Nov 23, 2022
1 parent 9217481 commit 5cb10c8
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2022 Armory, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.rosco.api;

import java.util.ArrayList;
import java.util.List;
import lombok.Data;

@Data
public class DeleteBakesRequest {

private List<String> pipelineExecutionIds = new ArrayList<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ interface BakeStore {
*/
public String deleteBakeByKeyPreserveDetails(String bakeKey)

/**
* Delete the bake entities associated with the given pipeline execution id.
*/
void deleteBakeByPipelineExecutionId(String pipelineExecutionId);

/**
* Cancel the incomplete bake associated with the bake id and delete the completed bake details associated with the
* bake id. If the bake is still incomplete, remove the bake id from the set of incomplete bakes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,16 @@ class RedisBackedBakeStore implements BakeStore {
return false
end
""")
// Expected key list: "allBakes", bake id, bake key, this instance incomplete bakes key, lock key
// Expected key list: "allBakes", bake id, bake key, this instance incomplete bakes key, lock key, pipeline execution key
// Expected arg list: createdTimestampMilliseconds, region, bake request json, bake status json, bake logs json, command, rosco instance id
storeNewBakeStatusSHA = jedis.scriptLoad("""\
-- Delete the bake id key.
redis.call('DEL', KEYS[2])
-- Add bake id and bake key to set identified by pipeline execution key.
redis.call('SADD', KEYS[6], KEYS[2])
redis.call('SADD', KEYS[6], KEYS[3])
-- Add bake key to set of bakes.
redis.call('ZADD', KEYS[1], ARGV[1], KEYS[3])
Expand Down Expand Up @@ -283,6 +287,19 @@ class RedisBackedBakeStore implements BakeStore {
return ret
""")
// Expected key list: pipeline execution key
// Expected arg list:
deleteBakeByPipelineExecutionKeySHA = jedis.scriptLoad("""
-- Get all bake entities' keys by pipeline execution key.
local bake_keys = redis.call('SMEMBERS', KEYS[1])
for _,key in ipairs(bake_keys)
do
redis.call('DEL', key)
end
redis.call('DEL', KEYS[1])
""")
}
}
}
Expand All @@ -308,12 +325,14 @@ class RedisBackedBakeStore implements BakeStore {
@Override
public BakeStatus storeNewBakeStatus(String bakeKey, String region, BakeRecipe bakeRecipe, BakeRequest bakeRequest, BakeStatus bakeStatus, String command) {
def lockKey = "lock:$bakeKey"
def pipelineExecutionId = getPipelineExecutionId(bakeRequest.spinnaker_execution_id)
def pipelineExecutionKey = getBakePipelineExecutionKey(pipelineExecutionId)
def bakeRecipeJson = mapper.writeValueAsString(bakeRecipe)
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 keyList = ["allBakes", bakeStatus.id, bakeKey, thisInstanceIncompleteBakesKey, lockKey.toString(), pipelineExecutionKey.toString()]
def argList = [createdTimestampMilliseconds as String, region, bakeRecipeJson, bakeRequestJson, bakeStatusJson, bakeLogsJson, command, roscoInstanceId]
def result = evalSHA("storeNewBakeStatusSHA", keyList, argList)

Expand Down Expand Up @@ -473,6 +492,13 @@ class RedisBackedBakeStore implements BakeStore {
return evalSHA("deleteBakeByKeyPreserveDetailsSHA", keyList, argList)
}

@Override
public void deleteBakeByPipelineExecutionId(String pipelineExecutionId) {
def keyList = [getBakePipelineExecutionKey(pipelineExecutionId)]

evalSHA("deleteBakeByPipelineExecutionKeySHA", keyList, [])
}

@Override
public boolean cancelBakeById(String bakeId) {
def bakeStatus = new BakeStatus(id: bakeId,
Expand Down Expand Up @@ -592,4 +618,12 @@ class RedisBackedBakeStore implements BakeStore {
}
}
}

private static String getBakePipelineExecutionKey(String pipelineExecutionId) {
return "bake:pipeline_execution:$pipelineExecutionId"
}

private static String getPipelineExecutionId(String spinnakerExecutionId) {
return spinnakerExecutionId.split(":")[0]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.netflix.spinnaker.rosco.api.Bake
import com.netflix.spinnaker.rosco.api.BakeOptions
import com.netflix.spinnaker.rosco.api.BakeRequest
import com.netflix.spinnaker.rosco.api.BakeStatus
import com.netflix.spinnaker.rosco.api.DeleteBakesRequest
import com.netflix.spinnaker.rosco.jobs.BakeRecipe
import com.netflix.spinnaker.rosco.jobs.JobExecutor
import com.netflix.spinnaker.rosco.jobs.JobRequest
Expand Down Expand Up @@ -308,6 +309,13 @@ class BakeryController {
}
}

@RequestMapping(value = '/api/v1/bakes/delete-requests', method = RequestMethod.POST)
void createDeleteBakesRequest(@RequestBody DeleteBakesRequest deleteBakesRequest) {
deleteBakesRequest.getPipelineExecutionIds().forEach({ pipelineExecutionId ->
bakeStore.deleteBakeByPipelineExecutionId(pipelineExecutionId)
})
}

// TODO(duftler): Synchronize this with existing bakery api.
@ApiOperation(value = "Cancel bake request")
@RequestMapping(value = "/api/v1/{region}/cancel/{statusId}", method = RequestMethod.GET)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.netflix.spinnaker.rosco.api.Bake
import com.netflix.spinnaker.rosco.api.BakeOptions
import com.netflix.spinnaker.rosco.api.BakeRequest
import com.netflix.spinnaker.rosco.api.BakeStatus
import com.netflix.spinnaker.rosco.api.DeleteBakesRequest
import com.netflix.spinnaker.rosco.jobs.BakeRecipe
import com.netflix.spinnaker.rosco.persistence.RedisBackedBakeStore
import com.netflix.spinnaker.rosco.providers.CloudProviderBakeHandler
Expand Down Expand Up @@ -782,4 +783,20 @@ class BakeryControllerSpec extends Specification {
thrown BakeOptions.Exception
}

void 'delete bakes by pipeline execution ids'() {
setup:
def bakeStoreMock = Mock(RedisBackedBakeStore)
def pipelineExecutionId = UUID.randomUUID().toString()
def deleteBakesRequest = new DeleteBakesRequest()
deleteBakesRequest.pipelineExecutionIds.add(pipelineExecutionId)

@Subject
def bakeryController = new BakeryController(bakeStore: bakeStoreMock)

when:
bakeryController.createDeleteBakesRequest(deleteBakesRequest)

then:
1 * bakeStoreMock.deleteBakeByPipelineExecutionId(pipelineExecutionId)
}
}

0 comments on commit 5cb10c8

Please sign in to comment.