Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 15 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@
"node/shebang": "off",
"node/no-deprecated-api": "warn",
"no-useless-constructor": "warn",
"no-return-await": "off"
"no-return-await": "off",
"import/extensions": ["error", "never", { "json": "always" }]
},

"overrides": [
Expand Down Expand Up @@ -125,5 +126,17 @@
]
}
}
]
],

"settings": {
"import/resolver": {
"typescript": {
"alwaysTryTypes": true,
"project": ["tsconfig.json"]
},
"node": {
"extensions": [".js", ".ts", ".json"]
}
}
}
}
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v22.17.1
v22.18.0
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG NODE_VERSION=22.17.1
ARG NODE_VERSION=22.18.0
FROM node:${NODE_VERSION}-bookworm-slim AS base
# that workdir MUST NOT be changed because of backward compatibility with the engine <= 1.177.7
WORKDIR /root/cf-runtime
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# FIREBASE_AUTH_URL - the main firebase ref to authenticate on initialization
# FIREBASE_SECRET - the secret key to write to the firebase auth url and all future derived urls
# LOGGER_ID - logger id. if a container will include this id in its label, we will log it
# LOG_TO_CONSOLE - by default, logging to console is disabled and only logging to a file is enabled. set this env to log to console to
# LISTEN_ON_EXISTING - by default, if not provided, will only listen for new containers. this will enable listening on existing containers

# Container labels
Expand Down
1 change: 0 additions & 1 deletion lib/@types/index.d.ts

This file was deleted.

4 changes: 3 additions & 1 deletion lib/ContainerLogger.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const EventEmitter = require('events');
const Q = require('q');
const promiseRetry = require('promise-retry');
const logger = require('cf-logs').Logger('codefresh:containerLogger');
const { Logger } = require('@codefresh-io/cf-telemetry/logs');
const CFError = require('cf-errors');
const { Transform } = require('stream');

Expand All @@ -11,6 +11,8 @@ const { LoggerStrategy } = require('./enums');
// eslint-disable-next-line import/no-unresolved
const { DeprecatedImagesInterceptorStream } = require('./metric/deprecated-images/deprecated-images-interceptor.stream');

const logger = new Logger('codefresh:containerLogger');

const CONTAINER_START_RETRY_TIMEOUT_SECONDS = 1;
const CONTAINER_START_RETRY_LIMIT = 10;
const BUFFER_SIZE = 2 * 1024 * 1024; // 2 MiB
Expand Down
25 changes: 18 additions & 7 deletions lib/addNewMask.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
const { getServerAddress } = require('./helpers');
// ↓ Should be imported first
require('@codefresh-io/cf-telemetry/init');
// ↓ Keep one blank line below to prevent automatic import reordering

const { Logger } = require('@codefresh-io/cf-telemetry/logs');
const { getServerAddress, registerExitHandlers } = require('./helpers');

const logger = new Logger('codefresh:containerLogger:addNewMask');

logger.info(`addNewMask.js env: ${JSON.stringify(process.env)}`);

const exitCodes = {
success: 0,
Expand All @@ -14,7 +23,7 @@ const exitCodes = {
let exitWithError = true;
const exitHandler = (exitCode) => {
if ((!exitCode || !process.exitCode) && exitWithError) {
console.warn(`Unexpected exit with code 0. Exiting with ${exitCodes.unexpectedSuccess} instead`);
logger.warn(`Unexpected exit with code 0. Exiting with ${exitCodes.unexpectedSuccess} instead`);
process.exitCode = exitCodes.unexpectedSuccess;
}
};
Expand All @@ -23,7 +32,7 @@ process.on('exit', exitHandler);
async function updateMasks(secret) {
try {
const serverAddress = await getServerAddress();
console.debug(`server address: ${serverAddress}`);
logger.debug(`server address: ${serverAddress}`);
const url = new URL('secrets', serverAddress);

// eslint-disable-next-line import/no-unresolved
Expand All @@ -34,23 +43,25 @@ async function updateMasks(secret) {
});

if (response.statusCode === 201) {
console.log(`successfully updated masks with secret: ${secret.key}`);
logger.log(`successfully updated masks with secret: ${secret.key}`);
exitWithError = false;
process.exit(exitCodes.success);
} else {
console.error(`could not create mask for secret: ${secret.key}. Server responded with: ${response.statusCode}\n\n${response.body}`);
logger.error(`could not create mask for secret: ${secret.key}. Server responded with: ${response.statusCode}\n\n${response.body}`);
process.exit(exitCodes.error);
}
} catch (error) {
console.error(`could not create mask for secret: ${secret.key}. Error: ${error}`);
logger.error(`could not create mask for secret: ${secret.key}. Error: ${error}`);
process.exit(exitCodes.error);
}
}

if (require.main === module) {
registerExitHandlers();

// first argument is the secret key second argument is the secret value
if (process.argv.length < 4) {
console.log('not enough arguments, need secret key and secret value');
logger.log('not enough arguments, need secret key and secret value');
process.exit(exitCodes.missingArguments);
}
const key = process.argv[2];
Expand Down
29 changes: 20 additions & 9 deletions lib/helpers.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
const { stat, writeFile, readFile } = require('node:fs/promises');
const path = require('path');
const logger = require('cf-logs').Logger('codefresh:containerLogger');
const getPromiseWithResolvers = require('core-js-pure/es/promise/with-resolvers');
const { Logger } = require('@codefresh-io/cf-telemetry/logs');
const { BuildFinishedSignalFilename } = require('./enums');
const { SERVER_ADDRESS_PATH } = require('./const');

const logger = new Logger('codefresh:containerLogger');

const checkFileInterval = 1000;

function _watchForBuildFinishedSignal(deferred) {
Expand All @@ -19,7 +20,7 @@ function _watchForBuildFinishedSignal(deferred) {
}

if (fileExists) {
console.log(`FOUND FILE '${BuildFinishedSignalFilename}' --- engine signaling build is finished`);
logger.log(`FOUND FILE '${BuildFinishedSignalFilename}' --- engine signaling build is finished`);
return deferred.resolve();
}

Expand All @@ -28,7 +29,7 @@ function _watchForBuildFinishedSignal(deferred) {
}

function watchForBuildFinishedSignal() {
const deferred = getPromiseWithResolvers();
const deferred = Promise.withResolvers();

_watchForBuildFinishedSignal(deferred);

Expand All @@ -53,13 +54,23 @@ const getServerAddress = async () => {
}
};

/**
* As `@codefresh-io/cf-telemetry/init` changes the original node.js behavior of how SIGTERM and SIGINT
* signals are handled, we revert this change back to the original node.js behavior.
*/
const registerExitHandlers = () => {
process.on('SIGTERM', () => {
process.exit(143); // default exit code for SIGTERM
});

process.on('SIGINT', () => {
process.exit(130); // default exit code for SIGINT
});
};

module.exports = {
/**
* Polyfill of `Promise.withResolvers`, TC39 Stage 4 proposal.
* @see https://github.com/tc39/proposal-promise-with-resolvers
*/
getPromiseWithResolvers,
watchForBuildFinishedSignal,
saveServerAddress,
getServerAddress,
registerExitHandlers,
};
4 changes: 2 additions & 2 deletions lib/http-server/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import fastify from 'fastify';
import cfLogs from 'cf-logs';
import { Logger } from '@codefresh-io/cf-telemetry/logs';

import { saveServerAddress } from '../helpers';

// eslint-disable-next-line import/no-unresolved
import deprecatedImagesCollector from '../metric/deprecated-images/deprecated-images.collector';

const logger = cfLogs.Logger('codefresh:containerLogger');
const logger = new Logger('codefresh:containerLogger');

export class HttpServer {

Expand Down
44 changes: 26 additions & 18 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
const path = require('node:path');
const cflogs = require('cf-logs');

const loggerOptions = {
filePath: path.join(__dirname, '../logs', 'logs.log'),
console: process.env.LOG_TO_CONSOLE || false,
consoleOptions: {
timestamp() {
return new Date().toISOString();
}
}
};
cflogs.init(loggerOptions);
// ↓ Should be imported first
require('@codefresh-io/cf-telemetry/init');
// ↓ Keep one blank line below to prevent automatic import reordering

const otel = require('@codefresh-io/cf-telemetry/otel');
const { Logger: Logs } = require('@codefresh-io/cf-telemetry/logs');
const { watchForBuildFinishedSignal, registerExitHandlers } = require('./helpers');

registerExitHandlers();

const logs = new Logs('codefresh:containerLogger:index');

const unhandledErrorsTotal = otel.cf.getMeter().createCounter(
'codefresh.unhandled_errors',
{
description: 'Number of unhandled errors',
unit: '{unhandled_error}',
valueType: otel.api.ValueType.INT,
},
);

const Logger = require('./logger');
const { watchForBuildFinishedSignal } = require('./helpers');

const taskLoggerConfig = JSON.parse(process.env.TASK_LOGGER_CONFIG);

Expand All @@ -30,24 +36,26 @@ logger.validate();
logger.start();

process.on('beforeExit', (code) => {
console.log(`beforeExit: ${code}`);
logs.log(`beforeExit: ${code}`);
logger.state.beforeExitCode = code;
logger._writeNewState();
});
process.on('exit', (code) => {
console.log(`exit: ${code}`);
logs.log(`exit: ${code}`);
logger.state.exitCode = code;
logger._writeNewState();
});

process.on('uncaughtException', (error) => {
console.log(`uncaughtException: ${error}`);
unhandledErrorsTotal.add(1, { 'cf.unhandled_error.type': 'uncaughtException' });
logs.log(`uncaughtException: ${error}`);
logger.state.uncaughtException = error;
logger._writeNewState();
});

process.on('unhandledRejection', (reason) => {
console.log(`unhandledRejection: ${reason}`);
unhandledErrorsTotal.add(1, { 'cf.unhandled_error.type': 'unhandledRejection' });
logs.log(`unhandledRejection: ${reason}`);
logger.state.unhandledRejection = reason;
logger._writeNewState();
});
20 changes: 16 additions & 4 deletions lib/isReady.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
// ↓ Should be imported first
require('@codefresh-io/cf-telemetry/init');
// ↓ Keep one blank line below to prevent automatic import reordering

const { readFileSync } = require('fs');
const _ = require('lodash');
const { Logger } = require('@codefresh-io/cf-telemetry/logs');
const { ContainerHandlingStatus } = require('./enums');
const { registerExitHandlers } = require('./helpers');

registerExitHandlers();

const logger = new Logger('codefresh:containerLogger:isReady');

logger.info(`isReady env: ${JSON.stringify(process.env)}`);

function isContainerReady(state, containerId) {
console.log(`checking if container ${containerId} is ready`);
logger.log(`checking if container ${containerId} is ready`);
const containerState = _.get(state, `containers[${containerId}]`, {});
const isReady = [
ContainerHandlingStatus.LISTENING,
ContainerHandlingStatus.WAITING_FOR_START,
ContainerHandlingStatus.FINISHED,
].includes(containerState.status);
console.log(`container ${containerId} is: ${isReady ? 'READY' : 'NOT READY'}`);
logger.log(`container ${containerId} is: ${isReady ? 'READY' : 'NOT READY'}`);
return isReady;
}

function isContainerLoggerReady(state) {
console.log(`checking if container logger is ready`);
logger.log(`checking if container logger is ready`);
const isReady = state.status === 'ready';
console.log(`container logger is: ${isReady ? 'READY' : 'NOT READY'}`);
logger.log(`container logger is: ${isReady ? 'READY' : 'NOT READY'}`);
return isReady;
}

Expand Down
7 changes: 4 additions & 3 deletions lib/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ const _ = require('lodash');
const Docker = require('dockerode');
const DockerEvents = require('docker-events');
const CFError = require('cf-errors');
const logger = require('cf-logs').Logger('codefresh:containerLogger');
const { Logger: Logs } = require('@codefresh-io/cf-telemetry/logs');
const { TaskLogger } = require('@codefresh-io/task-logger');
const { ContainerStatus } = require('./enums');
const { LoggerStrategy } = require('./enums');
const { ContainerHandlingStatus } = require('./enums');
const ContainerLogger = require('./ContainerLogger');
const { getPromiseWithResolvers } = require('./helpers');

// eslint-disable-next-line import/no-unresolved,import/extensions
const { HttpServer } = require('./http-server');

const logger = new Logs('codefresh:containerLogger');

const initialState = {
pid: process.pid, status: 'init', lastLogsDate: new Date(), failedHealthChecks: [], restartCounter: 0, containers: {}
};
Expand Down Expand Up @@ -367,7 +368,7 @@ class Logger {

// do not call before build is finished
_awaitAllStreamsClosed() {
const deferred = getPromiseWithResolvers();
const deferred = Promise.withResolvers();
this._checkAllStreamsClosed(deferred);
this.finishedContainersEmitter.on('end', this._checkAllStreamsClosed.bind(this, deferred));
return deferred.promise;
Expand Down
4 changes: 2 additions & 2 deletions lib/metric/deprecated-images/deprecated-images.collector.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import cfLogs from 'cf-logs';
import { Logger } from '@codefresh-io/cf-telemetry/logs';

// eslint-disable-next-line import/no-unresolved
import { DeprecatedImageDto } from './deprecated-image.dto';

const logger = cfLogs.Logger('codefresh:containerLogger');
const logger = new Logger('codefresh:containerLogger');

// eslint-disable-next-line no-control-regex
const DEPRECATED_IMAGE_REGEX = /^(?:\u001b\[31m\u001b\[1m)?\[DEPRECATION NOTICE].+?Suggest the author of (?<image>.+?) to/;
Expand Down
Loading