Skip to content

Commit 18b68f3

Browse files
Merge pull request #499 from snyk/test/add-local-registry-coverage
Test/add local registry coverage
2 parents 809e536 + aef7965 commit 18b68f3

File tree

9 files changed

+168
-3
lines changed

9 files changed

+168
-3
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
apiVersion: batch/v1
2+
kind: Job
3+
metadata:
4+
name: push-to-local-registry
5+
spec:
6+
template:
7+
spec:
8+
containers:
9+
- name: my-container
10+
image: golang:1.13.1-alpine3.10
11+
command:
12+
- "sh"
13+
args:
14+
- "-c"
15+
- "apk --no-cache add git make gcc musl-dev ostree-dev go-md2man &&
16+
git clone --depth 1 -b 'v0.2.0' https://github.com/containers/skopeo $GOPATH/src/github.com/containers/skopeo &&
17+
cd $GOPATH/src/github.com/containers/skopeo &&
18+
make binary-local-static DISABLE_CGO=1 &&
19+
make install &&
20+
skopeo copy --dest-tls-verify=false docker://python:rc-buster docker://kind-registry:5000/python:rc-buster"
21+
restartPolicy: Never
22+
backoffLimit: 4
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: python-local
5+
namespace: services
6+
labels:
7+
app.kubernetes.io/name: python-local
8+
spec:
9+
replicas: 1
10+
selector:
11+
matchLabels:
12+
app.kubernetes.io/name: python-local
13+
template:
14+
metadata:
15+
labels:
16+
app.kubernetes.io/name: python-local
17+
spec:
18+
containers:
19+
- image: kind-registry:5000/python:rc-buster
20+
imagePullPolicy: Always
21+
name: python-local
22+
command: ['/bin/sleep']
23+
args: ['9999999']
24+
securityContext: {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[[registry]]
2+
location = "kind-registry:5000"
3+
insecure = true

test/helpers/kubectl.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ export async function createSecret(
6464
console.log(`Created secret ${secretName}`);
6565
}
6666

67+
export async function createConfigMap(
68+
configMapName: string,
69+
namespace: string,
70+
filePath: string
71+
): Promise<void> {
72+
console.log(`Creating config map ${configMapName} in namespace ${namespace}...`);
73+
await exec(`./kubectl create configmap ${configMapName} -n ${namespace} --from-file=${filePath}`);
74+
console.log(`Created config map ${configMapName}`);
75+
}
76+
6777
export async function applyK8sYaml(pathToYamlDeployment: string): Promise<void> {
6878
console.log(`Applying ${pathToYamlDeployment}...`);
6979
await exec(`./kubectl apply -f ${pathToYamlDeployment}`);
@@ -145,6 +155,22 @@ export async function waitForServiceAccount(name: string, namespace: string): Pr
145155
}
146156
}
147157

158+
export async function waitForJob(name: string, namespace: string): Promise<void> {
159+
console.log(`Trying to find job ${name} in namespace ${namespace}`);
160+
for (let attempt = 0; attempt < 60; attempt++) {
161+
try {
162+
await exec(`./kubectl get jobs/${name} -n ${namespace}`);
163+
} catch (error) {
164+
await sleep(1000);
165+
}
166+
}
167+
console.log(`Found job ${name} in namespace ${namespace}`);
168+
169+
console.log(`Begin waiting for job ${name} in namespace ${namespace} to complete`);
170+
await exec(`./kubectl wait --for=condition=complete jobs/${name} -n ${namespace} --timeout=240s`);
171+
console.log(`Job ${name} in namespace ${namespace} is complete`);
172+
}
173+
148174
async function getLatestStableK8sRelease(): Promise<string> {
149175
const k8sRelease = await needle('get',
150176
'https://storage.googleapis.com/kubernetes-release/release/stable.txt',

test/integration/kubernetes.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CoreV1Api, KubeConfig, AppsV1Api } from '@kubernetes/client-node';
2+
import { exec } from 'child-process-promise';
23
import setup = require('../setup');
34
import * as tap from 'tap';
45
import { WorkloadKind } from '../../src/supervisor/types';
@@ -21,6 +22,12 @@ tap.tearDown(async() => {
2122
console.log('Begin removing the snyk-monitor...');
2223
await setup.removeMonitor();
2324
console.log('Removed the snyk-monitor!');
25+
console.log('Begin removing local container registry...');
26+
await setup.removeLocalContainerRegistry();
27+
console.log('Removed local container registry');
28+
console.log('Begin removing "kind" network...');
29+
await setup.removeUnusedKindNetwork();
30+
console.log('Removed "kind" network');
2431
});
2532

2633
// Make sure this runs first -- deploying the monitor for the next tests
@@ -65,6 +72,19 @@ tap.test('snyk-monitor container started', async (t) => {
6572
console.log('Done -- snyk-monitor exists!');
6673
});
6774

75+
tap.test('create local container registry and push an image', async (t) => {
76+
console.log('Creating local container registry...');
77+
await exec('docker run -d --restart=always -p "5000:5000" --name "kind-registry" registry:2');
78+
await exec('docker network connect "kind" "kind-registry"');
79+
80+
console.log('Pushing python:rc-buster image to the local registry');
81+
//Note: this job takes a while and waitForJob() should be called before trying to access local registry image,
82+
//to make sure it completed
83+
await kubectl.applyK8sYaml('./test/fixtures/insecure-registries/push-dockerhub-image-to-local-registry.yaml');
84+
85+
t.pass('successfully started a job to push image to a local registry');
86+
});
87+
6888
tap.test('snyk-monitor sends data to kubernetes-upstream', async (t) => {
6989
t.plan(7);
7090

@@ -226,6 +246,46 @@ tap.test('snyk-monitor pulls images from a private ECR and sends data to kuberne
226246
'snyk-monitor sent expected data to upstream in the expected timeframe');
227247
});
228248

249+
tap.test('snyk-monitor pulls images from a local registry and sends data to kubernetes-upstream', async (t) => {
250+
t.plan(4);
251+
252+
const deploymentName = 'python-local';
253+
const namespace = 'services';
254+
const clusterName = 'Default cluster';
255+
const deploymentType = WorkloadKind.Deployment;
256+
const imageName = 'kind-registry:5000/python:rc-buster';
257+
258+
await kubectl.waitForJob('push-to-local-registry', 'default');
259+
260+
console.log('Applying local registry workload...');
261+
await kubectl.applyK8sYaml('./test/fixtures/insecure-registries/python-local-deployment.yaml');
262+
263+
console.log(`Begin polling upstream for the expected kind-registry:5000 image with integration ID ${integrationId}...`);
264+
265+
const validatorFn: WorkloadLocatorValidator = (workloads) => {
266+
return workloads !== undefined &&
267+
workloads.find((workload) => workload.name === deploymentName &&
268+
workload.type === WorkloadKind.Deployment) !== undefined;
269+
};
270+
271+
const testResult = await validateUpstreamStoredData(
272+
validatorFn, `api/v2/workloads/${integrationId}/${clusterName}/${namespace}`);
273+
t.ok(testResult, 'snyk-monitor sent expected data to upstream in the expected timeframe');
274+
275+
const depGraphResult = await getUpstreamResponseBody(
276+
`api/v1/dependency-graphs/${integrationId}/${clusterName}/${namespace}/${deploymentType}/${deploymentName}`);
277+
278+
t.ok('dependencyGraphResults' in depGraphResult,
279+
'expected dependencyGraphResults field to exist in /dependency-graphs response');
280+
281+
/* Because of a bug in removeTagFromImage() func in src/scanner/images/index.ts,
282+
which chops off everything after ':' from the image name, we store a wrong image name
283+
and the result does not exist in the object referred below */
284+
t.same(depGraphResult.dependencyGraphResults[imageName], null,
285+
'expected result for image kind-registry:5000/python:rc-buster does not exist');
286+
t.ok('kind-registry' in depGraphResult.dependencyGraphResults, 'BUG: the full image name is not stored in kubernetes-upstream');
287+
});
288+
229289
tap.test('snyk-monitor sends deleted workload to kubernetes-upstream', async (t) => {
230290
// First ensure the deployment exists from the previous test
231291
const deploymentValidatorFn: WorkloadLocatorValidator = (workloads) => {

test/setup/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as fs from 'fs';
22
import * as sleep from 'sleep-promise';
33
import * as uuidv4 from 'uuid/v4';
4+
import { exec } from 'child-process-promise';
45

56
import platforms, { getKubernetesVersionForPlatform } from './platforms';
67
import deployers from './deployers';
@@ -37,6 +38,22 @@ export async function removeMonitor(): Promise<void> {
3738
}
3839
}
3940

41+
export async function removeLocalContainerRegistry(): Promise<void> {
42+
try {
43+
await exec('docker rm kind-registry --force');
44+
} catch (error) {
45+
console.log(`Could not remove container registry, it probably did not exist: ${error.message}`);
46+
}
47+
}
48+
49+
export async function removeUnusedKindNetwork(): Promise<void> {
50+
try {
51+
await exec('docker network rm kind');
52+
} catch (error) {
53+
console.log(`Could not remove "kind" network: ${error.message}`);
54+
}
55+
}
56+
4057
async function createEnvironment(): Promise<void> {
4158
// TODO: we probably want to use k8s-api for that, not kubectl
4259
await kubectl.createNamespace('services');
@@ -56,6 +73,7 @@ async function predeploy(integrationId: string): Promise<void> {
5673
'dockercfg.json': gcrDockercfg,
5774
integrationId,
5875
});
76+
await createRegistriesConfigMap();
5977
} catch (error) {
6078
console.log('Could not create namespace and secret, they probably already exist');
6179
}
@@ -80,6 +98,10 @@ async function createSecretForGcrIoAccess(): Promise<void> {
8098
);
8199
}
82100

101+
async function createRegistriesConfigMap(): Promise<void> {
102+
await kubectl.createConfigMap('snyk-monitor-registries-conf', 'snyk-monitor', './test/fixtures/insecure-registries/registries.conf');
103+
}
104+
83105
export async function deployMonitor(): Promise<string> {
84106
console.log('Begin deploying the snyk-monitor...');
85107

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: Cluster
2+
apiVersion: kind.x-k8s.io/v1alpha4
3+
containerdConfigPatches:
4+
- |-
5+
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."kind-registry:5000"]
6+
endpoint = ["http://kind-registry:5000"]

test/setup/platforms/kind.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ export async function createCluster(version: string): Promise<void> {
2121
// which does not necessarily have the "latest" tag
2222
kindImageArgument = `--image="kindest/node:${kindImageTag}"`;
2323
}
24-
await exec(`./kind create cluster --name="${clusterName}" ${kindImageArgument}`);
24+
const clusterConfigPath = "test/setup/platforms/cluster-config.yaml";
25+
26+
await exec(`./kind create cluster --name="${clusterName}" ${kindImageArgument} --config="${clusterConfigPath}"`);
2527
console.log(`Created cluster ${clusterName}!`);
2628
}
2729

@@ -59,7 +61,7 @@ async function download(osDistro: string): Promise<void> {
5961
} catch (error) {
6062
console.log('Downloading KinD...');
6163

62-
const url = `https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-${osDistro}-amd64`;
64+
const url = `https://github.com/kubernetes-sigs/kind/releases/download/v0.8.1/kind-${osDistro}-amd64`;
6365
await exec(`curl -Lo ./kind ${url}`);
6466
chmodSync('kind', 0o755); // rwxr-xr-x
6567

test/system/kind.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ tap.test('Kubernetes-Monitor with KinD', async (t) => {
3636
// linux-oriented, not mac
3737
// for mac, install skopeo with brew
3838
console.log('installing Skopeo');
39-
await exec('git clone https://github.com/containers/skopeo');
39+
await exec('git clone --depth 1 -b "v0.2.0" https://github.com/containers/skopeo');
4040
await exec('(cd skopeo && make binary-static DISABLE_CGO=1)');
4141
await exec('sudo mkdir -p /etc/containers');
4242
await exec('sudo chown circleci:circleci /etc/containers');

0 commit comments

Comments
 (0)