From 282aa4c9a1bc470e8f57f7dea8786a25d4d63ede Mon Sep 17 00:00:00 2001 From: Silvestre Zabala Date: Thu, 16 May 2024 15:47:56 +0200 Subject: [PATCH 1/3] add `uaac` to devbox # Issue `uaac` was missing in the devbox. The version installed in the `Makefile` could get out of date with the Ruby version and break. # Fix Add `uaac` in `local-flake`. # Note Having the gemset nix in the flake directory seem ugly, but moving it to a subdirectory did not work on first try. --- devbox.json | 6 +- devbox.lock | 144 ++++++++++++++++++++++----------- local-flake/Gemfile | 3 + local-flake/Gemfile.lock | 48 +++++++++++ local-flake/flake.nix | 12 +++ local-flake/gemset.nix | 168 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 331 insertions(+), 50 deletions(-) create mode 100644 local-flake/Gemfile create mode 100644 local-flake/Gemfile.lock create mode 100644 local-flake/gemset.nix diff --git a/devbox.json b/devbox.json index 2415c5c1ea..2498449ee0 100644 --- a/devbox.json +++ b/devbox.json @@ -3,6 +3,7 @@ "path:local-flake#bosh-bootloader", "path:local-flake#app-autoscaler-cli-plugin", "path:local-flake#log-cache-cli-plugin", + "path:local-flake#uaac", "credhub-cli@latest", "delve@latest", "gh@latest", @@ -27,13 +28,14 @@ "python@latest", "cloudfoundry-cli@8.7.10", "shellcheck@0.10.0", - "hey@latest", "act@0.2.62", "go@1.21.5", "ruby@3.3.1", "ginkgo@2.17.3", "google-cloud-sdk@latest", - "temurin-bin-17@latest" + "temurin-bin-17@latest", + "bundix@latest", + "oha@latest" ], "shell": { "init_hook": [ diff --git a/devbox.lock b/devbox.lock index e5b672eba1..d09b14340c 100644 --- a/devbox.lock +++ b/devbox.lock @@ -117,6 +117,54 @@ } } }, + "bundix@latest": { + "last_modified": "2024-05-13T18:06:16Z", + "resolved": "github:NixOS/nixpkgs/1daef0114a6074be56586f2cf81898ed142e1e44#bundix", + "source": "devbox-search", + "version": "2.5.2", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/z6i8bpx563s6vk4n41n3bs5zwxc547yh-bundix-2.5.2", + "default": true + } + ], + "store_path": "/nix/store/z6i8bpx563s6vk4n41n3bs5zwxc547yh-bundix-2.5.2" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/5nx02x3njcypwcq71kqfri1i6p8dldag-bundix-2.5.2", + "default": true + } + ], + "store_path": "/nix/store/5nx02x3njcypwcq71kqfri1i6p8dldag-bundix-2.5.2" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/nprjv4nqk72g8sc0yngjw28f31qbs1m3-bundix-2.5.2", + "default": true + } + ], + "store_path": "/nix/store/nprjv4nqk72g8sc0yngjw28f31qbs1m3-bundix-2.5.2" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ygc5d4xay2hm8d2lrlxy01lgzfxhlzag-bundix-2.5.2", + "default": true + } + ], + "store_path": "/nix/store/ygc5d4xay2hm8d2lrlxy01lgzfxhlzag-bundix-2.5.2" + } + } + }, "cloudfoundry-cli@8.7.10": { "last_modified": "2024-04-19T17:36:04-04:00", "resolved": "github:NixOS/nixpkgs/92d295f588631b0db2da509f381b4fb1e74173c5#cloudfoundry-cli", @@ -545,54 +593,6 @@ } } }, - "hey@latest": { - "last_modified": "2024-04-19T21:36:04Z", - "resolved": "github:NixOS/nixpkgs/92d295f588631b0db2da509f381b4fb1e74173c5#hey", - "source": "devbox-search", - "version": "0.1.4", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/cjpydm1gw7ib0vw5kd5fmvr36w2zzi1i-hey-0.1.4", - "default": true - } - ], - "store_path": "/nix/store/cjpydm1gw7ib0vw5kd5fmvr36w2zzi1i-hey-0.1.4" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7q9x6j3aylz8lb0w9hxqcjw6bidhfbvi-hey-0.1.4", - "default": true - } - ], - "store_path": "/nix/store/7q9x6j3aylz8lb0w9hxqcjw6bidhfbvi-hey-0.1.4" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/c6l9h5wqcmk5sq2ihrg1by7s36w4pi61-hey-0.1.4", - "default": true - } - ], - "store_path": "/nix/store/c6l9h5wqcmk5sq2ihrg1by7s36w4pi61-hey-0.1.4" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/36jj648k5cp8qi0sd4i0ypys6mmdn42m-hey-0.1.4", - "default": true - } - ], - "store_path": "/nix/store/36jj648k5cp8qi0sd4i0ypys6mmdn42m-hey-0.1.4" - } - } - }, "jq@latest": { "last_modified": "2024-04-21T11:44:28-04:00", "resolved": "github:NixOS/nixpkgs/69ee1d82f1fa4c70a3dc9a64111e7eef3b8e4527#jq", @@ -786,6 +786,54 @@ } } }, + "oha@latest": { + "last_modified": "2024-05-12T16:19:40Z", + "resolved": "github:NixOS/nixpkgs/3281bec7174f679eabf584591e75979a258d8c40#oha", + "source": "devbox-search", + "version": "1.4.4", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ffmzinm475nq5wk4805sl180qmyy5yps-oha-1.4.4", + "default": true + } + ], + "store_path": "/nix/store/ffmzinm475nq5wk4805sl180qmyy5yps-oha-1.4.4" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/6k6hsmq2fiij7hlxv4bn9f8sy9qjjyg2-oha-1.4.4", + "default": true + } + ], + "store_path": "/nix/store/6k6hsmq2fiij7hlxv4bn9f8sy9qjjyg2-oha-1.4.4" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/8hj0f5yywbxchxl3qha1zwv0aqxpxwri-oha-1.4.4", + "default": true + } + ], + "store_path": "/nix/store/8hj0f5yywbxchxl3qha1zwv0aqxpxwri-oha-1.4.4" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/pqj46rbqw29j4h8hadhm2d2k0xibsqnc-oha-1.4.4", + "default": true + } + ], + "store_path": "/nix/store/pqj46rbqw29j4h8hadhm2d2k0xibsqnc-oha-1.4.4" + } + } + }, "pre-commit@latest": { "last_modified": "2024-03-17T01:03:25Z", "resolved": "github:NixOS/nixpkgs/299d4668ba61600311553920d9fd9c102145b2cb#pre-commit", diff --git a/local-flake/Gemfile b/local-flake/Gemfile new file mode 100644 index 0000000000..fa2dff96c9 --- /dev/null +++ b/local-flake/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "cf-uaac" diff --git a/local-flake/Gemfile.lock b/local-flake/Gemfile.lock new file mode 100644 index 0000000000..aa2b3bf95f --- /dev/null +++ b/local-flake/Gemfile.lock @@ -0,0 +1,48 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.8.6) + public_suffix (>= 2.0.2, < 6.0) + cf-uaa-lib (4.0.4) + addressable (~> 2.8, >= 2.8.0) + httpclient (~> 2.8, >= 2.8.2.4) + multi_json (>= 1.12.1, < 1.16) + cf-uaac (4.23.0) + cf-uaa-lib (~> 4.0.4) + em-http-request (~> 1.1, >= 1.1.2) + eventmachine (~> 1.2) + highline (>= 2, < 4) + json_pure (~> 2.6) + launchy (>= 2.5, < 4.0) + rack (~> 3.0) + childprocess (5.0.0) + cookiejar (0.3.4) + em-http-request (1.1.7) + addressable (>= 2.3.4) + cookiejar (!= 0.3.1) + em-socksify (>= 0.3) + eventmachine (>= 1.0.3) + http_parser.rb (>= 0.6.0) + em-socksify (0.3.2) + eventmachine (>= 1.0.0.beta.4) + eventmachine (1.2.7) + highline (3.0.1) + http_parser.rb (0.8.0) + httpclient (2.8.3) + json_pure (2.7.2) + launchy (3.0.1) + addressable (~> 2.8) + childprocess (~> 5.0) + multi_json (1.15.0) + public_suffix (5.0.5) + rack (3.0.11) + +PLATFORMS + ruby + x86_64-linux + +DEPENDENCIES + cf-uaac + +BUNDLED WITH + 2.5.9 diff --git a/local-flake/flake.nix b/local-flake/flake.nix index e63f6d75ff..ff108fd774 100644 --- a/local-flake/flake.nix +++ b/local-flake/flake.nix @@ -57,6 +57,18 @@ vendorHash = null; ldflags = ["-s" "-w" "-X main.version=${version}"]; }; + + uaac = nixpkgsFor.${system}.bundlerApp rec { + pname = "cf-uaac"; + gemdir = ./.; + exes = ["uaac"]; + + meta = { + description = "CloudFoundry UAA Command Line Client"; + homepage = "https://github.com/cloudfoundry/cf-uaac"; + mainProgram = "uaac"; + }; + }; }); }; } diff --git a/local-flake/gemset.nix b/local-flake/gemset.nix new file mode 100644 index 0000000000..c156ebb31a --- /dev/null +++ b/local-flake/gemset.nix @@ -0,0 +1,168 @@ +{ + addressable = { + dependencies = ["public_suffix"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0irbdwkkjwzajq1ip6ba46q49sxnrl2cw7ddkdhsfhb6aprnm3vr"; + type = "gem"; + }; + version = "2.8.6"; + }; + cf-uaa-lib = { + dependencies = ["addressable" "httpclient" "multi_json"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0mqdgbpcarblrcng66729fp7qi4qvzs0dlaq3dx1jf1pg6mjxh90"; + type = "gem"; + }; + version = "4.0.4"; + }; + cf-uaac = { + dependencies = ["cf-uaa-lib" "em-http-request" "eventmachine" "highline" "json_pure" "launchy" "rack"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "02gf1sqrnvbj7sv11w74cka7bh9yjdvp9wnz1d4d8jkd465a85sf"; + type = "gem"; + }; + version = "4.23.0"; + }; + childprocess = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0dfq21rszw5754llkh4jc58j2h8jswqpcxm3cip1as3c3nmvfih7"; + type = "gem"; + }; + version = "5.0.0"; + }; + cookiejar = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1px0zlnlkwwp9prdkm2lamgy412y009646n2cgsa1xxsqk7nmc8i"; + type = "gem"; + }; + version = "0.3.4"; + }; + em-http-request = { + dependencies = ["addressable" "cookiejar" "em-socksify" "eventmachine" "http_parser.rb"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1azx5rgm1zvx7391sfwcxzyccs46x495vb34ql2ch83f58mwgyqn"; + type = "gem"; + }; + version = "1.1.7"; + }; + em-socksify = { + dependencies = ["eventmachine"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0rk43ywaanfrd8180d98287xv2pxyl7llj291cwy87g1s735d5nk"; + type = "gem"; + }; + version = "0.3.2"; + }; + eventmachine = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0wh9aqb0skz80fhfn66lbpr4f86ya2z5rx6gm5xlfhd05bj1ch4r"; + type = "gem"; + }; + version = "1.2.7"; + }; + highline = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "02ghhvigqbq4252gsi4w8a9klkdkybmbz29ghfp1y6sqzlcb466a"; + type = "gem"; + }; + version = "3.0.1"; + }; + "http_parser.rb" = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1gj4fmls0mf52dlr928gaq0c0cb0m3aqa9kaa6l0ikl2zbqk42as"; + type = "gem"; + }; + version = "0.8.0"; + }; + httpclient = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "19mxmvghp7ki3klsxwrlwr431li7hm1lczhhj8z4qihl2acy8l99"; + type = "gem"; + }; + version = "2.8.3"; + }; + json_pure = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "13b4dminf6znfwvj8d61w6dar9zrxnndrmiig19adbliv0haxmlr"; + type = "gem"; + }; + version = "2.7.2"; + }; + launchy = { + dependencies = ["addressable" "childprocess"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0b3zi9ydbibyyrrkr6l8mcs6l7yam18a4wg22ivgaz0rl2yn1ymp"; + type = "gem"; + }; + version = "3.0.1"; + }; + multi_json = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0pb1g1y3dsiahavspyzkdy39j4q377009f6ix0bh1ag4nqw43l0z"; + type = "gem"; + }; + version = "1.15.0"; + }; + public_suffix = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "14y4vzjwf5gp0mqgs880kis0k7n2biq8i6ci6q2n315kichl1hvj"; + type = "gem"; + }; + version = "5.0.5"; + }; + rack = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "137r9zqwh0dan6s0fw91wk6iip9alh44bqgbhn80sxk0h5kp7150"; + type = "gem"; + }; + version = "3.0.11"; + }; +} From d5985f810da796f99003ac1059bb15d02854445f Mon Sep 17 00:00:00 2001 From: Silvestre Zabala Date: Thu, 4 Apr 2024 11:20:33 +0200 Subject: [PATCH 2/3] feat(scalingengine): Support label to disable autoscaling # Background During DevOps tasks such as deployments or periods where manual scaling is required (e.g., in an outage situation) a simple and quick way to disable autoscaling might be helpful that does not involve editing or deleting the autoscaling policy. # Details This PR introduces a label `app-autoscaler.cloudfoundry.org/disable-autoscaling`. If it is set on an app the app-autoscaler will not scale it, even if a scaling policy is active. --- src/acceptance/app/cf_metadata_test.go | 49 +++++++++++ src/acceptance/app/dynamic_policy_test.go | 7 -- src/acceptance/helpers/debug.go | 1 + src/acceptance/helpers/helpers.go | 6 ++ src/autoscaler/cf/app.go | 1 + src/autoscaler/cf/app_test.go | 11 +++ src/autoscaler/cf/client_test.go | 84 +++++++++---------- src/autoscaler/cf/config_test.go | 10 +-- src/autoscaler/cf/metadata.go | 8 ++ src/autoscaler/cf/oauth_test.go | 20 ++--- src/autoscaler/cf/testdata/app.json | 1 + .../healthendpoint/health_readiness_test.go | 2 +- src/autoscaler/scalingengine/scalingengine.go | 18 ++++ .../scalingengine/scalingengine_test.go | 27 ++++++ 14 files changed, 180 insertions(+), 65 deletions(-) create mode 100644 src/acceptance/app/cf_metadata_test.go create mode 100644 src/autoscaler/cf/metadata.go diff --git a/src/acceptance/app/cf_metadata_test.go b/src/acceptance/app/cf_metadata_test.go new file mode 100644 index 0000000000..c098b9d1dc --- /dev/null +++ b/src/acceptance/app/cf_metadata_test.go @@ -0,0 +1,49 @@ +package app_test + +import ( + "acceptance" + . "acceptance/helpers" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("AutoScaler CF metadata support", func() { + var ( + policy string + err error + ) + BeforeEach(func() { + policy = GenerateDynamicScaleOutAndInPolicy(1, 2, "test_metric", 500, 500) + appName = CreateTestApp(cfg, "labeled-go_app", 1) + appGUID, err = GetAppGuid(cfg, appName) + Expect(err).NotTo(HaveOccurred()) + instanceName = CreatePolicy(cfg, appName, appGUID, policy) + StartApp(appName, cfg.CfPushTimeoutDuration()) + }) + AfterEach(AppAfterEach) + + Context("when scaling by custom metrics", func() { + It("should scale out normally", Label(acceptance.LabelSmokeTests), func() { + By("Scale out to 2 instances") + scaleOut := sendMetricToAutoscaler(cfg, appGUID, appName, 550, true) + Eventually(scaleOut). + WithTimeout(5 * time.Minute). + WithPolling(15 * time.Second). + Should(Equal(2)) + }) + + Context("when the label app-autoscaler.cloudfoundry.org/disable-autoscaling is set", func() { + It("should not scale out", Label(acceptance.LabelSmokeTests), func() { + By("Set the label app-autoscaler.cloudfoundry.org/disable-autoscaling to true") + SetLabel(cfg, appGUID, "app-autoscaler.cloudfoundry.org/disable-autoscaling", "true") + scaleOut := sendMetricToAutoscaler(cfg, appGUID, appName, 550, true) + Consistently(scaleOut). + WithTimeout(5 * time.Minute). + WithPolling(15 * time.Second). + Should(Equal(1)) + }) + }) + }) +}) diff --git a/src/acceptance/app/dynamic_policy_test.go b/src/acceptance/app/dynamic_policy_test.go index dd23695b4a..4515026ee4 100644 --- a/src/acceptance/app/dynamic_policy_test.go +++ b/src/acceptance/app/dynamic_policy_test.go @@ -377,10 +377,3 @@ var _ = Describe("AutoScaler dynamic policy", func() { }) }) }) - -func min(a int, b int) int { - if a <= b { - return a - } - return b -} diff --git a/src/acceptance/helpers/debug.go b/src/acceptance/helpers/debug.go index 6b28df262a..6d93d7dc75 100644 --- a/src/acceptance/helpers/debug.go +++ b/src/acceptance/helpers/debug.go @@ -20,6 +20,7 @@ func DebugInfo(cfg *config.Config, setup *workflowhelpers.ReproducibleTestSuiteS } var commands []*Session commands = append(commands, command("cf", "app", anApp)) + commands = append(commands, command("cf", "events", anApp)) commands = append(commands, command("cf", "logs", "--recent", anApp)) commands = append(commands, command("cf", "autoscaling-api", cfg.ASApiEndpoint)) commands = append(commands, command("cf", "autoscaling-policy", anApp)) diff --git a/src/acceptance/helpers/helpers.go b/src/acceptance/helpers/helpers.go index ee0ec5be7e..55a66832ec 100644 --- a/src/acceptance/helpers/helpers.go +++ b/src/acceptance/helpers/helpers.go @@ -637,3 +637,9 @@ func FailOnCommandFailuref(command *Session, format string, args ...any) *Sessio } return command } + +func SetLabel(cfg *config.Config, appGUID string, labelKey string, labelValue string) { + GinkgoHelper() + cmd := cf.Cf("curl", "--fail", fmt.Sprintf("/v3/apps/%s", appGUID), "-X", "PATCH", "-d", fmt.Sprintf(`{"metadata": {"labels": {"%s": "%s"}}}`, labelKey, labelValue)).Wait(cfg.DefaultTimeoutDuration()) + Expect(cmd).To(Exit(0)) +} diff --git a/src/autoscaler/cf/app.go b/src/autoscaler/cf/app.go index 44cc47ff46..9fd7a2ac24 100644 --- a/src/autoscaler/cf/app.go +++ b/src/autoscaler/cf/app.go @@ -20,6 +20,7 @@ type ( CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` Relationships Relationships `json:"relationships"` + Metadata `json:"metadata"` } AppAndProcesses struct { diff --git a/src/autoscaler/cf/app_test.go b/src/autoscaler/cf/app_test.go index cf779617da..3a0ba8b121 100644 --- a/src/autoscaler/cf/app_test.go +++ b/src/autoscaler/cf/app_test.go @@ -22,6 +22,7 @@ var _ = Describe("Cf client App", func() { appTestJson := LoadFile("testdata/app.json") + autoscalingDisabled := "true" Describe("GetApp", func() { When("get app succeeds", func() { BeforeEach(func() { @@ -50,6 +51,11 @@ var _ = Describe("Cf client App", func() { }, }, }, + Metadata: cf.Metadata{ + Labels: cf.Labels{ + DisableAutoscaling: &autoscalingDisabled, + }, + }, })) }) }) @@ -110,6 +116,11 @@ var _ = Describe("Cf client App", func() { }, }, }, + Metadata: cf.Metadata{ + Labels: cf.Labels{ + DisableAutoscaling: &autoscalingDisabled, + }, + }, }, Processes: cf.Processes{ { diff --git a/src/autoscaler/cf/client_test.go b/src/autoscaler/cf/client_test.go index b39d6f6121..7ce444c251 100644 --- a/src/autoscaler/cf/client_test.go +++ b/src/autoscaler/cf/client_test.go @@ -13,14 +13,14 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/ghttp" - . "code.cloudfoundry.org/app-autoscaler/src/autoscaler/cf" + "code.cloudfoundry.org/app-autoscaler/src/autoscaler/cf" ) var _ = Describe("Client", func() { BeforeEach(func() { fakeCC.Add().Info(fakeLoginServer.URL()) }) Describe("Login", func() { - var tokens Tokens + var tokens cf.Tokens JustBeforeEach(func() { err = cfc.Login() }) Context("when the token url is valid", func() { @@ -29,14 +29,14 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), + ghttp.VerifyRequest("POST", cf.PathCFAuth), ghttp.VerifyBasicAuth(conf.ClientID, conf.Secret), ghttp.VerifyForm(url.Values{ - "grant_type": {GrantTypeClientCredentials}, + "grant_type": {cf.GrantTypeClientCredentials}, "client_id": {conf.ClientID}, "client_secret": {conf.Secret}, }), - ghttp.RespondWithJSONEncoded(http.StatusOK, Tokens{ + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, }), @@ -69,7 +69,7 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), + ghttp.VerifyRequest("POST", cf.PathCFAuth), ghttp.RespondWith(401, ""), ), ) @@ -88,8 +88,8 @@ var _ = Describe("Client", func() { //var tokens Tokens BeforeEach(func() { fakeCC.Add().Info(fakeLoginServer.URL()) - fakeLoginServer.RouteToHandler(http.MethodPost, PathCFAuth, - ghttp.RespondWithJSONEncoded(http.StatusOK, Tokens{ + fakeLoginServer.RouteToHandler(http.MethodPost, cf.PathCFAuth, + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, }), @@ -113,21 +113,21 @@ var _ = Describe("Client", func() { } mu.Unlock() wg.Wait() - Expect(fakeLoginServer.Count().Requests(PathCFAuth)).To(Equal(1)) + Expect(fakeLoginServer.Count().Requests(cf.PathCFAuth)).To(Equal(1)) }) }) }) Describe("RefreshAuthToken", func() { - var authToken Tokens + var authToken cf.Tokens JustBeforeEach(func() { authToken, err = cfc.RefreshAuthToken() }) Context("when not logged in", func() { - var tokens Tokens + var tokens cf.Tokens BeforeEach(func() { fakeCC.Add().Info(fakeLoginServer.URL()) @@ -137,8 +137,8 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), - ghttp.RespondWithJSONEncoded(http.StatusOK, Tokens{ + ghttp.VerifyRequest("POST", cf.PathCFAuth), + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, }), @@ -148,7 +148,7 @@ var _ = Describe("Client", func() { It("returns valid token", func() { Expect(err).NotTo(HaveOccurred()) - Expect(authToken).To(Equal(Tokens{ + Expect(authToken).To(Equal(cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, })) @@ -164,7 +164,7 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), + ghttp.VerifyRequest("POST", cf.PathCFAuth), ghttp.RespondWith(401, ""), ), ) @@ -182,8 +182,8 @@ var _ = Describe("Client", func() { fakeCC.Add().Info(fakeLoginServer.URL()) fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), - ghttp.RespondWithJSONEncoded(http.StatusOK, Tokens{ + ghttp.VerifyRequest("POST", cf.PathCFAuth), + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, }), @@ -197,9 +197,9 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), + ghttp.VerifyRequest("POST", cf.PathCFAuth), ghttp.VerifyForm(url.Values{ - "grant_type": {GrantTypeClientCredentials}, + "grant_type": {cf.GrantTypeClientCredentials}, "client_id": {conf.ClientID}, "client_secret": {conf.Secret}, }), @@ -218,13 +218,13 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), + ghttp.VerifyRequest("POST", cf.PathCFAuth), ghttp.VerifyForm(url.Values{ - "grant_type": {GrantTypeClientCredentials}, + "grant_type": {cf.GrantTypeClientCredentials}, "client_id": {conf.ClientID}, "client_secret": {conf.Secret}, }), - ghttp.RespondWithJSONEncoded(http.StatusOK, Tokens{ + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, }), @@ -233,7 +233,7 @@ var _ = Describe("Client", func() { }) It("returns valid tokens", func() { Expect(err).NotTo(HaveOccurred()) - Expect(authToken).To(Equal(Tokens{ + Expect(authToken).To(Equal(cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, })) @@ -247,18 +247,18 @@ var _ = Describe("Client", func() { }) Describe("GetTokens", func() { - var tokens Tokens + var tokens cf.Tokens JustBeforeEach(func() { tokens, err = cfc.GetTokens() }) BeforeEach(func() { - cfc = NewCFClient(conf, lager.NewLogger("cf"), fclock) + cfc = cf.NewCFClient(conf, lager.NewLogger("cf"), fclock) fakeCC.Add().Info(fakeLoginServer.URL()) fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), - ghttp.RespondWithJSONEncoded(http.StatusOK, Tokens{ + ghttp.VerifyRequest("POST", cf.PathCFAuth), + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, }), @@ -270,7 +270,7 @@ var _ = Describe("Client", func() { Context("when the token is not going to be expired", func() { BeforeEach(func() { - fclock.Increment(12000*time.Second - TimeToRefreshBeforeTokenExpire) + fclock.Increment(12000*time.Second - cf.TimeToRefreshBeforeTokenExpire) }) It("does not refresh tokens", func() { Expect(tokens.AccessToken).To(Equal("test-access-token")) @@ -284,19 +284,19 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), + ghttp.VerifyRequest("POST", cf.PathCFAuth), ghttp.VerifyForm(url.Values{ - "grant_type": {GrantTypeClientCredentials}, + "grant_type": {cf.GrantTypeClientCredentials}, "client_id": {conf.ClientID}, "client_secret": {conf.Secret}, }), - ghttp.RespondWithJSONEncoded(http.StatusOK, Tokens{ + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.Tokens{ AccessToken: "test-access-token-refreshed", ExpiresIn: 24000, }), ), ) - fclock.Increment(12001*time.Second - TimeToRefreshBeforeTokenExpire) + fclock.Increment(12001*time.Second - cf.TimeToRefreshBeforeTokenExpire) }) It("refreshes tokens", func() { @@ -310,7 +310,7 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeCC.Add().Info(fakeLoginServer.URL()) fakeLoginServer.RouteToHandler("POST", "/oauth/token", ghttp.RespondWith(401, "")) - fclock.Increment(12001*time.Second - TimeToRefreshBeforeTokenExpire) + fclock.Increment(12001*time.Second - cf.TimeToRefreshBeforeTokenExpire) }) It("returns existing tokens", func() { @@ -327,12 +327,12 @@ var _ = Describe("Client", func() { Describe("IsTokenAuthorized", func() { BeforeEach(func() { - cfc = NewCFClient(conf, lager.NewLogger("cf"), fclock) + cfc = cf.NewCFClient(conf, lager.NewLogger("cf"), fclock) fakeCC.Add().Info(fakeLoginServer.URL()) fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathCFAuth), - ghttp.RespondWithJSONEncoded(http.StatusOK, Tokens{ + ghttp.VerifyRequest("POST", cf.PathCFAuth), + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, }), @@ -356,8 +356,8 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathIntrospectToken), - ghttp.RespondWithJSONEncoded(http.StatusOK, IntrospectionResponse{Active: false}), + ghttp.VerifyRequest("POST", cf.PathIntrospectToken), + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.IntrospectionResponse{Active: false}), ), ) }) @@ -378,8 +378,8 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathIntrospectToken), - ghttp.RespondWithJSONEncoded(http.StatusOK, IntrospectionResponse{Active: true, ClientId: wrongClientID, Email: validClientID}), + ghttp.VerifyRequest("POST", cf.PathIntrospectToken), + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.IntrospectionResponse{Active: true, ClientId: wrongClientID, Email: validClientID}), ), ) }) @@ -401,8 +401,8 @@ var _ = Describe("Client", func() { BeforeEach(func() { fakeLoginServer.AppendHandlers( ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", PathIntrospectToken), - ghttp.RespondWithJSONEncoded(http.StatusOK, IntrospectionResponse{Active: true, ClientId: validClientID, Email: "john@doe"}), + ghttp.VerifyRequest("POST", cf.PathIntrospectToken), + ghttp.RespondWithJSONEncoded(http.StatusOK, cf.IntrospectionResponse{Active: true, ClientId: validClientID, Email: "john@doe"}), ), ) }) diff --git a/src/autoscaler/cf/config_test.go b/src/autoscaler/cf/config_test.go index c8d89b8ed7..a523d12cff 100644 --- a/src/autoscaler/cf/config_test.go +++ b/src/autoscaler/cf/config_test.go @@ -1,7 +1,7 @@ package cf_test import ( - . "code.cloudfoundry.org/app-autoscaler/src/autoscaler/cf" + "code.cloudfoundry.org/app-autoscaler/src/autoscaler/cf" "gopkg.in/yaml.v3" . "github.com/onsi/ginkgo/v2" @@ -11,7 +11,7 @@ import ( var _ = Describe("Config", func() { var ( - conf *Config + conf *cf.Config err error ) Describe("Deserialise", func() { @@ -37,12 +37,12 @@ idle_connection_timeout_ms: 200 }) It("should deserialise correctly", func() { Expect(err).To(Not(HaveOccurred())) - Expect(conf).To(Equal(&Config{ + Expect(conf).To(Equal(&cf.Config{ API: "https://api.example.com", ClientID: "client-id", Secret: "client-secret", PerPage: 3, - ClientConfig: ClientConfig{ + ClientConfig: cf.ClientConfig{ SkipSSLValidation: true, MaxRetries: 3, MaxRetryWaitMs: 27, @@ -57,7 +57,7 @@ idle_connection_timeout_ms: 200 Describe("Validate", func() { BeforeEach(func() { - conf = &Config{} + conf = &cf.Config{} conf.API = "http://api.example.com" conf.ClientID = "admin" conf.SkipSSLValidation = false diff --git a/src/autoscaler/cf/metadata.go b/src/autoscaler/cf/metadata.go new file mode 100644 index 0000000000..d922f32b72 --- /dev/null +++ b/src/autoscaler/cf/metadata.go @@ -0,0 +1,8 @@ +package cf + +type Metadata struct { + Labels `json:"labels"` +} +type Labels struct { + DisableAutoscaling *string `json:"app-autoscaler.cloudfoundry.org/disable-autoscaling"` +} diff --git a/src/autoscaler/cf/oauth_test.go b/src/autoscaler/cf/oauth_test.go index 84428ee8e1..ac2145e1f3 100644 --- a/src/autoscaler/cf/oauth_test.go +++ b/src/autoscaler/cf/oauth_test.go @@ -5,7 +5,7 @@ import ( "code.cloudfoundry.org/app-autoscaler/src/autoscaler/cf/mocks" - . "code.cloudfoundry.org/app-autoscaler/src/autoscaler/cf" + "code.cloudfoundry.org/app-autoscaler/src/autoscaler/cf" "code.cloudfoundry.org/clock" "code.cloudfoundry.org/lager/v3/lagertest" . "github.com/onsi/ginkgo/v2" @@ -31,8 +31,8 @@ const ( var _ = Describe("Oauth", func() { var ( - conf *Config - cfc CFClient + conf *cf.Config + cfc cf.CFClient err error userToken string logger *lagertest.TestLogger @@ -52,7 +52,7 @@ var _ = Describe("Oauth", func() { appStatus int rolesStatus int - roles Roles + roles cf.Roles ) BeforeEach(func() { @@ -61,7 +61,7 @@ var _ = Describe("Oauth", func() { userScopeStatus = http.StatusOK userInfoStatus = http.StatusOK rolesStatus = http.StatusOK - roles = Roles{{Type: RoleSpaceDeveloper}} + roles = cf.Roles{{Type: cf.RoleSpaceDeveloper}} userInfoResponse = userInfo{ UserId: TestUserId, } @@ -70,15 +70,15 @@ var _ = Describe("Oauth", func() { fakeTokenServer = mocks.NewServer() fakeTokenServer.RouteToHandler(http.MethodGet, "/userinfo", ghttp.RespondWithJSONEncodedPtr(&userInfoStatus, &userInfoResponse)) fakeTokenServer.RouteToHandler(http.MethodPost, "/check_token", ghttp.RespondWithJSONEncodedPtr(&userScopeStatus, &userScopeResponse)) - fakeTokenServer.RouteToHandler("POST", PathCFAuth, ghttp.RespondWithJSONEncoded(http.StatusOK, Tokens{ + fakeTokenServer.RouteToHandler("POST", cf.PathCFAuth, ghttp.RespondWithJSONEncoded(http.StatusOK, cf.Tokens{ AccessToken: "test-access-token", ExpiresIn: 12000, })) fakeCCServer.Add().Info(fakeTokenServer.URL()) - conf = &Config{} + conf = &cf.Config{} conf.API = fakeCCServer.URL() logger = lagertest.NewTestLogger("oauth-test") - cfc = NewCFClient(conf, logger, clock.NewClock()) + cfc = cf.NewCFClient(conf, logger, clock.NewClock()) err = cfc.Login() }) @@ -225,7 +225,7 @@ var _ = Describe("Oauth", func() { Context("user is not space developer", func() { BeforeEach(func() { - roles = Roles{{Type: RoleOrganizationManager}} + roles = cf.Roles{{Type: cf.RoleOrganizationManager}} }) It("should return false", func() { Expect(err).NotTo(HaveOccurred()) @@ -296,7 +296,7 @@ var _ = Describe("Oauth", func() { BeforeEach(func() { userScopeStatus = http.StatusOK userScopeResponse = userScope{ - Scope: []string{CCAdminScope}, + Scope: []string{cf.CCAdminScope}, } }) It("should return true", func() { diff --git a/src/autoscaler/cf/testdata/app.json b/src/autoscaler/cf/testdata/app.json index 9d6ae09e69..9fdd874692 100644 --- a/src/autoscaler/cf/testdata/app.json +++ b/src/autoscaler/cf/testdata/app.json @@ -22,6 +22,7 @@ }, "metadata": { "labels": { + "app-autoscaler.cloudfoundry.org/disable-autoscaling": "true" }, "annotations": { } diff --git a/src/autoscaler/healthendpoint/health_readiness_test.go b/src/autoscaler/healthendpoint/health_readiness_test.go index b45d19d7f5..3d90cea8e7 100644 --- a/src/autoscaler/healthendpoint/health_readiness_test.go +++ b/src/autoscaler/healthendpoint/health_readiness_test.go @@ -230,7 +230,7 @@ var _ = Describe("Health Readiness", func() { }) It("should respond with 401 due fallthough to Prometheus health", func() { - apitest.New().Debug(). + apitest.New(). Handler(healthRoute). Get("/health/readiness"). Expect(t). diff --git a/src/autoscaler/scalingengine/scalingengine.go b/src/autoscaler/scalingengine/scalingengine.go index 5507d6ac4f..18622f12dc 100644 --- a/src/autoscaler/scalingengine/scalingengine.go +++ b/src/autoscaler/scalingengine/scalingengine.go @@ -101,6 +101,24 @@ func (s *scalingEngine) Scale(appId string, trigger *models.Trigger) (*models.Ap return result, nil } + if disableAutoscaling := appAndProcesses.App.DisableAutoscaling; disableAutoscaling != nil { + logger.Info("check-app-label", lager.Data{"message": "ignore scaling since app has the label app-autoscaler.cloudfoundry.org/disable-autoscaling set", "label-value": *disableAutoscaling}) + history.Status = models.ScalingStatusIgnored + history.NewInstances = instances + appNotScaledDueTolabel := "The application was not scaled as the label " + + "\"app-autoscaler.cloudfoundry.org/disable-autoscaling\" " + + "was set on the app." + if *disableAutoscaling == "" { + history.Message = appNotScaledDueTolabel + } else { + history.Message = fmt.Sprintf(appNotScaledDueTolabel+ + " The content of the label might give a hint on why the label was set: \"%s\"", + *disableAutoscaling) + } + result.Status = history.Status + return result, nil + } + ok, expiredAt, err := s.scalingEngineDB.CanScaleApp(appId) if err != nil { logger.Error("failed-to-check-cooldown", err) diff --git a/src/autoscaler/scalingengine/scalingengine_test.go b/src/autoscaler/scalingengine/scalingengine_test.go index 98f58bc1ad..ba0db338cc 100644 --- a/src/autoscaler/scalingengine/scalingengine_test.go +++ b/src/autoscaler/scalingengine/scalingengine_test.go @@ -133,6 +133,33 @@ var _ = Describe("ScalingEngine", func() { }) }) + Context("When app is labeled with app-autoscaler.cloudfoundry.org/disable-autoscaling", func() { + BeforeEach(func() { + labelContent := "for test purposes" + cfc.GetAppAndProcessesReturns(&cf.AppAndProcesses{Processes: cf.Processes{{Instances: 2}}, App: &cf.App{State: appState, Metadata: cf.Metadata{Labels: cf.Labels{DisableAutoscaling: &labelContent}}}}, nil) + }) + It("ignore the scaling and store the ignored scaling history", func() { + Eventually(buffer).Should(gbytes.Say("check-app-label")) + Eventually(buffer).Should(gbytes.Say("ignore scaling since app has the label app-autoscaler.cloudfoundry.org/disable-autoscaling set")) + + Expect(scalingEngineDB.SaveScalingHistoryArgsForCall(0)).To(Equal(&models.AppScalingHistory{ + AppId: "an-app-id", + Timestamp: clock.Now().UnixNano(), + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusIgnored, + OldInstances: 2, + NewInstances: 2, + Reason: "+1 instance(s) because test-metric-type > 80test-unit for 100 seconds", + Message: "The application was not scaled as the label \"app-autoscaler.cloudfoundry.org/disable-autoscaling\" was set on the app. The content of the label might give a hint on why the label was set: \"for test purposes\"", + })) + + Expect(scalingResult.AppId).To(Equal("an-app-id")) + Expect(scalingResult.Status).To(Equal(models.ScalingStatusIgnored)) + Expect(scalingResult.Adjustment).To(Equal(0)) + Expect(scalingResult.CooldownExpiredAt).To(Equal(int64(0))) + }) + }) + Context("when app is in cooldown period", func() { BeforeEach(func() { setAppAndProcesses(2, appState) From b44b05f05453a10c531a2a76c4eda379df0a26fa Mon Sep 17 00:00:00 2001 From: Silvestre Zabala Date: Fri, 17 May 2024 18:25:11 +0200 Subject: [PATCH 3/3] fixup! feat! Remove `buildin` mode (#2916) --- .../workflows/acceptance_tests_reusable.yaml | 5 - ci/autoscaler/scripts/common.sh | 1 - ci/autoscaler/scripts/run-acceptance-tests.sh | 2 - ci/autoscaler/scripts/vars.source.sh | 3 - ci/autoscaler/tasks/register-broker.yml | 1 - scripts/deploy_acceptance_app.sh | 60 ---------- src/acceptance/README.md | 2 - src/acceptance/app/app_suite_test.go | 8 -- src/acceptance/app/custom_metric_test.go | 1 - src/acceptance/assets/app/go_app/deploy.sh | 13 +-- src/acceptance/broker/broker_suite_test.go | 3 - src/acceptance/config/config.go | 10 +- src/acceptance/example_config/example.json | 3 +- src/acceptance/helpers/helpers.go | 105 ++++++++---------- src/acceptance/helpers/services.go | 48 +------- .../post_upgrade/post_upgrade_suite_test.go | 4 +- .../pre_upgrade/pre_custom_metric_test.go | 1 - .../pre_upgrade/pre_upgrade_suite_test.go | 4 +- .../run_performance_suite_test.go | 4 +- .../setup_performance_suite_test.go | 4 +- .../setup_performance_test.go | 1 - 21 files changed, 63 insertions(+), 220 deletions(-) delete mode 100755 scripts/deploy_acceptance_app.sh diff --git a/.github/workflows/acceptance_tests_reusable.yaml b/.github/workflows/acceptance_tests_reusable.yaml index bc8d251a2b..06945330d0 100644 --- a/.github/workflows/acceptance_tests_reusable.yaml +++ b/.github/workflows/acceptance_tests_reusable.yaml @@ -5,10 +5,6 @@ on: self_hosted_image: type: string default: ghcr.io/cloudfoundry/app-autoscaler-release-tools:main - service_offering_enabled: - required: false - type: boolean - default: true suites: required: false type: string @@ -25,7 +21,6 @@ defaults: shell: bash env: - SERVICE_OFFERING_ENABLED: "${{ inputs.service_offering_enabled }}" PR_NUMBER: "${{ github.event.pull_request.number }}" DEPLOYMENT_NAME: "${{ inputs.deployment_name }}" BBL_STATE_PATH: "${{ github.workspace }}/bbl/bbl-state" diff --git a/ci/autoscaler/scripts/common.sh b/ci/autoscaler/scripts/common.sh index 35221bca82..b4e41ca8d7 100644 --- a/ci/autoscaler/scripts/common.sh +++ b/ci/autoscaler/scripts/common.sh @@ -89,6 +89,5 @@ function unset_vars() { unset SERVICE_NAME unset SERVICE_BROKER_NAME unset NAME_PREFIX - unset SERVICE_OFFERING_ENABLED unset GINKGO_OPTS } diff --git a/ci/autoscaler/scripts/run-acceptance-tests.sh b/ci/autoscaler/scripts/run-acceptance-tests.sh index 23e2c2640c..b09a07b857 100755 --- a/ci/autoscaler/scripts/run-acceptance-tests.sh +++ b/ci/autoscaler/scripts/run-acceptance-tests.sh @@ -5,7 +5,6 @@ script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source "${script_dir}/vars.source.sh" cf_admin_password="${CF_ADMIN_PASSWORD:-}" -service_offering_enabled="${SERVICE_OFFERING_ENABLED:-true}" skip_ssl_validation="${SKIP_SSL_VALIDATION:-true}" skip_teardown="${SKIP_TEARDOWN:-false}" use_existing_organization="${USE_EXISTING_ORGANIZATION:-false}" @@ -56,7 +55,6 @@ cat > acceptance_config.json < /dev/null && pwd )" -pushd "${script_dir}" > /dev/null -source ./vars.source.sh -test_app_name=test-app -#test_service_name=test-app-service -test_org="testing-pr-app" -test_space="testing-pr-app" -number_apps=${NUMBER_OF_APPS:-1} -app_location="${script_dir}/../src/acceptance/assets/app/nodeApp" -#service_offering_enabled=false -# shellcheck disable=SC2154 -service_offering="app-autoscaler-${pr_number}" - -function create_app { - local app_name=$1 - cf push --var app_name="${app_name}"\ - --var app_domain=autoscaler.app-runtime-interfaces.ci.cloudfoundry.org\ - --var service_name="${service_offering}"\ - --var instances=1\ - --var node_tls_reject_unauthorized=0\ - -p "${app_location}"\ - -f "${app_location}/app_manifest.yml"\ - --no-start & - -# cf bind-service "${app_name}" "${test_service_name}" - } - -# shellcheck disable=SC1091 -cf create-org "${test_org}" -cf target -o "${test_org}" -cf create-space "${test_space}" -cf target -s "${test_space}" -#cf enable-service-access "${service_offering}" -b "${service_offering}" -o "${test_org}" -#cf create-service "${service_offering}" autoscaler-free-plan "${test_service_name}" -b "${service_offering}" -for app_number in $(seq 1 "${number_apps}") ; do - app_name="${test_app_name}-${app_number}" - echo " - creating app ${app_name}" - create_app "${app_name}" -done -wait - -for app_number in $(seq 1 "${number_apps}") ; do - app_name="${test_app_name}-${app_number}" - app_guid="$(cf app "${app_name}" --guid)" - - echo " - ${app_name} guid: ${app_guid}" -done -wait - - -for app_number in $(seq 1 "${number_apps}") ; do - echo " - starting app ${app_name}" - cf start "${app_name}" -done -wait - - -echo ">> $0 FINISHED" diff --git a/src/acceptance/README.md b/src/acceptance/README.md index b2d7eb4fec..92b23778b1 100644 --- a/src/acceptance/README.md +++ b/src/acceptance/README.md @@ -44,7 +44,6 @@ cat > integration_config.json <