Skip to content

Commit

Permalink
Add --service-account flag to cleanup.sh (knative#312)
Browse files Browse the repository at this point in the history
This is required when running the script from Prow jobs, to establish the authentication.

Bonuses:
* update documentation
* used the term "gcr" instead of project to clearly differentiate from the GCP projects parsed from a YAML file
* separated the deletion functions for testing purposes
* assorted code refactoring, documentation, simplification, fixing and nitpicking
  • Loading branch information
adrcunha authored and knative-prow-robot committed Dec 12, 2018
1 parent 5771cc5 commit 528cba9
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 135 deletions.
1 change: 1 addition & 0 deletions ci/prow/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2227,6 +2227,7 @@ periodics:
- "delete-old-gcr-images"
- "--project-resource-yaml ci/prow/boskos/resources.yaml"
- "--days-to-keep 90"
- "--service-account /etc/test-account/service-account.json"

postsubmits:
knative/serving:
Expand Down
24 changes: 12 additions & 12 deletions test/unit/cleanup-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# limitations under the License.

source $(dirname $0)/helper.sh
source "$(dirname $0)/../../tools/cleanup/cleanup.sh"
source $(dirname $0)/../../tools/cleanup/cleanup-functions.sh

readonly _FAKE_NIGHTLY_PROJECT_NAME="gcr.io/knative-nightly"
readonly _FAKE_BOSKOS_PROJECT_NAME="gcr.io/fake-boskos-project"
Expand All @@ -29,35 +29,35 @@ function cleanup_script() {
}

set -e

cd ${REPO_ROOT_DIR}

echo ">> Testing directly invoking cleanup script"

test_function ${FAILURE} "error: unknown option" cleanup_script "action-not-exist"
test_function ${FAILURE} "error: missing project" cleanup_script "delete-old-gcr-images-from-project"
test_function ${FAILURE} "error: missing gcr" cleanup_script "delete-old-images-from-gcr"
test_function ${FAILURE} "error: missing resource" cleanup_script "delete-old-gcr-images"

test_function ${FAILURE} "error: expecting value following" cleanup_script "delete-old-gcr-images" --project-resource-yaml --dry-run
test_function ${FAILURE} "error: expecting value following" cleanup_script "delete-old-gcr-images" --re-project-name --dry-run
test_function ${FAILURE} "error: expecting value following" cleanup_script "delete-old-gcr-images" --project-to-cleanup --dry-run
test_function ${FAILURE} "error: expecting value following" cleanup_script "delete-old-gcr-images" --gcr-to-cleanup --dry-run
test_function ${FAILURE} "error: expecting value following" cleanup_script "delete-old-gcr-images" --days-to-keep --dry-run

test_function ${FAILURE} "error: days to keep" cleanup_script "delete-old-gcr-images-from-project" --days-to-keep "a" --dry-run
test_function ${FAILURE} "error: days to keep" cleanup_script "delete-old-images-from-gcr" --days-to-keep "a" --dry-run
test_function ${FAILURE} "error: days to keep" cleanup_script "delete-old-gcr-images" --days-to-keep "a" --dry-run

# Test individual functions
echo ">> Testing deleting images from single project"

test_function ${FAILURE} "error: missing" delete_old_gcr_images_from_project
test_function ${SUCCESS} "" mock_gcloud_function delete_old_gcr_images_from_project ${_FAKE_BOSKOS_PROJECT_NAME}
test_function ${SUCCESS} "" mock_gcloud_function delete_old_gcr_images_from_project ${_FAKE_BOSKOS_PROJECT_NAME} 1
test_function ${FAILURE} "error: missing gcr" delete_old_images_from_gcr
test_function ${FAILURE} "error: missing days" delete_old_images_from_gcr ${_FAKE_BOSKOS_PROJECT_NAME}
test_function ${SUCCESS} "" mock_gcloud_function delete_old_images_from_gcr ${_FAKE_BOSKOS_PROJECT_NAME} 1

echo ">> Testing deleting images from multiple projects"

test_function ${FAILURE} "error: missing" delete_old_gcr_images
test_function ${FAILURE} "error: no project" delete_old_gcr_images "${_PROJECT_RESOURCE_YAML}file_not_exist" ${_RE_PROJECT_NAME}
test_function ${FAILURE} "error: no project" delete_old_gcr_images ${_PROJECT_RESOURCE_YAML} "${_RE_PROJECT_NAME}project-not-exist"
test_function ${SUCCESS} "Start" mock_gcloud_function delete_old_gcr_images ${_PROJECT_RESOURCE_YAML}
test_function ${SUCCESS} "Start" mock_gcloud_function delete_old_gcr_images ${_PROJECT_RESOURCE_YAML} ${_RE_PROJECT_NAME}
test_function ${FAILURE} "error: missing resource" delete_old_gcr_images
test_function ${FAILURE} "error: missing regex" delete_old_gcr_images "file"
test_function ${FAILURE} "error: missing days" delete_old_gcr_images "file" "regex"
test_function ${SUCCESS} "Start" mock_gcloud_function delete_old_gcr_images ${_PROJECT_RESOURCE_YAML} ${_RE_PROJECT_NAME} 99

echo ">> All tests passed"
21 changes: 14 additions & 7 deletions tools/cleanup/README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
# Resources Clean Up Tool
This tool is designed to clean up staled resources from gcr, for now it only deletes old images created during testing.

This tool is designed to clean up stale resources from gcr, for now it only deletes old images created during testing.

## Basic Usage

Directly invoke [cleanup.sh](cleanup.sh) script with certain flags. There is no-op if invoking or sourcing this script without arguments.

### Clean up old images from multiple gcr
By default the current gcloud credentials are used to delete the images. If necessary, use the flag `--service-account _key-file.json_` to specify a service account that will be performing the access to the gcr.

### Clean up old images from multiple gcrs

Projects to be cleaned up are expected to be defined in a `resources.yaml` file. To remove old images from them, call [cleanup.sh](cleanup.sh) with action "delete-old-gcr-images" and following flags:
- "--project-resource-yaml" as path of `resources.yaml` file - Mandatory
- "--re-project-name" for regex matching projects names - Optional, default `knative-boskos-[a-zA-Z0-9]+`
- "--re-project-name" for regex matching projects names - Optional, defaults to `knative-boskos-[a-zA-Z0-9]+`
- "--days-to-keep" - Optional, default `365`

Example:

```./cleanup.sh "delete-old-gcr-images" --project-resource-yaml "ci/prow/boskos/resources.yaml" --days-to-keep 90```

### Clean up old images from specified gcr
Cleaning up from specific gcr is supported, except for some special ones (_knative-release_ and _knative-nightly_). Call [cleanup.sh](cleanup.sh) with action "delete-old-gcr-images-from-project" and following flags:
- "--project-to-cleanup" as name of gcr, e.g. "gcr.io/foo" - Mandatory
### Clean up old images from a specific gcr

Cleaning up from a specific gcr is supported, except for some special ones (_knative-release_ and _knative-nightly_). Call [cleanup.sh](cleanup.sh) with action "delete-old-images-from-gcr" and following flags:
- "--gcr-to-cleanup" as name of gcr, e.g. "gcr.io/foo" - Mandatory
- "--days-to-keep" - Optional, default `365`

Example:

```./cleanup.sh "delete-old-gcr-images-from-project" --project-to-cleanup "gcr.io/foo" --days-to-keep 90```
```./cleanup.sh "delete-old-images-from-gcr" --gcr-to-cleanup "gcr.io/foo" --days-to-keep 90```

## Prow Job

There is a weekly prow job that triggers this tool runs at 11:00/12:00PM(Day light saving) PST every Monday. This tool scans all gcr projects defined in [ci/prow/boskos/resources.yaml](/ci/prow/boskos/resources.yaml) and deletes images older than 90 days.
68 changes: 68 additions & 0 deletions tools/cleanup/cleanup-functions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/bash

# Copyright 2018 The Knative Authors
#
# 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.

# Functions for cleaning up GCRs.
# It doesn't do anything when called from command line.

source $(dirname $0)/../../scripts/library.sh

# Delete old images in the given GCR.
# Parameters: $1 - gcr to be cleaned up (e.g. gcr.io/fooProj)
# $2 - days to keep images
function delete_old_images_from_gcr() {
[[ -z $1 ]] && abort "missing gcr name"
[[ -z $2 ]] && abort "missing days to keep images"

is_protected_gcr $1 && \
abort "Target GCR set to $1, which is forbidden"

for image in $(gcloud --format='value(name)' container images list --repository=$1); do
echo "Checking ${image} for removal"

delete_old_images_from_gcr ${image} $2

local target_date=$(date -d "`date`-$2days" +%Y-%m-%d)
for digest in $(gcloud --format='get(digest)' container images list-tags ${image} \
--filter="timestamp.datetime<${target_date}" --limit=99999); do
local full_image="${image}@${digest}"
echo "Deleting image: ${full_image}"
if (( DRY_RUN )); then
echo "[DRY RUN] gcloud container images delete -q --force-delete-tags ${full_image}"
else
gcloud container images delete -q --force-delete-tags ${full_image}
fi
done
done
}

# Delete old images in the GCP projects defined in the yaml file provided.
# Parameters: $1 - yaml file path defining projects that will be cleaned up
# $2 - regex pattern for parsing the project names
# $3 - days to keep images
function delete_old_gcr_images() {
[[ -z $1 ]] && abort "missing resource yaml path"
[[ -z $2 ]] && abort "missing regex pattern for project name"
[[ -z $3 ]] && abort "missing days to keep images"

local target_projects # delared here as local + assignment in one line always return 0 exit code
target_projects="$(grep -Eio "$2" "$1")"
[[ $? -eq 0 ]] || abort "no project found in $1"

for project in ${target_projects}; do
echo "Start deleting images from ${project}"
delete_old_images_from_gcr "gcr.io/${project}" $3
done
}
156 changes: 40 additions & 116 deletions tools/cleanup/cleanup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,147 +16,71 @@

# This is a script to clean up stale resources

source $(dirname $0)/../../scripts/library.sh
source $(dirname $0)/cleanup-functions.sh

# Global variables
DAYS_TO_KEEP_IMAGES=365 # Keep images up to 1 year by default
RE_PROJECT_NAME="knative-boskos-[a-zA-Z0-9]+"
PROJECT_RESOURCE_YAML=""
PROJECT_TO_CLEANUP=""
GCR_TO_CLEANUP=""
DRY_RUN=0

FUNCTION_TO_RUN=""


function parse_args() {
while [[ $# -ne 0 ]]; do
local parameter=$1
case ${parameter} in
--project-resource-yaml)
[[ -z $2 || $2 =~ ^-- ]] && abort "expecting value following $1"
shift
PROJECT_RESOURCE_YAML=$1
;;
--re-project-name)
[[ -z $2 || $2 =~ ^-- ]] && abort "expecting value following $1"
shift
RE_PROJECT_NAME=$1
;;
--project-to-cleanup)
[[ -z $2 || $2 =~ ^-- ]] && abort "expecting value following $1"
shift
PROJECT_TO_CLEANUP=$1
;;
--days-to-keep)
--dry-run) DRY_RUN=1 ;;
*)
[[ -z $2 || $2 =~ ^-- ]] && abort "expecting value following $1"
shift
DAYS_TO_KEEP_IMAGES=$1
;;
--dry-run)
DRY_RUN=1
;;
*) abort "unknown option ${parameter}" ;;
case ${parameter} in
--project-resource-yaml) PROJECT_RESOURCE_YAML=$1 ;;
--re-project-name) RE_PROJECT_NAME=$1 ;;
--gcr-to-cleanup) GCR_TO_CLEANUP=$1 ;;
--days-to-keep) DAYS_TO_KEEP_IMAGES=$1 ;;
--service-account)
gcloud auth activate-service-account --key-file=$1 || exit 1
;;
*) abort "unknown option ${parameter}" ;;
esac
esac
shift
done

is_int ${DAYS_TO_KEEP_IMAGES} || abort "days to keep has to be integer"

readonly DAYS_TO_KEEP_IMAGES
readonly PROJECT_RESOURCE_YAML
readonly RE_PROJECT_NAME
readonly PROJECT_TO_CLEANUP
readonly GCR_TO_CLEANUP
readonly DRY_RUN


is_int $DAYS_TO_KEEP_IMAGES || abort "days to keep has to be integer"

(( DRY_RUN )) && echo "-- Running in dry-run mode, no image deletion --"
echo "Removing images with following rules:"
case ${FUNCTION_TO_RUN} in
delete-old-gcr-images)
echo "- from projects defined in $PROJECT_RESOURCE_YAML, matching $RE_PROJECT_NAME"
;;
delete-old-gcr-images-from-project)
echo "- from project $PROJECT_TO_CLEANUP"
;;
*) ;;
esac
echo "- older than $DAYS_TO_KEEP_IMAGES days"
}

# Delete old images in given GCR project
# Parameters: $1 - gcr to be cleaned up, i.e. gcr.io/fooProj
# Parameters: $2 - days to keep images
function delete_old_gcr_images_from_project() {
local project_to_cleanup_override=$PROJECT_TO_CLEANUP
[[ $# -ge 1 ]] && project_to_cleanup_override=$1

[[ -z ${project_to_cleanup_override} ]] && abort "missing project name"
is_protected_gcr ${project_to_cleanup_override} && \
abort "\$project_to_cleanup_override set to ${project_to_cleanup_override}, which is forbidden"

for image in $(gcloud --format='value(name)' container images list --repository=${project_to_cleanup_override}); do
echo "Checking ${image} for removal"

delete_old_gcr_images_from_project ${image} ${DAYS_TO_KEEP_IMAGES}

local target_date=$(date -d "`date`-${DAYS_TO_KEEP_IMAGES}days" +%Y-%m-%d)
for digest in $(gcloud --format='get(digest)' container images list-tags ${image} \
--filter="timestamp.datetime<${target_date}" --limit=99999); do
local full_image="${image}@${digest}"
if (( $DRY_RUN )); then
echo "DRYRUN - Deleting image: $full_image"
else
echo "Deleting image: $full_image"
gcloud container images delete -q --force-delete-tags ${full_image}
fi
done
done
}

# Delete old images in GCR projects defined in yaml file provided
# Parameters: $1 - yaml file path defining projects to be cleaned up
# Parameters: $2 - regex pattern for parsing projects' names
# Parameters: $3 - days to keep images
function delete_old_gcr_images() {
local project_resource_yaml_override=$PROJECT_RESOURCE_YAML
local re_project_name_override=$RE_PROJECT_NAME
[[ $# -ge 1 ]] && project_resource_yaml_override=$1
[[ $# -ge 2 ]] && re_project_name_override=$2

[[ -z ${project_resource_yaml_override} ]] && abort "missing resource yaml path"
[[ -z ${re_project_name_override} ]] && abort "missing regex pattern after resource yaml path"

local target_projects # delared here as local + assignment in one line always return 0 exit code
target_projects=$(grep -Eio "${re_project_name_override}" "${project_resource_yaml_override}")
[[ $? -eq 0 ]] || abort "no project found in ${project_resource_yaml_override}"

for project in ${target_projects}; do
echo "Start deleting images from ${project}"
delete_old_gcr_images_from_project "gcr.io/${project}" $DAYS_TO_KEEP_IMAGES
done
}

# Script entry point

cd ${REPO_ROOT_DIR}

# Entry point
# Dispatching commands to different functions
if [[ $# -ne 0 ]]; then
case $1 in
delete-old-gcr-images)
FUNCTION_TO_RUN=$1
shift
parse_args $@
delete_old_gcr_images
;;
delete-old-gcr-images-from-project)
FUNCTION_TO_RUN=$1
shift
parse_args $@
delete_old_gcr_images_from_project
;;
*) abort "unknown option ${parameter}" ;;
esac
else
warning "no params passed in, no ops. do not source this script unless you know what you are doing"
if [[ -z $1 ]]; then
abort "missing parameters to the tool"
fi

FUNCTION_TO_RUN=$1
shift
parse_args $@

(( DRY_RUN )) && echo "-- Running in dry-run mode, no image deletion --"

echo "Removing images with following rules:"
echo "- older than ${DAYS_TO_KEEP_IMAGES} days"
case ${FUNCTION_TO_RUN} in
delete-old-gcr-images)
echo "- from projects defined in '${PROJECT_RESOURCE_YAML}', matching '${RE_PROJECT_NAME}"
delete_old_gcr_images "${PROJECT_RESOURCE_YAML}" "${RE_PROJECT_NAME}" "${DAYS_TO_KEEP_IMAGES}"
;;
delete-old-images-from-gcr)
echo "- from gcr '${GCR_TO_CLEANUP}'"
delete_old_images_from_gcr "${GCR_TO_CLEANUP}" "${DAYS_TO_KEEP_IMAGES}"
;;
*) abort "unknown option '${FUNCTION_TO_RUN}'" ;;
esac

0 comments on commit 528cba9

Please sign in to comment.