* Adding "db-name" parameter, and renaming "database" to "db-type" (#65)

This is done in part to match Buffalo's parameter naming.

* Cache parameters (#67)

* Writing Template and parameters to disk

* Opportunistically skipping template cache

* allowing for skipping the deployment phase

* Automatically generate random dbAdmin password

* WIP populating from file

* More WIP

* Fixes #66

* Fixing CI reported issues

* Polishing defaults

* Fixing seg-fault

* Adding missing DB-Admin default setting
This commit is contained in:
Martin Strobel 2018-06-27 16:40:41 -07:00 коммит произвёл GitHub
Родитель 22ad6c2c23
Коммит 578d16f4ec
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 417 добавлений и 83 удалений

98
cmd/deployment_test.go Normal file
Просмотреть файл

@ -0,0 +1,98 @@
package cmd
import (
"bytes"
"encoding/json"
"os"
"testing"
)
func TestDeploymentParameters_UnmarshalFile(t *testing.T) {
handle, err := os.Open("./testdata/parameters1.json")
if err != nil {
t.Error(err)
return
}
defer handle.Close()
subject := NewDeploymentParameters()
dec := json.NewDecoder(handle)
dec.Decode(subject)
if got, want := len(subject.Parameters), 5; got != want {
t.Logf("Number Parameters:\n\tgot: %d want: %d", got, want)
t.Fail()
}
expected := map[string]string{
"database": "postgresql",
"databaseAdministratorLogin": "buffaloAdmin",
"databaseName": "buffalo30_development",
"imageName": "marstr/quickstart:latest",
"name": "buffalo-app-uqqq1nfno1",
}
for k, v := range expected {
if val, ok := subject.Parameters[k]; ok {
if v != val.Value.(string) {
t.Logf("got: %q want: %q", val, v)
t.Fail()
}
} else {
t.Logf("didn't find expected parameter %q", k)
t.Fail()
}
}
}
func TestDeploymentParameters_MarshalRoundTrip(t *testing.T) {
subject := NewDeploymentParameters()
subject.Parameters["foo"] = DeploymentParameter{"bar"}
subject.Parameters["bar"] = DeploymentParameter{2}
buf := bytes.NewBuffer([]byte{})
enc := json.NewEncoder(buf)
if err := enc.Encode(subject); err != nil {
t.Error(err)
return
}
rehydrated := NewDeploymentParameters()
dec := json.NewDecoder(buf)
if err := dec.Decode(rehydrated); err != nil {
t.Error(err)
return
}
if rehydrated.ContentVersion != subject.ContentVersion {
t.Logf("Unexpected Content Version:\n\tgot: %q\n\twant: %q", rehydrated.ContentVersion, subject.ContentVersion)
t.Fail()
}
if rehydrated.Schema != subject.Schema {
t.Logf("Unexpected Content Version:\n\tgot: %q\n\twant: %q", rehydrated.Schema, subject.Schema)
t.Fail()
}
if len(rehydrated.Parameters) != len(subject.Parameters) {
t.Logf("parameter count:\n\tgot: %d want: %d", len(rehydrated.Parameters), len(subject.Parameters))
t.Fail()
}
for k, v := range rehydrated.Parameters {
if orig, ok := subject.Parameters[k]; ok {
t.Logf("Found %q -> %v : %v", k, orig, v)
delete(subject.Parameters, k)
} else {
t.Logf("unexpected parameter: %q included with value: %v", k, v)
t.Fail()
}
}
for k := range subject.Parameters {
t.Logf("Missing parameter: %q", k)
t.Fail()
}
}

Просмотреть файл

@ -53,6 +53,8 @@ const deviceClientID = "04b07795-8ddb-461a-bbee-02f9e1bf7b46"
var provisionConfig = viper.New()
var userAgent string
// These constants define a parameter which allows control of the name of the site that is to be created.
const (
SiteName = "site-name"
@ -74,10 +76,11 @@ const (
// These constants define a parameter which allows control over the Azure Region that should be used when creating a
// resource group. If the specified resource group already exists, its location is used and this parameter is discarded.
const (
LocationName = "location"
LocationShorthand = "l"
LocationDefault = "centralus"
locationUsage = "The Azure Region that should be used when creating a resource group."
LocationName = "location"
LocationShorthand = "l"
LocationDefault = "centralus"
LocationDefaultText = "<resource group location>, or " + LocationDefault
locationUsage = "The Azure Region that should be used when creating a resource group."
)
// These constants define a parameter that allows control of the type of database to be provisioned. This is largely an
@ -89,11 +92,35 @@ const (
// - Postgresql
// - MySQL
const (
DatabaseName = "database"
DatabaseTypeName = "db-type"
DatabaseShorthand = "d"
databaseUsage = "The type of database to provision."
)
// These constants define a parameter which gives control of the name of the database to be connected to by the
// Buffalo application.
const (
DatabaseNameName = "db-name"
databaseNameUsage = "The name of the database to be connected to by the Buffalo application once its deployed."
)
// These constants defeine a parameter which controls the password of the
const (
DatabaseAdminName = "db-admin"
DatabaseAdminDefault = "buffaloAdmin"
databaseAdminUsage = "The user handle of the administratr account "
)
// These constants define a parameter which controls the password of the database provisioned. For marginal security,
// it is randomly generated each time `buffalo azure provision` is run. It will be visibile in the "connection strings"
// of your App Service.
const (
DatabasePasswordName = "db-password"
DatabasePasswordShorthand = "w"
DatabasePasswordDefault = "<randomly generated>"
databasePasswordUsage = "The administrator password for the database created. It is recommended you read this from a file instead of typing it in from your terminal."
)
// These constants define a parameter which allows control over the particular Azure cloud which should be used for
// deployment.
// Some examples of Azure environments by name include:
@ -102,8 +129,8 @@ const (
// - AzureGermanCloud
// - AzureUSGovernmentCloud
const (
EnvironmentName = "environment"
EnvironmentShorthand = "e"
EnvironmentName = "az-env"
EnvironmentShorthand = "a"
EnvironmentDefault = "AzurePublicCloud"
environmentUsage = "The Azure environment that will be targeted for deployment."
)
@ -152,20 +179,29 @@ const (
templateUsage = "The Azure Resource Management template which specifies the resources to provision."
)
// These constants define a parameter which allows control of the ARM template parameters that should be used during
// deployment.
const (
TemplateParametersName = "rm-template-params"
TemplateParametersShorthand = "p"
TemplateParametersDefault = "./azuredeploy.parameters.json"
templateParametersUsage = "The parameters that should be provided when creating a deployment."
)
// These constants define a parameter that Azure subscription to own the resources created.
//
// This can also be specified with the environment variable AZURE_SUBSCRIPTION_ID or AZ_SUBSCRIPTION_ID.
const (
SubscriptionName = "subscription"
SubscriptionName = "subscription-id"
SubscriptionShorthand = "s"
subscriptionUsage = "The ID (in UUID format) of the Azure subscription which should host the provisioned resources."
)
// These constants define a parameter which will control the profile being used for the sake of connections.
const (
ProfileName = "profile"
ProfileShorthand = "p"
profileUsage = ""
ProfileName = "buffalo-env"
ProfileShorthand = "b"
profileUsage = "The buffalo environment that should be used."
)
// These constants define a parameter which allows specification of a Service Principal for authentication.
@ -217,24 +253,42 @@ const (
verboseUsage = "Print out status information as this program executes."
)
// These constants define a parameter which toggles whether or not to save the template used for deployment to disk.
const (
SkipTemplateCacheName = "skip-template-cache"
skipTemplateCacheUsage = "After downloading the default template, do NOT save it in the working directory."
)
// These constants define a parameter which toggles whether or not to save the parameters used for deployment to disk.
const (
SkipParameterCacheName = "skip-parameters-cache"
SkipParameterCacheShorthand = "y"
skipParameterCacheUsage = "After creating deploying the site, do NOT save the parameters that were used for deployment."
)
// These constants define a parameter which toggles whether or not a deployment is actually started.
const (
SkipDeploymentName = "skip-deployment"
SkipDeploymentShorthand = "x"
skipDeploymentUsage = "Do not create an Azure deployment, do just the meta tasks."
)
var status *log.Logger
var errLog = newFormattedLog(os.Stderr, "error")
var debugLog *log.Logger
var debug string
var deployParams *DeploymentParameters
// provisionCmd represents the provision command
var provisionCmd = &cobra.Command{
Aliases: []string{"p"},
Use: "provision",
Short: "Create the infrastructure necessary to run a buffalo app on Azure.",
Run: func(cmd *cobra.Command, args []string) {
exitStatus := 1
defer func() {
os.Exit(exitStatus)
}()
debugLog.Print("debugging enabled")
debugLog.Printf("User Agent built as: %q", userAgent)
// Authenticate and setup clients
subscriptionID := provisionConfig.GetString(SubscriptionName)
@ -242,7 +296,9 @@ var provisionCmd = &cobra.Command{
clientSecret := provisionConfig.GetString(ClientSecretName)
templateLocation := provisionConfig.GetString(TemplateName)
image := provisionConfig.GetString(ImageName)
databaseType := provisionConfig.GetString(DatabaseName)
databaseType := provisionConfig.GetString(DatabaseTypeName)
databaseName := provisionConfig.GetString(DatabaseNameName)
databaseAdmin := provisionConfig.GetString(DatabaseAdminName)
siteName := provisionConfig.GetString(SiteName)
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Minute)
@ -253,20 +309,25 @@ var provisionCmd = &cobra.Command{
errLog.Print("unable to authenticate: ", err)
return
}
status.Print("tenant selected: ", provisionConfig.GetString(TenantIDName))
status.Print("subscription selected: ", subscriptionID)
status.Println("template selected: ", templateLocation)
status.Println("database selected: ", databaseType)
status.Println("image selected: ", image)
status.Print(TenantIDName+" selected: ", provisionConfig.GetString(TenantIDName))
status.Print(SubscriptionName+" selected: ", subscriptionID)
status.Println(TemplateName+" selected: ", templateLocation)
status.Println(DatabaseTypeName+" selected: ", databaseType)
status.Println(DatabaseNameName+" selected: ", databaseName)
status.Println(DatabaseAdminName+" selected: ", databaseAdmin)
if usingDB, dbPassword := !strings.EqualFold(provisionConfig.GetString(DatabaseTypeName), "none"), provisionConfig.GetString(DatabasePasswordName); usingDB && dbPassword == DatabasePasswordDefault {
provisionConfig.Set(DatabasePasswordName, randname.GenerateWithPrefix("MSFT+Buffalo-", 20))
status.Println("generated database password")
} else if usingDB {
status.Println("using provided password")
}
status.Println(ImageName+" selected: ", image)
groups := resources.NewGroupsClient(subscriptionID)
groups.Authorizer = auth
userAgentBuilder := bytes.NewBufferString("buffalo-azure")
if version != "" {
userAgentBuilder.WriteRune('/')
userAgentBuilder.WriteString(version)
}
groups.AddToUserAgent(userAgentBuilder.String())
groups.AddToUserAgent(userAgent)
// Assert the presence of the specified Resource Group
rgName := provisionConfig.GetString(ResoureGroupName)
@ -282,17 +343,16 @@ var provisionCmd = &cobra.Command{
}
status.Println("site name selected: ", siteName)
// Provision the necessary assets.
deployments := resources.NewDeploymentsClient(subscriptionID)
deployments.Authorizer = auth
deployments.AddToUserAgent(userAgentBuilder.String())
pLink := portalLink(subscriptionID, rgName)
params := NewDeploymentParameters()
params.Parameters["name"] = DeploymentParameter{siteName}
params.Parameters["database"] = DeploymentParameter{strings.ToLower(databaseType)}
params.Parameters["imageName"] = DeploymentParameter{image}
params.Parameters["databaseAdministratorLogin"] = DeploymentParameter{"buffaloAdmin"}
params.Parameters["databaseAdministratorLoginPassword"] = DeploymentParameter{"M$FT<3sBuffalo"}
// Provision the necessary assets.
deployParams.Parameters["name"] = DeploymentParameter{siteName}
deployParams.Parameters["database"] = DeploymentParameter{strings.ToLower(databaseType)}
deployParams.Parameters["databaseName"] = DeploymentParameter{databaseName}
deployParams.Parameters["imageName"] = DeploymentParameter{image}
deployParams.Parameters["databaseAdministratorLogin"] = DeploymentParameter{databaseAdmin}
deployParams.Parameters["databaseAdministratorLoginPassword"] = DeploymentParameter{provisionConfig.GetString(DatabasePasswordName)}
template, err := getDeploymentTemplate(ctx, templateLocation)
if err != nil {
@ -300,36 +360,65 @@ var provisionCmd = &cobra.Command{
return
}
template.Parameters = params.Parameters
template.Parameters = deployParams.Parameters
template.Mode = resources.Incremental
status.Println("beginning deployment")
fut, err := deployments.CreateOrUpdate(ctx, rgName, siteDefaultPrefix, resources.Deployment{
Properties: template,
})
if err != nil {
errLog.Print("unable to start deployment: ", err)
return
deploymentResults := make(chan error)
if provisionConfig.GetBool(SkipDeploymentName) {
close(deploymentResults)
} else {
go func(errOut chan<- error) {
defer close(errOut)
status.Println("beginning deployment")
if err := doDeployment(ctx, auth, subscriptionID, rgName, template); err == nil {
fmt.Println("Check on your new Resource Group in the Azure Portal: ", pLink)
fmt.Printf("Your site will be available shortly at: https://%s.azurewebsites.net\n", siteName)
} else {
errLog.Printf("unable to poll for completion progress, your assets may or may not have finished provisioning.\nCheck on their status in the portal: %s\nError: %v\n", pLink, err)
errOut <- err
return
}
status.Print("finished deployment")
}(deploymentResults)
}
portalLink := bytes.NewBufferString("https://portal.azure.com/#resource/subscriptions/")
portalLink.WriteString(subscriptionID)
portalLink.WriteString("/resourceGroups/")
portalLink.WriteString(rgName)
portalLink.WriteString("/overview")
err = fut.WaitForCompletion(ctx, deployments.Client)
if err != nil {
errLog.Printf("unable to poll for completion progress, your assets may or may not have finished provisioning.\nCheck on their status in the portal: %s\n", portalLink.String())
return
doCache := func(ctx context.Context, errOut chan<- error, contents interface{}, location, flavor string) {
defer close(errOut)
status.Printf("caching %s", flavor)
err := cache(ctx, contents, location)
if err != nil {
errLog.Printf("unable to cache file %s because: %v", location, err)
errOut <- err
return
}
status.Printf("%s cached", flavor)
}
fmt.Println("Check on your new Resource Group in the Azure Portal: ", portalLink.String())
fmt.Printf("Your site will be available shortly at: https://%s.azurewebsites.net\n", siteName)
templateSaveResults, parameterSaveResults := make(chan error), make(chan error)
if provisionConfig.GetBool(SkipTemplateCacheName) {
close(templateSaveResults)
} else {
go doCache(ctx, templateSaveResults, template.Template, TemplateDefault, "template")
}
status.Print("finished deployment")
exitStatus = 0
if provisionConfig.GetBool(SkipParameterCacheName) {
close(parameterSaveResults)
} else {
go doCache(ctx, parameterSaveResults, stripDBPassword(deployParams), TemplateParametersDefault, "parameters")
}
waitOnResults := func(ctx context.Context, results <-chan error) error {
select {
case <-ctx.Done():
return ctx.Err()
case err := <-results:
return err
}
}
waitOnResults(ctx, templateSaveResults)
waitOnResults(ctx, parameterSaveResults)
waitOnResults(ctx, deploymentResults)
},
Args: func(cmd *cobra.Command, args []string) error {
if provisionConfig.GetString(SubscriptionName) == "" {
@ -345,6 +434,29 @@ var provisionCmd = &cobra.Command{
return errors.New("--client-id and --client-secret must be specified together or not at all")
}
statusWriter := ioutil.Discard
if provisionConfig.GetBool(VerboseName) {
statusWriter = os.Stdout
}
status = newFormattedLog(statusWriter, "information")
if provisionConfig.GetString(TemplateName) == TemplateDefault {
provisionConfig.Set(SkipTemplateCacheName, true)
}
if provisionConfig.GetString(LocationName) == LocationDefaultText {
provisionConfig.SetDefault(LocationName, LocationDefault)
}
paramFile := provisionConfig.GetString(TemplateParametersName)
p, err := loadFromParameterFile(paramFile)
if err == nil {
setDefaults(provisionConfig, p)
deployParams = p
} else if paramFile != TemplateParametersDefault {
return fmt.Errorf("unable to load parameters file: %v", err)
}
nameGenerator := randname.Prefixed{
Prefix: siteDefaultPrefix + "-",
Len: 10,
@ -359,22 +471,47 @@ var provisionCmd = &cobra.Command{
provisionConfig.Set(ResoureGroupName, provisionConfig.GetString(SiteName))
}
var err error
environment, err = azure.EnvironmentFromName(provisionConfig.GetString(EnvironmentName))
if err != nil {
return err
}
statusWriter := ioutil.Discard
if provisionConfig.GetBool(VerboseName) {
statusWriter = os.Stdout
}
status = newFormattedLog(statusWriter, "information")
return nil
},
}
func stripDBPassword(original *DeploymentParameters) (copy *DeploymentParameters) {
copy = NewDeploymentParameters()
copy.Parameters = make(map[string]DeploymentParameter, len(original.Parameters))
copy.ContentVersion = original.ContentVersion
copy.Schema = original.Schema
for k, v := range original.Parameters {
copy.Parameters[k] = v
}
delete(copy.Parameters, "databaseAdministratorLoginPassword")
return copy
}
func cache(ctx context.Context, contents interface{}, outputName string) error {
if handle, err := os.Create(outputName); err == nil {
defer handle.Close()
enc := json.NewEncoder(handle)
err = enc.Encode(contents)
if err != nil {
return err
}
} else {
return err
}
return nil
}
func portalLink(subscriptionID, rgName string) string {
return fmt.Sprintf("https://portal.azure.com/#resource/subscriptions/%s/resourceGroups/%s/overview", subscriptionID, rgName)
}
// insertResourceGroup checks for a Resource Groups's existence, if it is not found it creates that resource group. If
// that resource group exists, it leaves it alone.
func insertResourceGroup(ctx context.Context, groups resources.GroupsClient, name string, location string) (bool, error) {
@ -466,18 +603,32 @@ func getAuthorizer(ctx context.Context, subscriptionID, clientID, clientSecret,
return autorest.NewBearerAuthorizer(auth), nil
}
func getDatabaseFlavor(buffaloRoot, profile string) (string, error) {
func getDatabaseFlavor(buffaloRoot, profile string) (string, string, error) {
app := meta.New(buffaloRoot)
if !app.WithPop {
return "none", nil
return "none", "", nil
}
conn, err := pop.Connect(profile)
if err != nil {
return "", err
return "", "", err
}
return conn.Dialect.Name(), nil
return conn.Dialect.Name(), conn.Dialect.Details().Database, nil
}
func doDeployment(ctx context.Context, authorizer autorest.Authorizer, subscriptionID, resourceGroup string, properties *resources.DeploymentProperties) (err error) {
deployments := resources.NewDeploymentsClient(subscriptionID)
deployments.Authorizer = authorizer
deployments.AddToUserAgent(userAgent)
fut, err := deployments.CreateOrUpdate(ctx, resourceGroup, siteDefaultPrefix, resources.Deployment{Properties: properties})
if err != nil {
return
}
err = fut.WaitForCompletion(ctx, deployments.Client)
return
}
func getDeploymentTemplate(ctx context.Context, raw string) (*resources.DeploymentProperties, error) {
@ -653,6 +804,45 @@ func newFormattedLog(output io.Writer, identifier string) *log.Logger {
return log.New(output, fmt.Sprintf("[%s] ", strings.ToUpper(identifier)[:identLen]), log.Ldate|log.Ltime)
}
func setDefaults(conf *viper.Viper, params *DeploymentParameters) {
if name, ok := params.Parameters["name"]; ok {
conf.SetDefault(SiteName, name.Value)
}
if database, ok := params.Parameters["database"]; ok {
conf.SetDefault(DatabaseTypeName, database.Value)
}
if databaseName, ok := params.Parameters["databaseName"]; ok {
conf.SetDefault(DatabaseNameName, databaseName.Value)
}
if image, ok := params.Parameters["imageName"]; ok {
conf.SetDefault(ImageName, image.Value)
}
if dbAdmin, ok := params.Parameters["databaseAdministratorLogin"]; ok {
conf.SetDefault(DatabaseAdminName, dbAdmin.Value)
}
}
func loadFromParameterFile(paramFile string) (*DeploymentParameters, error) {
loaded := NewDeploymentParameters()
if _, err := os.Stat(TemplateParametersDefault); err == nil {
provisionConfig.SetDefault(TemplateParametersName, TemplateParametersDefault)
if handle, err := os.Open(provisionConfig.GetString(TemplateParametersName)); err == nil {
dec := json.NewDecoder(handle)
err = dec.Decode(loaded)
if err != nil {
return nil, err
}
}
} else {
return nil, err
}
return loaded, nil
}
func init() {
var debugWriter io.Writer
if debug == "" {
@ -683,6 +873,22 @@ func init() {
provisionConfig.SetDefault(ProfileName, "development")
if dialect, dbname, err := getDatabaseFlavor(".", provisionConfig.GetString(ProfileName)); err == nil {
provisionConfig.SetDefault(DatabaseTypeName, dialect)
provisionConfig.SetDefault(DatabaseNameName, dbname)
} else {
provisionConfig.SetDefault(DatabaseTypeName, "none")
debugLog.Print("unable to parse buffalo app for db dialect: ", err)
}
provisionConfig.SetDefault(DatabaseAdminName, DatabaseAdminDefault)
provisionConfig.SetDefault(ImageName, ImageDefault)
provisionConfig.SetDefault(EnvironmentName, EnvironmentDefault)
provisionConfig.SetDefault(ResoureGroupName, ResourceGroupDefault)
provisionConfig.SetDefault(LocationName, LocationDefaultText)
provisionConfig.SetDefault(SiteName, siteDefaultMessage)
provisionConfig.SetDefault(TemplateParametersName, TemplateParametersDefault)
var sanitizedClientSecret string
if rawSecret := provisionConfig.GetString(ClientSecretName); rawSecret != "" {
const safeCharCount = 10
@ -699,18 +905,14 @@ func init() {
provisionConfig.SetDefault(TemplateName, TemplateDefaultLink)
}
if dialect, err := getDatabaseFlavor(".", provisionConfig.GetString(ProfileName)); err == nil {
provisionConfig.SetDefault(DatabaseName, dialect)
if p, err := loadFromParameterFile(provisionConfig.GetString(TemplateParametersName)); err == nil {
setDefaults(provisionConfig, p)
deployParams = p
} else {
debugLog.Print("unable to parse buffalo app for db dialect: ", err)
deployParams = NewDeploymentParameters()
}
provisionConfig.SetDefault(EnvironmentName, EnvironmentDefault)
provisionConfig.SetDefault(ResoureGroupName, ResourceGroupDefault)
provisionConfig.SetDefault(LocationName, LocationDefault)
provisionConfig.SetDefault(SiteName, siteDefaultMessage)
provisionCmd.Flags().StringP(ImageName, ImageShorthand, ImageDefault, imageUsage)
provisionCmd.Flags().StringP(ImageName, ImageShorthand, provisionConfig.GetString(ImageName), imageUsage)
provisionCmd.Flags().StringP(TemplateName, TemplateShorthand, provisionConfig.GetString(TemplateName), templateUsage)
provisionCmd.Flags().StringP(SubscriptionName, SubscriptionShorthand, provisionConfig.GetString(SubscriptionName), subscriptionUsage)
provisionCmd.Flags().String(ClientIDName, provisionConfig.GetString(ClientIDName), clientIDUsage)
@ -719,11 +921,24 @@ func init() {
provisionCmd.Flags().BoolP(VerboseName, VerboseShortname, false, verboseUsage)
provisionCmd.Flags().String(TenantIDName, provisionConfig.GetString(TenantIDName), tenantUsage)
provisionCmd.Flags().StringP(EnvironmentName, EnvironmentShorthand, provisionConfig.GetString(EnvironmentName), environmentUsage)
provisionCmd.Flags().StringP(DatabaseName, DatabaseShorthand, provisionConfig.GetString(DatabaseName), databaseUsage)
provisionCmd.Flags().String(DatabaseNameName, provisionConfig.GetString(DatabaseNameName), databaseNameUsage)
provisionCmd.Flags().StringP(DatabaseTypeName, DatabaseShorthand, provisionConfig.GetString(DatabaseTypeName), databaseUsage)
provisionCmd.Flags().StringP(ResoureGroupName, ResourceGroupShorthand, provisionConfig.GetString(ResoureGroupName), resourceGroupUsage)
provisionCmd.Flags().StringP(SiteName, SiteShorthand, provisionConfig.GetString(SiteName), siteUsage)
provisionCmd.Flags().StringP(LocationName, LocationShorthand, provisionConfig.GetString(LocationName), locationUsage)
//provisionCmd.Flags().StringP(ProfileName, ProfileShorthand, provisionConfig.GetString(ProfileName), profileUsage)
provisionCmd.Flags().Bool(SkipTemplateCacheName, false, skipTemplateCacheUsage)
provisionCmd.Flags().BoolP(SkipParameterCacheName, SkipParameterCacheShorthand, false, skipParameterCacheUsage)
provisionCmd.Flags().BoolP(SkipDeploymentName, SkipDeploymentShorthand, false, skipDeploymentUsage)
provisionCmd.Flags().StringP(DatabasePasswordName, DatabasePasswordShorthand, DatabasePasswordDefault, databasePasswordUsage)
provisionCmd.Flags().String(DatabaseAdminName, provisionConfig.GetString(DatabaseAdminName), databaseAdminUsage)
provisionCmd.Flags().StringP(TemplateParametersName, TemplateParametersShorthand, provisionConfig.GetString(TemplateParametersName), templateParametersUsage)
provisionConfig.BindPFlags(provisionCmd.Flags())
userAgentBuilder := bytes.NewBufferString("buffalo-azure")
if version != "" {
userAgentBuilder.WriteRune('/')
userAgentBuilder.WriteString(version)
}
userAgent = userAgentBuilder.String()
}

21
cmd/testdata/parameters1.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,21 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"database": {
"value": "postgresql"
},
"databaseAdministratorLogin": {
"value": "buffaloAdmin"
},
"databaseName": {
"value": "buffalo30_development"
},
"imageName": {
"value": "marstr/quickstart:latest"
},
"name": {
"value": "buffalo-app-uqqq1nfno1"
}
}
}