Skip to content

Commit

Permalink
(feat) Add XFCC authenticated eventgenerator endpoint (#3330)
Browse files Browse the repository at this point in the history
* Adds cf_Server config for scalingengine

* Adds xfcc cf endpoint support to scaling engine

* Remove debug println

* Update jobs/scalingengine/spec

Co-authored-by: Silvestre Zabala <[email protected]>

* Update jobs/scalingengine/spec

Co-authored-by: Silvestre Zabala <[email protected]>

* Remove pending test

* Removes subrouter in api server

* WIP

* Fix typo

* Fix issue with routes

* Remove log message

* Fix case sensitivity in URLPath parameters for aggregated metric histories route

* Fix lint

* Refactor eventgenerator tests and improve liveness endpoint test clarity

* Refactor variable naming in server creation for clarity

* Remove EventgeneratorServer interface from server.go

---------

Co-authored-by: Silvestre Zabala <[email protected]>
  • Loading branch information
bonzofenix and silvestre authored Nov 30, 2024
1 parent 7ac946f commit fb74a2d
Show file tree
Hide file tree
Showing 21 changed files with 437 additions and 239 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ clean-targets:
clean-vendor:
@echo " - cleaning vendored go"
@find . -depth -name "vendor" -type d -exec rm -rf {} \;
clean-fakes:
@echo " - cleaning fakes"
@find . -depth -name "fakes" -type d -exec rm -rf {} \;
clean-autoscaler:
@make --directory='./src/autoscaler' clean
clean-scheduler:
Expand Down
12 changes: 12 additions & 0 deletions jobs/eventgenerator/spec
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,18 @@ properties:
autoscaler.eventgenerator.server_key:
description: "PEM-encoded server key"

autoscaler.cf_server.port:
description: "the listening port of cf xfcc endpoint"
default: 8080

autoscaler.cf_server.xfcc.valid_org_guid:
description: approve org guid for xfcc endpoint
default: ''

autoscaler.cf_server.xfcc.valid_space_guid:
description: approve space guid for xfcc endpoint
default: ''

autoscaler.eventgenerator.aggregator.aggregator_execute_interval:
description: "the time interval to aggregate metrics data"
default: 40s
Expand Down
6 changes: 6 additions & 0 deletions jobs/eventgenerator/templates/eventgenerator.yml.erb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ server:
node_addrs: <%= nodeAddrs %>
node_index: <%= nodeIndex %>

cf_server:
port: <%= p("autoscaler.cf_server.port") %>
xfcc:
valid_org_guid: <%= p("autoscaler.cf_server.xfcc.valid_org_guid") %>
valid_space_guid: <%= p("autoscaler.cf_server.xfcc.valid_space_guid") %>

logging:
level: <%= p("autoscaler.eventgenerator.logging.level") %>
http_client_timeout: <%= p("autoscaler.eventgenerator.http_client_timeout") %>
Expand Down
25 changes: 25 additions & 0 deletions operations/use-cf-services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,28 @@
uris:
- ((deployment_name))-cf-scalingengine.((system_domain))

## EVENTGENERATOR - Enable cf Server to receive calls from api running on cf --

- type: replace
path: /instance_groups/name=eventgenerator/jobs/name=eventgenerator/properties/autoscaler/eventgenerator/cf_server?/xfcc?/valid_org_guid?
value: ((autoscaler_cf_server_xfcc_valid_org_guid))

- type: replace
path: /instance_groups/name=eventgenerator/jobs/name=eventgenerator/properties/autoscaler/eventgenerator/cf_server?/xfcc?/valid_space_guid?
value: ((autoscaler_cf_server_xfcc_valid_space_guid))


- type: replace
path: /instance_groups/name=eventgenerator/jobs/name=eventgenerator/properties/autoscaler/eventgenerator/cf_server?/port?
value: &EventGeneratorCfPort 6205

- type: replace
path: /instance_groups/name=postgres/jobs/name=route_registrar/properties/route_registrar/routes/-
value:
name: ((deployment_name))-cf-eventgenerator
registration_interval: 20s
port: *EventGeneratorCfPort
tags:
component: autoscaler_cf_eventgenerator
uris:
- ((deployment_name))-cf-eventgenerator.((system_domain))
1 change: 1 addition & 0 deletions packages/eventgenerator/spec
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ files:
- autoscaler/eventgenerator/server/* # gosub
- autoscaler/healthendpoint/* # gosub
- autoscaler/helpers/* # gosub
- autoscaler/helpers/auth/* # gosub
- autoscaler/helpers/handlers/* # gosub
- autoscaler/metricsforwarder/server/common/* # gosub
- autoscaler/models/* # gosub
Expand Down
17 changes: 17 additions & 0 deletions spec/jobs/eventgenerator/eventgenerator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,23 @@
end
end

context "cf server" do
it "includes default port for cf server" do
expect(rendered_template["cf_server"]["port"]).to eq(8080)
end

it "defaults xfcc valid org and space " do
properties["autoscaler"]["cf_server"] = {}
properties["autoscaler"]["cf_server"]["xfcc"] = {
"valid_org_guid" => "some-valid-org-guid",
"valid_space_guid" => "some-valid-space-guid"
}

expect(rendered_template["cf_server"]["xfcc"]["valid_org_guid"]).to eq(properties["autoscaler"]["cf_server"]["xfcc"]["valid_org_guid"])
expect(rendered_template["cf_server"]["xfcc"]["valid_space_guid"]).to eq(properties["autoscaler"]["cf_server"]["xfcc"]["valid_space_guid"])
end
end

context "uses tls" do
context "policy_db" do
it "includes the ca, cert and key in url when configured" do
Expand Down
13 changes: 12 additions & 1 deletion src/autoscaler/api/publicapiserver/public_api_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,18 @@ func (h *PublicApiHandler) GetAggregatedMetricsHistories(w http.ResponseWriter,
}

pathFn := func() string {
path, _ := routes.EventGeneratorRoutes().Get(routes.GetAggregatedMetricHistoriesRouteName).URLPath("appid", appId, "metrictype", metricType)
r := routes.NewRouter()
router := r.CreateEventGeneratorRoutes()
if router == nil {
panic("Failed to create event generator routes")
}

route := router.Get(routes.GetAggregatedMetricHistoriesRouteName)
path, err := route.URLPath("appid", appId, "metrictype", metricType)
if err != nil {
logger.Error("Failed to create path", err)
panic(err)
}
return h.conf.EventGenerator.EventGeneratorUrl + path.RequestURI() + "?" + parameters.Encode()
}
proxyRequest(pathFn, h.eventGeneratorClient.Get, w, req.URL, parameters, "metrics history from eventgenerator", logger)
Expand Down
5 changes: 5 additions & 0 deletions src/autoscaler/build-extension-file.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ export POSTGRES_EXTERNAL_PORT="${PR_NUMBER:-5432}"

export METRICSFORWARDER_HOST="${METRICSFORWARDER_HOST:-"${DEPLOYMENT_NAME}-metricsforwarder"}"
export METRICSFORWARDER_MTLS_HOST="${METRICSFORWARDER_MTLS_HOST:-"${DEPLOYMENT_NAME}-metricsforwarder-mtls"}"

export SCALINGENGINE_HOST="${SCALINGENGINE_HOST:-"${DEPLOYMENT_NAME}-cf-scalingengine"}"
export EVENTGENERATOR_HOST="${EVENTGENERATOR_HOST:-"${DEPLOYMENT_NAME}-cf-eventgenerator"}"

export PUBLICAPISERVER_HOST="${PUBLICAPISERVER_HOST:-"${DEPLOYMENT_NAME}"}"
export SERVICEBROKER_HOST="${SERVICEBROKER_HOST:-"${DEPLOYMENT_NAME}servicebroker"}"

Expand Down Expand Up @@ -116,4 +119,6 @@ resources:
metrics_forwarder_mtls_url: ${METRICSFORWARDER_MTLS_HOST}.\${default-domain}
scaling_engine:
scaling_engine_url: ${SCALINGENGINE_HOST}.\${default-domain}
event_generator:
event_generator_url: ${EVENTGENERATOR_HOST}.\${default-domain}
EOF
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ var (
regPath = regexp.MustCompile(`^/v1/apps/.*/scale$`)
configFile *os.File
conf config.Config
egPort int
healthport int
httpClient *http.Client
healthHttpClient *http.Client
mockLogCache *testhelpers.MockLogCache
Expand Down Expand Up @@ -240,22 +238,9 @@ func initHttpEndPoints() {
func initConfig() {
testCertDir := testhelpers.TestCertFolder()

egPort = 7000 + GinkgoParallelProcess()
healthport = 8000 + GinkgoParallelProcess()
dbUrl := testhelpers.GetDbUrl()
conf = config.Config{
Logging: helpers.LoggingConfig{
Level: "debug",
},
Server: config.ServerConfig{
ServerConfig: helpers.ServerConfig{
Port: egPort,
TLS: models.TLSCerts{
KeyFile: filepath.Join(testCertDir, "eventgenerator.key"),
CertFile: filepath.Join(testCertDir, "eventgenerator.crt"),
CACertFile: filepath.Join(testCertDir, "autoscaler-ca.crt"),
},
},
NodeAddrs: []string{"localhost"},
NodeIndex: 0,
},
Expand Down Expand Up @@ -313,14 +298,27 @@ func initConfig() {
HttpClientTimeout: 10 * time.Second,
Health: helpers.HealthConfig{
ServerConfig: helpers.ServerConfig{
Port: healthport,
Port: 8000 + GinkgoParallelProcess(),
},
BasicAuth: models.BasicAuth{
Username: "healthcheckuser",
Password: "healthcheckpassword",
},
},
}

conf.Health.ServerConfig.Port = 8000 + GinkgoParallelProcess()

conf.CFServer.Port = 9000 + GinkgoParallelProcess()
conf.CFServer.XFCC.ValidOrgGuid = "org-guid"
conf.CFServer.XFCC.ValidSpaceGuid = "space-guid"

// Configure the server to use the test certs
conf.Server.Port = 7000 + GinkgoParallelProcess()
conf.Server.TLS.KeyFile = filepath.Join(testCertDir, "eventgenerator.key")
conf.Server.TLS.CertFile = filepath.Join(testCertDir, "eventgenerator.crt")
conf.Server.TLS.CACertFile = filepath.Join(testCertDir, "autoscaler-ca.crt")
conf.Logging.Level = "debug"
configFile = writeConfig(&conf)
}

Expand Down Expand Up @@ -361,7 +359,7 @@ func (eg *EventGeneratorRunner) Start() {
Expect(err).NotTo(HaveOccurred())

if eg.startCheck != "" {
Eventually(egSession.Buffer, 2).Should(gbytes.Say(eg.startCheck))
Eventually(egSession.Buffer, 6).Should(gbytes.Say(eg.startCheck))
}

eg.Session = egSession
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

"code.cloudfoundry.org/app-autoscaler/src/autoscaler/eventgenerator/config"
"code.cloudfoundry.org/app-autoscaler/src/autoscaler/helpers"
"code.cloudfoundry.org/app-autoscaler/src/autoscaler/testhelpers"
. "code.cloudfoundry.org/app-autoscaler/src/autoscaler/testhelpers"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand All @@ -25,34 +25,38 @@ var _ = Describe("Eventgenerator", func() {
httpClientForEventGenerator *http.Client
httpClientForHealth *http.Client

serverURL *url.URL
healthURL *url.URL
serverURL *url.URL
healthURL *url.URL
cfServerURL *url.URL

err error
)

BeforeEach(func() {
runner = NewEventGeneratorRunner()

httpClientForEventGenerator = testhelpers.NewEventGeneratorClient()
httpClientForEventGenerator = NewEventGeneratorClient()
httpClientForHealth = &http.Client{}

serverURL, err = url.Parse("https://127.0.0.1:" + strconv.Itoa(conf.Server.Port))
Expect(err).ToNot(HaveOccurred())

healthURL, err = url.Parse("http://127.0.0.1:" + strconv.Itoa(conf.Health.ServerConfig.Port))
Expect(err).ToNot(HaveOccurred())

cfServerURL, err = url.Parse("http://127.0.0.1:" + strconv.Itoa(conf.CFServer.Port))
Expect(err).ToNot(HaveOccurred())

})

JustBeforeEach(func() {
runner.Start()
})

AfterEach(func() {
runner.KillWithFire()
})

Context("with a valid config file", func() {
BeforeEach(func() {
runner.Start()
})

It("Starts successfully, retrives metrics and generates events", func() {
Consistently(runner.Session).ShouldNot(Exit())
Eventually(func() bool { return mockLogCache.ReadRequestsCount() >= 1 }, 5*time.Second).Should(BeTrue())
Expand All @@ -64,7 +68,6 @@ var _ = Describe("Eventgenerator", func() {
BeforeEach(func() {
runner.startCheck = ""
runner.configPath = "bogus"
runner.Start()
})

It("fails with an error", func() {
Expand All @@ -82,7 +85,6 @@ var _ = Describe("Eventgenerator", func() {
// #nosec G306
err = os.WriteFile(runner.configPath, []byte("bogus"), os.ModePerm)
Expect(err).NotTo(HaveOccurred())
runner.Start()
})

AfterEach(func() {
Expand Down Expand Up @@ -116,7 +118,6 @@ var _ = Describe("Eventgenerator", func() {
}
configFile := writeConfig(conf)
runner.configPath = configFile.Name()
runner.Start()
})

AfterEach(func() {
Expand All @@ -130,9 +131,6 @@ var _ = Describe("Eventgenerator", func() {
})

When("an interrupt is sent", func() {
BeforeEach(func() {
runner.Start()
})

It("should stop", func() {
runner.Session.Interrupt()
Expand All @@ -144,7 +142,6 @@ var _ = Describe("Eventgenerator", func() {
When("a request for aggregated metrics history comes", func() {
BeforeEach(func() {
serverURL.Path = "/v1/apps/an-app-id/aggregated_metric_histories/a-metric-type"
runner.Start()
})

It("returns with a 200", func() {
Expand All @@ -169,8 +166,6 @@ var _ = Describe("Eventgenerator", func() {
basicAuthConfig.Health.BasicAuth.Password = ""
runner.configPath = writeConfig(&basicAuthConfig).Name()

runner.Start()

})

When("a request to query health comes", func() {
Expand All @@ -194,9 +189,6 @@ var _ = Describe("Eventgenerator", func() {
})

When("Health server is ready to serve RESTful API with basic Auth", func() {
BeforeEach(func() {
runner.Start()
})

When("username and password are incorrect for basic authentication during health check", func() {
It("should return 401", func() {
Expand Down Expand Up @@ -226,9 +218,6 @@ var _ = Describe("Eventgenerator", func() {
})

When("Health server is ready to serve RESTful API with basic Auth", func() {
BeforeEach(func() {
runner.Start()
})

When("username and password are incorrect for basic authentication during health check", func() {
It("should return 401", func() {
Expand Down Expand Up @@ -257,4 +246,23 @@ var _ = Describe("Eventgenerator", func() {
})
})
})

When("running CF server", func() {
Context("Get /v1/liveness", func() {
It("should return 200", func() {
cfServerURL.Path = "/v1/liveness"

req, err := http.NewRequest(http.MethodGet, cfServerURL.String(), nil)
Expect(err).NotTo(HaveOccurred())

err = SetXFCCCertHeader(req, conf.CFServer.XFCC.ValidOrgGuid, conf.CFServer.XFCC.ValidSpaceGuid)
Expect(err).NotTo(HaveOccurred())

rsp, err := healthHttpClient.Do(req)
Expect(err).ToNot(HaveOccurred())

Expect(rsp.StatusCode).To(Equal(http.StatusOK))
})
})
})
})
Loading

0 comments on commit fb74a2d

Please sign in to comment.