Skip to content
5 changes: 4 additions & 1 deletion src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Dockerode from "dockerode";
import {getCurrent} from "./docker-api.js";
import {initHashedConfigs} from "./hashed-config.js";
import {ArgumentsCamelCase} from "yargs";
import {loadDockerAuths} from "./docker-config.js";


export async function initContext (args: ArgumentsCamelCase) {
Expand All @@ -24,5 +25,7 @@ export async function initContext (args: ArgumentsCamelCase) {

const hashedConfigs = await initHashedConfigs(config);

return {appName, config, dockerode, current, hashedConfigs};
const dockerAuths = await loadDockerAuths();

return {appName, config, dockerode, current, hashedConfigs, dockerAuths};
}
11 changes: 8 additions & 3 deletions src/docker-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {initServiceSpec, sortServiceSpec} from "./service-spec.js";
import {HashedConfigs} from "./hashed-config.js";
import {assertString} from "./asserts.js";
import {SwarmAppConfig} from "./swarm-app-config.js";
import {resolveAuthConfig} from "./docker-config.js";
import {AuthConfigObject} from "dockerode";
import timers from "timers/promises";
import assert from "assert";

Expand Down Expand Up @@ -116,18 +118,21 @@ interface UpsertServicesOpts {
current: DockerResources;
appName: string;
hashedConfigs: HashedConfigs;
dockerAuths?: Record<string, AuthConfigObject> | undefined;
}
export async function upsertServices ({dockerode, config, current, appName, hashedConfigs}: UpsertServicesOpts) {
export async function upsertServices ({dockerode, config, current, appName, hashedConfigs, dockerAuths}: UpsertServicesOpts) {
for (const serviceName of Object.keys(config.service_specs)) {
const serviceSpec = initServiceSpec({appName, serviceName, config, hashedConfigs, current});
const image = config.service_specs[serviceName]?.image;
const authconfig = image && dockerAuths ? resolveAuthConfig(image, dockerAuths) : undefined;
const foundService = current.services.find((s) => s.Spec?.Name === `${appName}_${serviceName}`);
if (!foundService) {
console.log(`Creating service ${appName}_${serviceName}`);
await dockerode.createService(serviceSpec);
await dockerode.createService({...serviceSpec, authconfig});
} else {
serviceSpec.version = foundService.Version?.Index ?? 0;
console.log(`Updating service ${appName}_${serviceName}`);
await dockerode.getService(foundService.ID).update(serviceSpec);
await dockerode.getService(foundService.ID).update({...serviceSpec, authconfig});
}
}
}
27 changes: 27 additions & 0 deletions src/docker-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import fs from "fs";
import path from "path";
import {AuthConfig, AuthConfigObject} from "dockerode";

export async function loadDockerAuths (): Promise<Record<string, AuthConfigObject>> {
const configDir = process.env.DOCKER_CONFIG ?? path.join(process.env.HOME ?? "~", ".docker");
const configPath = path.join(configDir, "config.json");

try {
const content = await fs.promises.readFile(configPath, "utf-8");
const config = JSON.parse(content) as {auths?: Record<string, AuthConfigObject>};
return config.auths ?? {};
} catch {
return {};
}
}

export function resolveAuthConfig (image: string, auths: Record<string, AuthConfigObject>): AuthConfig | undefined {
const parts = image.split("/");
const first = parts[0];
const registry = parts.length >= 2 && first && (first.includes(".") || first.includes(":")) ? first : "https://index.docker.io/v1/";

const entry = auths[registry];
if (!entry?.auth) return undefined;

return {auth: entry.auth, serveraddress: registry};
}