sigs.k8s.io/cluster-api@v1.7.1/internal/contract/infrastructure_cluster.go (about)

     1  /*
     2  Copyright 2021 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package contract
    18  
    19  import (
    20  	"encoding/json"
    21  	"strings"
    22  	"sync"
    23  
    24  	"github.com/pkg/errors"
    25  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    26  
    27  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    28  )
    29  
    30  // InfrastructureClusterContract encodes information about the Cluster API contract for InfrastructureCluster objects
    31  // like DockerClusters, AWS Clusters, etc.
    32  type InfrastructureClusterContract struct{}
    33  
    34  var infrastructureCluster *InfrastructureClusterContract
    35  var onceInfrastructureCluster sync.Once
    36  
    37  // InfrastructureCluster provide access to the information about the Cluster API contract for InfrastructureCluster objects.
    38  func InfrastructureCluster() *InfrastructureClusterContract {
    39  	onceInfrastructureCluster.Do(func() {
    40  		infrastructureCluster = &InfrastructureClusterContract{}
    41  	})
    42  	return infrastructureCluster
    43  }
    44  
    45  // ControlPlaneEndpoint provides access to ControlPlaneEndpoint in an InfrastructureCluster object.
    46  func (c *InfrastructureClusterContract) ControlPlaneEndpoint() *InfrastructureClusterControlPlaneEndpoint {
    47  	return &InfrastructureClusterControlPlaneEndpoint{}
    48  }
    49  
    50  // InfrastructureClusterControlPlaneEndpoint provides a helper struct for working with ControlPlaneEndpoint
    51  // in an InfrastructureCluster object.
    52  type InfrastructureClusterControlPlaneEndpoint struct{}
    53  
    54  // Host provides access to the host field in the ControlPlaneEndpoint in an InfrastructureCluster object.
    55  func (c *InfrastructureClusterControlPlaneEndpoint) Host() *String {
    56  	return &String{
    57  		path: []string{"spec", "controlPlaneEndpoint", "host"},
    58  	}
    59  }
    60  
    61  // Port provides access to the port field in the ControlPlaneEndpoint in an InfrastructureCluster object.
    62  func (c *InfrastructureClusterControlPlaneEndpoint) Port() *Int64 {
    63  	return &Int64{
    64  		path: []string{"spec", "controlPlaneEndpoint", "port"},
    65  	}
    66  }
    67  
    68  // Ready provides access to the status.ready field in an InfrastructureCluster object.
    69  func (c *InfrastructureClusterContract) Ready() *Bool {
    70  	return &Bool{
    71  		path: []string{"status", "ready"},
    72  	}
    73  }
    74  
    75  // FailureReason provides access to the status.failureReason field in an InfrastructureCluster object. Note that this field is optional.
    76  func (c *InfrastructureClusterContract) FailureReason() *String {
    77  	return &String{
    78  		path: []string{"status", "failureReason"},
    79  	}
    80  }
    81  
    82  // FailureMessage provides access to the status.failureMessage field in an InfrastructureCluster object. Note that this field is optional.
    83  func (c *InfrastructureClusterContract) FailureMessage() *String {
    84  	return &String{
    85  		path: []string{"status", "failureMessage"},
    86  	}
    87  }
    88  
    89  // FailureDomains provides access to the status.failureDomains field in an InfrastructureCluster object. Note that this field is optional.
    90  func (c *InfrastructureClusterContract) FailureDomains() *FailureDomains {
    91  	return &FailureDomains{
    92  		path: []string{"status", "failureDomains"},
    93  	}
    94  }
    95  
    96  // IgnorePaths returns a list of paths to be ignored when reconciling an InfrastructureCluster.
    97  // NOTE: The controlPlaneEndpoint struct currently contains two mandatory fields (host and port).
    98  // As the host and port fields are not using omitempty, they are automatically set to their zero values
    99  // if they are not set by the user. We don't want to reconcile the zero values as we would then overwrite
   100  // changes applied by the infrastructure provider controller.
   101  func (c *InfrastructureClusterContract) IgnorePaths(infrastructureCluster *unstructured.Unstructured) ([]Path, error) {
   102  	var ignorePaths []Path
   103  
   104  	host, ok, err := unstructured.NestedString(infrastructureCluster.UnstructuredContent(), InfrastructureCluster().ControlPlaneEndpoint().Host().Path()...)
   105  	if err != nil {
   106  		return nil, errors.Wrapf(err, "failed to retrieve %s", InfrastructureCluster().ControlPlaneEndpoint().Host().Path().String())
   107  	}
   108  	if ok && host == "" {
   109  		ignorePaths = append(ignorePaths, InfrastructureCluster().ControlPlaneEndpoint().Host().Path())
   110  	}
   111  
   112  	port, ok, err := unstructured.NestedInt64(infrastructureCluster.UnstructuredContent(), InfrastructureCluster().ControlPlaneEndpoint().Port().Path()...)
   113  	if err != nil {
   114  		return nil, errors.Wrapf(err, "failed to retrieve %s", InfrastructureCluster().ControlPlaneEndpoint().Port().Path().String())
   115  	}
   116  	if ok && port == 0 {
   117  		ignorePaths = append(ignorePaths, InfrastructureCluster().ControlPlaneEndpoint().Port().Path())
   118  	}
   119  
   120  	return ignorePaths, nil
   121  }
   122  
   123  // FailureDomains represents an accessor to a clusterv1.FailureDomains path value.
   124  type FailureDomains struct {
   125  	path Path
   126  }
   127  
   128  // Path returns the path to the clusterv1.FailureDomains value.
   129  func (d *FailureDomains) Path() Path {
   130  	return d.path
   131  }
   132  
   133  // Get gets the metav1.MachineAddressList value.
   134  func (d *FailureDomains) Get(obj *unstructured.Unstructured) (*clusterv1.FailureDomains, error) {
   135  	domainMap, ok, err := unstructured.NestedMap(obj.UnstructuredContent(), d.path...)
   136  	if err != nil {
   137  		return nil, errors.Wrapf(err, "failed to get %s from object", "."+strings.Join(d.path, "."))
   138  	}
   139  	if !ok {
   140  		return nil, errors.Wrapf(ErrFieldNotFound, "path %s", "."+strings.Join(d.path, "."))
   141  	}
   142  
   143  	domains := make(clusterv1.FailureDomains, len(domainMap))
   144  	s, err := json.Marshal(domainMap)
   145  	if err != nil {
   146  		return nil, errors.Wrapf(err, "failed to marshall field at %s to json", "."+strings.Join(d.path, "."))
   147  	}
   148  	err = json.Unmarshal(s, &domains)
   149  	if err != nil {
   150  		return nil, errors.Wrapf(err, "failed to unmarshall field at %s to json", "."+strings.Join(d.path, "."))
   151  	}
   152  
   153  	return &domains, nil
   154  }
   155  
   156  // Set sets the clusterv1.FailureDomains value in the path.
   157  func (d *FailureDomains) Set(obj *unstructured.Unstructured, values clusterv1.FailureDomains) error {
   158  	domains := make(map[string]interface{}, len(values))
   159  	s, err := json.Marshal(values)
   160  	if err != nil {
   161  		return errors.Wrapf(err, "failed to marshall supplied values to json for path %s", "."+strings.Join(d.path, "."))
   162  	}
   163  	err = json.Unmarshal(s, &domains)
   164  	if err != nil {
   165  		return errors.Wrapf(err, "failed to unmarshall supplied values to json for path %s", "."+strings.Join(d.path, "."))
   166  	}
   167  
   168  	if err := unstructured.SetNestedField(obj.UnstructuredContent(), domains, d.path...); err != nil {
   169  		return errors.Wrapf(err, "failed to set path %s of object %v", "."+strings.Join(d.path, "."), obj.GroupVersionKind())
   170  	}
   171  	return nil
   172  }