From patchwork Mon Jan 29 08:41:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefano Babic X-Patchwork-Id: 1892120 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=WWo0XTHv; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::13c; helo=mail-lf1-x13c.google.com; envelope-from=swupdate+bncbaabbr6j3wwqmgqendbvo3i@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lf1-x13c.google.com (mail-lf1-x13c.google.com [IPv6:2a00:1450:4864:20::13c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4TNhcD2HXsz23fD for ; Mon, 29 Jan 2024 19:41:48 +1100 (AEDT) Received: by mail-lf1-x13c.google.com with SMTP id 2adb3069b0e04-50e5195db01sf2174361e87.3 for ; Mon, 29 Jan 2024 00:41:48 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706517704; cv=pass; d=google.com; s=arc-20160816; b=mgJ+8g/LYBExXMdjjQlSX+ltLyn3uFuW6TRqlXwthcmLDc6ikYBQOPFP5tr8pbjYgi oYioi3uOhmlsOybr23Qo6MS5fUnEwkJO5c2uAWxe3yaHEOg/IN4cBAd61SQt2t6oEm3k x2CTzqz2pnJQLQMiLTsBGKZYfJY5YCIHOqkeu11XkNukRdw9InMCOG/Zy7Krl1Nv+0N5 U2i/EcwZYGyL4PLOoYrBkSmY2vCEJb/qdCI6Wzcpv8t7n5gJ3UCWknzG0QA4pfgouMjL TkDyb8ZYHhUa+Pcu/9kLpr/dDho0uRKry4NCMDWaVr5az1JjaFaI/G9L0eNkgz6DoPn7 ybpw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:ui-outboundreport:mime-version :message-id:date:subject:cc:to:from:sender:dkim-signature; bh=lhe353tJfntTkjzqHOCeeNmvIKU/U/qSXWAPzQoWavU=; fh=TiEWcqMcKpHk5s7uErzpntoONrNfOXwKpI5P8bIlggk=; b=h+fJ/KPHsKBCqIpV6KjT1ynTG6W/b17ulqVI7ZvA8MQ2j2RKFC0k5mt40pRvUNUEyw ML/BZ5EpzZ57BB/Phj7TxQS/M5VRRnt9wnUYzsspRaxdFJzFttlYwJ5J5dl/s7TXupCI x2vvYIiqHvUMwqa5r7geIYrx10fl8M8EoL/pbnMqXuNF9au48SMZkJ4bjtRxrUDuysyS huTt2d94xkT2O6w42usdB1V2SEe5cG+hsBnwHp1BA1cdLr6j5UDXMkbPSGSD+oxxIWeI kuVutFsu6aDcydSUms5XF71nEPLNL9r7POcJJQd6iY36g7F4JP6efWr6TSGyXdeY8Vh5 Y2vg== ARC-Authentication-Results: i=2; gmr-mx.google.com; spf=pass (google.com: domain of stefano.babic@swupdate.org designates 217.72.192.73 as permitted sender) smtp.mailfrom=stefano.babic@swupdate.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1706517704; x=1707122504; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:ui-outboundreport:mime-version:message-id:date :subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=lhe353tJfntTkjzqHOCeeNmvIKU/U/qSXWAPzQoWavU=; b=WWo0XTHv3hxvUJ1QMiFgraOCkwZtQravTOFwCv6xIk6RoTzfEiPY8sfuCBT8ng9g9N aaOjYrbk6DyjeSANDXlF39SvhcXTzeeKWFBaTh5iLm9hcNoYbfpw7TGogNQFeD0k3I9A lSw0vet9Pt5zCU4XqEIGAXZJSdjHAHcsfxkwIxzYf57BbzUUWRhFosk4Fen8m8CgyV8Y 9I4V1IbArc5gBWJeQ8s8fnx7vHWw3nlM2wOrA2hlrtZ+trEpP1BrO/ffmYwYOjYPCesm gGAHPOZUvXTH3Pz2fYbYJXQWZua0uBxEIME7JPCglOO3Cg6JR/vEKlwPiNvFbZChytGB Vm8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706517704; x=1707122504; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender :ui-outboundreport:mime-version:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=lhe353tJfntTkjzqHOCeeNmvIKU/U/qSXWAPzQoWavU=; b=uvhy8TCPmS5wtgy2y7ljYd4HSbdwEwxhyDDiSlFWdqvNqoS/705PSWFKeIlUp83stM gTl6ppsKhdj9GMiegQSzqeRaBELjZXDiLnCh00wmi9IksMylvwUEf0mrl+7V80/b1KnK G2NHJDhb933HLdYqc0hLg3uwvAeObOdRBi7qf6uNHgAAEuGnyYl7zzWWCoYsX6qWPmAk 41d4sUSKUL+Qgyypm0cepWI9M7u+BZ/Np2GtjCjODchsA0cscLZj5JldDfQZxJ/cPd/V egOeTV4helVlZiSSv47khShJHD1sOpvCGDp6UwTvRyOKsnKxt8QGFOeMv2KXFSLFqsO4 ii/Q== Sender: swupdate@googlegroups.com X-Gm-Message-State: AOJu0YzcTkXsWiiJAjB9kXsOXO4+7eRCBbj03M/0rJVqtaCqcBUhciTp c+a1pA+JMjj1wQJ3K/8JIwnUyZMhDW+GObr6OHkunPU+5ErAYTeO X-Google-Smtp-Source: AGHT+IFHcJ86mgsbOStA947WiBPdIBYXdEZk9JYGJwRTTdyr6TMwkO4mZc8eieXZ2kG5f6OASxOtWw== X-Received: by 2002:a19:770f:0:b0:50e:ccfa:56c3 with SMTP id s15-20020a19770f000000b0050eccfa56c3mr2975802lfc.34.1706517703890; Mon, 29 Jan 2024 00:41:43 -0800 (PST) X-BeenThere: swupdate@googlegroups.com Received: by 2002:ac2:5f77:0:b0:510:1f28:24c with SMTP id c23-20020ac25f77000000b005101f28024cls800169lfc.2.-pod-prod-01-eu; Mon, 29 Jan 2024 00:41:42 -0800 (PST) X-Received: by 2002:a05:6512:3e03:b0:511:f63:d412 with SMTP id i3-20020a0565123e0300b005110f63d412mr1630893lfv.33.1706517702024; Mon, 29 Jan 2024 00:41:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1706517702; cv=none; d=google.com; s=arc-20160816; b=gUdcjTesh5xPd5kQBR273VGzbc/nwj3e9S56SNUw6EaVc0IZ6uKBant45DrmeWOtcw 8/3wy7M8GRfH0mkXjHT4X1Z+g/YEgkUVNgMyobn5eeTR/FmcFQn02RyT6rLNx4dIIGGv Hdu3Gmpb9yWfO1OS+Sjq1/OATtOVOS3lz9+0XMxwmoGwa8+nDViCXWjt1VRvATJ9im9c kzFAFshxtyif9F7c76eVm7JKptOX414bI/q5PUXOTZ+Lwv7WNHwUwLW+D6wET+c2RjyG 64D6CioKtnQDlN9GLcY0HlZ5pAz+1T5tJib5U6UUIEKQNW2gf2oWjbMvq78xg7UdT223 treA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=ui-outboundreport:content-transfer-encoding:mime-version:message-id :date:subject:cc:to:from; bh=NwdA+eqkr2WB9kOTwMCbPJSWFBiGoIBWoidrWdynhO4=; fh=TiEWcqMcKpHk5s7uErzpntoONrNfOXwKpI5P8bIlggk=; b=nUCXLIQHJFUfpjBE+m1x52b7fC4PcHaYS0unL76eIPmVjFIhMdPmvBmM5jM5rh19Be VlJVH2r8tCzQT1kAbl8qDRm6aPvcUlnWvvdyykYgik9kAo0McGN0ZxtgHf7muxOs1p71 9FOdKXOjFlYnqOl05801cDMCUoX8SfKfcznCTsplIcCIETsmcSP4l+8k+KHEeuI+NAfn Kiqkwb3EI9YYW0EW2vLsJKR8G1AEnMZpVKn7ULdpHL9kyov3BnaS0kXrVxRhIwNByXUH DYqucM9EmcNZIs4bnd9dPSJGzOVKSUaa/VV7TIMqlhUftTs5aAskdrI535jglNCwk0ry +aKg== ARC-Authentication-Results: i=1; gmr-mx.google.com; spf=pass (google.com: domain of stefano.babic@swupdate.org designates 217.72.192.73 as permitted sender) smtp.mailfrom=stefano.babic@swupdate.org Received: from mout.kundenserver.de (mout.kundenserver.de. [217.72.192.73]) by gmr-mx.google.com with ESMTPS id b40-20020a0565120ba800b005100c5a1470si229262lfv.5.2024.01.29.00.41.41 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 00:41:41 -0800 (PST) Received-SPF: pass (google.com: domain of stefano.babic@swupdate.org designates 217.72.192.73 as permitted sender) client-ip=217.72.192.73; Received: from paperino.fritz.box ([88.217.136.221]) by mrelayeu.kundenserver.de (mreue108 [213.165.67.113]) with ESMTPSA (Nemesis) id 1MO9vD-1rjSI80V3Z-00OW1t; Mon, 29 Jan 2024 09:41:41 +0100 From: Stefano Babic To: swupdate@googlegroups.com Cc: Stefano Babic Subject: [swupdate] [PATCH] docker: rework and add support for network / volumes Date: Mon, 29 Jan 2024 09:41:39 +0100 Message-Id: <20240129084139.13063-1-stefano.babic@swupdate.org> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-Provags-ID: V03:K1:+gGw0xCHTCzxVCoFL/qSZ4tpuIhU+uqdW+PPyvz+9ewaKSIM6cZ tdnJgdnlxG17hV+/tEergE0SjuaT4Q74IEDaNluKJNtLI7YltQawTyy/4K/e8reygg7t1QT TZiv8smEvTDZYf4QoPqNFiTsRi/L4Owd1fimG6PxSOMZG07uLfEN8VIT47YpZ9PmjjbnYSX hdnMRIUzRSMwaEjmMEcEg== X-Spam-Flag: NO UI-OutboundReport: notjunk:1;M01:P0:CcwOqtMqx4I=;qtAGj2EQm5eyCXSwz0KVRhfVa2L 46LrVZ/k5hwh3SnALWtrngsPxrrNZusXtkCgU/L4+kfOpbNpX1S0RSdJ20Bt68WpsPc5ihrkT m3LR42o0rhwuFpIdPQHhSoLu0jVCUfg038SX3Sg6oKJs99ONbOwatmXgLGRAs3MUyPdsoEPjd XWj2QAHat9IQ6nN2ksUqfID5aQAwrZt7wR1DDPDnTD8qtyEwz6129zpPwkm4RQ5du+q/Fk4b3 rkHtSOFTJ24wj429talAXOvYzpw9uLLHPP9jqWAHceT4J+omFFm3MbG57W2hP+afuz32m6mCH FlawXCNsEDqZxcrm4qelOYkfIYG/hy+gRPRP3H8SpZ8kwNX7kod/WTwSveL1FlEBojuiS8Qfv Ko46xRW3j3f21Cl1uLf4p49BobA33stYRvF4m0xGZFY5IDAmI5RRk2DvjCYDAg1eqJTy8zq3V /68qmbxGgO7XBxsBCVaWCyujiCDprHnn3IanQeVF1WRN/dnC5xlupk+Zu6OpqVi5EuC59j7UK oZXfCc6KqnsP1SFOLL/a+vlyPApUYbyi2AMxXzyv4lzmOLFn4vEid4vRdHvVOwFlxGDx8fqrr +e7o6v/PCDU93N1pLCr4ORVpBNT3uVr++WP0Vb57Lh6Aj0ONkVbDe99E+dtgvoHnTtFTO9Bg6 07kjqBKl0A02xJ4e95YOg1pQsVCF0aKJeaJHUxleLK1QaTf8jG/zDNn0T+3jW8B4l3DRWGPPr vM5ru3oklXoetX/EES+h1m9+5lflO3AOLvgJarOzEeH2xad2tRdyG28WPavfmEz6VhDcVeL6V MuYoU7SQMt3GEVCgnYAZOLOVA5OF1uS9TWX5kSO7iLe2LpbWsJ8ym8FeCjqUFh7WjxpK+NO++ hsgEM2jQnQU2sZg== X-Original-Sender: stefano.babic@swupdate.org X-Original-Authentication-Results: gmr-mx.google.com; spf=pass (google.com: domain of stefano.babic@swupdate.org designates 217.72.192.73 as permitted sender) smtp.mailfrom=stefano.babic@swupdate.org Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , Simplify the interface between handler and docker client. The client functions are hidden and the handler just asks for a docker service. Extend the API to support: - network: creation / deletion - volume : creation / deletion Signed-off-by: Stefano Babic --- containers/docker.c | 188 +++++++++++++++++++++++++------------ containers/docker.h | 10 -- handlers/docker_handler.c | 149 +++++++++++++++++++++-------- include/docker_interface.h | 26 +++-- 4 files changed, 254 insertions(+), 119 deletions(-) diff --git a/containers/docker.c b/containers/docker.c index 4250bebf..dff19e17 100644 --- a/containers/docker.c +++ b/containers/docker.c @@ -27,16 +27,33 @@ typedef struct { const char *url; channel_method_t method; + docker_fn func; + const char *desc; } docker_api_t; +static server_op_res_t docker_container_create(const char *name, const char *setup); +static server_op_res_t docker_image_remove(const char *name, const char *setup); +static server_op_res_t docker_image_prune(const char *name, const char *setup); +static server_op_res_t docker_container_remove(const char *name, const char *setup); +static server_op_res_t docker_container_start(const char *name, const char *setup); +static server_op_res_t docker_container_stop(const char *name, const char *setup); +static server_op_res_t docker_volumes_create(const char *name, const char *setup); +static server_op_res_t docker_volumes_remove(const char *name, const char *setup); +static server_op_res_t docker_networks_create(const char *name, const char *setup); +static server_op_res_t docker_networks_remove(const char *name, const char *setup); + docker_api_t docker_api[] = { - [DOCKER_IMAGE_LOAD] = {"/images/load", CHANNEL_POST}, - [DOCKER_IMAGE_DELETE] = {"/images/%s", CHANNEL_DELETE}, - [DOCKER_IMAGE_PRUNE] = {"/images/prune", CHANNEL_POST}, - [DOCKER_CONTAINER_CREATE] = {"/containers/create", CHANNEL_POST}, - [DOCKER_CONTAINER_DELETE] = {"/containers/%s", CHANNEL_DELETE}, - [DOCKER_CONTAINER_START] = {"/containers/%s/start", CHANNEL_POST}, - [DOCKER_CONTAINER_STOP] = {"/containers/%s/stop", CHANNEL_POST}, + [DOCKER_IMAGE_LOAD] = {"/images/load", CHANNEL_POST, NULL, "load image"}, + [DOCKER_IMAGE_DELETE] = {"/images/%s", CHANNEL_DELETE, docker_image_remove, "remove image"}, + [DOCKER_IMAGE_PRUNE] = {"/images/prune", CHANNEL_POST, docker_image_prune, "prune images"}, + [DOCKER_CONTAINER_CREATE] = {"/containers/create", CHANNEL_POST, docker_container_create, "create container"}, + [DOCKER_CONTAINER_DELETE] = {"/containers/%s", CHANNEL_DELETE, docker_container_remove, "remove container"}, + [DOCKER_CONTAINER_START] = {"/containers/%s/start", CHANNEL_POST, docker_container_start, "start container"}, + [DOCKER_CONTAINER_STOP] = {"/containers/%s/stop", CHANNEL_POST, docker_container_stop, "stop container"}, + [DOCKER_VOLUMES_CREATE] = {"/volumes/create", CHANNEL_POST, docker_volumes_create, "create volume"}, + [DOCKER_VOLUMES_DELETE] = {"/volumes/%s", CHANNEL_DELETE, docker_volumes_remove, "remove volume"}, + [DOCKER_NETWORKS_CREATE] = {"/networks/create", CHANNEL_POST, docker_networks_create, "create network"}, + [DOCKER_NETWORKS_DELETE] = {"/networks/%s", CHANNEL_DELETE, docker_networks_remove, "remove network"}, }; static channel_data_t channel_data_defaults = {.debug = true, @@ -110,6 +127,53 @@ static server_op_res_t evaluate_docker_answer(json_object *json_reply) return SERVER_EBADMSG; } +static server_op_res_t docker_send_request(docker_services_t service, char *url, const char *setup) +{ + channel_t *channel; + channel_op_res_t ch_response; + server_op_res_t result = SERVER_OK; + channel_data_t channel_data = channel_data_defaults; + + channel_data.url = url; + channel_data.method = docker_api[service].method; + + channel = docker_prepare_channel(&channel_data); + if (!channel) { + return SERVER_EERR; + } + + if (setup) + channel_data.request_body = (char *)setup; + + ch_response = channel->put(channel, &channel_data); + + if ((result = map_channel_retcode(ch_response)) != + SERVER_OK) { + channel->close(channel); + free(channel); + return SERVER_EERR; + } + + channel->close(channel); + free(channel); + + return result; +} + +static server_op_res_t docker_simple_post(docker_services_t service, const char *name, const char *setup) +{ + char url[256]; + + docker_prepare_url(service, url, sizeof(url)); + if (name) { + char *tmp=strdup(url); + snprintf(url, sizeof(url), tmp, name); + free(tmp); + } + + return docker_send_request(service, url, setup); +} + server_op_res_t docker_image_load(int fd, size_t len) { channel_t *channel; @@ -157,87 +221,87 @@ server_op_res_t docker_image_load(int fd, size_t len) return evaluate_docker_answer(channel_data.json_reply); } -static server_op_res_t docker_send_request(docker_services_t service, char *url, char *setup) -{ - channel_t *channel; - channel_op_res_t ch_response; - server_op_res_t result = SERVER_OK; - channel_data_t channel_data = channel_data_defaults; - - channel_data.url = url; - channel_data.method = docker_api[service].method; - - channel = docker_prepare_channel(&channel_data); - if (!channel) { - return SERVER_EERR; +docker_fn docker_fn_lookup(docker_services_t service) { + + switch (service) { + case DOCKER_IMAGE_LOAD: + case DOCKER_IMAGE_DELETE: + case DOCKER_IMAGE_PRUNE: + case DOCKER_CONTAINER_CREATE: + case DOCKER_CONTAINER_DELETE: + case DOCKER_CONTAINER_START: + case DOCKER_CONTAINER_STOP: + case DOCKER_VOLUMES_CREATE: + case DOCKER_VOLUMES_DELETE: + case DOCKER_NETWORKS_CREATE: + case DOCKER_NETWORKS_DELETE: + break; + default: + return NULL; } - if (setup) - channel_data.request_body = setup; - - ch_response = channel->put(channel, &channel_data); - - if ((result = map_channel_retcode(ch_response)) != - SERVER_OK) { - channel->close(channel); - free(channel); - return SERVER_EERR; - } + return docker_api[service].func; +} - channel->close(channel); - free(channel); +static server_op_res_t docker_send_with_parms(docker_services_t service, const char *name, const char *setup) +{ + char url[256]; + + if (name) { + snprintf(url, sizeof(url), "%s%s?name=%s", + docker_base_url(), docker_api[service].url, name); + } else + docker_prepare_url(service, url, sizeof(url)); - return result; + return docker_send_request(service, url, setup); } -static server_op_res_t docker_simple_post(docker_services_t service, const char *name) +static server_op_res_t docker_container_create(const char *name, const char *setup) { - char url[256]; + return docker_send_with_parms(DOCKER_CONTAINER_CREATE, name, setup); +} - docker_prepare_url(service, url, sizeof(url)); - if (name) { - char *tmp=strdup(url); - snprintf(url, sizeof(url), tmp, name); - free(tmp); - } +static server_op_res_t docker_container_remove(const char *name, const char *setup) +{ + return docker_simple_post(DOCKER_CONTAINER_DELETE, name, setup); +} - return docker_send_request(service, url, NULL); +static server_op_res_t docker_container_start(const char *name, const char *setup) +{ + return docker_simple_post(DOCKER_CONTAINER_START, name, setup); } -server_op_res_t docker_container_create(const char *name, char *setup) +static server_op_res_t docker_container_stop(const char *name, const char *setup) { - char url[256]; - - if (name) { - snprintf(url, sizeof(url), "%s%s?name=%s", - docker_base_url(), docker_api[DOCKER_CONTAINER_CREATE].url, name); - } else - docker_prepare_url(DOCKER_CONTAINER_CREATE, url, sizeof(url)); + return docker_simple_post(DOCKER_CONTAINER_STOP, name, setup); +} - return docker_send_request(DOCKER_CONTAINER_CREATE, url, setup); +static server_op_res_t docker_image_remove(const char *name, const char *setup) +{ + return docker_simple_post(DOCKER_IMAGE_DELETE, name, setup); } -server_op_res_t docker_container_remove(const char *name) +static server_op_res_t docker_image_prune(const char *name, const char *setup) { - return docker_simple_post(DOCKER_CONTAINER_DELETE, name); + return docker_simple_post(DOCKER_IMAGE_PRUNE, name, setup); } -server_op_res_t docker_container_start(const char *name) +static server_op_res_t docker_volumes_create(const char __attribute__ ((__unused__)) *name, const char *setup) { - return docker_simple_post(DOCKER_CONTAINER_START, name); + return docker_send_with_parms(DOCKER_VOLUMES_CREATE, NULL, setup); } -server_op_res_t docker_container_stop(const char *name) +static server_op_res_t docker_volumes_remove(const char *name, const char *setup) { - return docker_simple_post(DOCKER_CONTAINER_STOP, name); + return docker_simple_post(DOCKER_VOLUMES_DELETE, name, setup); } -server_op_res_t docker_image_remove(const char *name) +static server_op_res_t docker_networks_create(const char __attribute__ ((__unused__)) *name, const char *setup) { - return docker_simple_post(DOCKER_IMAGE_DELETE, name); + return docker_send_with_parms(DOCKER_NETWORKS_CREATE, NULL, setup); } -server_op_res_t docker_image_prune(const char *name) +static server_op_res_t docker_networks_remove(const char *name, const char *setup) { - return docker_simple_post(DOCKER_IMAGE_PRUNE, name); + return docker_simple_post(DOCKER_NETWORKS_DELETE, name, setup); } diff --git a/containers/docker.h b/containers/docker.h index 84ad3a0d..9d72db17 100644 --- a/containers/docker.h +++ b/containers/docker.h @@ -21,13 +21,3 @@ /* Docker base URL */ #define DOCKER_BASE_URL DOCKER_SOCKET_URL DOCKER_API_VERSION "/" - -typedef enum { - DOCKER_IMAGE_LOAD, - DOCKER_IMAGE_DELETE, - DOCKER_IMAGE_PRUNE, - DOCKER_CONTAINER_CREATE, - DOCKER_CONTAINER_DELETE, - DOCKER_CONTAINER_START, - DOCKER_CONTAINER_STOP -} docker_services_t; diff --git a/handlers/docker_handler.c b/handlers/docker_handler.c index 0509abd2..e9cbae0c 100644 --- a/handlers/docker_handler.c +++ b/handlers/docker_handler.c @@ -28,16 +28,6 @@ #include "swupdate_image.h" #include "docker_interface.h" -void docker_loadimage_handler(void); -void docker_deleteimage_handler(void); -void docker_pruneimage_handler(void); -void docker_createcontainer_handler(void); -void docker_deletecontainer_handler(void); -void docker_container_start_handler(void); -void docker_container_stop_handler(void); - -typedef server_op_res_t (*docker_fn)(const char *name); - #define FIFO_THREAD_READ 0 #define FIFO_HND_WRITE 1 @@ -154,10 +144,11 @@ handler_exit: } /* - * Implementation POST /container/create + * Docker API requires one parameter and maybe a JSON file used as configuration. + * Pass to the docker client the properties (only name is checked) and a JSON file if + * present. This is the script itself and not an "artifact image". */ -static int docker_create_container(struct img_type *img, - void __attribute__ ((__unused__)) *data) +static int docker_send_cmd_with_setup(struct img_type *img, void *data, docker_services_t service) { struct script_handler_data *script_data = data; char *script = NULL; @@ -172,7 +163,6 @@ static int docker_create_container(struct img_type *img, if (!script_data || script_data->scriptfn != POSTINSTALL) return 0; - if (asprintf(&script, "%s%s", get_tmpdirscripts(), img->fname) == ENOMEM_ASPRINTF) { ERROR("OOM when creating script path"); return -ENOMEM; @@ -181,14 +171,17 @@ static int docker_create_container(struct img_type *img, if (stat(script, &sb) == -1) { ERROR("stat fails on %s", script); result = -EFAULT; - goto create_container_exit; + goto send_to_docker_exit; } + /* + * Load the script / JSON config in memory + */ fd = open(script, O_RDONLY); if (fd < 0) { ERROR("%s cannot be opened, exiting..", script); result = -EFAULT; - goto create_container_exit; + goto send_to_docker_exit; } buf = (char *)malloc(sb.st_size); @@ -196,7 +189,7 @@ static int docker_create_container(struct img_type *img, ERROR("OOM creating buffer for reading %s of %ld bytes", script, sb.st_size); result = -ENOMEM; - goto create_container_exit; + goto send_to_docker_exit; } ssize_t n = read(fd, buf, sb.st_size); @@ -204,16 +197,32 @@ static int docker_create_container(struct img_type *img, ERROR("Script %s cannot be read, return value %ld != %ld", script, n, sb.st_size); result = -EFAULT; - goto create_container_exit; + goto send_to_docker_exit; } + /* + * Check for a "name" properties - this is mandatory + * when a resource is deleted + */ char *name = dict_get_value(&img->properties, "name"); - TRACE("DOCKER CREATE CONTAINER"); + /* + * Retrieve which function is responsible for a service + */ + docker_fn fn = docker_fn_lookup(service); - result = docker_container_create(name, buf); + /* + * Call docker internal client + */ + if (fn) { + result = fn(name, buf); + } else { + result = -EINVAL; + ERROR("Service %d not supported", service); + } -create_container_exit: +send_to_docker_exit: + /* cleanup and exit */ free(script); free(buf); if (fd > 0) close(fd); @@ -223,11 +232,14 @@ create_container_exit: } /* - * Implementation DELETE /container/{id} + * Simple service without configuration file + * Just lokup for the client function and call it */ -static int docker_query(struct img_type *img, void *data, docker_fn fn) +static int docker_query(struct img_type *img, void *data, docker_services_t service) { struct script_handler_data *script_data = data; + docker_fn fn; + /* * Call only in case of postinstall */ @@ -241,52 +253,85 @@ static int docker_query(struct img_type *img, void *data, docker_fn fn) return -EINVAL; } - return fn(name); + fn = docker_fn_lookup(service); + + if (!fn) { + ERROR("Docker service %d nbot supported", service); + return -EINVAL; + } + return fn(name, NULL); +} + +/* Docker service wrappers */ +static int container_create(struct img_type *img, void *data) +{ + return docker_send_cmd_with_setup(img, data, DOCKER_CONTAINER_CREATE); } static int container_delete(struct img_type *img, void *data) { - return docker_query(img, data, docker_container_remove); + return docker_query(img, data, DOCKER_CONTAINER_DELETE); } static int image_delete(struct img_type *img, void *data) { - return docker_query(img, data, docker_image_remove); + return docker_query(img, data, DOCKER_IMAGE_DELETE); } static int image_prune(struct img_type *img, void *data) { - return docker_query(img, data, docker_image_prune); + return docker_query(img, data, DOCKER_IMAGE_PRUNE); } - static int container_start(struct img_type *img, void *data) { - return docker_query(img, data, docker_container_start); + return docker_query(img, data, DOCKER_CONTAINER_START); +} + +static int network_create(struct img_type *img, void *data) +{ + return docker_send_cmd_with_setup(img, data, DOCKER_NETWORKS_CREATE); +} + +static int network_delete(struct img_type *img, void *data) +{ + return docker_query(img, data, DOCKER_NETWORKS_DELETE); +} + +static int volume_create(struct img_type *img, void *data) +{ + return docker_send_cmd_with_setup(img, data, DOCKER_VOLUMES_CREATE); +} + +static int volume_delete(struct img_type *img, void *data) +{ + return docker_query(img, data, DOCKER_VOLUMES_DELETE); } static int container_stop(struct img_type *img, void *data) { - return docker_query(img, data, docker_container_stop); + return docker_query(img, data, DOCKER_CONTAINER_STOP); } +/* Handlers entry points */ + __attribute__((constructor)) -void docker_loadimage_handler(void) +static void docker_loadimage_handler(void) { register_handler("docker_imageload", docker_install_image, IMAGE_HANDLER, NULL); } __attribute__((constructor)) -void docker_deleteimage_handler(void) +static void docker_deleteimage_handler(void) { register_handler("docker_imagedelete", image_delete, SCRIPT_HANDLER | NO_DATA_HANDLER, NULL); } __attribute__((constructor)) -void docker_pruneimage_handler(void) +static void docker_pruneimage_handler(void) { register_handler("docker_imageprune", image_prune, SCRIPT_HANDLER | NO_DATA_HANDLER, NULL); @@ -294,29 +339,57 @@ void docker_pruneimage_handler(void) __attribute__((constructor)) -void docker_createcontainer_handler(void) +static void docker_createcontainer_handler(void) { - register_handler("docker_containercreate", docker_create_container, + register_handler("docker_containercreate", container_create, SCRIPT_HANDLER, NULL); } __attribute__((constructor)) -void docker_deletecontainer_handler(void) +static void docker_deletecontainer_handler(void) { register_handler("docker_containerdelete", container_delete, SCRIPT_HANDLER | NO_DATA_HANDLER, NULL); } __attribute__((constructor)) -void docker_container_start_handler(void) +static void docker_container_start_handler(void) { register_handler("docker_containerstart", container_start, SCRIPT_HANDLER | NO_DATA_HANDLER, NULL); } __attribute__((constructor)) -void docker_container_stop_handler(void) +static void docker_container_stop_handler(void) { register_handler("docker_containerstart", container_stop, SCRIPT_HANDLER | NO_DATA_HANDLER, NULL); } + +__attribute__((constructor)) +static void docker_createnetwork_handler(void) +{ + register_handler("docker_networkcreate", network_create, + SCRIPT_HANDLER, NULL); +} + +__attribute__((constructor)) +static void docker_deletenetwork_handler(void) +{ + register_handler("docker_networkdelete", network_delete, + SCRIPT_HANDLER | NO_DATA_HANDLER, NULL); +} + +__attribute__((constructor)) +static void docker_createvolume_handler(void) +{ + register_handler("docker_volumecreate", volume_create, + SCRIPT_HANDLER, NULL); +} + +__attribute__((constructor)) +static void docker_deletevolume_handler(void) +{ + register_handler("docker_volumedelete", volume_delete, + SCRIPT_HANDLER | NO_DATA_HANDLER, NULL); +} diff --git a/include/docker_interface.h b/include/docker_interface.h index f77453d6..789c995c 100644 --- a/include/docker_interface.h +++ b/include/docker_interface.h @@ -9,13 +9,21 @@ #include "server_utils.h" -/* Load an image - * fd : file descriptor where to read the stream to be pushed - */ +typedef enum { + DOCKER_IMAGE_LOAD, + DOCKER_IMAGE_DELETE, + DOCKER_IMAGE_PRUNE, + DOCKER_CONTAINER_CREATE, + DOCKER_CONTAINER_DELETE, + DOCKER_CONTAINER_START, + DOCKER_CONTAINER_STOP, + DOCKER_VOLUMES_CREATE, + DOCKER_VOLUMES_DELETE, + DOCKER_NETWORKS_CREATE, + DOCKER_NETWORKS_DELETE, + DOCKER_SERVICE_LAST = DOCKER_NETWORKS_DELETE, +} docker_services_t; + +typedef server_op_res_t (*docker_fn)(const char *name, const char *setup); +docker_fn docker_fn_lookup(docker_services_t service); server_op_res_t docker_image_load(int fd, size_t nbytes); -server_op_res_t docker_image_remove(const char *name); -server_op_res_t docker_image_prune(const char *name); -server_op_res_t docker_container_create(const char *name, char *setup); -server_op_res_t docker_container_remove(const char *name); -server_op_res_t docker_container_start(const char *name); -server_op_res_t docker_container_stop(const char *name);