Skip to content
This repository was archived by the owner on Jul 6, 2022. It is now read-only.

Commit 87d222f

Browse files
authored
Support specifying server name, admin username and password of postgreSQL (#711)
* Support specifying server name, admin username and admin password of postgreSQL * Fix lint issues and add lifecycle test * Change regexp to custom validator * Fix typo * Update lifecycle test * Fix bug * Fix role name error
1 parent d631928 commit 87d222f

17 files changed

+386
-32
lines changed

docs/modules/postgresql.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Open Service Broker for Azure contains three types of Azure Database for Postgre
1010
| `azure-postgresql-*-dbms` | Provision only an Azure Database for PostgreSQL DBMS. This can be used to provision multiple databases at a later time. |
1111
| `azure-postgresql-*-database` | Provision a new database only upon a previously provisioned DBMS. |
1212

13-
The `azure-postgresql-*` services allow you to provision both a DBMS and a database. When the provision operation is successful, the database will be ready to use. You can not provision additional databases onto an instance provisioned through these two services. The `azure-postgresql-*-dbms` and `azure-postgresql-*-database` services, on the other hand, can be combined to provision multiple databases on a single DBMS. Currently, OSBA supports two versions of Azure Database for PostgreSQL services:
13+
The `azure-postgresql-*` services allow you to provision both a DBMS and a database. When the provision operation is successful, the database will be ready to use. You can not provision additional databases onto an instance of `azure-postgresql-*`. The `azure-postgresql-*-dbms` and `azure-postgresql-*-database` services, on the other hand, can be combined to provision multiple databases on a single DBMS. Currently, OSBA supports two versions of Azure Database for PostgreSQL services:
1414
<table>
1515
<thead>
1616
<tr>
@@ -78,6 +78,10 @@ name.
7878
|----------------|------|-------------|----------|---------------|
7979
| `location` | `string` | The Azure region in which to provision applicable resources. | Y | |
8080
| `resourceGroup` | `string` | The (new or existing) resource group with which to associate new resources. | Y | |
81+
| `serverName` | `string` | Name of the PostgreSQL server. | N | A random generated string. |
82+
| `adminAccountSettings` | `object` | Settings of administrator account of PostgreSQL server. Typically you do not need to specify this. | N | Default admin username is "postgres" and password is a randomly generated string. |
83+
| `adminAccountSettings.adminUsername` | `string` | The administrator username for the server. | N | "postgres" |
84+
| `adminAccountSettings.adminPassword` | `string` | The administrator password for the server. **Warning**: you may leak your password if you specify this property, others can see this password in your request body and `ServiceInstance` definition. DO NOT use this property unless you know what you are doing. | N | A random generated password. |
8185
| `sslEnforcement` | `string` | Specifies whether the server requires the use of TLS when connecting. Valid valued are `""` (unspecified), `enabled`, or `disabled`. | N | `""`. Left unspecified, SSL _will_ be enforced. |
8286
| `firewallRules` | `array` | Specifies the firewall rules to apply to the server. Definition follows. | N | `[]` Left unspecified, Firewall will default to only Azure IPs. If rules are provided, they must have valid values. |
8387
| `firewallRules[n].name` | `string` | Specifies the name of the generated firewall rule |Y | |
@@ -275,6 +279,9 @@ Provisions an Azure Database for PostgreSQL DBMS instance containing no database
275279
|----------------|------|-------------|----------|---------------|
276280
| `location` | `string` | The Azure region in which to provision applicable resources. | Y | |
277281
| `resourceGroup` | `string` | The (new or existing) resource group with which to associate new resources. | Y | |
282+
| `serverName` | `string` | Name of the PostgreSQL server. | N | A random generated string. |
283+
| `adminUsername` | `string` | The administrator username for the server. | N | "postgresql" |
284+
| `adminPassword` | `string` | The administrator password for the server. **Warning**: you may leak your password if you specify this property, others can see this password in your request body and `ServiceInstance` definition. DO NOT use this property unless you know what you are doing. | N | A random generated password. |
278285
| `alias` | `string` | Specifies an alias that can be used by later provision actions to create databases on this DBMS. | Y | |
279286
| `sslEnforcement` | `string` | Specifies whether the server requires the use of TLS when connecting. Valid valued are `""` (unspecified), `enabled`, or `disabled`. | N | `""`. Left unspecified, SSL _will_ be enforced. |
280287
| `firewallRules` | `array` | Specifies the firewall rules to apply to the server. Definition follows. | N | `[]` Left unspecified, Firewall will default to only Azure IPs. If rules are provided, they must have valid values. |

pkg/services/postgresql/all_in_one_arm_template.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ var allInOneARMTemplateBytes = []byte(`
2121
"name": "{{ .serverName }}",
2222
"properties": {
2323
"version": "{{.version}}",
24-
"administratorLogin": "postgres",
24+
"administratorLogin": "{{ .administratorLogin }}",
2525
"administratorLoginPassword": "{{ .administratorLoginPassword }}",
2626
"storageProfile": {
2727
"storageMB": {{.storage}},

pkg/services/postgresql/all_in_one_bind.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ func (a *allInOneManager) Bind(
1111
dt := instance.Details.(*allInOneInstanceDetails)
1212
bd, err := createBinding(
1313
isSSLRequired(*instance.ProvisioningParameters),
14+
dt.AdministratorLogin,
1415
dt.ServerName,
1516
string(dt.AdministratorLoginPassword),
1617
dt.FullyQualifiedDomainName,

pkg/services/postgresql/all_in_one_provision.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66

77
"github.com/Azure/open-service-broker-azure/pkg/generate"
88
"github.com/Azure/open-service-broker-azure/pkg/service"
9-
uuid "github.com/satori/go.uuid"
109
)
1110

1211
func (a *allInOneManager) GetProvisioner(
@@ -22,24 +21,23 @@ func (a *allInOneManager) GetProvisioner(
2221

2322
func (a *allInOneManager) preProvision(
2423
ctx context.Context,
25-
_ service.Instance,
24+
instance service.Instance,
2625
) (service.InstanceDetails, error) {
2726
ctx, cancel := context.WithCancel(ctx)
2827
defer cancel()
29-
serverName, err := getAvailableServerName(
28+
29+
dbmsInstanceDetails, err := generateDBMSInstanceDetails(
3030
ctx,
31+
instance,
3132
a.checkNameAvailabilityClient,
3233
)
3334
if err != nil {
34-
return nil, err
35+
return nil, fmt.Errorf("error generating instance detail: %v", err)
3536
}
37+
3638
return &allInOneInstanceDetails{
37-
dbmsInstanceDetails: dbmsInstanceDetails{
38-
ARMDeploymentName: uuid.NewV4().String(),
39-
ServerName: serverName,
40-
AdministratorLoginPassword: service.SecureString(generate.NewPassword()),
41-
},
42-
DatabaseName: generate.NewIdentifier(),
39+
dbmsInstanceDetails: *dbmsInstanceDetails,
40+
DatabaseName: generate.NewIdentifier(),
4341
}, nil
4442
}
4543

@@ -97,6 +95,7 @@ func (a *allInOneManager) setupDatabase(
9795
dt := instance.Details.(*allInOneInstanceDetails)
9896
err := setupDatabase(
9997
isSSLRequired(*instance.ProvisioningParameters),
98+
dt.AdministratorLogin,
10099
dt.ServerName,
101100
string(dt.AdministratorLoginPassword),
102101
dt.FullyQualifiedDomainName,
@@ -117,6 +116,7 @@ func (a *allInOneManager) createExtensions(
117116
if len(extensions) > 0 {
118117
err := createExtensions(
119118
isSSLRequired(*instance.ProvisioningParameters),
119+
dt.AdministratorLogin,
120120
dt.ServerName,
121121
string(dt.AdministratorLoginPassword),
122122
dt.FullyQualifiedDomainName,

pkg/services/postgresql/all_in_one_unbind.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ func (a *allInOneManager) Unbind(
1212
bd := binding.Details.(*bindingDetails)
1313
return unbind(
1414
isSSLRequired(*instance.ProvisioningParameters),
15+
dt.AdministratorLogin,
1516
dt.ServerName,
1617
string(dt.AdministratorLoginPassword),
1718
dt.FullyQualifiedDomainName,

pkg/services/postgresql/common.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ var dbExtensionsSchema = &service.ArrayPropertySchema{
2121

2222
func getDBConnection(
2323
enforceSSL bool,
24+
administratorLogin string,
2425
serverName string,
2526
administratorLoginPassword string,
2627
fullyQualifiedDomainName string,
@@ -29,12 +30,13 @@ func getDBConnection(
2930
var connectionStrTemplate string
3031
if enforceSSL {
3132
connectionStrTemplate =
32-
"postgres://postgres@%s:%s@%s/%s?sslmode=require"
33+
"postgres://%s@%s:%s@%s/%s?sslmode=require"
3334
} else {
34-
connectionStrTemplate = "postgres://postgres@%s:%s@%s/%s"
35+
connectionStrTemplate = "postgres://%s@%s:%s@%s/%s"
3536
}
3637
db, err := sql.Open("postgres", fmt.Sprintf(
3738
connectionStrTemplate,
39+
administratorLogin,
3840
serverName,
3941
administratorLoginPassword,
4042
fullyQualifiedDomainName,

pkg/services/postgresql/common_bind.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
func createBinding(
1414
enforceSSL bool,
15+
administratorLogin string,
1516
serverName string,
1617
administratorLoginPassword string,
1718
fullyQualifiedDomainName string,
@@ -22,6 +23,7 @@ func createBinding(
2223

2324
db, err := getDBConnection(
2425
enforceSSL,
26+
administratorLogin,
2527
serverName,
2628
administratorLoginPassword,
2729
fullyQualifiedDomainName,

pkg/services/postgresql/common_provision.go

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66

77
postgresSDK "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" // nolint: lll
8+
"github.com/Azure/open-service-broker-azure/pkg/generate"
89
"github.com/Azure/open-service-broker-azure/pkg/service"
910
log "github.com/Sirupsen/logrus"
1011
uuid "github.com/satori/go.uuid"
@@ -21,33 +22,115 @@ func getAvailableServerName(
2122
) (string, error) {
2223
for {
2324
serverName := uuid.NewV4().String()
24-
nameAvailability, err := checkNameAvailabilityClient.Execute(
25+
available, err := isServerNameAvailable(
2526
ctx,
26-
postgresSDK.NameAvailabilityRequest{
27-
Name: &serverName,
28-
},
27+
serverName,
28+
checkNameAvailabilityClient,
2929
)
3030
if err != nil {
3131
return "", fmt.Errorf(
3232
"error determining server name availability: %s",
3333
err,
3434
)
3535
}
36-
if *nameAvailability.NameAvailable {
36+
if available {
3737
return serverName, nil
3838
}
3939
}
4040
}
4141

42+
func isServerNameAvailable(
43+
ctx context.Context,
44+
serverName string,
45+
checkNameAvailabilityClient postgresSDK.CheckNameAvailabilityClient,
46+
) (bool, error) {
47+
nameAvailability, err := checkNameAvailabilityClient.Execute(
48+
ctx,
49+
postgresSDK.NameAvailabilityRequest{
50+
Name: &serverName,
51+
},
52+
)
53+
if err != nil {
54+
return false, err
55+
}
56+
57+
if *nameAvailability.NameAvailable {
58+
return true, nil
59+
}
60+
return false, nil
61+
}
62+
63+
// generateDBMSInstanceDetail will read information
64+
// from instance provision parameters, and generate
65+
// a dbmsInstanceDetail. This method is expected to
66+
// be invoked by preProvision step of all-in-one and
67+
// dbms.
68+
func generateDBMSInstanceDetails(
69+
ctx context.Context,
70+
instance service.Instance,
71+
checkNameAvailabilityClient postgresSDK.CheckNameAvailabilityClient,
72+
) (*dbmsInstanceDetails, error) {
73+
ctx, cancel := context.WithCancel(ctx)
74+
defer cancel()
75+
76+
// Determine server name. If specified,
77+
// check availability; else, generate one.
78+
pp := instance.ProvisioningParameters
79+
serverName := pp.GetString("serverName")
80+
if serverName != "" {
81+
available, err := isServerNameAvailable(
82+
ctx,
83+
serverName,
84+
checkNameAvailabilityClient,
85+
)
86+
if err != nil {
87+
return nil, err
88+
} else if !available {
89+
return nil, fmt.Errorf("server name %s is already in use", serverName)
90+
}
91+
} else {
92+
var err error
93+
serverName, err = getAvailableServerName(
94+
ctx,
95+
checkNameAvailabilityClient,
96+
)
97+
if err != nil {
98+
return nil, err
99+
}
100+
}
101+
102+
// Determine administratorLogin. If specified,
103+
// use it; else, use default value "postgres".
104+
adminAccountSettings := pp.GetObject("adminAccountSettings")
105+
adminUsername := adminAccountSettings.GetString("adminUsername")
106+
if adminUsername == "" {
107+
adminUsername = "postgres"
108+
}
109+
// Determine AdministratorLoginPassword. If specified,
110+
// use it; else, generate one.
111+
adminPassword := adminAccountSettings.GetString("adminPassword")
112+
if adminPassword == "" {
113+
adminPassword = generate.NewPassword()
114+
}
115+
return &dbmsInstanceDetails{
116+
ARMDeploymentName: uuid.NewV4().String(),
117+
ServerName: serverName,
118+
AdministratorLogin: adminUsername,
119+
AdministratorLoginPassword: service.SecureString(adminPassword),
120+
}, nil
121+
}
122+
42123
func setupDatabase(
43124
enforceSSL bool,
125+
administratorLogin string,
44126
serverName string,
45127
administratorLoginPassword string,
46128
fullyQualifiedDomainName string,
47129
dbName string,
48130
) error {
49131
db, err := getDBConnection(
50132
enforceSSL,
133+
administratorLogin,
51134
serverName,
52135
administratorLoginPassword,
53136
fullyQualifiedDomainName,
@@ -74,12 +157,18 @@ func setupDatabase(
74157
); err != nil {
75158
return fmt.Errorf(`error creating role "%s": %s`, dbName, err)
76159
}
160+
// Azure will automatically create a role having name of
161+
// postgreSQL server admin user.
162+
// Here the purpose of granting one role to another role is
163+
// to make admin role to be a member of created db role.
164+
// Please see: https://www.postgresql.org/docs/10/role-membership.html
77165
if _, err = tx.Exec(
78-
fmt.Sprintf("grant %s to postgres", dbName),
166+
fmt.Sprintf("grant %s to %s", dbName, administratorLogin),
79167
); err != nil {
80168
return fmt.Errorf(
81-
`error adding role "%s" to role "postgres": %s`,
169+
`error adding role "%s" to role "%s": %s`,
82170
dbName,
171+
administratorLogin,
83172
err,
84173
)
85174
}
@@ -105,6 +194,7 @@ func setupDatabase(
105194

106195
func createExtensions(
107196
enforceSSL bool,
197+
administratorLogin string,
108198
serverName string,
109199
administratorLoginPassword string,
110200
fullyQualifiedDomainName string,
@@ -113,6 +203,7 @@ func createExtensions(
113203
) error {
114204
db, err := getDBConnection(
115205
enforceSSL,
206+
administratorLogin,
116207
serverName,
117208
administratorLoginPassword,
118209
fullyQualifiedDomainName,
@@ -179,6 +270,7 @@ func buildGoTemplateParameters(
179270
}
180271
p["version"] = version
181272
p["serverName"] = dt.ServerName
273+
p["administratorLogin"] = dt.AdministratorLogin
182274
p["administratorLoginPassword"] = string(dt.AdministratorLoginPassword)
183275
if isSSLRequired(pp) {
184276
p["sslEnforcement"] = enabledARMString

pkg/services/postgresql/common_unbind.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import (
66

77
func unbind(
88
enforceSSL bool,
9+
administratorLogin string,
910
serverName string,
1011
administratorLoginPassword string,
1112
fullyQualifiedDomainName string,
1213
loginName string,
1314
) error {
1415
db, err := getDBConnection(
1516
enforceSSL,
17+
administratorLogin,
1618
serverName,
1719
administratorLoginPassword,
1820
fullyQualifiedDomainName,

pkg/services/postgresql/database_bind.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ func (d *databaseManager) Bind(
1212
dt := instance.Details.(*databaseInstanceDetails)
1313
bd, err := createBinding(
1414
isSSLRequired(*instance.Parent.ProvisioningParameters),
15+
pdt.AdministratorLogin,
1516
pdt.ServerName,
1617
string(pdt.AdministratorLoginPassword),
1718
pdt.FullyQualifiedDomainName,

0 commit comments

Comments
 (0)