Skip to content
Open
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
74 changes: 74 additions & 0 deletions bin/docker-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,56 @@ const { Writable } = require('stream');
const { EOL } = require('os');
const path = require('path')
const fs = require('fs')
const os = require('os');

// dockerode does not support docker-credential-helper
// so we need to use docker-credential-helpers

const useCredHelper = !!parseInt(process.env['USE_CREDHELPER'])

function getDockerConfig() {
const dockerConfigPath = process.env.DOCKER_CONFIG
? path.join(process.env.DOCKER_CONFIG, 'config.json')
: path.join(os.homedir(), '.docker', 'config.json');
try {
const configContent = fs.readFileSync(dockerConfigPath, 'utf8');
return JSON.parse(configContent);
} catch (e) {
return {};
}
}

function getRegistryAuth(registry) {
const dockerConfig = getDockerConfig();
if (dockerConfig.credHelpers && dockerConfig.credHelpers[registry]) {
const helperName = dockerConfig.credHelpers[registry];
const helperBinary = `docker-credential-${helperName}`;
try {
const result = spawnSync(helperBinary, ['get'], {
input: registry,
encoding: 'utf8'
});
if (result.error) {
throw result.error;
}
const output = result.stdout.trim();
const cred = JSON.parse(output);
return { username: cred.Username, password: cred.Secret };
} catch (e) {
console.error(`Error handling ${helperBinary}: ${e.message}`);
return null;
}
}
return null;
}

function getRegistryFromImage(image) {
const parts = image.split('/');
if (parts.length > 1 && (parts[0].includes('.') || parts[0].includes(':') || parts[0] === 'localhost')) {
return parts[0];
}
return 'index.docker.io';
}

// cronicle should send job json to stdin
let job = {}
Expand Down Expand Up @@ -34,6 +84,7 @@ let registryAuth = {
password: process.env['DOCKER_PASSWORD']
}


// check if user specified DOCKER_HOST. If not just user socket default connection
let dh = process.env['DOCKER_HOST']

Expand Down Expand Up @@ -72,6 +123,20 @@ const keepEntrypoint = !!parseInt(process.env['KEEP_ENTRYPOINT'])
const json = !!parseInt(process.env['JSON'])
let stderr_msg

const registry = getRegistryFromImage(imageName);

if (useCredHelper) {
const helperAuth = getRegistryAuth(registry);
if (helperAuth) {
registryAuth = helperAuth;
printInfo(`Used credHelper from registry ${registry}`);
} else {
printInfo(`Error handling credHelper from registry ${registry}. Use ENV.`);
}
} else {
printInfo(`Use ENV for registry ${registry}`);
}

let command = []
if ((process.env['COMMAND'] || '').trim()) {
command = process.env['COMMAND'].trim().match(/(?:[^\s"]+|"[^"]*")+/g).map(e => e.replace(/["]+/g, ''))
Expand Down Expand Up @@ -127,6 +192,15 @@ let vars = Object.entries(process.env)
.filter(([k, v]) => ((k.startsWith('JOB_') || k.startsWith('DOCKER_') || k.startsWith('ARG') || include.indexOf(k) > -1) && exclude.indexOf(k) === -1))
.map(([k, v]) => `${truncVar ? k.replace(/^DOCKER_/, '') : k}=${v}`)

if (process.env.OPTIONS) {
let extraOptions = process.env.OPTIONS;
extraOptions.split(/\r?\n/).forEach(line => {
if (line.trim() !== '') {
vars.push(line.trim());
}
});
}

// CONTAINER SETTING
const createOptions = {
Image: imageName,
Expand Down
2 changes: 1 addition & 1 deletion engines/SQL.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ module.exports = class SQLEngine extends Component {
*/
client // db client type

getBlobSizeFn = 'length(V)'
getBlobSizeFn = 'length("V")'

/**
* @type {String}
Expand Down
2 changes: 2 additions & 0 deletions sample_conf/setup.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@
"params": [
{ "id":"docker_host", "type":"text", "size":40, "title":"Docker Host", "value": "" },
{ "id":"image", "type":"text", "size":40, "title":"Image", "value": "alpine" },
{ "id":"use_credhelper", "type":"checkbox","title": "Use Credential Helper", "value": 1},
{ "id":"command", "type":"text", "size":40, "title":"Command", "value": "" },
{ "id":"options", "type":"textarea", "rows": 5, "title": "Options"},
{ "id":"script", "type":"textarea", "rows":10, "title":"Script", "value": "\n#!/bin/sh\n\necho \"Running Docker job on $HOSTNAME\"\n\ncat /etc/os-release\n\nls -lah chain_data || echo \"no chain data\"\n\n# If Docker Host is not specified, docker socket will be used\n# To access remote docker machine via ssh (on top of socket) specify DH as:\n# ssh://user[:password]@host[:port]\n# To specify ssh credentials you can also use SSH_PASSWORD/SSH_KEY env varaibles\n# To access remote docker instance with exposed http:\n# http://dockerhost:2375 (there is no auth options for that at this point)\n# To specify image registry credentials use DOCKER_USER, DOCKER_PASSWORD variables\n# All credential variables can be set via event/plugin secrets\n\n# To specify volumes to be mount, list the volumes separated by comma:\n# /host/path1:/container/path1:rw,/host/path2:/container/path2,named_volume:/container/named_volume\n# To delete named volumes when the container is destroyed, untick \"Keep Named Volumes\".\n\n# This script will be used as an entrypoint on the container (mounted as /cronicle.sh by default).\n# To use original entrypoint check corresponding checkbox below,\n# and use command parameter above to pass argument to it\n# If this job is chained by other event, chain data will be mounted to the container\n# as chain_data file \n\n# In order to pass variables to container (other than JOB_ and ARG*) it should start with DOCKER_\n\n# If job is aborted \"docker stop\" is invoked (SIGTERM), docker will send SIGKILL after some time\n# Try to handle SIGTERM in your script for proper shutdown on abortion\n"},
{ "id":"entrypoint_path", "type":"text", "size":40, "title":"Mount As", "value": "" },
{ "id":"volumes", "type":"text", "size":100, "title":"Volumes", "value": ""},
Expand Down