diff --git a/cmd/agent/agent.go b/cmd/agent/agent.go index 127f67c22..a56cd2256 100644 --- a/cmd/agent/agent.go +++ b/cmd/agent/agent.go @@ -284,7 +284,7 @@ func serverCommunication( var imageBuildRequest dx.ImageBuildRequest _ = json.Unmarshal(requestString, &imageBuildRequest) - if imageBuildRequest.Dockerfile != "" { + if imageBuildRequest.Strategy == "dockerfile" { go dockerfileImageBuild(kubeEnv, gimletHost, buildId, imageBuildRequest, messages) } else { go buildImage(gimletHost, agentKey, buildId, imageBuildRequest, messages, config.ImageBuilderHost) diff --git a/pkg/dashboard/server/api.go b/pkg/dashboard/server/api.go index 2f904f23f..0d140fadb 100644 --- a/pkg/dashboard/server/api.go +++ b/pkg/dashboard/server/api.go @@ -301,28 +301,17 @@ func stackConfig(w http.ResponseWriter, r *http.Request) { return } - var stackConfig *dx.StackConfig stackYamlPath := "stack.yaml" if !env.RepoPerEnv { stackYamlPath = filepath.Join(env.Name, "stack.yaml") } gitRepoCache, _ := r.Context().Value("gitRepoCache").(*nativeGit.RepoCache) - err = gitRepoCache.PerformAction(env.InfraRepo, func(repo *git.Repository) error { - var inerErr error - stackConfig, inerErr = stackYaml(repo, stackYamlPath) - return inerErr - }) + stackConfig, err := StackConfig(gitRepoCache, stackYamlPath, env.InfraRepo) if err != nil { - if !strings.Contains(err.Error(), "file not found") { - logrus.Errorf("cannot get stack yaml from repo: %s", err) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - return - } else { - logrus.Errorf("cannot get repo: %s", err) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - return - } + logrus.Errorf("cannot get stack config: %s", err) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return } stackDefinition, err := loadStackDefinition(stackConfig) @@ -349,6 +338,23 @@ func stackConfig(w http.ResponseWriter, r *http.Request) { w.Write(gitopsEnvString) } +func StackConfig(gitRepoCache *nativeGit.RepoCache, stackYamlPath, infraRepo string) (*dx.StackConfig, error) { + var stackConfig *dx.StackConfig + err := gitRepoCache.PerformAction(infraRepo, func(repo *git.Repository) error { + var inerErr error + stackConfig, inerErr = stackYaml(repo, stackYamlPath) + return inerErr + }) + if err != nil { + if !strings.Contains(err.Error(), "file not found") { + return nil, fmt.Errorf("cannot get stack yaml from repo: %s", err) + } else { + return nil, fmt.Errorf("cannot get repo: %s", err) + } + } + return stackConfig, nil +} + func loadStackDefinition(stackConfig *dx.StackConfig) (map[string]interface{}, error) { var url string if stackConfig != nil { diff --git a/pkg/dashboard/server/releases.go b/pkg/dashboard/server/releases.go index f4472adeb..2eb96c429 100644 --- a/pkg/dashboard/server/releases.go +++ b/pkg/dashboard/server/releases.go @@ -295,6 +295,7 @@ func release(w http.ResponseWriter, r *http.Request) { Image: imageRepository, Tag: imageTag, Dockerfile: dockerfile, + Strategy: strategy, Registry: registry, } break diff --git a/pkg/dashboard/worker/gitops.go b/pkg/dashboard/worker/gitops.go index 45f188090..7367d77a7 100644 --- a/pkg/dashboard/worker/gitops.go +++ b/pkg/dashboard/worker/gitops.go @@ -20,11 +20,9 @@ import ( "github.com/gimlet-io/gimlet/pkg/dx" "github.com/gimlet-io/gimlet/pkg/git/customScm" "github.com/gimlet-io/gimlet/pkg/git/nativeGit" - helper "github.com/gimlet-io/gimlet/pkg/git/nativeGit" bootstrap "github.com/gimlet-io/gimlet/pkg/gitops" "github.com/gimlet-io/gimlet/pkg/gitops/sync" "github.com/joho/godotenv" - "sigs.k8s.io/yaml" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" @@ -726,23 +724,14 @@ func cloneTemplateWriteAndPush( } } - var stackConfig *dx.StackConfig stackYamlPath := "stack.yaml" if !envFromStore.RepoPerEnv { stackYamlPath = filepath.Join(envFromStore.Name, "stack.yaml") } - err = gitopsRepoCache.PerformAction(envFromStore.InfraRepo, func(repo *git.Repository) error { - var inerErr error - stackConfig, inerErr = stackYaml(repo, stackYamlPath) - return inerErr - }) + stackConfig, err := server.StackConfig(gitopsRepoCache, stackYamlPath, envFromStore.InfraRepo) if err != nil { - if !strings.Contains(err.Error(), "file not found") { - return "", err - } else { - return "", err - } + return "", err } imagepullSecretManifest, err := imagepullSecretTemplate( @@ -808,28 +797,6 @@ func cloneTemplateWriteAndPush( return sha, nil } -// TODO Duplication -func stackYaml(repo *git.Repository, path string) (*dx.StackConfig, error) { - var stackConfig dx.StackConfig - - headBranch, err := helper.HeadBranch(repo) - if err != nil { - return nil, err - } - - yamlString, err := helper.RemoteContentOnBranchWithoutCheckout(repo, headBranch, path) - if err != nil { - return nil, err - } - - err = yaml.Unmarshal([]byte(yamlString), &stackConfig) - if err != nil { - return nil, err - } - - return &stackConfig, nil -} - func cloneTemplateDeleteAndPush( gitopsRepoCache *nativeGit.RepoCache, cleanupPolicy *dx.Cleanup, @@ -1228,7 +1195,6 @@ func kustomizationTemplate( repoPerEnv) } -// TODO CLEANUP IN CASE OF APP DELETE!!! func imagepullSecretTemplate( manifest *dx.Manifest, stackConfig *dx.StackConfig, @@ -1261,11 +1227,9 @@ func imagepullSecretTemplate( encryptedConfigString = encryptedConfig.(string) } - secretName := fmt.Sprintf("%s-pullsecret", strings.ToLower(registryString)) return sync.GenerateImagePullSecret( manifest.Env, manifest.App, - secretName, manifest.Namespace, encryptedConfigString, repoPerEnv, diff --git a/pkg/dashboard/worker/gitops_test.go b/pkg/dashboard/worker/gitops_test.go index 015af58bf..8994c13f5 100644 --- a/pkg/dashboard/worker/gitops_test.go +++ b/pkg/dashboard/worker/gitops_test.go @@ -97,7 +97,7 @@ func Test_gitopsTemplateAndWrite(t *testing.T) { repo.CreateRemote(&config.RemoteConfig{Name: "origin", URLs: []string{""}}) repoPerEnv := false - _, err := gitopsTemplateAndWrite(repo, a.Environments[0], &dx.Release{}, "", repoPerEnv, nil, nil, nil) + _, err := gitopsTemplateAndWrite(repo, a.Environments[0], &dx.Release{}, "", repoPerEnv, nil, nil, nil, nil) assert.Nil(t, err) content, _ := nativeGit.Content(repo, "staging/my-app/deployment.yaml") assert.True(t, len(content) > 100) @@ -107,7 +107,7 @@ func Test_gitopsTemplateAndWrite(t *testing.T) { assert.True(t, len(content) > 1) repoPerEnv = true - _, err = gitopsTemplateAndWrite(repo, a.Environments[0], &dx.Release{}, "", repoPerEnv, nil, nil, nil) + _, err = gitopsTemplateAndWrite(repo, a.Environments[0], &dx.Release{}, "", repoPerEnv, nil, nil, nil, nil) assert.Nil(t, err) content, _ = nativeGit.Content(repo, "my-app/deployment.yaml") assert.True(t, len(content) > 100) @@ -163,10 +163,10 @@ func Test_gitopsTemplateAndWrite_deleteStaleFiles(t *testing.T) { json.Unmarshal([]byte(withVolume), &a) repoPerEnv := true - _, err := gitopsTemplateAndWrite(repo, a.Environments[0], &dx.Release{}, "", repoPerEnv, nil, nil, nil) + _, err := gitopsTemplateAndWrite(repo, a.Environments[0], &dx.Release{}, "", repoPerEnv, nil, nil, nil, nil) assert.Nil(t, err) - _, err = gitopsTemplateAndWrite(repo, a.Environments[0], &dx.Release{}, "", repoPerEnv, nil, nil, nil) + _, err = gitopsTemplateAndWrite(repo, a.Environments[0], &dx.Release{}, "", repoPerEnv, nil, nil, nil, nil) assert.Nil(t, err) content, _ := nativeGit.Content(repo, "my-app/deployment.yaml") @@ -204,7 +204,7 @@ func Test_gitopsTemplateAndWrite_deleteStaleFiles(t *testing.T) { var b dx.Artifact json.Unmarshal([]byte(withoutVolume), &b) - _, err = gitopsTemplateAndWrite(repo, b.Environments[0], &dx.Release{}, "", false, nil, nil, nil) + _, err = gitopsTemplateAndWrite(repo, b.Environments[0], &dx.Release{}, "", false, nil, nil, nil, nil) assert.Nil(t, err) content, _ = nativeGit.Content(repo, "staging/my-app/pvc.yaml") diff --git a/pkg/gitops/sync/sync.go b/pkg/gitops/sync/sync.go index e1dfec500..c3b1a072c 100644 --- a/pkg/gitops/sync/sync.go +++ b/pkg/gitops/sync/sync.go @@ -264,8 +264,7 @@ func GenerateKustomizationForApp( } func GenerateImagePullSecret( - env, app string, - secretName, namespace string, + env, app, namespace string, encryptedDockerconfigjson string, singleEnv bool, ) (*manifestgen.Manifest, error) { @@ -280,7 +279,7 @@ func GenerateImagePullSecret( APIVersion: "bitnami.com/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ - Name: secretName, + Name: "regcred", Namespace: namespace, Annotations: map[string]string{ "sealedsecrets.bitnami.com/cluster-wide": "true", diff --git a/web/dashboard/src/views/envConfig/envConfig.jsx b/web/dashboard/src/views/envConfig/envConfig.jsx index 87d83b9b4..e0d2da3b9 100644 --- a/web/dashboard/src/views/envConfig/envConfig.jsx +++ b/web/dashboard/src/views/envConfig/envConfig.jsx @@ -51,6 +51,7 @@ class EnvConfig extends Component { this.setValues = this.setValues.bind(this); this.resetNotificationStateAfterThreeSeconds = this.resetNotificationStateAfterThreeSeconds.bind(this); + this.setImagePullSecret = this.setImagePullSecret.bind(this); } componentDidMount() { @@ -59,6 +60,14 @@ class EnvConfig extends Component { const { gimletClient } = this.props; + gimletClient.getStackConfig(env) + .then(data => { + this.setState({ + stackConfig: data.stackConfig, + stackDefinition: data.stackDefinition + }); + }, () => {/* Generic error handler deals with it */ }); + if (action === "new") { gimletClient.getDefaultDeploymentTemplates() .then(data => { @@ -455,6 +464,18 @@ class EnvConfig extends Component { }) } + setImagePullSecret(secret) { + this.setState(prevState => ({ + configFile: { + ...prevState.configFile, + values: { + ...prevState.configFile.values, + imagePullSecrets: [secret] + } + } + })); + } + renderTemplateFromConfig() { let title = "Web application template" let description = "To deploy any web application. Multiple image build options available." @@ -530,11 +551,6 @@ class EnvConfig extends Component { const hasChange = JSON.stringify(this.state.configFile) !== JSON.stringify(this.state.defaultConfigFile) - const customFields = { - imageWidget: ImageWidget, - sealedSecretWidget: (props) => , - } - if (!this.state.configFile) { return ; } @@ -543,6 +559,15 @@ class EnvConfig extends Component { return ; } + if (!this.state.stackConfig) { + return ; + } + + const customFields = { + imageWidget: (props) => , + sealedSecretWidget: (props) => , + } + return (

Editing {config} config for {env}

@@ -850,4 +875,11 @@ class EnvConfig extends Component { } } +const filterRegistry = (stackConfig, stackDefinition) => { + const config = stackConfig.config; + const elements = stackDefinition.components.filter(c => c.category === "registry") + + return Object.fromEntries(Object.entries(config).filter(([key]) => elements.some(e => e.variable === key))) +} + export default EnvConfig; diff --git a/web/dashboard/src/views/envConfig/imageWidget.jsx b/web/dashboard/src/views/envConfig/imageWidget.jsx index 4e5268bec..4b3115769 100644 --- a/web/dashboard/src/views/envConfig/imageWidget.jsx +++ b/web/dashboard/src/views/envConfig/imageWidget.jsx @@ -12,6 +12,11 @@ class ImageWidget extends Component { }; } + // TODO bug input field loses focus on writing + componentDidMount() { + this.props.setImagePullSecret("regcred") + } + defaults(strategy) { let repository = "" let tag = "" @@ -54,37 +59,41 @@ class ImageWidget extends Component { { [name]: event.target.value, }, - () => this.props.onChange({"repository": this.state.repository, "tag": this.state.tag, "dockerfile": this.state.dockerfile, "strategy": this.state.strategy, "registry": this.state.registry }) + () => this.props.onChange({"repository": this.state.repository, "tag": this.state.tag, "dockerfile": this.state.dockerfile, "strategy": this.state.strategy, "registry": this.state.registry}) ); }; } - selectOnChange(value) { - const { registry } = this.props; - let repository = ""; - const login = registry[value].login ?? "your-company" - - switch (value) { - case 'dockerhubRegistry': - repository = `${login}/{{ .APP }}` - break; - case 'ghcrRegistry': - repository = `ghcr.io/${login}/{{ .APP }}` - break; - default: - repository = "127.0.0.1:32447/{{ .APP }}" - } + selectOnChange(name) { + return (event) => { + const { registry } = this.props; + const login = registry[event.target.value].login ?? "your-company" + let repository = ""; + + switch (event.target.value) { + case 'dockerhubRegistry': + repository = `${login}/{{ .APP }}` + break; + case 'ghcrRegistry': + repository = `ghcr.io/${login}/{{ .APP }}` + break; + default: + repository = "127.0.0.1:32447/{{ .APP }}" + } - this.props.onChange({"repository": repository, "tag": this.state.tag, "dockerfile": this.state.dockerfile, "strategy": this.state.strategy, "registry": value}) - this.setState({ registry: value }); + this.setState( + { + [name]: event.target.value, + }, + () => this.props.onChange({"repository": repository, "tag": this.state.tag, "dockerfile": this.state.dockerfile, "strategy": this.state.strategy, "registry": this.state.registry }) + ); + }; } render() { const { strategy, repository, tag, dockerfile } = this.state; const { registry } = this.props; - console.log(this.state) - return ( <>
@@ -168,9 +177,12 @@ class ImageWidget extends Component {
} {(strategy === "dockerfile" || strategy === "buildpacks") && + Object.keys(registry).length !== 0 &&
- { Object.keys(registry).map((item, idx) => { if (!registry[item].hasOwnProperty("enabled")) {