From cc67789d6a7d3b7ee9acf9473ff1dffb367f5f3b Mon Sep 17 00:00:00 2001 From: jamesread Date: Tue, 7 Jul 2026 16:45:12 +0100 Subject: [PATCH] chore: fabric config --- go.mod | 10 +--- go.sum | 54 +----------------- internal/amqp/executionRequests.go | 2 +- internal/amqp/heartbeat.go | 2 +- internal/amqp/pings.go | 2 +- internal/amqp/startup.go | 2 +- internal/fabricConfig/fetch.go | 48 ++++++++++++++++ internal/fabricConfig/model.go | 48 +++++++++------- internal/fabricConfig/model_test.go | 54 ++++++++++++++++++ internal/fabricConfig/runner.go | 19 +++++-- internal/fabricConfig/runner_test.go | 27 ++++----- internal/serviceConfig/config.go | 79 ++++++++++++++++++++------- internal/serviceConfig/config_test.go | 22 ++++++++ internal/updater/updater.go | 53 +++++++++++++----- internal/updater/updater_test.go | 22 ++++++++ internal/util/events.go | 2 +- internal/util/hostname.go | 9 +++ internal/util/hostname_test.go | 22 ++++++++ 18 files changed, 337 insertions(+), 140 deletions(-) create mode 100644 internal/fabricConfig/fetch.go create mode 100644 internal/fabricConfig/model_test.go create mode 100644 internal/serviceConfig/config_test.go create mode 100644 internal/updater/updater_test.go create mode 100644 internal/util/hostname_test.go diff --git a/go.mod b/go.mod index b1edd06..091679c 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 github.com/upsilonproject/upsilon-gocommon v0.0.0-20250216225835-71bff12ad35e + google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v2 v2.4.0 ) @@ -27,13 +28,10 @@ require ( github.com/google/go-github/v30 v30.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/magiconair/properties v1.8.10 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/onsi/gomega v1.36.2 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -41,8 +39,6 @@ require ( github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect @@ -53,14 +49,10 @@ require ( github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 // indirect github.com/ulikunitz/xz v0.5.14 // indirect go.uber.org/atomic v1.11.0 // indirect - go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.35.0 // indirect - golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect golang.org/x/oauth2 v0.27.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 874e632..8e4ff5a 100644 --- a/go.sum +++ b/go.sum @@ -6,7 +6,6 @@ github.com/apenella/go-common-utils/error v0.0.0-20221227202648-5452d804e940 h1: github.com/apenella/go-common-utils/error v0.0.0-20221227202648-5452d804e940/go.mod h1:+3dyIlHX350xJIUIffwMLswZXU+N2FwDE05VuKqxYdw= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -18,8 +17,6 @@ github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4Nij github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= @@ -31,8 +28,8 @@ github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlnd github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -41,8 +38,6 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= @@ -57,23 +52,15 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= -github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= -github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -91,39 +78,21 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4 github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= -github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sosedoff/ansible-vault-go v0.2.0 h1:XqkBdqbXgTuFQ++NdrZvSdUTNozeb6S3V5x7FVs17vg= github.com/sosedoff/ansible-vault-go v0.2.0/go.mod h1:wMU54HNJfY0n0KIgbpA9m15NBfaUDlJrAsaZp0FwzkI= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM= @@ -138,8 +107,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= @@ -150,25 +118,17 @@ github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569/go.mod h1:2Ly+NIf github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.14 h1:uv/0Bq533iFdnMHZdRBTOlaNMdb1+ZxXIlHDZHIHcvg= github.com/ulikunitz/xz v0.5.14/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/upsilonproject/upsilon-gocommon v0.0.0-20250213175504-bfa5c06156b6 h1:vbuJKIEOYG5ZwnNYgR3SPcuCblh6XAi/K2R3tOus2FA= -github.com/upsilonproject/upsilon-gocommon v0.0.0-20250213175504-bfa5c06156b6/go.mod h1:Hxf759RHG+diuWilWwtaKQ6RYJ0sRP/sbyX1Y9xT9pw= github.com/upsilonproject/upsilon-gocommon v0.0.0-20250216225835-71bff12ad35e h1:ow69nYW1K2cyU0m3+D1d0r0NR+88/XbLTk1NVdBiyLs= github.com/upsilonproject/upsilon-gocommon v0.0.0-20250216225835-71bff12ad35e/go.mod h1:Hxf759RHG+diuWilWwtaKQ6RYJ0sRP/sbyX1Y9xT9pw= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -186,23 +146,17 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -211,8 +165,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/internal/amqp/executionRequests.go b/internal/amqp/executionRequests.go index a471e06..07c0469 100644 --- a/internal/amqp/executionRequests.go +++ b/internal/amqp/executionRequests.go @@ -16,7 +16,7 @@ func ListenForExecutionRequests() { amqp.Decode(d.Message.Body, &execReq) - if execReq.Hostname == util.GetHostname() { + if execReq.Hostname == util.GetIdentifier() { log.Infof("Responding to execreq: %v", execReq.CommandName) fabricConfig.ExecCommandByName(execReq.CommandName) diff --git a/internal/amqp/heartbeat.go b/internal/amqp/heartbeat.go index 1e1a1dc..1445071 100644 --- a/internal/amqp/heartbeat.go +++ b/internal/amqp/heartbeat.go @@ -30,7 +30,7 @@ func newMessageHeartbeat() *pb.Heartbeat { hb := &pb.Heartbeat{ UnixTimestamp: time.Now().Unix(), Type: "drone", - Hostname: util.GetHostname(), + Hostname: util.GetIdentifier(), StatusLine: fmt.Sprintf("cfg: %+v", fabricConfig.ConfigStatus), Version: buildconstants.Timestamp, } diff --git a/internal/amqp/pings.go b/internal/amqp/pings.go index 9edf746..318fc93 100644 --- a/internal/amqp/pings.go +++ b/internal/amqp/pings.go @@ -16,7 +16,7 @@ func ListenForPings() { log.Infof("Responding to ping") res := &pb.PingResponse{} - res.Hostname = util.GetHostname() + res.Hostname = util.GetIdentifier() amqp.PublishPb(res) }) diff --git a/internal/amqp/startup.go b/internal/amqp/startup.go index cdae73f..ccd17e7 100644 --- a/internal/amqp/startup.go +++ b/internal/amqp/startup.go @@ -9,7 +9,7 @@ import ( func SendStartup() { startup := &pb.Startup { - Hostname: util.GetHostname(), + Hostname: util.GetIdentifier(), } amqp.PublishPb(startup) diff --git a/internal/fabricConfig/fetch.go b/internal/fabricConfig/fetch.go new file mode 100644 index 0000000..a53f699 --- /dev/null +++ b/internal/fabricConfig/fetch.go @@ -0,0 +1,48 @@ +package fabricConfig + +import ( + "fmt" + "io" + "net/http" + "os" + "path/filepath" +) + +const defaultFabricConfigURL = "http://upsilon/upsilon-config/config.yml" + +func fabricConfigURL() string { + if url := os.Getenv("UPSILON_FABRIC_CONFIG_URL"); url != "" { + return url + } + return defaultFabricConfigURL +} + +func FetchConfigFromHTTP(destPath string) error { + url := fabricConfigURL() + + resp, err := http.Get(url) + if err != nil { + return fmt.Errorf("fetch fabric config from %s: %w", url, err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("fetch fabric config from %s: HTTP %d", url, resp.StatusCode) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("read fabric config body: %w", err) + } + + if err := os.MkdirAll(destPath, 0755); err != nil { + return fmt.Errorf("create fabric config directory: %w", err) + } + + configPath := filepath.Join(destPath, "config.yml") + if err := os.WriteFile(configPath, body, 0644); err != nil { + return fmt.Errorf("write fabric config: %w", err) + } + + return nil +} diff --git a/internal/fabricConfig/model.go b/internal/fabricConfig/model.go index 76ba6e8..0c2df16 100644 --- a/internal/fabricConfig/model.go +++ b/internal/fabricConfig/model.go @@ -1,7 +1,7 @@ package fabricConfig func (cfg *FabricConfig) FindCommand(search string) *Command { - for _, cmd := range(cfg.Commands) { + for _, cmd := range cfg.Commands { if cmd.Name == search { return &cmd } @@ -11,7 +11,7 @@ func (cfg *FabricConfig) FindCommand(search string) *Command { } func (cfg *FabricConfig) FindPipeline(search string) *CommandPipeline { - for _, pl := range(cfg.Pipelines) { + for _, pl := range cfg.Pipelines { if pl.Name == search { return &pl } @@ -20,37 +20,47 @@ func (cfg *FabricConfig) FindPipeline(search string) *CommandPipeline { return nil } +func (cfg *FabricConfig) normalize() { + for i := range cfg.Groups { + group := &cfg.Groups[i] + if len(group.Commands) == 0 && len(group.Mappings) > 0 { + group.Commands = group.Mappings + } + } +} + type FabricConfig struct { - Commands []Command - Groups []CommandGroup - Pipelines []CommandPipeline + Commands []Command `yaml:"commands"` + Groups []CommandGroup `yaml:"groups"` + Pipelines []CommandPipeline `yaml:"pipelines"` } type CommandGroup struct { - Hosts []string - Commands []CommandMapping - Pipelines []PipelineMapping + Hosts []string `yaml:"hosts"` + Commands []CommandMapping `yaml:"commands"` + Mappings []CommandMapping `yaml:"mappings"` + Pipelines []PipelineMapping `yaml:"pipelines"` } type Command struct { - Name string - Exec string - Label string + Name string `yaml:"name"` + Exec string `yaml:"exec"` + Label string `yaml:"label"` } type CommandMapping struct { - Command string - Interval int - Arguments map[string]any + Command string `yaml:"command"` + Interval int `yaml:"interval"` + Arguments map[string]any `yaml:"arguments"` } type PipelineMapping struct { - Pipeline string - Interval int - Arguments map[string]any + Pipeline string `yaml:"pipeline"` + Interval int `yaml:"interval"` + Arguments map[string]any `yaml:"arguments"` } type CommandPipeline struct { - Name string - Sequence []CommandMapping + Name string `yaml:"name"` + Sequence []CommandMapping `yaml:"sequence"` } diff --git a/internal/fabricConfig/model_test.go b/internal/fabricConfig/model_test.go new file mode 100644 index 0000000..f8b9346 --- /dev/null +++ b/internal/fabricConfig/model_test.go @@ -0,0 +1,54 @@ +package fabricConfig + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" +) + +func TestUnmarshalMappingsAlias(t *testing.T) { + raw := []byte(` +commands: + - name: date + exec: date +groups: + - hosts: [all] + mappings: + - command: date + interval: 1 +`) + + var cfg FabricConfig + err := yaml.UnmarshalStrict(raw, &cfg) + assert.NoError(t, err) + + cfg.normalize() + + assert.Len(t, cfg.Groups, 1) + assert.Len(t, cfg.Groups[0].Commands, 1) + assert.Equal(t, "date", cfg.Groups[0].Commands[0].Command) + assert.Equal(t, 1, cfg.Groups[0].Commands[0].Interval) +} + +func TestUnmarshalCommandsField(t *testing.T) { + raw := []byte(` +commands: + - name: date + exec: date +groups: + - hosts: [worker-1] + commands: + - command: date + interval: 5 +`) + + var cfg FabricConfig + err := yaml.UnmarshalStrict(raw, &cfg) + assert.NoError(t, err) + + cfg.normalize() + + assert.Len(t, cfg.Groups[0].Commands, 1) + assert.Equal(t, 5, cfg.Groups[0].Commands[0].Interval) +} diff --git a/internal/fabricConfig/runner.go b/internal/fabricConfig/runner.go index 69269b8..1aa6798 100644 --- a/internal/fabricConfig/runner.go +++ b/internal/fabricConfig/runner.go @@ -55,6 +55,8 @@ func UnmarshalConfig(path string) bool { return false } + cfg.normalize() + log.Debugf("Got config: %+v", cfg) ConfigStatus[path] = fmt.Sprintf("OK %v", hash_file_sha1(path + "/config.yml")) @@ -93,9 +95,18 @@ func hash_file_sha1(filePath string) (string) { } func SetupConfig(path string) { - if UnmarshalConfig(path) { - scheduleConfig() + if !UnmarshalConfig(path) { + log.Infof("Local fabric config unavailable, fetching from %s", fabricConfigURL()) + if err := FetchConfigFromHTTP(path); err != nil { + log.Warnf("HTTP fabric config fetch failed: %v", err) + return + } + if !UnmarshalConfig(path) { + return + } } + + scheduleConfig() } func scheduleConfig() { @@ -106,7 +117,7 @@ func scheduleConfig() { return } - hostname := util.GetHostname() + hostname := util.GetIdentifier() log.Infof("Scheduling config for %v", hostname) @@ -328,7 +339,7 @@ func execCommand(cmd *Command, arguments map[string]string) { res := &pb.ExecutionResult{ UnixTimestamp: time.Now().Unix(), - Hostname: util.GetHostname(), + Hostname: util.GetIdentifier(), Name: commandLabel, Runerr: runerrString, Stdout: stdout, diff --git a/internal/fabricConfig/runner_test.go b/internal/fabricConfig/runner_test.go index be3082d..3c8c135 100644 --- a/internal/fabricConfig/runner_test.go +++ b/internal/fabricConfig/runner_test.go @@ -2,27 +2,20 @@ package fabricConfig import ( "testing" + "github.com/stretchr/testify/assert" ) -func TestArgMapCount(t *testing.T) { - mapping := make(map[string]ArgumentMapping) - mapping["foo"] = ArgumentMapping { - Values: []string { - "bar1", - "bar2", - }, - } - - mapping["cake"] = ArgumentMapping { - Values: []string { - "one", - "two", - "three", - }, +func TestArgumentsToExecutionsPermutations(t *testing.T) { + arguments := map[string]any{ + "hostname": []interface{}{"one", "two"}, + "port": "80", } - ret := argumentListToMap("testing", mapping); + ret := argumentsToExecutions(arguments) - assert.Equal(t, 6, len(ret), "Correct permutation count") + assert.Len(t, ret, 2) + assert.Equal(t, "one", ret[0]["hostname"]) + assert.Equal(t, "two", ret[1]["hostname"]) + assert.Equal(t, "80", ret[0]["port"]) } diff --git a/internal/serviceConfig/config.go b/internal/serviceConfig/config.go index e0a6ed7..69570aa 100644 --- a/internal/serviceConfig/config.go +++ b/internal/serviceConfig/config.go @@ -1,6 +1,9 @@ package serviceConfig import ( + "os" + "strconv" + commonAmqp "github.com/upsilonproject/upsilon-gocommon/pkg/amqp" "github.com/spf13/viper" log "github.com/sirupsen/logrus" @@ -11,12 +14,11 @@ var ( ) type Config struct { - AmqpHost string - AmqpUser string - AmqpPass string - AmqpPort int - - LogLevel string + AmqpHost string `mapstructure:"amqphost"` + AmqpUser string `mapstructure:"amqpuser"` + AmqpPass string `mapstructure:"amqppass"` + AmqpPort int `mapstructure:"amqpport"` + LogLevel string `mapstructure:"loglevel"` } func DefaultConfig() *Config { @@ -38,33 +40,68 @@ func updateAmqpConfigFromRuntime() { commonAmqp.AmqpPass = RuntimeConfig.AmqpPass } +func applyEnvOverrides() { + if v := os.Getenv("UPSILON_CONFIG_SYSTEM_AMQPHOST"); v != "" { + RuntimeConfig.AmqpHost = v + } + if v := os.Getenv("UPSILON_AMQPHOST"); v != "" { + RuntimeConfig.AmqpHost = v + } + if v := os.Getenv("UPSILON_CONFIG_SYSTEM_AMQPUSER"); v != "" { + RuntimeConfig.AmqpUser = v + } + if v := os.Getenv("UPSILON_AMQPUSER"); v != "" { + RuntimeConfig.AmqpUser = v + } + if v := os.Getenv("UPSILON_CONFIG_SYSTEM_AMQPPASS"); v != "" { + RuntimeConfig.AmqpPass = v + } + if v := os.Getenv("UPSILON_AMQPPASS"); v != "" { + RuntimeConfig.AmqpPass = v + } + if v := os.Getenv("UPSILON_CONFIG_SYSTEM_AMQPPORT"); v != "" { + if port, err := strconv.Atoi(v); err == nil { + RuntimeConfig.AmqpPort = port + } + } + if v := os.Getenv("UPSILON_AMQPPORT"); v != "" { + if port, err := strconv.Atoi(v); err == nil { + RuntimeConfig.AmqpPort = port + } + } + if v := os.Getenv("UPSILON_LOGLEVEL"); v != "" { + RuntimeConfig.LogLevel = v + } +} + func Refresh() { - updateAmqpConfigFromRuntime(); // that way, if config loading fails, we have safe defaults + RuntimeConfig = DefaultConfig() + updateAmqpConfigFromRuntime() if err := viper.ReadInConfig(); err != nil { log.Warn(err) - return; - } - - if err := viper.UnmarshalExact(&RuntimeConfig); err != nil { + } else if err := viper.UnmarshalExact(&RuntimeConfig); err != nil { log.Warn(err) - return; + } else { + log.WithFields(log.Fields{ + "cfgfile": viper.ConfigFileUsed(), + }).Debugf("Loaded service config") } - updateAmqpConfigFromRuntime(); - - lvl, _ := log.ParseLevel(RuntimeConfig.LogLevel) + applyEnvOverrides() + updateAmqpConfigFromRuntime() - log.SetLevel(lvl) - - log.WithFields(log.Fields{ - "cfgfile": viper.ConfigFileUsed(), - }).Debugf("Loaded service config") + lvl, err := log.ParseLevel(RuntimeConfig.LogLevel) + if err != nil { + log.Warnf("Invalid log level %q: %v", RuntimeConfig.LogLevel, err) + } else { + log.SetLevel(lvl) + } } func init() { viper.SetConfigType("yaml") viper.AddConfigPath("/etc/upsilon-drone/") viper.SetConfigName("upsilon-drone") - viper.AutomaticEnv() // read in environment variables that match + viper.AutomaticEnv() } diff --git a/internal/serviceConfig/config_test.go b/internal/serviceConfig/config_test.go new file mode 100644 index 0000000..8d8d02c --- /dev/null +++ b/internal/serviceConfig/config_test.go @@ -0,0 +1,22 @@ +package serviceConfig + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + commonAmqp "github.com/upsilonproject/upsilon-gocommon/pkg/amqp" +) + +func TestApplyEnvOverridesAmqpHost(t *testing.T) { + RuntimeConfig = DefaultConfig() + + t.Setenv("UPSILON_CONFIG_SYSTEM_AMQPHOST", "amqp.example.com") + applyEnvOverrides() + updateAmqpConfigFromRuntime() + + assert.Equal(t, "amqp.example.com", RuntimeConfig.AmqpHost) + assert.Equal(t, "amqp.example.com", commonAmqp.AmqpHost) + + os.Unsetenv("UPSILON_CONFIG_SYSTEM_AMQPHOST") +} diff --git a/internal/updater/updater.go b/internal/updater/updater.go index 0bbb41c..4a5f018 100644 --- a/internal/updater/updater.go +++ b/internal/updater/updater.go @@ -117,31 +117,56 @@ func downloadUpdate() { log.Info("Update downloaded") } -func getUpdatedTimestamp() int { +func getRemoteVersion() string { url := "http://upsilon/upsilon-drone.timestamp" resp, err := http.Get(url) if err != nil { log.Errorf("%v", err) - return -1 + return "" } + defer resp.Body.Close() + if resp.StatusCode != 200 { log.Errorf("timestamp http status code %v", resp.StatusCode) - return -1 + return "" } - body, _ := io.ReadAll(resp.Body) - - updateTimestamp, err := strconv.Atoi(strings.Trim(string(body), "\n")) - + body, err := io.ReadAll(resp.Body) if err != nil { log.Errorf("%v", err) - return -1 + return "" + } + + return strings.TrimSpace(string(body)) +} + +func versionUpdateAvailable(local, remote string) bool { + local = strings.TrimSpace(local) + remote = strings.TrimSpace(remote) + + if remote == "" { + return false + } + + if local == remote { + return false + } + + localInt, localErr := strconv.Atoi(local) + remoteInt, remoteErr := strconv.Atoi(remote) + + if localErr == nil && remoteErr == nil { + return remoteInt > localInt } - return updateTimestamp + return local != remote +} + +func isNewerVersionAvailable() bool { + return versionUpdateAvailable(buildconstants.Timestamp, getRemoteVersion()) } func copyFile(in, out string) (int64, error) { @@ -177,15 +202,15 @@ func Update() { log.Fatalf("Exiting due to update") } - currentTimestamp, _ := strconv.Atoi(buildconstants.Timestamp) - updatedTimestamp := getUpdatedTimestamp() + local := strings.TrimSpace(buildconstants.Timestamp) + remote := getRemoteVersion() log.WithFields(log.Fields{ - "current": currentTimestamp, - "updated": updatedTimestamp, + "current": local, + "updated": remote, }).Infof("Version comparison") - if updatedTimestamp > currentTimestamp { + if isNewerVersionAvailable() { log.Infof("Downloading update due to newer timestamp") downloadUpdate() log.Fatalf("Exiting due to update") diff --git a/internal/updater/updater_test.go b/internal/updater/updater_test.go new file mode 100644 index 0000000..4e73e98 --- /dev/null +++ b/internal/updater/updater_test.go @@ -0,0 +1,22 @@ +package updater + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestVersionUpdateAvailableIntegerTimestamps(t *testing.T) { + assert.True(t, versionUpdateAvailable("100", "200")) + assert.False(t, versionUpdateAvailable("200", "100")) + assert.False(t, versionUpdateAvailable("200", "200")) +} + +func TestVersionUpdateAvailableSemverStrings(t *testing.T) { + assert.True(t, versionUpdateAvailable("3.1.2", "3.1.3")) + assert.False(t, versionUpdateAvailable("3.1.2", "3.1.2")) +} + +func TestVersionUpdateAvailableEmptyRemote(t *testing.T) { + assert.False(t, versionUpdateAvailable("3.1.2", "")) +} diff --git a/internal/util/events.go b/internal/util/events.go index 65be5ca..a19d92e 100644 --- a/internal/util/events.go +++ b/internal/util/events.go @@ -11,7 +11,7 @@ func SendEvent(msg string) { log.Error(msg) // Log here, so that callers don't have to log also event := &pb.Event { - Hostname: GetHostname(), + Hostname: GetIdentifier(), Content: msg, } diff --git a/internal/util/hostname.go b/internal/util/hostname.go index 06c0fdb..98efa84 100644 --- a/internal/util/hostname.go +++ b/internal/util/hostname.go @@ -14,3 +14,12 @@ func GetHostname() string { return hostname } +// GetIdentifier returns the node identity used for AMQP routing and fabric +// config host matching. UPSILON_IDENTIFIER overrides the OS hostname. +func GetIdentifier() string { + if id := os.Getenv("UPSILON_IDENTIFIER"); id != "" { + return id + } + + return GetHostname() +} diff --git a/internal/util/hostname_test.go b/internal/util/hostname_test.go new file mode 100644 index 0000000..fca8888 --- /dev/null +++ b/internal/util/hostname_test.go @@ -0,0 +1,22 @@ +package util + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetIdentifierUsesEnvOverride(t *testing.T) { + t.Setenv("UPSILON_IDENTIFIER", "spot-worker-01") + + assert.Equal(t, "spot-worker-01", GetIdentifier()) +} + +func TestGetIdentifierFallsBackToHostname(t *testing.T) { + os.Unsetenv("UPSILON_IDENTIFIER") + + hostname, err := os.Hostname() + assert.NoError(t, err) + assert.Equal(t, hostname, GetIdentifier()) +}