aboutsummaryrefslogtreecommitdiff
path: root/src/lib/delivery/delivery_docker.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/delivery/delivery_docker.c')
-rw-r--r--src/lib/delivery/delivery_docker.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/lib/delivery/delivery_docker.c b/src/lib/delivery/delivery_docker.c
new file mode 100644
index 0000000..57015ad
--- /dev/null
+++ b/src/lib/delivery/delivery_docker.c
@@ -0,0 +1,132 @@
+#include "delivery.h"
+
+int delivery_docker(struct Delivery *ctx) {
+ if (!docker_capable(&ctx->deploy.docker.capabilities)) {
+ return -1;
+ }
+ char tag[STASIS_NAME_MAX];
+ char args[PATH_MAX];
+ int has_registry = ctx->deploy.docker.registry != NULL;
+ size_t total_tags = strlist_count(ctx->deploy.docker.tags);
+ size_t total_build_args = strlist_count(ctx->deploy.docker.build_args);
+
+ if (!has_registry) {
+ msg(STASIS_MSG_WARN | STASIS_MSG_L2, "No docker registry defined. You will need to manually re-tag the resulting image.\n");
+ }
+
+ if (!total_tags) {
+ char default_tag[PATH_MAX];
+ msg(STASIS_MSG_WARN | STASIS_MSG_L2, "No docker tags defined by configuration. Generating default tag(s).\n");
+ // generate local tag
+ memset(default_tag, 0, sizeof(default_tag));
+ sprintf(default_tag, "%s:%s-py%s", ctx->meta.name, ctx->info.build_name, ctx->meta.python_compact);
+ tolower_s(default_tag);
+
+ // Add tag
+ ctx->deploy.docker.tags = strlist_init();
+ strlist_append(&ctx->deploy.docker.tags, default_tag);
+
+ if (has_registry) {
+ // generate tag for target registry
+ memset(default_tag, 0, sizeof(default_tag));
+ sprintf(default_tag, "%s/%s:%s-py%s", ctx->deploy.docker.registry, ctx->meta.name, ctx->info.build_number, ctx->meta.python_compact);
+ tolower_s(default_tag);
+
+ // Add tag
+ strlist_append(&ctx->deploy.docker.tags, default_tag);
+ }
+ // regenerate total tag available
+ total_tags = strlist_count(ctx->deploy.docker.tags);
+ }
+
+ memset(args, 0, sizeof(args));
+
+ // Append image tags to command
+ for (size_t i = 0; i < total_tags; i++) {
+ char *tag_orig = strlist_item(ctx->deploy.docker.tags, i);
+ strcpy(tag, tag_orig);
+ docker_sanitize_tag(tag);
+ sprintf(args + strlen(args), " -t \"%s\" ", tag);
+ }
+
+ // Append build arguments to command (i.e. --build-arg "key=value"
+ for (size_t i = 0; i < total_build_args; i++) {
+ char *build_arg = strlist_item(ctx->deploy.docker.build_args, i);
+ if (!build_arg) {
+ break;
+ }
+ sprintf(args + strlen(args), " --build-arg \"%s\" ", build_arg);
+ }
+
+ // Build the image
+ char delivery_file[PATH_MAX] = {0};
+ char dest[PATH_MAX] = {0};
+ char rsync_cmd[PATH_MAX * 2] = {0};
+ memset(delivery_file, 0, sizeof(delivery_file));
+ memset(dest, 0, sizeof(dest));
+
+ sprintf(delivery_file, "%s/%s.yml", ctx->storage.delivery_dir, ctx->info.release_name);
+ if (access(delivery_file, F_OK) < 0) {
+ fprintf(stderr, "docker build cannot proceed without delivery file: %s\n", delivery_file);
+ return -1;
+ }
+
+ sprintf(dest, "%s/%s.yml", ctx->storage.build_docker_dir, ctx->info.release_name);
+ if (copy2(delivery_file, dest, CT_PERM)) {
+ fprintf(stderr, "Failed to copy delivery file to %s: %s\n", dest, strerror(errno));
+ return -1;
+ }
+
+ memset(dest, 0, sizeof(dest));
+ sprintf(dest, "%s/packages", ctx->storage.build_docker_dir);
+
+ msg(STASIS_MSG_L2, "Copying conda packages\n");
+ memset(rsync_cmd, 0, sizeof(rsync_cmd));
+ sprintf(rsync_cmd, "rsync -avi --progress '%s' '%s'", ctx->storage.conda_artifact_dir, dest);
+ if (system(rsync_cmd)) {
+ fprintf(stderr, "Failed to copy conda artifacts to docker build directory\n");
+ return -1;
+ }
+
+ msg(STASIS_MSG_L2, "Copying wheel packages\n");
+ memset(rsync_cmd, 0, sizeof(rsync_cmd));
+ sprintf(rsync_cmd, "rsync -avi --progress '%s' '%s'", ctx->storage.wheel_artifact_dir, dest);
+ if (system(rsync_cmd)) {
+ fprintf(stderr, "Failed to copy wheel artifacts to docker build directory\n");
+ }
+
+ if (docker_build(ctx->storage.build_docker_dir, args, ctx->deploy.docker.capabilities.build)) {
+ return -1;
+ }
+
+ // Test the image
+ // All tags point back to the same image so test the first one we see
+ // regardless of how many are defined
+ strcpy(tag, strlist_item(ctx->deploy.docker.tags, 0));
+ docker_sanitize_tag(tag);
+
+ msg(STASIS_MSG_L2, "Executing image test script for %s\n", tag);
+ if (ctx->deploy.docker.test_script) {
+ if (isempty(ctx->deploy.docker.test_script)) {
+ msg(STASIS_MSG_L2 | STASIS_MSG_WARN, "Image test script has no content\n");
+ } else {
+ int state;
+ if ((state = docker_script(tag, ctx->deploy.docker.test_script, 0))) {
+ msg(STASIS_MSG_L2 | STASIS_MSG_ERROR, "Non-zero exit (%d) from test script. %s image archive will not be generated.\n", state >> 8, tag);
+ // test failed -- don't save the image
+ return -1;
+ }
+ }
+ } else {
+ msg(STASIS_MSG_L2 | STASIS_MSG_WARN, "No image test script defined\n");
+ }
+
+ // Test successful, save image
+ if (docker_save(path_basename(tag), ctx->storage.docker_artifact_dir, ctx->deploy.docker.image_compression)) {
+ // save failed
+ return -1;
+ }
+
+ return 0;
+}
+