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

Make annotating resources optional #287

Merged
merged 37 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c9bfbf9
Make annotating resources optional
bramdehart May 24, 2023
43cb5b6
Clarify descriptions
bramdehart May 24, 2023
2c91d4c
Update README
bramdehart May 24, 2023
a3a277b
Refactor retrieving pods
bramdehart Jun 1, 2023
4c8a530
Remove annotating resources check in deploy.ts
bramdehart Jun 1, 2023
2865116
Add resource annotation integration test
bramdehart Jun 1, 2023
71831b0
Move resource annotation integration test to seperate file
bramdehart Aug 9, 2023
cd77b32
Lint code
bramdehart Aug 9, 2023
ebf5ee6
Remove temporary debugging statements
bramdehart Aug 9, 2023
43b9310
Fix integration test name
bramdehart Aug 9, 2023
6f593dd
Fix test
bramdehart Aug 9, 2023
fd023f5
Abstracting out repeated logic between verifyDeployment and verifySer…
bramdehart Sep 5, 2023
81f050b
Fix formattin
bramdehart Sep 5, 2023
a4069fd
Fix reference
bramdehart Sep 5, 2023
abcfa71
Fix test
bramdehart Sep 5, 2023
98d9095
Refactor test
bramdehart Sep 5, 2023
a49dc0f
Update ubuntu version to latest on canary SMI test
bramdehart Sep 6, 2023
ccedd24
Update ubuntu version to latest on canary SMI test
bramdehart Sep 6, 2023
40edeef
Merge branch 'main' of github.com:bramdehart/k8s-deploy
bramdehart Oct 13, 2023
5f7a33c
Make annotating resources optional
bramdehart May 24, 2023
6b8c3c0
Clarify descriptions
bramdehart May 24, 2023
9164243
Update README
bramdehart May 24, 2023
1d17e9d
Refactor retrieving pods
bramdehart Jun 1, 2023
c57dcdd
Remove annotating resources check in deploy.ts
bramdehart Jun 1, 2023
655f5e7
Add resource annotation integration test
bramdehart Jun 1, 2023
e220b8c
Move resource annotation integration test to seperate file
bramdehart Aug 9, 2023
c18bc40
Lint code
bramdehart Aug 9, 2023
f257bd2
Remove temporary debugging statements
bramdehart Aug 9, 2023
2ac37a9
Fix integration test name
bramdehart Aug 9, 2023
3c8c1dd
Fix test
bramdehart Aug 9, 2023
0020a07
Abstracting out repeated logic between verifyDeployment and verifySer…
bramdehart Sep 5, 2023
b099d8e
Fix formattin
bramdehart Sep 5, 2023
3c39b35
Fix reference
bramdehart Sep 5, 2023
449e2d3
Fix test
bramdehart Sep 5, 2023
b2babe2
Refactor test
bramdehart Sep 5, 2023
b474cda
Update ubuntu version to latest on canary SMI test
bramdehart Sep 6, 2023
e3491e0
Merge branch 'main' of github.com:bramdehart/k8s-deploy
bramdehart Oct 13, 2023
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: 1 addition & 1 deletion .github/workflows/run-integration-tests-canary-smi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
jobs:
run-integration-test:
name: Run Minikube Integration Tests
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
env:
KUBECONFIG: /home/runner/.kube/config
NAMESPACE: test-${{ github.run_id }}
Expand Down
89 changes: 89 additions & 0 deletions .github/workflows/run-integration-tests-resource-annotation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Minikube Integration Tests - resource annotation
on:
pull_request:
branches:
- main
- 'releases/*'
push:
branches:
- main
- 'releases/*'
workflow_dispatch:

jobs:
run-integration-test:
name: Run Minikube Integration Tests
runs-on: ubuntu-latest
env:
KUBECONFIG: /home/runner/.kube/config
NAMESPACE: test-${{ github.run_id }}
steps:
- uses: actions/checkout@v3

- name: Install dependencies
run: |
rm -rf node_modules/
npm install
- name: Install ncc
run: npm i -g @vercel/ncc
- name: Install conntrack
run: sudo apt-get install -y conntrack
- name: Build
run: ncc build src/run.ts -o lib

- uses: Azure/setup-kubectl@v3
name: Install Kubectl

- id: setup-minikube
name: Setup Minikube
uses: medyagh/setup-minikube@latest
with:
minikube-version: 1.24.0
kubernetes-version: 1.22.3
driver: 'none'
timeout-minutes: 3

- name: Create namespace to run tests
run: kubectl create ns ${{ env.NAMESPACE }}

- uses: actions/setup-python@v2
name: Install Python
with:
python-version: '3.x'

- name: Cleaning any previously created items
run: |
python test/integration/k8s-deploy-delete.py 'Service' 'all' ${{ env.NAMESPACE }}
python test/integration/k8s-deploy-delete.py 'Deployment' 'all' ${{ env.NAMESPACE }}
python test/integration/k8s-deploy-delete.py 'Ingress' 'all' ${{ env.NAMESPACE }}

- name: Executing deploy action for pod with resource annotation enabled by default
uses: ./
with:
namespace: ${{ env.NAMESPACE }}
images: nginx:1.14.2
manifests: |
test/integration/manifests/test.yml
action: deploy

- name: Checking if deployments is created with additional resource annotation
run: |
python test/integration/k8s-deploy-test.py namespace=${{ env.NAMESPACE }} kind=Deployment name=nginx-deployment containerName=nginx:1.14.2 labels=app:nginx,workflow:actions.github.com-k8s-deploy,workflowFriendlyName:Minikube_Integration_Tests_-_resource_annotation selectorLabels=app:nginx annotations=actions.github.com/k8s-deploy,deployment.kubernetes.io/revision,kubectl.kubernetes.io/last-applied-configuration

- name: Cleaning previously created deployment
run: |
python test/integration/k8s-deploy-delete.py 'Deployment' 'all' ${{ env.NAMESPACE }}

- name: Executing deploy action for pod with resource annotation disabled
uses: ./
with:
namespace: ${{ env.NAMESPACE }}
images: nginx:1.14.2
manifests: |
test/integration/manifests/test.yml
action: deploy
annotate-resources: false

- name: Checking if deployment is created without additional resource annotation
run: |
python test/integration/k8s-deploy-test.py namespace=${{ env.NAMESPACE }} kind=Deployment name=nginx-deployment containerName=nginx:1.14.2 selectorLabels=app:nginx annotations=deployment.kubernetes.io/revision,kubectl.kubernetes.io/last-applied-configuration
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,13 @@ Following are the key capabilities of this action:
<td>force </br></br>(Optional)</td>
<td>Deploy when a previous deployment already exists. If true then '--force' argument is added to the apply command. Using '--force' argument is not recommended in production.</td>
</tr>
<tr>
<td>annotate-resources</br></br>(Optional)</td>
<td>Acceptable values: true/false</br>Default value: true</br>Switch whether to annotate the resources or not. If set to false all annotations are skipped completely.</td>
</tr>
<tr>
<td>annotate-namespace</br></br>(Optional)</td>
<td>Acceptable values: true/false</br>Default value: true</br>Switch whether to annotate the namespace resources object or not</td>
<td>Acceptable values: true/false</br>Default value: true</br>Switch whether to annotate the namespace resources object or not. Ignored when annotate-resources is set to false.</td>
</tr>
<tr>
<td>skip-tls-verify</br></br>(Optional)</td>
Expand Down
6 changes: 5 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,12 @@ inputs:
description: 'Github token'
default: ${{ github.token }}
required: true
annotate-resources:
description: 'Annotate the resources. If set to false all annotations are skipped completely.'
required: false
default: true
annotate-namespace:
description: 'Annotate the target namespace'
description: 'Annotate the target namespace. Ignored when annotate-resources is set to false.'
required: false
default: true
private-cluster:
Expand Down
9 changes: 1 addition & 8 deletions src/actions/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,10 @@ export async function deploy(

// annotate resources
core.startGroup('Annotating resources')
let allPods
try {
allPods = JSON.parse((await kubectl.getAllPods()).stdout)
} catch (e) {
core.debug(`Unable to parse pods: ${e}`)
}
await annotateAndLabelResources(
deployedManifestFiles,
kubectl,
resourceTypes,
allPods
resourceTypes
)
core.endGroup()
}
21 changes: 2 additions & 19 deletions src/actions/promote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,19 +129,13 @@ async function promoteCanary(kubectl: Kubectl, manifests: string[]) {

// annotate resources
core.startGroup('Annotating resources')
let allPods
try {
allPods = JSON.parse((await kubectl.getAllPods()).stdout)
} catch (e) {
core.debug(`Unable to parse pods: ${e}`)
}
const resources: Resource[] = getResources(
filesToAnnotate,
models.DEPLOYMENT_TYPES.concat([
models.DiscoveryAndLoadBalancerResource.SERVICE
])
)
await annotateAndLabelResources(filesToAnnotate, kubectl, resources, allPods)
await annotateAndLabelResources(filesToAnnotate, kubectl, resources)
core.endGroup()
}

Expand Down Expand Up @@ -219,17 +213,6 @@ async function promoteBlueGreen(kubectl: Kubectl, manifests: string[]) {

// annotate resources
core.startGroup('Annotating resources')
let allPods
try {
allPods = JSON.parse((await kubectl.getAllPods()).stdout)
} catch (e) {
core.debug(`Unable to parse pods: ${e}`)
}
await annotateAndLabelResources(
deployedManifestFiles,
kubectl,
resources,
allPods
)
await annotateAndLabelResources(deployedManifestFiles, kubectl, resources)
core.endGroup()
}
34 changes: 19 additions & 15 deletions src/strategyHelpers/deploymentHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,7 @@ export async function checkManifestStability(
export async function annotateAndLabelResources(
files: string[],
kubectl: Kubectl,
resourceTypes: Resource[],
allPods: any
resourceTypes: Resource[]
) {
const defaultWorkflowFileName = 'k8s-deploy-failed-workflow-annotation'
const githubToken = core.getInput('token')
Expand All @@ -163,15 +162,20 @@ export async function annotateAndLabelResources(
const deploymentConfig = await getDeploymentConfig()
const annotationKeyLabel = getWorkflowAnnotationKeyLabel()

await annotateResources(
files,
kubectl,
resourceTypes,
allPods,
annotationKeyLabel,
workflowFilePath,
deploymentConfig
).catch((err) => core.warning(`Failed to annotate resources: ${err} `))
const shouldAnnotateResources = !(
core.getInput('annotate-resources').toLowerCase() === 'false'
)

if (shouldAnnotateResources) {
await annotateResources(
files,
kubectl,
resourceTypes,
annotationKeyLabel,
workflowFilePath,
deploymentConfig
).catch((err) => core.warning(`Failed to annotate resources: ${err} `))
}

await labelResources(files, kubectl, annotationKeyLabel).catch((err) =>
core.warning(`Failed to label resources: ${err}`)
Expand All @@ -182,7 +186,6 @@ async function annotateResources(
files: string[],
kubectl: Kubectl,
resourceTypes: Resource[],
allPods: any,
annotationKey: string,
workflowFilePath: string,
deploymentConfig: DeploymentConfig
Expand Down Expand Up @@ -226,11 +229,13 @@ async function annotateResources(
)
)
}

for (const file of files) {
try {
const annotateResult = await kubectl.annotateFiles(
file,
annotationKeyValStr
annotationKeyValStr,
namespace
)
annotateResults.push(annotateResult)
} catch (e) {
Expand All @@ -249,8 +254,7 @@ async function annotateResources(
resource.type,
resource.name,
resource.namespace,
annotationKeyValStr,
allPods
annotationKeyValStr
)
).forEach((execResult) => annotateResults.push(execResult))
}
Expand Down
11 changes: 9 additions & 2 deletions src/utilities/kubectlUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,22 @@ export async function annotateChildPods(
resourceType: string,
resourceName: string,
namespace: string | undefined,
annotationKeyValStr: string,
allPods
annotationKeyValStr: string
): Promise<ExecOutput[]> {
let owner = resourceName
if (resourceType.toLowerCase().indexOf('deployment') > -1) {
owner = await kubectl.getNewReplicaSet(resourceName, namespace)
}

const commandExecutionResults = []

let allPods
try {
allPods = JSON.parse((await kubectl.getAllPods()).stdout)
} catch (e) {
core.debug(`Unable to parse pods: ${e}`)
}

if (allPods?.items && allPods.items?.length > 0) {
allPods.items.forEach((pod) => {
const owners = pod?.metadata?.ownerReferences
Expand Down
4 changes: 2 additions & 2 deletions test/integration/k8s-deploy-delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def delete(kind, name, namespace):
if (name == "all"):
print('kubectl delete --all' + kind + ' -n ' + namespace)
deletion = subprocess.Popen(
['kubectl', 'delete', kind, name, '--namespace', namespace])
['kubectl', 'delete', kind, '--all', '--namespace', namespace])
result, err = deletion.communicate()
else:
print('kubectl delete ' + kind + ' ' + name + ' -n ' + namespace)
Expand All @@ -21,7 +21,7 @@ def delete(kind, name, namespace):
def main():
kind = sys.argv[1]
name = sys.argv[2]
namespace = 'test-' + sys.argv[3]
namespace = sys.argv[3]
delete(kind, name, namespace)


Expand Down
36 changes: 21 additions & 15 deletions test/integration/k8s-deploy-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ def parseArgs(sysArgs):
argsDict[labelsKey] = stringListToDict(
argsDict[labelsKey].split(","), ":")

if annotationsKey in argsDict:
argsDict[annotationsKey] = stringListToDict(
argsDict[annotationsKey].split(","), ":")

if selectorLabelsKey in argsDict:
argsDict[selectorLabelsKey] = stringListToDict(
argsDict[selectorLabelsKey].split(","), ":")
Expand All @@ -60,6 +56,9 @@ def parseArgs(sysArgs):
if ingressServicesKey in argsDict:
argsDict[ingressServicesKey] = argsDict[ingressServicesKey].split(",")

if annotationsKey in argsDict:
argsDict[annotationsKey] = argsDict[annotationsKey].split(",")

return argsDict


Expand Down Expand Up @@ -98,14 +97,14 @@ def verifyDeployment(deployment, parsedArgs):
return dictMatch, msg

if annotationsKey in parsedArgs:
dictMatch, msg = compareDicts(
deployment['metadata']['annotations'], parsedArgs[annotationsKey], annotationsKey)
if not dictMatch:
return dictMatch, msg

if len(parsedArgs[annotationsKey]) != len(deployment['metadata']['annotations']):
return False, f"expected {len(parsedArgs[annotationsKey])} annotations but found {len(deployment['metadata']['annotations'])}"
keysPresent, msg = validateKeyPresence(
deployment['metadata']['annotations'], parsedArgs[annotationsKey])
if not keysPresent:
return keysPresent, msg
return True, ""


def verifyService(service, parsedArgs):
# test selector labels, labels, annotations
if not selectorLabelsKey in parsedArgs:
Expand All @@ -124,10 +123,10 @@ def verifyService(service, parsedArgs):
return dictMatch, msg

if annotationsKey in parsedArgs:
dictMatch, msg = compareDicts(
service['metadata']['annotations'], parsedArgs[annotationsKey], annotationsKey)
if not dictMatch:
return dictMatch, msg
keysPresent, msg = validateKeyPresence(
service['metadata']['annotations'], parsedArgs[annotationsKey])
if not keysPresent:
return keysPresent, msg

return True, ""

Expand Down Expand Up @@ -188,6 +187,13 @@ def compareDicts(actual: dict, expected: dict, paramName=""):

return True, ""

def validateKeyPresence(actualDict: dict, expectedKeys: list):
actualKeys = actualDict.keys()
for key in expectedKeys:
if key not in actualKeys:
return False, f"expected key {key} not found in actual dict. \n actual dict keys {','.join(actualKeys)}"

return True, ""

def main():
parsedArgs: dict = parseArgs(sys.argv[1:])
Expand Down Expand Up @@ -220,7 +226,7 @@ def main():

if k8_object == None:
raise ValueError(f"{kind} {name} was not found")

except:
msg = kind+' '+name+' not created or not found'
getAllObjectsCmd = azPrefix + 'kubectl get '+kind+' -n '+namespace
Expand Down
Loading