diff --git a/src/acceptance/assets/app/go_app/Makefile b/src/acceptance/assets/app/go_app/Makefile index 429a7f16ce..a65cda45fd 100644 --- a/src/acceptance/assets/app/go_app/Makefile +++ b/src/acceptance/assets/app/go_app/Makefile @@ -72,6 +72,10 @@ build: ./build/app ./build/manifest.yml CGO_ENABLED='${CGO_ENABLED}' GOOS='linux' GOARCH='amd64' go build -o './build/app' cp './app_manifest.yml' './build/manifest.yml' +.PHONY: cf-build +cf-build: ./build/app ./build/manifest.yml + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o './build/app' + cp './app_manifest.yml' './build/manifest.yml' .PHONY: build_tests diff --git a/src/autoscaler/Makefile b/src/autoscaler/Makefile index a91bb8c691..73e11a0f11 100644 --- a/src/autoscaler/Makefile +++ b/src/autoscaler/Makefile @@ -149,12 +149,19 @@ clean: @rm --force --recursive "${openapi-generated-clients-and-servers-dir}" .PHONY: mta-deploy -mta-deploy: mta-build cf-build +mta-deploy: mta-build @echo "Deploying mta" @echo " CF_TRACE=true cf deploy MTA mta_archives/*.mtar -e config.mtaext" - CF_TRACE=true cf deploy mta_archives/com.github.cloudfoundry.app-autoscaler-release_0.0.1.mtar -e config.mtaext + CF_TRACE=true cf deploy mta_archives/com.github.cloudfoundry.app-autoscaler-release_0.0.1.mtar +mta-logs: + rm -rf mta-* + cf dmol --mta com.github.cloudfoundry.app-autoscaler-release --last 1 + vim mta-* .PHONY: mta-build -mta-build: +mta-build: mta-build-clean cf-build mbt build + +mta-build-clean: + rm -rf mta_archives diff --git a/src/autoscaler/go.mod b/src/autoscaler/go.mod index c78d527618..1a9d28fc04 100644 --- a/src/autoscaler/go.mod +++ b/src/autoscaler/go.mod @@ -12,6 +12,7 @@ require ( code.cloudfoundry.org/tlsconfig v0.0.0-20240613173017-075d5b187a0d dario.cat/mergo v1.0.0 github.com/cenkalti/backoff/v4 v4.3.0 + github.com/cloudfoundry-community/go-cfenv v1.18.0 github.com/go-chi/chi/v5 v5.0.14 github.com/go-faster/errors v0.7.1 github.com/go-faster/jx v1.1.0 @@ -81,6 +82,7 @@ require ( github.com/klauspost/compress v1.17.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/mapstructure v1.1.2 // indirect github.com/openzipkin/zipkin-go v0.4.2 // indirect github.com/pborman/uuid v1.2.1 // indirect github.com/peterbourgon/g2s v0.0.0-20170223122336-d4e7ad98afea // indirect diff --git a/src/autoscaler/go.sum b/src/autoscaler/go.sum index b7f3c10d44..998933ca0c 100644 --- a/src/autoscaler/go.sum +++ b/src/autoscaler/go.sum @@ -654,6 +654,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudfoundry-community/go-cfenv v1.18.0 h1:dOIRSHUSaj4r6Q9Cx+nzz2OytHt+QNKqtOuKTQsa+zw= +github.com/cloudfoundry-community/go-cfenv v1.18.0/go.mod h1:qGMSI6lygPzqugFs9M1NFjJBtEPgl0MgT6drMFZGUoU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -874,6 +876,8 @@ github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/joefitzgerald/rainbow-reporter v0.1.0 h1:AuMG652zjdzI0YCCnXAqATtRBpGXMcAnrajcaTrSeuo= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= @@ -915,16 +919,17 @@ github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1 h1:NicmruxkeqHjDv03SfSxqmaLuisdd github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1/go.mod h1:eyp4DdUJAKkr9tvxR3jWhw2mDK7CWABMG5r9uyaKC7I= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/ogen-go/ogen v1.1.1 h1:ccHc/vgS+WbOLLgM4JYW7EDiBv7DPfbvKCnbo5fctSY= -github.com/ogen-go/ogen v1.1.1/go.mod h1:ZmPa2LwJrwXKPo3s3p/XFMg5znV60IX5950UftdNmb4= github.com/ogen-go/ogen v1.2.2 h1:fFqZzRacbdnOQeqep4efVeqj7/4hI1mlimrY8rn970A= github.com/ogen-go/ogen v1.2.2/go.mod h1:S8X2dBfTKlpy+pcGLXP+aLLzvUAXAvtONtuovrN3+gw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -943,6 +948,7 @@ github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxe github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -1003,6 +1009,7 @@ github.com/rubyist/circuitbreaker v2.2.1+incompatible h1:KUKd/pV8Geg77+8LNDwdow6 github.com/rubyist/circuitbreaker v2.2.1+incompatible/go.mod h1:Ycs3JgJADPuzJDwffe12k6BZT8hxVi6lFK+gWYJLN4A= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= @@ -1066,20 +1073,12 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.51.0 h1:rXpHmgy1pMXlfv3W1T5ctoDA3QeTFjNq/YwCmwrfr8Q= go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.51.0/go.mod h1:9uIRD3NZrM7QMQEGeKhr7V4xSDTMku3MPOVs8iZ3VVk= -go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= -go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= -go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= -go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= -go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= -go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= -go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= -go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= @@ -1762,6 +1761,7 @@ 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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 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.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/src/autoscaler/helpers/cf.go b/src/autoscaler/helpers/cf.go new file mode 100644 index 0000000000..6d37d2cad7 --- /dev/null +++ b/src/autoscaler/helpers/cf.go @@ -0,0 +1,25 @@ +package helpers + +import ( + "encoding/json" + "fmt" +) + +func GetDbURLFromVcap(vcapServices string, dbType string) (string, error) { + var vcap map[string][]struct { + Credentials map[string]interface{} `json:"credentials"` + } + + err := json.Unmarshal([]byte(vcapServices), &vcap) + if err != nil { + return "", err + } + + creds := vcap[dbType][0].Credentials + if creds == nil { + return "", fmt.Errorf("credentials not found for %s", dbType) + } + + dbURL := creds["uri"].(string) + return dbURL, nil +} diff --git a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/main.go b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/main.go index 511fbe4ede..b72001432c 100644 --- a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/main.go +++ b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/main.go @@ -27,25 +27,17 @@ import ( func main() { var path string + var err error + var conf *config.Config + flag.StringVar(&path, "c", "", "config file") flag.Parse() - if path == "" { - _, _ = fmt.Fprintln(os.Stderr, "missing config file") - os.Exit(1) - } - configFile, err := os.Open(path) - if err != nil { - _, _ = fmt.Fprintf(os.Stdout, "failed to open config file '%s' : %s\n", path, err.Error()) - os.Exit(1) - } - var conf *config.Config - conf, err = config.LoadConfig(configFile) + conf, err = config.LoadConfig(path) if err != nil { - _, _ = fmt.Fprintf(os.Stdout, "failed to read config file '%s' : %s\n", path, err.Error()) + _, _ = fmt.Fprintf(os.Stdout, "failed to load config : %s\n", err.Error()) os.Exit(1) } - _ = configFile.Close() err = conf.Validate() if err != nil { diff --git a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go index a72a650957..a8a6ec29e5 100644 --- a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go +++ b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" "os" + "strconv" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/db" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/models" @@ -18,6 +19,10 @@ import ( . "github.com/onsi/gomega" ) +func unsetEnvVars() { + os.Unsetenv("PORT") +} + var _ = Describe("Metricsforwarder", func() { var ( runner *MetricsForwarderRunner @@ -29,16 +34,49 @@ var _ = Describe("Metricsforwarder", func() { Describe("MetricsForwarder configuration check", func() { - Context("with a missing config file", func() { + When("config file is missing", func() { BeforeEach(func() { runner.startCheck = "" - runner.configPath = "bogus" + runner.configPath = "" runner.Start() }) + When("environment variables not provided", func() { + BeforeEach(func() { + unsetEnvVars() + }) - It("fails with an error", func() { - Eventually(runner.Session).Should(Exit(1)) - Expect(runner.Session.Buffer()).To(Say("failed to open config file")) + It("fails with an error", func() { + Eventually(runner.Session).Should(Exit(1)) + Expect(runner.Session.Buffer()).To(Say("failed to validate configuration")) + }) + }) + + When("environment variables not provided", func() { + BeforeEach(func() { + os.Setenv("PORT", strconv.Itoa(cfg.Server.Port)) + }) + + It("fails with an error", func() { + Eventually(runner.Session).Should(Exit(1)) + Expect(runner.Session.Buffer()).ToNot(Say("failed to validate configuration")) + }) + }) + }) + + When("config file is not provided", func() { + BeforeEach(func() { + runner.startCheck = "" + runner.configPath = "bogus" + runner.Start() + }) + When("environment variables not provided", func() { + BeforeEach(func() { + unsetEnvVars() + }) + It("fails with an error", func() { + Eventually(runner.Session).Should(Exit(1)) + Expect(runner.Session.Buffer()).To(Say("failed to open config file")) + }) }) }) diff --git a/src/autoscaler/metricsforwarder/config/config.go b/src/autoscaler/metricsforwarder/config/config.go index 2aa36faf8a..9aa5fb3c82 100644 --- a/src/autoscaler/metricsforwarder/config/config.go +++ b/src/autoscaler/metricsforwarder/config/config.go @@ -1,10 +1,13 @@ package config import ( + "errors" "fmt" - "io" + "os" "time" + "github.com/cloudfoundry-community/go-cfenv" + "code.cloudfoundry.org/app-autoscaler/src/autoscaler/db" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/helpers" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/models" @@ -14,6 +17,16 @@ import ( "gopkg.in/yaml.v3" ) +// There are 3 type of errors that this package can return: +// - ReadYamlError +// - ReadFileError +// - ReadEnvironmentError + +var ReadYamlError = errors.New("failed to read config file") +var ReadFileError = errors.New("failed to open config file") +var ReadEnvironmentError = errors.New("failed to read environment variables") +var ReadVCAPEnvironmentError = errors.New("failed to read VCAP environment variables") + const ( DefaultMetronAddress = "127.0.0.1:3458" DefaultCacheTTL = 15 * time.Minute @@ -68,8 +81,9 @@ type SyslogConfig struct { TLS models.TLSCerts `yaml:"tls"` } -func LoadConfig(reader io.Reader) (*Config, error) { +func LoadConfig(filepath string) (*Config, error) { var conf Config + var err error conf = Config{ Server: defaultServerConfig, @@ -87,16 +101,35 @@ func LoadConfig(reader io.Reader) (*Config, error) { }, } - dec := yaml.NewDecoder(reader) - dec.KnownFields(true) - err := dec.Decode(&conf) - if err != nil { - return nil, err + if filepath == "" { + fmt.Fprintln(os.Stdout, "missing config file, using environment variables") + } else { + r, err := os.Open(filepath) + + if err != nil { + _, _ = fmt.Fprintf(os.Stdout, "failed to open config file '%s' : %s\n", filepath, err.Error()) + return nil, err + } + + dec := yaml.NewDecoder(r) + dec.KnownFields(true) + err = dec.Decode(&conf) + + if err != nil { + return nil, fmt.Errorf("%w: %w", ReadYamlError, err) + } + + defer r.Close() } err = envconfig.Process("", &conf) if err != nil { - return nil, err + return nil, fmt.Errorf("%w: %w", ReadEnvironmentError, err) + } + + err = loadVCAPEnvs(&conf) + if err != nil { + return nil, fmt.Errorf("%w: %w", ReadVCAPEnvironmentError, err) } return &conf, nil @@ -148,3 +181,64 @@ func (c *Config) Validate() error { return nil } + +func loadVCAPEnvs(c *Config) error { + if os.Getenv("VCAP_APPLICATION") == "" || os.Getenv("VCAP_SERVICES") == "" { + return nil + } + + // panic here + appEnv, err := cfenv.Current() + if err != nil { + return err + } + + dbServices, err := appEnv.Services.WithTag("relational") + if err != nil { + return fmt.Errorf("failed to get db service with relational tag") + } + + // if len(dbServices) != 1 { + // return nil, + // } + + dbService := dbServices[0] + + dbURI, ok := dbService.CredentialString("uri") + if !ok { + return fmt.Errorf("failed to get uri from db service") + } + + c.Db[db.PolicyDb] = db.DatabaseConfig{ + URL: dbURI, + } + + //dbURL, err := url.Parse(dbURI) + //if err != nil { + // return nil, err + //} + + //parameters, err := url.ParseQuery(dbURL.RawQuery) + //if err != nil { + // return nil, err + //} + + //err = materializeConnectionParameter(dbService, parameters, "client_cert", "sslcert") + //if err != nil { + // return nil, err + //} + + //err = materializeConnectionParameter(dbService, parameters, "client_key", "sslkey") + //if err != nil { + // return nil, err + //} + + //err = materializeConnectionParameter(dbService, parameters, "server_ca", "sslrootcert") + //if err != nil { + // return nil, err + //} + + //dbURL.RawQuery = parameters.Encode() + + return nil +} diff --git a/src/autoscaler/metricsforwarder/config/config_test.go b/src/autoscaler/metricsforwarder/config/config_test.go index 1cf326e0fa..6d7ded3463 100644 --- a/src/autoscaler/metricsforwarder/config/config_test.go +++ b/src/autoscaler/metricsforwarder/config/config_test.go @@ -1,31 +1,45 @@ package config_test import ( - "bytes" "os" "time" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/db" + "code.cloudfoundry.org/app-autoscaler/src/autoscaler/metricsforwarder/config" . "code.cloudfoundry.org/app-autoscaler/src/autoscaler/metricsforwarder/config" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/models" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "gopkg.in/yaml.v3" ) +func bytesToFile(b []byte) string { + file, err := os.CreateTemp("", "") + Expect(err).NotTo(HaveOccurred()) + _, err = file.Write(b) + Expect(err).NotTo(HaveOccurred()) + return file.Name() +} + var _ = Describe("Config", func() { var ( conf *Config err error configBytes []byte + configFile string ) Describe("LoadConfig", func() { JustBeforeEach(func() { - conf, err = LoadConfig(bytes.NewReader(configBytes)) + configFile = bytesToFile(configBytes) + conf, err = LoadConfig(configFile) + }) + + AfterEach(func() { + //clean up config file + Expect(os.Remove(configFile)).To(Succeed()) }) Context("with invalid yaml", func() { @@ -105,13 +119,51 @@ cred_helper_impl: default }) It("return invalid port error", func() { - Expect(err).To(MatchError(MatchRegexp("strconv.ParseInt: parsing \"NAN\""))) + Expect(err).To(MatchError(config.ReadEnvironmentError)) + Expect(err).To(MatchError(MatchRegexp("converting 'NAN' to type int"))) + }) + + AfterEach(func() { + os.Unsetenv("PORT") }) }) }) - AfterEach(func() { - os.Unsetenv("PORT") + When("VCAP_SERVICES is set", func() { + BeforeEach(func() { + // vcap services has a postgres service provisioned by + // a service broker binding + vcapServices := `{ + "autoscaler": [ + { + "credentials": { + "uri":"postgres://foo:bar@postgres.example.com:5432/policy_db" + }, + "label": "postgres", + "name": "policy_db", + "syslog_drain_url": "", + "tags": ["postgres","postgresql","relational"] + } + ] + }` + + os.Setenv("VCAP_APPLICATION", "{}") + os.Setenv("VCAP_SERVICES", vcapServices) + }) + + It("loads the db config from VCAP_SERVICES", func() { + expectedDbConfig := db.DatabaseConfig{ + URL: "postgres://foo:bar@postgres.example.com:5432/policy_db", + } + + Expect(err).NotTo(HaveOccurred()) + Expect(conf.Db[db.PolicyDb]).To(Equal(expectedDbConfig)) + }) + + AfterEach(func() { + os.Unsetenv("VCAP_SERVICES") + os.Unsetenv("VCAP_APPLICATION") + }) }) }) @@ -143,7 +195,6 @@ health: Expect(conf.CacheCleanupInterval).To(Equal(DefaultCacheCleanupInterval)) Expect(conf.Health.Port).To(Equal(8081)) }) - }) When("it gives a non integer port", func() { @@ -155,7 +206,7 @@ server: }) It("should error", func() { - Expect(err).To(BeAssignableToTypeOf(&yaml.TypeError{})) + Expect(err).To(MatchError(config.ReadYamlError)) Expect(err).To(MatchError(MatchRegexp("cannot unmarshal.*into int"))) }) }) @@ -169,7 +220,7 @@ health: }) It("should error", func() { - Expect(err).To(BeAssignableToTypeOf(&yaml.TypeError{})) + Expect(err).To(MatchError(config.ReadYamlError)) Expect(err).To(MatchError(MatchRegexp("cannot unmarshal.*into int"))) }) }) @@ -195,7 +246,7 @@ health: }) It("should error", func() { - Expect(err).To(BeAssignableToTypeOf(&yaml.TypeError{})) + Expect(err).To(MatchError(config.ReadYamlError)) Expect(err).To(MatchError(MatchRegexp("cannot unmarshal.*into int"))) }) }) @@ -221,7 +272,7 @@ health: }) It("should error", func() { - Expect(err).To(BeAssignableToTypeOf(&yaml.TypeError{})) + Expect(err).To(MatchError(config.ReadYamlError)) Expect(err).To(MatchError(MatchRegexp("cannot unmarshal.*into int"))) }) }) @@ -247,7 +298,7 @@ health: }) It("should error", func() { - Expect(err).To(BeAssignableToTypeOf(&yaml.TypeError{})) + Expect(err).To(MatchError(config.ReadYamlError)) Expect(err).To(MatchError(MatchRegexp("cannot unmarshal .* into time.Duration"))) }) }) @@ -276,7 +327,7 @@ rate_limit: }) It("should error", func() { - Expect(err).To(BeAssignableToTypeOf(&yaml.TypeError{})) + Expect(err).To(MatchError(config.ReadYamlError)) Expect(err).To(MatchError(MatchRegexp("cannot unmarshal .* into int"))) }) }) @@ -305,7 +356,7 @@ rate_limit: }) It("should error", func() { - Expect(err).To(BeAssignableToTypeOf(&yaml.TypeError{})) + Expect(err).To(MatchError(config.ReadYamlError)) Expect(err).To(MatchError(MatchRegexp("cannot unmarshal .* into time.Duration"))) }) }) diff --git a/src/autoscaler/mta.yaml b/src/autoscaler/mta.yaml index 926f7d7124..c9c628b6b6 100644 --- a/src/autoscaler/mta.yaml +++ b/src/autoscaler/mta.yaml @@ -27,7 +27,7 @@ modules: health-check-type: http health-check-http-endpoint: "/health" stack: cflinuxfs4 - command: ls -1 + command: ./app # ID: sap.tools.github.autoscaler.application-autoscaler-dashboard # _schema-version: 3.3.0