Skip to content

Commit 5b0cde1

Browse files
test: Adding missing local registry coverage
Additionaly, the test exposed a bug in removeTagFromImage() func in src/scanner/images/index.ts, which chops off everything after ':' from the image name, so as a result we store a wrong image name.
1 parent 25c4954 commit 5b0cde1

File tree

8 files changed

+177
-1
lines changed

8 files changed

+177
-1
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: 71 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';
@@ -65,6 +66,23 @@ tap.test('snyk-monitor container started', async (t) => {
6566
console.log('Done -- snyk-monitor exists!');
6667
});
6768

69+
tap.test('create local container registry and push an image', async (t) => {
70+
if (process.env['TEST_PLATFORM'] !== 'kind') {
71+
t.pass('Not testing local container registry because we\'re not running in KinD');
72+
return;
73+
}
74+
console.log('Creating local container registry...');
75+
await exec('docker run -d --restart=always -p "5000:5000" --name "kind-registry" registry:2');
76+
await exec('docker network connect "kind" "kind-registry"');
77+
78+
console.log('Pushing python:rc-buster image to the local registry');
79+
//Note: this job takes a while and waitForJob() should be called before trying to access local registry image,
80+
//to make sure it completed
81+
await kubectl.applyK8sYaml('./test/fixtures/insecure-registries/push-dockerhub-image-to-local-registry.yaml');
82+
83+
t.pass('successfully started a job to push image to a local registry');
84+
});
85+
6886
tap.test('snyk-monitor sends data to kubernetes-upstream', async (t) => {
6987
t.plan(7);
7088

@@ -226,6 +244,59 @@ tap.test('snyk-monitor pulls images from a private ECR and sends data to kuberne
226244
'snyk-monitor sent expected data to upstream in the expected timeframe');
227245
});
228246

247+
tap.test('snyk-monitor pulls images from a local registry and sends data to kubernetes-upstream', async (t) => {
248+
t.teardown(async () => {
249+
console.log('Begin removing local container registry...');
250+
await setup.removeLocalContainerRegistry();
251+
console.log('Removed local container registry');
252+
console.log('Begin removing "kind" network...');
253+
await setup.removeUnusedKindNetwork();
254+
console.log('Removed "kind" network');
255+
});
256+
257+
if (process.env['TEST_PLATFORM'] !== 'kind') {
258+
t.pass('Not testing local container registry because we\'re not running in KinD');
259+
return;
260+
}
261+
t.plan(4);
262+
263+
const deploymentName = 'python-local';
264+
const namespace = 'services';
265+
const clusterName = 'Default cluster';
266+
const deploymentType = WorkloadKind.Deployment;
267+
const imageName = 'kind-registry:5000/python:rc-buster';
268+
269+
await kubectl.waitForJob('push-to-local-registry', 'default');
270+
271+
console.log('Applying local registry workload...');
272+
await kubectl.applyK8sYaml('./test/fixtures/insecure-registries/python-local-deployment.yaml');
273+
274+
console.log(`Begin polling upstream for the expected kind-registry:5000 image with integration ID ${integrationId}...`);
275+
276+
const validatorFn: WorkloadLocatorValidator = (workloads) => {
277+
return workloads !== undefined &&
278+
workloads.find((workload) => workload.name === deploymentName &&
279+
workload.type === deploymentType) !== undefined;
280+
};
281+
282+
const testResult = await validateUpstreamStoredData(
283+
validatorFn, `api/v2/workloads/${integrationId}/${clusterName}/${namespace}`);
284+
t.ok(testResult, 'snyk-monitor sent expected data to upstream in the expected timeframe');
285+
286+
const depGraphResult = await getUpstreamResponseBody(
287+
`api/v1/dependency-graphs/${integrationId}/${clusterName}/${namespace}/${deploymentType}/${deploymentName}`);
288+
289+
t.ok('dependencyGraphResults' in depGraphResult,
290+
'expected dependencyGraphResults field to exist in /dependency-graphs response');
291+
292+
/* Because of a bug in removeTagFromImage() func in src/scanner/images/index.ts,
293+
which chops off everything after ':' from the image name, we store a wrong image name
294+
and the result does not exist in the object referred below */
295+
t.same(depGraphResult.dependencyGraphResults[imageName], null,
296+
'expected result for image kind-registry:5000/python:rc-buster does not exist');
297+
t.ok('kind-registry' in depGraphResult.dependencyGraphResults, 'BUG: the full image name is not stored in kubernetes-upstream');
298+
});
299+
229300
tap.test('snyk-monitor sends deleted workload to kubernetes-upstream', async (t) => {
230301
// First ensure the deployment exists from the previous test
231302
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: 3 additions & 1 deletion
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

0 commit comments

Comments
 (0)