From 41e83c0614d600c2ec2e697c32d7f8e32b2f0258 Mon Sep 17 00:00:00 2001 From: gechris <69321460+gechris@users.noreply.github.com> Date: Tue, 13 Oct 2020 17:29:15 -0700 Subject: [PATCH] Add postgresql flexible servers samples (#284) * Simple sample sceleton for mysql & postgresql * Test basic operations * Fixed issue with confusing git mod name between current and forked branch * Fix typo * Fix malformed Example_ test name * Change sample file names. Add README.md files * Properly delete old files, add necessary parameters for server creation * Update README.md files * Refactor FirewallRule call in the clients. Fix invalid name * Update postgresql sample to reflect newest sdk changes * Fix package names for mysql,postgresql flexible server samples * Add PostgreSQL samples * Change user to Azure * Revert some changes in the files * Revert groups.go * Fix module name * Change to Azure-Samples instead of Azure * Randomize the password to pass gosec * Refactor password generator * Fix Build error * Fix README.md, refactor sample * Styling fixes * Some final format refinement * Missed one error to output * Fix example test * Update output of the example Co-authored-by: Dapeng Zhang --- go.sum | 37 +----- postgresql/.env.tpl | 19 +++ postgresql/README.md | 61 +++++++++ postgresql/postgresql_client.go | 166 +++++++++++++++++++++++++ postgresql/postgresql_client_test.go | 177 +++++++++++++++++++++++++++ 5 files changed, 424 insertions(+), 36 deletions(-) create mode 100644 postgresql/.env.tpl create mode 100644 postgresql/README.md create mode 100644 postgresql/postgresql_client.go create mode 100644 postgresql/postgresql_client_test.go diff --git a/go.sum b/go.sum index 3c22bd486..b7618158e 100644 --- a/go.sum +++ b/go.sum @@ -17,56 +17,28 @@ github.com/Azure/azure-sdk-for-go v46.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo github.com/Azure/azure-storage-blob-go v0.0.0-20181023070848-cf01652132cc h1:BElWmFfsryQD72OcovStKpkIcd4e9ozSkdsTNQDSHGk= github.com/Azure/azure-storage-blob-go v0.0.0-20181023070848-cf01652132cc/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= github.com/Azure/go-autorest v11.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v11.1.1+incompatible h1:kqw9PTHZBZKk6kSv/S7L/qxKKcz6hBDnmjWJU5RnHTw= github.com/Azure/go-autorest v11.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v13.3.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= -github.com/Azure/go-autorest/autorest v0.9.4 h1:1cM+NmKw91+8h5vfjgzK4ZGLuN72k87XVZBWyGwNjUM= -github.com/Azure/go-autorest/autorest v0.9.4/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= github.com/Azure/go-autorest/autorest v0.11.9/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest v0.11.10 h1:j5sGbX7uj1ieYYkQ3Mpvewd4DCsEQ+ZeJpqnSM9pjnM= github.com/Azure/go-autorest/autorest v0.11.10/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/adal v0.8.1 h1:pZdL8o72rK+avFWl+p9nE8RWi1JInZrWJYlnpfXJwHk= -github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= -github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwpKNMpV+/FTWjwEbuPD495Tk= -github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= github.com/Azure/go-autorest/autorest/azure/auth v0.5.3 h1:lZifaPRAk1bqg5vGqreL6F8uLC5V0fDpY8nFvc3boFc= github.com/Azure/go-autorest/autorest/azure/auth v0.5.3/go.mod h1:4bJZhUhcq8LB20TruwHbAQsmUs2Xh+QR7utuJpLXX3A= -github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U= -github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 h1:dMOmEJfkLKW/7JsokJqkyoYSgmR08hi9KrhjZb+JALY= github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= -github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.2.0 h1:15vMO4y76dehZSq7pAaOLQxC6dZYsSrj2GQpflyM/L4= -github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= github.com/Azure/go-autorest/autorest/validation v0.3.0 h1:3I9AAI63HfcLtphd9g39ruUwRI+Ca+z/f36KHPFRUss= github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= -github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -82,7 +54,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dimchansky/utfbom v1.0.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= @@ -114,9 +85,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -154,7 +123,6 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/openzipkin/zipkin-go v0.1.6 h1:yXiysv1CSK7Q5yjGy1710zZGnsbMUIjluWBxtLXHPBo= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -191,10 +159,7 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= diff --git a/postgresql/.env.tpl b/postgresql/.env.tpl new file mode 100644 index 000000000..1fd71e544 --- /dev/null +++ b/postgresql/.env.tpl @@ -0,0 +1,19 @@ +AZURE_BASE_GROUP_NAME=az-samples-go +AZURE_LOCATION_DEFAULT=westus2 +AZURE_SAMPLES_KEEP_RESOURCES=0 + +# create with: +# `az ad sp create-for-rbac --name 'my-sp' --output json` +# sp must have Contributor role on subscription +AZURE_TENANT_ID= +AZURE_CLIENT_ID= +AZURE_CLIENT_SECRET= +AZURE_SUBSCRIPTION_ID= + +# create with: +# `az ad sp create-for-rbac --name 'my-sp' --sdk-auth > $HOME/.azure/sdk_auth.json` +# sp must have Contributor role on subscription +AZURE_AUTH_LOCATION=$HOME/.azure/sdk_auth.json + +AZURE_STORAGE_ACCOUNT_NAME= +AZURE_STORAGE_ACCOUNT_GROUP_NAME= diff --git a/postgresql/README.md b/postgresql/README.md new file mode 100644 index 000000000..87a83edfc --- /dev/null +++ b/postgresql/README.md @@ -0,0 +1,61 @@ +--- +services: postgresql +platforms: go +author: gechris +--- + +# Azure PostgreSQL Samples + +This package demonstrates how to manage PostgreSQL flexible servers with the Go SDK. + +## Contents + +* [How to run all samples](#run) +* Management + * CreateServer - Create a PostgreSQL. + * UpdateServer - Updates a PostgreSQL server. + * DeleteServer - Deletes an existing PostgreSQL server. + * CreateOrUpdateFirewallRules - Creates or updates a firewall rule on the server. + * GetConfiguration - Get the configuration value that is set on the server. + * UpdateConfiguration - Updates the configuration. + + + +## How to run all samples + +1. Get this package and all dependencies. + + ```bash + export PROJECT=github.com/Azure-Samples/azure-sdk-for-go-samples/postgresql + go get -u $PROJECT + cd ${GOPATH}/src/${PROJECT} + ``` +2. Create an Azure service principal with the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/get-started-with-azure-cli) command `az ad sp create-for-rbac --output json` and set the following environment variables per that command's output. You can also copy `.env.tpl` to `.env` and fill it in; the configuration system will utilize this. + + ```bash + AZURE_CLIENT_ID= + AZURE_CLIENT_SECRET= + AZURE_TENANT_ID= + AZURE_SUBSCRIPTION_ID= + AZURE_BASE_GROUP_NAME= + AZURE_LOCATION_DEFAULT=westus2 + ``` + +3. Run the tests: `go test -v -timeout 12h` + + The timeout is optional, but some tests take longer than then default 10m to complete. + + +## More information + +Please refer to [Azure SDK for Go](https://github.com/Azure/azure-sdk-for-go) +for more information. + +--- + +This project has adopted the [Microsoft Open Source Code of +Conduct](https://opensource.microsoft.com/codeofconduct/). For more information +see the [Code of Conduct +FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact +[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional +questions or comments. \ No newline at end of file diff --git a/postgresql/postgresql_client.go b/postgresql/postgresql_client.go new file mode 100644 index 000000000..b64df14ad --- /dev/null +++ b/postgresql/postgresql_client.go @@ -0,0 +1,166 @@ +package postgresql + +import ( + "context" + "fmt" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/iam" + flexibleservers "github.com/Azure/azure-sdk-for-go/services/preview/postgresql/mgmt/2020-02-14-preview/postgresqlflexibleservers" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/to" +) + +// GetServersClient returns +func getServersClient() flexibleservers.ServersClient { + serversClient := flexibleservers.NewServersClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + serversClient.Authorizer = a + serversClient.AddToUserAgent(config.UserAgent()) + return serversClient +} + +// CreateServer creates a new PostgreSQL Server +func CreateServer(ctx context.Context, resourceGroup, serverName, dbLogin, dbPassword string) (server flexibleservers.Server, err error) { + serversClient := getServersClient() + + // Create the server + future, err := serversClient.Create( + ctx, + resourceGroup, + serverName, + flexibleservers.Server{ + Location: to.StringPtr(config.Location()), + Sku: &flexibleservers.Sku{ + Name: to.StringPtr("Standard_D4s_v3"), + Tier: "GeneralPurpose", + }, + ServerProperties: &flexibleservers.ServerProperties{ + AdministratorLogin: to.StringPtr(dbLogin), + AdministratorLoginPassword: to.StringPtr(dbPassword), + Version: flexibleservers.OneTwo, + StorageProfile: &flexibleservers.StorageProfile{ + StorageMB: to.Int32Ptr(524288), + }, + }, + }) + + if err != nil { + return server, fmt.Errorf("cannot create pg server: %+v", err) + } + + if err := future.WaitForCompletionRef(ctx, serversClient.Client); err != nil { + return server, fmt.Errorf("cannot get the pg server create or update future response: %+v", err) + } + + return future.Result(serversClient) +} + +// UpdateServerStorageCapacity given the server name and the new storage capacity it updates the server's storage capacity. +func UpdateServerStorageCapacity(ctx context.Context, resourceGroup, serverName string, storageCapacity int32) (server flexibleservers.Server, err error) { + serversClient := getServersClient() + + future, err := serversClient.Update( + ctx, + resourceGroup, + serverName, + flexibleservers.ServerForUpdate{ + ServerPropertiesForUpdate: &flexibleservers.ServerPropertiesForUpdate{ + StorageProfile: &flexibleservers.StorageProfile{ + StorageMB: &storageCapacity, + }, + }, + }, + ) + if err != nil { + return server, fmt.Errorf("cannot update pg server: %+v", err) + } + + if err := future.WaitForCompletionRef(ctx, serversClient.Client); err != nil { + return server, fmt.Errorf("cannot get the pg server update future response: %+v", err) + } + + return future.Result(serversClient) +} + +// DeleteServer deletes the PostgreSQL server. +func DeleteServer(ctx context.Context, resourceGroup, serverName string) (resp autorest.Response, err error) { + serversClient := getServersClient() + + future, err := serversClient.Delete(ctx, resourceGroup, serverName) + if err != nil { + return resp, fmt.Errorf("cannot delete the pg server: %+v", err) + } + + if err := future.WaitForCompletionRef(ctx, serversClient.Client); err != nil { + return resp, fmt.Errorf("cannot get the pg server update future response: %+v", err) + } + + return future.Result(serversClient) +} + +// GetFwRulesClient returns the FirewallClient +func getFwRulesClient() flexibleservers.FirewallRulesClient { + fwrClient := flexibleservers.NewFirewallRulesClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + fwrClient.Authorizer = a + fwrClient.AddToUserAgent(config.UserAgent()) + return fwrClient +} + +// CreateOrUpdateFirewallRule given the firewallname and new properties it updates the firewall rule. +func CreateOrUpdateFirewallRule(ctx context.Context, resourceGroup, serverName, firewallRuleName, startIPAddr, endIPAddr string) (rule flexibleservers.FirewallRule, err error) { + fwrClient := getFwRulesClient() + + future, err := fwrClient.CreateOrUpdate( + ctx, + resourceGroup, + serverName, + firewallRuleName, + flexibleservers.FirewallRule{ + FirewallRuleProperties: &flexibleservers.FirewallRuleProperties{ + StartIPAddress: &startIPAddr, + EndIPAddress: &endIPAddr, + }, + }, + ) + if err != nil { + return rule, fmt.Errorf("cannot create the firewall rule: %+v", err) + } + if err := future.WaitForCompletionRef(ctx, fwrClient.Client); err != nil { + return rule, fmt.Errorf("cannot get the firewall rule create or update future response: %+v", err) + } + + return future.Result(fwrClient) +} + +// GetConfigurationsClient creates and returns the configuration client for the server. +func getConfigurationsClient() flexibleservers.ConfigurationsClient { + configClient := flexibleservers.NewConfigurationsClient(config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + configClient.Authorizer = a + configClient.AddToUserAgent(config.UserAgent()) + return configClient +} + +// GetConfiguration given the server name and configuration name it returns the configuration. +func GetConfiguration(ctx context.Context, resourceGroup, serverName, configurationName string) (flexibleservers.Configuration, error) { + configClient := getConfigurationsClient() + return configClient.Get(ctx, resourceGroup, serverName, configurationName) +} + +// UpdateConfiguration given the name of the configuation and the configuration object it updates the configuration for the given server. +func UpdateConfiguration(ctx context.Context, resourceGroup, serverName string, configurationName string, configuration flexibleservers.Configuration) (updatedConfig flexibleservers.Configuration, err error) { + configClient := getConfigurationsClient() + + future, err := configClient.Update(ctx, resourceGroup, serverName, configurationName, configuration) + if err != nil { + return updatedConfig, fmt.Errorf("cannot update the configuration with name %s: %+v", configurationName, err) + } + + if err := future.WaitForCompletionRef(ctx, configClient.Client); err != nil { + return updatedConfig, fmt.Errorf("cannot get the pg configuration update future response: %+v", err) + } + + return future.Result(configClient) +} diff --git a/postgresql/postgresql_client_test.go b/postgresql/postgresql_client_test.go new file mode 100644 index 000000000..b667e4a1d --- /dev/null +++ b/postgresql/postgresql_client_test.go @@ -0,0 +1,177 @@ +package postgresql + +import ( + "context" + "flag" + "fmt" + "log" + "os" + "strings" + "testing" + + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/config" + "github.com/Azure-Samples/azure-sdk-for-go-samples/internal/util" + "github.com/Azure-Samples/azure-sdk-for-go-samples/resources" + flexibleservers "github.com/Azure/azure-sdk-for-go/services/preview/postgresql/mgmt/2020-02-14-preview/postgresqlflexibleservers" + "github.com/Azure/go-autorest/autorest/to" + "github.com/marstr/randname" +) + +var ( + groupName = config.GenerateGroupName("PgServerOperations") + serverName = generateName("gosdkpostgresql") + dbName = "postgresqldb1" + dbLogin = "postgresqldbuser1" + dbPassword = generatePassword("postgresqldbuserpass!1") +) + +func addLocalEnvAndParse() error { + // parse env at top-level (also controls dotenv load) + err := config.ParseEnvironment() + if err != nil { + return fmt.Errorf("failed to add top-level env: %+v", err) + } + return nil +} + +func addLocalFlagsAndParse() error { + // add top-level flags + err := config.AddFlags() + if err != nil { + return fmt.Errorf("failed to add top-level flags: %+v", err) + } + + flag.StringVar(&serverName, "pgsqlServerName", serverName, "Name for PostgreSQL server.") + flag.StringVar(&dbName, "pgsqlDbName", dbName, "Name for PostgreSQL database.") + flag.StringVar(&dbLogin, "pgsqlDbUsername", dbLogin, "Username for PostgreSQL login.") + flag.StringVar(&dbPassword, "pgsqlDbPassword", dbPassword, "Password for PostgreSQL login.") + + // parse all flags + flag.Parse() + return nil +} + +func setup() error { + var err error + err = addLocalEnvAndParse() + if err != nil { + return err + } + err = addLocalFlagsAndParse() + if err != nil { + return err + } + + return nil +} + +func teardown() error { + if !config.KeepResources() { + // does not wait + _, err := resources.DeleteGroup(context.Background(), groupName) + if err != nil { + return err + } + } + return nil +} + +// test helpers +func generateName(prefix string) string { + return strings.ToLower(randname.GenerateWithPrefix(prefix, 5)) +} + +// Just add 5 random digits at the end of the prefix password. +func generatePassword(pass string) string { + return randname.GenerateWithPrefix(pass, 5) +} + +// TestMain sets up the environment and initiates tests. +func TestMain(m *testing.M) { + var err error + var code int + + err = setup() + if err != nil { + log.Fatalf("could not set up environment: %+v", err) + } + + code = m.Run() + + err = teardown() + if err != nil { + log.Fatalf( + "could not tear down environment: %v\n; original exit code: %v\n", + err, code) + } + + os.Exit(code) +} + +// Example_performServerOperations creates a postgresql server, updates it, add firewall rules and configurations and at the end it deletes it. +func Example_performServerOperations() { + serverName = strings.ToLower(serverName) + + ctx := context.Background() + defer resources.Cleanup(ctx) + + if _, err := resources.CreateGroup(ctx, groupName); err != nil { + util.LogAndPanic(err) + } + util.PrintAndLog("resource group created") + + // Create the server. + if _, err := CreateServer(ctx, groupName, serverName, dbLogin, dbPassword); err != nil { + util.LogAndPanic(fmt.Errorf("cannot create postgresql server: %+v", err)) + } + util.PrintAndLog("postgresql server created") + + // Update the server's storage capacity field. + if _, err := UpdateServerStorageCapacity(ctx, groupName, serverName, 1048576); err != nil { + util.LogAndPanic(fmt.Errorf("cannot update postgresql server: %+v", err)) + } + util.PrintAndLog("postgresql server's storage capacity updated") + + if _, err := CreateOrUpdateFirewallRule(ctx, groupName, serverName, "FirewallRuleName", "0.0.0.0", "0.0.0.0"); err != nil { + util.LogAndPanic(err) + } + util.PrintAndLog("firewall rule set created") + + if _, err := CreateOrUpdateFirewallRule(ctx, groupName, serverName, "FirewallRuleName", "0.0.0.0", "1.1.1.1"); err != nil { + util.LogAndPanic(err) + } + util.PrintAndLog("firewall rule updated") + + var configuration flexibleservers.Configuration + + configuration, err := GetConfiguration(ctx, groupName, serverName, "max_replication_slots") + if err != nil { + util.LogAndPanic(err) + } + util.PrintAndLog("got the max_replication_slots configuration") + + // Update the configuration Value. + configuration.ConfigurationProperties.Value = to.StringPtr("20") + configuration.ConfigurationProperties.Source = to.StringPtr("user-override") + + if _, err := UpdateConfiguration(ctx, groupName, serverName, "max_replication_slots", configuration); err != nil { + util.LogAndPanic(err) + } + util.PrintAndLog("max_replication_slots configuration updated") + + // Finally delete the server. + if _, err := DeleteServer(ctx, groupName, serverName); err != nil { + util.LogAndPanic(err) + } + util.PrintAndLog("postgresql server deleted") + + // Output: + // resource group created + // postgresql server created + // postgresql server's storage capacity updated + // firewall rule set created + // firewall rule updated + // got the max_replication_slots configuration + // max_replication_slots configuration updated + // postgresql server deleted +}