services/google/compute/beta/forwarding_rule.go (593 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 beta
import (
"context"
"crypto/sha256"
"encoding/json"
"fmt"
"time"
"google.golang.org/api/googleapi"
"github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl"
)
type ForwardingRule struct {
Labels map[string]string `json:"labels"`
AllPorts *bool `json:"allPorts"`
AllowGlobalAccess *bool `json:"allowGlobalAccess"`
LabelFingerprint *string `json:"labelFingerprint"`
BackendService *string `json:"backendService"`
CreationTimestamp *string `json:"creationTimestamp"`
Description *string `json:"description"`
IPAddress *string `json:"ipAddress"`
IPProtocol *ForwardingRuleIPProtocolEnum `json:"ipProtocol"`
IPVersion *ForwardingRuleIPVersionEnum `json:"ipVersion"`
IsMirroringCollector *bool `json:"isMirroringCollector"`
LoadBalancingScheme *ForwardingRuleLoadBalancingSchemeEnum `json:"loadBalancingScheme"`
MetadataFilter []ForwardingRuleMetadataFilter `json:"metadataFilter"`
Name *string `json:"name"`
Network *string `json:"network"`
NetworkTier *ForwardingRuleNetworkTierEnum `json:"networkTier"`
PortRange *string `json:"portRange"`
Ports []string `json:"ports"`
Region *string `json:"region"`
SelfLink *string `json:"selfLink"`
ServiceLabel *string `json:"serviceLabel"`
ServiceName *string `json:"serviceName"`
Subnetwork *string `json:"subnetwork"`
Target *string `json:"target"`
Project *string `json:"project"`
Location *string `json:"location"`
ServiceDirectoryRegistrations []ForwardingRuleServiceDirectoryRegistrations `json:"serviceDirectoryRegistrations"`
PscConnectionId *string `json:"pscConnectionId"`
PscConnectionStatus *ForwardingRulePscConnectionStatusEnum `json:"pscConnectionStatus"`
SourceIPRanges []string `json:"sourceIPRanges"`
BaseForwardingRule *string `json:"baseForwardingRule"`
AllowPscGlobalAccess *bool `json:"allowPscGlobalAccess"`
}
func (r *ForwardingRule) String() string {
return dcl.SprintResource(r)
}
// The enum ForwardingRuleIPProtocolEnum.
type ForwardingRuleIPProtocolEnum string
// ForwardingRuleIPProtocolEnumRef returns a *ForwardingRuleIPProtocolEnum with the value of string s
// If the empty string is provided, nil is returned.
func ForwardingRuleIPProtocolEnumRef(s string) *ForwardingRuleIPProtocolEnum {
v := ForwardingRuleIPProtocolEnum(s)
return &v
}
func (v ForwardingRuleIPProtocolEnum) Validate() error {
if string(v) == "" {
// Empty enum is okay.
return nil
}
for _, s := range []string{"TCP", "UDP", "ESP", "AH", "SCTP", "ICMP", "L3_DEFAULT"} {
if string(v) == s {
return nil
}
}
return &dcl.EnumInvalidError{
Enum: "ForwardingRuleIPProtocolEnum",
Value: string(v),
Valid: []string{},
}
}
// The enum ForwardingRuleIPVersionEnum.
type ForwardingRuleIPVersionEnum string
// ForwardingRuleIPVersionEnumRef returns a *ForwardingRuleIPVersionEnum with the value of string s
// If the empty string is provided, nil is returned.
func ForwardingRuleIPVersionEnumRef(s string) *ForwardingRuleIPVersionEnum {
v := ForwardingRuleIPVersionEnum(s)
return &v
}
func (v ForwardingRuleIPVersionEnum) Validate() error {
if string(v) == "" {
// Empty enum is okay.
return nil
}
for _, s := range []string{"UNSPECIFIED_VERSION", "IPV4", "IPV6"} {
if string(v) == s {
return nil
}
}
return &dcl.EnumInvalidError{
Enum: "ForwardingRuleIPVersionEnum",
Value: string(v),
Valid: []string{},
}
}
// The enum ForwardingRuleLoadBalancingSchemeEnum.
type ForwardingRuleLoadBalancingSchemeEnum string
// ForwardingRuleLoadBalancingSchemeEnumRef returns a *ForwardingRuleLoadBalancingSchemeEnum with the value of string s
// If the empty string is provided, nil is returned.
func ForwardingRuleLoadBalancingSchemeEnumRef(s string) *ForwardingRuleLoadBalancingSchemeEnum {
v := ForwardingRuleLoadBalancingSchemeEnum(s)
return &v
}
func (v ForwardingRuleLoadBalancingSchemeEnum) Validate() error {
if string(v) == "" {
// Empty enum is okay.
return nil
}
for _, s := range []string{"INVALID", "INTERNAL", "INTERNAL_MANAGED", "INTERNAL_SELF_MANAGED", "EXTERNAL", "EXTERNAL_MANAGED"} {
if string(v) == s {
return nil
}
}
return &dcl.EnumInvalidError{
Enum: "ForwardingRuleLoadBalancingSchemeEnum",
Value: string(v),
Valid: []string{},
}
}
// The enum ForwardingRuleMetadataFilterFilterMatchCriteriaEnum.
type ForwardingRuleMetadataFilterFilterMatchCriteriaEnum string
// ForwardingRuleMetadataFilterFilterMatchCriteriaEnumRef returns a *ForwardingRuleMetadataFilterFilterMatchCriteriaEnum with the value of string s
// If the empty string is provided, nil is returned.
func ForwardingRuleMetadataFilterFilterMatchCriteriaEnumRef(s string) *ForwardingRuleMetadataFilterFilterMatchCriteriaEnum {
v := ForwardingRuleMetadataFilterFilterMatchCriteriaEnum(s)
return &v
}
func (v ForwardingRuleMetadataFilterFilterMatchCriteriaEnum) Validate() error {
if string(v) == "" {
// Empty enum is okay.
return nil
}
for _, s := range []string{"NOT_SET", "MATCH_ALL", "MATCH_ANY"} {
if string(v) == s {
return nil
}
}
return &dcl.EnumInvalidError{
Enum: "ForwardingRuleMetadataFilterFilterMatchCriteriaEnum",
Value: string(v),
Valid: []string{},
}
}
// The enum ForwardingRuleNetworkTierEnum.
type ForwardingRuleNetworkTierEnum string
// ForwardingRuleNetworkTierEnumRef returns a *ForwardingRuleNetworkTierEnum with the value of string s
// If the empty string is provided, nil is returned.
func ForwardingRuleNetworkTierEnumRef(s string) *ForwardingRuleNetworkTierEnum {
v := ForwardingRuleNetworkTierEnum(s)
return &v
}
func (v ForwardingRuleNetworkTierEnum) Validate() error {
if string(v) == "" {
// Empty enum is okay.
return nil
}
for _, s := range []string{"PREMIUM", "STANDARD"} {
if string(v) == s {
return nil
}
}
return &dcl.EnumInvalidError{
Enum: "ForwardingRuleNetworkTierEnum",
Value: string(v),
Valid: []string{},
}
}
// The enum ForwardingRulePscConnectionStatusEnum.
type ForwardingRulePscConnectionStatusEnum string
// ForwardingRulePscConnectionStatusEnumRef returns a *ForwardingRulePscConnectionStatusEnum with the value of string s
// If the empty string is provided, nil is returned.
func ForwardingRulePscConnectionStatusEnumRef(s string) *ForwardingRulePscConnectionStatusEnum {
v := ForwardingRulePscConnectionStatusEnum(s)
return &v
}
func (v ForwardingRulePscConnectionStatusEnum) Validate() error {
if string(v) == "" {
// Empty enum is okay.
return nil
}
for _, s := range []string{"STATUS_UNSPECIFIED", "PENDING", "ACCEPTED", "REJECTED", "CLOSED"} {
if string(v) == s {
return nil
}
}
return &dcl.EnumInvalidError{
Enum: "ForwardingRulePscConnectionStatusEnum",
Value: string(v),
Valid: []string{},
}
}
type ForwardingRuleMetadataFilter struct {
empty bool `json:"-"`
FilterMatchCriteria *ForwardingRuleMetadataFilterFilterMatchCriteriaEnum `json:"filterMatchCriteria"`
FilterLabel []ForwardingRuleMetadataFilterFilterLabel `json:"filterLabel"`
}
type jsonForwardingRuleMetadataFilter ForwardingRuleMetadataFilter
func (r *ForwardingRuleMetadataFilter) UnmarshalJSON(data []byte) error {
var res jsonForwardingRuleMetadataFilter
if err := json.Unmarshal(data, &res); err != nil {
return err
}
var m map[string]interface{}
json.Unmarshal(data, &m)
if len(m) == 0 {
*r = *EmptyForwardingRuleMetadataFilter
} else {
r.FilterMatchCriteria = res.FilterMatchCriteria
r.FilterLabel = res.FilterLabel
}
return nil
}
// This object is used to assert a desired state where this ForwardingRuleMetadataFilter is
// empty. Go lacks global const objects, but this object should be treated
// as one. Modifying this object will have undesirable results.
var EmptyForwardingRuleMetadataFilter *ForwardingRuleMetadataFilter = &ForwardingRuleMetadataFilter{empty: true}
func (r *ForwardingRuleMetadataFilter) Empty() bool {
return r.empty
}
func (r *ForwardingRuleMetadataFilter) String() string {
return dcl.SprintResource(r)
}
func (r *ForwardingRuleMetadataFilter) 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 ForwardingRuleMetadataFilterFilterLabel struct {
empty bool `json:"-"`
Name *string `json:"name"`
Value *string `json:"value"`
}
type jsonForwardingRuleMetadataFilterFilterLabel ForwardingRuleMetadataFilterFilterLabel
func (r *ForwardingRuleMetadataFilterFilterLabel) UnmarshalJSON(data []byte) error {
var res jsonForwardingRuleMetadataFilterFilterLabel
if err := json.Unmarshal(data, &res); err != nil {
return err
}
var m map[string]interface{}
json.Unmarshal(data, &m)
if len(m) == 0 {
*r = *EmptyForwardingRuleMetadataFilterFilterLabel
} else {
r.Name = res.Name
r.Value = res.Value
}
return nil
}
// This object is used to assert a desired state where this ForwardingRuleMetadataFilterFilterLabel is
// empty. Go lacks global const objects, but this object should be treated
// as one. Modifying this object will have undesirable results.
var EmptyForwardingRuleMetadataFilterFilterLabel *ForwardingRuleMetadataFilterFilterLabel = &ForwardingRuleMetadataFilterFilterLabel{empty: true}
func (r *ForwardingRuleMetadataFilterFilterLabel) Empty() bool {
return r.empty
}
func (r *ForwardingRuleMetadataFilterFilterLabel) String() string {
return dcl.SprintResource(r)
}
func (r *ForwardingRuleMetadataFilterFilterLabel) 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 ForwardingRuleServiceDirectoryRegistrations struct {
empty bool `json:"-"`
Namespace *string `json:"namespace"`
Service *string `json:"service"`
}
type jsonForwardingRuleServiceDirectoryRegistrations ForwardingRuleServiceDirectoryRegistrations
func (r *ForwardingRuleServiceDirectoryRegistrations) UnmarshalJSON(data []byte) error {
var res jsonForwardingRuleServiceDirectoryRegistrations
if err := json.Unmarshal(data, &res); err != nil {
return err
}
var m map[string]interface{}
json.Unmarshal(data, &m)
if len(m) == 0 {
*r = *EmptyForwardingRuleServiceDirectoryRegistrations
} else {
r.Namespace = res.Namespace
r.Service = res.Service
}
return nil
}
// This object is used to assert a desired state where this ForwardingRuleServiceDirectoryRegistrations is
// empty. Go lacks global const objects, but this object should be treated
// as one. Modifying this object will have undesirable results.
var EmptyForwardingRuleServiceDirectoryRegistrations *ForwardingRuleServiceDirectoryRegistrations = &ForwardingRuleServiceDirectoryRegistrations{empty: true}
func (r *ForwardingRuleServiceDirectoryRegistrations) Empty() bool {
return r.empty
}
func (r *ForwardingRuleServiceDirectoryRegistrations) String() string {
return dcl.SprintResource(r)
}
func (r *ForwardingRuleServiceDirectoryRegistrations) 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 *ForwardingRule) Describe() dcl.ServiceTypeVersion {
return dcl.ServiceTypeVersion{
Service: "compute",
Type: "ForwardingRule",
Version: "beta",
}
}
func (r *ForwardingRule) ID() (string, error) {
if err := extractForwardingRuleFields(r); err != nil {
return "", err
}
nr := r.urlNormalized()
params := map[string]interface{}{
"labels": dcl.ValueOrEmptyString(nr.Labels),
"all_ports": dcl.ValueOrEmptyString(nr.AllPorts),
"allow_global_access": dcl.ValueOrEmptyString(nr.AllowGlobalAccess),
"label_fingerprint": dcl.ValueOrEmptyString(nr.LabelFingerprint),
"backend_service": dcl.ValueOrEmptyString(nr.BackendService),
"creation_timestamp": dcl.ValueOrEmptyString(nr.CreationTimestamp),
"description": dcl.ValueOrEmptyString(nr.Description),
"ip_address": dcl.ValueOrEmptyString(nr.IPAddress),
"ip_protocol": dcl.ValueOrEmptyString(nr.IPProtocol),
"ip_version": dcl.ValueOrEmptyString(nr.IPVersion),
"is_mirroring_collector": dcl.ValueOrEmptyString(nr.IsMirroringCollector),
"load_balancing_scheme": dcl.ValueOrEmptyString(nr.LoadBalancingScheme),
"metadata_filter": dcl.ValueOrEmptyString(nr.MetadataFilter),
"name": dcl.ValueOrEmptyString(nr.Name),
"network": dcl.ValueOrEmptyString(nr.Network),
"network_tier": dcl.ValueOrEmptyString(nr.NetworkTier),
"port_range": dcl.ValueOrEmptyString(nr.PortRange),
"ports": dcl.ValueOrEmptyString(nr.Ports),
"region": dcl.ValueOrEmptyString(nr.Region),
"self_link": dcl.ValueOrEmptyString(nr.SelfLink),
"service_label": dcl.ValueOrEmptyString(nr.ServiceLabel),
"service_name": dcl.ValueOrEmptyString(nr.ServiceName),
"subnetwork": dcl.ValueOrEmptyString(nr.Subnetwork),
"target": dcl.ValueOrEmptyString(nr.Target),
"project": dcl.ValueOrEmptyString(nr.Project),
"location": dcl.ValueOrEmptyString(nr.Location),
"service_directory_registrations": dcl.ValueOrEmptyString(nr.ServiceDirectoryRegistrations),
"psc_connection_id": dcl.ValueOrEmptyString(nr.PscConnectionId),
"psc_connection_status": dcl.ValueOrEmptyString(nr.PscConnectionStatus),
"source_ip_ranges": dcl.ValueOrEmptyString(nr.SourceIPRanges),
"base_forwarding_rule": dcl.ValueOrEmptyString(nr.BaseForwardingRule),
"allow_psc_global_access": dcl.ValueOrEmptyString(nr.AllowPscGlobalAccess),
}
if dcl.IsRegion(nr.Location) {
return dcl.Nprintf("projects/{{project}}/regions/{{location}}/forwardingRules/{{name}}", params), nil
}
return dcl.Nprintf("projects/{{project}}/global/forwardingRules/{{name}}", params), nil
}
const ForwardingRuleMaxPage = -1
type ForwardingRuleList struct {
Items []*ForwardingRule
nextToken string
pageSize int32
resource *ForwardingRule
}
func (l *ForwardingRuleList) HasNext() bool {
return l.nextToken != ""
}
func (l *ForwardingRuleList) 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.listForwardingRule(ctx, l.resource, l.nextToken, l.pageSize)
if err != nil {
return err
}
l.Items = items
l.nextToken = token
return err
}
func (c *Client) ListForwardingRule(ctx context.Context, project, location string) (*ForwardingRuleList, error) {
ctx = dcl.ContextWithRequestID(ctx)
c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{
412: dcl.Retryability{
Retryable: false,
Pattern: "",
Timeout: 0,
},
})))
ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second))
defer cancel()
return c.ListForwardingRuleWithMaxResults(ctx, project, location, ForwardingRuleMaxPage)
}
func (c *Client) ListForwardingRuleWithMaxResults(ctx context.Context, project, location string, pageSize int32) (*ForwardingRuleList, 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 := &ForwardingRule{
Project: &project,
Location: &location,
}
items, token, err := c.listForwardingRule(ctx, r, "", pageSize)
if err != nil {
return nil, err
}
return &ForwardingRuleList{
Items: items,
nextToken: token,
pageSize: pageSize,
resource: r,
}, nil
}
func (c *Client) GetForwardingRule(ctx context.Context, r *ForwardingRule) (*ForwardingRule, error) {
ctx = dcl.ContextWithRequestID(ctx)
c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{
412: dcl.Retryability{
Retryable: false,
Pattern: "",
Timeout: 0,
},
})))
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.
extractForwardingRuleFields(r)
b, err := c.getForwardingRuleRaw(ctx, r)
if err != nil {
if dcl.IsNotFound(err) {
return nil, &googleapi.Error{
Code: 404,
Message: err.Error(),
}
}
return nil, err
}
result, err := unmarshalForwardingRule(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 = canonicalizeForwardingRuleNewState(c, result, r)
if err != nil {
return nil, err
}
if err := postReadExtractForwardingRuleFields(result); err != nil {
return result, err
}
c.Config.Logger.InfoWithContextf(ctx, "Created result state: %v", result)
return result, nil
}
func (c *Client) DeleteForwardingRule(ctx context.Context, r *ForwardingRule) error {
ctx = dcl.ContextWithRequestID(ctx)
c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{
412: dcl.Retryability{
Retryable: false,
Pattern: "",
Timeout: 0,
},
})))
ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second))
defer cancel()
if r == nil {
return fmt.Errorf("ForwardingRule resource is nil")
}
c.Config.Logger.InfoWithContext(ctx, "Deleting ForwardingRule...")
deleteOp := deleteForwardingRuleOperation{}
return deleteOp.do(ctx, r, c)
}
// DeleteAllForwardingRule deletes all resources that the filter functions returns true on.
func (c *Client) DeleteAllForwardingRule(ctx context.Context, project, location string, filter func(*ForwardingRule) bool) error {
listObj, err := c.ListForwardingRule(ctx, project, location)
if err != nil {
return err
}
err = c.deleteAllForwardingRule(ctx, filter, listObj.Items)
if err != nil {
return err
}
for listObj.HasNext() {
err = listObj.Next(ctx, c)
if err != nil {
return nil
}
err = c.deleteAllForwardingRule(ctx, filter, listObj.Items)
if err != nil {
return err
}
}
return nil
}
func (c *Client) ApplyForwardingRule(ctx context.Context, rawDesired *ForwardingRule, opts ...dcl.ApplyOption) (*ForwardingRule, error) {
ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second))
defer cancel()
ctx = dcl.ContextWithRequestID(ctx)
c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{
412: dcl.Retryability{
Retryable: false,
Pattern: "",
Timeout: 0,
},
})))
var resultNewState *ForwardingRule
err := dcl.Do(ctx, func(ctx context.Context) (*dcl.RetryDetails, error) {
newState, err := applyForwardingRuleHelper(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 applyForwardingRuleHelper(c *Client, ctx context.Context, rawDesired *ForwardingRule, opts ...dcl.ApplyOption) (*ForwardingRule, error) {
c.Config.Logger.InfoWithContext(ctx, "Beginning ApplyForwardingRule...")
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 := extractForwardingRuleFields(rawDesired); err != nil {
return nil, err
}
initial, desired, fieldDiffs, err := c.forwardingRuleDiffsForRawDesired(ctx, rawDesired, opts...)
if err != nil {
return nil, fmt.Errorf("failed to create a diff: %w", err)
}
diffs, err := convertFieldDiffsToForwardingRuleDiffs(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 []forwardingRuleApiOperation
if create {
ops = append(ops, &createForwardingRuleOperation{})
} else {
for _, d := range diffs {
ops = append(ops, d.UpdateOp)
}
}
ops, err = forwardingRuleSetLabelsPostCreate(ops)
if err != nil {
return nil, err
}
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 applyForwardingRuleDiff(c, ctx, desired, rawDesired, ops, opts...)
}
func applyForwardingRuleDiff(c *Client, ctx context.Context, desired *ForwardingRule, rawDesired *ForwardingRule, ops []forwardingRuleApiOperation, opts ...dcl.ApplyOption) (*ForwardingRule, 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.GetForwardingRule(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.(*createForwardingRuleOperation); ok {
if r, hasR := o.FirstResponse(); hasR {
c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state from operation...")
fullResp, err := unmarshalMapForwardingRule(r, c, rawDesired)
if err != nil {
return nil, err
}
rawNew, err = canonicalizeForwardingRuleNewState(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 := canonicalizeForwardingRuleNewState(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 := canonicalizeForwardingRuleDesiredState(rawDesired, newState)
if err != nil {
return newState, err
}
if err := postReadExtractForwardingRuleFields(newState); err != nil {
return newState, err
}
// Need to ensure any transformations made here match acceptably in differ.
if err := postReadExtractForwardingRuleFields(newDesired); err != nil {
return newState, err
}
c.Config.Logger.InfoWithContextf(ctx, "Diffing using canonicalized desired state: %v", newDesired)
newDiffs, err := diffForwardingRule(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
}