]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Flock: Stopping containers from CLI
authorMaria Matejka <mq@ucw.cz>
Fri, 27 Sep 2024 18:09:51 +0000 (20:09 +0200)
committerMaria Matejka <mq@ucw.cz>
Sun, 23 Feb 2025 18:07:35 +0000 (19:07 +0100)
flock/container.c
flock/ctl.c
flock/flock-cli
flock/flock.h

index 234610e110d281a2cd9420f0e294934f7560dafb..d3fe2e95dc2177b5a0407bb2476e9cc5da7e2504 100644 (file)
@@ -31,7 +31,7 @@ struct container_runtime {
   uint hash;
   pid_t pid;
   sock *s;
-  struct container_created_callback {
+  struct container_operation_callback {
     callback cb;
     sock *s;
     void *data;
@@ -60,6 +60,19 @@ container_child_sighandler(int signo UNUSED)
 
 static int container_forker_fd = -1;
 
+static void
+container_poweroff(int fd, int sig)
+{
+  byte outbuf[128];
+  linpool *lp = lp_new(&root_pool);
+  struct cbor_writer *cw = cbor_init(outbuf, sizeof outbuf, lp);
+  cbor_open_block_with_length(cw, 1);
+  cbor_add_int(cw, -4);
+  cbor_add_int(cw, sig);
+  ASSERT_DIE(write(fd, outbuf, cw->pt) == cw->pt);
+  exit(0);
+}
+
 static void
 container_mainloop(int fd)
 {
@@ -83,15 +96,27 @@ container_mainloop(int fd)
     int res = ppoll(&pfd, 1, NULL, &newmask);
 
     if (poweroff)
+      container_poweroff(fd, poweroff);
+
+    if (pfd.revents & POLLIN)
     {
-      byte outbuf[128];
-      linpool *lp = lp_new(&root_pool);
-      struct cbor_writer *cw = cbor_init(outbuf, sizeof outbuf, lp);
-      cbor_open_block_with_length(cw, 1);
-      cbor_add_int(cw, -4);
-      cbor_add_int(cw, poweroff);
-      ASSERT_DIE(write(fd, outbuf, cw->pt) == cw->pt);
-      exit(0);
+      byte buf[128];
+      ssize_t sz = read(fd, buf, sizeof buf);
+      if (sz < 0)
+      {
+       log(L_ERR "error reading data from control socket: %m");
+       exit(1);
+      }
+
+      ASSERT_DIE(sz >= 3);
+      ASSERT_DIE(buf[0] == 0xa1);
+      switch (buf[1]) {
+       case 0:
+         ASSERT_DIE(buf[2] == 0xf6);
+         container_poweroff(fd, 0);
+         break;
+
+      }
     }
 
     /* TODO: check for telnet socket */
@@ -203,6 +228,14 @@ container_start(void)
 
 /* The Parent */
 
+static void
+container_cleanup(struct container_runtime *crt)
+{
+  HASH_REMOVE(hcf.hash, CRT, crt);
+  sk_close(crt->s);
+  mb_free(crt);
+}
+
 static int
 hypervisor_container_rx(sock *sk, uint _sz UNUSED)
 {
@@ -215,7 +248,25 @@ hypervisor_container_rx(sock *sk, uint _sz UNUSED)
     return 0;
   }
 
-  log(L_INFO "received %u data from %p (container_rx)", sz, sk);
+  struct container_runtime *crt = sk->data;
+  ASSERT_DIE(crt->s == sk);
+
+  ASSERT_DIE(sz >= 3);
+  ASSERT_DIE(buf[0] == 0xa1);
+
+  switch (buf[1]) {
+    case 0x23:
+      log(L_INFO "container %s ended by signal %d", crt->ccf.hostname, buf[2]);
+      if (crt->ccc)
+       callback_activate(&crt->ccc->cb);
+      container_cleanup(crt);
+      break;
+
+    default:
+      log(L_ERR "container %s sent a weird message 0x%02x sz %d", crt->ccf.hostname, buf[1], sz);
+      break;
+  }
+
   return 0;
 }
 
@@ -267,18 +318,23 @@ hypervisor_container_forker_rx(sock *sk, uint _sz UNUSED)
   skl->type = SK_MAGIC;
   skl->rx_hook = hypervisor_container_rx;
   skl->fd = sfd;
+  sk_set_tbsize(skl, 1024);
+
   if (sk_open(skl, sk->loop) < 0)
     bug("Machine control socket: sk_open failed");
 
   ASSERT_DIE(birdloop_inside(hcf.loop));
 
   ASSERT_DIE(hcf.cur_crt);
+  skl->data = hcf.cur_crt;
+
   hcf.cur_crt->pid = pid;
   hcf.cur_crt->s = skl;
   if (hcf.cur_crt->ccc)
     callback_activate(&hcf.cur_crt->ccc->cb);
   hcf.cur_crt->ccc = NULL;
   hcf.cur_crt = NULL;
+
   return 0;
 }
 
@@ -303,8 +359,8 @@ crt_err(sock *s, int err UNUSED)
 static void
 container_created(callback *cb)
 {
-  SKIP_BACK_DECLARE(struct container_created_callback, ccc, cb, cb);
-  
+  SKIP_BACK_DECLARE(struct container_operation_callback, ccc, cb, cb);
+
   sock *s = ccc->s;
   linpool *lp = lp_new(s->pool);
   struct cbor_writer *cw = cbor_init(s->tbuf, s->tbsize, lp);
@@ -363,8 +419,8 @@ hypervisor_container_request(sock *s, const char *name, const char *basedir, con
 
   crt->hash = h;
 
-  struct container_created_callback *ccc = mb_alloc(s->pool, sizeof *ccc);
-  *ccc = (struct container_created_callback) {
+  struct container_operation_callback *ccc = mb_alloc(s->pool, sizeof *ccc);
+  *ccc = (struct container_operation_callback) {
     .s = s,
     .data = s->data,
   };
@@ -397,6 +453,72 @@ hypervisor_container_request(sock *s, const char *name, const char *basedir, con
   birdloop_leave(hcf.loop);
 }
 
+static void
+container_stopped(callback *cb)
+{
+  SKIP_BACK_DECLARE(struct container_operation_callback, ccc, cb, cb);
+
+  sock *s = ccc->s;
+  linpool *lp = lp_new(s->pool);
+  struct cbor_writer *cw = cbor_init(s->tbuf, s->tbsize, lp);
+  cbor_open_block_with_length(cw, 1);
+  cbor_add_int(cw, -1);
+  cbor_add_string(cw, "OK");
+  sk_send(s, cw->pt);
+  rfree(lp);
+
+  s->data = ccc->data;
+  sk_resume_rx(s->loop, s);
+
+  mb_free(ccc);
+}
+
+void
+hypervisor_container_shutdown(sock *s, const char *name)
+{
+  birdloop_enter(hcf.loop);
+
+  uint h = mem_hash(name, strlen(name));
+  struct container_runtime *crt = HASH_FIND(hcf.hash, CRT, name, h);
+
+  linpool *lp = lp_new(hcf.p);
+
+  if (!crt || !crt->s)
+  {
+    struct cbor_writer *cw = cbor_init(s->tbuf, s->tbsize, lp);
+    cbor_open_block_with_length(cw, 1);
+    cbor_add_int(cw, -127);
+    cbor_add_string(cw, "BAD: Not found");
+
+    sk_send(s, cw->pt);
+    rfree(lp);
+    birdloop_leave(hcf.loop);
+    return;
+  }
+
+  struct cbor_writer *cw = cbor_init(crt->s->tbuf, crt->s->tbsize, lp);
+  cbor_open_block_with_length(cw, 1);
+  cbor_add_int(cw, 0);
+  write_item(cw, 7, 22);
+
+  sk_send(crt->s, cw->pt);
+  rfree(lp);
+
+  struct container_operation_callback *ccc = mb_alloc(s->pool, sizeof *ccc);
+  *ccc = (struct container_operation_callback) {
+    .s = s,
+    .data = s->data,
+  };
+  callback_init(&ccc->cb, container_stopped, s->loop);
+  crt->ccc = ccc;
+
+  s->err_paused = crt_err;
+  s->data = crt;
+  sk_pause_rx(s->loop, s);
+
+  birdloop_leave(hcf.loop);
+}
+
 struct cbor_parser_context {
   linpool *lp;
 
index 83433e3d4aea956e7979075aade003a23b66ea16..7d816d58b8557fbc03be833a14e7f6efb88cabaf 100644 (file)
@@ -212,7 +212,14 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            ctx->major_state = 501;
            break;
 
-         case 6: /* process spawner */
+         case 6: /* machine shutdown request */
+           if (ctx->type != 5)
+             CBOR_PARSER_ERROR("Expecting mapping, got %u", ctx->type);
+
+           ctx->major_state = 601;
+           break;
+
+         case 7: /* process spawner */
            CBOR_PARSER_ERROR("NOT IMPLEMENTED YET");
            break;
 
@@ -285,6 +292,31 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            ctx->target_len = ctx->value;
            break;
 
+         case 601: /* machine shutdown argument */
+           if (ctx->type != 0)
+             CBOR_PARSER_ERROR("Expected integer, got %u", ctx->type);
+
+           if (ctx->value >= 1)
+             CBOR_PARSER_ERROR("Command key too high, got %lu", ctx->value);
+
+           ctx->major_state = ctx->value + 602;
+           break;
+
+         case 602: /* machine creation argument 0: name */
+           if (ctx->type != 3)
+             CBOR_PARSER_ERROR("Expected string, got %u", ctx->type);
+
+           if (value_is_special)
+             CBOR_PARSER_ERROR("Variable length string not supported yet");
+
+           if (ctx->cfg.cf.name)
+             CBOR_PARSER_ERROR("Duplicate argument 0 / name");
+
+           ASSERT_DIE(!ctx->target_buf);
+           ctx->cfg.cf.name = ctx->target_buf = lp_alloc(ctx->lp, ctx->value + 1);
+           ctx->target_len = ctx->value;
+           break;
+
          default:
            bug("invalid parser state");
        }
@@ -342,6 +374,10 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
            ctx->major_state = 501;
            break;
 
+         case 602:
+           ctx->major_state = 601;
+           break;
+
          default:
            bug("Unexpected state to end a (byte)string in");
          /* Code to run at the end of a (byte)string */
@@ -395,6 +431,15 @@ hcs_parse(struct cbor_parser_context *ctx, const byte *buf, s64 size)
          ctx->major_state = 1;
          break;
 
+       case 601:
+         if (!ctx->cfg.cf.name)
+           CBOR_PARSER_ERROR("Machine name not specified");
+
+         hypervisor_container_shutdown(ctx->sock, ctx->cfg.cf.name);
+
+         ctx->major_state = 1;
+         break;
+
        default:
          bug("Unexpected state to end a mapping in");
       }
index ed60d81ece6eea4c7affd8237b91920d64f92d1d..5cac0e6ccdeb17dbc4041fa73e990ffecd83cf22 100755 (executable)
@@ -100,6 +100,11 @@ def container_start(hypervisor: str, name: str):
         }}).items():
         print(k,v)
 
+@handler
+def container_stop(hypervisor: str, name: str):
+    for k,v in msg(hypervisor, { 4: { 0: name, }}).items():
+        print(k,v)
+
 try:
     binname = sys.argv.pop(0)
 except Exception as e:
index 01835de9052a82b69ece1a1907013d8ec3080741..0601848f4cf88214bb611f286801b88e66e04a28 100644 (file)
@@ -47,6 +47,7 @@ union flock_machine_config {
 
 
 void hypervisor_container_request(sock *s, const char *name, const char *basedir, const char *workdir);
+void hypervisor_container_shutdown(sock *s, const char *name);
 
 extern event reboot_event, poweroff_event;
 extern event_list shutdown_event_list;