Skip to content

Commit e007d13

Browse files
authored
feat: collect deprecated images metric (CR-26713) (#138)
1 parent 86e84f8 commit e007d13

23 files changed

+786
-78
lines changed

.dockerignore

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ lib/state.json
88
.eslintrc.json
99
test
1010
.eslintignore
11+
dist

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Ignore built files except build/index.js
44
build/*
55
!build/index.js
6+
dist/*
67
coverage/*
78

89
# Directory for instrumented libs generated by jscoverage/JSCover

.eslintrc.json

+39-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"impliedStrict": true
1515
}
1616
},
17-
17+
1818
"plugins": [
1919
"chai-friendly",
2020
"import",
@@ -85,9 +85,45 @@
8585

8686
"node/no-unsupported-features": "error",
8787
"node/process-exit-as-throw": "error",
88-
"node/shebang": "warn",
88+
"node/shebang": "off",
8989
"node/no-deprecated-api": "warn",
9090
"no-useless-constructor": "warn",
9191
"no-return-await": "off"
92-
}
92+
},
93+
94+
"overrides": [
95+
{
96+
"files": ["**/*.ts"],
97+
"parser": "@typescript-eslint/parser",
98+
"plugins": ["@typescript-eslint/eslint-plugin"],
99+
"extends": ["plugin:@typescript-eslint/recommended"],
100+
"parserOptions": {
101+
"project": "tsconfig.json",
102+
"sourceType": "module"
103+
},
104+
"env": {
105+
"node": true
106+
},
107+
"rules": {
108+
"no-restricted-syntax": "warn",
109+
"import/prefer-default-export": "off",
110+
"node/no-unsupported-features": "off",
111+
"node/no-unsupported-features/es-builtins": "error",
112+
"node/no-unsupported-features/es-syntax": ["error", {
113+
"ignores": ["modules"]
114+
}],
115+
"node/no-unsupported-features/node-builtins": "error",
116+
"no-empty-function": "warn",
117+
"lines-between-class-members": "off",
118+
"@typescript-eslint/no-explicit-any": "warn",
119+
"@typescript-eslint/no-var-requires": "warn",
120+
"@typescript-eslint/no-unused-vars": ["error", {
121+
"argsIgnorePattern": "^_",
122+
"varsIgnorePattern": "^_",
123+
"caughtErrorsIgnorePattern": "^_"
124+
}
125+
]
126+
}
127+
}
128+
]
93129
}

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ state.json
1010
.idea
1111
.vscode
1212
lib/manual-test.js
13+
dist/

Dockerfile

+11-3
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,30 @@ RUN adduser --disabled-password -home /home/cfu -shell /bin/bash cfu
33
WORKDIR /root/cf-runtime
44
COPY package.json yarn.lock ./
55

6-
FROM base AS dependencies
6+
FROM base AS build-dependencies
77
RUN apt-get update \
88
&& apt upgrade -y \
99
&& apt-get install -y \
1010
g++ \
1111
git \
1212
make \
1313
python3
14+
15+
FROM build-dependencies AS build
16+
RUN yarn install --frozen-lockfile
17+
COPY . .
18+
RUN yarn build
19+
20+
FROM build-dependencies AS prod-dependencies
1421
RUN yarn install --frozen-lockfile --production
1522

1623
FROM base AS production
17-
COPY --from=dependencies /root/cf-runtime/node_modules ./node_modules
24+
COPY --from=prod-dependencies /root/cf-runtime/node_modules ./node_modules
25+
COPY --from=build /root/cf-runtime/dist ./dist
1826
COPY . .
1927

2028
#purpose of security
2129
RUN npm -g uninstall npm
2230

2331
USER cfu
24-
CMD ["node", "lib/index.js"]
32+
CMD ["node", "dist/index.js"]

lib/@types/index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
declare module 'cf-logs';

lib/ContainerLogger.js

+19-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ const promiseRetry = require('promise-retry');
44
const logger = require('cf-logs').Logger('codefresh:containerLogger');
55
const CFError = require('cf-errors');
66
const { Transform } = require('stream');
7+
78
const _ = require('lodash');
89
const { LoggerStrategy } = require('./enums');
910

11+
// eslint-disable-next-line import/no-unresolved
12+
const { DeprecatedImagesInterceptorStream } = require('./metric/deprecated-images/deprecated-images-interceptor.stream');
13+
1014
const CONTAINER_START_RETRY_TIMEOUT_SECONDS = 1;
1115
const CONTAINER_START_RETRY_LIMIT = 10;
1216
const BUFFER_SIZE = 2 * 1024 * 1024; // 2 MiB
@@ -131,6 +135,7 @@ class ContainerLogger extends EventEmitter {
131135
// { end = false } on the stepLoggerWritableStream because there is only one instance of it for all the steps.
132136
this.handledStreams++;
133137
let stdoutStream = stdout
138+
.pipe(new DeprecatedImagesInterceptorStream())
134139
.pipe(this._logSizeLimitStream())
135140
.pipe(this.stepLogger.createMaskingStream());
136141

@@ -148,6 +153,7 @@ class ContainerLogger extends EventEmitter {
148153

149154
this.handledStreams++;
150155
let stderrStream = stderr
156+
.pipe(new DeprecatedImagesInterceptorStream())
151157
.pipe(this._logSizeLimitStream())
152158
.pipe(this._errorTransformerStream())
153159
.pipe(this.stepLogger.createMaskingStream());
@@ -180,27 +186,38 @@ class ContainerLogger extends EventEmitter {
180186

181187
_handleTtyStream(stream, isError) {
182188
this.handledStreams++;
183-
stream.on('end', this._handleFinished.bind(this));
189+
const deprecatedImagesInterceptor = new DeprecatedImagesInterceptorStream(true);
190+
stream.on('end', () => {
191+
this._handleFinished();
192+
deprecatedImagesInterceptor.end();
193+
});
184194
stream.on('data', (chunk) => {
195+
deprecatedImagesInterceptor.write(chunk);
185196
this._logMessage(Buffer.from(chunk).toString('utf-8'), isError);
186197
});
187198
logger.info(`Listening on stream 'data' event for container: ${this.containerId}`);
188199
}
189200

190201
_handleNonTtyStream(stream, isError) {
191202
this.handledStreams++;
203+
const deprecatedImagesInterceptor = new DeprecatedImagesInterceptorStream(true);
192204
stream.on('readable', () => {
193205
let header = stream.read(8);
194206
while (header !== null) {
207+
deprecatedImagesInterceptor.write(header);
195208
const payload = stream.read(header.readUInt32BE(4));
196209
if (payload === null) {
197210
break;
198211
}
212+
deprecatedImagesInterceptor.write(payload);
199213
this._logMessage(Buffer.from(payload).toString('utf8'), isError);
200214
header = stream.read(8);
201215
}
202216
});
203-
stream.on('end', this._handleFinished.bind(this));
217+
stream.on('end', () => {
218+
this._handleFinished();
219+
deprecatedImagesInterceptor.end();
220+
});
204221
logger.info(`Listening on stream 'readable' event for container: ${this.containerId}`);
205222
}
206223

lib/forever.ps1

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
while ($true) {
22
Start-Sleep -s 1
3-
& node lib/index.js
3+
& node dist/index.js
44
}

lib/http-server/index.ts

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import fastify from 'fastify';
2+
import cfLogs from 'cf-logs';
3+
4+
import { saveServerAddress } from '../helpers';
5+
6+
// eslint-disable-next-line import/no-unresolved
7+
import deprecatedImagesCollector from '../metric/deprecated-images/deprecated-images.collector';
8+
9+
const logger = cfLogs.Logger('codefresh:containerLogger');
10+
11+
export class HttpServer {
12+
13+
private readonly host;
14+
private readonly port;
15+
private readonly server;
16+
17+
constructor(private taskLogger: any) {
18+
try {
19+
this.host = process.env.HOST || '0.0.0.0';
20+
this.port = +(process.env.PORT || 8080);
21+
this.server = fastify();
22+
23+
this.initSecrets();
24+
this.initDeprecatedImages();
25+
} catch (error) {
26+
logger.error(`could not initialize server for engine's requests due to error: ${error}`);
27+
throw error;
28+
}
29+
}
30+
31+
private initSecrets() {
32+
const secretsOptions = {
33+
schema: {
34+
body: {
35+
type: 'object',
36+
required: ['key', 'value'],
37+
properties: {
38+
key: { type: 'string' },
39+
value: { type: 'string' },
40+
},
41+
},
42+
},
43+
};
44+
45+
this.server.post('/secrets', secretsOptions, async (request, reply) => {
46+
try {
47+
const { body }: { body: any } = request;
48+
const { secret } = body;
49+
logger.info(`got request to add new mask: ${secret.key}`);
50+
this.taskLogger.addNewMask(secret);
51+
reply.code(201);
52+
return 'secret added';
53+
} catch (err) {
54+
logger.info(`could not create new mask for due to error: ${err}`);
55+
reply.code(500);
56+
throw err;
57+
}
58+
});
59+
}
60+
61+
private initDeprecatedImages() {
62+
this.server.get('/deprecated-images', async () => {
63+
logger.info(`got request to retrieve deprecated images`);
64+
return deprecatedImagesCollector.consumeAll();
65+
});
66+
67+
this.server.post<{ Body: { count: number } }>('/deprecated-images/ack', async (request, reply) => {
68+
const { count } = request.body;
69+
70+
if (typeof count !== 'number' || count < 1) {
71+
return reply.status(400).send({ error: 'You must provide a valid count (positive integer).' });
72+
}
73+
74+
deprecatedImagesCollector.destroyConsumed(count);
75+
76+
return reply.status(200).send({ count });
77+
});
78+
}
79+
80+
async start() {
81+
let address: string;
82+
try {
83+
address = await this.server.listen({
84+
host: this.host,
85+
port: this.port,
86+
});
87+
88+
logger.info(`listening for engine's requests on ${address}`);
89+
} catch (error) {
90+
logger.error(`could not start server for engine updates due to error: ${error}`);
91+
throw error;
92+
}
93+
94+
try {
95+
await saveServerAddress(address);
96+
} catch (error) {
97+
logger.error(`could not save server address due to error: ${error}`);
98+
throw error;
99+
}
100+
}
101+
102+
}

lib/isReady.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function isContainerLoggerReady(state) {
2323

2424
(() => {
2525
const containerId = process.argv[2];
26-
const state = JSON.parse(readFileSync('./lib/state.json').toString('utf-8'));
26+
const state = JSON.parse(readFileSync('./dist/state.json').toString('utf-8'));
2727
let isReady = false;
2828
if (containerId) {
2929
isReady = isContainerReady(state, containerId);

lib/isReady.ps1

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ $CONTAINER_ID=$args[0]
66

77
if ( $CONTAINER_ID ) {
88
echo "checking if container:$CONTAINER_ID exists"
9-
if (select-string -Pattern $CONTAINER_ID -Path ./lib/state.json) {
9+
if (select-string -Pattern $CONTAINER_ID -Path ./dist/state.json) {
1010
echo "container $CONTAINER_ID is ready"
1111
Exit 0
1212
} else {
@@ -15,7 +15,7 @@ if ( $CONTAINER_ID ) {
1515
}
1616
} else {
1717
echo "checking if container logger is ready"
18-
if (select-string -Pattern "ready" -Path ./lib/state.json) {
18+
if (select-string -Pattern "ready" -Path ./dist/state.json) {
1919
echo "ready"
2020
Exit 0
2121
} else {

lib/isReady.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ CONTAINER_ID=$1
77

88
if [ -n "$CONTAINER_ID" ]; then
99
echo "checking if container: $CONTAINER_ID exists"
10-
grep -q $CONTAINER_ID ./lib/state.json
10+
grep -q $CONTAINER_ID ./dist/state.json
1111
else
1212
echo "checking if container logger is ready"
13-
grep -q "ready" ./lib/state.json
13+
grep -q "ready" ./dist/state.json
1414
fi
1515

1616

0 commit comments

Comments
 (0)