app/registry/external_system.go (238 lines of code) (raw):

package registry import ( "ddm-admin-console/router" "fmt" "net/http" "strings" "time" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) const ( authTypeNoAuth = "NO_AUTH" authTypeAuthToken = "AUTH_TOKEN" authTypeBearer = "BEARER" authTypeBasic = "BASIC" authTypeAuthTokenBearer = "AUTH_TOKEN+BEARER" registryNamePlaceholder = "{NAME_REGISTRY}" ) type RegistryExternalSystemForm struct { RegistryName string `form:"external-system-registry-name" binding:"required"` URL string `form:"external-system-url"` Protocol string `form:"external-system-protocol" binding:"required"` AuthType string `form:"external-system-auth-type" binding:"required"` AuthURL string `form:"external-system-auth-url"` AccessTokenJSONPath string `form:"external-system-auth-access-token-json-path"` AuthSecret string `form:"external-system-auth-secret"` AuthUsername string `form:"external-system-auth-username"` } func externalSystemsSecretPath(vaultRegistryPath string, exRegistryName string) string { return fmt.Sprintf("%s/external-systems/%s-%s", vaultRegistryPath, exRegistryName, time.Now().Format("20060201T150405Z")) } func externalSystemSecretPrefixedPath(originalPath string) string { return fmt.Sprintf("vault:%s", originalPath) } func (f RegistryExternalSystemForm) ToNestedForm(vaultRegistryPath, wiremockAddr string) ExternalSystem { es := ExternalSystem{ URL: f.URL, Protocol: f.Protocol, Auth: map[string]string{ "type": f.AuthType, }, } if f.AuthType != authTypeNoAuth { es.Auth["secret"] = externalSystemSecretPrefixedPath(vaultRegistryPath) } if f.AuthType == authTypeAuthTokenBearer { es.Auth["auth-url"] = f.AuthURL es.Auth["access-token-json-path"] = f.AccessTokenJSONPath } if es.URL == "" { es.Mock = true es.URL = wiremockAddr } return es } func (a *App) getBasicUsername(ctx *gin.Context) (rsp router.Response, retErr error) { registryName := ctx.Param("name") systemRegsitryName := ctx.Query("registry-name") if systemRegsitryName == "" { return nil, errors.New("bad request") } values, err := GetValuesFromGit(registryName, MasterBranch, a.Gerrit) if err != nil { return nil, errors.Wrap(err, "unable to get values") } cbService, err := a.Services.Codebase.ServiceForContext(router.ContextWithUserAccessToken(ctx)) if err != nil { return nil, fmt.Errorf("unable to init service for user context, %w", err) } _, err = cbService.Get(registryName) if err != nil { return nil, fmt.Errorf("unable to find registry, %w", err) } secret := values.ExternalSystems[systemRegsitryName].Auth["secret"] dataDict, err := a.Vault.Read(secret) if err != nil { return nil, fmt.Errorf("unable to load id-gov-ua secret, err: %w", err) } d, ok := dataDict[fmt.Sprintf("external-systems.%s.auth.secret.username", systemRegsitryName)] if !ok { return nil, errors.New("no basic data") } str, ok := d.(string) if !ok { return nil, errors.New("wrong basic data") } return router.MakeJSONResponse(200, str), nil } func (a *App) deleteExternalSystem(ctx *gin.Context) (rsp router.Response, retErr error) { registryName := ctx.Param("name") _, err := a.Codebase.Get(registryName) if err != nil { return nil, errors.Wrap(err, "unable to find registry") } exSystemName := ctx.Query("external-system") values, err := GetValuesFromGit(registryName, MasterBranch, a.Gerrit) if err != nil { return nil, errors.Wrap(err, "unable to get values") } eSys, ok := values.ExternalSystems[exSystemName] if !ok { return nil, errors.New("external system does not exists") } if eSys.Type == "platform" { return nil, errors.New("external system is unavailable to delete") } delete(values.ExternalSystems, exSystemName) values.OriginalYaml[externalSystemsKey] = values.ExternalSystems if err := CreateEditMergeRequest(ctx, registryName, values.OriginalYaml, a.Gerrit, []string{}); err != nil { return nil, errors.Wrap(err, "unable to create merge request") } return router.MakeRedirectResponse(http.StatusFound, fmt.Sprintf("/admin/registry/view/%s", registryName)), nil } func (a *App) checkExternalSystemExists(ctx *gin.Context) (rsp router.Response, retErr error) { registryName := ctx.Param("name") _, err := a.Codebase.Get(registryName) if err != nil { return nil, errors.Wrap(err, "unable to find registry") } exSystemName := ctx.Query("external-system") values, err := GetValuesFromGit(registryName, MasterBranch, a.Gerrit) if err != nil { return nil, errors.Wrap(err, "unable to get values") } _, ok := values.ExternalSystems[exSystemName] if ok { return router.MakeStatusResponse(http.StatusOK), nil } return router.MakeStatusResponse(http.StatusNotFound), nil } func (a *App) createExternalSystemRegistry(ctx *gin.Context) (rsp router.Response, retErr error) { registryName := ctx.Param("name") _, err := a.Codebase.Get(registryName) if err != nil { return nil, errors.Wrap(err, "unable to find registry") } var f RegistryExternalSystemForm if err := ctx.ShouldBind(&f); err != nil { return nil, errors.Wrap(err, "unable to parse form") } values, err := GetValuesFromGit(registryName, MasterBranch, a.Gerrit) if err != nil { return nil, errors.Wrap(err, "unable to get values") } _, ok := values.ExternalSystems[f.RegistryName] if ok { return nil, errors.Wrap(err, "external system already exists") } var secretPath = externalSystemsSecretPath(a.vaultRegistryPath(registryName), f.RegistryName) extenalSystem := f.ToNestedForm(secretPath, strings.ReplaceAll(a.WiremockAddr, registryNamePlaceholder, registryName)) extenalSystem.Protocol = externalSystemDefaultProtocol extenalSystem.Type = externalSystemDeletableType valuesExternalSystems, ok := values.OriginalYaml[externalSystemsKey] if !ok { return nil, errors.Wrap(err, "no external systems key in values") } valuesExternalSystemsDict := valuesExternalSystems.(map[string]interface{}) valuesExternalSystemsDict[f.RegistryName] = extenalSystem values.OriginalYaml[externalSystemsKey] = valuesExternalSystemsDict if err := a.setExternalSystemRegistrySecrets(&f, secretPath); err != nil { return nil, errors.Wrap(err, "unable to set external system") } if err := CreateEditMergeRequest(ctx, registryName, values.OriginalYaml, a.Gerrit, []string{}); err != nil { return nil, errors.Wrap(err, "unable to create merge request") } return router.MakeRedirectResponse(http.StatusFound, fmt.Sprintf("/admin/registry/view/%s", registryName)), nil } // edit func (a *App) setExternalSystemRegistryData(ctx *gin.Context) (rsp router.Response, retErr error) { registryName := ctx.Param("name") _, err := a.Codebase.Get(registryName) if err != nil { return nil, errors.Wrap(err, "unable to find registry") } var f RegistryExternalSystemForm if err := ctx.ShouldBind(&f); err != nil { return nil, errors.Wrap(err, "unable to parse form") } var secretPath = externalSystemsSecretPath(a.vaultRegistryPath(registryName), f.RegistryName) values, err := GetValuesFromGit(registryName, MasterBranch, a.Gerrit) if err != nil { return nil, errors.Wrap(err, "unable to get values") } valuesExternalSystem, ok := values.ExternalSystems[f.RegistryName] if !ok { return nil, errors.Wrap(err, "unable to get external system") } editExtenalSystem := f.ToNestedForm(secretPath, strings.ReplaceAll(a.WiremockAddr, registryNamePlaceholder, registryName)) editExtenalSystem.Type = valuesExternalSystem.Type editExtenalSystem.Protocol = valuesExternalSystem.Protocol valuesExternalSystems, ok := values.OriginalYaml[externalSystemsKey] if !ok { return nil, errors.Wrap(err, "no external systems key in values") } valuesExternalSystemsDict := valuesExternalSystems.(map[string]interface{}) valuesExternalSystemsDict[f.RegistryName] = editExtenalSystem values.OriginalYaml[externalSystemsKey] = valuesExternalSystemsDict if err := a.setExternalSystemRegistrySecrets(&f, secretPath); err != nil { return nil, errors.Wrap(err, "unable to set external system") } if err := CreateEditMergeRequest(ctx, registryName, values.OriginalYaml, a.Gerrit, []string{}); err != nil { return nil, errors.Wrap(err, "unable to create merge request") } return router.MakeRedirectResponse(http.StatusFound, fmt.Sprintf("/admin/registry/view/%s", registryName)), nil } func (a *App) setExternalSystemRegistrySecrets(f *RegistryExternalSystemForm, secretPath string) error { secretData := make(map[string]interface{}) prefixedPath := externalSystemSecretPrefixedPath(secretPath) createSecrets := false if f.AuthType == authTypeAuthToken || f.AuthType == authTypeAuthTokenBearer || f.AuthType == authTypeBearer { if f.AuthSecret == prefixedPath { return nil } secretData[fmt.Sprintf("external-systems.%s.auth.secret.token", f.RegistryName)] = f.AuthSecret createSecrets = true } else if f.AuthType == authTypeBasic { if f.AuthUsername != prefixedPath { secretData[fmt.Sprintf("external-systems.%s.auth.secret.username", f.RegistryName)] = f.AuthUsername createSecrets = true } if f.AuthSecret != prefixedPath { secretData[fmt.Sprintf("external-systems.%s.auth.secret.password", f.RegistryName)] = f.AuthSecret createSecrets = true } } if !createSecrets { return nil } if err := CreateVaultSecrets(a.Vault, map[string]map[string]interface{}{ secretPath: secretData, }, true); err != nil { return errors.Wrap(err, "unable to create auth token secret") } return nil }