Skip to content

Commit 7bbca42

Browse files
bonzofenixgithub-advanced-security[bot]asalan316
authored
(feature): allow storeprocedure run in publicapi mtar deployment (#3637)
* Refactor configureDb function to accept a pointer to the database config map in metricsforwarder config * Refactor database configuration in autoscaler API and metrics forwarder • Centralize database configuration logic into db.ConfigureDb and db.ConfigureStoredProcedureDb • Remove individual configurePolicyDb and configureBindingDb functions • Move DatabaseConfig struct to a new models.go file in the db package • Update calls to database configuration in both API and metrics forwarder to use the new centralized functions * Refactor database configuration in autoscaler API and metrics forwarder • Change db.ConfigureDb calls to vcapReader.ConfigureDb for PolicyDb and BindingDb. • Introduce vcapReader.ConfigureStoredProcedureDb for handling stored procedure database configuration. • Remove ConfigureStoredProcedureDb and ConfigureDb from db/helper.go. • Update tests to reflect changes in database configuration methods. * Remove debug print statements and enable ConfigureStoredProcedureDb test in autoscaler config utils * Add time import and DatabaseConfig struct to db.go; remove models.go - Import the "time" package in db.go for time.Duration usage. - Introduce DatabaseConfig struct in db.go with connection parameters. - Delete models.go, moving DatabaseConfig to db.go. * Add stored procedure support to autoscaler API config • Implement configuration loading for stored procedure database in config.go • Enable tests for stored procedure database when cred_helper_impl is set to default in config_test.go * Potential fix for code scanning alert no. 431: Potentially unsafe quoting Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * Fix lints * Increase instances for publicapiserver and metricsforwarder, add eventgenerator module with configuration and routes, and set default instances to 0 for new modules in autoscaler app. * correct public api server properties * debug: register broker * reduce code duplication * Makes metricsforwarde and api config dry for databases * Deploy only one public api * Fix sonarqube issues * Add list-apps target to Makefile and create list_apps.sh script for listing apps with org and space names * Remove missing repetitive definition * Fix code duplication warning * Add nosec comment to suppress false positive in configutil test dbUri --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: Arsalan Khan <[email protected]>
1 parent c4ff676 commit 7bbca42

File tree

14 files changed

+402
-268
lines changed

14 files changed

+402
-268
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@ start-scheduler:
476476
make --directory='./src/scheduler' start DBURL="${DBURL}"
477477

478478

479+
list-apps:
480+
echo " - listing apps"
481+
DEBUG="${DEBUG}" ${CI_DIR}/../scripts/list_apps.sh
482+
479483
deploy-apps:
480484
echo " - deploying apps"
481485
DEBUG="${DEBUG}" ${CI_DIR}/autoscaler/scripts/deploy-apps.sh

ci/autoscaler/scripts/register-broker.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/bin/bash
22

33
set -euo pipefail
4+
45
script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
56
source "${script_dir}/vars.source.sh"
67

scripts/list_apps.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash
2+
3+
echo "Fetching all apps with org and space names..."
4+
5+
NEXT_URL="/v3/apps"
6+
7+
while [ "$NEXT_URL" != "null" ]; do
8+
RESPONSE=$(cf curl "$NEXT_URL")
9+
10+
echo "$RESPONSE" | jq -c '.resources[]' | while read -r app; do
11+
APP_NAME=$(echo "$app" | jq -r '.name')
12+
SPACE_GUID=$(echo "$app" | jq -r '.relationships.space.data.guid')
13+
14+
# Get space details
15+
SPACE_INFO=$(cf curl "/v3/spaces/$SPACE_GUID")
16+
SPACE_NAME=$(echo "$SPACE_INFO" | jq -r '.name')
17+
ORG_GUID=$(echo "$SPACE_INFO" | jq -r '.relationships.organization.data.guid')
18+
19+
# Get org details
20+
ORG_NAME=$(cf curl "/v3/organizations/$ORG_GUID" | jq -r '.name')
21+
22+
echo "$ORG_NAME / $SPACE_NAME / $APP_NAME"
23+
done
24+
25+
NEXT_URL=$(echo "$RESPONSE" | jq -r '.pagination.next.href')
26+
done
27+

src/autoscaler/api/config/config.go

Lines changed: 3 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ const (
3636
)
3737

3838
var (
39-
ErrReadYaml = errors.New("failed to read config file")
4039
ErrPublicApiServerConfigNotFound = errors.New("publicapiserver config service not found")
4140
)
4241

@@ -140,6 +139,7 @@ func defaultConfig() Config {
140139
SkipSSLValidation: false,
141140
},
142141
},
142+
Db: make(map[string]db.DatabaseConfig),
143143
RateLimit: models.RateLimitConfig{
144144
MaxAmount: DefaultMaxAmount,
145145
ValidDuration: DefaultValidDuration,
@@ -164,24 +164,6 @@ func defaultConfig() Config {
164164
},
165165
}
166166
}
167-
func loadYamlFile(filepath string, conf *Config) error {
168-
if filepath == "" {
169-
return nil
170-
}
171-
file, err := os.Open(filepath)
172-
if err != nil {
173-
fmt.Fprintf(os.Stdout, "failed to open config file '%s': %s\n", filepath, err)
174-
return ErrReadYaml
175-
}
176-
defer file.Close()
177-
178-
dec := yaml.NewDecoder(file)
179-
dec.KnownFields(true)
180-
if err := dec.Decode(conf); err != nil {
181-
return fmt.Errorf("%w: %v", ErrReadYaml, err)
182-
}
183-
return nil
184-
}
185167
func loadPublicApiServerConfig(conf *Config, vcapReader configutil.VCAPConfigurationReader) error {
186168
data, err := vcapReader.GetServiceCredentialContent("publicapiserver-config", "publicapiserver-config")
187169
if err != nil {
@@ -203,15 +185,7 @@ func loadVcapConfig(conf *Config, vcapReader configutil.VCAPConfigurationReader)
203185
return err
204186
}
205187

206-
if conf.Db == nil {
207-
conf.Db = make(map[string]db.DatabaseConfig)
208-
}
209-
210-
if err := configurePolicyDb(conf, vcapReader); err != nil {
211-
return err
212-
}
213-
214-
if err := configureBindingDb(conf, vcapReader); err != nil {
188+
if err := vcapReader.ConfigureDatabases(&conf.Db, conf.StoredProcedureConfig, conf.CredHelperImpl); err != nil {
215189
return err
216190
}
217191

@@ -260,41 +234,10 @@ func configureScheduler(conf *Config) {
260234
conf.Scheduler.TLSClientCerts.KeyFile = os.Getenv("CF_INSTANCE_KEY")
261235
}
262236

263-
func configurePolicyDb(conf *Config, vcapReader configutil.VCAPConfigurationReader) error {
264-
currentPolicyDb, ok := conf.Db[db.PolicyDb]
265-
if !ok {
266-
conf.Db[db.PolicyDb] = db.DatabaseConfig{}
267-
}
268-
269-
dbURL, err := vcapReader.MaterializeDBFromService(db.PolicyDb)
270-
currentPolicyDb.URL = dbURL
271-
if err != nil {
272-
return err
273-
}
274-
conf.Db[db.PolicyDb] = currentPolicyDb
275-
return nil
276-
}
277-
278-
func configureBindingDb(conf *Config, vcapReader configutil.VCAPConfigurationReader) error {
279-
currentBindingDb, ok := conf.Db[db.BindingDb]
280-
if !ok {
281-
conf.Db[db.BindingDb] = db.DatabaseConfig{}
282-
}
283-
284-
dbURL, err := vcapReader.MaterializeDBFromService(db.BindingDb)
285-
currentBindingDb.URL = dbURL
286-
if err != nil {
287-
return err
288-
}
289-
conf.Db[db.BindingDb] = currentBindingDb
290-
291-
return nil
292-
}
293-
294237
func LoadConfig(filepath string, vcapReader configutil.VCAPConfigurationReader) (*Config, error) {
295238
conf := defaultConfig()
296239

297-
if err := loadYamlFile(filepath, &conf); err != nil {
240+
if err := helpers.LoadYamlFile(filepath, &conf); err != nil {
298241
return nil, err
299242
}
300243

src/autoscaler/api/config/config_test.go

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ var _ = Describe("Config", func() {
113113

114114
})
115115

116+
When("handling available databases", func() {
117+
It("calls vcapReader ConfigureDatabases with the right arguments", func() {
118+
testhelpers.ExpectConfigureDatabasesCalledOnce(err, mockVCAPConfigurationReader, conf.CredHelperImpl)
119+
})
120+
})
121+
116122
When("service is empty", func() {
117123
var expectedErr error
118124
BeforeEach(func() {
@@ -125,34 +131,6 @@ var _ = Describe("Config", func() {
125131
})
126132
})
127133

128-
When("VCAP_SERVICES has relational db service bind to app for policy db", func() {
129-
BeforeEach(func() {
130-
mockVCAPConfigurationReader.GetServiceCredentialContentReturns([]byte(`{ "cred_helper_impl": "default" }`), nil) // #nosec G101
131-
expectedDbUrl = "postgres://foo:[email protected]:5432/policy_db?sslcert=%2Ftmp%2Fclient_cert.sslcert&sslkey=%2Ftmp%2Fclient_key.sslkey&sslrootcert=%2Ftmp%2Fserver_ca.sslrootcert" // #nosec G101
132-
})
133-
134-
It("loads the db config from VCAP_SERVICES successfully", func() {
135-
Expect(err).NotTo(HaveOccurred())
136-
Expect(conf.Db[db.PolicyDb].URL).To(Equal(expectedDbUrl))
137-
actualDbName := mockVCAPConfigurationReader.MaterializeDBFromServiceArgsForCall(0)
138-
Expect(actualDbName).To(Equal(db.PolicyDb))
139-
})
140-
})
141-
142-
When("VCAP_SERVICES has relational db service bind to app for binding db", func() {
143-
BeforeEach(func() {
144-
mockVCAPConfigurationReader.GetServiceCredentialContentReturns([]byte(`{ "cred_helper_impl": "default" }`), nil) // #nosec G101
145-
expectedDbUrl = "postgres://foo:[email protected]:5432/binding_db?sslcert=%2Ftmp%2Fclient_cert.sslcert&sslkey=%2Ftmp%2Fclient_key.sslkey&sslrootcert=%2Ftmp%2Fserver_ca.sslrootcert" // #nosec G101
146-
})
147-
148-
It("loads the db config from VCAP_SERVICES successfully", func() {
149-
Expect(err).NotTo(HaveOccurred())
150-
Expect(conf.Db[db.BindingDb].URL).To(Equal(expectedDbUrl))
151-
actualDbName := mockVCAPConfigurationReader.MaterializeDBFromServiceArgsForCall(1)
152-
Expect(actualDbName).To(Equal(db.BindingDb))
153-
})
154-
})
155-
156134
When("VCAP_SERVICES has catalog", func() {
157135
var expectedCatalogContent string
158136

src/autoscaler/build-extension-file.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ modules:
8787
- name: database
8888
- name: syslog-client
8989
parameters:
90+
instances: 2
9091
routes:
9192
- route: ${METRICSFORWARDER_HOST}.\${default-domain}
9293
- route: ${METRICSFORWARDER_MTLS_HOST}.\${default-domain}
@@ -128,7 +129,6 @@ resources:
128129
broker_password: $SERVICE_BROKER_PASSWORD
129130
- broker_username: 'autoscaler-broker-user-blue'
130131
broker_password: $SERVICE_BROKER_PASSWORD_BLUE
131-
132132
- name: database
133133
parameters:
134134
config:

src/autoscaler/configutil/cf.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import (
55
"errors"
66
"fmt"
77
"net/url"
8+
"strings"
89

10+
"code.cloudfoundry.org/app-autoscaler/src/autoscaler/db"
911
"code.cloudfoundry.org/app-autoscaler/src/autoscaler/models"
1012
"github.com/cloud-gov/go-cfenv"
1113
)
@@ -21,6 +23,9 @@ type VCAPConfigurationReader interface {
2123
GetServiceCredentialContent(serviceTag string, credentialKey string) ([]byte, error)
2224
GetPort() int
2325
IsRunningOnCF() bool
26+
27+
ConfigureStoredProcedureDb(dbName string, confDb *map[string]db.DatabaseConfig, storedProcedureConfig *models.StoredProcedureConfig) error
28+
ConfigureDatabases(confDb *map[string]db.DatabaseConfig, storedProcedureConfig *models.StoredProcedureConfig, credHelperImpl string) error
2429
}
2530

2631
type VCAPConfiguration struct {
@@ -34,6 +39,8 @@ func NewVCAPConfigurationReader() (result *VCAPConfiguration, err error) {
3439
if cfenv.IsRunningOnCF() {
3540
appEnv, err = cfenv.Current()
3641
result.appEnv = appEnv
42+
} else {
43+
fmt.Println("VCAPConfigurationReader: Not running on CF")
3744
}
3845

3946
return result, err
@@ -207,3 +214,62 @@ func (vc *VCAPConfiguration) addConnectionParam(service *cfenv.Service, dbName,
207214
}
208215
return nil
209216
}
217+
218+
func (vc *VCAPConfiguration) ConfigureStoredProcedureDb(dbName string, confDb *map[string]db.DatabaseConfig, storedProcedureConfig *models.StoredProcedureConfig) error {
219+
if err := vc.configureDb(dbName, confDb); err != nil {
220+
return err
221+
}
222+
223+
currentStoredProcedureDb := (*confDb)[dbName]
224+
parsedUrl, err := url.Parse(currentStoredProcedureDb.URL)
225+
if err != nil {
226+
return err
227+
}
228+
229+
if storedProcedureConfig != nil {
230+
if storedProcedureConfig.Username != "" {
231+
currentStoredProcedureDb.URL = strings.Replace(currentStoredProcedureDb.URL, parsedUrl.User.Username(), storedProcedureConfig.Username, 1)
232+
}
233+
if storedProcedureConfig.Password != "" {
234+
bindingPassword, _ := parsedUrl.User.Password()
235+
currentStoredProcedureDb.URL = strings.Replace(currentStoredProcedureDb.URL, bindingPassword, storedProcedureConfig.Password, 1)
236+
}
237+
}
238+
(*confDb)[dbName] = currentStoredProcedureDb
239+
240+
return nil
241+
}
242+
243+
func (vc *VCAPConfiguration) configureDb(dbName string, confDb *map[string]db.DatabaseConfig) error {
244+
currentDb, ok := (*confDb)[dbName]
245+
if !ok {
246+
(*confDb)[dbName] = db.DatabaseConfig{}
247+
}
248+
249+
dbURL, err := vc.MaterializeDBFromService(dbName)
250+
currentDb.URL = dbURL
251+
if err != nil {
252+
return err
253+
}
254+
(*confDb)[dbName] = currentDb
255+
256+
return nil
257+
}
258+
259+
func (vc *VCAPConfiguration) ConfigureDatabases(confDb *map[string]db.DatabaseConfig, storedProcedureConfig *models.StoredProcedureConfig, credHelperImpl string) error {
260+
if err := vc.configureDb(db.PolicyDb, confDb); err != nil {
261+
return err
262+
}
263+
264+
if err := vc.configureDb(db.BindingDb, confDb); err != nil {
265+
return err
266+
}
267+
268+
if credHelperImpl == "stored_procedure" {
269+
if err := vc.ConfigureStoredProcedureDb(db.StoredProcedureDb, confDb, storedProcedureConfig); err != nil {
270+
return err
271+
}
272+
}
273+
274+
return nil
275+
}

0 commit comments

Comments
 (0)