services/google/cloudbuildv2/connection.go (632 lines of code) (raw):

// Copyright 2025 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cloudbuildv2 import ( "context" "crypto/sha256" "encoding/json" "fmt" "time" "google.golang.org/api/googleapi" "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" ) type Connection struct { Name *string `json:"name"` CreateTime *string `json:"createTime"` UpdateTime *string `json:"updateTime"` GithubConfig *ConnectionGithubConfig `json:"githubConfig"` GithubEnterpriseConfig *ConnectionGithubEnterpriseConfig `json:"githubEnterpriseConfig"` GitlabConfig *ConnectionGitlabConfig `json:"gitlabConfig"` InstallationState *ConnectionInstallationState `json:"installationState"` Disabled *bool `json:"disabled"` Reconciling *bool `json:"reconciling"` Annotations map[string]string `json:"annotations"` Etag *string `json:"etag"` Project *string `json:"project"` Location *string `json:"location"` } func (r *Connection) String() string { return dcl.SprintResource(r) } // The enum ConnectionInstallationStateStageEnum. type ConnectionInstallationStateStageEnum string // ConnectionInstallationStateStageEnumRef returns a *ConnectionInstallationStateStageEnum with the value of string s // If the empty string is provided, nil is returned. func ConnectionInstallationStateStageEnumRef(s string) *ConnectionInstallationStateStageEnum { v := ConnectionInstallationStateStageEnum(s) return &v } func (v ConnectionInstallationStateStageEnum) Validate() error { if string(v) == "" { // Empty enum is okay. return nil } for _, s := range []string{"STAGE_UNSPECIFIED", "PENDING_CREATE_APP", "PENDING_USER_OAUTH", "PENDING_INSTALL_APP", "COMPLETE"} { if string(v) == s { return nil } } return &dcl.EnumInvalidError{ Enum: "ConnectionInstallationStateStageEnum", Value: string(v), Valid: []string{}, } } type ConnectionGithubConfig struct { empty bool `json:"-"` AuthorizerCredential *ConnectionGithubConfigAuthorizerCredential `json:"authorizerCredential"` AppInstallationId *int64 `json:"appInstallationId"` } type jsonConnectionGithubConfig ConnectionGithubConfig func (r *ConnectionGithubConfig) UnmarshalJSON(data []byte) error { var res jsonConnectionGithubConfig if err := json.Unmarshal(data, &res); err != nil { return err } var m map[string]interface{} json.Unmarshal(data, &m) if len(m) == 0 { *r = *EmptyConnectionGithubConfig } else { r.AuthorizerCredential = res.AuthorizerCredential r.AppInstallationId = res.AppInstallationId } return nil } // This object is used to assert a desired state where this ConnectionGithubConfig is // empty. Go lacks global const objects, but this object should be treated // as one. Modifying this object will have undesirable results. var EmptyConnectionGithubConfig *ConnectionGithubConfig = &ConnectionGithubConfig{empty: true} func (r *ConnectionGithubConfig) Empty() bool { return r.empty } func (r *ConnectionGithubConfig) String() string { return dcl.SprintResource(r) } func (r *ConnectionGithubConfig) HashCode() string { // Placeholder for a more complex hash method that handles ordering, etc // Hash resource body for easy comparison later hash := sha256.Sum256([]byte(r.String())) return fmt.Sprintf("%x", hash) } type ConnectionGithubConfigAuthorizerCredential struct { empty bool `json:"-"` OAuthTokenSecretVersion *string `json:"oauthTokenSecretVersion"` Username *string `json:"username"` } type jsonConnectionGithubConfigAuthorizerCredential ConnectionGithubConfigAuthorizerCredential func (r *ConnectionGithubConfigAuthorizerCredential) UnmarshalJSON(data []byte) error { var res jsonConnectionGithubConfigAuthorizerCredential if err := json.Unmarshal(data, &res); err != nil { return err } var m map[string]interface{} json.Unmarshal(data, &m) if len(m) == 0 { *r = *EmptyConnectionGithubConfigAuthorizerCredential } else { r.OAuthTokenSecretVersion = res.OAuthTokenSecretVersion r.Username = res.Username } return nil } // This object is used to assert a desired state where this ConnectionGithubConfigAuthorizerCredential is // empty. Go lacks global const objects, but this object should be treated // as one. Modifying this object will have undesirable results. var EmptyConnectionGithubConfigAuthorizerCredential *ConnectionGithubConfigAuthorizerCredential = &ConnectionGithubConfigAuthorizerCredential{empty: true} func (r *ConnectionGithubConfigAuthorizerCredential) Empty() bool { return r.empty } func (r *ConnectionGithubConfigAuthorizerCredential) String() string { return dcl.SprintResource(r) } func (r *ConnectionGithubConfigAuthorizerCredential) HashCode() string { // Placeholder for a more complex hash method that handles ordering, etc // Hash resource body for easy comparison later hash := sha256.Sum256([]byte(r.String())) return fmt.Sprintf("%x", hash) } type ConnectionGithubEnterpriseConfig struct { empty bool `json:"-"` HostUri *string `json:"hostUri"` AppId *int64 `json:"appId"` AppSlug *string `json:"appSlug"` PrivateKeySecretVersion *string `json:"privateKeySecretVersion"` WebhookSecretSecretVersion *string `json:"webhookSecretSecretVersion"` AppInstallationId *int64 `json:"appInstallationId"` ServiceDirectoryConfig *ConnectionGithubEnterpriseConfigServiceDirectoryConfig `json:"serviceDirectoryConfig"` SslCa *string `json:"sslCa"` } type jsonConnectionGithubEnterpriseConfig ConnectionGithubEnterpriseConfig func (r *ConnectionGithubEnterpriseConfig) UnmarshalJSON(data []byte) error { var res jsonConnectionGithubEnterpriseConfig if err := json.Unmarshal(data, &res); err != nil { return err } var m map[string]interface{} json.Unmarshal(data, &m) if len(m) == 0 { *r = *EmptyConnectionGithubEnterpriseConfig } else { r.HostUri = res.HostUri r.AppId = res.AppId r.AppSlug = res.AppSlug r.PrivateKeySecretVersion = res.PrivateKeySecretVersion r.WebhookSecretSecretVersion = res.WebhookSecretSecretVersion r.AppInstallationId = res.AppInstallationId r.ServiceDirectoryConfig = res.ServiceDirectoryConfig r.SslCa = res.SslCa } return nil } // This object is used to assert a desired state where this ConnectionGithubEnterpriseConfig is // empty. Go lacks global const objects, but this object should be treated // as one. Modifying this object will have undesirable results. var EmptyConnectionGithubEnterpriseConfig *ConnectionGithubEnterpriseConfig = &ConnectionGithubEnterpriseConfig{empty: true} func (r *ConnectionGithubEnterpriseConfig) Empty() bool { return r.empty } func (r *ConnectionGithubEnterpriseConfig) String() string { return dcl.SprintResource(r) } func (r *ConnectionGithubEnterpriseConfig) HashCode() string { // Placeholder for a more complex hash method that handles ordering, etc // Hash resource body for easy comparison later hash := sha256.Sum256([]byte(r.String())) return fmt.Sprintf("%x", hash) } type ConnectionGithubEnterpriseConfigServiceDirectoryConfig struct { empty bool `json:"-"` Service *string `json:"service"` } type jsonConnectionGithubEnterpriseConfigServiceDirectoryConfig ConnectionGithubEnterpriseConfigServiceDirectoryConfig func (r *ConnectionGithubEnterpriseConfigServiceDirectoryConfig) UnmarshalJSON(data []byte) error { var res jsonConnectionGithubEnterpriseConfigServiceDirectoryConfig if err := json.Unmarshal(data, &res); err != nil { return err } var m map[string]interface{} json.Unmarshal(data, &m) if len(m) == 0 { *r = *EmptyConnectionGithubEnterpriseConfigServiceDirectoryConfig } else { r.Service = res.Service } return nil } // This object is used to assert a desired state where this ConnectionGithubEnterpriseConfigServiceDirectoryConfig is // empty. Go lacks global const objects, but this object should be treated // as one. Modifying this object will have undesirable results. var EmptyConnectionGithubEnterpriseConfigServiceDirectoryConfig *ConnectionGithubEnterpriseConfigServiceDirectoryConfig = &ConnectionGithubEnterpriseConfigServiceDirectoryConfig{empty: true} func (r *ConnectionGithubEnterpriseConfigServiceDirectoryConfig) Empty() bool { return r.empty } func (r *ConnectionGithubEnterpriseConfigServiceDirectoryConfig) String() string { return dcl.SprintResource(r) } func (r *ConnectionGithubEnterpriseConfigServiceDirectoryConfig) HashCode() string { // Placeholder for a more complex hash method that handles ordering, etc // Hash resource body for easy comparison later hash := sha256.Sum256([]byte(r.String())) return fmt.Sprintf("%x", hash) } type ConnectionGitlabConfig struct { empty bool `json:"-"` HostUri *string `json:"hostUri"` WebhookSecretSecretVersion *string `json:"webhookSecretSecretVersion"` ReadAuthorizerCredential *ConnectionGitlabConfigReadAuthorizerCredential `json:"readAuthorizerCredential"` AuthorizerCredential *ConnectionGitlabConfigAuthorizerCredential `json:"authorizerCredential"` ServiceDirectoryConfig *ConnectionGitlabConfigServiceDirectoryConfig `json:"serviceDirectoryConfig"` SslCa *string `json:"sslCa"` ServerVersion *string `json:"serverVersion"` } type jsonConnectionGitlabConfig ConnectionGitlabConfig func (r *ConnectionGitlabConfig) UnmarshalJSON(data []byte) error { var res jsonConnectionGitlabConfig if err := json.Unmarshal(data, &res); err != nil { return err } var m map[string]interface{} json.Unmarshal(data, &m) if len(m) == 0 { *r = *EmptyConnectionGitlabConfig } else { r.HostUri = res.HostUri r.WebhookSecretSecretVersion = res.WebhookSecretSecretVersion r.ReadAuthorizerCredential = res.ReadAuthorizerCredential r.AuthorizerCredential = res.AuthorizerCredential r.ServiceDirectoryConfig = res.ServiceDirectoryConfig r.SslCa = res.SslCa r.ServerVersion = res.ServerVersion } return nil } // This object is used to assert a desired state where this ConnectionGitlabConfig is // empty. Go lacks global const objects, but this object should be treated // as one. Modifying this object will have undesirable results. var EmptyConnectionGitlabConfig *ConnectionGitlabConfig = &ConnectionGitlabConfig{empty: true} func (r *ConnectionGitlabConfig) Empty() bool { return r.empty } func (r *ConnectionGitlabConfig) String() string { return dcl.SprintResource(r) } func (r *ConnectionGitlabConfig) HashCode() string { // Placeholder for a more complex hash method that handles ordering, etc // Hash resource body for easy comparison later hash := sha256.Sum256([]byte(r.String())) return fmt.Sprintf("%x", hash) } type ConnectionGitlabConfigReadAuthorizerCredential struct { empty bool `json:"-"` UserTokenSecretVersion *string `json:"userTokenSecretVersion"` Username *string `json:"username"` } type jsonConnectionGitlabConfigReadAuthorizerCredential ConnectionGitlabConfigReadAuthorizerCredential func (r *ConnectionGitlabConfigReadAuthorizerCredential) UnmarshalJSON(data []byte) error { var res jsonConnectionGitlabConfigReadAuthorizerCredential if err := json.Unmarshal(data, &res); err != nil { return err } var m map[string]interface{} json.Unmarshal(data, &m) if len(m) == 0 { *r = *EmptyConnectionGitlabConfigReadAuthorizerCredential } else { r.UserTokenSecretVersion = res.UserTokenSecretVersion r.Username = res.Username } return nil } // This object is used to assert a desired state where this ConnectionGitlabConfigReadAuthorizerCredential is // empty. Go lacks global const objects, but this object should be treated // as one. Modifying this object will have undesirable results. var EmptyConnectionGitlabConfigReadAuthorizerCredential *ConnectionGitlabConfigReadAuthorizerCredential = &ConnectionGitlabConfigReadAuthorizerCredential{empty: true} func (r *ConnectionGitlabConfigReadAuthorizerCredential) Empty() bool { return r.empty } func (r *ConnectionGitlabConfigReadAuthorizerCredential) String() string { return dcl.SprintResource(r) } func (r *ConnectionGitlabConfigReadAuthorizerCredential) HashCode() string { // Placeholder for a more complex hash method that handles ordering, etc // Hash resource body for easy comparison later hash := sha256.Sum256([]byte(r.String())) return fmt.Sprintf("%x", hash) } type ConnectionGitlabConfigAuthorizerCredential struct { empty bool `json:"-"` UserTokenSecretVersion *string `json:"userTokenSecretVersion"` Username *string `json:"username"` } type jsonConnectionGitlabConfigAuthorizerCredential ConnectionGitlabConfigAuthorizerCredential func (r *ConnectionGitlabConfigAuthorizerCredential) UnmarshalJSON(data []byte) error { var res jsonConnectionGitlabConfigAuthorizerCredential if err := json.Unmarshal(data, &res); err != nil { return err } var m map[string]interface{} json.Unmarshal(data, &m) if len(m) == 0 { *r = *EmptyConnectionGitlabConfigAuthorizerCredential } else { r.UserTokenSecretVersion = res.UserTokenSecretVersion r.Username = res.Username } return nil } // This object is used to assert a desired state where this ConnectionGitlabConfigAuthorizerCredential is // empty. Go lacks global const objects, but this object should be treated // as one. Modifying this object will have undesirable results. var EmptyConnectionGitlabConfigAuthorizerCredential *ConnectionGitlabConfigAuthorizerCredential = &ConnectionGitlabConfigAuthorizerCredential{empty: true} func (r *ConnectionGitlabConfigAuthorizerCredential) Empty() bool { return r.empty } func (r *ConnectionGitlabConfigAuthorizerCredential) String() string { return dcl.SprintResource(r) } func (r *ConnectionGitlabConfigAuthorizerCredential) HashCode() string { // Placeholder for a more complex hash method that handles ordering, etc // Hash resource body for easy comparison later hash := sha256.Sum256([]byte(r.String())) return fmt.Sprintf("%x", hash) } type ConnectionGitlabConfigServiceDirectoryConfig struct { empty bool `json:"-"` Service *string `json:"service"` } type jsonConnectionGitlabConfigServiceDirectoryConfig ConnectionGitlabConfigServiceDirectoryConfig func (r *ConnectionGitlabConfigServiceDirectoryConfig) UnmarshalJSON(data []byte) error { var res jsonConnectionGitlabConfigServiceDirectoryConfig if err := json.Unmarshal(data, &res); err != nil { return err } var m map[string]interface{} json.Unmarshal(data, &m) if len(m) == 0 { *r = *EmptyConnectionGitlabConfigServiceDirectoryConfig } else { r.Service = res.Service } return nil } // This object is used to assert a desired state where this ConnectionGitlabConfigServiceDirectoryConfig is // empty. Go lacks global const objects, but this object should be treated // as one. Modifying this object will have undesirable results. var EmptyConnectionGitlabConfigServiceDirectoryConfig *ConnectionGitlabConfigServiceDirectoryConfig = &ConnectionGitlabConfigServiceDirectoryConfig{empty: true} func (r *ConnectionGitlabConfigServiceDirectoryConfig) Empty() bool { return r.empty } func (r *ConnectionGitlabConfigServiceDirectoryConfig) String() string { return dcl.SprintResource(r) } func (r *ConnectionGitlabConfigServiceDirectoryConfig) HashCode() string { // Placeholder for a more complex hash method that handles ordering, etc // Hash resource body for easy comparison later hash := sha256.Sum256([]byte(r.String())) return fmt.Sprintf("%x", hash) } type ConnectionInstallationState struct { empty bool `json:"-"` Stage *ConnectionInstallationStateStageEnum `json:"stage"` Message *string `json:"message"` ActionUri *string `json:"actionUri"` } type jsonConnectionInstallationState ConnectionInstallationState func (r *ConnectionInstallationState) UnmarshalJSON(data []byte) error { var res jsonConnectionInstallationState if err := json.Unmarshal(data, &res); err != nil { return err } var m map[string]interface{} json.Unmarshal(data, &m) if len(m) == 0 { *r = *EmptyConnectionInstallationState } else { r.Stage = res.Stage r.Message = res.Message r.ActionUri = res.ActionUri } return nil } // This object is used to assert a desired state where this ConnectionInstallationState is // empty. Go lacks global const objects, but this object should be treated // as one. Modifying this object will have undesirable results. var EmptyConnectionInstallationState *ConnectionInstallationState = &ConnectionInstallationState{empty: true} func (r *ConnectionInstallationState) Empty() bool { return r.empty } func (r *ConnectionInstallationState) String() string { return dcl.SprintResource(r) } func (r *ConnectionInstallationState) HashCode() string { // Placeholder for a more complex hash method that handles ordering, etc // Hash resource body for easy comparison later hash := sha256.Sum256([]byte(r.String())) return fmt.Sprintf("%x", hash) } // Describe returns a simple description of this resource to ensure that automated tools // can identify it. func (r *Connection) Describe() dcl.ServiceTypeVersion { return dcl.ServiceTypeVersion{ Service: "cloudbuildv2", Type: "Connection", Version: "cloudbuildv2", } } func (r *Connection) ID() (string, error) { if err := extractConnectionFields(r); err != nil { return "", err } nr := r.urlNormalized() params := map[string]interface{}{ "name": dcl.ValueOrEmptyString(nr.Name), "create_time": dcl.ValueOrEmptyString(nr.CreateTime), "update_time": dcl.ValueOrEmptyString(nr.UpdateTime), "github_config": dcl.ValueOrEmptyString(nr.GithubConfig), "github_enterprise_config": dcl.ValueOrEmptyString(nr.GithubEnterpriseConfig), "gitlab_config": dcl.ValueOrEmptyString(nr.GitlabConfig), "installation_state": dcl.ValueOrEmptyString(nr.InstallationState), "disabled": dcl.ValueOrEmptyString(nr.Disabled), "reconciling": dcl.ValueOrEmptyString(nr.Reconciling), "annotations": dcl.ValueOrEmptyString(nr.Annotations), "etag": dcl.ValueOrEmptyString(nr.Etag), "project": dcl.ValueOrEmptyString(nr.Project), "location": dcl.ValueOrEmptyString(nr.Location), } return dcl.Nprintf("projects/{{project}}/locations/{{location}}/connections/{{name}}", params), nil } const ConnectionMaxPage = -1 type ConnectionList struct { Items []*Connection nextToken string pageSize int32 resource *Connection } func (l *ConnectionList) HasNext() bool { return l.nextToken != "" } func (l *ConnectionList) Next(ctx context.Context, c *Client) error { ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) defer cancel() if !l.HasNext() { return fmt.Errorf("no next page") } items, token, err := c.listConnection(ctx, l.resource, l.nextToken, l.pageSize) if err != nil { return err } l.Items = items l.nextToken = token return err } func (c *Client) ListConnection(ctx context.Context, project, location string) (*ConnectionList, error) { ctx = dcl.ContextWithRequestID(ctx) ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) defer cancel() return c.ListConnectionWithMaxResults(ctx, project, location, ConnectionMaxPage) } func (c *Client) ListConnectionWithMaxResults(ctx context.Context, project, location string, pageSize int32) (*ConnectionList, error) { ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) defer cancel() // Create a resource object so that we can use proper url normalization methods. r := &Connection{ Project: &project, Location: &location, } items, token, err := c.listConnection(ctx, r, "", pageSize) if err != nil { return nil, err } return &ConnectionList{ Items: items, nextToken: token, pageSize: pageSize, resource: r, }, nil } func (c *Client) GetConnection(ctx context.Context, r *Connection) (*Connection, error) { ctx = dcl.ContextWithRequestID(ctx) ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) defer cancel() // This is *purposefully* supressing errors. // This function is used with url-normalized values + not URL normalized values. // URL Normalized values will throw unintentional errors, since those values are not of the proper parent form. extractConnectionFields(r) b, err := c.getConnectionRaw(ctx, r) if err != nil { if dcl.IsNotFound(err) { return nil, &googleapi.Error{ Code: 404, Message: err.Error(), } } return nil, err } result, err := unmarshalConnection(b, c, r) if err != nil { return nil, err } result.Project = r.Project result.Location = r.Location result.Name = r.Name c.Config.Logger.InfoWithContextf(ctx, "Retrieved raw result state: %v", result) c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with specified state: %v", r) result, err = canonicalizeConnectionNewState(c, result, r) if err != nil { return nil, err } if err := postReadExtractConnectionFields(result); err != nil { return result, err } c.Config.Logger.InfoWithContextf(ctx, "Created result state: %v", result) return result, nil } func (c *Client) DeleteConnection(ctx context.Context, r *Connection) error { ctx = dcl.ContextWithRequestID(ctx) ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) defer cancel() if r == nil { return fmt.Errorf("Connection resource is nil") } c.Config.Logger.InfoWithContext(ctx, "Deleting Connection...") deleteOp := deleteConnectionOperation{} return deleteOp.do(ctx, r, c) } // DeleteAllConnection deletes all resources that the filter functions returns true on. func (c *Client) DeleteAllConnection(ctx context.Context, project, location string, filter func(*Connection) bool) error { listObj, err := c.ListConnection(ctx, project, location) if err != nil { return err } err = c.deleteAllConnection(ctx, filter, listObj.Items) if err != nil { return err } for listObj.HasNext() { err = listObj.Next(ctx, c) if err != nil { return nil } err = c.deleteAllConnection(ctx, filter, listObj.Items) if err != nil { return err } } return nil } func (c *Client) ApplyConnection(ctx context.Context, rawDesired *Connection, opts ...dcl.ApplyOption) (*Connection, error) { ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) defer cancel() ctx = dcl.ContextWithRequestID(ctx) var resultNewState *Connection err := dcl.Do(ctx, func(ctx context.Context) (*dcl.RetryDetails, error) { newState, err := applyConnectionHelper(c, ctx, rawDesired, opts...) resultNewState = newState if err != nil { // If the error is 409, there is conflict in resource update. // Here we want to apply changes based on latest state. if dcl.IsConflictError(err) { return &dcl.RetryDetails{}, dcl.OperationNotDone{Err: err} } return nil, err } return nil, nil }, c.Config.RetryProvider) return resultNewState, err } func applyConnectionHelper(c *Client, ctx context.Context, rawDesired *Connection, opts ...dcl.ApplyOption) (*Connection, error) { c.Config.Logger.InfoWithContext(ctx, "Beginning ApplyConnection...") c.Config.Logger.InfoWithContextf(ctx, "User specified desired state: %v", rawDesired) // 1.1: Validation of user-specified fields in desired state. if err := rawDesired.validate(); err != nil { return nil, err } if err := extractConnectionFields(rawDesired); err != nil { return nil, err } initial, desired, fieldDiffs, err := c.connectionDiffsForRawDesired(ctx, rawDesired, opts...) if err != nil { return nil, fmt.Errorf("failed to create a diff: %w", err) } diffs, err := convertFieldDiffsToConnectionDiffs(c.Config, fieldDiffs, opts) if err != nil { return nil, err } // TODO(magic-modules-eng): 2.2 Feasibility check (all updates are feasible so far). // 2.3: Lifecycle Directive Check var create bool lp := dcl.FetchLifecycleParams(opts) if initial == nil { if dcl.HasLifecycleParam(lp, dcl.BlockCreation) { return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Creation blocked by lifecycle params: %#v.", desired)} } create = true } else if dcl.HasLifecycleParam(lp, dcl.BlockAcquire) { return nil, dcl.ApplyInfeasibleError{ Message: fmt.Sprintf("Resource already exists - apply blocked by lifecycle params: %#v.", initial), } } else { for _, d := range diffs { if d.RequiresRecreate { return nil, dcl.ApplyInfeasibleError{ Message: fmt.Sprintf("infeasible update: (%v) would require recreation", d), } } if dcl.HasLifecycleParam(lp, dcl.BlockModification) { return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Modification blocked, diff (%v) unresolvable.", d)} } } } // 2.4 Imperative Request Planning var ops []connectionApiOperation if create { ops = append(ops, &createConnectionOperation{}) } else { for _, d := range diffs { ops = append(ops, d.UpdateOp) } } c.Config.Logger.InfoWithContextf(ctx, "Created plan: %#v", ops) // 2.5 Request Actuation for _, op := range ops { c.Config.Logger.InfoWithContextf(ctx, "Performing operation %T %+v", op, op) if err := op.do(ctx, desired, c); err != nil { c.Config.Logger.InfoWithContextf(ctx, "Failed operation %T %+v: %v", op, op, err) return nil, err } c.Config.Logger.InfoWithContextf(ctx, "Finished operation %T %+v", op, op) } return applyConnectionDiff(c, ctx, desired, rawDesired, ops, opts...) } func applyConnectionDiff(c *Client, ctx context.Context, desired *Connection, rawDesired *Connection, ops []connectionApiOperation, opts ...dcl.ApplyOption) (*Connection, error) { // 3.1, 3.2a Retrieval of raw new state & canonicalization with desired state c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state...") rawNew, err := c.GetConnection(ctx, desired) if err != nil { return nil, err } // Get additional values from the first response. // These values should be merged into the newState above. if len(ops) > 0 { lastOp := ops[len(ops)-1] if o, ok := lastOp.(*createConnectionOperation); ok { if r, hasR := o.FirstResponse(); hasR { c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state from operation...") fullResp, err := unmarshalMapConnection(r, c, rawDesired) if err != nil { return nil, err } rawNew, err = canonicalizeConnectionNewState(c, rawNew, fullResp) if err != nil { return nil, err } } } } c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with raw desired state: %v", rawDesired) // 3.2b Canonicalization of raw new state using raw desired state newState, err := canonicalizeConnectionNewState(c, rawNew, rawDesired) if err != nil { return rawNew, err } c.Config.Logger.InfoWithContextf(ctx, "Created canonical new state: %v", newState) // 3.3 Comparison of the new state and raw desired state. // TODO(magic-modules-eng): EVENTUALLY_CONSISTENT_UPDATE newDesired, err := canonicalizeConnectionDesiredState(rawDesired, newState) if err != nil { return newState, err } if err := postReadExtractConnectionFields(newState); err != nil { return newState, err } // Need to ensure any transformations made here match acceptably in differ. if err := postReadExtractConnectionFields(newDesired); err != nil { return newState, err } c.Config.Logger.InfoWithContextf(ctx, "Diffing using canonicalized desired state: %v", newDesired) newDiffs, err := diffConnection(c, newDesired, newState) if err != nil { return newState, err } if len(newDiffs) == 0 { c.Config.Logger.InfoWithContext(ctx, "No diffs found. Apply was successful.") } else { c.Config.Logger.InfoWithContextf(ctx, "Found diffs: %v", newDiffs) diffMessages := make([]string, len(newDiffs)) for i, d := range newDiffs { diffMessages[i] = fmt.Sprintf("%v", d) } return newState, dcl.DiffAfterApplyError{Diffs: diffMessages} } c.Config.Logger.InfoWithContext(ctx, "Done Apply.") return newState, nil }