From 5e506771c2907d8ad18c2a254478c4644a5aa7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=C3=A1n=20C=20McCord?= Date: Mon, 30 Mar 2020 17:36:33 -0400 Subject: [PATCH] Add CLI-based system-ready state indicator This eliminates the need for artificial delays to make sure Asterisk is up and ready. We now leverage a `cli.conf` entry to set the system global variable `ASTERISK_CONFIG_SYSTEM_READY` when Asterisk has completely loaded. --- defaults/cli.conf | 5 +++++ defaults/cli.d/keep.conf | 0 defaults/cli_custom.conf | 0 main.go | 46 +++++++++++++++++++++++----------------- 4 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 defaults/cli.conf create mode 100644 defaults/cli.d/keep.conf create mode 100644 defaults/cli_custom.conf diff --git a/defaults/cli.conf b/defaults/cli.conf new file mode 100644 index 0000000..28a6161 --- /dev/null +++ b/defaults/cli.conf @@ -0,0 +1,5 @@ +[startup_commands] +dialplan set global ASTERISK_CONFIG_SYSTEM_READY 1 + +#include cli_custom.conf +#include cli.d/*.conf diff --git a/defaults/cli.d/keep.conf b/defaults/cli.d/keep.conf new file mode 100644 index 0000000..e69de29 diff --git a/defaults/cli_custom.conf b/defaults/cli_custom.conf new file mode 100644 index 0000000..e69de29 diff --git a/main.go b/main.go index 69db489..9bf1118 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "archive/zip" "context" + "encoding/json" "fmt" "io" "io/ioutil" @@ -170,18 +171,6 @@ func (s *Service) Run() error { s.engine.FirstRenderComplete(true) - // Wait for Asterisk to come up before proceeding, so as to not interrupt - // normal Asterisk loading with a reload - if err := waitAsterisk(ariUsername, s.Secret); err != nil { - return errors.Wrap(err, "failed to wait for Asterisk to come up") - } - - // pad Asterisk startup to wait for complete load - // - // FIXME: we need to figure out a canonical and proactive way to determine - // is Asterisk fully up - time.Sleep(time.Second) - for { if err := <-renderChan; err != nil { return errors.Wrap(err, "failure during watch") @@ -295,27 +284,39 @@ func render(e *kubetemplate.Engine, customRoot string, exportRoot string) error } func waitAsterisk(username, secret string) error { - r, err := http.NewRequest("GET", "http://127.0.0.1:8088/ari/asterisk/ping", nil) + r, err := http.NewRequest("GET", "http://127.0.0.1:8088/ari/asterisk/variable?variable=ASTERISK_CONFIG_SYSTEM_READY", nil) if err != nil { return errors.Wrap(err, "failed to construct ping request") } r.Header.Set("Content-Type", "application/json") r.SetBasicAuth(username, secret) + type response struct { + Value string `json:"value"` + } + resp := new(response) + for { + time.Sleep(time.Second / 2) + ret, err := http.DefaultClient.Do(r) if err != nil { - time.Sleep(time.Second) continue } - if err := ret.Body.Close(); err != nil { - return errors.Wrap(err, "failed to close http response body") + if err = json.NewDecoder(ret.Body).Decode(resp); err != nil { + // failed to decode into resp format + log.Println("failed to decode Asterisk response:", err) + continue } - - if ret.StatusCode == http.StatusOK { - return nil + if resp.Value != "1" { + // not yet ready + continue } + + // System ready + log.Println("Asterisk ready") + return nil } } @@ -437,6 +438,13 @@ func newReloader(ctx context.Context, username, secret, modules string) *reloade } func (r *reloader) run(ctx context.Context) { + // Wait for Asterisk to come up before proceeding, so as to not interrupt + // normal Asterisk loading with a reload + log.Println("Waiting for Asterisk to be ready...") + if err := waitAsterisk(r.username, r.secret); err != nil { + log.Fatalln("failed to wait for Asterisk to come up:", err) + } + for { select { case <-ctx.Done():