Kaynağa Gözat

Merge pull request #1872 from porter-dev/master

RDS read replica support -> staging
abelanger5 4 yıl önce
ebeveyn
işleme
982b8d0b32

+ 2 - 2
.github/workflows/prerelease.yaml

@@ -72,7 +72,7 @@ jobs:
           NODE_ENV: production
           NODE_ENV: production
       - name: Build Linux binaries
       - name: Build Linux binaries
         run: |
         run: |
-          go build -ldflags="-w -s -X 'github.com/porter-dev/porter/cli/cmd.Version=${{steps.tag_name.outputs.tag}}'" -a -tags cli -o ./porter ./cli &
+          go build -ldflags="-w -s -X 'github.com/porter-dev/porter/cli/cmd/config.Version=${{steps.tag_name.outputs.tag}}'" -a -tags cli -o ./porter ./cli &
           go build -ldflags="-w -s -X 'main.Version=${{steps.tag_name.outputs.tag}}'" -a -o ./docker-credential-porter ./cmd/docker-credential-porter/ &
           go build -ldflags="-w -s -X 'main.Version=${{steps.tag_name.outputs.tag}}'" -a -o ./docker-credential-porter ./cmd/docker-credential-porter/ &
           go build -ldflags="-w -s -X 'main.Version=${{steps.tag_name.outputs.tag}}'" -a -tags ee -o ./portersvr ./cmd/app/ &
           go build -ldflags="-w -s -X 'main.Version=${{steps.tag_name.outputs.tag}}'" -a -tags ee -o ./portersvr ./cmd/app/ &
           wait
           wait
@@ -129,7 +129,7 @@ jobs:
           EOL
           EOL
       - name: Build and Zip MacOS amd64 binaries
       - name: Build and Zip MacOS amd64 binaries
         run: |
         run: |
-          go build -ldflags="-w -s -X 'github.com/porter-dev/porter/cli/cmd.Version=${{steps.tag_name.outputs.tag}}'" -a -tags cli -o ./amd64/porter ./cli &
+          go build -ldflags="-w -s -X 'github.com/porter-dev/porter/cli/cmd/config.Version=${{steps.tag_name.outputs.tag}}'" -a -tags cli -o ./amd64/porter ./cli &
           go build -ldflags="-w -s -X 'main.Version=${{steps.tag_name.outputs.tag}}'" -a -o ./amd64/docker-credential-porter ./cmd/docker-credential-porter/ &
           go build -ldflags="-w -s -X 'main.Version=${{steps.tag_name.outputs.tag}}'" -a -o ./amd64/docker-credential-porter ./cmd/docker-credential-porter/ &
           go build -ldflags="-w -s -X 'main.Version=${{steps.tag_name.outputs.tag}}'" -a -tags ee -o ./amd64/portersvr ./cmd/app/ &
           go build -ldflags="-w -s -X 'main.Version=${{steps.tag_name.outputs.tag}}'" -a -tags ee -o ./amd64/portersvr ./cmd/app/ &
           wait
           wait

+ 21 - 0
api/client/k8s.go

@@ -91,6 +91,27 @@ func (c *Client) GetEnvGroup(
 	return resp, err
 	return resp, err
 }
 }
 
 
+func (c *Client) CreateEnvGroup(
+	ctx context.Context,
+	projectID, clusterID uint,
+	namespace string,
+	req *types.CreateEnvGroupRequest,
+) (*types.EnvGroup, error) {
+	resp := &types.EnvGroup{}
+
+	err := c.postRequest(
+		fmt.Sprintf(
+			"/projects/%d/clusters/%d/namespaces/%s/envgroup/create",
+			projectID, clusterID,
+			namespace,
+		),
+		req,
+		resp,
+	)
+
+	return resp, err
+}
+
 func (c *Client) CloneEnvGroup(
 func (c *Client) CloneEnvGroup(
 	ctx context.Context,
 	ctx context.Context,
 	projectID, clusterID uint,
 	projectID, clusterID uint,

+ 30 - 0
api/client/release.go

@@ -0,0 +1,30 @@
+package client
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/porter-dev/porter/api/types"
+	"helm.sh/helm/v3/pkg/release"
+)
+
+func (c *Client) ListReleases(
+	ctx context.Context,
+	projectID, clusterID uint,
+	namespace string,
+	req *types.ListReleasesRequest,
+) ([]*release.Release, error) {
+	resp := make([]*release.Release, 0)
+
+	err := c.getRequest(
+		fmt.Sprintf(
+			"/projects/%d/clusters/%d/namespaces/%s/releases",
+			projectID, clusterID,
+			namespace,
+		),
+		req,
+		&resp,
+	)
+
+	return resp, err
+}

+ 18 - 3
api/server/handlers/infra/forms.go

@@ -290,13 +290,13 @@ tabs:
     - type: heading
     - type: heading
       label: Storage Settings
       label: Storage Settings
     - type: number-input
     - type: number-input
-      label: Gigabytes
+      label: Specify the amount of storage to allocate to this instance in gigabytes.
       variable: db_allocated_storage
       variable: db_allocated_storage
       placeholder: "ex: 10"
       placeholder: "ex: 10"
       settings:
       settings:
         default: 10
         default: 10
     - type: number-input
     - type: number-input
-      label: Gigabytes
+      label: Specify the maximum storage that this instance can scale to in gigabytes.
       variable: db_max_allocated_storage
       variable: db_max_allocated_storage
       placeholder: "ex: 20"
       placeholder: "ex: 20"
       settings:
       settings:
@@ -305,7 +305,22 @@ tabs:
       variable: db_storage_encrypted
       variable: db_storage_encrypted
       label: Enable storage encryption for the database. 
       label: Enable storage encryption for the database. 
       settings:
       settings:
-        default: false`
+        default: false
+- name: advanced
+  label: Advanced
+  sections:
+  - name: replicas
+    contents:
+    - type: heading
+      label: Read Replicas
+    - type: subtitle
+      label: Specify the number of read replicas to run alongside your RDS instance.
+    - type: number-input
+      label: Replicas
+      variable: db_replicas
+      placeholder: "ex: 1"
+      settings:
+        default: 0`
 
 
 const ecrForm = `name: ECR
 const ecrForm = `name: ECR
 hasSource: false
 hasSource: false

+ 6 - 0
cli/cmd/apply.go

@@ -101,6 +101,8 @@ func apply(_ *types.GetAuthenticatedUserResponse, client *api.Client, args []str
 	worker.RegisterDriver("build-image", preview.NewBuildDriver)
 	worker.RegisterDriver("build-image", preview.NewBuildDriver)
 	worker.RegisterDriver("push-image", preview.NewPushDriver)
 	worker.RegisterDriver("push-image", preview.NewPushDriver)
 	worker.RegisterDriver("update-config", preview.NewUpdateConfigDriver)
 	worker.RegisterDriver("update-config", preview.NewUpdateConfigDriver)
+	worker.RegisterDriver("random-string", preview.NewRandomStringDriver)
+	worker.RegisterDriver("env-group", preview.NewEnvGroupDriver)
 
 
 	worker.SetDefaultDriver("deploy")
 	worker.SetDefaultDriver("deploy")
 
 
@@ -824,6 +826,10 @@ func NewCloneEnvGroupHook(client *api.Client, resourceGroup *switchboardTypes.Re
 
 
 func (t *CloneEnvGroupHook) PreApply() error {
 func (t *CloneEnvGroupHook) PreApply() error {
 	for _, res := range t.resGroup.Resources {
 	for _, res := range t.resGroup.Resources {
+		if res.Driver == "env-group" {
+			continue
+		}
+
 		config := &ApplicationConfig{}
 		config := &ApplicationConfig{}
 
 
 		err := mapstructure.Decode(res.Config, &config)
 		err := mapstructure.Decode(res.Config, &config)

+ 130 - 0
cli/cmd/list.go

@@ -0,0 +1,130 @@
+package cmd
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"text/tabwriter"
+
+	api "github.com/porter-dev/porter/api/client"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/spf13/cobra"
+	"helm.sh/helm/v3/pkg/release"
+)
+
+// listCmd represents the "porter list" base command when called
+// without any subcommands
+var listCmd = &cobra.Command{
+	Use:   "list",
+	Args:  cobra.ExactArgs(1),
+	Short: "List applications or jobs.",
+}
+
+var listAppsCmd = &cobra.Command{
+	Use:     "apps",
+	Aliases: []string{"applications", "app", "application"},
+	Short:   "Lists applications in a specific namespace, or across all namespaces",
+	Run: func(cmd *cobra.Command, args []string) {
+		err := checkLoginAndRun(args, listApps)
+
+		if err != nil {
+			os.Exit(1)
+		}
+	},
+}
+
+var listJobsCmd = &cobra.Command{
+	Use:     "jobs",
+	Aliases: []string{"job"},
+	Short:   "Lists jobs in a specific namespace, or across all namespaces",
+	Run: func(cmd *cobra.Command, args []string) {
+		err := checkLoginAndRun(args, listJobs)
+
+		if err != nil {
+			os.Exit(1)
+		}
+	},
+}
+
+func init() {
+	listCmd.PersistentFlags().StringVar(
+		&namespace,
+		"namespace",
+		"default",
+		"the namespace of the release",
+	)
+
+	listCmd.AddCommand(listAppsCmd)
+	listCmd.AddCommand(listJobsCmd)
+
+	rootCmd.AddCommand(listCmd)
+}
+
+func listApps(_ *types.GetAuthenticatedUserResponse, client *api.Client, args []string) error {
+	releases, err := client.ListReleases(context.Background(), cliConf.Project, cliConf.Cluster, namespace, &types.ListReleasesRequest{
+		ReleaseListFilter: &types.ReleaseListFilter{
+			Limit: 50,
+			Skip:  0,
+			StatusFilter: []string{
+				"deployed",
+				"uninstalled",
+				"pending",
+				"pending-install",
+				"pending-upgrade",
+				"pending-rollback",
+				"failed",
+			},
+		},
+	})
+
+	if err != nil {
+		return err
+	}
+
+	writeReleases("application", releases)
+
+	return nil
+}
+
+func listJobs(_ *types.GetAuthenticatedUserResponse, client *api.Client, args []string) error {
+	releases, err := client.ListReleases(context.Background(), cliConf.Project, cliConf.Cluster, namespace, &types.ListReleasesRequest{
+		ReleaseListFilter: &types.ReleaseListFilter{
+			Limit: 50,
+			Skip:  0,
+			StatusFilter: []string{
+				"deployed",
+				"uninstalled",
+				"pending",
+				"pending-install",
+				"pending-upgrade",
+				"pending-rollback",
+				"failed",
+			},
+		},
+	})
+
+	if err != nil {
+		return err
+	}
+
+	writeReleases("job", releases)
+
+	return nil
+}
+
+func writeReleases(kind string, releases []*release.Release) {
+	w := new(tabwriter.Writer)
+	w.Init(os.Stdout, 3, 8, 0, '\t', tabwriter.AlignRight)
+
+	fmt.Fprintf(w, "%s\t%s\t%s\n", "NAME", "NAMESPACE", "STATUS")
+
+	for _, rel := range releases {
+		if chartName := rel.Chart.Name(); kind == "application" && (chartName == "web" || chartName == "worker") {
+			fmt.Fprintf(w, "%s\t%s\t%s\n", rel.Name, rel.Namespace, rel.Info.Status)
+		} else if chartName := rel.Chart.Name(); kind == "job" && (chartName == "job") {
+			fmt.Fprintf(w, "%s\t%s\t%s\n", rel.Name, rel.Namespace, rel.Info.Status)
+		}
+	}
+
+	w.Flush()
+}

+ 128 - 0
cli/cmd/preview/env_group_driver.go

@@ -0,0 +1,128 @@
+package preview
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/fatih/color"
+	"github.com/mitchellh/mapstructure"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/cli/cmd/config"
+	"github.com/porter-dev/switchboard/pkg/drivers"
+	"github.com/porter-dev/switchboard/pkg/models"
+)
+
+type EnvGroupDriverConfig struct {
+	EnvGroups []*types.EnvGroup `mapstructure:"env_groups"`
+}
+
+type EnvGroupDriver struct {
+	output      map[string]interface{}
+	lookupTable *map[string]drivers.Driver
+	target      *Target
+	config      *EnvGroupDriverConfig
+}
+
+func NewEnvGroupDriver(resource *models.Resource, opts *drivers.SharedDriverOpts) (drivers.Driver, error) {
+	driver := &EnvGroupDriver{
+		lookupTable: opts.DriverLookupTable,
+		output:      make(map[string]interface{}),
+	}
+
+	target, err := GetTarget(resource.Target)
+
+	if err != nil {
+		return nil, err
+	}
+
+	driver.target = target
+
+	return driver, nil
+}
+
+func (d *EnvGroupDriver) ShouldApply(resource *models.Resource) bool {
+	return true
+}
+
+func (d *EnvGroupDriver) Apply(resource *models.Resource) (*models.Resource, error) {
+	driverConfig, err := d.getConfig(resource)
+
+	if err != nil {
+		return nil, err
+	}
+
+	d.config = driverConfig
+
+	client := config.GetAPIClient()
+
+	for _, group := range d.config.EnvGroups {
+		if group.Name == "" {
+			return nil, fmt.Errorf("env group name cannot be empty")
+		}
+
+		if group.Namespace == "" {
+			color.New(color.FgYellow).Printf("env group %s has empty namespace so defaulting to target namespace %s\n",
+				group.Name, d.target.Namespace)
+
+			group.Namespace = d.target.Namespace
+		}
+
+		envGroup, err := client.GetEnvGroup(
+			context.Background(),
+			d.target.Project,
+			d.target.Cluster,
+			group.Namespace,
+			&types.GetEnvGroupRequest{
+				Name: group.Name,
+			},
+		)
+
+		if err != nil && err.Error() == "env group not found" {
+			envGroup, err = client.CreateEnvGroup(
+				context.Background(), d.target.Project, d.target.Cluster, group.Namespace,
+				&types.CreateEnvGroupRequest{
+					Name:      group.Name,
+					Variables: group.Variables,
+				},
+			)
+
+			if err != nil {
+				return nil, err
+			}
+		} else if err != nil {
+			return nil, err
+		}
+
+		d.output[envGroup.Name] = map[string]interface{}{
+			"variables": envGroup.Variables,
+		}
+	}
+
+	return resource, nil
+}
+
+func (d *EnvGroupDriver) Output() (map[string]interface{}, error) {
+	return d.output, nil
+}
+
+func (d *EnvGroupDriver) getConfig(resource *models.Resource) (*EnvGroupDriverConfig, error) {
+	populatedConf, err := drivers.ConstructConfig(&drivers.ConstructConfigOpts{
+		RawConf:      resource.Config,
+		LookupTable:  *d.lookupTable,
+		Dependencies: resource.Dependencies,
+	})
+
+	if err != nil {
+		return nil, err
+	}
+
+	config := &EnvGroupDriverConfig{}
+
+	err = mapstructure.Decode(populatedConf, config)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return config, nil
+}

+ 67 - 0
cli/cmd/preview/random_string_driver.go

@@ -0,0 +1,67 @@
+package preview
+
+import (
+	"math/rand"
+	"time"
+
+	"github.com/mitchellh/mapstructure"
+	"github.com/porter-dev/switchboard/pkg/drivers"
+	"github.com/porter-dev/switchboard/pkg/models"
+)
+
+const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+
+var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+type RandomStringDriverConfig struct {
+	Length uint
+}
+
+type RandomStringDriver struct {
+	output map[string]interface{}
+	config *RandomStringDriverConfig
+}
+
+func NewRandomStringDriver(resource *models.Resource, opts *drivers.SharedDriverOpts) (drivers.Driver, error) {
+	driver := &RandomStringDriver{
+		output: make(map[string]interface{}),
+	}
+
+	driverConfig := &RandomStringDriverConfig{}
+
+	err := mapstructure.Decode(resource.Config, driverConfig)
+
+	if err != nil {
+		return nil, err
+	}
+
+	if driverConfig.Length == 0 {
+		driverConfig.Length = 8
+	}
+
+	driver.config = driverConfig
+
+	return driver, nil
+}
+
+func (d *RandomStringDriver) ShouldApply(resource *models.Resource) bool {
+	return true
+}
+
+func (d *RandomStringDriver) Apply(resource *models.Resource) (*models.Resource, error) {
+	d.output["value"] = randomString(d.config.Length)
+
+	return resource, nil
+}
+
+func (d *RandomStringDriver) Output() (map[string]interface{}, error) {
+	return d.output, nil
+}
+
+func randomString(length uint) string {
+	b := make([]byte, length)
+	for i := range b {
+		b[i] = charset[seededRand.Intn(len(charset))]
+	}
+	return string(b)
+}

+ 0 - 31
cli/cmd/preview/uuid_driver.go

@@ -1,31 +0,0 @@
-package preview
-
-import (
-	"github.com/google/uuid"
-	"github.com/porter-dev/switchboard/pkg/drivers"
-	"github.com/porter-dev/switchboard/pkg/models"
-)
-
-type UUIDDriver struct {
-	output map[string]interface{}
-}
-
-func NewUUIDDriver(resource *models.Resource, opts *drivers.SharedDriverOpts) (drivers.Driver, error) {
-	return &BuildDriver{
-		output: make(map[string]interface{}),
-	}, nil
-}
-
-func (d *UUIDDriver) ShouldApply(resource *models.Resource) bool {
-	return true
-}
-
-func (d *UUIDDriver) Apply(resource *models.Resource) (*models.Resource, error) {
-	d.output["uuid"] = uuid.NewString()
-
-	return resource, nil
-}
-
-func (d *UUIDDriver) Output() (map[string]interface{}, error) {
-	return d.output, nil
-}

+ 1 - 1
scripts/build/osx.sh

@@ -2,7 +2,7 @@
 #
 #
 # Accepts the version as an argument
 # Accepts the version as an argument
 
 
-go build -ldflags="-w -s -X 'github.com/porter-dev/porter/cli/cmd.Version=$1'" -a -tags cli -o ./porter ./cli &
+go build -ldflags="-w -s -X 'github.com/porter-dev/porter/cli/cmd/config.Version=$1'" -a -tags cli -o ./porter ./cli &
 go build -ldflags="-w -s -X 'main.Version=$1'" -a -o ./docker-credential-porter ./cmd/docker-credential-porter/ &
 go build -ldflags="-w -s -X 'main.Version=$1'" -a -o ./docker-credential-porter ./cmd/docker-credential-porter/ &
 go build -ldflags="-w -s -X 'main.Version=$1'" -a -tags ee -o ./portersvr ./cmd/app/ &
 go build -ldflags="-w -s -X 'main.Version=$1'" -a -tags ee -o ./portersvr ./cmd/app/ &
 wait
 wait

+ 1 - 1
scripts/build/win.sh

@@ -2,7 +2,7 @@
 #
 #
 # Accepts the version as an argument
 # Accepts the version as an argument
 
 
-go build -ldflags="-w -s -X 'github.com/porter-dev/porter/cli/cmd.Version=$1'" -a -tags cli -o ./porter.exe ./cli &
+go build -ldflags="-w -s -X 'github.com/porter-dev/porter/cli/cmd/config.Version=$1'" -a -tags cli -o ./porter.exe ./cli &
 go build -ldflags="-w -s -X 'main.Version=$1'" -a -o ./docker-credential-porter.exe ./cmd/docker-credential-porter/ &
 go build -ldflags="-w -s -X 'main.Version=$1'" -a -o ./docker-credential-porter.exe ./cmd/docker-credential-porter/ &
 go build -ldflags="-w -s -X 'main.Version=$1'" -a -tags ee -o ./portersvr.exe ./cmd/app/ &
 go build -ldflags="-w -s -X 'main.Version=$1'" -a -tags ee -o ./portersvr.exe ./cmd/app/ &
 wait
 wait