Skip to content

Commit

Permalink
2.5.2 - allow entrypoint, user and workdir to be overridden when usin…
Browse files Browse the repository at this point in the history
…g customContent
  • Loading branch information
eoftedal committed Oct 11, 2023
1 parent 4bc049a commit 2d1b209
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 63 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
# Changelog

## [2.5.1] - TBD
## [2.5.2] - 2023-10-11

### Fixed

- Reverting 2.5.1, but allowing `ENTRYPOINT`, `WORKDIR` and `USER` to be explicitely set when using `customContent`

## [2.5.1] - 2023-10-11

### Fixed

- Layers for `ENTRYPOINT`, `WORKDIR` and user information are now being added when using `customContent`

## [2.5.0] - TBD
## [2.5.0] - 2023-07-07

### Added

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "containerify",
"version": "2.5.1",
"version": "2.5.2",
"description": "Build node.js docker images without docker",
"main": "./lib/cli.js",
"scripts": {
Expand Down
47 changes: 28 additions & 19 deletions src/appLayerCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,28 +185,19 @@ function parseCommandLineToParts(entrypoint: string) {
}

async function addAppLayers(options: Options, config: Config, todir: string, manifest: Manifest, tmpdir: string) {
addEmptyLayer(
config,
options,
`WORKDIR ${options.workdir}`,
(config) => (config.config.WorkingDir = options.workdir),
);
const entrypoint = parseCommandLineToParts(options.entrypoint);
addEmptyLayer(
config,
options,
`ENTRYPOINT ${JSON.stringify(entrypoint)}`,
(config) => (config.config.Entrypoint = entrypoint),
);
addEmptyLayer(config, options, `USER ${options.user}`, (config) => {
config.config.User = options.user;
config.container_config.User = options.user;
});
await addEnvsLayer(options, config);
await addLabelsLayer(options, config);
if (options.customContent.length > 0) {
if (options.nonDefaults.workdir) await addWorkdirLayer(options, config, options.nonDefaults.workdir);
if (options.nonDefaults.entrypoint) await addEntrypointLayer(options, config, options.nonDefaults.entrypoint);
if (options.nonDefaults.user) await addUserLayer(options, config, options.nonDefaults.user);
await addEnvsLayer(options, config);
await addLabelsLayer(options, config);
await addDataLayer(tmpdir, todir, options, config, manifest, options.customContent, "custom");
} else {
await addWorkdirLayer(options, config, options.workdir);
await addEntrypointLayer(options, config, options.entrypoint);
await addUserLayer(options, config, options.user);
await addEnvsLayer(options, config);
await addLabelsLayer(options, config);
const appFiles = (await fs.readdir(options.folder)).filter((l) => !ignore.includes(l));
const depLayerContent = appFiles.filter((l) => depLayerPossibles.includes(l));
const appLayerContent = appFiles.filter((l) => !depLayerPossibles.includes(l));
Expand All @@ -218,6 +209,24 @@ async function addAppLayers(options: Options, config: Config, todir: string, man
await addDataLayer(tmpdir, todir, options, config, manifest, [extraContent], "extra");
}
}
async function addWorkdirLayer(options: Options, config: Config, workdir: string) {
addEmptyLayer(config, options, `WORKDIR ${workdir}`, (config) => (config.config.WorkingDir = workdir));
}
async function addEntrypointLayer(options: Options, config: Config, entrypoint: string) {
const entrypointParts = parseCommandLineToParts(entrypoint);
addEmptyLayer(
config,
options,
`ENTRYPOINT ${JSON.stringify(entrypoint)}`,
(config) => (config.config.Entrypoint = entrypointParts),
);
}
async function addUserLayer(options: Options, config: Config, user: string) {
addEmptyLayer(config, options, `USER ${user}`, (config) => {
config.config.User = user;
config.container_config.User = user;
});
}

async function addLabelsLayer(options: Options, config: Config) {
if (Object.keys(options.labels).length > 0) {
Expand Down
42 changes: 25 additions & 17 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ const possibleArgs = {
"--registry <path>": "Optional: Convenience argument for setting both from and to registry",
"--platform <platform>": "Optional: Preferred platform, e.g. linux/amd64 or arm64",
"--token <path>": "Optional: Convenience argument for setting token for both from and to registry",
"--user <user>": "Optional: User account to run process in container - default: 1000",
"--workdir <directory>": "Optional: Workdir where node app will be added and run from - default: /app",
"--entrypoint <entrypoint>": "Optional: Entrypoint when starting container - default: npm start",
"--user <user>": "Optional: User account to run process in container - default: 1000 (empty for customContent)",
"--workdir <directory>":
"Optional: Workdir where node app will be added and run from - default: /app (empty for customContent)",
"--entrypoint <entrypoint>":
"Optional: Entrypoint when starting container - default: npm start (empty for customContent)",
"--labels <labels>": "Optional: Comma-separated list of key value pairs to use as labels",
"--label <label>": "Optional: Single label (name=value). This option can be used multiple times.",
"--envs <envs>": "Optional: Comma-separated list of key value pairs to use av environment variables.",
Expand Down Expand Up @@ -145,8 +147,7 @@ const cliParams: Record<string, string> = omit(cliOptions, [
"extraContent",
]);

const options: Options = {
...defaultOptions,
const setOptions: Options = {
...configFromFile,
...cliParams,
customContent,
Expand All @@ -155,6 +156,16 @@ const options: Options = {
envs: Object.entries(envs).map(([k, v]) => `${k}=${v}`),
};

const options: Options = {
...defaultOptions,
...setOptions,
nonDefaults: {
user: setOptions.user,
workdir: setOptions.workdir,
entrypoint: setOptions.entrypoint,
},
};

function exitWithErrorIf(check: boolean, error: string) {
if (check) {
logger.error("ERROR: " + error);
Expand Down Expand Up @@ -200,11 +211,11 @@ if (options.token) {
exitWithErrorIf(!options.folder, "--folder must be specified");
exitWithErrorIf(!options.fromImage, "--fromImage must be specified");
exitWithErrorIf(!options.toImage, "--toImage must be specified");
exitWithErrorIf(!options.toRegistry && !options.toTar && !options.toDocker, "Must specify either --toTar, --toRegistry or --toDocker");
exitWithErrorIf(
!!options.toRegistry && !options.toToken,
"A token must be given when uploading to docker hub",
!options.toRegistry && !options.toTar && !options.toDocker,
"Must specify either --toTar, --toRegistry or --toDocker",
);
exitWithErrorIf(!!options.toRegistry && !options.toToken, "A token must be given when uploading to docker hub");

if (options.toRegistry && !options.toRegistry.endsWith("/")) options.toRegistry += "/";
if (options.fromRegistry && !options.fromRegistry.endsWith("/")) options.fromRegistry += "/";
Expand All @@ -231,11 +242,8 @@ if (options.layerCacheFolder) {
}
}

Object.keys(options.extraContent).forEach(k => {
exitWithErrorIf(
!fs.existsSync(options.folder + k),
"Could not find `" + k + "` in the folder " + options.folder,
);
Object.keys(options.extraContent).forEach((k) => {
exitWithErrorIf(!fs.existsSync(options.folder + k), "Could not find `" + k + "` in the folder " + options.folder);
});

async function run(options: Options) {
Expand All @@ -259,11 +267,11 @@ async function run(options: Options) {
await appLayerCreator.addLayers(tmpdir, fromdir, todir, options);

if (options.toDocker) {
if (!await dockerExporter.isAvailable()) {
throw new Error("Docker executable not found on path. Unable to export to local docker registry.")
if (!(await dockerExporter.isAvailable())) {
throw new Error("Docker executable not found on path. Unable to export to local docker registry.");
}
const dockerDir = path.join(tmpdir, "toDocker")
await tarExporter.saveToTar(todir, tmpdir, dockerDir, [options.toImage], options)
const dockerDir = path.join(tmpdir, "toDocker");
await tarExporter.saveToTar(todir, tmpdir, dockerDir, [options.toImage], options);
await dockerExporter.load(dockerDir);
}
if (options.toTar) {
Expand Down
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,9 @@ export type Options = {
layerOwner?: string;
buildFolder?: string;
layerCacheFolder?: string;
nonDefaults: {
user?: string;
workdir?: string;
entrypoint?: string;
};
};
2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const VERSION = "2.5.1";
export const VERSION = "2.5.2";
13 changes: 7 additions & 6 deletions tests/integration/file/containerify.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"fromImage": "node:alpine",
"toImage": "containerify:demo-app",
"folder": ".",
"customContent": [
"customContent"
]
"fromImage": "node:alpine",
"toImage": "containerify:demo-app",
"folder": ".",
"customContent": ["customContent"],
"entrypoint": "npm start",
"user": "1000",
"workdir": "/app"
}
24 changes: 9 additions & 15 deletions tests/integration/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,51 +36,45 @@ tar -xf tmp/v4.tar -C tmp/v4/content/

jqscript='if (.config.Entrypoint == ["npm", "start"]) then true else false end'

echo "Checking that entrypoint is correctly set for 1 ..."
if [[ $(cat tmp/v1/content/config.json | jq "$jqscript") != "true" ]]; then
echo "ERROR: wrong entrypoint set";
exit 1;
fi

echo "Checking that entrypoint is correctly set for 3 ..."
if [[ $(cat tmp/v3/content/config.json | jq "$jqscript") != "true" ]]; then
echo "ERROR: wrong entrypoint set";
if [[ $(cat tmp/v4/content/config.json | jq "$jqscript") != "true" ]]; then
echo "ERROR: wrong entrypoint set for 3";
exit 1;
fi

echo "Checking that config files for 1 and 2 are equal ..."
if ! cmp -s tmp/v1/content/config.json tmp/v2/content/config.json; then
echo "ERROR: config.jsons are different";
echo "ERROR: config.jsons are different for 1 and 2";
exit 1;
fi

echo "Checking that manifest files for 1 and 2 are equal ..."
if ! cmp -s tmp/v1/content/manifest.json tmp/v2/content/manifest.json; then
echo "ERROR: manifest.jsons are different";
echo "ERROR: manifest.jsons are different for 1 and 2";
exit 1;
fi

echo "Checking that config files for 1 and 3 are not equal ..."
if cmp -s tmp/v1/content/config.json tmp/v3/content/config.json; then
echo "ERROR: config.jsons are the same";
echo "ERROR: config.jsons are the same for 1 and 3";
exit 1;
fi

echo "Checking that manifest files for 1 and 3 are not equal ..."
if cmp -s tmp/v1/content/manifest.json tmp/v3/content/manifest.json; then
echo "ERROR: manifest.jsons are the same";
echo "ERROR: manifest.jsons are the same for 1 and 3";
exit 1;
fi

echo "Checking that config files for 3 and 4 are equal ..."
if ! cmp -s tmp/v3/content/config.json tmp/v4/content/config.json; then
echo "ERROR: config.jsons are not the same";
if cmp -s tmp/v3/content/config.json tmp/v4/content/config.json; then
echo "ERROR: config.jsons are the same for 3 and 4";
exit 1;
fi

echo "Checking that manifest files for 3 and 4 are equal ..."
if ! cmp -s tmp/v3/content/manifest.json tmp/v4/content/manifest.json; then
echo "ERROR: manifest.jsons are not the same";
echo "ERROR: manifest.jsons are not the same for 3 and 4";
exit 1;
fi

Expand Down

0 comments on commit 2d1b209

Please sign in to comment.