Procházet zdrojové kódy

Stacks build settings pull from db if no build settings are provided in porter yaml (#2967)

Feroze Mohideen před 3 roky
rodič
revize
a0227f8cd6

+ 19 - 0
api/client/stack.go

@@ -39,3 +39,22 @@ func (c *Client) UpdateStack(
 		nil,
 	)
 }
+
+func (c *Client) GetStack(
+	ctx context.Context,
+	projectID, clusterID uint,
+	stackName string,
+) (*types.PorterApp, error) {
+	resp := &types.PorterApp{}
+
+	err := c.getRequest(
+		fmt.Sprintf(
+			"/projects/%d/clusters/%d/stacks/%s",
+			projectID, clusterID, stackName,
+		),
+		nil,
+		resp,
+	)
+
+	return resp, err
+}

+ 0 - 3
api/server/handlers/stacks/get_porter_app.go

@@ -1,7 +1,6 @@
 package stacks
 
 import (
-	"fmt"
 	"net/http"
 
 	"github.com/porter-dev/porter/api/server/authz"
@@ -39,7 +38,5 @@ func (c *GetPorterAppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	fmt.Println("got here", app)
-
 	c.WriteResult(w, r, app.ToPorterAppType())
 }

+ 1 - 1
api/server/shared/config/env/envconfs.go

@@ -23,7 +23,7 @@ type ServerConf struct {
 	CookieInsecure       bool          `env:"COOKIE_INSECURE,default=false"`
 	TokenGeneratorSecret string        `env:"TOKEN_GENERATOR_SECRET,default=secret"`
 	TimeoutRead          time.Duration `env:"SERVER_TIMEOUT_READ,default=5s"`
-	TimeoutWrite         time.Duration `env:"SERVER_TIMEOUT_WRITE,default=10s"`
+	TimeoutWrite         time.Duration `env:"SERVER_TIMEOUT_WRITE,default=30s"`
 	TimeoutIdle          time.Duration `env:"SERVER_TIMEOUT_IDLE,default=15s"`
 	IsLocal              bool          `env:"IS_LOCAL,default=false"`
 	IsTesting            bool          `env:"IS_TESTING,default=false"`

+ 2 - 0
api/types/stack.go

@@ -22,3 +22,5 @@ type CreateSecretAndOpenGHPRRequest struct {
 type CreateSecretAndOpenGHPRResponse struct {
 	URL string `json:"url"`
 }
+
+type GetStackResponse PorterApp

+ 1 - 1
cli/cmd/apply.go

@@ -157,7 +157,7 @@ func apply(_ *types.GetAuthenticatedUserResponse, client *api.Client, _ []string
 			return fmt.Errorf("environment variable PORTER_STACK_NAME must be set")
 		}
 
-		resGroup, err = stack.CreateV1BuildResources(client, fileBytes)
+		resGroup, err = stack.CreateV1BuildResources(client, fileBytes, stackName, cliConf.Project, cliConf.Cluster)
 		if err != nil {
 			return fmt.Errorf("error parsing porter.yaml for build resources: %w", err)
 		}

+ 123 - 15
cli/cmd/stack/apply.go

@@ -1,53 +1,66 @@
 package stack
 
 import (
+	"context"
 	"fmt"
+	"strings"
 
+	"github.com/fatih/color"
 	api "github.com/porter-dev/porter/api/client"
+	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/cli/cmd/config"
-	"github.com/porter-dev/switchboard/pkg/types"
+	switchboardTypes "github.com/porter-dev/switchboard/pkg/types"
 	"gopkg.in/yaml.v2"
 )
 
 type StackConf struct {
-	apiClient *api.Client
-	rawBytes  []byte
-	parsed    *PorterStackYAML
+	apiClient            *api.Client
+	rawBytes             []byte
+	parsed               *PorterStackYAML
+	stackName            string
+	projectID, clusterID uint
 }
 
-func CreateV1BuildResources(client *api.Client, raw []byte) (*types.ResourceGroup, error) {
-	stackConf, err := createStackConf(client, raw)
+func CreateV1BuildResources(client *api.Client, raw []byte, stackName string, projectID uint, clusterID uint) (*switchboardTypes.ResourceGroup, error) {
+	stackConf, err := createStackConf(client, raw, stackName, projectID, clusterID)
 	if err != nil {
 		return nil, err
 	}
 
-	v1File := &types.ResourceGroup{
+	v1File := &switchboardTypes.ResourceGroup{
 		Version: "v1",
-		Resources: []*types.Resource{
+		Resources: []*switchboardTypes.Resource{
 			{
 				Name:   "get-env",
 				Driver: "os-env",
 			},
 		},
 	}
+
+	var bi, pi *switchboardTypes.Resource
+
 	if stackConf.parsed.Build != nil {
-		bi, err := stackConf.parsed.Build.getV1BuildImage(stackConf.parsed.Env)
+		bi, pi, err = createV1BuildResourcesFromPorterYaml(stackConf)
 		if err != nil {
-			return nil, err
+			color.New(color.FgRed).Printf("Could not build using values specified in porter.yaml (%s), attempting to load stack build settings instead \n", err.Error())
+			bi, pi, err = createV1BuildResourcesFromDB(client, stackConf)
+			if err != nil {
+				return nil, err
+			}
 		}
-
-		pi, err := stackConf.parsed.Build.getV1PushImage()
+	} else {
+		bi, pi, err = createV1BuildResourcesFromDB(client, stackConf)
 		if err != nil {
 			return nil, err
 		}
-
-		v1File.Resources = append(v1File.Resources, bi, pi)
 	}
 
+	v1File.Resources = append(v1File.Resources, bi, pi)
+
 	return v1File, nil
 }
 
-func createStackConf(client *api.Client, raw []byte) (*StackConf, error) {
+func createStackConf(client *api.Client, raw []byte, stackName string, projectID uint, clusterID uint) (*StackConf, error) {
 	parsed := &PorterStackYAML{}
 
 	err := yaml.Unmarshal(raw, parsed)
@@ -66,5 +79,100 @@ func createStackConf(client *api.Client, raw []byte) (*StackConf, error) {
 		apiClient: client,
 		rawBytes:  raw,
 		parsed:    parsed,
+		stackName: stackName,
+		projectID: projectID,
+		clusterID: clusterID,
 	}, nil
 }
+
+func createV1BuildResourcesFromPorterYaml(stackConf *StackConf) (*switchboardTypes.Resource, *switchboardTypes.Resource, error) {
+	bi, err := stackConf.parsed.Build.getV1BuildImage(stackConf.parsed.Env)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	pi, err := stackConf.parsed.Build.getV1PushImage()
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return bi, pi, nil
+}
+
+func createV1BuildResourcesFromDB(client *api.Client, stackConf *StackConf) (*switchboardTypes.Resource, *switchboardTypes.Resource, error) {
+	res, err := client.GetStack(context.Background(), stackConf.projectID, stackConf.clusterID, stackConf.stackName)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	if res == nil {
+		return nil, nil, fmt.Errorf("stack %s not found", stackConf.stackName)
+	}
+
+	build := convertToBuild(res)
+
+	bi, err := build.getV1BuildImage(stackConf.parsed.Env)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	pi, err := build.getV1PushImage()
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return bi, pi, nil
+}
+
+func convertToBuild(porterApp *types.PorterApp) Build {
+	var context *string
+	if porterApp.BuildContext != "" {
+		context = &porterApp.BuildContext
+	}
+
+	var method *string
+	var m string
+	if porterApp.RepoName == "" {
+		m = "registry"
+		method = &m
+	} else if porterApp.Dockerfile == "" {
+		m = "pack"
+		method = &m
+	} else {
+		m = "docker"
+		method = &m
+	}
+
+	var builder *string
+	if porterApp.Builder != "" {
+		builder = &porterApp.Builder
+	}
+
+	var buildpacks []*string
+	if porterApp.Buildpacks != "" {
+		bpSlice := strings.Split(porterApp.Buildpacks, ",")
+		buildpacks = make([]*string, len(bpSlice))
+		for i, bp := range bpSlice {
+			buildpacks[i] = &bp
+		}
+	}
+
+	var dockerfile *string
+	if porterApp.Dockerfile != "" {
+		dockerfile = &porterApp.Dockerfile
+	}
+
+	var image *string
+	if porterApp.ImageRepoURI != "" {
+		image = &porterApp.ImageRepoURI
+	}
+
+	return Build{
+		Context:    context,
+		Method:     method,
+		Builder:    builder,
+		Buildpacks: buildpacks,
+		Dockerfile: dockerfile,
+		Image:      image,
+	}
+}