Skip to content

Instantly share code, notes, and snippets.

@fabriziopandini
Created July 8, 2020 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fabriziopandini/195e4f59c2fa33a1bb6cd5b7a11238fd to your computer and use it in GitHub Desktop.
Save fabriziopandini/195e4f59c2fa33a1bb6cd5b7a11238fd to your computer and use it in GitHub Desktop.
CAPI-coverage-07/08/2020
This file has been truncated, but you can view the full file.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
body {
background: black;
color: rgb(80, 80, 80);
}
body, pre, #legend span {
font-family: Menlo, monospace;
font-weight: bold;
}
#topbar {
background: black;
position: fixed;
top: 0; left: 0; right: 0;
height: 42px;
border-bottom: 1px solid rgb(80, 80, 80);
}
#content {
margin-top: 50px;
}
#nav, #legend {
float: left;
margin-left: 10px;
}
#legend {
margin-top: 12px;
}
#nav {
margin-top: 10px;
}
#legend span {
margin: 0 5px;
}
.cov0 { color: rgb(192, 0, 0) }
.cov1 { color: rgb(128, 128, 128) }
.cov2 { color: rgb(116, 140, 131) }
.cov3 { color: rgb(104, 152, 134) }
.cov4 { color: rgb(92, 164, 137) }
.cov5 { color: rgb(80, 176, 140) }
.cov6 { color: rgb(68, 188, 143) }
.cov7 { color: rgb(56, 200, 146) }
.cov8 { color: rgb(44, 212, 149) }
.cov9 { color: rgb(32, 224, 152) }
.cov10 { color: rgb(20, 236, 155) }
</style>
</head>
<body>
<div id="topbar">
<div id="nav">
<select id="files">
<option value="file0">sigs.k8s.io/cluster-api/api/v1alpha2/cluster_types.go (20.0%)</option>
<option value="file1">sigs.k8s.io/cluster-api/api/v1alpha2/cluster_webhook.go (0.0%)</option>
<option value="file2">sigs.k8s.io/cluster-api/api/v1alpha2/clusterlist_webhook.go (0.0%)</option>
<option value="file3">sigs.k8s.io/cluster-api/api/v1alpha2/conversion.go (75.0%)</option>
<option value="file4">sigs.k8s.io/cluster-api/api/v1alpha2/defaults.go (0.0%)</option>
<option value="file5">sigs.k8s.io/cluster-api/api/v1alpha2/machine_types.go (20.0%)</option>
<option value="file6">sigs.k8s.io/cluster-api/api/v1alpha2/machine_webhook.go (0.0%)</option>
<option value="file7">sigs.k8s.io/cluster-api/api/v1alpha2/machinedeployment_types.go (100.0%)</option>
<option value="file8">sigs.k8s.io/cluster-api/api/v1alpha2/machinedeployment_webhook.go (0.0%)</option>
<option value="file9">sigs.k8s.io/cluster-api/api/v1alpha2/machinedeploymentlist_webhook.go (0.0%)</option>
<option value="file10">sigs.k8s.io/cluster-api/api/v1alpha2/machinelist_webhook.go (0.0%)</option>
<option value="file11">sigs.k8s.io/cluster-api/api/v1alpha2/machineset_types.go (4.3%)</option>
<option value="file12">sigs.k8s.io/cluster-api/api/v1alpha2/machineset_webhook.go (0.0%)</option>
<option value="file13">sigs.k8s.io/cluster-api/api/v1alpha2/machinesetlist_webhook.go (0.0%)</option>
<option value="file14">sigs.k8s.io/cluster-api/api/v1alpha2/zz_generated.conversion.go (36.3%)</option>
<option value="file15">sigs.k8s.io/cluster-api/api/v1alpha2/zz_generated.deepcopy.go (24.1%)</option>
<option value="file16">sigs.k8s.io/cluster-api/api/v1alpha3/cluster_types.go (4.8%)</option>
<option value="file17">sigs.k8s.io/cluster-api/api/v1alpha3/cluster_webhook.go (81.2%)</option>
<option value="file18">sigs.k8s.io/cluster-api/api/v1alpha3/conversion.go (0.0%)</option>
<option value="file19">sigs.k8s.io/cluster-api/api/v1alpha3/machine_types.go (14.3%)</option>
<option value="file20">sigs.k8s.io/cluster-api/api/v1alpha3/machine_webhook.go (90.6%)</option>
<option value="file21">sigs.k8s.io/cluster-api/api/v1alpha3/machinedeployment_types.go (20.0%)</option>
<option value="file22">sigs.k8s.io/cluster-api/api/v1alpha3/machinedeployment_webhook.go (94.2%)</option>
<option value="file23">sigs.k8s.io/cluster-api/api/v1alpha3/machinehealthcheck_types.go (100.0%)</option>
<option value="file24">sigs.k8s.io/cluster-api/api/v1alpha3/machinehealthcheck_webhook.go (91.7%)</option>
<option value="file25">sigs.k8s.io/cluster-api/api/v1alpha3/machineset_types.go (7.7%)</option>
<option value="file26">sigs.k8s.io/cluster-api/api/v1alpha3/machineset_webhook.go (90.9%)</option>
<option value="file27">sigs.k8s.io/cluster-api/api/v1alpha3/zz_generated.deepcopy.go (5.0%)</option>
<option value="file28">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha2/conversion.go (66.7%)</option>
<option value="file29">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha2/kubeadmbootstrapconfig_types.go (100.0%)</option>
<option value="file30">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha2/kubeadmconfigtemplate_types.go (100.0%)</option>
<option value="file31">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha2/zz_generated.conversion.go (24.9%)</option>
<option value="file32">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha2/zz_generated.deepcopy.go (0.0%)</option>
<option value="file33">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3/conversion.go (0.0%)</option>
<option value="file34">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3/kubeadmbootstrapconfig_types.go (33.3%)</option>
<option value="file35">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3/kubeadmconfig_webhook.go (90.9%)</option>
<option value="file36">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3/kubeadmconfiglist_webhook.go (0.0%)</option>
<option value="file37">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3/kubeadmconfigtemplate_types.go (100.0%)</option>
<option value="file38">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3/kubeadmconfigtemplate_webhook.go (0.0%)</option>
<option value="file39">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3/kubeadmconfigtemplatelist_webhook.go (0.0%)</option>
<option value="file40">sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3/zz_generated.deepcopy.go (0.0%)</option>
<option value="file41">sigs.k8s.io/cluster-api/bootstrap/kubeadm/controllers/kubeadmconfig_controller.go (63.2%)</option>
<option value="file42">sigs.k8s.io/cluster-api/bootstrap/kubeadm/controllers/token.go (76.0%)</option>
<option value="file43">sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/cloudinit/cloudinit.go (33.3%)</option>
<option value="file44">sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/cloudinit/controlplane_init.go (85.7%)</option>
<option value="file45">sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/cloudinit/controlplane_join.go (0.0%)</option>
<option value="file46">sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/cloudinit/node.go (0.0%)</option>
<option value="file47">sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/cloudinit/utils.go (100.0%)</option>
<option value="file48">sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/cloudinit/zz_generated.bindata.go (0.0%)</option>
<option value="file49">sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/locking/control_plane_init_mutex.go (84.5%)</option>
<option value="file50">sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1/bootstraptokenstring.go (88.9%)</option>
<option value="file51">sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1/utils.go (0.0%)</option>
<option value="file52">sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1/zz_generated.deepcopy.go (0.0%)</option>
<option value="file53">sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta2/bootstraptokenstring.go (88.9%)</option>
<option value="file54">sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta2/zz_generated.deepcopy.go (0.0%)</option>
<option value="file55">sigs.k8s.io/cluster-api/bootstrap/util/configowner.go (88.6%)</option>
<option value="file56">sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3/labels.go (83.3%)</option>
<option value="file57">sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3/metadata_type.go (20.0%)</option>
<option value="file58">sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3/provider_type.go (13.3%)</option>
<option value="file59">sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3/zz_generated.deepcopy.go (0.0%)</option>
<option value="file60">sigs.k8s.io/cluster-api/cmd/clusterctl/client/client.go (54.2%)</option>
<option value="file61">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/cert_manager.go (14.4%)</option>
<option value="file62">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/client.go (51.1%)</option>
<option value="file63">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/components.go (53.6%)</option>
<option value="file64">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/installer.go (56.6%)</option>
<option value="file65">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/inventory.go (32.0%)</option>
<option value="file66">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/inventory_managementgroup.go (90.5%)</option>
<option value="file67">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/mover.go (71.5%)</option>
<option value="file68">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/objectgraph.go (92.2%)</option>
<option value="file69">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/proxy.go (30.9%)</option>
<option value="file70">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/template.go (70.6%)</option>
<option value="file71">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/upgrader.go (54.0%)</option>
<option value="file72">sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster/upgrader_info.go (90.5%)</option>
<option value="file73">sigs.k8s.io/cluster-api/cmd/clusterctl/client/common.go (80.6%)</option>
<option value="file74">sigs.k8s.io/cluster-api/cmd/clusterctl/client/config.go (78.0%)</option>
<option value="file75">sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/client.go (0.0%)</option>
<option value="file76">sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/imagemeta_client.go (97.1%)</option>
<option value="file77">sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/provider.go (50.0%)</option>
<option value="file78">sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/providers_client.go (95.6%)</option>
<option value="file79">sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/reader_viper.go (89.2%)</option>
<option value="file80">sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/variables_client.go (33.3%)</option>
<option value="file81">sigs.k8s.io/cluster-api/cmd/clusterctl/client/delete.go (82.2%)</option>
<option value="file82">sigs.k8s.io/cluster-api/cmd/clusterctl/client/init.go (83.8%)</option>
<option value="file83">sigs.k8s.io/cluster-api/cmd/clusterctl/client/move.go (77.8%)</option>
<option value="file84">sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository/client.go (60.6%)</option>
<option value="file85">sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository/components.go (86.7%)</option>
<option value="file86">sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository/components_client.go (80.0%)</option>
<option value="file87">sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository/metadata_client.go (48.8%)</option>
<option value="file88">sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository/overrides.go (87.5%)</option>
<option value="file89">sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository/repository_github.go (77.3%)</option>
<option value="file90">sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository/repository_local.go (82.3%)</option>
<option value="file91">sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository/template.go (94.1%)</option>
<option value="file92">sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository/template_client.go (81.2%)</option>
<option value="file93">sigs.k8s.io/cluster-api/cmd/clusterctl/client/upgrade.go (77.0%)</option>
<option value="file94">sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor/simple_processor.go (100.0%)</option>
<option value="file95">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/config.go (100.0%)</option>
<option value="file96">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/config_cluster.go (29.2%)</option>
<option value="file97">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/config_provider.go (12.3%)</option>
<option value="file98">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/config_repositories.go (88.0%)</option>
<option value="file99">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/delete.go (47.8%)</option>
<option value="file100">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/init.go (40.0%)</option>
<option value="file101">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/move.go (40.0%)</option>
<option value="file102">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/root.go (52.5%)</option>
<option value="file103">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/upgrade.go (27.3%)</option>
<option value="file104">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/upgrade_apply.go (44.4%)</option>
<option value="file105">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/upgrade_plan.go (5.9%)</option>
<option value="file106">sigs.k8s.io/cluster-api/cmd/clusterctl/cmd/version.go (11.1%)</option>
<option value="file107">sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util/cmd.go (0.0%)</option>
<option value="file108">sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util/objs.go (66.0%)</option>
<option value="file109">sigs.k8s.io/cluster-api/cmd/clusterctl/log/log.go (0.0%)</option>
<option value="file110">sigs.k8s.io/cluster-api/cmd/clusterctl/log/logger.go (44.3%)</option>
<option value="file111">sigs.k8s.io/cluster-api/cmd/clusterctl/log/util.go (0.0%)</option>
<option value="file112">sigs.k8s.io/cluster-api/controllers/cluster_controller.go (77.2%)</option>
<option value="file113">sigs.k8s.io/cluster-api/controllers/cluster_controller_phases.go (65.7%)</option>
<option value="file114">sigs.k8s.io/cluster-api/controllers/external/tracker.go (0.0%)</option>
<option value="file115">sigs.k8s.io/cluster-api/controllers/external/util.go (74.2%)</option>
<option value="file116">sigs.k8s.io/cluster-api/controllers/machine_controller.go (60.8%)</option>
<option value="file117">sigs.k8s.io/cluster-api/controllers/machine_controller_noderef.go (80.5%)</option>
<option value="file118">sigs.k8s.io/cluster-api/controllers/machine_controller_phases.go (83.3%)</option>
<option value="file119">sigs.k8s.io/cluster-api/controllers/machine_helpers.go (95.0%)</option>
<option value="file120">sigs.k8s.io/cluster-api/controllers/machinedeployment_controller.go (74.0%)</option>
<option value="file121">sigs.k8s.io/cluster-api/controllers/machinedeployment_rolling.go (75.7%)</option>
<option value="file122">sigs.k8s.io/cluster-api/controllers/machinedeployment_sync.go (55.5%)</option>
<option value="file123">sigs.k8s.io/cluster-api/controllers/machinehealthcheck_controller.go (84.6%)</option>
<option value="file124">sigs.k8s.io/cluster-api/controllers/machinehealthcheck_status_matcher.go (78.6%)</option>
<option value="file125">sigs.k8s.io/cluster-api/controllers/machinehealthcheck_targets.go (86.4%)</option>
<option value="file126">sigs.k8s.io/cluster-api/controllers/machineset_controller.go (79.2%)</option>
<option value="file127">sigs.k8s.io/cluster-api/controllers/machineset_delete_policy.go (88.9%)</option>
<option value="file128">sigs.k8s.io/cluster-api/controllers/mdutil/util.go (46.1%)</option>
<option value="file129">sigs.k8s.io/cluster-api/controllers/noderefutil/providerid.go (94.1%)</option>
<option value="file130">sigs.k8s.io/cluster-api/controllers/noderefutil/util.go (77.8%)</option>
<option value="file131">sigs.k8s.io/cluster-api/controllers/remote/cluster.go (92.9%)</option>
<option value="file132">sigs.k8s.io/cluster-api/controllers/remote/cluster_cache.go (74.7%)</option>
<option value="file133">sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_types.go (33.3%)</option>
<option value="file134">sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_webhook.go (86.4%)</option>
<option value="file135">sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3/zz_generated.deepcopy.go (33.9%)</option>
<option value="file136">sigs.k8s.io/cluster-api/controlplane/kubeadm/controllers/controller.go (63.7%)</option>
<option value="file137">sigs.k8s.io/cluster-api/controlplane/kubeadm/controllers/helpers.go (57.5%)</option>
<option value="file138">sigs.k8s.io/cluster-api/controlplane/kubeadm/controllers/scale.go (55.7%)</option>
<option value="file139">sigs.k8s.io/cluster-api/controlplane/kubeadm/controllers/status.go (85.3%)</option>
<option value="file140">sigs.k8s.io/cluster-api/controlplane/kubeadm/controllers/upgrade.go (53.1%)</option>
<option value="file141">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/cluster.go (38.1%)</option>
<option value="file142">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/cluster_labels.go (100.0%)</option>
<option value="file143">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/control_plane.go (32.5%)</option>
<option value="file144">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/etcd/backoff_adapter.go (0.0%)</option>
<option value="file145">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/etcd/etcd.go (72.3%)</option>
<option value="file146">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/etcd_client_generator.go (0.0%)</option>
<option value="file147">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/failure_domain.go (100.0%)</option>
<option value="file148">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/kubeadm_config_map.go (84.0%)</option>
<option value="file149">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/machine_collection.go (66.7%)</option>
<option value="file150">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/machinefilters/machine_filters.go (64.6%)</option>
<option value="file151">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/workload_cluster.go (72.4%)</option>
<option value="file152">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/workload_cluster_coredns.go (75.7%)</option>
<option value="file153">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/workload_cluster_etcd.go (65.2%)</option>
<option value="file154">sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/workload_cluster_rbac.go (90.0%)</option>
<option value="file155">sigs.k8s.io/cluster-api/exp/addons/api/v1alpha3/clusterresourceset_types.go (25.0%)</option>
<option value="file156">sigs.k8s.io/cluster-api/exp/addons/api/v1alpha3/clusterresourceset_webhook.go (86.4%)</option>
<option value="file157">sigs.k8s.io/cluster-api/exp/addons/api/v1alpha3/clusterresourcesetbinding_types.go (100.0%)</option>
<option value="file158">sigs.k8s.io/cluster-api/exp/addons/api/v1alpha3/zz_generated.deepcopy.go (0.0%)</option>
<option value="file159">sigs.k8s.io/cluster-api/exp/addons/controllers/clusterresourceset_controller.go (69.6%)</option>
<option value="file160">sigs.k8s.io/cluster-api/exp/addons/controllers/clusterresourceset_helpers.go (73.1%)</option>
<option value="file161">sigs.k8s.io/cluster-api/exp/api/v1alpha3/machinepool_types.go (20.0%)</option>
<option value="file162">sigs.k8s.io/cluster-api/exp/api/v1alpha3/machinepool_webhook.go (88.5%)</option>
<option value="file163">sigs.k8s.io/cluster-api/exp/api/v1alpha3/zz_generated.deepcopy.go (0.0%)</option>
<option value="file164">sigs.k8s.io/cluster-api/exp/controllers/machinepool_controller.go (75.8%)</option>
<option value="file165">sigs.k8s.io/cluster-api/exp/controllers/machinepool_controller_noderef.go (63.2%)</option>
<option value="file166">sigs.k8s.io/cluster-api/exp/controllers/machinepool_controller_phases.go (80.0%)</option>
<option value="file167">sigs.k8s.io/cluster-api/test/framework/alltypes_helpers.go (0.0%)</option>
<option value="file168">sigs.k8s.io/cluster-api/test/framework/cluster_helpers.go (0.0%)</option>
<option value="file169">sigs.k8s.io/cluster-api/test/framework/cluster_proxy.go (0.0%)</option>
<option value="file170">sigs.k8s.io/cluster-api/test/framework/clusterresourceset_helpers.go (0.0%)</option>
<option value="file171">sigs.k8s.io/cluster-api/test/framework/config.go (45.2%)</option>
<option value="file172">sigs.k8s.io/cluster-api/test/framework/control_plane.go (0.0%)</option>
<option value="file173">sigs.k8s.io/cluster-api/test/framework/controller_helpers.go (0.0%)</option>
<option value="file174">sigs.k8s.io/cluster-api/test/framework/controlpane_helpers.go (0.0%)</option>
<option value="file175">sigs.k8s.io/cluster-api/test/framework/convenience.go (9.1%)</option>
<option value="file176">sigs.k8s.io/cluster-api/test/framework/daemonset_helpers.go (0.0%)</option>
<option value="file177">sigs.k8s.io/cluster-api/test/framework/deployment_helpers.go (0.0%)</option>
<option value="file178">sigs.k8s.io/cluster-api/test/framework/deprecated.go (0.0%)</option>
<option value="file179">sigs.k8s.io/cluster-api/test/framework/machine_helpers.go (0.0%)</option>
<option value="file180">sigs.k8s.io/cluster-api/test/framework/machinedeployment_helpers.go (0.0%)</option>
<option value="file181">sigs.k8s.io/cluster-api/test/framework/machinehealthcheck_helpers.go (0.0%)</option>
<option value="file182">sigs.k8s.io/cluster-api/test/framework/machines.go (0.0%)</option>
<option value="file183">sigs.k8s.io/cluster-api/test/framework/namespace_helpers.go (0.0%)</option>
<option value="file184">sigs.k8s.io/cluster-api/test/framework/pod_helpers.go (0.0%)</option>
<option value="file185">sigs.k8s.io/cluster-api/util/certs/certs.go (51.4%)</option>
<option value="file186">sigs.k8s.io/cluster-api/util/certs/types.go (0.0%)</option>
<option value="file187">sigs.k8s.io/cluster-api/util/conditions/getter.go (88.2%)</option>
<option value="file188">sigs.k8s.io/cluster-api/util/conditions/merge.go (94.4%)</option>
<option value="file189">sigs.k8s.io/cluster-api/util/conditions/merge_strategies.go (84.6%)</option>
<option value="file190">sigs.k8s.io/cluster-api/util/conditions/patch.go (98.3%)</option>
<option value="file191">sigs.k8s.io/cluster-api/util/conditions/setter.go (92.5%)</option>
<option value="file192">sigs.k8s.io/cluster-api/util/conditions/unstructured.go (81.2%)</option>
<option value="file193">sigs.k8s.io/cluster-api/util/container/image.go (88.9%)</option>
<option value="file194">sigs.k8s.io/cluster-api/util/conversion/conversion.go (28.8%)</option>
<option value="file195">sigs.k8s.io/cluster-api/util/kubeconfig/kubeconfig.go (73.8%)</option>
<option value="file196">sigs.k8s.io/cluster-api/util/kubeconfig/testing.go (0.0%)</option>
<option value="file197">sigs.k8s.io/cluster-api/util/patch/options.go (100.0%)</option>
<option value="file198">sigs.k8s.io/cluster-api/util/patch/patch.go (80.2%)</option>
<option value="file199">sigs.k8s.io/cluster-api/util/patch/utils.go (100.0%)</option>
<option value="file200">sigs.k8s.io/cluster-api/util/resource/resource.go (100.0%)</option>
<option value="file201">sigs.k8s.io/cluster-api/util/retry.go (0.0%)</option>
<option value="file202">sigs.k8s.io/cluster-api/util/secret/certificates.go (9.6%)</option>
<option value="file203">sigs.k8s.io/cluster-api/util/secret/secret.go (56.2%)</option>
<option value="file204">sigs.k8s.io/cluster-api/util/util.go (47.2%)</option>
<option value="file205">sigs.k8s.io/cluster-api/util/yaml/yaml.go (65.7%)</option>
</select>
</div>
<div id="legend">
<span>not tracked</span>
<span class="cov0">not covered</span>
<span class="cov8">covered</span>
</div>
</div>
<div id="content">
<pre class="file" id="file0" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
capierrors "sigs.k8s.io/cluster-api/errors"
)
const (
ClusterFinalizer = "cluster.cluster.x-k8s.io"
)
// ANCHOR: ClusterSpec
// ClusterSpec defines the desired state of Cluster
type ClusterSpec struct {
// Cluster network configuration
// +optional
ClusterNetwork *ClusterNetwork `json:"clusterNetwork,omitempty"`
// InfrastructureRef is a reference to a provider-specific resource that holds the details
// for provisioning infrastructure for a cluster in said provider.
// +optional
InfrastructureRef *corev1.ObjectReference `json:"infrastructureRef,omitempty"`
}
// ANCHOR_END: ClusterSpec
// ANCHOR: ClusterNetwork
// ClusterNetwork specifies the different networking
// parameters for a cluster.
type ClusterNetwork struct {
// APIServerPort specifies the port the API Server should bind to.
// Defaults to 6443.
// +optional
APIServerPort *int32 `json:"apiServerPort,omitempty"`
// The network ranges from which service VIPs are allocated.
// +optional
Services *NetworkRanges `json:"services,omitempty"`
// The network ranges from which Pod networks are allocated.
// +optional
Pods *NetworkRanges `json:"pods,omitempty"`
// Domain name for services.
// +optional
ServiceDomain string `json:"serviceDomain,omitempty"`
}
// ANCHOR_END: ClusterNetwork
// ANCHOR: NetworkRanges
// NetworkRanges represents ranges of network addresses.
type NetworkRanges struct {
CIDRBlocks []string `json:"cidrBlocks"`
}
// ANCHOR_END: NetworkRanges
// ANCHOR: ClusterStatus
// ClusterStatus defines the observed state of Cluster
type ClusterStatus struct {
// APIEndpoints represents the endpoints to communicate with the control plane.
// +optional
APIEndpoints []APIEndpoint `json:"apiEndpoints,omitempty"`
// ErrorReason indicates that there is a problem reconciling the
// state, and will be set to a token value suitable for
// programmatic interpretation.
// +optional
ErrorReason *capierrors.ClusterStatusError `json:"errorReason,omitempty"`
// ErrorMessage indicates that there is a problem reconciling the
// state, and will be set to a descriptive error message.
// +optional
ErrorMessage *string `json:"errorMessage,omitempty"`
// Phase represents the current phase of cluster actuation.
// E.g. Pending, Running, Terminating, Failed etc.
// +optional
Phase string `json:"phase,omitempty"`
// InfrastructureReady is the state of the infrastructure provider.
// +optional
InfrastructureReady bool `json:"infrastructureReady"`
// ControlPlaneInitialized defines if the control plane has been initialized.
// +optional
ControlPlaneInitialized bool `json:"controlPlaneInitialized"`
}
// ANCHOR_END: ClusterStatus
// SetTypedPhase sets the Phase field to the string representation of ClusterPhase.
func (c *ClusterStatus) SetTypedPhase(p ClusterPhase) <span class="cov0" title="0">{
c.Phase = string(p)
}</span>
// GetTypedPhase attempts to parse the Phase field and return
// the typed ClusterPhase representation as described in `machine_phase_types.go`.
func (c *ClusterStatus) GetTypedPhase() ClusterPhase <span class="cov0" title="0">{
switch phase := ClusterPhase(c.Phase); phase </span>{
case
ClusterPhasePending,
ClusterPhaseProvisioning,
ClusterPhaseProvisioned,
ClusterPhaseDeleting,
ClusterPhaseFailed:<span class="cov0" title="0">
return phase</span>
default:<span class="cov0" title="0">
return ClusterPhaseUnknown</span>
}
}
// ANCHOR: APIEndpoint
// APIEndpoint represents a reachable Kubernetes API endpoint.
type APIEndpoint struct {
// The hostname on which the API server is serving.
Host string `json:"host"`
// The port on which the API server is serving.
Port int `json:"port"`
}
// ANCHOR_END: APIEndpoint
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=clusters,shortName=cl,scope=Namespaced,categories=cluster-api
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Cluster status such as Pending/Provisioning/Provisioned/Deleting/Failed"
// Cluster is the Schema for the clusters API
type Cluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ClusterSpec `json:"spec,omitempty"`
Status ClusterStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// ClusterList contains a list of Cluster
type ClusterList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Cluster `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;Cluster{}, &amp;ClusterList{})
}</span>
</pre>
<pre class="file" id="file1" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
// log is for logging in this package.
var _ = logf.Log.WithName("cluster-resource")
func (r *Cluster) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file2" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
// log is for logging in this package.
var _ = logf.Log.WithName("clusterlist-resource")
func (r *ClusterList) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file3" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
apiconversion "k8s.io/apimachinery/pkg/conversion"
"sigs.k8s.io/cluster-api/api/v1alpha3"
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
"sigs.k8s.io/controller-runtime/pkg/conversion"
)
var (
v2Annotations = []string{RevisionAnnotation, RevisionHistoryAnnotation, DesiredReplicasAnnotation, MaxReplicasAnnotation}
v3Annotations = []string{v1alpha3.RevisionAnnotation, v1alpha3.RevisionHistoryAnnotation, v1alpha3.DesiredReplicasAnnotation, v1alpha3.MaxReplicasAnnotation}
)
func (src *Cluster) ConvertTo(dstRaw conversion.Hub) error <span class="cov8" title="1">{
dst := dstRaw.(*v1alpha3.Cluster)
if err := Convert_v1alpha2_Cluster_To_v1alpha3_Cluster(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert Status.APIEndpoints to Spec.ControlPlaneEndpoint.
<span class="cov8" title="1">if len(src.Status.APIEndpoints) &gt; 0 </span><span class="cov8" title="1">{
endpoint := src.Status.APIEndpoints[0]
dst.Spec.ControlPlaneEndpoint.Host = endpoint.Host
dst.Spec.ControlPlaneEndpoint.Port = int32(endpoint.Port)
}</span>
// Manually restore data.
<span class="cov8" title="1">restored := &amp;v1alpha3.Cluster{}
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok </span><span class="cov8" title="1">{
return err
}</span>
<span class="cov8" title="1">dst.Spec.ControlPlaneRef = restored.Spec.ControlPlaneRef
dst.Status.ControlPlaneReady = restored.Status.ControlPlaneReady
dst.Status.FailureDomains = restored.Status.FailureDomains
dst.Spec.Paused = restored.Spec.Paused
dst.Status.Conditions = restored.Status.Conditions
dst.Status.ObservedGeneration = restored.Status.ObservedGeneration
return nil</span>
}
func (dst *Cluster) ConvertFrom(srcRaw conversion.Hub) error <span class="cov8" title="1">{
src := srcRaw.(*v1alpha3.Cluster)
if err := Convert_v1alpha3_Cluster_To_v1alpha2_Cluster(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert Spec.ControlPlaneEndpoint to Status.APIEndpoints.
<span class="cov8" title="1">if !src.Spec.ControlPlaneEndpoint.IsZero() </span><span class="cov8" title="1">{
dst.Status.APIEndpoints = []APIEndpoint{
{
Host: src.Spec.ControlPlaneEndpoint.Host,
Port: int(src.Spec.ControlPlaneEndpoint.Port),
},
}
}</span>
// Preserve Hub data on down-conversion except for metadata
<span class="cov8" title="1">if err := utilconversion.MarshalData(src, dst); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
func (src *ClusterList) ConvertTo(dstRaw conversion.Hub) error <span class="cov0" title="0">{
dst := dstRaw.(*v1alpha3.ClusterList)
return Convert_v1alpha2_ClusterList_To_v1alpha3_ClusterList(src, dst, nil)
}</span>
func (dst *ClusterList) ConvertFrom(srcRaw conversion.Hub) error <span class="cov0" title="0">{
src := srcRaw.(*v1alpha3.ClusterList)
return Convert_v1alpha3_ClusterList_To_v1alpha2_ClusterList(src, dst, nil)
}</span>
func (src *Machine) ConvertTo(dstRaw conversion.Hub) error <span class="cov8" title="1">{
dst := dstRaw.(*v1alpha3.Machine)
if err := Convert_v1alpha2_Machine_To_v1alpha3_Machine(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert ExcludeNodeDrainingAnnotation annotation if set.
<span class="cov8" title="1">if val, ok := src.Annotations[ExcludeNodeDrainingAnnotation]; ok </span><span class="cov0" title="0">{
src.Annotations[v1alpha3.ExcludeNodeDrainingAnnotation] = val
delete(src.Annotations, ExcludeNodeDrainingAnnotation)
}</span>
// Manually convert ClusterName from label, if any.
// This conversion can be overwritten when restoring the ClusterName field.
<span class="cov8" title="1">if name, ok := src.Labels[MachineClusterLabelName]; ok </span><span class="cov8" title="1">{
dst.Spec.ClusterName = name
}</span>
// Manually restore data.
<span class="cov8" title="1">restored := &amp;v1alpha3.Machine{}
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok </span><span class="cov8" title="1">{
return err
}</span>
<span class="cov8" title="1">restoreMachineSpec(&amp;restored.Spec, &amp;dst.Spec)
dst.Status.ObservedGeneration = restored.Status.ObservedGeneration
dst.Status.Conditions = restored.Status.Conditions
return nil</span>
}
func restoreMachineSpec(restored *v1alpha3.MachineSpec, dst *v1alpha3.MachineSpec) <span class="cov8" title="1">{
if restored.ClusterName != "" </span><span class="cov8" title="1">{
dst.ClusterName = restored.ClusterName
}</span>
<span class="cov8" title="1">dst.Bootstrap.DataSecretName = restored.Bootstrap.DataSecretName
dst.FailureDomain = restored.FailureDomain</span>
}
func (dst *Machine) ConvertFrom(srcRaw conversion.Hub) error <span class="cov8" title="1">{
src := srcRaw.(*v1alpha3.Machine)
if err := Convert_v1alpha3_Machine_To_v1alpha2_Machine(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert ExcludeNodeDrainingAnnotation annotation if set.
<span class="cov8" title="1">if val, ok := src.Annotations[v1alpha3.ExcludeNodeDrainingAnnotation]; ok </span><span class="cov0" title="0">{
src.Annotations[ExcludeNodeDrainingAnnotation] = val
delete(src.Annotations, v1alpha3.ExcludeNodeDrainingAnnotation)
}</span>
// Preserve Hub data on down-conversion except for metadata
<span class="cov8" title="1">if err := utilconversion.MarshalData(src, dst); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
func (src *MachineList) ConvertTo(dstRaw conversion.Hub) error <span class="cov0" title="0">{
dst := dstRaw.(*v1alpha3.MachineList)
return Convert_v1alpha2_MachineList_To_v1alpha3_MachineList(src, dst, nil)
}</span>
func (dst *MachineList) ConvertFrom(srcRaw conversion.Hub) error <span class="cov0" title="0">{
src := srcRaw.(*v1alpha3.MachineList)
return Convert_v1alpha3_MachineList_To_v1alpha2_MachineList(src, dst, nil)
}</span>
func (src *MachineSet) ConvertTo(dstRaw conversion.Hub) error <span class="cov8" title="1">{
dst := dstRaw.(*v1alpha3.MachineSet)
if err := Convert_v1alpha2_MachineSet_To_v1alpha3_MachineSet(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert ClusterName from label, if any.
// This conversion can be overwritten when restoring the ClusterName field.
<span class="cov8" title="1">if name, ok := src.Labels[MachineClusterLabelName]; ok </span><span class="cov8" title="1">{
dst.Spec.ClusterName = name
dst.Spec.Template.Spec.ClusterName = name
}</span>
// Manually convert annotations
<span class="cov8" title="1">for i := range v2Annotations </span><span class="cov8" title="1">{
convertAnnotations(v2Annotations[i], v3Annotations[i], dst.Annotations)
}</span>
// Manually restore data.
<span class="cov8" title="1">restored := &amp;v1alpha3.MachineSet{}
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok </span><span class="cov8" title="1">{
return err
}</span>
<span class="cov8" title="1">if restored.Spec.ClusterName != "" </span><span class="cov8" title="1">{
dst.Spec.ClusterName = restored.Spec.ClusterName
}</span>
<span class="cov8" title="1">restoreMachineSpec(&amp;restored.Spec.Template.Spec, &amp;dst.Spec.Template.Spec)
return nil</span>
}
func (dst *MachineSet) ConvertFrom(srcRaw conversion.Hub) error <span class="cov8" title="1">{
src := srcRaw.(*v1alpha3.MachineSet)
if err := Convert_v1alpha3_MachineSet_To_v1alpha2_MachineSet(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert annotations
<span class="cov8" title="1">for i := range v3Annotations </span><span class="cov8" title="1">{
convertAnnotations(v3Annotations[i], v2Annotations[i], dst.Annotations)
}</span>
// Preserve Hub data on down-conversion except for metadata
<span class="cov8" title="1">if err := utilconversion.MarshalData(src, dst); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
func (src *MachineSetList) ConvertTo(dstRaw conversion.Hub) error <span class="cov0" title="0">{
dst := dstRaw.(*v1alpha3.MachineSetList)
return Convert_v1alpha2_MachineSetList_To_v1alpha3_MachineSetList(src, dst, nil)
}</span>
func (dst *MachineSetList) ConvertFrom(srcRaw conversion.Hub) error <span class="cov0" title="0">{
src := srcRaw.(*v1alpha3.MachineSetList)
return Convert_v1alpha3_MachineSetList_To_v1alpha2_MachineSetList(src, dst, nil)
}</span>
func (src *MachineDeployment) ConvertTo(dstRaw conversion.Hub) error <span class="cov8" title="1">{
dst := dstRaw.(*v1alpha3.MachineDeployment)
if err := Convert_v1alpha2_MachineDeployment_To_v1alpha3_MachineDeployment(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert ClusterName from label, if any.
// This conversion can be overwritten when restoring the ClusterName field.
<span class="cov8" title="1">if name, ok := src.Labels[MachineClusterLabelName]; ok </span><span class="cov8" title="1">{
dst.Spec.ClusterName = name
dst.Spec.Template.Spec.ClusterName = name
}</span>
// Manually convert annotations
<span class="cov8" title="1">for i := range v2Annotations </span><span class="cov8" title="1">{
convertAnnotations(v2Annotations[i], v3Annotations[i], dst.Annotations)
}</span>
// Manually restore data.
<span class="cov8" title="1">restored := &amp;v1alpha3.MachineDeployment{}
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok </span><span class="cov8" title="1">{
return err
}</span>
<span class="cov8" title="1">if restored.Spec.ClusterName != "" </span><span class="cov8" title="1">{
dst.Spec.ClusterName = restored.Spec.ClusterName
}</span>
<span class="cov8" title="1">dst.Spec.Paused = restored.Spec.Paused
dst.Status.Phase = restored.Status.Phase
restoreMachineSpec(&amp;restored.Spec.Template.Spec, &amp;dst.Spec.Template.Spec)
return nil</span>
}
func (dst *MachineDeployment) ConvertFrom(srcRaw conversion.Hub) error <span class="cov8" title="1">{
src := srcRaw.(*v1alpha3.MachineDeployment)
if err := Convert_v1alpha3_MachineDeployment_To_v1alpha2_MachineDeployment(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert annotations
<span class="cov8" title="1">for i := range v3Annotations </span><span class="cov8" title="1">{
convertAnnotations(v3Annotations[i], v2Annotations[i], dst.Annotations)
}</span>
// Preserve Hub data on down-conversion except for metadata
<span class="cov8" title="1">if err := utilconversion.MarshalData(src, dst); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
func convertAnnotations(fromAnnotation string, toAnnotation string, annotations map[string]string) <span class="cov8" title="1">{
if value, ok := annotations[fromAnnotation]; ok </span><span class="cov8" title="1">{
delete(annotations, fromAnnotation)
annotations[toAnnotation] = value
}</span>
}
func (src *MachineDeploymentList) ConvertTo(dstRaw conversion.Hub) error <span class="cov0" title="0">{
dst := dstRaw.(*v1alpha3.MachineDeploymentList)
return Convert_v1alpha2_MachineDeploymentList_To_v1alpha3_MachineDeploymentList(src, dst, nil)
}</span>
func (dst *MachineDeploymentList) ConvertFrom(srcRaw conversion.Hub) error <span class="cov0" title="0">{
src := srcRaw.(*v1alpha3.MachineDeploymentList)
return Convert_v1alpha3_MachineDeploymentList_To_v1alpha2_MachineDeploymentList(src, dst, nil)
}</span>
func Convert_v1alpha2_MachineSpec_To_v1alpha3_MachineSpec(in *MachineSpec, out *v1alpha3.MachineSpec, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha2_MachineSpec_To_v1alpha3_MachineSpec(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Discards unused ObjectMeta
<span class="cov8" title="1">return nil</span>
}
func Convert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(in *ClusterSpec, out *v1alpha3.ClusterSpec, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
func Convert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(in *ClusterStatus, out *v1alpha3.ClusterStatus, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert the Error fields to the Failure fields
<span class="cov8" title="1">out.FailureMessage = in.ErrorMessage
out.FailureReason = in.ErrorReason
return nil</span>
}
func Convert_v1alpha3_ClusterStatus_To_v1alpha2_ClusterStatus(in *v1alpha3.ClusterStatus, out *ClusterStatus, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha3_ClusterStatus_To_v1alpha2_ClusterStatus(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert the Failure fields to the Error fields
<span class="cov8" title="1">out.ErrorMessage = in.FailureMessage
out.ErrorReason = in.FailureReason
return nil</span>
}
func Convert_v1alpha2_MachineSetStatus_To_v1alpha3_MachineSetStatus(in *MachineSetStatus, out *v1alpha3.MachineSetStatus, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha2_MachineSetStatus_To_v1alpha3_MachineSetStatus(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert the Error fields to the Failure fields
<span class="cov8" title="1">out.FailureMessage = in.ErrorMessage
out.FailureReason = in.ErrorReason
return nil</span>
}
func Convert_v1alpha3_MachineSetStatus_To_v1alpha2_MachineSetStatus(in *v1alpha3.MachineSetStatus, out *MachineSetStatus, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha3_MachineSetStatus_To_v1alpha2_MachineSetStatus(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert the Failure fields to the Error fields
<span class="cov8" title="1">out.ErrorMessage = in.FailureMessage
out.ErrorReason = in.FailureReason
return nil</span>
}
func Convert_v1alpha2_MachineStatus_To_v1alpha3_MachineStatus(in *MachineStatus, out *v1alpha3.MachineStatus, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha2_MachineStatus_To_v1alpha3_MachineStatus(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert the Error fields to the Failure fields
<span class="cov8" title="1">out.FailureMessage = in.ErrorMessage
out.FailureReason = in.ErrorReason
return nil</span>
}
func Convert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(in *v1alpha3.ClusterSpec, out *ClusterSpec, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
func Convert_v1alpha3_MachineStatus_To_v1alpha2_MachineStatus(in *v1alpha3.MachineStatus, out *MachineStatus, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha3_MachineStatus_To_v1alpha2_MachineStatus(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert the Failure fields to the Error fields
<span class="cov8" title="1">out.ErrorMessage = in.FailureMessage
out.ErrorReason = in.FailureReason
return nil</span>
}
func Convert_v1alpha3_MachineDeploymentSpec_To_v1alpha2_MachineDeploymentSpec(in *v1alpha3.MachineDeploymentSpec, out *MachineDeploymentSpec, s apiconversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_MachineDeploymentSpec_To_v1alpha2_MachineDeploymentSpec(in, out, s)
}</span>
func Convert_v1alpha3_MachineDeploymentStatus_To_v1alpha2_MachineDeploymentStatus(in *v1alpha3.MachineDeploymentStatus, out *MachineDeploymentStatus, s apiconversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_MachineDeploymentStatus_To_v1alpha2_MachineDeploymentStatus(in, out, s)
}</span>
func Convert_v1alpha3_MachineSetSpec_To_v1alpha2_MachineSetSpec(in *v1alpha3.MachineSetSpec, out *MachineSetSpec, s apiconversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_MachineSetSpec_To_v1alpha2_MachineSetSpec(in, out, s)
}</span>
func Convert_v1alpha3_MachineSpec_To_v1alpha2_MachineSpec(in *v1alpha3.MachineSpec, out *MachineSpec, s apiconversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_MachineSpec_To_v1alpha2_MachineSpec(in, out, s)
}</span>
func Convert_v1alpha3_Bootstrap_To_v1alpha2_Bootstrap(in *v1alpha3.Bootstrap, out *Bootstrap, s apiconversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_Bootstrap_To_v1alpha2_Bootstrap(in, out, s)
}</span>
</pre>
<pre class="file" id="file4" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
// PopulateDefaultsMachineDeployment fills in default field values
// Currently it is called after reading objects, but it could be called in an admission webhook also
func PopulateDefaultsMachineDeployment(d *MachineDeployment) <span class="cov0" title="0">{
if d.Spec.Replicas == nil </span><span class="cov0" title="0">{
d.Spec.Replicas = new(int32)
*d.Spec.Replicas = 1
}</span>
<span class="cov0" title="0">if d.Spec.MinReadySeconds == nil </span><span class="cov0" title="0">{
d.Spec.MinReadySeconds = new(int32)
*d.Spec.MinReadySeconds = 0
}</span>
<span class="cov0" title="0">if d.Spec.RevisionHistoryLimit == nil </span><span class="cov0" title="0">{
d.Spec.RevisionHistoryLimit = new(int32)
*d.Spec.RevisionHistoryLimit = 1
}</span>
<span class="cov0" title="0">if d.Spec.ProgressDeadlineSeconds == nil </span><span class="cov0" title="0">{
d.Spec.ProgressDeadlineSeconds = new(int32)
*d.Spec.ProgressDeadlineSeconds = 600
}</span>
<span class="cov0" title="0">if d.Spec.Strategy == nil </span><span class="cov0" title="0">{
d.Spec.Strategy = &amp;MachineDeploymentStrategy{}
}</span>
<span class="cov0" title="0">if d.Spec.Strategy.Type == "" </span><span class="cov0" title="0">{
d.Spec.Strategy.Type = RollingUpdateMachineDeploymentStrategyType
}</span>
// Default RollingUpdate strategy only if strategy type is RollingUpdate.
<span class="cov0" title="0">if d.Spec.Strategy.Type == RollingUpdateMachineDeploymentStrategyType </span><span class="cov0" title="0">{
if d.Spec.Strategy.RollingUpdate == nil </span><span class="cov0" title="0">{
d.Spec.Strategy.RollingUpdate = &amp;MachineRollingUpdateDeployment{}
}</span>
<span class="cov0" title="0">if d.Spec.Strategy.RollingUpdate.MaxSurge == nil </span><span class="cov0" title="0">{
ios1 := intstr.FromInt(1)
d.Spec.Strategy.RollingUpdate.MaxSurge = &amp;ios1
}</span>
<span class="cov0" title="0">if d.Spec.Strategy.RollingUpdate.MaxUnavailable == nil </span><span class="cov0" title="0">{
ios0 := intstr.FromInt(0)
d.Spec.Strategy.RollingUpdate.MaxUnavailable = &amp;ios0
}</span>
}
<span class="cov0" title="0">if len(d.Namespace) == 0 </span><span class="cov0" title="0">{
d.Namespace = metav1.NamespaceDefault
}</span>
}
</pre>
<pre class="file" id="file5" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
capierrors "sigs.k8s.io/cluster-api/errors"
)
const (
// MachineFinalizer is set on PrepareForCreate callback.
MachineFinalizer = "machine.cluster.x-k8s.io"
// MachineClusterLabelName is the label set on machines linked to a cluster.
MachineClusterLabelName = "cluster.x-k8s.io/cluster-name"
// MachineControlPlaneLabelName is the label set on machines part of a control plane.
MachineControlPlaneLabelName = "cluster.x-k8s.io/control-plane"
// ExcludeNodeDrainingAnnotation annotation explicitly skips node draining if set
ExcludeNodeDrainingAnnotation = "machine.cluster.x-k8s.io.io/exclude-node-draining"
)
// ANCHOR: MachineSpec
// MachineSpec defines the desired state of Machine
type MachineSpec struct {
// DEPRECATED: ObjectMeta has no function and isn't used anywhere.
// +optional
ObjectMeta `json:"metadata,omitempty"`
// Bootstrap is a reference to a local struct which encapsulates
// fields to configure the Machine’s bootstrapping mechanism.
Bootstrap Bootstrap `json:"bootstrap"`
// InfrastructureRef is a required reference to a custom resource
// offered by an infrastructure provider.
InfrastructureRef corev1.ObjectReference `json:"infrastructureRef"`
// Version defines the desired Kubernetes version.
// This field is meant to be optionally used by bootstrap providers.
// +optional
Version *string `json:"version,omitempty"`
// ProviderID is the identification ID of the machine provided by the provider.
// This field must match the provider ID as seen on the node object corresponding to this machine.
// This field is required by higher level consumers of cluster-api. Example use case is cluster autoscaler
// with cluster-api as provider. Clean-up logic in the autoscaler compares machines to nodes to find out
// machines at provider which could not get registered as Kubernetes nodes. With cluster-api as a
// generic out-of-tree provider for autoscaler, this field is required by autoscaler to be
// able to have a provider view of the list of machines. Another list of nodes is queried from the k8s apiserver
// and then a comparison is done to find out unregistered machines and are marked for delete.
// This field will be set by the actuators and consumed by higher level entities like autoscaler that will
// be interfacing with cluster-api as generic provider.
// +optional
ProviderID *string `json:"providerID,omitempty"`
}
// ANCHOR_END: MachineSpec
// ANCHOR: MachineStatus
// MachineStatus defines the observed state of Machine
type MachineStatus struct {
// NodeRef will point to the corresponding Node if it exists.
// +optional
NodeRef *corev1.ObjectReference `json:"nodeRef,omitempty"`
// LastUpdated identifies when this status was last observed.
// +optional
LastUpdated *metav1.Time `json:"lastUpdated,omitempty"`
// Version specifies the current version of Kubernetes running
// on the corresponding Node. This is meant to be a means of bubbling
// up status from the Node to the Machine.
// It is entirely optional, but useful for end-user UX if it’s present.
// +optional
Version *string `json:"version,omitempty"`
// ErrorReason will be set in the event that there is a terminal problem
// reconciling the Machine and will contain a succinct value suitable
// for machine interpretation.
//
// This field should not be set for transitive errors that a controller
// faces that are expected to be fixed automatically over
// time (like service outages), but instead indicate that something is
// fundamentally wrong with the Machine's spec or the configuration of
// the controller, and that manual intervention is required. Examples
// of terminal errors would be invalid combinations of settings in the
// spec, values that are unsupported by the controller, or the
// responsible controller itself being critically misconfigured.
//
// Any transient errors that occur during the reconciliation of Machines
// can be added as events to the Machine object and/or logged in the
// controller's output.
// +optional
ErrorReason *capierrors.MachineStatusError `json:"errorReason,omitempty"`
// ErrorMessage will be set in the event that there is a terminal problem
// reconciling the Machine and will contain a more verbose string suitable
// for logging and human consumption.
//
// This field should not be set for transitive errors that a controller
// faces that are expected to be fixed automatically over
// time (like service outages), but instead indicate that something is
// fundamentally wrong with the Machine's spec or the configuration of
// the controller, and that manual intervention is required. Examples
// of terminal errors would be invalid combinations of settings in the
// spec, values that are unsupported by the controller, or the
// responsible controller itself being critically misconfigured.
//
// Any transient errors that occur during the reconciliation of Machines
// can be added as events to the Machine object and/or logged in the
// controller's output.
// +optional
ErrorMessage *string `json:"errorMessage,omitempty"`
// Addresses is a list of addresses assigned to the machine.
// This field is copied from the infrastructure provider reference.
// +optional
Addresses MachineAddresses `json:"addresses,omitempty"`
// Phase represents the current phase of machine actuation.
// E.g. Pending, Running, Terminating, Failed etc.
// +optional
Phase string `json:"phase,omitempty"`
// BootstrapReady is the state of the bootstrap provider.
// +optional
BootstrapReady bool `json:"bootstrapReady"`
// InfrastructureReady is the state of the infrastructure provider.
// +optional
InfrastructureReady bool `json:"infrastructureReady"`
}
// ANCHOR_END: MachineStatus
// SetTypedPhase sets the Phase field to the string representation of MachinePhase.
func (m *MachineStatus) SetTypedPhase(p MachinePhase) <span class="cov0" title="0">{
m.Phase = string(p)
}</span>
// GetTypedPhase attempts to parse the Phase field and return
// the typed MachinePhase representation as described in `machine_phase_types.go`.
func (m *MachineStatus) GetTypedPhase() MachinePhase <span class="cov0" title="0">{
switch phase := MachinePhase(m.Phase); phase </span>{
case
MachinePhasePending,
MachinePhaseProvisioning,
MachinePhaseProvisioned,
MachinePhaseRunning,
MachinePhaseDeleting,
MachinePhaseDeleted,
MachinePhaseFailed:<span class="cov0" title="0">
return phase</span>
default:<span class="cov0" title="0">
return MachinePhaseUnknown</span>
}
}
// ANCHOR: Bootstrap
// Bootstrap capsulates fields to configure the Machine’s bootstrapping mechanism.
type Bootstrap struct {
// ConfigRef is a reference to a bootstrap provider-specific resource
// that holds configuration details. The reference is optional to
// allow users/operators to specify Bootstrap.Data without
// the need of a controller.
// +optional
ConfigRef *corev1.ObjectReference `json:"configRef,omitempty"`
// Data contains the bootstrap data, such as cloud-init details scripts.
// If nil, the Machine should remain in the Pending state.
// +optional
Data *string `json:"data,omitempty"`
}
// ANCHOR_END: Bootstrap
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=machines,shortName=ma,scope=Namespaced,categories=cluster-api
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="ProviderID",type="string",JSONPath=".spec.providerID",description="Provider ID"
// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Machine status such as Terminating/Pending/Running/Failed etc"
// +kubebuilder:printcolumn:name="NodeName",type="string",JSONPath=".status.nodeRef.name",description="Node name associated with this machine",priority=1
// Machine is the Schema for the machines API
type Machine struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec MachineSpec `json:"spec,omitempty"`
Status MachineStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// MachineList contains a list of Machine
type MachineList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Machine `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;Machine{}, &amp;MachineList{})
}</span>
</pre>
<pre class="file" id="file6" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
// log is for logging in this package.
var _ = logf.Log.WithName("machine-resource")
func (r *Machine) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file7" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
type MachineDeploymentStrategyType string
const (
// Replace the old MachineSet by new one using rolling update
// i.e. gradually scale down the old MachineSet and scale up the new one.
RollingUpdateMachineDeploymentStrategyType MachineDeploymentStrategyType = "RollingUpdate"
// RevisionAnnotation is the revision annotation of a machine deployment's machine sets which records its rollout sequence
RevisionAnnotation = "machinedeployment.clusters.k8s.io/revision"
// RevisionHistoryAnnotation maintains the history of all old revisions that a machine set has served for a machine deployment.
RevisionHistoryAnnotation = "machinedeployment.clusters.k8s.io/revision-history"
// DesiredReplicasAnnotation is the desired replicas for a machine deployment recorded as an annotation
// in its machine sets. Helps in separating scaling events from the rollout process and for
// determining if the new machine set for a deployment is really saturated.
DesiredReplicasAnnotation = "machinedeployment.clusters.k8s.io/desired-replicas"
// MaxReplicasAnnotation is the maximum replicas a deployment can have at a given point, which
// is machinedeployment.spec.replicas + maxSurge. Used by the underlying machine sets to estimate their
// proportions in case the deployment has surge replicas.
MaxReplicasAnnotation = "machinedeployment.clusters.k8s.io/max-replicas"
)
// ANCHOR: MachineDeploymentSpec
// MachineDeploymentSpec defines the desired state of MachineDeployment
type MachineDeploymentSpec struct {
// Number of desired machines. Defaults to 1.
// This is a pointer to distinguish between explicit zero and not specified.
Replicas *int32 `json:"replicas,omitempty"`
// Label selector for machines. Existing MachineSets whose machines are
// selected by this will be the ones affected by this deployment.
// It must match the machine template's labels.
Selector metav1.LabelSelector `json:"selector"`
// Template describes the machines that will be created.
Template MachineTemplateSpec `json:"template"`
// The deployment strategy to use to replace existing machines with
// new ones.
// +optional
Strategy *MachineDeploymentStrategy `json:"strategy,omitempty"`
// Minimum number of seconds for which a newly created machine should
// be ready.
// Defaults to 0 (machine will be considered available as soon as it
// is ready)
// +optional
MinReadySeconds *int32 `json:"minReadySeconds,omitempty"`
// The number of old MachineSets to retain to allow rollback.
// This is a pointer to distinguish between explicit zero and not specified.
// Defaults to 1.
// +optional
RevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty"`
// Indicates that the deployment is paused.
// +optional
Paused bool `json:"paused,omitempty"`
// The maximum time in seconds for a deployment to make progress before it
// is considered to be failed. The deployment controller will continue to
// process failed deployments and a condition with a ProgressDeadlineExceeded
// reason will be surfaced in the deployment status. Note that progress will
// not be estimated during the time a deployment is paused. Defaults to 600s.
ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty"`
}
// ANCHOR_END: MachineDeploymentSpec
// ANCHOR: MachineDeploymentStrategy
// MachineDeploymentStrategy describes how to replace existing machines
// with new ones.
type MachineDeploymentStrategy struct {
// Type of deployment. Currently the only supported strategy is
// "RollingUpdate".
// Default is RollingUpdate.
// +optional
Type MachineDeploymentStrategyType `json:"type,omitempty"`
// Rolling update config params. Present only if
// MachineDeploymentStrategyType = RollingUpdate.
// +optional
RollingUpdate *MachineRollingUpdateDeployment `json:"rollingUpdate,omitempty"`
}
// ANCHOR_END: MachineDeploymentStrategy
// ANCHOR: MachineRollingUpdateDeployment
// MachineRollingUpdateDeployment is used to control the desired behavior of rolling update.
type MachineRollingUpdateDeployment struct {
// The maximum number of machines that can be unavailable during the update.
// Value can be an absolute number (ex: 5) or a percentage of desired
// machines (ex: 10%).
// Absolute number is calculated from percentage by rounding down.
// This can not be 0 if MaxSurge is 0.
// Defaults to 0.
// Example: when this is set to 30%, the old MachineSet can be scaled
// down to 70% of desired machines immediately when the rolling update
// starts. Once new machines are ready, old MachineSet can be scaled
// down further, followed by scaling up the new MachineSet, ensuring
// that the total number of machines available at all times
// during the update is at least 70% of desired machines.
// +optional
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
// The maximum number of machines that can be scheduled above the
// desired number of machines.
// Value can be an absolute number (ex: 5) or a percentage of
// desired machines (ex: 10%).
// This can not be 0 if MaxUnavailable is 0.
// Absolute number is calculated from percentage by rounding up.
// Defaults to 1.
// Example: when this is set to 30%, the new MachineSet can be scaled
// up immediately when the rolling update starts, such that the total
// number of old and new machines do not exceed 130% of desired
// machines. Once old machines have been killed, new MachineSet can
// be scaled up further, ensuring that total number of machines running
// at any time during the update is at most 130% of desired machines.
// +optional
MaxSurge *intstr.IntOrString `json:"maxSurge,omitempty"`
}
// ANCHOR_END: MachineRollingUpdateDeployment
// ANCHOR: MachineDeploymentStatus
// MachineDeploymentStatus defines the observed state of MachineDeployment
type MachineDeploymentStatus struct {
// The generation observed by the deployment controller.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// Selector is the same as the label selector but in the string format to avoid introspection
// by clients. The string will be in the same format as the query-param syntax.
// More info about label selectors: http://kubernetes.io/docs/user-guide/labels#label-selectors
// +optional
Selector string `json:"selector,omitempty"`
// Total number of non-terminated machines targeted by this deployment
// (their labels match the selector).
// +optional
Replicas int32 `json:"replicas,omitempty"`
// Total number of non-terminated machines targeted by this deployment
// that have the desired template spec.
// +optional
UpdatedReplicas int32 `json:"updatedReplicas,omitempty"`
// Total number of ready machines targeted by this deployment.
// +optional
ReadyReplicas int32 `json:"readyReplicas,omitempty"`
// Total number of available machines (ready for at least minReadySeconds)
// targeted by this deployment.
// +optional
AvailableReplicas int32 `json:"availableReplicas,omitempty"`
// Total number of unavailable machines targeted by this deployment.
// This is the total number of machines that are still required for
// the deployment to have 100% available capacity. They may either
// be machines that are running but not yet available or machines
// that still have not been created.
// +optional
UnavailableReplicas int32 `json:"unavailableReplicas,omitempty"`
}
// ANCHOR_END: MachineDeploymentStatus
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=machinedeployments,shortName=md,scope=Namespaced,categories=cluster-api
// +kubebuilder:subresource:status
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector
// MachineDeployment is the Schema for the machinedeployments API
type MachineDeployment struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec MachineDeploymentSpec `json:"spec,omitempty"`
Status MachineDeploymentStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// MachineDeploymentList contains a list of MachineDeployment
type MachineDeploymentList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []MachineDeployment `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;MachineDeployment{}, &amp;MachineDeploymentList{})
}</span>
</pre>
<pre class="file" id="file8" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
// log is for logging in this package.
var _ = logf.Log.WithName("machinedeployment-resource")
func (r *MachineDeployment) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file9" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
// log is for logging in this package.
var _ = logf.Log.WithName("machinedeploymentlist-resource")
func (r *MachineDeploymentList) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file10" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
// log is for logging in this package.
var _ = logf.Log.WithName("machinelist-resource")
func (r *MachineList) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file11" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
"log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/validation/field"
capierrors "sigs.k8s.io/cluster-api/errors"
)
// ANCHOR: MachineSetSpec
// MachineSetSpec defines the desired state of MachineSet
type MachineSetSpec struct {
// Replicas is the number of desired replicas.
// This is a pointer to distinguish between explicit zero and unspecified.
// Defaults to 1.
// +optional
Replicas *int32 `json:"replicas,omitempty"`
// MinReadySeconds is the minimum number of seconds for which a newly created machine should be ready.
// Defaults to 0 (machine will be considered available as soon as it is ready)
// +optional
MinReadySeconds int32 `json:"minReadySeconds,omitempty"`
// DeletePolicy defines the policy used to identify nodes to delete when downscaling.
// Defaults to "Random". Valid values are "Random, "Newest", "Oldest"
// +kubebuilder:validation:Enum=Random;Newest;Oldest
DeletePolicy string `json:"deletePolicy,omitempty"`
// Selector is a label query over machines that should match the replica count.
// Label keys and values that must match in order to be controlled by this MachineSet.
// It must match the machine template's labels.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
Selector metav1.LabelSelector `json:"selector"`
// Template is the object that describes the machine that will be created if
// insufficient replicas are detected.
// Object references to custom resources resources are treated as templates.
// +optional
Template MachineTemplateSpec `json:"template,omitempty"`
}
// ANCHOR_END: MachineSetSpec
// ANCHOR: MachineTemplateSpec
// MachineTemplateSpec describes the data needed to create a Machine from a template
type MachineTemplateSpec struct {
// Standard object's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
ObjectMeta `json:"metadata,omitempty"`
// Specification of the desired behavior of the machine.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
// +optional
Spec MachineSpec `json:"spec,omitempty"`
}
// ANCHOR_END: MachineTemplateSpec
// MachineSetDeletePolicy defines how priority is assigned to nodes to delete when
// downscaling a MachineSet. Defaults to "Random".
type MachineSetDeletePolicy string
const (
// RandomMachineSetDeletePolicy prioritizes both Machines that have the annotation
// "cluster.x-k8s.io/delete-machine=yes" and Machines that are unhealthy
// (Status.ErrorReason or Status.ErrorMessage are set to a non-empty value).
// Finally, it picks Machines at random to delete.
RandomMachineSetDeletePolicy MachineSetDeletePolicy = "Random"
// NewestMachineSetDeletePolicy prioritizes both Machines that have the annotation
// "cluster.x-k8s.io/delete-machine=yes" and Machines that are unhealthy
// (Status.ErrorReason or Status.ErrorMessage are set to a non-empty value).
// It then prioritizes the newest Machines for deletion based on the Machine's CreationTimestamp.
NewestMachineSetDeletePolicy MachineSetDeletePolicy = "Newest"
// OldestMachineSetDeletePolicy prioritizes both Machines that have the annotation
// "cluster.x-k8s.io/delete-machine=yes" and Machines that are unhealthy
// (Status.ErrorReason or Status.ErrorMessage are set to a non-empty value).
// It then prioritizes the oldest Machines for deletion based on the Machine's CreationTimestamp.
OldestMachineSetDeletePolicy MachineSetDeletePolicy = "Oldest"
)
// ANCHOR: MachineSetStatus
// MachineSetStatus defines the observed state of MachineSet
type MachineSetStatus struct {
// Selector is the same as the label selector but in the string format to avoid introspection
// by clients. The string will be in the same format as the query-param syntax.
// More info about label selectors: http://kubernetes.io/docs/user-guide/labels#label-selectors
// +optional
Selector string `json:"selector,omitempty"`
// Replicas is the most recently observed number of replicas.
Replicas int32 `json:"replicas"`
// The number of replicas that have labels matching the labels of the machine template of the MachineSet.
// +optional
FullyLabeledReplicas int32 `json:"fullyLabeledReplicas,omitempty"`
// The number of ready replicas for this MachineSet. A machine is considered ready when the node has been created and is "Ready".
// +optional
ReadyReplicas int32 `json:"readyReplicas,omitempty"`
// The number of available replicas (ready for at least minReadySeconds) for this MachineSet.
// +optional
AvailableReplicas int32 `json:"availableReplicas,omitempty"`
// ObservedGeneration reflects the generation of the most recently observed MachineSet.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// In the event that there is a terminal problem reconciling the
// replicas, both ErrorReason and ErrorMessage will be set. ErrorReason
// will be populated with a succinct value suitable for machine
// interpretation, while ErrorMessage will contain a more verbose
// string suitable for logging and human consumption.
//
// These fields should not be set for transitive errors that a
// controller faces that are expected to be fixed automatically over
// time (like service outages), but instead indicate that something is
// fundamentally wrong with the MachineTemplate's spec or the configuration of
// the machine controller, and that manual intervention is required. Examples
// of terminal errors would be invalid combinations of settings in the
// spec, values that are unsupported by the machine controller, or the
// responsible machine controller itself being critically misconfigured.
//
// Any transient errors that occur during the reconciliation of Machines
// can be added as events to the MachineSet object and/or logged in the
// controller's output.
// +optional
ErrorReason *capierrors.MachineSetStatusError `json:"errorReason,omitempty"`
// +optional
ErrorMessage *string `json:"errorMessage,omitempty"`
}
// ANCHOR_END: MachineSetStatus
// Validate validates the MachineSet fields.
func (m *MachineSet) Validate() field.ErrorList <span class="cov0" title="0">{
errors := field.ErrorList{}
// validate spec.selector and spec.template.labels
fldPath := field.NewPath("spec")
errors = append(errors, metav1validation.ValidateLabelSelector(&amp;m.Spec.Selector, fldPath.Child("selector"))...)
if len(m.Spec.Selector.MatchLabels)+len(m.Spec.Selector.MatchExpressions) == 0 </span><span class="cov0" title="0">{
errors = append(errors, field.Invalid(fldPath.Child("selector"), m.Spec.Selector, "empty selector is not valid for MachineSet."))
}</span>
<span class="cov0" title="0">selector, err := metav1.LabelSelectorAsSelector(&amp;m.Spec.Selector)
if err != nil </span><span class="cov0" title="0">{
errors = append(errors, field.Invalid(fldPath.Child("selector"), m.Spec.Selector, "invalid label selector."))
}</span> else<span class="cov0" title="0"> {
labels := labels.Set(m.Spec.Template.Labels)
if !selector.Matches(labels) </span><span class="cov0" title="0">{
errors = append(errors, field.Invalid(fldPath.Child("template", "metadata", "labels"), m.Spec.Template.Labels, "`selector` does not match template `labels`"))
}</span>
}
<span class="cov0" title="0">return errors</span>
}
// DefaultingFunction sets default MachineSet field values.
func (m *MachineSet) Default() <span class="cov0" title="0">{
log.Printf("Defaulting fields for MachineSet %s\n", m.Name)
if m.Spec.Replicas == nil </span><span class="cov0" title="0">{
m.Spec.Replicas = new(int32)
*m.Spec.Replicas = 1
}</span>
<span class="cov0" title="0">if len(m.Namespace) == 0 </span><span class="cov0" title="0">{
m.Namespace = metav1.NamespaceDefault
}</span>
<span class="cov0" title="0">if m.Spec.DeletePolicy == "" </span><span class="cov0" title="0">{
randomPolicy := string(RandomMachineSetDeletePolicy)
log.Printf("Defaulting to %s\n", randomPolicy)
m.Spec.DeletePolicy = randomPolicy
}</span>
}
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=machinesets,shortName=ms,scope=Namespaced,categories=cluster-api
// +kubebuilder:subresource:status
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector
// MachineSet is the Schema for the machinesets API
type MachineSet struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec MachineSetSpec `json:"spec,omitempty"`
Status MachineSetStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// MachineSetList contains a list of MachineSet
type MachineSetList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []MachineSet `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;MachineSet{}, &amp;MachineSetList{})
}</span>
</pre>
<pre class="file" id="file12" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
// log is for logging in this package.
var _ = logf.Log.WithName("machineset-resource")
func (r *MachineSet) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file13" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
// log is for logging in this package.
var _ = logf.Log.WithName("machinesetlist-resource")
func (r *MachineSetList) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file14" style="display: none">// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by conversion-gen. DO NOT EDIT.
package v1alpha2
import (
unsafe "unsafe"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
intstr "k8s.io/apimachinery/pkg/util/intstr"
v1alpha3 "sigs.k8s.io/cluster-api/api/v1alpha3"
)
func init() <span class="cov8" title="1">{
localSchemeBuilder.Register(RegisterConversions)
}</span>
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error <span class="cov0" title="0">{
if err := s.AddGeneratedConversionFunc((*APIEndpoint)(nil), (*v1alpha3.APIEndpoint)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_APIEndpoint_To_v1alpha3_APIEndpoint(a.(*APIEndpoint), b.(*v1alpha3.APIEndpoint), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.APIEndpoint)(nil), (*APIEndpoint)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_APIEndpoint_To_v1alpha2_APIEndpoint(a.(*v1alpha3.APIEndpoint), b.(*APIEndpoint), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*Bootstrap)(nil), (*v1alpha3.Bootstrap)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_Bootstrap_To_v1alpha3_Bootstrap(a.(*Bootstrap), b.(*v1alpha3.Bootstrap), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*Cluster)(nil), (*v1alpha3.Cluster)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_Cluster_To_v1alpha3_Cluster(a.(*Cluster), b.(*v1alpha3.Cluster), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.Cluster)(nil), (*Cluster)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_Cluster_To_v1alpha2_Cluster(a.(*v1alpha3.Cluster), b.(*Cluster), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*ClusterList)(nil), (*v1alpha3.ClusterList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_ClusterList_To_v1alpha3_ClusterList(a.(*ClusterList), b.(*v1alpha3.ClusterList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.ClusterList)(nil), (*ClusterList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_ClusterList_To_v1alpha2_ClusterList(a.(*v1alpha3.ClusterList), b.(*ClusterList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*ClusterNetwork)(nil), (*v1alpha3.ClusterNetwork)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_ClusterNetwork_To_v1alpha3_ClusterNetwork(a.(*ClusterNetwork), b.(*v1alpha3.ClusterNetwork), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.ClusterNetwork)(nil), (*ClusterNetwork)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_ClusterNetwork_To_v1alpha2_ClusterNetwork(a.(*v1alpha3.ClusterNetwork), b.(*ClusterNetwork), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*Machine)(nil), (*v1alpha3.Machine)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_Machine_To_v1alpha3_Machine(a.(*Machine), b.(*v1alpha3.Machine), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.Machine)(nil), (*Machine)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_Machine_To_v1alpha2_Machine(a.(*v1alpha3.Machine), b.(*Machine), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineAddress)(nil), (*v1alpha3.MachineAddress)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineAddress_To_v1alpha3_MachineAddress(a.(*MachineAddress), b.(*v1alpha3.MachineAddress), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.MachineAddress)(nil), (*MachineAddress)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineAddress_To_v1alpha2_MachineAddress(a.(*v1alpha3.MachineAddress), b.(*MachineAddress), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineDeployment)(nil), (*v1alpha3.MachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineDeployment_To_v1alpha3_MachineDeployment(a.(*MachineDeployment), b.(*v1alpha3.MachineDeployment), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.MachineDeployment)(nil), (*MachineDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineDeployment_To_v1alpha2_MachineDeployment(a.(*v1alpha3.MachineDeployment), b.(*MachineDeployment), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineDeploymentList)(nil), (*v1alpha3.MachineDeploymentList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineDeploymentList_To_v1alpha3_MachineDeploymentList(a.(*MachineDeploymentList), b.(*v1alpha3.MachineDeploymentList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.MachineDeploymentList)(nil), (*MachineDeploymentList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineDeploymentList_To_v1alpha2_MachineDeploymentList(a.(*v1alpha3.MachineDeploymentList), b.(*MachineDeploymentList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineDeploymentSpec)(nil), (*v1alpha3.MachineDeploymentSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec(a.(*MachineDeploymentSpec), b.(*v1alpha3.MachineDeploymentSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineDeploymentStatus)(nil), (*v1alpha3.MachineDeploymentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus(a.(*MachineDeploymentStatus), b.(*v1alpha3.MachineDeploymentStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineDeploymentStrategy)(nil), (*v1alpha3.MachineDeploymentStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineDeploymentStrategy_To_v1alpha3_MachineDeploymentStrategy(a.(*MachineDeploymentStrategy), b.(*v1alpha3.MachineDeploymentStrategy), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.MachineDeploymentStrategy)(nil), (*MachineDeploymentStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineDeploymentStrategy_To_v1alpha2_MachineDeploymentStrategy(a.(*v1alpha3.MachineDeploymentStrategy), b.(*MachineDeploymentStrategy), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineList)(nil), (*v1alpha3.MachineList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineList_To_v1alpha3_MachineList(a.(*MachineList), b.(*v1alpha3.MachineList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.MachineList)(nil), (*MachineList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineList_To_v1alpha2_MachineList(a.(*v1alpha3.MachineList), b.(*MachineList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineRollingUpdateDeployment)(nil), (*v1alpha3.MachineRollingUpdateDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineRollingUpdateDeployment_To_v1alpha3_MachineRollingUpdateDeployment(a.(*MachineRollingUpdateDeployment), b.(*v1alpha3.MachineRollingUpdateDeployment), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.MachineRollingUpdateDeployment)(nil), (*MachineRollingUpdateDeployment)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineRollingUpdateDeployment_To_v1alpha2_MachineRollingUpdateDeployment(a.(*v1alpha3.MachineRollingUpdateDeployment), b.(*MachineRollingUpdateDeployment), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineSet)(nil), (*v1alpha3.MachineSet)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineSet_To_v1alpha3_MachineSet(a.(*MachineSet), b.(*v1alpha3.MachineSet), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.MachineSet)(nil), (*MachineSet)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineSet_To_v1alpha2_MachineSet(a.(*v1alpha3.MachineSet), b.(*MachineSet), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineSetList)(nil), (*v1alpha3.MachineSetList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineSetList_To_v1alpha3_MachineSetList(a.(*MachineSetList), b.(*v1alpha3.MachineSetList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.MachineSetList)(nil), (*MachineSetList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineSetList_To_v1alpha2_MachineSetList(a.(*v1alpha3.MachineSetList), b.(*MachineSetList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineSetSpec)(nil), (*v1alpha3.MachineSetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineSetSpec_To_v1alpha3_MachineSetSpec(a.(*MachineSetSpec), b.(*v1alpha3.MachineSetSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*MachineTemplateSpec)(nil), (*v1alpha3.MachineTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineTemplateSpec_To_v1alpha3_MachineTemplateSpec(a.(*MachineTemplateSpec), b.(*v1alpha3.MachineTemplateSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.MachineTemplateSpec)(nil), (*MachineTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineTemplateSpec_To_v1alpha2_MachineTemplateSpec(a.(*v1alpha3.MachineTemplateSpec), b.(*MachineTemplateSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*NetworkRanges)(nil), (*v1alpha3.NetworkRanges)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_NetworkRanges_To_v1alpha3_NetworkRanges(a.(*NetworkRanges), b.(*v1alpha3.NetworkRanges), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.NetworkRanges)(nil), (*NetworkRanges)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_NetworkRanges_To_v1alpha2_NetworkRanges(a.(*v1alpha3.NetworkRanges), b.(*NetworkRanges), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*ObjectMeta)(nil), (*v1alpha3.ObjectMeta)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_ObjectMeta_To_v1alpha3_ObjectMeta(a.(*ObjectMeta), b.(*v1alpha3.ObjectMeta), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.ObjectMeta)(nil), (*ObjectMeta)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_ObjectMeta_To_v1alpha2_ObjectMeta(a.(*v1alpha3.ObjectMeta), b.(*ObjectMeta), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*ClusterSpec)(nil), (*v1alpha3.ClusterSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(a.(*ClusterSpec), b.(*v1alpha3.ClusterSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*ClusterStatus)(nil), (*v1alpha3.ClusterStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(a.(*ClusterStatus), b.(*v1alpha3.ClusterStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*MachineSetStatus)(nil), (*v1alpha3.MachineSetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineSetStatus_To_v1alpha3_MachineSetStatus(a.(*MachineSetStatus), b.(*v1alpha3.MachineSetStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*MachineSpec)(nil), (*v1alpha3.MachineSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineSpec_To_v1alpha3_MachineSpec(a.(*MachineSpec), b.(*v1alpha3.MachineSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*MachineStatus)(nil), (*v1alpha3.MachineStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_MachineStatus_To_v1alpha3_MachineStatus(a.(*MachineStatus), b.(*v1alpha3.MachineStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.Bootstrap)(nil), (*Bootstrap)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_Bootstrap_To_v1alpha2_Bootstrap(a.(*v1alpha3.Bootstrap), b.(*Bootstrap), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.ClusterSpec)(nil), (*ClusterSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(a.(*v1alpha3.ClusterSpec), b.(*ClusterSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.ClusterStatus)(nil), (*ClusterStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_ClusterStatus_To_v1alpha2_ClusterStatus(a.(*v1alpha3.ClusterStatus), b.(*ClusterStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.MachineDeploymentSpec)(nil), (*MachineDeploymentSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineDeploymentSpec_To_v1alpha2_MachineDeploymentSpec(a.(*v1alpha3.MachineDeploymentSpec), b.(*MachineDeploymentSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.MachineDeploymentStatus)(nil), (*MachineDeploymentStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineDeploymentStatus_To_v1alpha2_MachineDeploymentStatus(a.(*v1alpha3.MachineDeploymentStatus), b.(*MachineDeploymentStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.MachineSetSpec)(nil), (*MachineSetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineSetSpec_To_v1alpha2_MachineSetSpec(a.(*v1alpha3.MachineSetSpec), b.(*MachineSetSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.MachineSetStatus)(nil), (*MachineSetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineSetStatus_To_v1alpha2_MachineSetStatus(a.(*v1alpha3.MachineSetStatus), b.(*MachineSetStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.MachineSpec)(nil), (*MachineSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineSpec_To_v1alpha2_MachineSpec(a.(*v1alpha3.MachineSpec), b.(*MachineSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.MachineStatus)(nil), (*MachineStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_MachineStatus_To_v1alpha2_MachineStatus(a.(*v1alpha3.MachineStatus), b.(*MachineStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
func autoConvert_v1alpha2_APIEndpoint_To_v1alpha3_APIEndpoint(in *APIEndpoint, out *v1alpha3.APIEndpoint, s conversion.Scope) error <span class="cov0" title="0">{
out.Host = in.Host
out.Port = int32(in.Port)
return nil
}</span>
// Convert_v1alpha2_APIEndpoint_To_v1alpha3_APIEndpoint is an autogenerated conversion function.
func Convert_v1alpha2_APIEndpoint_To_v1alpha3_APIEndpoint(in *APIEndpoint, out *v1alpha3.APIEndpoint, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_APIEndpoint_To_v1alpha3_APIEndpoint(in, out, s)
}</span>
func autoConvert_v1alpha3_APIEndpoint_To_v1alpha2_APIEndpoint(in *v1alpha3.APIEndpoint, out *APIEndpoint, s conversion.Scope) error <span class="cov0" title="0">{
out.Host = in.Host
out.Port = int(in.Port)
return nil
}</span>
// Convert_v1alpha3_APIEndpoint_To_v1alpha2_APIEndpoint is an autogenerated conversion function.
func Convert_v1alpha3_APIEndpoint_To_v1alpha2_APIEndpoint(in *v1alpha3.APIEndpoint, out *APIEndpoint, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_APIEndpoint_To_v1alpha2_APIEndpoint(in, out, s)
}</span>
func autoConvert_v1alpha2_Bootstrap_To_v1alpha3_Bootstrap(in *Bootstrap, out *v1alpha3.Bootstrap, s conversion.Scope) error <span class="cov8" title="1">{
out.ConfigRef = (*v1.ObjectReference)(unsafe.Pointer(in.ConfigRef))
out.Data = (*string)(unsafe.Pointer(in.Data))
return nil
}</span>
// Convert_v1alpha2_Bootstrap_To_v1alpha3_Bootstrap is an autogenerated conversion function.
func Convert_v1alpha2_Bootstrap_To_v1alpha3_Bootstrap(in *Bootstrap, out *v1alpha3.Bootstrap, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_Bootstrap_To_v1alpha3_Bootstrap(in, out, s)
}</span>
func autoConvert_v1alpha3_Bootstrap_To_v1alpha2_Bootstrap(in *v1alpha3.Bootstrap, out *Bootstrap, s conversion.Scope) error <span class="cov8" title="1">{
out.ConfigRef = (*v1.ObjectReference)(unsafe.Pointer(in.ConfigRef))
out.Data = (*string)(unsafe.Pointer(in.Data))
// WARNING: in.DataSecretName requires manual conversion: does not exist in peer-type
return nil
}</span>
func autoConvert_v1alpha2_Cluster_To_v1alpha3_Cluster(in *Cluster, out *v1alpha3.Cluster, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha2_Cluster_To_v1alpha3_Cluster is an autogenerated conversion function.
func Convert_v1alpha2_Cluster_To_v1alpha3_Cluster(in *Cluster, out *v1alpha3.Cluster, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_Cluster_To_v1alpha3_Cluster(in, out, s)
}</span>
func autoConvert_v1alpha3_Cluster_To_v1alpha2_Cluster(in *v1alpha3.Cluster, out *Cluster, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha3_ClusterStatus_To_v1alpha2_ClusterStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha3_Cluster_To_v1alpha2_Cluster is an autogenerated conversion function.
func Convert_v1alpha3_Cluster_To_v1alpha2_Cluster(in *v1alpha3.Cluster, out *Cluster, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_Cluster_To_v1alpha2_Cluster(in, out, s)
}</span>
func autoConvert_v1alpha2_ClusterList_To_v1alpha3_ClusterList(in *ClusterList, out *v1alpha3.ClusterList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]v1alpha3.Cluster, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha2_Cluster_To_v1alpha3_Cluster(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha2_ClusterList_To_v1alpha3_ClusterList is an autogenerated conversion function.
func Convert_v1alpha2_ClusterList_To_v1alpha3_ClusterList(in *ClusterList, out *v1alpha3.ClusterList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_ClusterList_To_v1alpha3_ClusterList(in, out, s)
}</span>
func autoConvert_v1alpha3_ClusterList_To_v1alpha2_ClusterList(in *v1alpha3.ClusterList, out *ClusterList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]Cluster, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha3_Cluster_To_v1alpha2_Cluster(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha3_ClusterList_To_v1alpha2_ClusterList is an autogenerated conversion function.
func Convert_v1alpha3_ClusterList_To_v1alpha2_ClusterList(in *v1alpha3.ClusterList, out *ClusterList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_ClusterList_To_v1alpha2_ClusterList(in, out, s)
}</span>
func autoConvert_v1alpha2_ClusterNetwork_To_v1alpha3_ClusterNetwork(in *ClusterNetwork, out *v1alpha3.ClusterNetwork, s conversion.Scope) error <span class="cov0" title="0">{
out.APIServerPort = (*int32)(unsafe.Pointer(in.APIServerPort))
out.Services = (*v1alpha3.NetworkRanges)(unsafe.Pointer(in.Services))
out.Pods = (*v1alpha3.NetworkRanges)(unsafe.Pointer(in.Pods))
out.ServiceDomain = in.ServiceDomain
return nil
}</span>
// Convert_v1alpha2_ClusterNetwork_To_v1alpha3_ClusterNetwork is an autogenerated conversion function.
func Convert_v1alpha2_ClusterNetwork_To_v1alpha3_ClusterNetwork(in *ClusterNetwork, out *v1alpha3.ClusterNetwork, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_ClusterNetwork_To_v1alpha3_ClusterNetwork(in, out, s)
}</span>
func autoConvert_v1alpha3_ClusterNetwork_To_v1alpha2_ClusterNetwork(in *v1alpha3.ClusterNetwork, out *ClusterNetwork, s conversion.Scope) error <span class="cov0" title="0">{
out.APIServerPort = (*int32)(unsafe.Pointer(in.APIServerPort))
out.Services = (*NetworkRanges)(unsafe.Pointer(in.Services))
out.Pods = (*NetworkRanges)(unsafe.Pointer(in.Pods))
out.ServiceDomain = in.ServiceDomain
return nil
}</span>
// Convert_v1alpha3_ClusterNetwork_To_v1alpha2_ClusterNetwork is an autogenerated conversion function.
func Convert_v1alpha3_ClusterNetwork_To_v1alpha2_ClusterNetwork(in *v1alpha3.ClusterNetwork, out *ClusterNetwork, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_ClusterNetwork_To_v1alpha2_ClusterNetwork(in, out, s)
}</span>
func autoConvert_v1alpha2_ClusterSpec_To_v1alpha3_ClusterSpec(in *ClusterSpec, out *v1alpha3.ClusterSpec, s conversion.Scope) error <span class="cov8" title="1">{
out.ClusterNetwork = (*v1alpha3.ClusterNetwork)(unsafe.Pointer(in.ClusterNetwork))
out.InfrastructureRef = (*v1.ObjectReference)(unsafe.Pointer(in.InfrastructureRef))
return nil
}</span>
func autoConvert_v1alpha3_ClusterSpec_To_v1alpha2_ClusterSpec(in *v1alpha3.ClusterSpec, out *ClusterSpec, s conversion.Scope) error <span class="cov8" title="1">{
// WARNING: in.Paused requires manual conversion: does not exist in peer-type
out.ClusterNetwork = (*ClusterNetwork)(unsafe.Pointer(in.ClusterNetwork))
// WARNING: in.ControlPlaneEndpoint requires manual conversion: does not exist in peer-type
// WARNING: in.ControlPlaneRef requires manual conversion: does not exist in peer-type
out.InfrastructureRef = (*v1.ObjectReference)(unsafe.Pointer(in.InfrastructureRef))
return nil
}</span>
func autoConvert_v1alpha2_ClusterStatus_To_v1alpha3_ClusterStatus(in *ClusterStatus, out *v1alpha3.ClusterStatus, s conversion.Scope) error <span class="cov8" title="1">{
// WARNING: in.APIEndpoints requires manual conversion: does not exist in peer-type
// WARNING: in.ErrorReason requires manual conversion: does not exist in peer-type
// WARNING: in.ErrorMessage requires manual conversion: does not exist in peer-type
out.Phase = in.Phase
out.InfrastructureReady = in.InfrastructureReady
out.ControlPlaneInitialized = in.ControlPlaneInitialized
return nil
}</span>
func autoConvert_v1alpha3_ClusterStatus_To_v1alpha2_ClusterStatus(in *v1alpha3.ClusterStatus, out *ClusterStatus, s conversion.Scope) error <span class="cov8" title="1">{
// WARNING: in.FailureDomains requires manual conversion: does not exist in peer-type
// WARNING: in.FailureReason requires manual conversion: does not exist in peer-type
// WARNING: in.FailureMessage requires manual conversion: does not exist in peer-type
out.Phase = in.Phase
out.InfrastructureReady = in.InfrastructureReady
out.ControlPlaneInitialized = in.ControlPlaneInitialized
// WARNING: in.ControlPlaneReady requires manual conversion: does not exist in peer-type
// WARNING: in.Conditions requires manual conversion: does not exist in peer-type
// WARNING: in.ObservedGeneration requires manual conversion: does not exist in peer-type
return nil
}</span>
func autoConvert_v1alpha2_Machine_To_v1alpha3_Machine(in *Machine, out *v1alpha3.Machine, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha2_MachineSpec_To_v1alpha3_MachineSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha2_MachineStatus_To_v1alpha3_MachineStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha2_Machine_To_v1alpha3_Machine is an autogenerated conversion function.
func Convert_v1alpha2_Machine_To_v1alpha3_Machine(in *Machine, out *v1alpha3.Machine, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_Machine_To_v1alpha3_Machine(in, out, s)
}</span>
func autoConvert_v1alpha3_Machine_To_v1alpha2_Machine(in *v1alpha3.Machine, out *Machine, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha3_MachineSpec_To_v1alpha2_MachineSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha3_MachineStatus_To_v1alpha2_MachineStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha3_Machine_To_v1alpha2_Machine is an autogenerated conversion function.
func Convert_v1alpha3_Machine_To_v1alpha2_Machine(in *v1alpha3.Machine, out *Machine, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_Machine_To_v1alpha2_Machine(in, out, s)
}</span>
func autoConvert_v1alpha2_MachineAddress_To_v1alpha3_MachineAddress(in *MachineAddress, out *v1alpha3.MachineAddress, s conversion.Scope) error <span class="cov0" title="0">{
out.Type = v1alpha3.MachineAddressType(in.Type)
out.Address = in.Address
return nil
}</span>
// Convert_v1alpha2_MachineAddress_To_v1alpha3_MachineAddress is an autogenerated conversion function.
func Convert_v1alpha2_MachineAddress_To_v1alpha3_MachineAddress(in *MachineAddress, out *v1alpha3.MachineAddress, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_MachineAddress_To_v1alpha3_MachineAddress(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineAddress_To_v1alpha2_MachineAddress(in *v1alpha3.MachineAddress, out *MachineAddress, s conversion.Scope) error <span class="cov0" title="0">{
out.Type = MachineAddressType(in.Type)
out.Address = in.Address
return nil
}</span>
// Convert_v1alpha3_MachineAddress_To_v1alpha2_MachineAddress is an autogenerated conversion function.
func Convert_v1alpha3_MachineAddress_To_v1alpha2_MachineAddress(in *v1alpha3.MachineAddress, out *MachineAddress, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_MachineAddress_To_v1alpha2_MachineAddress(in, out, s)
}</span>
func autoConvert_v1alpha2_MachineDeployment_To_v1alpha3_MachineDeployment(in *MachineDeployment, out *v1alpha3.MachineDeployment, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha2_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha2_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha2_MachineDeployment_To_v1alpha3_MachineDeployment is an autogenerated conversion function.
func Convert_v1alpha2_MachineDeployment_To_v1alpha3_MachineDeployment(in *MachineDeployment, out *v1alpha3.MachineDeployment, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_MachineDeployment_To_v1alpha3_MachineDeployment(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineDeployment_To_v1alpha2_MachineDeployment(in *v1alpha3.MachineDeployment, out *MachineDeployment, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha3_MachineDeploymentSpec_To_v1alpha2_MachineDeploymentSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha3_MachineDeploymentStatus_To_v1alpha2_MachineDeploymentStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha3_MachineDeployment_To_v1alpha2_MachineDeployment is an autogenerated conversion function.
func Convert_v1alpha3_MachineDeployment_To_v1alpha2_MachineDeployment(in *v1alpha3.MachineDeployment, out *MachineDeployment, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_MachineDeployment_To_v1alpha2_MachineDeployment(in, out, s)
}</span>
func autoConvert_v1alpha2_MachineDeploymentList_To_v1alpha3_MachineDeploymentList(in *MachineDeploymentList, out *v1alpha3.MachineDeploymentList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]v1alpha3.MachineDeployment, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha2_MachineDeployment_To_v1alpha3_MachineDeployment(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha2_MachineDeploymentList_To_v1alpha3_MachineDeploymentList is an autogenerated conversion function.
func Convert_v1alpha2_MachineDeploymentList_To_v1alpha3_MachineDeploymentList(in *MachineDeploymentList, out *v1alpha3.MachineDeploymentList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_MachineDeploymentList_To_v1alpha3_MachineDeploymentList(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineDeploymentList_To_v1alpha2_MachineDeploymentList(in *v1alpha3.MachineDeploymentList, out *MachineDeploymentList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]MachineDeployment, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha3_MachineDeployment_To_v1alpha2_MachineDeployment(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha3_MachineDeploymentList_To_v1alpha2_MachineDeploymentList is an autogenerated conversion function.
func Convert_v1alpha3_MachineDeploymentList_To_v1alpha2_MachineDeploymentList(in *v1alpha3.MachineDeploymentList, out *MachineDeploymentList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_MachineDeploymentList_To_v1alpha2_MachineDeploymentList(in, out, s)
}</span>
func autoConvert_v1alpha2_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec(in *MachineDeploymentSpec, out *v1alpha3.MachineDeploymentSpec, s conversion.Scope) error <span class="cov8" title="1">{
out.Replicas = (*int32)(unsafe.Pointer(in.Replicas))
out.Selector = in.Selector
if err := Convert_v1alpha2_MachineTemplateSpec_To_v1alpha3_MachineTemplateSpec(&amp;in.Template, &amp;out.Template, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">out.Strategy = (*v1alpha3.MachineDeploymentStrategy)(unsafe.Pointer(in.Strategy))
out.MinReadySeconds = (*int32)(unsafe.Pointer(in.MinReadySeconds))
out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
out.Paused = in.Paused
out.ProgressDeadlineSeconds = (*int32)(unsafe.Pointer(in.ProgressDeadlineSeconds))
return nil</span>
}
// Convert_v1alpha2_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec is an autogenerated conversion function.
func Convert_v1alpha2_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec(in *MachineDeploymentSpec, out *v1alpha3.MachineDeploymentSpec, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineDeploymentSpec_To_v1alpha2_MachineDeploymentSpec(in *v1alpha3.MachineDeploymentSpec, out *MachineDeploymentSpec, s conversion.Scope) error <span class="cov8" title="1">{
// WARNING: in.ClusterName requires manual conversion: does not exist in peer-type
out.Replicas = (*int32)(unsafe.Pointer(in.Replicas))
out.Selector = in.Selector
if err := Convert_v1alpha3_MachineTemplateSpec_To_v1alpha2_MachineTemplateSpec(&amp;in.Template, &amp;out.Template, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">out.Strategy = (*MachineDeploymentStrategy)(unsafe.Pointer(in.Strategy))
out.MinReadySeconds = (*int32)(unsafe.Pointer(in.MinReadySeconds))
out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
out.Paused = in.Paused
out.ProgressDeadlineSeconds = (*int32)(unsafe.Pointer(in.ProgressDeadlineSeconds))
return nil</span>
}
func autoConvert_v1alpha2_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus(in *MachineDeploymentStatus, out *v1alpha3.MachineDeploymentStatus, s conversion.Scope) error <span class="cov8" title="1">{
out.ObservedGeneration = in.ObservedGeneration
out.Selector = in.Selector
out.Replicas = in.Replicas
out.UpdatedReplicas = in.UpdatedReplicas
out.ReadyReplicas = in.ReadyReplicas
out.AvailableReplicas = in.AvailableReplicas
out.UnavailableReplicas = in.UnavailableReplicas
return nil
}</span>
// Convert_v1alpha2_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus is an autogenerated conversion function.
func Convert_v1alpha2_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus(in *MachineDeploymentStatus, out *v1alpha3.MachineDeploymentStatus, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineDeploymentStatus_To_v1alpha2_MachineDeploymentStatus(in *v1alpha3.MachineDeploymentStatus, out *MachineDeploymentStatus, s conversion.Scope) error <span class="cov8" title="1">{
out.ObservedGeneration = in.ObservedGeneration
out.Selector = in.Selector
out.Replicas = in.Replicas
out.UpdatedReplicas = in.UpdatedReplicas
out.ReadyReplicas = in.ReadyReplicas
out.AvailableReplicas = in.AvailableReplicas
out.UnavailableReplicas = in.UnavailableReplicas
// WARNING: in.Phase requires manual conversion: does not exist in peer-type
return nil
}</span>
func autoConvert_v1alpha2_MachineDeploymentStrategy_To_v1alpha3_MachineDeploymentStrategy(in *MachineDeploymentStrategy, out *v1alpha3.MachineDeploymentStrategy, s conversion.Scope) error <span class="cov0" title="0">{
out.Type = v1alpha3.MachineDeploymentStrategyType(in.Type)
out.RollingUpdate = (*v1alpha3.MachineRollingUpdateDeployment)(unsafe.Pointer(in.RollingUpdate))
return nil
}</span>
// Convert_v1alpha2_MachineDeploymentStrategy_To_v1alpha3_MachineDeploymentStrategy is an autogenerated conversion function.
func Convert_v1alpha2_MachineDeploymentStrategy_To_v1alpha3_MachineDeploymentStrategy(in *MachineDeploymentStrategy, out *v1alpha3.MachineDeploymentStrategy, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_MachineDeploymentStrategy_To_v1alpha3_MachineDeploymentStrategy(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineDeploymentStrategy_To_v1alpha2_MachineDeploymentStrategy(in *v1alpha3.MachineDeploymentStrategy, out *MachineDeploymentStrategy, s conversion.Scope) error <span class="cov0" title="0">{
out.Type = MachineDeploymentStrategyType(in.Type)
out.RollingUpdate = (*MachineRollingUpdateDeployment)(unsafe.Pointer(in.RollingUpdate))
return nil
}</span>
// Convert_v1alpha3_MachineDeploymentStrategy_To_v1alpha2_MachineDeploymentStrategy is an autogenerated conversion function.
func Convert_v1alpha3_MachineDeploymentStrategy_To_v1alpha2_MachineDeploymentStrategy(in *v1alpha3.MachineDeploymentStrategy, out *MachineDeploymentStrategy, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_MachineDeploymentStrategy_To_v1alpha2_MachineDeploymentStrategy(in, out, s)
}</span>
func autoConvert_v1alpha2_MachineList_To_v1alpha3_MachineList(in *MachineList, out *v1alpha3.MachineList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]v1alpha3.Machine, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha2_Machine_To_v1alpha3_Machine(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha2_MachineList_To_v1alpha3_MachineList is an autogenerated conversion function.
func Convert_v1alpha2_MachineList_To_v1alpha3_MachineList(in *MachineList, out *v1alpha3.MachineList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_MachineList_To_v1alpha3_MachineList(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineList_To_v1alpha2_MachineList(in *v1alpha3.MachineList, out *MachineList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]Machine, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha3_Machine_To_v1alpha2_Machine(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha3_MachineList_To_v1alpha2_MachineList is an autogenerated conversion function.
func Convert_v1alpha3_MachineList_To_v1alpha2_MachineList(in *v1alpha3.MachineList, out *MachineList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_MachineList_To_v1alpha2_MachineList(in, out, s)
}</span>
func autoConvert_v1alpha2_MachineRollingUpdateDeployment_To_v1alpha3_MachineRollingUpdateDeployment(in *MachineRollingUpdateDeployment, out *v1alpha3.MachineRollingUpdateDeployment, s conversion.Scope) error <span class="cov0" title="0">{
out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable))
out.MaxSurge = (*intstr.IntOrString)(unsafe.Pointer(in.MaxSurge))
return nil
}</span>
// Convert_v1alpha2_MachineRollingUpdateDeployment_To_v1alpha3_MachineRollingUpdateDeployment is an autogenerated conversion function.
func Convert_v1alpha2_MachineRollingUpdateDeployment_To_v1alpha3_MachineRollingUpdateDeployment(in *MachineRollingUpdateDeployment, out *v1alpha3.MachineRollingUpdateDeployment, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_MachineRollingUpdateDeployment_To_v1alpha3_MachineRollingUpdateDeployment(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineRollingUpdateDeployment_To_v1alpha2_MachineRollingUpdateDeployment(in *v1alpha3.MachineRollingUpdateDeployment, out *MachineRollingUpdateDeployment, s conversion.Scope) error <span class="cov0" title="0">{
out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable))
out.MaxSurge = (*intstr.IntOrString)(unsafe.Pointer(in.MaxSurge))
return nil
}</span>
// Convert_v1alpha3_MachineRollingUpdateDeployment_To_v1alpha2_MachineRollingUpdateDeployment is an autogenerated conversion function.
func Convert_v1alpha3_MachineRollingUpdateDeployment_To_v1alpha2_MachineRollingUpdateDeployment(in *v1alpha3.MachineRollingUpdateDeployment, out *MachineRollingUpdateDeployment, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_MachineRollingUpdateDeployment_To_v1alpha2_MachineRollingUpdateDeployment(in, out, s)
}</span>
func autoConvert_v1alpha2_MachineSet_To_v1alpha3_MachineSet(in *MachineSet, out *v1alpha3.MachineSet, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha2_MachineSetSpec_To_v1alpha3_MachineSetSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha2_MachineSetStatus_To_v1alpha3_MachineSetStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha2_MachineSet_To_v1alpha3_MachineSet is an autogenerated conversion function.
func Convert_v1alpha2_MachineSet_To_v1alpha3_MachineSet(in *MachineSet, out *v1alpha3.MachineSet, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_MachineSet_To_v1alpha3_MachineSet(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineSet_To_v1alpha2_MachineSet(in *v1alpha3.MachineSet, out *MachineSet, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha3_MachineSetSpec_To_v1alpha2_MachineSetSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha3_MachineSetStatus_To_v1alpha2_MachineSetStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha3_MachineSet_To_v1alpha2_MachineSet is an autogenerated conversion function.
func Convert_v1alpha3_MachineSet_To_v1alpha2_MachineSet(in *v1alpha3.MachineSet, out *MachineSet, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_MachineSet_To_v1alpha2_MachineSet(in, out, s)
}</span>
func autoConvert_v1alpha2_MachineSetList_To_v1alpha3_MachineSetList(in *MachineSetList, out *v1alpha3.MachineSetList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]v1alpha3.MachineSet, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha2_MachineSet_To_v1alpha3_MachineSet(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha2_MachineSetList_To_v1alpha3_MachineSetList is an autogenerated conversion function.
func Convert_v1alpha2_MachineSetList_To_v1alpha3_MachineSetList(in *MachineSetList, out *v1alpha3.MachineSetList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_MachineSetList_To_v1alpha3_MachineSetList(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineSetList_To_v1alpha2_MachineSetList(in *v1alpha3.MachineSetList, out *MachineSetList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]MachineSet, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha3_MachineSet_To_v1alpha2_MachineSet(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha3_MachineSetList_To_v1alpha2_MachineSetList is an autogenerated conversion function.
func Convert_v1alpha3_MachineSetList_To_v1alpha2_MachineSetList(in *v1alpha3.MachineSetList, out *MachineSetList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_MachineSetList_To_v1alpha2_MachineSetList(in, out, s)
}</span>
func autoConvert_v1alpha2_MachineSetSpec_To_v1alpha3_MachineSetSpec(in *MachineSetSpec, out *v1alpha3.MachineSetSpec, s conversion.Scope) error <span class="cov8" title="1">{
out.Replicas = (*int32)(unsafe.Pointer(in.Replicas))
out.MinReadySeconds = in.MinReadySeconds
out.DeletePolicy = in.DeletePolicy
out.Selector = in.Selector
if err := Convert_v1alpha2_MachineTemplateSpec_To_v1alpha3_MachineTemplateSpec(&amp;in.Template, &amp;out.Template, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha2_MachineSetSpec_To_v1alpha3_MachineSetSpec is an autogenerated conversion function.
func Convert_v1alpha2_MachineSetSpec_To_v1alpha3_MachineSetSpec(in *MachineSetSpec, out *v1alpha3.MachineSetSpec, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_MachineSetSpec_To_v1alpha3_MachineSetSpec(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineSetSpec_To_v1alpha2_MachineSetSpec(in *v1alpha3.MachineSetSpec, out *MachineSetSpec, s conversion.Scope) error <span class="cov8" title="1">{
// WARNING: in.ClusterName requires manual conversion: does not exist in peer-type
out.Replicas = (*int32)(unsafe.Pointer(in.Replicas))
out.MinReadySeconds = in.MinReadySeconds
out.DeletePolicy = in.DeletePolicy
out.Selector = in.Selector
if err := Convert_v1alpha3_MachineTemplateSpec_To_v1alpha2_MachineTemplateSpec(&amp;in.Template, &amp;out.Template, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
func autoConvert_v1alpha2_MachineSetStatus_To_v1alpha3_MachineSetStatus(in *MachineSetStatus, out *v1alpha3.MachineSetStatus, s conversion.Scope) error <span class="cov8" title="1">{
out.Selector = in.Selector
out.Replicas = in.Replicas
out.FullyLabeledReplicas = in.FullyLabeledReplicas
out.ReadyReplicas = in.ReadyReplicas
out.AvailableReplicas = in.AvailableReplicas
out.ObservedGeneration = in.ObservedGeneration
// WARNING: in.ErrorReason requires manual conversion: does not exist in peer-type
// WARNING: in.ErrorMessage requires manual conversion: does not exist in peer-type
return nil
}</span>
func autoConvert_v1alpha3_MachineSetStatus_To_v1alpha2_MachineSetStatus(in *v1alpha3.MachineSetStatus, out *MachineSetStatus, s conversion.Scope) error <span class="cov8" title="1">{
out.Selector = in.Selector
out.Replicas = in.Replicas
out.FullyLabeledReplicas = in.FullyLabeledReplicas
out.ReadyReplicas = in.ReadyReplicas
out.AvailableReplicas = in.AvailableReplicas
out.ObservedGeneration = in.ObservedGeneration
// WARNING: in.FailureReason requires manual conversion: does not exist in peer-type
// WARNING: in.FailureMessage requires manual conversion: does not exist in peer-type
return nil
}</span>
func autoConvert_v1alpha2_MachineSpec_To_v1alpha3_MachineSpec(in *MachineSpec, out *v1alpha3.MachineSpec, s conversion.Scope) error <span class="cov8" title="1">{
// WARNING: in.ObjectMeta requires manual conversion: does not exist in peer-type
if err := Convert_v1alpha2_Bootstrap_To_v1alpha3_Bootstrap(&amp;in.Bootstrap, &amp;out.Bootstrap, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">out.InfrastructureRef = in.InfrastructureRef
out.Version = (*string)(unsafe.Pointer(in.Version))
out.ProviderID = (*string)(unsafe.Pointer(in.ProviderID))
return nil</span>
}
func autoConvert_v1alpha3_MachineSpec_To_v1alpha2_MachineSpec(in *v1alpha3.MachineSpec, out *MachineSpec, s conversion.Scope) error <span class="cov8" title="1">{
// WARNING: in.ClusterName requires manual conversion: does not exist in peer-type
if err := Convert_v1alpha3_Bootstrap_To_v1alpha2_Bootstrap(&amp;in.Bootstrap, &amp;out.Bootstrap, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">out.InfrastructureRef = in.InfrastructureRef
out.Version = (*string)(unsafe.Pointer(in.Version))
out.ProviderID = (*string)(unsafe.Pointer(in.ProviderID))
// WARNING: in.FailureDomain requires manual conversion: does not exist in peer-type
return nil</span>
}
func autoConvert_v1alpha2_MachineStatus_To_v1alpha3_MachineStatus(in *MachineStatus, out *v1alpha3.MachineStatus, s conversion.Scope) error <span class="cov8" title="1">{
out.NodeRef = (*v1.ObjectReference)(unsafe.Pointer(in.NodeRef))
out.LastUpdated = (*metav1.Time)(unsafe.Pointer(in.LastUpdated))
out.Version = (*string)(unsafe.Pointer(in.Version))
// WARNING: in.ErrorReason requires manual conversion: does not exist in peer-type
// WARNING: in.ErrorMessage requires manual conversion: does not exist in peer-type
out.Addresses = *(*v1alpha3.MachineAddresses)(unsafe.Pointer(&amp;in.Addresses))
out.Phase = in.Phase
out.BootstrapReady = in.BootstrapReady
out.InfrastructureReady = in.InfrastructureReady
return nil
}</span>
func autoConvert_v1alpha3_MachineStatus_To_v1alpha2_MachineStatus(in *v1alpha3.MachineStatus, out *MachineStatus, s conversion.Scope) error <span class="cov8" title="1">{
out.NodeRef = (*v1.ObjectReference)(unsafe.Pointer(in.NodeRef))
out.LastUpdated = (*metav1.Time)(unsafe.Pointer(in.LastUpdated))
out.Version = (*string)(unsafe.Pointer(in.Version))
// WARNING: in.FailureReason requires manual conversion: does not exist in peer-type
// WARNING: in.FailureMessage requires manual conversion: does not exist in peer-type
out.Addresses = *(*MachineAddresses)(unsafe.Pointer(&amp;in.Addresses))
out.Phase = in.Phase
out.BootstrapReady = in.BootstrapReady
out.InfrastructureReady = in.InfrastructureReady
// WARNING: in.ObservedGeneration requires manual conversion: does not exist in peer-type
// WARNING: in.Conditions requires manual conversion: does not exist in peer-type
return nil
}</span>
func autoConvert_v1alpha2_MachineTemplateSpec_To_v1alpha3_MachineTemplateSpec(in *MachineTemplateSpec, out *v1alpha3.MachineTemplateSpec, s conversion.Scope) error <span class="cov8" title="1">{
if err := Convert_v1alpha2_ObjectMeta_To_v1alpha3_ObjectMeta(&amp;in.ObjectMeta, &amp;out.ObjectMeta, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha2_MachineSpec_To_v1alpha3_MachineSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha2_MachineTemplateSpec_To_v1alpha3_MachineTemplateSpec is an autogenerated conversion function.
func Convert_v1alpha2_MachineTemplateSpec_To_v1alpha3_MachineTemplateSpec(in *MachineTemplateSpec, out *v1alpha3.MachineTemplateSpec, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_MachineTemplateSpec_To_v1alpha3_MachineTemplateSpec(in, out, s)
}</span>
func autoConvert_v1alpha3_MachineTemplateSpec_To_v1alpha2_MachineTemplateSpec(in *v1alpha3.MachineTemplateSpec, out *MachineTemplateSpec, s conversion.Scope) error <span class="cov8" title="1">{
if err := Convert_v1alpha3_ObjectMeta_To_v1alpha2_ObjectMeta(&amp;in.ObjectMeta, &amp;out.ObjectMeta, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha3_MachineSpec_To_v1alpha2_MachineSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha3_MachineTemplateSpec_To_v1alpha2_MachineTemplateSpec is an autogenerated conversion function.
func Convert_v1alpha3_MachineTemplateSpec_To_v1alpha2_MachineTemplateSpec(in *v1alpha3.MachineTemplateSpec, out *MachineTemplateSpec, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_MachineTemplateSpec_To_v1alpha2_MachineTemplateSpec(in, out, s)
}</span>
func autoConvert_v1alpha2_NetworkRanges_To_v1alpha3_NetworkRanges(in *NetworkRanges, out *v1alpha3.NetworkRanges, s conversion.Scope) error <span class="cov0" title="0">{
out.CIDRBlocks = *(*[]string)(unsafe.Pointer(&amp;in.CIDRBlocks))
return nil
}</span>
// Convert_v1alpha2_NetworkRanges_To_v1alpha3_NetworkRanges is an autogenerated conversion function.
func Convert_v1alpha2_NetworkRanges_To_v1alpha3_NetworkRanges(in *NetworkRanges, out *v1alpha3.NetworkRanges, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_NetworkRanges_To_v1alpha3_NetworkRanges(in, out, s)
}</span>
func autoConvert_v1alpha3_NetworkRanges_To_v1alpha2_NetworkRanges(in *v1alpha3.NetworkRanges, out *NetworkRanges, s conversion.Scope) error <span class="cov0" title="0">{
out.CIDRBlocks = *(*[]string)(unsafe.Pointer(&amp;in.CIDRBlocks))
return nil
}</span>
// Convert_v1alpha3_NetworkRanges_To_v1alpha2_NetworkRanges is an autogenerated conversion function.
func Convert_v1alpha3_NetworkRanges_To_v1alpha2_NetworkRanges(in *v1alpha3.NetworkRanges, out *NetworkRanges, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_NetworkRanges_To_v1alpha2_NetworkRanges(in, out, s)
}</span>
func autoConvert_v1alpha2_ObjectMeta_To_v1alpha3_ObjectMeta(in *ObjectMeta, out *v1alpha3.ObjectMeta, s conversion.Scope) error <span class="cov8" title="1">{
out.Name = in.Name
out.GenerateName = in.GenerateName
out.Namespace = in.Namespace
out.Labels = *(*map[string]string)(unsafe.Pointer(&amp;in.Labels))
out.Annotations = *(*map[string]string)(unsafe.Pointer(&amp;in.Annotations))
out.OwnerReferences = *(*[]metav1.OwnerReference)(unsafe.Pointer(&amp;in.OwnerReferences))
return nil
}</span>
// Convert_v1alpha2_ObjectMeta_To_v1alpha3_ObjectMeta is an autogenerated conversion function.
func Convert_v1alpha2_ObjectMeta_To_v1alpha3_ObjectMeta(in *ObjectMeta, out *v1alpha3.ObjectMeta, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_ObjectMeta_To_v1alpha3_ObjectMeta(in, out, s)
}</span>
func autoConvert_v1alpha3_ObjectMeta_To_v1alpha2_ObjectMeta(in *v1alpha3.ObjectMeta, out *ObjectMeta, s conversion.Scope) error <span class="cov8" title="1">{
out.Name = in.Name
out.GenerateName = in.GenerateName
out.Namespace = in.Namespace
out.Labels = *(*map[string]string)(unsafe.Pointer(&amp;in.Labels))
out.Annotations = *(*map[string]string)(unsafe.Pointer(&amp;in.Annotations))
out.OwnerReferences = *(*[]metav1.OwnerReference)(unsafe.Pointer(&amp;in.OwnerReferences))
return nil
}</span>
// Convert_v1alpha3_ObjectMeta_To_v1alpha2_ObjectMeta is an autogenerated conversion function.
func Convert_v1alpha3_ObjectMeta_To_v1alpha2_ObjectMeta(in *v1alpha3.ObjectMeta, out *ObjectMeta, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_ObjectMeta_To_v1alpha2_ObjectMeta(in, out, s)
}</span>
</pre>
<pre class="file" id="file15" style="display: none">// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1alpha2
import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/cluster-api/errors"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *APIEndpoint) DeepCopyInto(out *APIEndpoint) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIEndpoint.
func (in *APIEndpoint) DeepCopy() *APIEndpoint <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(APIEndpoint)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Bootstrap) DeepCopyInto(out *Bootstrap) <span class="cov8" title="1">{
*out = *in
if in.ConfigRef != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ConfigRef, &amp;out.ConfigRef
*out = new(v1.ObjectReference)
**out = **in
}</span>
<span class="cov8" title="1">if in.Data != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Data, &amp;out.Data
*out = new(string)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bootstrap.
func (in *Bootstrap) DeepCopy() *Bootstrap <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Bootstrap)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Cluster) DeepCopyInto(out *Cluster) <span class="cov8" title="1">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
in.Status.DeepCopyInto(&amp;out.Status)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster.
func (in *Cluster) DeepCopy() *Cluster <span class="cov8" title="1">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov8" title="1">out := new(Cluster)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Cluster) DeepCopyObject() runtime.Object <span class="cov8" title="1">{
if c := in.DeepCopy(); c != nil </span><span class="cov8" title="1">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterList) DeepCopyInto(out *ClusterList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]Cluster, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterList.
func (in *ClusterList) DeepCopy() *ClusterList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ClusterList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterNetwork) DeepCopyInto(out *ClusterNetwork) <span class="cov0" title="0">{
*out = *in
if in.APIServerPort != nil </span><span class="cov0" title="0">{
in, out := &amp;in.APIServerPort, &amp;out.APIServerPort
*out = new(int32)
**out = **in
}</span>
<span class="cov0" title="0">if in.Services != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Services, &amp;out.Services
*out = new(NetworkRanges)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.Pods != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Pods, &amp;out.Pods
*out = new(NetworkRanges)
(*in).DeepCopyInto(*out)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterNetwork.
func (in *ClusterNetwork) DeepCopy() *ClusterNetwork <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterNetwork)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) <span class="cov8" title="1">{
*out = *in
if in.ClusterNetwork != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ClusterNetwork, &amp;out.ClusterNetwork
*out = new(ClusterNetwork)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov8" title="1">if in.InfrastructureRef != nil </span><span class="cov0" title="0">{
in, out := &amp;in.InfrastructureRef, &amp;out.InfrastructureRef
*out = new(v1.ObjectReference)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSpec.
func (in *ClusterSpec) DeepCopy() *ClusterSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) <span class="cov8" title="1">{
*out = *in
if in.APIEndpoints != nil </span><span class="cov0" title="0">{
in, out := &amp;in.APIEndpoints, &amp;out.APIEndpoints
*out = make([]APIEndpoint, len(*in))
copy(*out, *in)
}</span>
<span class="cov8" title="1">if in.ErrorReason != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ErrorReason, &amp;out.ErrorReason
*out = new(errors.ClusterStatusError)
**out = **in
}</span>
<span class="cov8" title="1">if in.ErrorMessage != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ErrorMessage, &amp;out.ErrorMessage
*out = new(string)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus.
func (in *ClusterStatus) DeepCopy() *ClusterStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Machine) DeepCopyInto(out *Machine) <span class="cov8" title="1">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
in.Status.DeepCopyInto(&amp;out.Status)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Machine.
func (in *Machine) DeepCopy() *Machine <span class="cov8" title="1">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov8" title="1">out := new(Machine)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Machine) DeepCopyObject() runtime.Object <span class="cov8" title="1">{
if c := in.DeepCopy(); c != nil </span><span class="cov8" title="1">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineAddress) DeepCopyInto(out *MachineAddress) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineAddress.
func (in *MachineAddress) DeepCopy() *MachineAddress <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineAddress)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in MachineAddresses) DeepCopyInto(out *MachineAddresses) <span class="cov0" title="0">{
</span><span class="cov0" title="0">{
in := &amp;in
*out = make(MachineAddresses, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineAddresses.
func (in MachineAddresses) DeepCopy() MachineAddresses <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineAddresses)
in.DeepCopyInto(out)
return *out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeployment) DeepCopyInto(out *MachineDeployment) <span class="cov8" title="1">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
out.Status = in.Status
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeployment.
func (in *MachineDeployment) DeepCopy() *MachineDeployment <span class="cov8" title="1">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov8" title="1">out := new(MachineDeployment)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineDeployment) DeepCopyObject() runtime.Object <span class="cov8" title="1">{
if c := in.DeepCopy(); c != nil </span><span class="cov8" title="1">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeploymentList) DeepCopyInto(out *MachineDeploymentList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]MachineDeployment, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentList.
func (in *MachineDeploymentList) DeepCopy() *MachineDeploymentList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineDeploymentList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineDeploymentList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeploymentSpec) DeepCopyInto(out *MachineDeploymentSpec) <span class="cov8" title="1">{
*out = *in
if in.Replicas != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Replicas, &amp;out.Replicas
*out = new(int32)
**out = **in
}</span>
<span class="cov8" title="1">in.Selector.DeepCopyInto(&amp;out.Selector)
in.Template.DeepCopyInto(&amp;out.Template)
if in.Strategy != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Strategy, &amp;out.Strategy
*out = new(MachineDeploymentStrategy)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov8" title="1">if in.MinReadySeconds != nil </span><span class="cov0" title="0">{
in, out := &amp;in.MinReadySeconds, &amp;out.MinReadySeconds
*out = new(int32)
**out = **in
}</span>
<span class="cov8" title="1">if in.RevisionHistoryLimit != nil </span><span class="cov0" title="0">{
in, out := &amp;in.RevisionHistoryLimit, &amp;out.RevisionHistoryLimit
*out = new(int32)
**out = **in
}</span>
<span class="cov8" title="1">if in.ProgressDeadlineSeconds != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ProgressDeadlineSeconds, &amp;out.ProgressDeadlineSeconds
*out = new(int32)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentSpec.
func (in *MachineDeploymentSpec) DeepCopy() *MachineDeploymentSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineDeploymentSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeploymentStatus) DeepCopyInto(out *MachineDeploymentStatus) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStatus.
func (in *MachineDeploymentStatus) DeepCopy() *MachineDeploymentStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineDeploymentStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeploymentStrategy) DeepCopyInto(out *MachineDeploymentStrategy) <span class="cov0" title="0">{
*out = *in
if in.RollingUpdate != nil </span><span class="cov0" title="0">{
in, out := &amp;in.RollingUpdate, &amp;out.RollingUpdate
*out = new(MachineRollingUpdateDeployment)
(*in).DeepCopyInto(*out)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStrategy.
func (in *MachineDeploymentStrategy) DeepCopy() *MachineDeploymentStrategy <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineDeploymentStrategy)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineList) DeepCopyInto(out *MachineList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]Machine, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineList.
func (in *MachineList) DeepCopy() *MachineList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineRollingUpdateDeployment) DeepCopyInto(out *MachineRollingUpdateDeployment) <span class="cov0" title="0">{
*out = *in
if in.MaxUnavailable != nil </span><span class="cov0" title="0">{
in, out := &amp;in.MaxUnavailable, &amp;out.MaxUnavailable
*out = new(intstr.IntOrString)
**out = **in
}</span>
<span class="cov0" title="0">if in.MaxSurge != nil </span><span class="cov0" title="0">{
in, out := &amp;in.MaxSurge, &amp;out.MaxSurge
*out = new(intstr.IntOrString)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineRollingUpdateDeployment.
func (in *MachineRollingUpdateDeployment) DeepCopy() *MachineRollingUpdateDeployment <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineRollingUpdateDeployment)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSet) DeepCopyInto(out *MachineSet) <span class="cov8" title="1">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
in.Status.DeepCopyInto(&amp;out.Status)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSet.
func (in *MachineSet) DeepCopy() *MachineSet <span class="cov8" title="1">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov8" title="1">out := new(MachineSet)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineSet) DeepCopyObject() runtime.Object <span class="cov8" title="1">{
if c := in.DeepCopy(); c != nil </span><span class="cov8" title="1">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSetList) DeepCopyInto(out *MachineSetList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]MachineSet, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetList.
func (in *MachineSetList) DeepCopy() *MachineSetList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineSetList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineSetList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSetSpec) DeepCopyInto(out *MachineSetSpec) <span class="cov8" title="1">{
*out = *in
if in.Replicas != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Replicas, &amp;out.Replicas
*out = new(int32)
**out = **in
}</span>
<span class="cov8" title="1">in.Selector.DeepCopyInto(&amp;out.Selector)
in.Template.DeepCopyInto(&amp;out.Template)</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetSpec.
func (in *MachineSetSpec) DeepCopy() *MachineSetSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineSetSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSetStatus) DeepCopyInto(out *MachineSetStatus) <span class="cov8" title="1">{
*out = *in
if in.ErrorReason != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ErrorReason, &amp;out.ErrorReason
*out = new(errors.MachineSetStatusError)
**out = **in
}</span>
<span class="cov8" title="1">if in.ErrorMessage != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ErrorMessage, &amp;out.ErrorMessage
*out = new(string)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetStatus.
func (in *MachineSetStatus) DeepCopy() *MachineSetStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineSetStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSpec) DeepCopyInto(out *MachineSpec) <span class="cov8" title="1">{
*out = *in
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Bootstrap.DeepCopyInto(&amp;out.Bootstrap)
out.InfrastructureRef = in.InfrastructureRef
if in.Version != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Version, &amp;out.Version
*out = new(string)
**out = **in
}</span>
<span class="cov8" title="1">if in.ProviderID != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ProviderID, &amp;out.ProviderID
*out = new(string)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSpec.
func (in *MachineSpec) DeepCopy() *MachineSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineStatus) DeepCopyInto(out *MachineStatus) <span class="cov8" title="1">{
*out = *in
if in.NodeRef != nil </span><span class="cov0" title="0">{
in, out := &amp;in.NodeRef, &amp;out.NodeRef
*out = new(v1.ObjectReference)
**out = **in
}</span>
<span class="cov8" title="1">if in.LastUpdated != nil </span><span class="cov0" title="0">{
in, out := &amp;in.LastUpdated, &amp;out.LastUpdated
*out = (*in).DeepCopy()
}</span>
<span class="cov8" title="1">if in.Version != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Version, &amp;out.Version
*out = new(string)
**out = **in
}</span>
<span class="cov8" title="1">if in.ErrorReason != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ErrorReason, &amp;out.ErrorReason
*out = new(errors.MachineStatusError)
**out = **in
}</span>
<span class="cov8" title="1">if in.ErrorMessage != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ErrorMessage, &amp;out.ErrorMessage
*out = new(string)
**out = **in
}</span>
<span class="cov8" title="1">if in.Addresses != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Addresses, &amp;out.Addresses
*out = make(MachineAddresses, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineStatus.
func (in *MachineStatus) DeepCopy() *MachineStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineTemplateSpec) DeepCopyInto(out *MachineTemplateSpec) <span class="cov8" title="1">{
*out = *in
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplateSpec.
func (in *MachineTemplateSpec) DeepCopy() *MachineTemplateSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineTemplateSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkRanges) DeepCopyInto(out *NetworkRanges) <span class="cov0" title="0">{
*out = *in
if in.CIDRBlocks != nil </span><span class="cov0" title="0">{
in, out := &amp;in.CIDRBlocks, &amp;out.CIDRBlocks
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkRanges.
func (in *NetworkRanges) DeepCopy() *NetworkRanges <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(NetworkRanges)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObjectMeta) DeepCopyInto(out *ObjectMeta) <span class="cov8" title="1">{
*out = *in
if in.Labels != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Labels, &amp;out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
<span class="cov8" title="1">if in.Annotations != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Annotations, &amp;out.Annotations
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
<span class="cov8" title="1">if in.OwnerReferences != nil </span><span class="cov0" title="0">{
in, out := &amp;in.OwnerReferences, &amp;out.OwnerReferences
*out = make([]metav1.OwnerReference, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectMeta.
func (in *ObjectMeta) DeepCopy() *ObjectMeta <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ObjectMeta)
in.DeepCopyInto(out)
return out</span>
}
</pre>
<pre class="file" id="file16" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
"fmt"
"strings"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
capierrors "sigs.k8s.io/cluster-api/errors"
)
const (
ClusterFinalizer = "cluster.cluster.x-k8s.io"
)
// ANCHOR: ClusterSpec
// ClusterSpec defines the desired state of Cluster
type ClusterSpec struct {
// Paused can be used to prevent controllers from processing the Cluster and all its associated objects.
// +optional
Paused bool `json:"paused,omitempty"`
// Cluster network configuration.
// +optional
ClusterNetwork *ClusterNetwork `json:"clusterNetwork,omitempty"`
// ControlPlaneEndpoint represents the endpoint used to communicate with the control plane.
// +optional
ControlPlaneEndpoint APIEndpoint `json:"controlPlaneEndpoint"`
// ControlPlaneRef is an optional reference to a provider-specific resource that holds
// the details for provisioning the Control Plane for a Cluster.
// +optional
ControlPlaneRef *corev1.ObjectReference `json:"controlPlaneRef,omitempty"`
// InfrastructureRef is a reference to a provider-specific resource that holds the details
// for provisioning infrastructure for a cluster in said provider.
// +optional
InfrastructureRef *corev1.ObjectReference `json:"infrastructureRef,omitempty"`
}
// ANCHOR_END: ClusterSpec
// ANCHOR: ClusterNetwork
// ClusterNetwork specifies the different networking
// parameters for a cluster.
type ClusterNetwork struct {
// APIServerPort specifies the port the API Server should bind to.
// Defaults to 6443.
// +optional
APIServerPort *int32 `json:"apiServerPort,omitempty"`
// The network ranges from which service VIPs are allocated.
// +optional
Services *NetworkRanges `json:"services,omitempty"`
// The network ranges from which Pod networks are allocated.
// +optional
Pods *NetworkRanges `json:"pods,omitempty"`
// Domain name for services.
// +optional
ServiceDomain string `json:"serviceDomain,omitempty"`
}
// ANCHOR_END: ClusterNetwork
// ANCHOR: NetworkRanges
// NetworkRanges represents ranges of network addresses.
type NetworkRanges struct {
CIDRBlocks []string `json:"cidrBlocks"`
}
func (n *NetworkRanges) String() string <span class="cov0" title="0">{
if n == nil </span><span class="cov0" title="0">{
return ""
}</span>
<span class="cov0" title="0">return strings.Join(n.CIDRBlocks, ",")</span>
}
// ANCHOR_END: NetworkRanges
// ANCHOR: ClusterStatus
// ClusterStatus defines the observed state of Cluster
type ClusterStatus struct {
// FailureDomains is a slice of failure domain objects synced from the infrastructure provider.
FailureDomains FailureDomains `json:"failureDomains,omitempty"`
// FailureReason indicates that there is a fatal problem reconciling the
// state, and will be set to a token value suitable for
// programmatic interpretation.
// +optional
FailureReason *capierrors.ClusterStatusError `json:"failureReason,omitempty"`
// FailureMessage indicates that there is a fatal problem reconciling the
// state, and will be set to a descriptive error message.
// +optional
FailureMessage *string `json:"failureMessage,omitempty"`
// Phase represents the current phase of cluster actuation.
// E.g. Pending, Running, Terminating, Failed etc.
// +optional
Phase string `json:"phase,omitempty"`
// InfrastructureReady is the state of the infrastructure provider.
// +optional
InfrastructureReady bool `json:"infrastructureReady"`
// ControlPlaneInitialized defines if the control plane has been initialized.
// +optional
ControlPlaneInitialized bool `json:"controlPlaneInitialized"`
// ControlPlaneReady defines if the control plane is ready.
// +optional
ControlPlaneReady bool `json:"controlPlaneReady,omitempty"`
// Conditions defines current service state of the cluster.
// +optional
Conditions Conditions `json:"conditions,omitempty"`
// ObservedGeneration is the latest generation observed by the controller.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}
// ANCHOR_END: ClusterStatus
// SetTypedPhase sets the Phase field to the string representation of ClusterPhase.
func (c *ClusterStatus) SetTypedPhase(p ClusterPhase) <span class="cov0" title="0">{
c.Phase = string(p)
}</span>
// GetTypedPhase attempts to parse the Phase field and return
// the typed ClusterPhase representation as described in `machine_phase_types.go`.
func (c *ClusterStatus) GetTypedPhase() ClusterPhase <span class="cov0" title="0">{
switch phase := ClusterPhase(c.Phase); phase </span>{
case
ClusterPhasePending,
ClusterPhaseProvisioning,
ClusterPhaseProvisioned,
ClusterPhaseDeleting,
ClusterPhaseFailed:<span class="cov0" title="0">
return phase</span>
default:<span class="cov0" title="0">
return ClusterPhaseUnknown</span>
}
}
// ANCHOR: APIEndpoint
// APIEndpoint represents a reachable Kubernetes API endpoint.
type APIEndpoint struct {
// The hostname on which the API server is serving.
Host string `json:"host"`
// The port on which the API server is serving.
Port int32 `json:"port"`
}
// IsZero returns true if host and the port are zero values.
func (v APIEndpoint) IsZero() bool <span class="cov0" title="0">{
return v.Host == "" &amp;&amp; v.Port == 0
}</span>
// String returns a formatted version HOST:PORT of this APIEndpoint.
func (v APIEndpoint) String() string <span class="cov0" title="0">{
return fmt.Sprintf("%s:%d", v.Host, v.Port)
}</span>
// ANCHOR_END: APIEndpoint
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=clusters,shortName=cl,scope=Namespaced,categories=cluster-api
// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Cluster status such as Pending/Provisioning/Provisioned/Deleting/Failed"
// Cluster is the Schema for the clusters API
type Cluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ClusterSpec `json:"spec,omitempty"`
Status ClusterStatus `json:"status,omitempty"`
}
func (c *Cluster) GetConditions() Conditions <span class="cov0" title="0">{
return c.Status.Conditions
}</span>
func (c *Cluster) SetConditions(conditions Conditions) <span class="cov0" title="0">{
c.Status.Conditions = conditions
}</span>
// +kubebuilder:object:root=true
// ClusterList contains a list of Cluster
type ClusterList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Cluster `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;Cluster{}, &amp;ClusterList{})
}</span>
// FailureDomains is a slice of FailureDomains.
type FailureDomains map[string]FailureDomainSpec
// FilterControlPlane returns a FailureDomain slice containing only the domains suitable to be used
// for control plane nodes.
func (in FailureDomains) FilterControlPlane() FailureDomains <span class="cov0" title="0">{
res := make(FailureDomains)
for id, spec := range in </span><span class="cov0" title="0">{
if spec.ControlPlane </span><span class="cov0" title="0">{
res[id] = spec
}</span>
}
<span class="cov0" title="0">return res</span>
}
// GetIDs returns a slice containing the ids for failure domains
func (in FailureDomains) GetIDs() []*string <span class="cov0" title="0">{
ids := make([]*string, 0, len(in))
for id := range in </span><span class="cov0" title="0">{
ids = append(ids, pointer.StringPtr(id))
}</span>
<span class="cov0" title="0">return ids</span>
}
// FailureDomainSpec is the Schema for Cluster API failure domains.
// It allows controllers to understand how many failure domains a cluster can optionally span across.
type FailureDomainSpec struct {
// ControlPlane determines if this failure domain is suitable for use by control plane machines.
// +optional
ControlPlane bool `json:"controlPlane"`
// Attributes is a free form map of attributes an infrastructure provider might use or require.
// +optional
Attributes map[string]string `json:"attributes,omitempty"`
}
</pre>
<pre class="file" id="file17" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)
func (c *Cluster) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(c).
Complete()
}</span>
// +kubebuilder:webhook:verbs=create;update,path=/validate-cluster-x-k8s-io-v1alpha3-cluster,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=clusters,versions=v1alpha3,name=validation.cluster.cluster.x-k8s.io,sideEffects=None
// +kubebuilder:webhook:verbs=create;update,path=/mutate-cluster-x-k8s-io-v1alpha3-cluster,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=clusters,versions=v1alpha3,name=default.cluster.cluster.x-k8s.io,sideEffects=None
var _ webhook.Defaulter = &amp;Cluster{}
var _ webhook.Validator = &amp;Cluster{}
func (c *Cluster) Default() <span class="cov8" title="1">{
if c.Spec.InfrastructureRef != nil &amp;&amp; len(c.Spec.InfrastructureRef.Namespace) == 0 </span><span class="cov8" title="1">{
c.Spec.InfrastructureRef.Namespace = c.Namespace
}</span>
<span class="cov8" title="1">if c.Spec.ControlPlaneRef != nil &amp;&amp; len(c.Spec.ControlPlaneRef.Namespace) == 0 </span><span class="cov8" title="1">{
c.Spec.ControlPlaneRef.Namespace = c.Namespace
}</span>
}
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (c *Cluster) ValidateCreate() error <span class="cov8" title="1">{
return c.validate()
}</span>
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (c *Cluster) ValidateUpdate(old runtime.Object) error <span class="cov8" title="1">{
return c.validate()
}</span>
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (c *Cluster) ValidateDelete() error <span class="cov0" title="0">{
return nil
}</span>
func (c *Cluster) validate() error <span class="cov8" title="1">{
var allErrs field.ErrorList
if c.Spec.InfrastructureRef != nil &amp;&amp; c.Spec.InfrastructureRef.Namespace != c.Namespace </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "infrastructureRef", "namespace"),
c.Spec.InfrastructureRef.Namespace,
"must match metadata.namespace",
),
)
}</span>
<span class="cov8" title="1">if c.Spec.ControlPlaneRef != nil &amp;&amp; c.Spec.ControlPlaneRef.Namespace != c.Namespace </span><span class="cov0" title="0">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "controlPlaneRef", "namespace"),
c.Spec.ControlPlaneRef.Namespace,
"must match metadata.namespace",
),
)
}</span>
<span class="cov8" title="1">if len(allErrs) == 0 </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov8" title="1">return apierrors.NewInvalid(GroupVersion.WithKind("Cluster").GroupKind(), c.Name, allErrs)</span>
}
</pre>
<pre class="file" id="file18" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
func (*Cluster) Hub() {<span class="cov0" title="0">}</span>
func (*ClusterList) Hub() {<span class="cov0" title="0">}</span>
func (*Machine) Hub() {<span class="cov0" title="0">}</span>
func (*MachineList) Hub() {<span class="cov0" title="0">}</span>
func (*MachineSet) Hub() {<span class="cov0" title="0">}</span>
func (*MachineSetList) Hub() {<span class="cov0" title="0">}</span>
func (*MachineDeployment) Hub() {<span class="cov0" title="0">}</span>
func (*MachineDeploymentList) Hub() {<span class="cov0" title="0">}</span>
func (*MachineHealthCheck) Hub() {<span class="cov0" title="0">}</span>
func (*MachineHealthCheckList) Hub() {<span class="cov0" title="0">}</span>
</pre>
<pre class="file" id="file19" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
capierrors "sigs.k8s.io/cluster-api/errors"
)
const (
// MachineFinalizer is set on PrepareForCreate callback.
MachineFinalizer = "machine.cluster.x-k8s.io"
// MachineControlPlaneLabelName is the label set on machines or related objects that are part of a control plane.
MachineControlPlaneLabelName = "cluster.x-k8s.io/control-plane"
// ExcludeNodeDrainingAnnotation annotation explicitly skips node draining if set
ExcludeNodeDrainingAnnotation = "machine.cluster.x-k8s.io/exclude-node-draining"
// MachineSetLabelName is the label set on machines if they're controlled by MachineSet
MachineSetLabelName = "cluster.x-k8s.io/set-name"
// MachineDeploymentLabelName is the label set on machines if they're controlled by MachineDeployment
MachineDeploymentLabelName = "cluster.x-k8s.io/deployment-name"
)
// ANCHOR: MachineSpec
// MachineSpec defines the desired state of Machine
type MachineSpec struct {
// ClusterName is the name of the Cluster this object belongs to.
// +kubebuilder:validation:MinLength=1
ClusterName string `json:"clusterName"`
// Bootstrap is a reference to a local struct which encapsulates
// fields to configure the Machine’s bootstrapping mechanism.
Bootstrap Bootstrap `json:"bootstrap"`
// InfrastructureRef is a required reference to a custom resource
// offered by an infrastructure provider.
InfrastructureRef corev1.ObjectReference `json:"infrastructureRef"`
// Version defines the desired Kubernetes version.
// This field is meant to be optionally used by bootstrap providers.
// +optional
Version *string `json:"version,omitempty"`
// ProviderID is the identification ID of the machine provided by the provider.
// This field must match the provider ID as seen on the node object corresponding to this machine.
// This field is required by higher level consumers of cluster-api. Example use case is cluster autoscaler
// with cluster-api as provider. Clean-up logic in the autoscaler compares machines to nodes to find out
// machines at provider which could not get registered as Kubernetes nodes. With cluster-api as a
// generic out-of-tree provider for autoscaler, this field is required by autoscaler to be
// able to have a provider view of the list of machines. Another list of nodes is queried from the k8s apiserver
// and then a comparison is done to find out unregistered machines and are marked for delete.
// This field will be set by the actuators and consumed by higher level entities like autoscaler that will
// be interfacing with cluster-api as generic provider.
// +optional
ProviderID *string `json:"providerID,omitempty"`
// FailureDomain is the failure domain the machine will be created in.
// Must match a key in the FailureDomains map stored on the cluster object.
// +optional
FailureDomain *string `json:"failureDomain,omitempty"`
}
// ANCHOR_END: MachineSpec
// ANCHOR: MachineStatus
// MachineStatus defines the observed state of Machine
type MachineStatus struct {
// NodeRef will point to the corresponding Node if it exists.
// +optional
NodeRef *corev1.ObjectReference `json:"nodeRef,omitempty"`
// LastUpdated identifies when the phase of the Machine last transitioned.
// +optional
LastUpdated *metav1.Time `json:"lastUpdated,omitempty"`
// Version specifies the current version of Kubernetes running
// on the corresponding Node. This is meant to be a means of bubbling
// up status from the Node to the Machine.
// It is entirely optional, but useful for end-user UX if it’s present.
// +optional
Version *string `json:"version,omitempty"`
// FailureReason will be set in the event that there is a terminal problem
// reconciling the Machine and will contain a succinct value suitable
// for machine interpretation.
//
// This field should not be set for transitive errors that a controller
// faces that are expected to be fixed automatically over
// time (like service outages), but instead indicate that something is
// fundamentally wrong with the Machine's spec or the configuration of
// the controller, and that manual intervention is required. Examples
// of terminal errors would be invalid combinations of settings in the
// spec, values that are unsupported by the controller, or the
// responsible controller itself being critically misconfigured.
//
// Any transient errors that occur during the reconciliation of Machines
// can be added as events to the Machine object and/or logged in the
// controller's output.
// +optional
FailureReason *capierrors.MachineStatusError `json:"failureReason,omitempty"`
// FailureMessage will be set in the event that there is a terminal problem
// reconciling the Machine and will contain a more verbose string suitable
// for logging and human consumption.
//
// This field should not be set for transitive errors that a controller
// faces that are expected to be fixed automatically over
// time (like service outages), but instead indicate that something is
// fundamentally wrong with the Machine's spec or the configuration of
// the controller, and that manual intervention is required. Examples
// of terminal errors would be invalid combinations of settings in the
// spec, values that are unsupported by the controller, or the
// responsible controller itself being critically misconfigured.
//
// Any transient errors that occur during the reconciliation of Machines
// can be added as events to the Machine object and/or logged in the
// controller's output.
// +optional
FailureMessage *string `json:"failureMessage,omitempty"`
// Addresses is a list of addresses assigned to the machine.
// This field is copied from the infrastructure provider reference.
// +optional
Addresses MachineAddresses `json:"addresses,omitempty"`
// Phase represents the current phase of machine actuation.
// E.g. Pending, Running, Terminating, Failed etc.
// +optional
Phase string `json:"phase,omitempty"`
// BootstrapReady is the state of the bootstrap provider.
// +optional
BootstrapReady bool `json:"bootstrapReady"`
// InfrastructureReady is the state of the infrastructure provider.
// +optional
InfrastructureReady bool `json:"infrastructureReady"`
// ObservedGeneration is the latest generation observed by the controller.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// Conditions defines current service state of the Machine.
// +optional
Conditions Conditions `json:"conditions,omitempty"`
}
// ANCHOR_END: MachineStatus
// SetTypedPhase sets the Phase field to the string representation of MachinePhase.
func (m *MachineStatus) SetTypedPhase(p MachinePhase) <span class="cov0" title="0">{
m.Phase = string(p)
}</span>
// GetTypedPhase attempts to parse the Phase field and return
// the typed MachinePhase representation as described in `machine_phase_types.go`.
func (m *MachineStatus) GetTypedPhase() MachinePhase <span class="cov0" title="0">{
switch phase := MachinePhase(m.Phase); phase </span>{
case
MachinePhasePending,
MachinePhaseProvisioning,
MachinePhaseProvisioned,
MachinePhaseRunning,
MachinePhaseDeleting,
MachinePhaseDeleted,
MachinePhaseFailed:<span class="cov0" title="0">
return phase</span>
default:<span class="cov0" title="0">
return MachinePhaseUnknown</span>
}
}
// ANCHOR: Bootstrap
// Bootstrap capsulates fields to configure the Machine’s bootstrapping mechanism.
type Bootstrap struct {
// ConfigRef is a reference to a bootstrap provider-specific resource
// that holds configuration details. The reference is optional to
// allow users/operators to specify Bootstrap.Data without
// the need of a controller.
// +optional
ConfigRef *corev1.ObjectReference `json:"configRef,omitempty"`
// Data contains the bootstrap data, such as cloud-init details scripts.
// If nil, the Machine should remain in the Pending state.
//
// Deprecated: This field has been deprecated in v1alpha3 and
// will be removed in a future version. Switch to DataSecretName.
//
// +optional
Data *string `json:"data,omitempty"`
// DataSecretName is the name of the secret that stores the bootstrap data script.
// If nil, the Machine should remain in the Pending state.
// +optional
DataSecretName *string `json:"dataSecretName,omitempty"`
}
// ANCHOR_END: Bootstrap
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=machines,shortName=ma,scope=Namespaced,categories=cluster-api
// +kubebuilder:subresource:status
// +kubebuilder:storageversion
// +kubebuilder:printcolumn:name="ProviderID",type="string",JSONPath=".spec.providerID",description="Provider ID"
// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Machine status such as Terminating/Pending/Running/Failed etc"
// +kubebuilder:printcolumn:name="NodeName",type="string",JSONPath=".status.nodeRef.name",description="Node name associated with this machine",priority=1
// Machine is the Schema for the machines API
type Machine struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec MachineSpec `json:"spec,omitempty"`
Status MachineStatus `json:"status,omitempty"`
}
func (m *Machine) GetConditions() Conditions <span class="cov0" title="0">{
return m.Status.Conditions
}</span>
func (m *Machine) SetConditions(conditions Conditions) <span class="cov0" title="0">{
m.Status.Conditions = conditions
}</span>
// +kubebuilder:object:root=true
// MachineList contains a list of Machine
type MachineList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Machine `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;Machine{}, &amp;MachineList{})
}</span>
</pre>
<pre class="file" id="file20" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
"fmt"
"regexp"
"strings"
apierrors "k8s.io/apimachinery/pkg/api/errors"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)
func (m *Machine) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(m).
Complete()
}</span>
// +kubebuilder:webhook:verbs=create;update,path=/validate-cluster-x-k8s-io-v1alpha3-machine,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machines,versions=v1alpha3,name=validation.machine.cluster.x-k8s.io,sideEffects=None
// +kubebuilder:webhook:verbs=create;update,path=/mutate-cluster-x-k8s-io-v1alpha3-machine,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machines,versions=v1alpha3,name=default.machine.cluster.x-k8s.io,sideEffects=None
var _ webhook.Validator = &amp;Machine{}
var _ webhook.Defaulter = &amp;Machine{}
var kubeSemver = regexp.MustCompile(`^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)([-0-9a-zA-Z_\.+]*)?$`)
// Default implements webhook.Defaulter so a webhook will be registered for the type
func (m *Machine) Default() <span class="cov8" title="1">{
if m.Labels == nil </span><span class="cov8" title="1">{
m.Labels = make(map[string]string)
}</span>
<span class="cov8" title="1">m.Labels[ClusterLabelName] = m.Spec.ClusterName
if m.Spec.Bootstrap.ConfigRef != nil &amp;&amp; len(m.Spec.Bootstrap.ConfigRef.Namespace) == 0 </span><span class="cov8" title="1">{
m.Spec.Bootstrap.ConfigRef.Namespace = m.Namespace
}</span>
<span class="cov8" title="1">if len(m.Spec.InfrastructureRef.Namespace) == 0 </span><span class="cov8" title="1">{
m.Spec.InfrastructureRef.Namespace = m.Namespace
}</span>
<span class="cov8" title="1">if m.Spec.Version != nil &amp;&amp; !strings.HasPrefix(*m.Spec.Version, "v") </span><span class="cov8" title="1">{
normalizedVersion := "v" + *m.Spec.Version
m.Spec.Version = &amp;normalizedVersion
}</span>
}
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (m *Machine) ValidateCreate() error <span class="cov8" title="1">{
return m.validate(nil)
}</span>
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (m *Machine) ValidateUpdate(old runtime.Object) error <span class="cov8" title="1">{
oldM, ok := old.(*Machine)
if !ok </span><span class="cov0" title="0">{
return apierrors.NewBadRequest(fmt.Sprintf("expected a Machine but got a %T", old))
}</span>
<span class="cov8" title="1">return m.validate(oldM)</span>
}
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (m *Machine) ValidateDelete() error <span class="cov0" title="0">{
return nil
}</span>
func (m *Machine) validate(old *Machine) error <span class="cov8" title="1">{
var allErrs field.ErrorList
if m.Spec.Bootstrap.ConfigRef == nil &amp;&amp; m.Spec.Bootstrap.DataSecretName == nil </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Required(
field.NewPath("spec", "bootstrap", "data"),
"expected either spec.bootstrap.dataSecretName or spec.bootstrap.configRef to be populated",
),
)
}</span>
<span class="cov8" title="1">if m.Spec.Bootstrap.ConfigRef != nil &amp;&amp; m.Spec.Bootstrap.ConfigRef.Namespace != m.Namespace </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "bootstrap", "configRef", "namespace"),
m.Spec.Bootstrap.ConfigRef.Namespace,
"must match metadata.namespace",
),
)
}</span>
<span class="cov8" title="1">if m.Spec.InfrastructureRef.Namespace != m.Namespace </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "infrastructureRef", "namespace"),
m.Spec.InfrastructureRef.Namespace,
"must match metadata.namespace",
),
)
}</span>
<span class="cov8" title="1">if old != nil &amp;&amp; old.Spec.ClusterName != m.Spec.ClusterName </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "clusterName"), m.Spec.ClusterName, "field is immutable"),
)
}</span>
<span class="cov8" title="1">if m.Spec.Version != nil </span><span class="cov8" title="1">{
if !kubeSemver.MatchString(*m.Spec.Version) </span><span class="cov8" title="1">{
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "version"), *m.Spec.Version, "must be a valid semantic version"))
}</span>
}
<span class="cov8" title="1">if len(allErrs) == 0 </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov8" title="1">return apierrors.NewInvalid(GroupVersion.WithKind("Machine").GroupKind(), m.Name, allErrs)</span>
}
</pre>
<pre class="file" id="file21" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
type MachineDeploymentStrategyType string
const (
// Replace the old MachineSet by new one using rolling update
// i.e. gradually scale down the old MachineSet and scale up the new one.
RollingUpdateMachineDeploymentStrategyType MachineDeploymentStrategyType = "RollingUpdate"
// RevisionAnnotation is the revision annotation of a machine deployment's machine sets which records its rollout sequence
RevisionAnnotation = "machinedeployment.clusters.x-k8s.io/revision"
// RevisionHistoryAnnotation maintains the history of all old revisions that a machine set has served for a machine deployment.
RevisionHistoryAnnotation = "machinedeployment.clusters.x-k8s.io/revision-history"
// DesiredReplicasAnnotation is the desired replicas for a machine deployment recorded as an annotation
// in its machine sets. Helps in separating scaling events from the rollout process and for
// determining if the new machine set for a deployment is really saturated.
DesiredReplicasAnnotation = "machinedeployment.clusters.x-k8s.io/desired-replicas"
// MaxReplicasAnnotation is the maximum replicas a deployment can have at a given point, which
// is machinedeployment.spec.replicas + maxSurge. Used by the underlying machine sets to estimate their
// proportions in case the deployment has surge replicas.
MaxReplicasAnnotation = "machinedeployment.clusters.x-k8s.io/max-replicas"
)
// ANCHOR: MachineDeploymentSpec
// MachineDeploymentSpec defines the desired state of MachineDeployment
type MachineDeploymentSpec struct {
// ClusterName is the name of the Cluster this object belongs to.
// +kubebuilder:validation:MinLength=1
ClusterName string `json:"clusterName"`
// Number of desired machines. Defaults to 1.
// This is a pointer to distinguish between explicit zero and not specified.
Replicas *int32 `json:"replicas,omitempty"`
// Label selector for machines. Existing MachineSets whose machines are
// selected by this will be the ones affected by this deployment.
// It must match the machine template's labels.
Selector metav1.LabelSelector `json:"selector"`
// Template describes the machines that will be created.
Template MachineTemplateSpec `json:"template"`
// The deployment strategy to use to replace existing machines with
// new ones.
// +optional
Strategy *MachineDeploymentStrategy `json:"strategy,omitempty"`
// Minimum number of seconds for which a newly created machine should
// be ready.
// Defaults to 0 (machine will be considered available as soon as it
// is ready)
// +optional
MinReadySeconds *int32 `json:"minReadySeconds,omitempty"`
// The number of old MachineSets to retain to allow rollback.
// This is a pointer to distinguish between explicit zero and not specified.
// Defaults to 1.
// +optional
RevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty"`
// Indicates that the deployment is paused.
// +optional
Paused bool `json:"paused,omitempty"`
// The maximum time in seconds for a deployment to make progress before it
// is considered to be failed. The deployment controller will continue to
// process failed deployments and a condition with a ProgressDeadlineExceeded
// reason will be surfaced in the deployment status. Note that progress will
// not be estimated during the time a deployment is paused. Defaults to 600s.
ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty"`
}
// ANCHOR_END: MachineDeploymentSpec
// ANCHOR: MachineDeploymentStrategy
// MachineDeploymentStrategy describes how to replace existing machines
// with new ones.
type MachineDeploymentStrategy struct {
// Type of deployment. Currently the only supported strategy is
// "RollingUpdate".
// Default is RollingUpdate.
// +optional
Type MachineDeploymentStrategyType `json:"type,omitempty"`
// Rolling update config params. Present only if
// MachineDeploymentStrategyType = RollingUpdate.
// +optional
RollingUpdate *MachineRollingUpdateDeployment `json:"rollingUpdate,omitempty"`
}
// ANCHOR_END: MachineDeploymentStrategy
// ANCHOR: MachineRollingUpdateDeployment
// MachineRollingUpdateDeployment is used to control the desired behavior of rolling update.
type MachineRollingUpdateDeployment struct {
// The maximum number of machines that can be unavailable during the update.
// Value can be an absolute number (ex: 5) or a percentage of desired
// machines (ex: 10%).
// Absolute number is calculated from percentage by rounding down.
// This can not be 0 if MaxSurge is 0.
// Defaults to 0.
// Example: when this is set to 30%, the old MachineSet can be scaled
// down to 70% of desired machines immediately when the rolling update
// starts. Once new machines are ready, old MachineSet can be scaled
// down further, followed by scaling up the new MachineSet, ensuring
// that the total number of machines available at all times
// during the update is at least 70% of desired machines.
// +optional
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
// The maximum number of machines that can be scheduled above the
// desired number of machines.
// Value can be an absolute number (ex: 5) or a percentage of
// desired machines (ex: 10%).
// This can not be 0 if MaxUnavailable is 0.
// Absolute number is calculated from percentage by rounding up.
// Defaults to 1.
// Example: when this is set to 30%, the new MachineSet can be scaled
// up immediately when the rolling update starts, such that the total
// number of old and new machines do not exceed 130% of desired
// machines. Once old machines have been killed, new MachineSet can
// be scaled up further, ensuring that total number of machines running
// at any time during the update is at most 130% of desired machines.
// +optional
MaxSurge *intstr.IntOrString `json:"maxSurge,omitempty"`
}
// ANCHOR_END: MachineRollingUpdateDeployment
// ANCHOR: MachineDeploymentStatus
// MachineDeploymentStatus defines the observed state of MachineDeployment
type MachineDeploymentStatus struct {
// The generation observed by the deployment controller.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// Selector is the same as the label selector but in the string format to avoid introspection
// by clients. The string will be in the same format as the query-param syntax.
// More info about label selectors: http://kubernetes.io/docs/user-guide/labels#label-selectors
// +optional
Selector string `json:"selector,omitempty"`
// Total number of non-terminated machines targeted by this deployment
// (their labels match the selector).
// +optional
Replicas int32 `json:"replicas,omitempty"`
// Total number of non-terminated machines targeted by this deployment
// that have the desired template spec.
// +optional
UpdatedReplicas int32 `json:"updatedReplicas,omitempty"`
// Total number of ready machines targeted by this deployment.
// +optional
ReadyReplicas int32 `json:"readyReplicas,omitempty"`
// Total number of available machines (ready for at least minReadySeconds)
// targeted by this deployment.
// +optional
AvailableReplicas int32 `json:"availableReplicas,omitempty"`
// Total number of unavailable machines targeted by this deployment.
// This is the total number of machines that are still required for
// the deployment to have 100% available capacity. They may either
// be machines that are running but not yet available or machines
// that still have not been created.
// +optional
UnavailableReplicas int32 `json:"unavailableReplicas,omitempty"`
// Phase represents the current phase of a MachineDeployment (ScalingUp, ScalingDown, Running, Failed, or Unknown).
// +optional
Phase string `json:"phase,omitempty"`
}
// ANCHOR_END: MachineDeploymentStatus
// MachineDeploymentPhase indicates the progress of the machine deployment
type MachineDeploymentPhase string
const (
// MachineDeploymentPhaseScalingUp indicates the MachineDeployment is scaling up.
MachineDeploymentPhaseScalingUp = MachineDeploymentPhase("ScalingUp")
// MachineDeploymentPhaseScalingDown indicates the MachineDeployment is scaling down.
MachineDeploymentPhaseScalingDown = MachineDeploymentPhase("ScalingDown")
// MachineDeploymentPhaseRunning indicates scaling has completed and all Machines are running.
MachineDeploymentPhaseRunning = MachineDeploymentPhase("Running")
// MachineDeploymentPhaseFailed indicates there was a problem scaling and user intervention might be required.
MachineDeploymentPhaseFailed = MachineDeploymentPhase("Failed")
// MachineDeploymentPhaseUnknown indicates the state of the MachineDeployment cannot be determined.
MachineDeploymentPhaseUnknown = MachineDeploymentPhase("Unknown")
)
// SetTypedPhase sets the Phase field to the string representation of MachineDeploymentPhase.
func (md *MachineDeploymentStatus) SetTypedPhase(p MachineDeploymentPhase) <span class="cov0" title="0">{
md.Phase = string(p)
}</span>
// GetTypedPhase attempts to parse the Phase field and return
// the typed MachineDeploymentPhase representation.
func (md *MachineDeploymentStatus) GetTypedPhase() MachineDeploymentPhase <span class="cov0" title="0">{
switch phase := MachineDeploymentPhase(md.Phase); phase </span>{
case
MachineDeploymentPhaseScalingDown,
MachineDeploymentPhaseScalingUp,
MachineDeploymentPhaseRunning,
MachineDeploymentPhaseFailed:<span class="cov0" title="0">
return phase</span>
default:<span class="cov0" title="0">
return MachineDeploymentPhaseUnknown</span>
}
}
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=machinedeployments,shortName=md,scope=Namespaced,categories=cluster-api
// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector
// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="MachineDeployment status such as ScalingUp/ScalingDown/Running/Failed/Unknown"
// +kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".status.replicas",description="Total number of non-terminated machines targeted by this deployment"
// +kubebuilder:printcolumn:name="Available",type="integer",JSONPath=".status.availableReplicas",description="Total number of available machines (ready for at least minReadySeconds)"
// +kubebuilder:printcolumn:name="Ready",type="integer",JSONPath=".status.readyReplicas",description="Total number of ready machines targeted by this deployment."
// MachineDeployment is the Schema for the machinedeployments API
type MachineDeployment struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec MachineDeploymentSpec `json:"spec,omitempty"`
Status MachineDeploymentStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// MachineDeploymentList contains a list of MachineDeployment
type MachineDeploymentList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []MachineDeployment `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;MachineDeployment{}, &amp;MachineDeploymentList{})
}</span>
</pre>
<pre class="file" id="file22" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
"fmt"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/utils/pointer"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)
func (m *MachineDeployment) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(m).
Complete()
}</span>
// +kubebuilder:webhook:verbs=create;update,path=/validate-cluster-x-k8s-io-v1alpha3-machinedeployment,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machinedeployments,versions=v1alpha3,name=validation.machinedeployment.cluster.x-k8s.io,sideEffects=None
// +kubebuilder:webhook:verbs=create;update,path=/mutate-cluster-x-k8s-io-v1alpha3-machinedeployment,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machinedeployments,versions=v1alpha3,name=default.machinedeployment.cluster.x-k8s.io,sideEffects=None
var _ webhook.Defaulter = &amp;MachineDeployment{}
var _ webhook.Validator = &amp;MachineDeployment{}
// Default implements webhook.Defaulter so a webhook will be registered for the type
func (m *MachineDeployment) Default() <span class="cov8" title="1">{
PopulateDefaultsMachineDeployment(m)
}</span>
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (m *MachineDeployment) ValidateCreate() error <span class="cov8" title="1">{
return m.validate(nil)
}</span>
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (m *MachineDeployment) ValidateUpdate(old runtime.Object) error <span class="cov8" title="1">{
oldMD, ok := old.(*MachineDeployment)
if !ok </span><span class="cov0" title="0">{
return apierrors.NewBadRequest(fmt.Sprintf("expected a MachineDeployment but got a %T", old))
}</span>
<span class="cov8" title="1">return m.validate(oldMD)</span>
}
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (m *MachineDeployment) ValidateDelete() error <span class="cov0" title="0">{
return nil
}</span>
func (m *MachineDeployment) validate(old *MachineDeployment) error <span class="cov8" title="1">{
var allErrs field.ErrorList
selector, err := metav1.LabelSelectorAsSelector(&amp;m.Spec.Selector)
if err != nil </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "selector"), m.Spec.Selector, err.Error()),
)
}</span> else<span class="cov8" title="1"> if !selector.Matches(labels.Set(m.Spec.Template.Labels)) </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "template", "labels"),
m.Spec.Template.Labels,
fmt.Sprintf("must match spec.selector %q", selector.String()),
),
)
}</span>
<span class="cov8" title="1">if old != nil &amp;&amp; old.Spec.ClusterName != m.Spec.ClusterName </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "clusterName"), m.Spec.ClusterName, "field is immutable"),
)
}</span>
<span class="cov8" title="1">if len(allErrs) == 0 </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov8" title="1">return apierrors.NewInvalid(GroupVersion.WithKind("MachineDeployment").GroupKind(), m.Name, allErrs)</span>
}
// PopulateDefaultsMachineDeployment fills in default field values.
// This is also called during MachineDeployment sync.
func PopulateDefaultsMachineDeployment(d *MachineDeployment) <span class="cov8" title="1">{
if d.Labels == nil </span><span class="cov8" title="1">{
d.Labels = make(map[string]string)
}</span>
<span class="cov8" title="1">d.Labels[ClusterLabelName] = d.Spec.ClusterName
if d.Spec.Replicas == nil </span><span class="cov8" title="1">{
d.Spec.Replicas = pointer.Int32Ptr(1)
}</span>
<span class="cov8" title="1">if d.Spec.MinReadySeconds == nil </span><span class="cov8" title="1">{
d.Spec.MinReadySeconds = pointer.Int32Ptr(0)
}</span>
<span class="cov8" title="1">if d.Spec.RevisionHistoryLimit == nil </span><span class="cov8" title="1">{
d.Spec.RevisionHistoryLimit = pointer.Int32Ptr(1)
}</span>
<span class="cov8" title="1">if d.Spec.ProgressDeadlineSeconds == nil </span><span class="cov8" title="1">{
d.Spec.ProgressDeadlineSeconds = pointer.Int32Ptr(600)
}</span>
<span class="cov8" title="1">if d.Spec.Selector.MatchLabels == nil </span><span class="cov8" title="1">{
d.Spec.Selector.MatchLabels = make(map[string]string)
}</span>
<span class="cov8" title="1">if d.Spec.Strategy == nil </span><span class="cov8" title="1">{
d.Spec.Strategy = &amp;MachineDeploymentStrategy{}
}</span>
<span class="cov8" title="1">if d.Spec.Strategy.Type == "" </span><span class="cov8" title="1">{
d.Spec.Strategy.Type = RollingUpdateMachineDeploymentStrategyType
}</span>
<span class="cov8" title="1">if d.Spec.Template.Labels == nil </span><span class="cov8" title="1">{
d.Spec.Template.Labels = make(map[string]string)
}</span>
// Default RollingUpdate strategy only if strategy type is RollingUpdate.
<span class="cov8" title="1">if d.Spec.Strategy.Type == RollingUpdateMachineDeploymentStrategyType </span><span class="cov8" title="1">{
if d.Spec.Strategy.RollingUpdate == nil </span><span class="cov8" title="1">{
d.Spec.Strategy.RollingUpdate = &amp;MachineRollingUpdateDeployment{}
}</span>
<span class="cov8" title="1">if d.Spec.Strategy.RollingUpdate.MaxSurge == nil </span><span class="cov8" title="1">{
ios1 := intstr.FromInt(1)
d.Spec.Strategy.RollingUpdate.MaxSurge = &amp;ios1
}</span>
<span class="cov8" title="1">if d.Spec.Strategy.RollingUpdate.MaxUnavailable == nil </span><span class="cov8" title="1">{
ios0 := intstr.FromInt(0)
d.Spec.Strategy.RollingUpdate.MaxUnavailable = &amp;ios0
}</span>
}
// If no selector has been provided, add label and selector for the
// MachineDeployment's name as a default way of providing uniqueness.
<span class="cov8" title="1">if len(d.Spec.Selector.MatchLabels) == 0 &amp;&amp; len(d.Spec.Selector.MatchExpressions) == 0 </span><span class="cov8" title="1">{
d.Spec.Selector.MatchLabels[MachineDeploymentLabelName] = d.Name
d.Spec.Template.Labels[MachineDeploymentLabelName] = d.Name
}</span>
// Make sure selector and template to be in the same cluster.
<span class="cov8" title="1">d.Spec.Selector.MatchLabels[ClusterLabelName] = d.Spec.ClusterName
d.Spec.Template.Labels[ClusterLabelName] = d.Spec.ClusterName</span>
}
</pre>
<pre class="file" id="file23" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
// ANCHOR: MachineHealthCheckSpec
// MachineHealthCheckSpec defines the desired state of MachineHealthCheck
type MachineHealthCheckSpec struct {
// ClusterName is the name of the Cluster this object belongs to.
// +kubebuilder:validation:MinLength=1
ClusterName string `json:"clusterName"`
// Label selector to match machines whose health will be exercised
Selector metav1.LabelSelector `json:"selector"`
// UnhealthyConditions contains a list of the conditions that determine
// whether a node is considered unhealthy. The conditions are combined in a
// logical OR, i.e. if any of the conditions is met, the node is unhealthy.
//
// +kubebuilder:validation:MinItems=1
UnhealthyConditions []UnhealthyCondition `json:"unhealthyConditions"`
// Any further remediation is only allowed if at most "MaxUnhealthy" machines selected by
// "selector" are not healthy.
// +optional
MaxUnhealthy *intstr.IntOrString `json:"maxUnhealthy,omitempty"`
// Machines older than this duration without a node will be considered to have
// failed and will be remediated.
// +optional
NodeStartupTimeout *metav1.Duration `json:"nodeStartupTimeout,omitempty"`
}
// ANCHOR_END: MachineHealthCHeckSpec
// ANCHOR: UnhealthyCondition
// UnhealthyCondition represents a Node condition type and value with a timeout
// specified as a duration. When the named condition has been in the given
// status for at least the timeout value, a node is considered unhealthy.
type UnhealthyCondition struct {
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:MinLength=1
Type corev1.NodeConditionType `json:"type"`
// +kubebuilder:validation:Type=string
// +kubebuilder:validation:MinLength=1
Status corev1.ConditionStatus `json:"status"`
Timeout metav1.Duration `json:"timeout"`
}
// ANCHOR_END: UnhealthyCondition
// ANCHOR: MachineHealthCheckStatus
// MachineHealthCheckStatus defines the observed state of MachineHealthCheck
type MachineHealthCheckStatus struct {
// total number of machines counted by this machine health check
// +kubebuilder:validation:Minimum=0
ExpectedMachines int32 `json:"expectedMachines,omitempty"`
// total number of healthy machines counted by this machine health check
// +kubebuilder:validation:Minimum=0
CurrentHealthy int32 `json:"currentHealthy,omitempty"`
// ObservedGeneration is the latest generation observed by the controller.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// Targets shows the current list of machines the machine health check is watching
// +optional
Targets []string `json:"targets,omitempty"`
}
// ANCHOR_END: MachineHealthCheckStatus
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=machinehealthchecks,shortName=mhc;mhcs,scope=Namespaced,categories=cluster-api
// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="MaxUnhealthy",type="string",JSONPath=".spec.maxUnhealthy",description="Maximum number of unhealthy machines allowed"
// +kubebuilder:printcolumn:name="ExpectedMachines",type="integer",JSONPath=".status.expectedMachines",description="Number of machines currently monitored"
// +kubebuilder:printcolumn:name="CurrentHealthy",type="integer",JSONPath=".status.currentHealthy",description="Current observed healthy machines"
// MachineHealthCheck is the Schema for the machinehealthchecks API
type MachineHealthCheck struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Specification of machine health check policy
Spec MachineHealthCheckSpec `json:"spec,omitempty"`
// Most recently observed status of MachineHealthCheck resource
Status MachineHealthCheckStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// MachineHealthCheckList contains a list of MachineHealthCheck
type MachineHealthCheckList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []MachineHealthCheck `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;MachineHealthCheck{}, &amp;MachineHealthCheckList{})
}</span>
</pre>
<pre class="file" id="file24" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 v1alpha3
import (
"fmt"
"time"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)
var (
// Default time allowed for a node to start up. Can be made longer as part of
// spec if required for particular provider.
// 10 minutes should allow the instance to start and the node to join the
// cluster on most providers.
defaultNodeStartupTimeout = metav1.Duration{Duration: 10 * time.Minute}
)
func (m *MachineHealthCheck) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(m).
Complete()
}</span>
// +kubebuilder:webhook:verbs=create;update,path=/validate-cluster-x-k8s-io-v1alpha3-machinehealthcheck,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machinehealthchecks,versions=v1alpha3,name=validation.machinehealthcheck.cluster.x-k8s.io,sideEffects=None
// +kubebuilder:webhook:verbs=create;update,path=/mutate-cluster-x-k8s-io-v1alpha3-machinehealthcheck,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machinehealthchecks,versions=v1alpha3,name=default.machinehealthcheck.cluster.x-k8s.io,sideEffects=None
var _ webhook.Defaulter = &amp;MachineHealthCheck{}
var _ webhook.Validator = &amp;MachineHealthCheck{}
// Default implements webhook.Defaulter so a webhook will be registered for the type
func (m *MachineHealthCheck) Default() <span class="cov8" title="1">{
if m.Labels == nil </span><span class="cov8" title="1">{
m.Labels = make(map[string]string)
}</span>
<span class="cov8" title="1">m.Labels[ClusterLabelName] = m.Spec.ClusterName
if m.Spec.MaxUnhealthy == nil </span><span class="cov8" title="1">{
defaultMaxUnhealthy := intstr.FromString("100%")
m.Spec.MaxUnhealthy = &amp;defaultMaxUnhealthy
}</span>
<span class="cov8" title="1">if m.Spec.NodeStartupTimeout == nil </span><span class="cov8" title="1">{
m.Spec.NodeStartupTimeout = &amp;defaultNodeStartupTimeout
}</span>
}
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (m *MachineHealthCheck) ValidateCreate() error <span class="cov8" title="1">{
return m.validate(nil)
}</span>
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (m *MachineHealthCheck) ValidateUpdate(old runtime.Object) error <span class="cov8" title="1">{
mhc, ok := old.(*MachineHealthCheck)
if !ok </span><span class="cov0" title="0">{
return apierrors.NewBadRequest(fmt.Sprintf("expected a MachineHealthCheck but got a %T", old))
}</span>
<span class="cov8" title="1">return m.validate(mhc)</span>
}
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (m *MachineHealthCheck) ValidateDelete() error <span class="cov0" title="0">{
return nil
}</span>
func (m *MachineHealthCheck) validate(old *MachineHealthCheck) error <span class="cov8" title="1">{
var allErrs field.ErrorList
// Validate selector parses as Selector
selector, err := metav1.LabelSelectorAsSelector(&amp;m.Spec.Selector)
if err != nil </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "selector"), m.Spec.Selector, err.Error()),
)
}</span>
// Validate that the selector isn't empty.
<span class="cov8" title="1">if selector != nil &amp;&amp; selector.Empty() </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "selector"), m.Spec.Selector, "selector must not be empty"),
)
}</span>
<span class="cov8" title="1">if clusterName, ok := m.Spec.Selector.MatchLabels[ClusterLabelName]; ok &amp;&amp; clusterName != m.Spec.ClusterName </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "selector"), m.Spec.Selector, "cannot specify a cluster selector other than the one specified by ClusterName"))
}</span>
<span class="cov8" title="1">if old != nil &amp;&amp; old.Spec.ClusterName != m.Spec.ClusterName </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "clusterName"), m.Spec.ClusterName, "field is immutable"),
)
}</span>
<span class="cov8" title="1">if m.Spec.NodeStartupTimeout != nil &amp;&amp; m.Spec.NodeStartupTimeout.Seconds() &lt; 30 </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "nodeStartupTimeout"), m.Spec.NodeStartupTimeout, "must be at least 30s"),
)
}</span>
<span class="cov8" title="1">if m.Spec.MaxUnhealthy != nil </span><span class="cov8" title="1">{
if _, err := intstr.GetValueFromIntOrPercent(m.Spec.MaxUnhealthy, 0, false); err != nil </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "maxUnhealthy"), m.Spec.MaxUnhealthy, "must be either an int or a percentage"),
)
}</span> else<span class="cov8" title="1"> if m.Spec.MaxUnhealthy.Type == intstr.String </span><span class="cov8" title="1">{
if len(validation.IsValidPercent(m.Spec.MaxUnhealthy.StrVal)) != 0 </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "maxUnhealthy"), m.Spec.MaxUnhealthy, "must be either an int or a percentage"),
)
}</span>
}
}
<span class="cov8" title="1">if len(allErrs) == 0 </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov8" title="1">return apierrors.NewInvalid(GroupVersion.WithKind("MachineHealthCheck").GroupKind(), m.Name, allErrs)</span>
}
</pre>
<pre class="file" id="file25" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/validation/field"
capierrors "sigs.k8s.io/cluster-api/errors"
)
// ANCHOR: MachineSetSpec
// MachineSetSpec defines the desired state of MachineSet
type MachineSetSpec struct {
// ClusterName is the name of the Cluster this object belongs to.
// +kubebuilder:validation:MinLength=1
ClusterName string `json:"clusterName"`
// Replicas is the number of desired replicas.
// This is a pointer to distinguish between explicit zero and unspecified.
// Defaults to 1.
// +optional
Replicas *int32 `json:"replicas,omitempty"`
// MinReadySeconds is the minimum number of seconds for which a newly created machine should be ready.
// Defaults to 0 (machine will be considered available as soon as it is ready)
// +optional
MinReadySeconds int32 `json:"minReadySeconds,omitempty"`
// DeletePolicy defines the policy used to identify nodes to delete when downscaling.
// Defaults to "Random". Valid values are "Random, "Newest", "Oldest"
// +kubebuilder:validation:Enum=Random;Newest;Oldest
DeletePolicy string `json:"deletePolicy,omitempty"`
// Selector is a label query over machines that should match the replica count.
// Label keys and values that must match in order to be controlled by this MachineSet.
// It must match the machine template's labels.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
Selector metav1.LabelSelector `json:"selector"`
// Template is the object that describes the machine that will be created if
// insufficient replicas are detected.
// Object references to custom resources resources are treated as templates.
// +optional
Template MachineTemplateSpec `json:"template,omitempty"`
}
// ANCHOR_END: MachineSetSpec
// ANCHOR: MachineTemplateSpec
// MachineTemplateSpec describes the data needed to create a Machine from a template
type MachineTemplateSpec struct {
// Standard object's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
ObjectMeta `json:"metadata,omitempty"`
// Specification of the desired behavior of the machine.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
// +optional
Spec MachineSpec `json:"spec,omitempty"`
}
// ANCHOR_END: MachineTemplateSpec
// MachineSetDeletePolicy defines how priority is assigned to nodes to delete when
// downscaling a MachineSet. Defaults to "Random".
type MachineSetDeletePolicy string
const (
// RandomMachineSetDeletePolicy prioritizes both Machines that have the annotation
// "cluster.x-k8s.io/delete-machine=yes" and Machines that are unhealthy
// (Status.FailureReason or Status.FailureMessage are set to a non-empty value).
// Finally, it picks Machines at random to delete.
RandomMachineSetDeletePolicy MachineSetDeletePolicy = "Random"
// NewestMachineSetDeletePolicy prioritizes both Machines that have the annotation
// "cluster.x-k8s.io/delete-machine=yes" and Machines that are unhealthy
// (Status.FailureReason or Status.FailureMessage are set to a non-empty value).
// It then prioritizes the newest Machines for deletion based on the Machine's CreationTimestamp.
NewestMachineSetDeletePolicy MachineSetDeletePolicy = "Newest"
// OldestMachineSetDeletePolicy prioritizes both Machines that have the annotation
// "cluster.x-k8s.io/delete-machine=yes" and Machines that are unhealthy
// (Status.FailureReason or Status.FailureMessage are set to a non-empty value).
// It then prioritizes the oldest Machines for deletion based on the Machine's CreationTimestamp.
OldestMachineSetDeletePolicy MachineSetDeletePolicy = "Oldest"
)
// ANCHOR: MachineSetStatus
// MachineSetStatus defines the observed state of MachineSet
type MachineSetStatus struct {
// Selector is the same as the label selector but in the string format to avoid introspection
// by clients. The string will be in the same format as the query-param syntax.
// More info about label selectors: http://kubernetes.io/docs/user-guide/labels#label-selectors
// +optional
Selector string `json:"selector,omitempty"`
// Replicas is the most recently observed number of replicas.
// +optional
Replicas int32 `json:"replicas,omitempty"`
// The number of replicas that have labels matching the labels of the machine template of the MachineSet.
// +optional
FullyLabeledReplicas int32 `json:"fullyLabeledReplicas,omitempty"`
// The number of ready replicas for this MachineSet. A machine is considered ready when the node has been created and is "Ready".
// +optional
ReadyReplicas int32 `json:"readyReplicas,omitempty"`
// The number of available replicas (ready for at least minReadySeconds) for this MachineSet.
// +optional
AvailableReplicas int32 `json:"availableReplicas,omitempty"`
// ObservedGeneration reflects the generation of the most recently observed MachineSet.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// In the event that there is a terminal problem reconciling the
// replicas, both FailureReason and FailureMessage will be set. FailureReason
// will be populated with a succinct value suitable for machine
// interpretation, while FailureMessage will contain a more verbose
// string suitable for logging and human consumption.
//
// These fields should not be set for transitive errors that a
// controller faces that are expected to be fixed automatically over
// time (like service outages), but instead indicate that something is
// fundamentally wrong with the MachineTemplate's spec or the configuration of
// the machine controller, and that manual intervention is required. Examples
// of terminal errors would be invalid combinations of settings in the
// spec, values that are unsupported by the machine controller, or the
// responsible machine controller itself being critically misconfigured.
//
// Any transient errors that occur during the reconciliation of Machines
// can be added as events to the MachineSet object and/or logged in the
// controller's output.
// +optional
FailureReason *capierrors.MachineSetStatusError `json:"failureReason,omitempty"`
// +optional
FailureMessage *string `json:"failureMessage,omitempty"`
}
// ANCHOR_END: MachineSetStatus
// Validate validates the MachineSet fields.
func (m *MachineSet) Validate() field.ErrorList <span class="cov0" title="0">{
errors := field.ErrorList{}
// validate spec.selector and spec.template.labels
fldPath := field.NewPath("spec")
errors = append(errors, metav1validation.ValidateLabelSelector(&amp;m.Spec.Selector, fldPath.Child("selector"))...)
if len(m.Spec.Selector.MatchLabels)+len(m.Spec.Selector.MatchExpressions) == 0 </span><span class="cov0" title="0">{
errors = append(errors, field.Invalid(fldPath.Child("selector"), m.Spec.Selector, "empty selector is not valid for MachineSet."))
}</span>
<span class="cov0" title="0">selector, err := metav1.LabelSelectorAsSelector(&amp;m.Spec.Selector)
if err != nil </span><span class="cov0" title="0">{
errors = append(errors, field.Invalid(fldPath.Child("selector"), m.Spec.Selector, "invalid label selector."))
}</span> else<span class="cov0" title="0"> {
labels := labels.Set(m.Spec.Template.Labels)
if !selector.Matches(labels) </span><span class="cov0" title="0">{
errors = append(errors, field.Invalid(fldPath.Child("template", "metadata", "labels"), m.Spec.Template.Labels, "`selector` does not match template `labels`"))
}</span>
}
<span class="cov0" title="0">return errors</span>
}
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=machinesets,shortName=ms,scope=Namespaced,categories=cluster-api
// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector
// +kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".status.replicas",description="Total number of non-terminated machines targeted by this machineset"
// +kubebuilder:printcolumn:name="Available",type="integer",JSONPath=".status.availableReplicas",description="Total number of available machines (ready for at least minReadySeconds)"
// +kubebuilder:printcolumn:name="Ready",type="integer",JSONPath=".status.readyReplicas",description="Total number of ready machines targeted by this machineset."
// MachineSet is the Schema for the machinesets API
type MachineSet struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec MachineSetSpec `json:"spec,omitempty"`
Status MachineSetStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// MachineSetList contains a list of MachineSet
type MachineSetList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []MachineSet `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;MachineSet{}, &amp;MachineSetList{})
}</span>
</pre>
<pre class="file" id="file26" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
"fmt"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/utils/pointer"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)
func (m *MachineSet) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(m).
Complete()
}</span>
// +kubebuilder:webhook:verbs=create;update,path=/validate-cluster-x-k8s-io-v1alpha3-machineset,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machinesets,versions=v1alpha3,name=validation.machineset.cluster.x-k8s.io,sideEffects=None
// +kubebuilder:webhook:verbs=create;update,path=/mutate-cluster-x-k8s-io-v1alpha3-machineset,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machinesets,versions=v1alpha3,name=default.machineset.cluster.x-k8s.io,sideEffects=None
var _ webhook.Defaulter = &amp;MachineSet{}
var _ webhook.Validator = &amp;MachineSet{}
// DefaultingFunction sets default MachineSet field values.
func (m *MachineSet) Default() <span class="cov8" title="1">{
if m.Labels == nil </span><span class="cov8" title="1">{
m.Labels = make(map[string]string)
}</span>
<span class="cov8" title="1">m.Labels[ClusterLabelName] = m.Spec.ClusterName
if m.Spec.Replicas == nil </span><span class="cov8" title="1">{
m.Spec.Replicas = pointer.Int32Ptr(1)
}</span>
<span class="cov8" title="1">if m.Spec.DeletePolicy == "" </span><span class="cov8" title="1">{
randomPolicy := string(RandomMachineSetDeletePolicy)
m.Spec.DeletePolicy = randomPolicy
}</span>
<span class="cov8" title="1">if m.Spec.Selector.MatchLabels == nil </span><span class="cov8" title="1">{
m.Spec.Selector.MatchLabels = make(map[string]string)
}</span>
<span class="cov8" title="1">if m.Spec.Template.Labels == nil </span><span class="cov8" title="1">{
m.Spec.Template.Labels = make(map[string]string)
}</span>
<span class="cov8" title="1">if len(m.Spec.Selector.MatchLabels) == 0 &amp;&amp; len(m.Spec.Selector.MatchExpressions) == 0 </span><span class="cov8" title="1">{
m.Spec.Selector.MatchLabels[MachineSetLabelName] = m.Name
m.Spec.Template.Labels[MachineSetLabelName] = m.Name
}</span>
}
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (m *MachineSet) ValidateCreate() error <span class="cov8" title="1">{
return m.validate(nil)
}</span>
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (m *MachineSet) ValidateUpdate(old runtime.Object) error <span class="cov8" title="1">{
oldMS, ok := old.(*MachineSet)
if !ok </span><span class="cov0" title="0">{
return apierrors.NewBadRequest(fmt.Sprintf("expected a MachineSet but got a %T", old))
}</span>
<span class="cov8" title="1">return m.validate(oldMS)</span>
}
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (m *MachineSet) ValidateDelete() error <span class="cov0" title="0">{
return nil
}</span>
func (m *MachineSet) validate(old *MachineSet) error <span class="cov8" title="1">{
var allErrs field.ErrorList
selector, err := metav1.LabelSelectorAsSelector(&amp;m.Spec.Selector)
if err != nil </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "selector"), m.Spec.Selector, err.Error()),
)
}</span> else<span class="cov8" title="1"> if !selector.Matches(labels.Set(m.Spec.Template.Labels)) </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "template", "labels"),
m.Spec.Template.Labels,
fmt.Sprintf("must match spec.selector %q", selector.String()),
),
)
}</span>
<span class="cov8" title="1">if old != nil &amp;&amp; old.Spec.ClusterName != m.Spec.ClusterName </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(field.NewPath("spec", "clusterName"), m.Spec.ClusterName, "field is immutable"),
)
}</span>
<span class="cov8" title="1">if len(allErrs) == 0 </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov8" title="1">return apierrors.NewInvalid(GroupVersion.WithKind("MachineSet").GroupKind(), m.Name, allErrs)</span>
}
</pre>
<pre class="file" id="file27" style="display: none">// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1alpha3
import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/cluster-api/errors"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *APIEndpoint) DeepCopyInto(out *APIEndpoint) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIEndpoint.
func (in *APIEndpoint) DeepCopy() *APIEndpoint <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(APIEndpoint)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Bootstrap) DeepCopyInto(out *Bootstrap) <span class="cov0" title="0">{
*out = *in
if in.ConfigRef != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ConfigRef, &amp;out.ConfigRef
*out = new(v1.ObjectReference)
**out = **in
}</span>
<span class="cov0" title="0">if in.Data != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Data, &amp;out.Data
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.DataSecretName != nil </span><span class="cov0" title="0">{
in, out := &amp;in.DataSecretName, &amp;out.DataSecretName
*out = new(string)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bootstrap.
func (in *Bootstrap) DeepCopy() *Bootstrap <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Bootstrap)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Cluster) DeepCopyInto(out *Cluster) <span class="cov8" title="1">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
in.Status.DeepCopyInto(&amp;out.Status)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster.
func (in *Cluster) DeepCopy() *Cluster <span class="cov8" title="1">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov8" title="1">out := new(Cluster)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Cluster) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterList) DeepCopyInto(out *ClusterList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]Cluster, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterList.
func (in *ClusterList) DeepCopy() *ClusterList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ClusterList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterNetwork) DeepCopyInto(out *ClusterNetwork) <span class="cov0" title="0">{
*out = *in
if in.APIServerPort != nil </span><span class="cov0" title="0">{
in, out := &amp;in.APIServerPort, &amp;out.APIServerPort
*out = new(int32)
**out = **in
}</span>
<span class="cov0" title="0">if in.Services != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Services, &amp;out.Services
*out = new(NetworkRanges)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.Pods != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Pods, &amp;out.Pods
*out = new(NetworkRanges)
(*in).DeepCopyInto(*out)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterNetwork.
func (in *ClusterNetwork) DeepCopy() *ClusterNetwork <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterNetwork)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) <span class="cov8" title="1">{
*out = *in
if in.ClusterNetwork != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ClusterNetwork, &amp;out.ClusterNetwork
*out = new(ClusterNetwork)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov8" title="1">out.ControlPlaneEndpoint = in.ControlPlaneEndpoint
if in.ControlPlaneRef != nil </span><span class="cov8" title="1">{
in, out := &amp;in.ControlPlaneRef, &amp;out.ControlPlaneRef
*out = new(v1.ObjectReference)
**out = **in
}</span>
<span class="cov8" title="1">if in.InfrastructureRef != nil </span><span class="cov8" title="1">{
in, out := &amp;in.InfrastructureRef, &amp;out.InfrastructureRef
*out = new(v1.ObjectReference)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSpec.
func (in *ClusterSpec) DeepCopy() *ClusterSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) <span class="cov8" title="1">{
*out = *in
if in.FailureDomains != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FailureDomains, &amp;out.FailureDomains
*out = make(FailureDomains, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = *val.DeepCopy()
}</span>
}
<span class="cov8" title="1">if in.FailureReason != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FailureReason, &amp;out.FailureReason
*out = new(errors.ClusterStatusError)
**out = **in
}</span>
<span class="cov8" title="1">if in.FailureMessage != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FailureMessage, &amp;out.FailureMessage
*out = new(string)
**out = **in
}</span>
<span class="cov8" title="1">if in.Conditions != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Conditions, &amp;out.Conditions
*out = make(Conditions, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus.
func (in *ClusterStatus) DeepCopy() *ClusterStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Condition) DeepCopyInto(out *Condition) <span class="cov0" title="0">{
*out = *in
in.LastTransitionTime.DeepCopyInto(&amp;out.LastTransitionTime)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition.
func (in *Condition) DeepCopy() *Condition <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Condition)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in Conditions) DeepCopyInto(out *Conditions) <span class="cov0" title="0">{
</span><span class="cov0" title="0">{
in := &amp;in
*out = make(Conditions, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Conditions.
func (in Conditions) DeepCopy() Conditions <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Conditions)
in.DeepCopyInto(out)
return *out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FailureDomainSpec) DeepCopyInto(out *FailureDomainSpec) <span class="cov0" title="0">{
*out = *in
if in.Attributes != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Attributes, &amp;out.Attributes
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailureDomainSpec.
func (in *FailureDomainSpec) DeepCopy() *FailureDomainSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(FailureDomainSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in FailureDomains) DeepCopyInto(out *FailureDomains) <span class="cov0" title="0">{
</span><span class="cov0" title="0">{
in := &amp;in
*out = make(FailureDomains, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = *val.DeepCopy()
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailureDomains.
func (in FailureDomains) DeepCopy() FailureDomains <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(FailureDomains)
in.DeepCopyInto(out)
return *out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Machine) DeepCopyInto(out *Machine) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
in.Status.DeepCopyInto(&amp;out.Status)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Machine.
func (in *Machine) DeepCopy() *Machine <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Machine)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Machine) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineAddress) DeepCopyInto(out *MachineAddress) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineAddress.
func (in *MachineAddress) DeepCopy() *MachineAddress <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineAddress)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in MachineAddresses) DeepCopyInto(out *MachineAddresses) <span class="cov0" title="0">{
</span><span class="cov0" title="0">{
in := &amp;in
*out = make(MachineAddresses, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineAddresses.
func (in MachineAddresses) DeepCopy() MachineAddresses <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineAddresses)
in.DeepCopyInto(out)
return *out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeployment) DeepCopyInto(out *MachineDeployment) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
out.Status = in.Status
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeployment.
func (in *MachineDeployment) DeepCopy() *MachineDeployment <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineDeployment)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineDeployment) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeploymentList) DeepCopyInto(out *MachineDeploymentList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]MachineDeployment, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentList.
func (in *MachineDeploymentList) DeepCopy() *MachineDeploymentList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineDeploymentList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineDeploymentList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeploymentSpec) DeepCopyInto(out *MachineDeploymentSpec) <span class="cov0" title="0">{
*out = *in
if in.Replicas != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Replicas, &amp;out.Replicas
*out = new(int32)
**out = **in
}</span>
<span class="cov0" title="0">in.Selector.DeepCopyInto(&amp;out.Selector)
in.Template.DeepCopyInto(&amp;out.Template)
if in.Strategy != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Strategy, &amp;out.Strategy
*out = new(MachineDeploymentStrategy)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.MinReadySeconds != nil </span><span class="cov0" title="0">{
in, out := &amp;in.MinReadySeconds, &amp;out.MinReadySeconds
*out = new(int32)
**out = **in
}</span>
<span class="cov0" title="0">if in.RevisionHistoryLimit != nil </span><span class="cov0" title="0">{
in, out := &amp;in.RevisionHistoryLimit, &amp;out.RevisionHistoryLimit
*out = new(int32)
**out = **in
}</span>
<span class="cov0" title="0">if in.ProgressDeadlineSeconds != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ProgressDeadlineSeconds, &amp;out.ProgressDeadlineSeconds
*out = new(int32)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentSpec.
func (in *MachineDeploymentSpec) DeepCopy() *MachineDeploymentSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineDeploymentSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeploymentStatus) DeepCopyInto(out *MachineDeploymentStatus) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStatus.
func (in *MachineDeploymentStatus) DeepCopy() *MachineDeploymentStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineDeploymentStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineDeploymentStrategy) DeepCopyInto(out *MachineDeploymentStrategy) <span class="cov0" title="0">{
*out = *in
if in.RollingUpdate != nil </span><span class="cov0" title="0">{
in, out := &amp;in.RollingUpdate, &amp;out.RollingUpdate
*out = new(MachineRollingUpdateDeployment)
(*in).DeepCopyInto(*out)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDeploymentStrategy.
func (in *MachineDeploymentStrategy) DeepCopy() *MachineDeploymentStrategy <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineDeploymentStrategy)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineHealthCheck) DeepCopyInto(out *MachineHealthCheck) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
in.Status.DeepCopyInto(&amp;out.Status)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineHealthCheck.
func (in *MachineHealthCheck) DeepCopy() *MachineHealthCheck <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineHealthCheck)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineHealthCheck) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineHealthCheckList) DeepCopyInto(out *MachineHealthCheckList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]MachineHealthCheck, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineHealthCheckList.
func (in *MachineHealthCheckList) DeepCopy() *MachineHealthCheckList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineHealthCheckList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineHealthCheckList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineHealthCheckSpec) DeepCopyInto(out *MachineHealthCheckSpec) <span class="cov0" title="0">{
*out = *in
in.Selector.DeepCopyInto(&amp;out.Selector)
if in.UnhealthyConditions != nil </span><span class="cov0" title="0">{
in, out := &amp;in.UnhealthyConditions, &amp;out.UnhealthyConditions
*out = make([]UnhealthyCondition, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.MaxUnhealthy != nil </span><span class="cov0" title="0">{
in, out := &amp;in.MaxUnhealthy, &amp;out.MaxUnhealthy
*out = new(intstr.IntOrString)
**out = **in
}</span>
<span class="cov0" title="0">if in.NodeStartupTimeout != nil </span><span class="cov0" title="0">{
in, out := &amp;in.NodeStartupTimeout, &amp;out.NodeStartupTimeout
*out = new(metav1.Duration)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineHealthCheckSpec.
func (in *MachineHealthCheckSpec) DeepCopy() *MachineHealthCheckSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineHealthCheckSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineHealthCheckStatus) DeepCopyInto(out *MachineHealthCheckStatus) <span class="cov0" title="0">{
*out = *in
if in.Targets != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Targets, &amp;out.Targets
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineHealthCheckStatus.
func (in *MachineHealthCheckStatus) DeepCopy() *MachineHealthCheckStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineHealthCheckStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineList) DeepCopyInto(out *MachineList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]Machine, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineList.
func (in *MachineList) DeepCopy() *MachineList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineRollingUpdateDeployment) DeepCopyInto(out *MachineRollingUpdateDeployment) <span class="cov0" title="0">{
*out = *in
if in.MaxUnavailable != nil </span><span class="cov0" title="0">{
in, out := &amp;in.MaxUnavailable, &amp;out.MaxUnavailable
*out = new(intstr.IntOrString)
**out = **in
}</span>
<span class="cov0" title="0">if in.MaxSurge != nil </span><span class="cov0" title="0">{
in, out := &amp;in.MaxSurge, &amp;out.MaxSurge
*out = new(intstr.IntOrString)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineRollingUpdateDeployment.
func (in *MachineRollingUpdateDeployment) DeepCopy() *MachineRollingUpdateDeployment <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineRollingUpdateDeployment)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSet) DeepCopyInto(out *MachineSet) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
in.Status.DeepCopyInto(&amp;out.Status)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSet.
func (in *MachineSet) DeepCopy() *MachineSet <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineSet)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineSet) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSetList) DeepCopyInto(out *MachineSetList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]MachineSet, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetList.
func (in *MachineSetList) DeepCopy() *MachineSetList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineSetList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MachineSetList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSetSpec) DeepCopyInto(out *MachineSetSpec) <span class="cov0" title="0">{
*out = *in
if in.Replicas != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Replicas, &amp;out.Replicas
*out = new(int32)
**out = **in
}</span>
<span class="cov0" title="0">in.Selector.DeepCopyInto(&amp;out.Selector)
in.Template.DeepCopyInto(&amp;out.Template)</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetSpec.
func (in *MachineSetSpec) DeepCopy() *MachineSetSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineSetSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSetStatus) DeepCopyInto(out *MachineSetStatus) <span class="cov0" title="0">{
*out = *in
if in.FailureReason != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FailureReason, &amp;out.FailureReason
*out = new(errors.MachineSetStatusError)
**out = **in
}</span>
<span class="cov0" title="0">if in.FailureMessage != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FailureMessage, &amp;out.FailureMessage
*out = new(string)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSetStatus.
func (in *MachineSetStatus) DeepCopy() *MachineSetStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineSetStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineSpec) DeepCopyInto(out *MachineSpec) <span class="cov0" title="0">{
*out = *in
in.Bootstrap.DeepCopyInto(&amp;out.Bootstrap)
out.InfrastructureRef = in.InfrastructureRef
if in.Version != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Version, &amp;out.Version
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.ProviderID != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ProviderID, &amp;out.ProviderID
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.FailureDomain != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FailureDomain, &amp;out.FailureDomain
*out = new(string)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSpec.
func (in *MachineSpec) DeepCopy() *MachineSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineStatus) DeepCopyInto(out *MachineStatus) <span class="cov0" title="0">{
*out = *in
if in.NodeRef != nil </span><span class="cov0" title="0">{
in, out := &amp;in.NodeRef, &amp;out.NodeRef
*out = new(v1.ObjectReference)
**out = **in
}</span>
<span class="cov0" title="0">if in.LastUpdated != nil </span><span class="cov0" title="0">{
in, out := &amp;in.LastUpdated, &amp;out.LastUpdated
*out = (*in).DeepCopy()
}</span>
<span class="cov0" title="0">if in.Version != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Version, &amp;out.Version
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.FailureReason != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FailureReason, &amp;out.FailureReason
*out = new(errors.MachineStatusError)
**out = **in
}</span>
<span class="cov0" title="0">if in.FailureMessage != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FailureMessage, &amp;out.FailureMessage
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.Addresses != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Addresses, &amp;out.Addresses
*out = make(MachineAddresses, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.Conditions != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Conditions, &amp;out.Conditions
*out = make(Conditions, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineStatus.
func (in *MachineStatus) DeepCopy() *MachineStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineTemplateSpec) DeepCopyInto(out *MachineTemplateSpec) <span class="cov0" title="0">{
*out = *in
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineTemplateSpec.
func (in *MachineTemplateSpec) DeepCopy() *MachineTemplateSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MachineTemplateSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkRanges) DeepCopyInto(out *NetworkRanges) <span class="cov0" title="0">{
*out = *in
if in.CIDRBlocks != nil </span><span class="cov0" title="0">{
in, out := &amp;in.CIDRBlocks, &amp;out.CIDRBlocks
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkRanges.
func (in *NetworkRanges) DeepCopy() *NetworkRanges <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(NetworkRanges)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObjectMeta) DeepCopyInto(out *ObjectMeta) <span class="cov0" title="0">{
*out = *in
if in.Labels != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Labels, &amp;out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
<span class="cov0" title="0">if in.Annotations != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Annotations, &amp;out.Annotations
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
<span class="cov0" title="0">if in.OwnerReferences != nil </span><span class="cov0" title="0">{
in, out := &amp;in.OwnerReferences, &amp;out.OwnerReferences
*out = make([]metav1.OwnerReference, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectMeta.
func (in *ObjectMeta) DeepCopy() *ObjectMeta <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ObjectMeta)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UnhealthyCondition) DeepCopyInto(out *UnhealthyCondition) <span class="cov0" title="0">{
*out = *in
out.Timeout = in.Timeout
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UnhealthyCondition.
func (in *UnhealthyCondition) DeepCopy() *UnhealthyCondition <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(UnhealthyCondition)
in.DeepCopyInto(out)
return out</span>
}
</pre>
<pre class="file" id="file28" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
apiconversion "k8s.io/apimachinery/pkg/conversion"
kubeadmbootstrapv1alpha3 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3"
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
"sigs.k8s.io/controller-runtime/pkg/conversion"
)
// ConvertTo converts this KubeadmConfig to the Hub version (v1alpha3).
func (src *KubeadmConfig) ConvertTo(dstRaw conversion.Hub) error <span class="cov8" title="1">{
dst := dstRaw.(*kubeadmbootstrapv1alpha3.KubeadmConfig)
if err := Convert_v1alpha2_KubeadmConfig_To_v1alpha3_KubeadmConfig(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually restore data.
<span class="cov8" title="1">restored := &amp;kubeadmbootstrapv1alpha3.KubeadmConfig{}
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">dst.Status.DataSecretName = restored.Status.DataSecretName
dst.Status.ObservedGeneration = restored.Status.ObservedGeneration
dst.Spec.Verbosity = restored.Spec.Verbosity
dst.Spec.UseExperimentalRetryJoin = restored.Spec.UseExperimentalRetryJoin
dst.Spec.DiskSetup = restored.Spec.DiskSetup
dst.Spec.Mounts = restored.Spec.Mounts
dst.Spec.Files = restored.Spec.Files
dst.Status.Conditions = restored.Status.Conditions
// Track files successfully up-converted. We need this to dedupe
// restored files from user-updated files on up-conversion. We store
// them as pointers for later modification without paying for second
// lookup.
dstPaths := make(map[string]*kubeadmbootstrapv1alpha3.File, len(dst.Spec.Files))
for i := range dst.Spec.Files </span><span class="cov8" title="1">{
path := dst.Spec.Files[i].Path
dstPaths[path] = &amp;dst.Spec.Files[i]
}</span>
// If we find a restored file matching the file path of a v1alpha2
// file with no content, we should restore contentFrom to that file.
<span class="cov8" title="1">for i := range restored.Spec.Files </span><span class="cov8" title="1">{
restoredFile := restored.Spec.Files[i]
dstFile, exists := dstPaths[restoredFile.Path]
if exists &amp;&amp; dstFile.Content == "" </span><span class="cov8" title="1">{
if dstFile.ContentFrom == nil </span><span class="cov0" title="0">{
dstFile.ContentFrom = new(kubeadmbootstrapv1alpha3.FileSource)
}</span>
<span class="cov8" title="1">*dstFile.ContentFrom = *restoredFile.ContentFrom</span>
}
}
<span class="cov8" title="1">return nil</span>
}
// ConvertFrom converts from the KubeadmConfig Hub version (v1alpha3) to this version.
func (dst *KubeadmConfig) ConvertFrom(srcRaw conversion.Hub) error <span class="cov8" title="1">{
src := srcRaw.(*kubeadmbootstrapv1alpha3.KubeadmConfig)
if err := Convert_v1alpha3_KubeadmConfig_To_v1alpha2_KubeadmConfig(src, dst, nil); err != nil </span><span class="cov0" title="0">{
return nil
}</span>
// Preserve Hub data on down-conversion.
<span class="cov8" title="1">if err := utilconversion.MarshalData(src, dst); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// ConvertTo converts this KubeadmConfigList to the Hub version (v1alpha3).
func (src *KubeadmConfigList) ConvertTo(dstRaw conversion.Hub) error <span class="cov0" title="0">{
dst := dstRaw.(*kubeadmbootstrapv1alpha3.KubeadmConfigList)
return Convert_v1alpha2_KubeadmConfigList_To_v1alpha3_KubeadmConfigList(src, dst, nil)
}</span>
// ConvertFrom converts from the KubeadmConfigList Hub version (v1alpha3) to this version.
func (dst *KubeadmConfigList) ConvertFrom(srcRaw conversion.Hub) error <span class="cov0" title="0">{
src := srcRaw.(*kubeadmbootstrapv1alpha3.KubeadmConfigList)
return Convert_v1alpha3_KubeadmConfigList_To_v1alpha2_KubeadmConfigList(src, dst, nil)
}</span>
// ConvertTo converts this KubeadmConfigTemplate to the Hub version (v1alpha3).
func (src *KubeadmConfigTemplate) ConvertTo(dstRaw conversion.Hub) error <span class="cov0" title="0">{
dst := dstRaw.(*kubeadmbootstrapv1alpha3.KubeadmConfigTemplate)
return Convert_v1alpha2_KubeadmConfigTemplate_To_v1alpha3_KubeadmConfigTemplate(src, dst, nil)
}</span>
// ConvertFrom converts from the KubeadmConfigTemplate Hub version (v1alpha3) to this version.
func (dst *KubeadmConfigTemplate) ConvertFrom(srcRaw conversion.Hub) error <span class="cov0" title="0">{
src := srcRaw.(*kubeadmbootstrapv1alpha3.KubeadmConfigTemplate)
return Convert_v1alpha3_KubeadmConfigTemplate_To_v1alpha2_KubeadmConfigTemplate(src, dst, nil)
}</span>
// ConvertTo converts this KubeadmConfigTemplateList to the Hub version (v1alpha3).
func (src *KubeadmConfigTemplateList) ConvertTo(dstRaw conversion.Hub) error <span class="cov0" title="0">{
dst := dstRaw.(*kubeadmbootstrapv1alpha3.KubeadmConfigTemplateList)
return Convert_v1alpha2_KubeadmConfigTemplateList_To_v1alpha3_KubeadmConfigTemplateList(src, dst, nil)
}</span>
// ConvertFrom converts from the KubeadmConfigTemplateList Hub version (v1alpha3) to this version.
func (dst *KubeadmConfigTemplateList) ConvertFrom(srcRaw conversion.Hub) error <span class="cov0" title="0">{
src := srcRaw.(*kubeadmbootstrapv1alpha3.KubeadmConfigTemplateList)
return Convert_v1alpha3_KubeadmConfigTemplateList_To_v1alpha2_KubeadmConfigTemplateList(src, dst, nil)
}</span>
// Convert_v1alpha2_KubeadmConfigStatus_To_v1alpha3_KubeadmConfigStatus converts this KubeadmConfigStatus to the Hub version (v1alpha3).
func Convert_v1alpha2_KubeadmConfigStatus_To_v1alpha3_KubeadmConfigStatus(in *KubeadmConfigStatus, out *kubeadmbootstrapv1alpha3.KubeadmConfigStatus, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha2_KubeadmConfigStatus_To_v1alpha3_KubeadmConfigStatus(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert the Error fields to the Failure fields
<span class="cov8" title="1">out.FailureMessage = in.ErrorMessage
out.FailureReason = in.ErrorReason
return nil</span>
}
// Convert_v1alpha3_KubeadmConfigStatus_To_v1alpha2_KubeadmConfigStatus converts from the Hub version (v1alpha3) of the KubeadmConfigStatus to this version.
func Convert_v1alpha3_KubeadmConfigStatus_To_v1alpha2_KubeadmConfigStatus(in *kubeadmbootstrapv1alpha3.KubeadmConfigStatus, out *KubeadmConfigStatus, s apiconversion.Scope) error <span class="cov8" title="1">{
if err := autoConvert_v1alpha3_KubeadmConfigStatus_To_v1alpha2_KubeadmConfigStatus(in, out, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Manually convert the Failure fields to the Error fields
<span class="cov8" title="1">out.ErrorMessage = in.FailureMessage
out.ErrorReason = in.FailureReason
return nil</span>
}
// Convert_v1alpha2_KubeadmConfigSpec_To_v1alpha3_KubeadmConfigSpec converts this KubeadmConfigSpec to the Hub version (v1alpha3).
func Convert_v1alpha2_KubeadmConfigSpec_To_v1alpha3_KubeadmConfigSpec(in *KubeadmConfigSpec, out *kubeadmbootstrapv1alpha3.KubeadmConfigSpec, s apiconversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_KubeadmConfigSpec_To_v1alpha3_KubeadmConfigSpec(in, out, s)
}</span>
// Convert_v1alpha3_KubeadmConfigSpec_To_v1alpha2_KubeadmConfigSpec converts from the Hub version (v1alpha3) of the KubeadmConfigSpec to this version.
func Convert_v1alpha3_KubeadmConfigSpec_To_v1alpha2_KubeadmConfigSpec(in *kubeadmbootstrapv1alpha3.KubeadmConfigSpec, out *KubeadmConfigSpec, s apiconversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_KubeadmConfigSpec_To_v1alpha2_KubeadmConfigSpec(in, out, s)
}</span>
// Convert_v1alpha3_File_To_v1alpha2_File converts from the Hub version (v1alpha3) of the File to this version.
func Convert_v1alpha3_File_To_v1alpha2_File(in *kubeadmbootstrapv1alpha3.File, out *File, s apiconversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_File_To_v1alpha2_File(in, out, s)
}</span>
</pre>
<pre class="file" id="file29" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeadmv1beta1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1"
)
// Format specifies the output format of the bootstrap data
// +kubebuilder:validation:Enum=cloud-config
type Format string
const (
// CloudConfig make the bootstrap data to be of cloud-config format
CloudConfig Format = "cloud-config"
)
// KubeadmConfigSpec defines the desired state of KubeadmConfig.
// Either ClusterConfiguration and InitConfiguration should be defined or the JoinConfiguration should be defined.
type KubeadmConfigSpec struct {
// ClusterConfiguration along with InitConfiguration are the configurations necessary for the init command
// +optional
ClusterConfiguration *kubeadmv1beta1.ClusterConfiguration `json:"clusterConfiguration,omitempty"`
// InitConfiguration along with ClusterConfiguration are the configurations necessary for the init command
// +optional
InitConfiguration *kubeadmv1beta1.InitConfiguration `json:"initConfiguration,omitempty"`
// JoinConfiguration is the kubeadm configuration for the join command
// +optional
JoinConfiguration *kubeadmv1beta1.JoinConfiguration `json:"joinConfiguration,omitempty"`
// Files specifies extra files to be passed to user_data upon creation.
// +optional
Files []File `json:"files,omitempty"`
// PreKubeadmCommands specifies extra commands to run before kubeadm runs
// +optional
PreKubeadmCommands []string `json:"preKubeadmCommands,omitempty"`
// PostKubeadmCommands specifies extra commands to run after kubeadm runs
// +optional
PostKubeadmCommands []string `json:"postKubeadmCommands,omitempty"`
// Users specifies extra users to add
// +optional
Users []User `json:"users,omitempty"`
// NTP specifies NTP configuration
// +optional
NTP *NTP `json:"ntp,omitempty"`
// Format specifies the output format of the bootstrap data
// +optional
Format Format `json:"format,omitempty"`
}
// KubeadmConfigStatus defines the observed state of KubeadmConfig
type KubeadmConfigStatus struct {
// Ready indicates the BootstrapData field is ready to be consumed
Ready bool `json:"ready,omitempty"`
// BootstrapData will be a cloud-init script for now
// +optional
BootstrapData []byte `json:"bootstrapData,omitempty"`
// ErrorReason will be set on non-retryable errors
// +optional
ErrorReason string `json:"errorReason,omitempty"`
// ErrorMessage will be set on non-retryable errors
// +optional
ErrorMessage string `json:"errorMessage,omitempty"`
}
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=kubeadmconfigs,scope=Namespaced,categories=cluster-api
// +kubebuilder:subresource:status
// KubeadmConfig is the Schema for the kubeadmconfigs API
type KubeadmConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec KubeadmConfigSpec `json:"spec,omitempty"`
Status KubeadmConfigStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// KubeadmConfigList contains a list of KubeadmConfig
type KubeadmConfigList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []KubeadmConfig `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;KubeadmConfig{}, &amp;KubeadmConfigList{})
}</span>
// Encoding specifies the cloud-init file encoding.
// +kubebuilder:validation:Enum=base64;gzip;gzip+base64
type Encoding string
const (
// Base64 implies the contents of the file are encoded as base64.
Base64 Encoding = "base64"
// Gzip implies the contents of the file are encoded with gzip.
Gzip Encoding = "gzip"
// GzipBase64 implies the contents of the file are first base64 encoded and then gzip encoded.
GzipBase64 Encoding = "gzip+base64"
)
// File defines the input for generating write_files in cloud-init.
type File struct {
// Path specifies the full path on disk where to store the file.
Path string `json:"path"`
// Owner specifies the ownership of the file, e.g. "root:root".
// +optional
Owner string `json:"owner,omitempty"`
// Permissions specifies the permissions to assign to the file, e.g. "0640".
// +optional
Permissions string `json:"permissions,omitempty"`
// Encoding specifies the encoding of the file contents.
// +optional
Encoding Encoding `json:"encoding,omitempty"`
// Content is the actual content of the file.
Content string `json:"content"`
}
// User defines the input for a generated user in cloud-init.
type User struct {
// Name specifies the user name
Name string `json:"name"`
// Gecos specifies the gecos to use for the user
// +optional
Gecos *string `json:"gecos,omitempty"`
// Groups specifies the additional groups for the user
// +optional
Groups *string `json:"groups,omitempty"`
// HomeDir specifies the home directory to use for the user
// +optional
HomeDir *string `json:"homeDir,omitempty"`
// Inactive specifies whether to mark the user as inactive
// +optional
Inactive *bool `json:"inactive,omitempty"`
// Shell specifies the user's shell
// +optional
Shell *string `json:"shell,omitempty"`
// Passwd specifies a hashed password for the user
// +optional
Passwd *string `json:"passwd,omitempty"`
// PrimaryGroup specifies the primary group for the user
// +optional
PrimaryGroup *string `json:"primaryGroup,omitempty"`
// LockPassword specifies if password login should be disabled
// +optional
LockPassword *bool `json:"lockPassword,omitempty"`
// Sudo specifies a sudo role for the user
// +optional
Sudo *string `json:"sudo,omitempty"`
// SSHAuthorizedKeys specifies a list of ssh authorized keys for the user
// +optional
SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"`
}
// NTP defines input for generated ntp in cloud-init
type NTP struct {
// Servers specifies which NTP servers to use
// +optional
Servers []string `json:"servers,omitempty"`
// Enabled specifies whether NTP should be enabled
// +optional
Enabled *bool `json:"enabled,omitempty"`
}
</pre>
<pre class="file" id="file30" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// KubeadmConfigTemplateSpec defines the desired state of KubeadmConfigTemplate
type KubeadmConfigTemplateSpec struct {
Template KubeadmConfigTemplateResource `json:"template"`
}
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=kubeadmconfigtemplates,scope=Namespaced,categories=cluster-api
// KubeadmConfigTemplate is the Schema for the kubeadmconfigtemplates API
type KubeadmConfigTemplate struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec KubeadmConfigTemplateSpec `json:"spec,omitempty"`
}
// +kubebuilder:object:root=true
// KubeadmConfigTemplateList contains a list of KubeadmConfigTemplate
type KubeadmConfigTemplateList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []KubeadmConfigTemplate `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;KubeadmConfigTemplate{}, &amp;KubeadmConfigTemplateList{})
}</span>
</pre>
<pre class="file" id="file31" style="display: none">// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by conversion-gen. DO NOT EDIT.
package v1alpha2
import (
unsafe "unsafe"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
v1alpha3 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3"
v1beta1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1"
)
func init() <span class="cov8" title="1">{
localSchemeBuilder.Register(RegisterConversions)
}</span>
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error <span class="cov0" title="0">{
if err := s.AddGeneratedConversionFunc((*File)(nil), (*v1alpha3.File)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_File_To_v1alpha3_File(a.(*File), b.(*v1alpha3.File), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*KubeadmConfig)(nil), (*v1alpha3.KubeadmConfig)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_KubeadmConfig_To_v1alpha3_KubeadmConfig(a.(*KubeadmConfig), b.(*v1alpha3.KubeadmConfig), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.KubeadmConfig)(nil), (*KubeadmConfig)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_KubeadmConfig_To_v1alpha2_KubeadmConfig(a.(*v1alpha3.KubeadmConfig), b.(*KubeadmConfig), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*KubeadmConfigList)(nil), (*v1alpha3.KubeadmConfigList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_KubeadmConfigList_To_v1alpha3_KubeadmConfigList(a.(*KubeadmConfigList), b.(*v1alpha3.KubeadmConfigList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.KubeadmConfigList)(nil), (*KubeadmConfigList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_KubeadmConfigList_To_v1alpha2_KubeadmConfigList(a.(*v1alpha3.KubeadmConfigList), b.(*KubeadmConfigList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*KubeadmConfigTemplate)(nil), (*v1alpha3.KubeadmConfigTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_KubeadmConfigTemplate_To_v1alpha3_KubeadmConfigTemplate(a.(*KubeadmConfigTemplate), b.(*v1alpha3.KubeadmConfigTemplate), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.KubeadmConfigTemplate)(nil), (*KubeadmConfigTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_KubeadmConfigTemplate_To_v1alpha2_KubeadmConfigTemplate(a.(*v1alpha3.KubeadmConfigTemplate), b.(*KubeadmConfigTemplate), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*KubeadmConfigTemplateList)(nil), (*v1alpha3.KubeadmConfigTemplateList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_KubeadmConfigTemplateList_To_v1alpha3_KubeadmConfigTemplateList(a.(*KubeadmConfigTemplateList), b.(*v1alpha3.KubeadmConfigTemplateList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.KubeadmConfigTemplateList)(nil), (*KubeadmConfigTemplateList)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_KubeadmConfigTemplateList_To_v1alpha2_KubeadmConfigTemplateList(a.(*v1alpha3.KubeadmConfigTemplateList), b.(*KubeadmConfigTemplateList), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*KubeadmConfigTemplateResource)(nil), (*v1alpha3.KubeadmConfigTemplateResource)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_KubeadmConfigTemplateResource_To_v1alpha3_KubeadmConfigTemplateResource(a.(*KubeadmConfigTemplateResource), b.(*v1alpha3.KubeadmConfigTemplateResource), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.KubeadmConfigTemplateResource)(nil), (*KubeadmConfigTemplateResource)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_KubeadmConfigTemplateResource_To_v1alpha2_KubeadmConfigTemplateResource(a.(*v1alpha3.KubeadmConfigTemplateResource), b.(*KubeadmConfigTemplateResource), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*KubeadmConfigTemplateSpec)(nil), (*v1alpha3.KubeadmConfigTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_KubeadmConfigTemplateSpec_To_v1alpha3_KubeadmConfigTemplateSpec(a.(*KubeadmConfigTemplateSpec), b.(*v1alpha3.KubeadmConfigTemplateSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.KubeadmConfigTemplateSpec)(nil), (*KubeadmConfigTemplateSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_KubeadmConfigTemplateSpec_To_v1alpha2_KubeadmConfigTemplateSpec(a.(*v1alpha3.KubeadmConfigTemplateSpec), b.(*KubeadmConfigTemplateSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*NTP)(nil), (*v1alpha3.NTP)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_NTP_To_v1alpha3_NTP(a.(*NTP), b.(*v1alpha3.NTP), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.NTP)(nil), (*NTP)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_NTP_To_v1alpha2_NTP(a.(*v1alpha3.NTP), b.(*NTP), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*User)(nil), (*v1alpha3.User)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_User_To_v1alpha3_User(a.(*User), b.(*v1alpha3.User), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddGeneratedConversionFunc((*v1alpha3.User)(nil), (*User)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_User_To_v1alpha2_User(a.(*v1alpha3.User), b.(*User), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*KubeadmConfigSpec)(nil), (*v1alpha3.KubeadmConfigSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_KubeadmConfigSpec_To_v1alpha3_KubeadmConfigSpec(a.(*KubeadmConfigSpec), b.(*v1alpha3.KubeadmConfigSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*KubeadmConfigStatus)(nil), (*v1alpha3.KubeadmConfigStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha2_KubeadmConfigStatus_To_v1alpha3_KubeadmConfigStatus(a.(*KubeadmConfigStatus), b.(*v1alpha3.KubeadmConfigStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.File)(nil), (*File)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_File_To_v1alpha2_File(a.(*v1alpha3.File), b.(*File), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.KubeadmConfigSpec)(nil), (*KubeadmConfigSpec)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_KubeadmConfigSpec_To_v1alpha2_KubeadmConfigSpec(a.(*v1alpha3.KubeadmConfigSpec), b.(*KubeadmConfigSpec), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if err := s.AddConversionFunc((*v1alpha3.KubeadmConfigStatus)(nil), (*KubeadmConfigStatus)(nil), func(a, b interface{}, scope conversion.Scope) error </span><span class="cov0" title="0">{
return Convert_v1alpha3_KubeadmConfigStatus_To_v1alpha2_KubeadmConfigStatus(a.(*v1alpha3.KubeadmConfigStatus), b.(*KubeadmConfigStatus), scope)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
func autoConvert_v1alpha2_File_To_v1alpha3_File(in *File, out *v1alpha3.File, s conversion.Scope) error <span class="cov8" title="1">{
out.Path = in.Path
out.Owner = in.Owner
out.Permissions = in.Permissions
out.Encoding = v1alpha3.Encoding(in.Encoding)
out.Content = in.Content
return nil
}</span>
// Convert_v1alpha2_File_To_v1alpha3_File is an autogenerated conversion function.
func Convert_v1alpha2_File_To_v1alpha3_File(in *File, out *v1alpha3.File, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_File_To_v1alpha3_File(in, out, s)
}</span>
func autoConvert_v1alpha3_File_To_v1alpha2_File(in *v1alpha3.File, out *File, s conversion.Scope) error <span class="cov8" title="1">{
out.Path = in.Path
out.Owner = in.Owner
out.Permissions = in.Permissions
out.Encoding = Encoding(in.Encoding)
out.Content = in.Content
// WARNING: in.ContentFrom requires manual conversion: does not exist in peer-type
return nil
}</span>
func autoConvert_v1alpha2_KubeadmConfig_To_v1alpha3_KubeadmConfig(in *KubeadmConfig, out *v1alpha3.KubeadmConfig, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha2_KubeadmConfigSpec_To_v1alpha3_KubeadmConfigSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha2_KubeadmConfigStatus_To_v1alpha3_KubeadmConfigStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha2_KubeadmConfig_To_v1alpha3_KubeadmConfig is an autogenerated conversion function.
func Convert_v1alpha2_KubeadmConfig_To_v1alpha3_KubeadmConfig(in *KubeadmConfig, out *v1alpha3.KubeadmConfig, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha2_KubeadmConfig_To_v1alpha3_KubeadmConfig(in, out, s)
}</span>
func autoConvert_v1alpha3_KubeadmConfig_To_v1alpha2_KubeadmConfig(in *v1alpha3.KubeadmConfig, out *KubeadmConfig, s conversion.Scope) error <span class="cov8" title="1">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha3_KubeadmConfigSpec_To_v1alpha2_KubeadmConfigSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := Convert_v1alpha3_KubeadmConfigStatus_To_v1alpha2_KubeadmConfigStatus(&amp;in.Status, &amp;out.Status, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// Convert_v1alpha3_KubeadmConfig_To_v1alpha2_KubeadmConfig is an autogenerated conversion function.
func Convert_v1alpha3_KubeadmConfig_To_v1alpha2_KubeadmConfig(in *v1alpha3.KubeadmConfig, out *KubeadmConfig, s conversion.Scope) error <span class="cov8" title="1">{
return autoConvert_v1alpha3_KubeadmConfig_To_v1alpha2_KubeadmConfig(in, out, s)
}</span>
func autoConvert_v1alpha2_KubeadmConfigList_To_v1alpha3_KubeadmConfigList(in *KubeadmConfigList, out *v1alpha3.KubeadmConfigList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]v1alpha3.KubeadmConfig, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha2_KubeadmConfig_To_v1alpha3_KubeadmConfig(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha2_KubeadmConfigList_To_v1alpha3_KubeadmConfigList is an autogenerated conversion function.
func Convert_v1alpha2_KubeadmConfigList_To_v1alpha3_KubeadmConfigList(in *KubeadmConfigList, out *v1alpha3.KubeadmConfigList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_KubeadmConfigList_To_v1alpha3_KubeadmConfigList(in, out, s)
}</span>
func autoConvert_v1alpha3_KubeadmConfigList_To_v1alpha2_KubeadmConfigList(in *v1alpha3.KubeadmConfigList, out *KubeadmConfigList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]KubeadmConfig, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha3_KubeadmConfig_To_v1alpha2_KubeadmConfig(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha3_KubeadmConfigList_To_v1alpha2_KubeadmConfigList is an autogenerated conversion function.
func Convert_v1alpha3_KubeadmConfigList_To_v1alpha2_KubeadmConfigList(in *v1alpha3.KubeadmConfigList, out *KubeadmConfigList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_KubeadmConfigList_To_v1alpha2_KubeadmConfigList(in, out, s)
}</span>
func autoConvert_v1alpha2_KubeadmConfigSpec_To_v1alpha3_KubeadmConfigSpec(in *KubeadmConfigSpec, out *v1alpha3.KubeadmConfigSpec, s conversion.Scope) error <span class="cov8" title="1">{
out.ClusterConfiguration = (*v1beta1.ClusterConfiguration)(unsafe.Pointer(in.ClusterConfiguration))
out.InitConfiguration = (*v1beta1.InitConfiguration)(unsafe.Pointer(in.InitConfiguration))
out.JoinConfiguration = (*v1beta1.JoinConfiguration)(unsafe.Pointer(in.JoinConfiguration))
if in.Files != nil </span><span class="cov8" title="1">{
in, out := &amp;in.Files, &amp;out.Files
*out = make([]v1alpha3.File, len(*in))
for i := range *in </span><span class="cov8" title="1">{
if err := Convert_v1alpha2_File_To_v1alpha3_File(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Files = nil
}</span>
<span class="cov8" title="1">out.PreKubeadmCommands = *(*[]string)(unsafe.Pointer(&amp;in.PreKubeadmCommands))
out.PostKubeadmCommands = *(*[]string)(unsafe.Pointer(&amp;in.PostKubeadmCommands))
out.Users = *(*[]v1alpha3.User)(unsafe.Pointer(&amp;in.Users))
out.NTP = (*v1alpha3.NTP)(unsafe.Pointer(in.NTP))
out.Format = v1alpha3.Format(in.Format)
return nil</span>
}
func autoConvert_v1alpha3_KubeadmConfigSpec_To_v1alpha2_KubeadmConfigSpec(in *v1alpha3.KubeadmConfigSpec, out *KubeadmConfigSpec, s conversion.Scope) error <span class="cov8" title="1">{
out.ClusterConfiguration = (*v1beta1.ClusterConfiguration)(unsafe.Pointer(in.ClusterConfiguration))
out.InitConfiguration = (*v1beta1.InitConfiguration)(unsafe.Pointer(in.InitConfiguration))
out.JoinConfiguration = (*v1beta1.JoinConfiguration)(unsafe.Pointer(in.JoinConfiguration))
if in.Files != nil </span><span class="cov8" title="1">{
in, out := &amp;in.Files, &amp;out.Files
*out = make([]File, len(*in))
for i := range *in </span><span class="cov8" title="1">{
if err := Convert_v1alpha3_File_To_v1alpha2_File(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Files = nil
}</span>
// WARNING: in.DiskSetup requires manual conversion: does not exist in peer-type
// WARNING: in.Mounts requires manual conversion: does not exist in peer-type
<span class="cov8" title="1">out.PreKubeadmCommands = *(*[]string)(unsafe.Pointer(&amp;in.PreKubeadmCommands))
out.PostKubeadmCommands = *(*[]string)(unsafe.Pointer(&amp;in.PostKubeadmCommands))
out.Users = *(*[]User)(unsafe.Pointer(&amp;in.Users))
out.NTP = (*NTP)(unsafe.Pointer(in.NTP))
out.Format = Format(in.Format)
// WARNING: in.Verbosity requires manual conversion: does not exist in peer-type
// WARNING: in.UseExperimentalRetryJoin requires manual conversion: does not exist in peer-type
return nil</span>
}
func autoConvert_v1alpha2_KubeadmConfigStatus_To_v1alpha3_KubeadmConfigStatus(in *KubeadmConfigStatus, out *v1alpha3.KubeadmConfigStatus, s conversion.Scope) error <span class="cov8" title="1">{
out.Ready = in.Ready
out.BootstrapData = *(*[]byte)(unsafe.Pointer(&amp;in.BootstrapData))
// WARNING: in.ErrorReason requires manual conversion: does not exist in peer-type
// WARNING: in.ErrorMessage requires manual conversion: does not exist in peer-type
return nil
}</span>
func autoConvert_v1alpha3_KubeadmConfigStatus_To_v1alpha2_KubeadmConfigStatus(in *v1alpha3.KubeadmConfigStatus, out *KubeadmConfigStatus, s conversion.Scope) error <span class="cov8" title="1">{
out.Ready = in.Ready
// WARNING: in.DataSecretName requires manual conversion: does not exist in peer-type
out.BootstrapData = *(*[]byte)(unsafe.Pointer(&amp;in.BootstrapData))
// WARNING: in.FailureReason requires manual conversion: does not exist in peer-type
// WARNING: in.FailureMessage requires manual conversion: does not exist in peer-type
// WARNING: in.ObservedGeneration requires manual conversion: does not exist in peer-type
// WARNING: in.Conditions requires manual conversion: does not exist in peer-type
return nil
}</span>
func autoConvert_v1alpha2_KubeadmConfigTemplate_To_v1alpha3_KubeadmConfigTemplate(in *KubeadmConfigTemplate, out *v1alpha3.KubeadmConfigTemplate, s conversion.Scope) error <span class="cov0" title="0">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha2_KubeadmConfigTemplateSpec_To_v1alpha3_KubeadmConfigTemplateSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha2_KubeadmConfigTemplate_To_v1alpha3_KubeadmConfigTemplate is an autogenerated conversion function.
func Convert_v1alpha2_KubeadmConfigTemplate_To_v1alpha3_KubeadmConfigTemplate(in *KubeadmConfigTemplate, out *v1alpha3.KubeadmConfigTemplate, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_KubeadmConfigTemplate_To_v1alpha3_KubeadmConfigTemplate(in, out, s)
}</span>
func autoConvert_v1alpha3_KubeadmConfigTemplate_To_v1alpha2_KubeadmConfigTemplate(in *v1alpha3.KubeadmConfigTemplate, out *KubeadmConfigTemplate, s conversion.Scope) error <span class="cov0" title="0">{
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha3_KubeadmConfigTemplateSpec_To_v1alpha2_KubeadmConfigTemplateSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha3_KubeadmConfigTemplate_To_v1alpha2_KubeadmConfigTemplate is an autogenerated conversion function.
func Convert_v1alpha3_KubeadmConfigTemplate_To_v1alpha2_KubeadmConfigTemplate(in *v1alpha3.KubeadmConfigTemplate, out *KubeadmConfigTemplate, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_KubeadmConfigTemplate_To_v1alpha2_KubeadmConfigTemplate(in, out, s)
}</span>
func autoConvert_v1alpha2_KubeadmConfigTemplateList_To_v1alpha3_KubeadmConfigTemplateList(in *KubeadmConfigTemplateList, out *v1alpha3.KubeadmConfigTemplateList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]v1alpha3.KubeadmConfigTemplate, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha2_KubeadmConfigTemplate_To_v1alpha3_KubeadmConfigTemplate(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha2_KubeadmConfigTemplateList_To_v1alpha3_KubeadmConfigTemplateList is an autogenerated conversion function.
func Convert_v1alpha2_KubeadmConfigTemplateList_To_v1alpha3_KubeadmConfigTemplateList(in *KubeadmConfigTemplateList, out *v1alpha3.KubeadmConfigTemplateList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_KubeadmConfigTemplateList_To_v1alpha3_KubeadmConfigTemplateList(in, out, s)
}</span>
func autoConvert_v1alpha3_KubeadmConfigTemplateList_To_v1alpha2_KubeadmConfigTemplateList(in *v1alpha3.KubeadmConfigTemplateList, out *KubeadmConfigTemplateList, s conversion.Scope) error <span class="cov0" title="0">{
out.ListMeta = in.ListMeta
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]KubeadmConfigTemplate, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if err := Convert_v1alpha3_KubeadmConfigTemplate_To_v1alpha2_KubeadmConfigTemplate(&amp;(*in)[i], &amp;(*out)[i], s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
} else<span class="cov0" title="0"> {
out.Items = nil
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha3_KubeadmConfigTemplateList_To_v1alpha2_KubeadmConfigTemplateList is an autogenerated conversion function.
func Convert_v1alpha3_KubeadmConfigTemplateList_To_v1alpha2_KubeadmConfigTemplateList(in *v1alpha3.KubeadmConfigTemplateList, out *KubeadmConfigTemplateList, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_KubeadmConfigTemplateList_To_v1alpha2_KubeadmConfigTemplateList(in, out, s)
}</span>
func autoConvert_v1alpha2_KubeadmConfigTemplateResource_To_v1alpha3_KubeadmConfigTemplateResource(in *KubeadmConfigTemplateResource, out *v1alpha3.KubeadmConfigTemplateResource, s conversion.Scope) error <span class="cov0" title="0">{
if err := Convert_v1alpha2_KubeadmConfigSpec_To_v1alpha3_KubeadmConfigSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha2_KubeadmConfigTemplateResource_To_v1alpha3_KubeadmConfigTemplateResource is an autogenerated conversion function.
func Convert_v1alpha2_KubeadmConfigTemplateResource_To_v1alpha3_KubeadmConfigTemplateResource(in *KubeadmConfigTemplateResource, out *v1alpha3.KubeadmConfigTemplateResource, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_KubeadmConfigTemplateResource_To_v1alpha3_KubeadmConfigTemplateResource(in, out, s)
}</span>
func autoConvert_v1alpha3_KubeadmConfigTemplateResource_To_v1alpha2_KubeadmConfigTemplateResource(in *v1alpha3.KubeadmConfigTemplateResource, out *KubeadmConfigTemplateResource, s conversion.Scope) error <span class="cov0" title="0">{
if err := Convert_v1alpha3_KubeadmConfigSpec_To_v1alpha2_KubeadmConfigSpec(&amp;in.Spec, &amp;out.Spec, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha3_KubeadmConfigTemplateResource_To_v1alpha2_KubeadmConfigTemplateResource is an autogenerated conversion function.
func Convert_v1alpha3_KubeadmConfigTemplateResource_To_v1alpha2_KubeadmConfigTemplateResource(in *v1alpha3.KubeadmConfigTemplateResource, out *KubeadmConfigTemplateResource, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_KubeadmConfigTemplateResource_To_v1alpha2_KubeadmConfigTemplateResource(in, out, s)
}</span>
func autoConvert_v1alpha2_KubeadmConfigTemplateSpec_To_v1alpha3_KubeadmConfigTemplateSpec(in *KubeadmConfigTemplateSpec, out *v1alpha3.KubeadmConfigTemplateSpec, s conversion.Scope) error <span class="cov0" title="0">{
if err := Convert_v1alpha2_KubeadmConfigTemplateResource_To_v1alpha3_KubeadmConfigTemplateResource(&amp;in.Template, &amp;out.Template, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha2_KubeadmConfigTemplateSpec_To_v1alpha3_KubeadmConfigTemplateSpec is an autogenerated conversion function.
func Convert_v1alpha2_KubeadmConfigTemplateSpec_To_v1alpha3_KubeadmConfigTemplateSpec(in *KubeadmConfigTemplateSpec, out *v1alpha3.KubeadmConfigTemplateSpec, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_KubeadmConfigTemplateSpec_To_v1alpha3_KubeadmConfigTemplateSpec(in, out, s)
}</span>
func autoConvert_v1alpha3_KubeadmConfigTemplateSpec_To_v1alpha2_KubeadmConfigTemplateSpec(in *v1alpha3.KubeadmConfigTemplateSpec, out *KubeadmConfigTemplateSpec, s conversion.Scope) error <span class="cov0" title="0">{
if err := Convert_v1alpha3_KubeadmConfigTemplateResource_To_v1alpha2_KubeadmConfigTemplateResource(&amp;in.Template, &amp;out.Template, s); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
// Convert_v1alpha3_KubeadmConfigTemplateSpec_To_v1alpha2_KubeadmConfigTemplateSpec is an autogenerated conversion function.
func Convert_v1alpha3_KubeadmConfigTemplateSpec_To_v1alpha2_KubeadmConfigTemplateSpec(in *v1alpha3.KubeadmConfigTemplateSpec, out *KubeadmConfigTemplateSpec, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_KubeadmConfigTemplateSpec_To_v1alpha2_KubeadmConfigTemplateSpec(in, out, s)
}</span>
func autoConvert_v1alpha2_NTP_To_v1alpha3_NTP(in *NTP, out *v1alpha3.NTP, s conversion.Scope) error <span class="cov0" title="0">{
out.Servers = *(*[]string)(unsafe.Pointer(&amp;in.Servers))
out.Enabled = (*bool)(unsafe.Pointer(in.Enabled))
return nil
}</span>
// Convert_v1alpha2_NTP_To_v1alpha3_NTP is an autogenerated conversion function.
func Convert_v1alpha2_NTP_To_v1alpha3_NTP(in *NTP, out *v1alpha3.NTP, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_NTP_To_v1alpha3_NTP(in, out, s)
}</span>
func autoConvert_v1alpha3_NTP_To_v1alpha2_NTP(in *v1alpha3.NTP, out *NTP, s conversion.Scope) error <span class="cov0" title="0">{
out.Servers = *(*[]string)(unsafe.Pointer(&amp;in.Servers))
out.Enabled = (*bool)(unsafe.Pointer(in.Enabled))
return nil
}</span>
// Convert_v1alpha3_NTP_To_v1alpha2_NTP is an autogenerated conversion function.
func Convert_v1alpha3_NTP_To_v1alpha2_NTP(in *v1alpha3.NTP, out *NTP, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_NTP_To_v1alpha2_NTP(in, out, s)
}</span>
func autoConvert_v1alpha2_User_To_v1alpha3_User(in *User, out *v1alpha3.User, s conversion.Scope) error <span class="cov0" title="0">{
out.Name = in.Name
out.Gecos = (*string)(unsafe.Pointer(in.Gecos))
out.Groups = (*string)(unsafe.Pointer(in.Groups))
out.HomeDir = (*string)(unsafe.Pointer(in.HomeDir))
out.Inactive = (*bool)(unsafe.Pointer(in.Inactive))
out.Shell = (*string)(unsafe.Pointer(in.Shell))
out.Passwd = (*string)(unsafe.Pointer(in.Passwd))
out.PrimaryGroup = (*string)(unsafe.Pointer(in.PrimaryGroup))
out.LockPassword = (*bool)(unsafe.Pointer(in.LockPassword))
out.Sudo = (*string)(unsafe.Pointer(in.Sudo))
out.SSHAuthorizedKeys = *(*[]string)(unsafe.Pointer(&amp;in.SSHAuthorizedKeys))
return nil
}</span>
// Convert_v1alpha2_User_To_v1alpha3_User is an autogenerated conversion function.
func Convert_v1alpha2_User_To_v1alpha3_User(in *User, out *v1alpha3.User, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha2_User_To_v1alpha3_User(in, out, s)
}</span>
func autoConvert_v1alpha3_User_To_v1alpha2_User(in *v1alpha3.User, out *User, s conversion.Scope) error <span class="cov0" title="0">{
out.Name = in.Name
out.Gecos = (*string)(unsafe.Pointer(in.Gecos))
out.Groups = (*string)(unsafe.Pointer(in.Groups))
out.HomeDir = (*string)(unsafe.Pointer(in.HomeDir))
out.Inactive = (*bool)(unsafe.Pointer(in.Inactive))
out.Shell = (*string)(unsafe.Pointer(in.Shell))
out.Passwd = (*string)(unsafe.Pointer(in.Passwd))
out.PrimaryGroup = (*string)(unsafe.Pointer(in.PrimaryGroup))
out.LockPassword = (*bool)(unsafe.Pointer(in.LockPassword))
out.Sudo = (*string)(unsafe.Pointer(in.Sudo))
out.SSHAuthorizedKeys = *(*[]string)(unsafe.Pointer(&amp;in.SSHAuthorizedKeys))
return nil
}</span>
// Convert_v1alpha3_User_To_v1alpha2_User is an autogenerated conversion function.
func Convert_v1alpha3_User_To_v1alpha2_User(in *v1alpha3.User, out *User, s conversion.Scope) error <span class="cov0" title="0">{
return autoConvert_v1alpha3_User_To_v1alpha2_User(in, out, s)
}</span>
</pre>
<pre class="file" id="file32" style="display: none">// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1alpha2
import (
runtime "k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *File) DeepCopyInto(out *File) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new File.
func (in *File) DeepCopy() *File <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(File)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfig) DeepCopyInto(out *KubeadmConfig) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
in.Status.DeepCopyInto(&amp;out.Status)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfig.
func (in *KubeadmConfig) DeepCopy() *KubeadmConfig <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfig)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KubeadmConfig) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigList) DeepCopyInto(out *KubeadmConfigList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]KubeadmConfig, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigList.
func (in *KubeadmConfigList) DeepCopy() *KubeadmConfigList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KubeadmConfigList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigSpec) DeepCopyInto(out *KubeadmConfigSpec) <span class="cov0" title="0">{
*out = *in
if in.ClusterConfiguration != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ClusterConfiguration, &amp;out.ClusterConfiguration
*out = new(v1beta1.ClusterConfiguration)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.InitConfiguration != nil </span><span class="cov0" title="0">{
in, out := &amp;in.InitConfiguration, &amp;out.InitConfiguration
*out = new(v1beta1.InitConfiguration)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.JoinConfiguration != nil </span><span class="cov0" title="0">{
in, out := &amp;in.JoinConfiguration, &amp;out.JoinConfiguration
*out = new(v1beta1.JoinConfiguration)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.Files != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Files, &amp;out.Files
*out = make([]File, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.PreKubeadmCommands != nil </span><span class="cov0" title="0">{
in, out := &amp;in.PreKubeadmCommands, &amp;out.PreKubeadmCommands
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.PostKubeadmCommands != nil </span><span class="cov0" title="0">{
in, out := &amp;in.PostKubeadmCommands, &amp;out.PostKubeadmCommands
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.Users != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Users, &amp;out.Users
*out = make([]User, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
<span class="cov0" title="0">if in.NTP != nil </span><span class="cov0" title="0">{
in, out := &amp;in.NTP, &amp;out.NTP
*out = new(NTP)
(*in).DeepCopyInto(*out)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigSpec.
func (in *KubeadmConfigSpec) DeepCopy() *KubeadmConfigSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigStatus) DeepCopyInto(out *KubeadmConfigStatus) <span class="cov0" title="0">{
*out = *in
if in.BootstrapData != nil </span><span class="cov0" title="0">{
in, out := &amp;in.BootstrapData, &amp;out.BootstrapData
*out = make([]byte, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigStatus.
func (in *KubeadmConfigStatus) DeepCopy() *KubeadmConfigStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigTemplate) DeepCopyInto(out *KubeadmConfigTemplate) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigTemplate.
func (in *KubeadmConfigTemplate) DeepCopy() *KubeadmConfigTemplate <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigTemplate)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KubeadmConfigTemplate) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigTemplateList) DeepCopyInto(out *KubeadmConfigTemplateList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]KubeadmConfigTemplate, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigTemplateList.
func (in *KubeadmConfigTemplateList) DeepCopy() *KubeadmConfigTemplateList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigTemplateList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KubeadmConfigTemplateList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigTemplateResource) DeepCopyInto(out *KubeadmConfigTemplateResource) <span class="cov0" title="0">{
*out = *in
in.Spec.DeepCopyInto(&amp;out.Spec)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigTemplateResource.
func (in *KubeadmConfigTemplateResource) DeepCopy() *KubeadmConfigTemplateResource <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigTemplateResource)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigTemplateSpec) DeepCopyInto(out *KubeadmConfigTemplateSpec) <span class="cov0" title="0">{
*out = *in
in.Template.DeepCopyInto(&amp;out.Template)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigTemplateSpec.
func (in *KubeadmConfigTemplateSpec) DeepCopy() *KubeadmConfigTemplateSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigTemplateSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NTP) DeepCopyInto(out *NTP) <span class="cov0" title="0">{
*out = *in
if in.Servers != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Servers, &amp;out.Servers
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.Enabled != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Enabled, &amp;out.Enabled
*out = new(bool)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NTP.
func (in *NTP) DeepCopy() *NTP <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(NTP)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *User) DeepCopyInto(out *User) <span class="cov0" title="0">{
*out = *in
if in.Gecos != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Gecos, &amp;out.Gecos
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.Groups != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Groups, &amp;out.Groups
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.HomeDir != nil </span><span class="cov0" title="0">{
in, out := &amp;in.HomeDir, &amp;out.HomeDir
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.Inactive != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Inactive, &amp;out.Inactive
*out = new(bool)
**out = **in
}</span>
<span class="cov0" title="0">if in.Shell != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Shell, &amp;out.Shell
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.Passwd != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Passwd, &amp;out.Passwd
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.PrimaryGroup != nil </span><span class="cov0" title="0">{
in, out := &amp;in.PrimaryGroup, &amp;out.PrimaryGroup
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.LockPassword != nil </span><span class="cov0" title="0">{
in, out := &amp;in.LockPassword, &amp;out.LockPassword
*out = new(bool)
**out = **in
}</span>
<span class="cov0" title="0">if in.Sudo != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Sudo, &amp;out.Sudo
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.SSHAuthorizedKeys != nil </span><span class="cov0" title="0">{
in, out := &amp;in.SSHAuthorizedKeys, &amp;out.SSHAuthorizedKeys
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User.
func (in *User) DeepCopy() *User <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(User)
in.DeepCopyInto(out)
return out</span>
}
</pre>
<pre class="file" id="file33" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
func (*KubeadmConfig) Hub() {<span class="cov0" title="0">}</span>
func (*KubeadmConfigList) Hub() {<span class="cov0" title="0">}</span>
func (*KubeadmConfigTemplate) Hub() {<span class="cov0" title="0">}</span>
func (*KubeadmConfigTemplateList) Hub() {<span class="cov0" title="0">}</span>
</pre>
<pre class="file" id="file34" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
kubeadmv1beta1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1"
)
// Format specifies the output format of the bootstrap data
// +kubebuilder:validation:Enum=cloud-config
type Format string
const (
// CloudConfig make the bootstrap data to be of cloud-config format
CloudConfig Format = "cloud-config"
)
// KubeadmConfigSpec defines the desired state of KubeadmConfig.
// Either ClusterConfiguration and InitConfiguration should be defined or the JoinConfiguration should be defined.
type KubeadmConfigSpec struct {
// ClusterConfiguration along with InitConfiguration are the configurations necessary for the init command
// +optional
ClusterConfiguration *kubeadmv1beta1.ClusterConfiguration `json:"clusterConfiguration,omitempty"`
// InitConfiguration along with ClusterConfiguration are the configurations necessary for the init command
// +optional
InitConfiguration *kubeadmv1beta1.InitConfiguration `json:"initConfiguration,omitempty"`
// JoinConfiguration is the kubeadm configuration for the join command
// +optional
JoinConfiguration *kubeadmv1beta1.JoinConfiguration `json:"joinConfiguration,omitempty"`
// Files specifies extra files to be passed to user_data upon creation.
// +optional
Files []File `json:"files,omitempty"`
// DiskSetup specifies options for the creation of partition tables and file systems on devices.
// +optional
DiskSetup *DiskSetup `json:"diskSetup,omitempty"`
// Mounts specifies a list of mount points to be setup.
// +optional
Mounts []MountPoints `json:"mounts,omitempty"`
// PreKubeadmCommands specifies extra commands to run before kubeadm runs
// +optional
PreKubeadmCommands []string `json:"preKubeadmCommands,omitempty"`
// PostKubeadmCommands specifies extra commands to run after kubeadm runs
// +optional
PostKubeadmCommands []string `json:"postKubeadmCommands,omitempty"`
// Users specifies extra users to add
// +optional
Users []User `json:"users,omitempty"`
// NTP specifies NTP configuration
// +optional
NTP *NTP `json:"ntp,omitempty"`
// Format specifies the output format of the bootstrap data
// +optional
Format Format `json:"format,omitempty"`
// Verbosity is the number for the kubeadm log level verbosity.
// It overrides the `--v` flag in kubeadm commands.
// +optional
Verbosity *int32 `json:"verbosity,omitempty"`
// UseExperimentalRetryJoin replaces a basic kubeadm command with a shell
// script with retries for joins.
//
// This is meant to be an experimental temporary workaround on some environments
// where joins fail due to timing (and other issues). The long term goal is to add retries to
// kubeadm proper and use that functionality.
//
// This will add about 40KB to userdata
//
// For more information, refer to https://github.com/kubernetes-sigs/cluster-api/pull/2763#discussion_r397306055.
// +optional
UseExperimentalRetryJoin bool `json:"useExperimentalRetryJoin,omitempty"`
}
// KubeadmConfigStatus defines the observed state of KubeadmConfig
type KubeadmConfigStatus struct {
// Ready indicates the BootstrapData field is ready to be consumed
Ready bool `json:"ready,omitempty"`
// DataSecretName is the name of the secret that stores the bootstrap data script.
// +optional
DataSecretName *string `json:"dataSecretName,omitempty"`
// BootstrapData will be a cloud-init script for now.
//
// Deprecated: This field has been deprecated in v1alpha3 and
// will be removed in a future version. Switch to DataSecretName.
//
// +optional
BootstrapData []byte `json:"bootstrapData,omitempty"`
// FailureReason will be set on non-retryable errors
// +optional
FailureReason string `json:"failureReason,omitempty"`
// FailureMessage will be set on non-retryable errors
// +optional
FailureMessage string `json:"failureMessage,omitempty"`
// ObservedGeneration is the latest generation observed by the controller.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// Conditions defines current service state of the KubeadmConfig.
// +optional
Conditions clusterv1.Conditions `json:"conditions,omitempty"`
}
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=kubeadmconfigs,scope=Namespaced,categories=cluster-api
// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// KubeadmConfig is the Schema for the kubeadmconfigs API
type KubeadmConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec KubeadmConfigSpec `json:"spec,omitempty"`
Status KubeadmConfigStatus `json:"status,omitempty"`
}
func (c *KubeadmConfig) GetConditions() clusterv1.Conditions <span class="cov0" title="0">{
return c.Status.Conditions
}</span>
func (c *KubeadmConfig) SetConditions(conditions clusterv1.Conditions) <span class="cov0" title="0">{
c.Status.Conditions = conditions
}</span>
// +kubebuilder:object:root=true
// KubeadmConfigList contains a list of KubeadmConfig
type KubeadmConfigList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []KubeadmConfig `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;KubeadmConfig{}, &amp;KubeadmConfigList{})
}</span>
// Encoding specifies the cloud-init file encoding.
// +kubebuilder:validation:Enum=base64;gzip;gzip+base64
type Encoding string
const (
// Base64 implies the contents of the file are encoded as base64.
Base64 Encoding = "base64"
// Gzip implies the contents of the file are encoded with gzip.
Gzip Encoding = "gzip"
// GzipBase64 implies the contents of the file are first base64 encoded and then gzip encoded.
GzipBase64 Encoding = "gzip+base64"
)
// File defines the input for generating write_files in cloud-init.
type File struct {
// Path specifies the full path on disk where to store the file.
Path string `json:"path"`
// Owner specifies the ownership of the file, e.g. "root:root".
// +optional
Owner string `json:"owner,omitempty"`
// Permissions specifies the permissions to assign to the file, e.g. "0640".
// +optional
Permissions string `json:"permissions,omitempty"`
// Encoding specifies the encoding of the file contents.
// +optional
Encoding Encoding `json:"encoding,omitempty"`
// Content is the actual content of the file.
// +optional
Content string `json:"content,omitempty"`
// ContentFrom is a referenced source of content to populate the file.
// +optional
ContentFrom *FileSource `json:"contentFrom,omitempty"`
}
// FileSource is a union of all possible external source types for file data.
// Only one field may be populated in any given instance. Developers adding new
// sources of data for target systems should add them here.
type FileSource struct {
// Secret represents a secret that should populate this file.
Secret SecretFileSource `json:"secret"`
}
// Adapts a Secret into a FileSource.
//
// The contents of the target Secret's Data field will be presented
// as files using the keys in the Data field as the file names.
type SecretFileSource struct {
// Name of the secret in the KubeadmBootstrapConfig's namespace to use.
Name string `json:"name"`
// Key is the key in the secret's data map for this value.
Key string `json:"key"`
}
// User defines the input for a generated user in cloud-init.
type User struct {
// Name specifies the user name
Name string `json:"name"`
// Gecos specifies the gecos to use for the user
// +optional
Gecos *string `json:"gecos,omitempty"`
// Groups specifies the additional groups for the user
// +optional
Groups *string `json:"groups,omitempty"`
// HomeDir specifies the home directory to use for the user
// +optional
HomeDir *string `json:"homeDir,omitempty"`
// Inactive specifies whether to mark the user as inactive
// +optional
Inactive *bool `json:"inactive,omitempty"`
// Shell specifies the user's shell
// +optional
Shell *string `json:"shell,omitempty"`
// Passwd specifies a hashed password for the user
// +optional
Passwd *string `json:"passwd,omitempty"`
// PrimaryGroup specifies the primary group for the user
// +optional
PrimaryGroup *string `json:"primaryGroup,omitempty"`
// LockPassword specifies if password login should be disabled
// +optional
LockPassword *bool `json:"lockPassword,omitempty"`
// Sudo specifies a sudo role for the user
// +optional
Sudo *string `json:"sudo,omitempty"`
// SSHAuthorizedKeys specifies a list of ssh authorized keys for the user
// +optional
SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"`
}
// NTP defines input for generated ntp in cloud-init
type NTP struct {
// Servers specifies which NTP servers to use
// +optional
Servers []string `json:"servers,omitempty"`
// Enabled specifies whether NTP should be enabled
// +optional
Enabled *bool `json:"enabled,omitempty"`
}
// DiskSetup defines input for generated disk_setup and fs_setup in cloud-init.
type DiskSetup struct {
// Partitions specifies the list of the partitions to setup.
Partitions []Partition `json:"partitions,omitempty"`
// Filesystems specifies the list of file systems to setup.
Filesystems []Filesystem `json:"filesystems,omitempty"`
}
// Partition defines how to create and layout a partition.
type Partition struct {
// Device is the name of the device.
Device string `json:"device"`
// Layout specifies the device layout.
// If it is true, a single partition will be created for the entire device.
// When layout is false, it means don't partition or ignore existing partitioning.
Layout bool `json:"layout"`
// Overwrite describes whether to skip checks and create the partition if a partition or filesystem is found on the device.
// Use with caution. Default is 'false'.
// +optional
Overwrite *bool `json:"overwrite,omitempty"`
// TableType specifies the tupe of partition table. The following are supported:
// 'mbr': default and setups a MS-DOS partition table
// 'gpt': setups a GPT partition table
// +optional
TableType *string `json:"tableType,omitempty"`
}
// Filesystem defines the file systems to be created.
type Filesystem struct {
// Device specifies the device name
Device string `json:"device"`
// Filesystem specifies the file system type.
Filesystem string `json:"filesystem"`
// Label specifies the file system label to be used. If set to None, no label is used.
Label string `json:"label"`
// Partition specifies the partition to use. The valid options are: "auto|any", "auto", "any", "none", and &lt;NUM&gt;, where NUM is the actual partition number.
// +optional
Partition *string `json:"partition,omitempty"`
// Overwrite defines whether or not to overwrite any existing filesystem.
// If true, any pre-existing file system will be destroyed. Use with Caution.
// +optional
Overwrite *bool `json:"overwrite,omitempty"`
// ReplaceFS is a special directive, used for Microsoft Azure that instructs cloud-init to replace a file system of &lt;FS_TYPE&gt;.
// NOTE: unless you define a label, this requires the use of the 'any' partition directive.
// +optional
ReplaceFS *string `json:"replaceFS,omitempty"`
// ExtraOpts defined extra options to add to the command for creating the file system.
// +optional
ExtraOpts []string `json:"extraOpts,omitempty"`
}
// MountPoints defines input for generated mounts in cloud-init.
type MountPoints []string
</pre>
<pre class="file" id="file35" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
"fmt"
apierrors "k8s.io/apimachinery/pkg/api/errors"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)
var (
ConflictingFileSourceMsg = "only one of content of contentFrom may be specified for a single file"
MissingFileSourceMsg = "source for file content must be specified if contenFrom is non-nil"
MissingSecretNameMsg = "secret file source must specify non-empty secret name"
MissingSecretKeyMsg = "secret file source must specify non-empty secret key"
PathConflictMsg = "path property must be unique among all files"
)
func (c *KubeadmConfig) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(c).
Complete()
}</span>
// +kubebuilder:webhook:verbs=create;update,path=/validate-bootstrap-cluster-x-k8s-io-v1alpha3-kubeadmconfig,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=bootstrap.cluster.x-k8s.io,resources=kubeadmconfigs,versions=v1alpha3,name=validation.kubeadmconfig.bootstrap.cluster.x-k8s.io,sideEffects=None
var _ webhook.Validator = &amp;KubeadmConfig{}
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (c *KubeadmConfig) ValidateCreate() error <span class="cov8" title="1">{
return c.Spec.validate(c.Name)
}</span>
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (c *KubeadmConfig) ValidateUpdate(old runtime.Object) error <span class="cov8" title="1">{
return c.Spec.validate(c.Name)
}</span>
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (c *KubeadmConfig) ValidateDelete() error <span class="cov0" title="0">{
return nil
}</span>
func (c *KubeadmConfigSpec) validate(name string) error <span class="cov8" title="1">{
var allErrs field.ErrorList
knownPaths := map[string]struct{}{}
for i := range c.Files </span><span class="cov8" title="1">{
file := c.Files[i]
if file.Content != "" &amp;&amp; file.ContentFrom != nil </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "files", fmt.Sprintf("%d", i)),
file,
ConflictingFileSourceMsg,
),
)
}</span>
// n.b.: if we ever add types besides Secret as a ContentFrom
// Source, we must add webhook validation here for one of the
// sources being non-nil.
<span class="cov8" title="1">if file.ContentFrom != nil </span><span class="cov8" title="1">{
if file.ContentFrom.Secret.Name == "" </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "files", fmt.Sprintf("%d", i), "contentFrom", "secret", "name"),
file,
MissingSecretNameMsg,
),
)
}</span>
<span class="cov8" title="1">if file.ContentFrom.Secret.Key == "" </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "files", fmt.Sprintf("%d", i), "contentFrom", "secret", "key"),
file,
MissingSecretKeyMsg,
),
)
}</span>
}
<span class="cov8" title="1">_, conflict := knownPaths[file.Path]
if conflict </span><span class="cov8" title="1">{
allErrs = append(
allErrs,
field.Invalid(
field.NewPath("spec", "files", fmt.Sprintf("%d", i), "path"),
file,
PathConflictMsg,
),
)
}</span>
<span class="cov8" title="1">knownPaths[file.Path] = struct{}{}</span>
}
<span class="cov8" title="1">if len(allErrs) == 0 </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov8" title="1">return apierrors.NewInvalid(GroupVersion.WithKind("KubeadmConfig").GroupKind(), name, allErrs)</span>
}
</pre>
<pre class="file" id="file36" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
ctrl "sigs.k8s.io/controller-runtime"
)
func (r *KubeadmConfigList) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file37" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// KubeadmConfigTemplateSpec defines the desired state of KubeadmConfigTemplate
type KubeadmConfigTemplateSpec struct {
Template KubeadmConfigTemplateResource `json:"template"`
}
// KubeadmConfigTemplateResource defines the Template structure
type KubeadmConfigTemplateResource struct {
Spec KubeadmConfigSpec `json:"spec,omitempty"`
}
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=kubeadmconfigtemplates,scope=Namespaced,categories=cluster-api
// +kubebuilder:storageversion
// KubeadmConfigTemplate is the Schema for the kubeadmconfigtemplates API
type KubeadmConfigTemplate struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec KubeadmConfigTemplateSpec `json:"spec,omitempty"`
}
// +kubebuilder:object:root=true
// KubeadmConfigTemplateList contains a list of KubeadmConfigTemplate
type KubeadmConfigTemplateList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []KubeadmConfigTemplate `json:"items"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;KubeadmConfigTemplate{}, &amp;KubeadmConfigTemplateList{})
}</span>
</pre>
<pre class="file" id="file38" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
ctrl "sigs.k8s.io/controller-runtime"
)
func (r *KubeadmConfigTemplate) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file39" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
ctrl "sigs.k8s.io/controller-runtime"
)
func (r *KubeadmConfigTemplateList) SetupWebhookWithManager(mgr ctrl.Manager) error <span class="cov0" title="0">{
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}</span>
</pre>
<pre class="file" id="file40" style="display: none">// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1alpha3
import (
"k8s.io/apimachinery/pkg/runtime"
apiv1alpha3 "sigs.k8s.io/cluster-api/api/v1alpha3"
"sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DiskSetup) DeepCopyInto(out *DiskSetup) <span class="cov0" title="0">{
*out = *in
if in.Partitions != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Partitions, &amp;out.Partitions
*out = make([]Partition, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
<span class="cov0" title="0">if in.Filesystems != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Filesystems, &amp;out.Filesystems
*out = make([]Filesystem, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DiskSetup.
func (in *DiskSetup) DeepCopy() *DiskSetup <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(DiskSetup)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *File) DeepCopyInto(out *File) <span class="cov0" title="0">{
*out = *in
if in.ContentFrom != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ContentFrom, &amp;out.ContentFrom
*out = new(FileSource)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new File.
func (in *File) DeepCopy() *File <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(File)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FileSource) DeepCopyInto(out *FileSource) <span class="cov0" title="0">{
*out = *in
out.Secret = in.Secret
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileSource.
func (in *FileSource) DeepCopy() *FileSource <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(FileSource)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Filesystem) DeepCopyInto(out *Filesystem) <span class="cov0" title="0">{
*out = *in
if in.Partition != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Partition, &amp;out.Partition
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.Overwrite != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Overwrite, &amp;out.Overwrite
*out = new(bool)
**out = **in
}</span>
<span class="cov0" title="0">if in.ReplaceFS != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ReplaceFS, &amp;out.ReplaceFS
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.ExtraOpts != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ExtraOpts, &amp;out.ExtraOpts
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Filesystem.
func (in *Filesystem) DeepCopy() *Filesystem <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Filesystem)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfig) DeepCopyInto(out *KubeadmConfig) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
in.Status.DeepCopyInto(&amp;out.Status)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfig.
func (in *KubeadmConfig) DeepCopy() *KubeadmConfig <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfig)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KubeadmConfig) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigList) DeepCopyInto(out *KubeadmConfigList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]KubeadmConfig, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigList.
func (in *KubeadmConfigList) DeepCopy() *KubeadmConfigList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KubeadmConfigList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigSpec) DeepCopyInto(out *KubeadmConfigSpec) <span class="cov0" title="0">{
*out = *in
if in.ClusterConfiguration != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ClusterConfiguration, &amp;out.ClusterConfiguration
*out = new(v1beta1.ClusterConfiguration)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.InitConfiguration != nil </span><span class="cov0" title="0">{
in, out := &amp;in.InitConfiguration, &amp;out.InitConfiguration
*out = new(v1beta1.InitConfiguration)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.JoinConfiguration != nil </span><span class="cov0" title="0">{
in, out := &amp;in.JoinConfiguration, &amp;out.JoinConfiguration
*out = new(v1beta1.JoinConfiguration)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.Files != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Files, &amp;out.Files
*out = make([]File, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
<span class="cov0" title="0">if in.DiskSetup != nil </span><span class="cov0" title="0">{
in, out := &amp;in.DiskSetup, &amp;out.DiskSetup
*out = new(DiskSetup)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.Mounts != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Mounts, &amp;out.Mounts
*out = make([]MountPoints, len(*in))
for i := range *in </span><span class="cov0" title="0">{
if (*in)[i] != nil </span><span class="cov0" title="0">{
in, out := &amp;(*in)[i], &amp;(*out)[i]
*out = make(MountPoints, len(*in))
copy(*out, *in)
}</span>
}
}
<span class="cov0" title="0">if in.PreKubeadmCommands != nil </span><span class="cov0" title="0">{
in, out := &amp;in.PreKubeadmCommands, &amp;out.PreKubeadmCommands
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.PostKubeadmCommands != nil </span><span class="cov0" title="0">{
in, out := &amp;in.PostKubeadmCommands, &amp;out.PostKubeadmCommands
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.Users != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Users, &amp;out.Users
*out = make([]User, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
<span class="cov0" title="0">if in.NTP != nil </span><span class="cov0" title="0">{
in, out := &amp;in.NTP, &amp;out.NTP
*out = new(NTP)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.Verbosity != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Verbosity, &amp;out.Verbosity
*out = new(int32)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigSpec.
func (in *KubeadmConfigSpec) DeepCopy() *KubeadmConfigSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigStatus) DeepCopyInto(out *KubeadmConfigStatus) <span class="cov0" title="0">{
*out = *in
if in.DataSecretName != nil </span><span class="cov0" title="0">{
in, out := &amp;in.DataSecretName, &amp;out.DataSecretName
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.BootstrapData != nil </span><span class="cov0" title="0">{
in, out := &amp;in.BootstrapData, &amp;out.BootstrapData
*out = make([]byte, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.Conditions != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Conditions, &amp;out.Conditions
*out = make(apiv1alpha3.Conditions, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigStatus.
func (in *KubeadmConfigStatus) DeepCopy() *KubeadmConfigStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigTemplate) DeepCopyInto(out *KubeadmConfigTemplate) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
in.Spec.DeepCopyInto(&amp;out.Spec)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigTemplate.
func (in *KubeadmConfigTemplate) DeepCopy() *KubeadmConfigTemplate <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigTemplate)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KubeadmConfigTemplate) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigTemplateList) DeepCopyInto(out *KubeadmConfigTemplateList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]KubeadmConfigTemplate, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigTemplateList.
func (in *KubeadmConfigTemplateList) DeepCopy() *KubeadmConfigTemplateList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigTemplateList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KubeadmConfigTemplateList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigTemplateResource) DeepCopyInto(out *KubeadmConfigTemplateResource) <span class="cov0" title="0">{
*out = *in
in.Spec.DeepCopyInto(&amp;out.Spec)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigTemplateResource.
func (in *KubeadmConfigTemplateResource) DeepCopy() *KubeadmConfigTemplateResource <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigTemplateResource)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeadmConfigTemplateSpec) DeepCopyInto(out *KubeadmConfigTemplateSpec) <span class="cov0" title="0">{
*out = *in
in.Template.DeepCopyInto(&amp;out.Template)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeadmConfigTemplateSpec.
func (in *KubeadmConfigTemplateSpec) DeepCopy() *KubeadmConfigTemplateSpec <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(KubeadmConfigTemplateSpec)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in MountPoints) DeepCopyInto(out *MountPoints) <span class="cov0" title="0">{
</span><span class="cov0" title="0">{
in := &amp;in
*out = make(MountPoints, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MountPoints.
func (in MountPoints) DeepCopy() MountPoints <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(MountPoints)
in.DeepCopyInto(out)
return *out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NTP) DeepCopyInto(out *NTP) <span class="cov0" title="0">{
*out = *in
if in.Servers != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Servers, &amp;out.Servers
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.Enabled != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Enabled, &amp;out.Enabled
*out = new(bool)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NTP.
func (in *NTP) DeepCopy() *NTP <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(NTP)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Partition) DeepCopyInto(out *Partition) <span class="cov0" title="0">{
*out = *in
if in.Overwrite != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Overwrite, &amp;out.Overwrite
*out = new(bool)
**out = **in
}</span>
<span class="cov0" title="0">if in.TableType != nil </span><span class="cov0" title="0">{
in, out := &amp;in.TableType, &amp;out.TableType
*out = new(string)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Partition.
func (in *Partition) DeepCopy() *Partition <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Partition)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretFileSource) DeepCopyInto(out *SecretFileSource) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretFileSource.
func (in *SecretFileSource) DeepCopy() *SecretFileSource <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(SecretFileSource)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *User) DeepCopyInto(out *User) <span class="cov0" title="0">{
*out = *in
if in.Gecos != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Gecos, &amp;out.Gecos
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.Groups != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Groups, &amp;out.Groups
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.HomeDir != nil </span><span class="cov0" title="0">{
in, out := &amp;in.HomeDir, &amp;out.HomeDir
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.Inactive != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Inactive, &amp;out.Inactive
*out = new(bool)
**out = **in
}</span>
<span class="cov0" title="0">if in.Shell != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Shell, &amp;out.Shell
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.Passwd != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Passwd, &amp;out.Passwd
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.PrimaryGroup != nil </span><span class="cov0" title="0">{
in, out := &amp;in.PrimaryGroup, &amp;out.PrimaryGroup
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.LockPassword != nil </span><span class="cov0" title="0">{
in, out := &amp;in.LockPassword, &amp;out.LockPassword
*out = new(bool)
**out = **in
}</span>
<span class="cov0" title="0">if in.Sudo != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Sudo, &amp;out.Sudo
*out = new(string)
**out = **in
}</span>
<span class="cov0" title="0">if in.SSHAuthorizedKeys != nil </span><span class="cov0" title="0">{
in, out := &amp;in.SSHAuthorizedKeys, &amp;out.SSHAuthorizedKeys
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User.
func (in *User) DeepCopy() *User <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(User)
in.DeepCopyInto(out)
return out</span>
}
</pre>
<pre class="file" id="file41" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 controllers
import (
"context"
"fmt"
"strconv"
"time"
"github.com/go-logr/logr"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
kerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/utils/pointer"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3"
"sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/cloudinit"
"sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/locking"
kubeadmv1beta1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1"
bsutil "sigs.k8s.io/cluster-api/bootstrap/util"
"sigs.k8s.io/cluster-api/controllers/remote"
capierrors "sigs.k8s.io/cluster-api/errors"
expv1 "sigs.k8s.io/cluster-api/exp/api/v1alpha3"
"sigs.k8s.io/cluster-api/feature"
"sigs.k8s.io/cluster-api/util"
"sigs.k8s.io/cluster-api/util/annotations"
"sigs.k8s.io/cluster-api/util/conditions"
"sigs.k8s.io/cluster-api/util/patch"
"sigs.k8s.io/cluster-api/util/predicates"
"sigs.k8s.io/cluster-api/util/secret"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/source"
)
// InitLocker is a lock that is used around kubeadm init
type InitLocker interface {
Lock(ctx context.Context, cluster *clusterv1.Cluster, machine *clusterv1.Machine) bool
Unlock(ctx context.Context, cluster *clusterv1.Cluster) bool
}
// +kubebuilder:rbac:groups=bootstrap.cluster.x-k8s.io,resources=kubeadmconfigs;kubeadmconfigs/status,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status;machines;machines/status,verbs=get;list;watch
// +kubebuilder:rbac:groups=exp.cluster.x-k8s.io,resources=machinepools;machinepools/status,verbs=get;list;watch
// +kubebuilder:rbac:groups="",resources=secrets;events;configmaps,verbs=get;list;watch;create;update;patch;delete
// KubeadmConfigReconciler reconciles a KubeadmConfig object
type KubeadmConfigReconciler struct {
Client client.Client
Log logr.Logger
KubeadmInitLock InitLocker
scheme *runtime.Scheme
remoteClientGetter remote.ClusterClientGetter
}
type Scope struct {
logr.Logger
Config *bootstrapv1.KubeadmConfig
ConfigOwner *bsutil.ConfigOwner
Cluster *clusterv1.Cluster
}
// SetupWithManager sets up the reconciler with the Manager.
func (r *KubeadmConfigReconciler) SetupWithManager(mgr ctrl.Manager, option controller.Options) error <span class="cov0" title="0">{
if r.KubeadmInitLock == nil </span><span class="cov0" title="0">{
r.KubeadmInitLock = locking.NewControlPlaneInitMutex(ctrl.Log.WithName("init-locker"), mgr.GetClient())
}</span>
<span class="cov0" title="0">if r.remoteClientGetter == nil </span><span class="cov0" title="0">{
r.remoteClientGetter = remote.NewClusterClient
}</span>
<span class="cov0" title="0">r.scheme = mgr.GetScheme()
b := ctrl.NewControllerManagedBy(mgr).
For(&amp;bootstrapv1.KubeadmConfig{}).
WithOptions(option).
WithEventFilter(predicates.ResourceNotPaused(r.Log)).
Watches(
&amp;source.Kind{Type: &amp;clusterv1.Machine{}},
&amp;handler.EnqueueRequestsFromMapFunc{
ToRequests: handler.ToRequestsFunc(r.MachineToBootstrapMapFunc),
},
)
if feature.Gates.Enabled(feature.MachinePool) </span><span class="cov0" title="0">{
b = b.Watches(
&amp;source.Kind{Type: &amp;expv1.MachinePool{}},
&amp;handler.EnqueueRequestsFromMapFunc{
ToRequests: handler.ToRequestsFunc(r.MachinePoolToBootstrapMapFunc),
},
)
}</span>
<span class="cov0" title="0">c, err := b.Build(r)
if err != nil </span><span class="cov0" title="0">{
return errors.Wrap(err, "failed setting up with a controller manager")
}</span>
<span class="cov0" title="0">err = c.Watch(
&amp;source.Kind{Type: &amp;clusterv1.Cluster{}},
&amp;handler.EnqueueRequestsFromMapFunc{
ToRequests: handler.ToRequestsFunc(r.ClusterToKubeadmConfigs),
},
predicates.ClusterUnpausedAndInfrastructureReady(r.Log),
)
if err != nil </span><span class="cov0" title="0">{
return errors.Wrap(err, "failed adding Watch for Clusters to controller manager")
}</span>
<span class="cov0" title="0">return nil</span>
}
// Reconcile handles KubeadmConfig events.
func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, rerr error) <span class="cov8" title="1">{
ctx := context.Background()
log := r.Log.WithValues("kubeadmconfig", req.NamespacedName)
// Lookup the kubeadm config
config := &amp;bootstrapv1.KubeadmConfig{}
if err := r.Client.Get(ctx, req.NamespacedName, config); err != nil </span><span class="cov8" title="1">{
if apierrors.IsNotFound(err) </span><span class="cov8" title="1">{
return ctrl.Result{}, nil
}</span>
<span class="cov0" title="0">log.Error(err, "Failed to get config")
return ctrl.Result{}, err</span>
}
// Look up the owner of this KubeConfig if there is one
<span class="cov8" title="1">configOwner, err := bsutil.GetConfigOwner(ctx, r.Client, config)
if apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
// Could not find the owner yet, this is not an error and will rereconcile when the owner gets set.
return ctrl.Result{}, nil
}</span>
<span class="cov8" title="1">if err != nil </span><span class="cov8" title="1">{
log.Error(err, "Failed to get owner")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">if configOwner == nil </span><span class="cov0" title="0">{
return ctrl.Result{}, nil
}</span>
<span class="cov8" title="1">log = log.WithValues("kind", configOwner.GetKind(), "version", configOwner.GetResourceVersion(), "name", configOwner.GetName())
// Lookup the cluster the config owner is associated with
cluster, err := util.GetClusterByName(ctx, r.Client, configOwner.GetNamespace(), configOwner.ClusterName())
if err != nil </span><span class="cov8" title="1">{
if errors.Cause(err) == util.ErrNoCluster </span><span class="cov0" title="0">{
log.Info(fmt.Sprintf("%s does not belong to a cluster yet, waiting until it's part of a cluster", configOwner.GetKind()))
return ctrl.Result{}, nil
}</span>
<span class="cov8" title="1">if apierrors.IsNotFound(err) </span><span class="cov8" title="1">{
log.Info("Cluster does not exist yet, waiting until it is created")
return ctrl.Result{}, nil
}</span>
<span class="cov0" title="0">log.Error(err, "Could not get cluster with metadata")
return ctrl.Result{}, err</span>
}
<span class="cov8" title="1">if annotations.IsPaused(cluster, config) </span><span class="cov0" title="0">{
log.Info("Reconciliation is paused for this object")
return ctrl.Result{}, nil
}</span>
<span class="cov8" title="1">scope := &amp;Scope{
Logger: log,
Config: config,
ConfigOwner: configOwner,
Cluster: cluster,
}
// Initialize the patch helper.
patchHelper, err := patch.NewHelper(config, r.Client)
if err != nil </span><span class="cov0" title="0">{
return ctrl.Result{}, err
}</span>
// Attempt to Patch the KubeadmConfig object and status after each reconciliation if no error occurs.
<span class="cov8" title="1">defer func() </span><span class="cov8" title="1">{
// always update the readyCondition; the summary is represented using the "1 of x completed" notation.
conditions.SetSummary(config,
conditions.WithConditions(
bootstrapv1.DataSecretAvailableCondition,
bootstrapv1.CertificatesAvailableCondition,
),
conditions.WithStepCounter(),
)
// Patch ObservedGeneration only if the reconciliation completed successfully
patchOpts := []patch.Option{}
if rerr == nil </span><span class="cov8" title="1">{
patchOpts = append(patchOpts, patch.WithStatusObservedGeneration{})
}</span>
<span class="cov8" title="1">if err := patchHelper.Patch(ctx, config, patchOpts...); err != nil </span><span class="cov0" title="0">{
log.Error(rerr, "Failed to patch config")
if rerr == nil </span><span class="cov0" title="0">{
rerr = err
}</span>
}
}()
<span class="cov8" title="1">switch </span>{
// Wait for the infrastructure to be ready.
case !cluster.Status.InfrastructureReady:<span class="cov8" title="1">
log.Info("Cluster infrastructure is not ready, waiting")
conditions.MarkFalse(config, bootstrapv1.DataSecretAvailableCondition, bootstrapv1.WaitingForClusterInfrastructureReason, clusterv1.ConditionSeverityInfo, "")
return ctrl.Result{}, nil</span>
// Migrate plaintext data to secret.
case config.Status.BootstrapData != nil &amp;&amp; config.Status.DataSecretName == nil:<span class="cov8" title="1">
if err := r.storeBootstrapData(ctx, scope, config.Status.BootstrapData); err != nil </span><span class="cov0" title="0">{
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">return ctrl.Result{}, nil</span>
// Reconcile status for machines that already have a secret reference, but our status isn't up to date.
// This case solves the pivoting scenario (or a backup restore) which doesn't preserve the status subresource on objects.
case configOwner.DataSecretName() != nil &amp;&amp; (!config.Status.Ready || config.Status.DataSecretName == nil):<span class="cov0" title="0">
config.Status.Ready = true
config.Status.DataSecretName = configOwner.DataSecretName()
conditions.MarkTrue(config, bootstrapv1.DataSecretAvailableCondition)
return ctrl.Result{}, nil</span>
// Status is ready means a config has been generated.
case config.Status.Ready:<span class="cov8" title="1">
// If the BootstrapToken has been generated for a join and the infrastructure is not ready.
// This indicates the token in the join config has not been consumed and it may need a refresh.
if (config.Spec.JoinConfiguration != nil &amp;&amp; config.Spec.JoinConfiguration.Discovery.BootstrapToken != nil) &amp;&amp; !configOwner.IsInfrastructureReady() </span><span class="cov8" title="1">{
token := config.Spec.JoinConfiguration.Discovery.BootstrapToken.Token
remoteClient, err := r.remoteClientGetter(ctx, r.Client, util.ObjectKey(cluster), r.scheme)
if err != nil </span><span class="cov0" title="0">{
log.Error(err, "Error creating remote cluster client")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">log.Info("Refreshing token until the infrastructure has a chance to consume it")
err = refreshToken(remoteClient, token)
if err != nil </span><span class="cov0" title="0">{
// It would be nice to re-create the bootstrap token if the error was "not found", but we have no way to update the Machine's bootstrap data
return ctrl.Result{}, errors.Wrapf(err, "failed to refresh bootstrap token")
}</span>
// NB: this may not be sufficient to keep the token live if we don't see it before it expires, but when we generate a config we will set the status to "ready" which should generate an update event
<span class="cov8" title="1">return ctrl.Result{
RequeueAfter: DefaultTokenTTL / 2,
}, nil</span>
}
// In any other case just return as the config is already generated and need not be generated again.
<span class="cov8" title="1">return ctrl.Result{}, nil</span>
}
<span class="cov8" title="1">if !cluster.Status.ControlPlaneInitialized </span><span class="cov8" title="1">{
return r.handleClusterNotInitialized(ctx, scope)
}</span>
// Every other case it's a join scenario
// Nb. in this case ClusterConfiguration and InitConfiguration should not be defined by users, but in case of misconfigurations, CABPK simply ignore them
// Unlock any locks that might have been set during init process
<span class="cov8" title="1">r.KubeadmInitLock.Unlock(ctx, cluster)
// if the JoinConfiguration is missing, create a default one
if config.Spec.JoinConfiguration == nil </span><span class="cov8" title="1">{
log.Info("Creating default JoinConfiguration")
config.Spec.JoinConfiguration = &amp;kubeadmv1beta1.JoinConfiguration{}
}</span>
// it's a control plane join
<span class="cov8" title="1">if configOwner.IsControlPlaneMachine() </span><span class="cov8" title="1">{
return r.joinControlplane(ctx, scope)
}</span>
// It's a worker join
<span class="cov8" title="1">return r.joinWorker(ctx, scope)</span>
}
func (r *KubeadmConfigReconciler) handleClusterNotInitialized(ctx context.Context, scope *Scope) (_ ctrl.Result, reterr error) <span class="cov8" title="1">{
// initialize the DataSecretAvailableCondition if missing.
// this is required in order to avoid the condition's LastTransitionTime to flicker in case of errors surfacing
// using the DataSecretGeneratedFailedReason
if conditions.GetReason(scope.Config, bootstrapv1.DataSecretAvailableCondition) != bootstrapv1.DataSecretGenerationFailedReason </span><span class="cov8" title="1">{
conditions.MarkFalse(scope.Config, bootstrapv1.DataSecretAvailableCondition, bootstrapv1.WaitingForControlPlaneAvailableReason, clusterv1.ConditionSeverityInfo, "")
}</span>
// if it's NOT a control plane machine, requeue
<span class="cov8" title="1">if !scope.ConfigOwner.IsControlPlaneMachine() </span><span class="cov8" title="1">{
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}</span>
// if the machine has not ClusterConfiguration and InitConfiguration, requeue
<span class="cov8" title="1">if scope.Config.Spec.InitConfiguration == nil &amp;&amp; scope.Config.Spec.ClusterConfiguration == nil </span><span class="cov8" title="1">{
scope.Info("Control plane is not ready, requeing joining control planes until ready.")
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}</span>
<span class="cov8" title="1">machine := &amp;clusterv1.Machine{}
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(scope.ConfigOwner.Object, machine); err != nil </span><span class="cov0" title="0">{
return ctrl.Result{}, errors.Wrapf(err, "cannot convert %s to Machine", scope.ConfigOwner.GetKind())
}</span>
// acquire the init lock so that only the first machine configured
// as control plane get processed here
// if not the first, requeue
<span class="cov8" title="1">if !r.KubeadmInitLock.Lock(ctx, scope.Cluster, machine) </span><span class="cov8" title="1">{
scope.Info("A control plane is already being initialized, requeing until control plane is ready")
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}</span>
<span class="cov8" title="1">defer func() </span><span class="cov8" title="1">{
if reterr != nil </span><span class="cov8" title="1">{
if !r.KubeadmInitLock.Unlock(ctx, scope.Cluster) </span><span class="cov0" title="0">{
reterr = kerrors.NewAggregate([]error{reterr, errors.New("failed to unlock the kubeadm init lock")})
}</span>
}
}()
<span class="cov8" title="1">scope.Info("Creating BootstrapData for the init control plane")
// Nb. in this case JoinConfiguration should not be defined by users, but in case of misconfigurations, CABPK simply ignore it
// get both of ClusterConfiguration and InitConfiguration strings to pass to the cloud init control plane generator
// kubeadm allows one of these values to be empty; CABPK replace missing values with an empty config, so the cloud init generation
// should not handle special cases.
if scope.Config.Spec.InitConfiguration == nil </span><span class="cov8" title="1">{
scope.Config.Spec.InitConfiguration = &amp;kubeadmv1beta1.InitConfiguration{
TypeMeta: metav1.TypeMeta{
APIVersion: "kubeadm.k8s.io/v1beta1",
Kind: "InitConfiguration",
},
}
}</span>
<span class="cov8" title="1">initdata, err := kubeadmv1beta1.ConfigurationToYAML(scope.Config.Spec.InitConfiguration)
if err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to marshal init configuration")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">if scope.Config.Spec.ClusterConfiguration == nil </span><span class="cov0" title="0">{
scope.Config.Spec.ClusterConfiguration = &amp;kubeadmv1beta1.ClusterConfiguration{
TypeMeta: metav1.TypeMeta{
APIVersion: "kubeadm.k8s.io/v1beta1",
Kind: "ClusterConfiguration",
},
}
}</span>
// injects into config.ClusterConfiguration values from top level object
<span class="cov8" title="1">r.reconcileTopLevelObjectSettings(scope.Cluster, machine, scope.Config)
clusterdata, err := kubeadmv1beta1.ConfigurationToYAML(scope.Config.Spec.ClusterConfiguration)
if err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to marshal cluster configuration")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">certificates := secret.NewCertificatesForInitialControlPlane(scope.Config.Spec.ClusterConfiguration)
err = certificates.LookupOrGenerate(
ctx,
r.Client,
util.ObjectKey(scope.Cluster),
*metav1.NewControllerRef(scope.Config, bootstrapv1.GroupVersion.WithKind("KubeadmConfig")),
)
if err != nil </span><span class="cov8" title="1">{
conditions.MarkFalse(scope.Config, bootstrapv1.CertificatesAvailableCondition, bootstrapv1.CertificatesGenerationFailedReason, clusterv1.ConditionSeverityWarning, err.Error())
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">conditions.MarkTrue(scope.Config, bootstrapv1.CertificatesAvailableCondition)
verbosityFlag := ""
if scope.Config.Spec.Verbosity != nil </span><span class="cov0" title="0">{
verbosityFlag = fmt.Sprintf("--v %s", strconv.Itoa(int(*scope.Config.Spec.Verbosity)))
}</span>
<span class="cov8" title="1">files, err := r.resolveFiles(ctx, scope.Config, certificates.AsFiles()...)
if err != nil </span><span class="cov0" title="0">{
conditions.MarkFalse(scope.Config, bootstrapv1.DataSecretAvailableCondition, bootstrapv1.DataSecretGenerationFailedReason, clusterv1.ConditionSeverityWarning, err.Error())
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">cloudInitData, err := cloudinit.NewInitControlPlane(&amp;cloudinit.ControlPlaneInput{
BaseUserData: cloudinit.BaseUserData{
AdditionalFiles: files,
NTP: scope.Config.Spec.NTP,
PreKubeadmCommands: scope.Config.Spec.PreKubeadmCommands,
PostKubeadmCommands: scope.Config.Spec.PostKubeadmCommands,
Users: scope.Config.Spec.Users,
Mounts: scope.Config.Spec.Mounts,
DiskSetup: scope.Config.Spec.DiskSetup,
KubeadmVerbosity: verbosityFlag,
},
InitConfiguration: initdata,
ClusterConfiguration: clusterdata,
Certificates: certificates,
})
if err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to generate cloud init for bootstrap control plane")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">if err := r.storeBootstrapData(ctx, scope, cloudInitData); err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to store bootstrap data")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">return ctrl.Result{}, nil</span>
}
func (r *KubeadmConfigReconciler) joinWorker(ctx context.Context, scope *Scope) (ctrl.Result, error) <span class="cov8" title="1">{
certificates := secret.NewCertificatesForWorker(scope.Config.Spec.JoinConfiguration.CACertPath)
err := certificates.Lookup(
ctx,
r.Client,
util.ObjectKey(scope.Cluster),
)
if err != nil </span><span class="cov0" title="0">{
conditions.MarkFalse(scope.Config, bootstrapv1.CertificatesAvailableCondition, bootstrapv1.CertificatesCorruptedReason, clusterv1.ConditionSeverityError, err.Error())
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">if err := certificates.EnsureAllExist(); err != nil </span><span class="cov0" title="0">{
conditions.MarkFalse(scope.Config, bootstrapv1.CertificatesAvailableCondition, bootstrapv1.CertificatesCorruptedReason, clusterv1.ConditionSeverityError, err.Error())
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">conditions.MarkTrue(scope.Config, bootstrapv1.CertificatesAvailableCondition)
// ensure that joinConfiguration.Discovery is properly set for joining node on the current cluster
if err := r.reconcileDiscovery(ctx, scope.Cluster, scope.Config, certificates); err != nil </span><span class="cov8" title="1">{
if requeueErr, ok := errors.Cause(err).(capierrors.HasRequeueAfterError); ok </span><span class="cov8" title="1">{
scope.Info(err.Error())
return ctrl.Result{RequeueAfter: requeueErr.GetRequeueAfter()}, nil
}</span>
<span class="cov0" title="0">return ctrl.Result{}, err</span>
}
<span class="cov8" title="1">joinData, err := kubeadmv1beta1.ConfigurationToYAML(scope.Config.Spec.JoinConfiguration)
if err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to marshal join configuration")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">if scope.Config.Spec.JoinConfiguration.ControlPlane != nil </span><span class="cov0" title="0">{
return ctrl.Result{}, errors.New("Machine is a Worker, but JoinConfiguration.ControlPlane is set in the KubeadmConfig object")
}</span>
<span class="cov8" title="1">scope.Info("Creating BootstrapData for the worker node")
verbosityFlag := ""
if scope.Config.Spec.Verbosity != nil </span><span class="cov0" title="0">{
verbosityFlag = fmt.Sprintf("--v %s", strconv.Itoa(int(*scope.Config.Spec.Verbosity)))
}</span>
<span class="cov8" title="1">files, err := r.resolveFiles(ctx, scope.Config)
if err != nil </span><span class="cov0" title="0">{
conditions.MarkFalse(scope.Config, bootstrapv1.DataSecretAvailableCondition, bootstrapv1.DataSecretGenerationFailedReason, clusterv1.ConditionSeverityWarning, err.Error())
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">cloudJoinData, err := cloudinit.NewNode(&amp;cloudinit.NodeInput{
BaseUserData: cloudinit.BaseUserData{
AdditionalFiles: files,
NTP: scope.Config.Spec.NTP,
PreKubeadmCommands: scope.Config.Spec.PreKubeadmCommands,
PostKubeadmCommands: scope.Config.Spec.PostKubeadmCommands,
Users: scope.Config.Spec.Users,
Mounts: scope.Config.Spec.Mounts,
DiskSetup: scope.Config.Spec.DiskSetup,
KubeadmVerbosity: verbosityFlag,
UseExperimentalRetry: scope.Config.Spec.UseExperimentalRetryJoin,
},
JoinConfiguration: joinData,
})
if err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to create a worker join configuration")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">if err := r.storeBootstrapData(ctx, scope, cloudJoinData); err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to store bootstrap data")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">return ctrl.Result{}, nil</span>
}
func (r *KubeadmConfigReconciler) joinControlplane(ctx context.Context, scope *Scope) (ctrl.Result, error) <span class="cov8" title="1">{
if !scope.ConfigOwner.IsControlPlaneMachine() </span><span class="cov0" title="0">{
return ctrl.Result{}, fmt.Errorf("%s is not a valid control plane kind, only Machine is supported", scope.ConfigOwner.GetKind())
}</span>
<span class="cov8" title="1">if scope.Config.Spec.JoinConfiguration.ControlPlane == nil </span><span class="cov8" title="1">{
scope.Config.Spec.JoinConfiguration.ControlPlane = &amp;kubeadmv1beta1.JoinControlPlane{}
}</span>
<span class="cov8" title="1">certificates := secret.NewCertificatesForJoiningControlPlane()
err := certificates.Lookup(
ctx,
r.Client,
util.ObjectKey(scope.Cluster),
)
if err != nil </span><span class="cov0" title="0">{
conditions.MarkFalse(scope.Config, bootstrapv1.CertificatesAvailableCondition, bootstrapv1.CertificatesCorruptedReason, clusterv1.ConditionSeverityError, err.Error())
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">if err := certificates.EnsureAllExist(); err != nil </span><span class="cov0" title="0">{
conditions.MarkFalse(scope.Config, bootstrapv1.CertificatesAvailableCondition, bootstrapv1.CertificatesCorruptedReason, clusterv1.ConditionSeverityError, err.Error())
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">conditions.MarkTrue(scope.Config, bootstrapv1.CertificatesAvailableCondition)
// ensure that joinConfiguration.Discovery is properly set for joining node on the current cluster
if err := r.reconcileDiscovery(ctx, scope.Cluster, scope.Config, certificates); err != nil </span><span class="cov0" title="0">{
if requeueErr, ok := errors.Cause(err).(capierrors.HasRequeueAfterError); ok </span><span class="cov0" title="0">{
scope.Info(err.Error())
return ctrl.Result{RequeueAfter: requeueErr.GetRequeueAfter()}, nil
}</span>
<span class="cov0" title="0">return ctrl.Result{}, err</span>
}
<span class="cov8" title="1">joinData, err := kubeadmv1beta1.ConfigurationToYAML(scope.Config.Spec.JoinConfiguration)
if err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to marshal join configuration")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">scope.Info("Creating BootstrapData for the join control plane")
verbosityFlag := ""
if scope.Config.Spec.Verbosity != nil </span><span class="cov0" title="0">{
verbosityFlag = fmt.Sprintf("--v %s", strconv.Itoa(int(*scope.Config.Spec.Verbosity)))
}</span>
<span class="cov8" title="1">files, err := r.resolveFiles(ctx, scope.Config, certificates.AsFiles()...)
if err != nil </span><span class="cov0" title="0">{
conditions.MarkFalse(scope.Config, bootstrapv1.DataSecretAvailableCondition, bootstrapv1.DataSecretGenerationFailedReason, clusterv1.ConditionSeverityWarning, err.Error())
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">cloudJoinData, err := cloudinit.NewJoinControlPlane(&amp;cloudinit.ControlPlaneJoinInput{
JoinConfiguration: joinData,
Certificates: certificates,
BaseUserData: cloudinit.BaseUserData{
AdditionalFiles: files,
NTP: scope.Config.Spec.NTP,
PreKubeadmCommands: scope.Config.Spec.PreKubeadmCommands,
PostKubeadmCommands: scope.Config.Spec.PostKubeadmCommands,
Users: scope.Config.Spec.Users,
Mounts: scope.Config.Spec.Mounts,
DiskSetup: scope.Config.Spec.DiskSetup,
KubeadmVerbosity: verbosityFlag,
UseExperimentalRetry: scope.Config.Spec.UseExperimentalRetryJoin,
},
})
if err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to create a control plane join configuration")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">if err := r.storeBootstrapData(ctx, scope, cloudJoinData); err != nil </span><span class="cov0" title="0">{
scope.Error(err, "Failed to store bootstrap data")
return ctrl.Result{}, err
}</span>
<span class="cov8" title="1">return ctrl.Result{}, nil</span>
}
// resolveFiles maps .Spec.Files into cloudinit.Files, resolving any object references
// along the way.
func (r *KubeadmConfigReconciler) resolveFiles(ctx context.Context, cfg *bootstrapv1.KubeadmConfig, merge ...bootstrapv1.File) ([]bootstrapv1.File, error) <span class="cov8" title="1">{
collected := append(cfg.Spec.Files, merge...)
for i := range collected </span><span class="cov8" title="1">{
in := collected[i]
if in.ContentFrom != nil </span><span class="cov0" title="0">{
data, err := r.resolveSecretFileContent(ctx, cfg.Namespace, in)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to resolve file source")
}</span>
<span class="cov0" title="0">in.ContentFrom = nil
in.Content = string(data)
collected[i] = in</span>
}
}
<span class="cov8" title="1">return collected, nil</span>
}
// resolveSecretFileContent returns file content fetched from a referenced secret object.
func (r *KubeadmConfigReconciler) resolveSecretFileContent(ctx context.Context, ns string, source bootstrapv1.File) ([]byte, error) <span class="cov0" title="0">{
secret := &amp;corev1.Secret{}
key := types.NamespacedName{Namespace: ns, Name: source.ContentFrom.Secret.Name}
if err := r.Client.Get(ctx, key, secret); err != nil </span><span class="cov0" title="0">{
if apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "secret not found: %s", key)
}</span>
<span class="cov0" title="0">return nil, errors.Wrapf(err, "failed to retrieve Secret %q", key)</span>
}
<span class="cov0" title="0">data, ok := secret.Data[source.ContentFrom.Secret.Key]
if !ok </span><span class="cov0" title="0">{
return nil, errors.Errorf("secret references non-existent secret key: %q", source.ContentFrom.Secret.Key)
}</span>
<span class="cov0" title="0">return data, nil</span>
}
// ClusterToKubeadmConfigs is a handler.ToRequestsFunc to be used to enqeue
// requests for reconciliation of KubeadmConfigs.
func (r *KubeadmConfigReconciler) ClusterToKubeadmConfigs(o handler.MapObject) []ctrl.Request <span class="cov8" title="1">{
result := []ctrl.Request{}
c, ok := o.Object.(*clusterv1.Cluster)
if !ok </span><span class="cov0" title="0">{
r.Log.Error(errors.Errorf("expected a Cluster but got a %T", o.Object), "failed to get Machine for Cluster")
return nil
}</span>
<span class="cov8" title="1">selectors := []client.ListOption{
client.InNamespace(c.Namespace),
client.MatchingLabels{
clusterv1.ClusterLabelName: c.Name,
},
}
machineList := &amp;clusterv1.MachineList{}
if err := r.Client.List(context.Background(), machineList, selectors...); err != nil </span><span class="cov0" title="0">{
r.Log.Error(err, "failed to list Machines", "Cluster", c.Name, "Namespace", c.Namespace)
return nil
}</span>
<span class="cov8" title="1">for _, m := range machineList.Items </span><span class="cov8" title="1">{
if m.Spec.Bootstrap.ConfigRef != nil &amp;&amp;
m.Spec.Bootstrap.ConfigRef.GroupVersionKind().GroupKind() == bootstrapv1.GroupVersion.WithKind("KubeadmConfig").GroupKind() </span><span class="cov8" title="1">{
name := client.ObjectKey{Namespace: m.Namespace, Name: m.Spec.Bootstrap.ConfigRef.Name}
result = append(result, ctrl.Request{NamespacedName: name})
}</span>
}
<span class="cov8" title="1">return result</span>
}
// MachineToBootstrapMapFunc is a handler.ToRequestsFunc to be used to enqeue
// request for reconciliation of KubeadmConfig.
func (r *KubeadmConfigReconciler) MachineToBootstrapMapFunc(o handler.MapObject) []ctrl.Request <span class="cov8" title="1">{
result := []ctrl.Request{}
m, ok := o.Object.(*clusterv1.Machine)
if !ok </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov8" title="1">if m.Spec.Bootstrap.ConfigRef != nil &amp;&amp; m.Spec.Bootstrap.ConfigRef.GroupVersionKind() == bootstrapv1.GroupVersion.WithKind("KubeadmConfig") </span><span class="cov8" title="1">{
name := client.ObjectKey{Namespace: m.Namespace, Name: m.Spec.Bootstrap.ConfigRef.Name}
result = append(result, ctrl.Request{NamespacedName: name})
}</span>
<span class="cov8" title="1">return result</span>
}
// MachinePoolToBootstrapMapFunc is a handler.ToRequestsFunc to be used to enqueue
// request for reconciliation of KubeadmConfig.
func (r *KubeadmConfigReconciler) MachinePoolToBootstrapMapFunc(o handler.MapObject) []ctrl.Request <span class="cov0" title="0">{
result := []ctrl.Request{}
m, ok := o.Object.(*expv1.MachinePool)
if !ok </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">configRef := m.Spec.Template.Spec.Bootstrap.ConfigRef
if configRef != nil &amp;&amp; configRef.GroupVersionKind().GroupKind() == bootstrapv1.GroupVersion.WithKind("KubeadmConfig").GroupKind() </span><span class="cov0" title="0">{
name := client.ObjectKey{Namespace: m.Namespace, Name: configRef.Name}
result = append(result, ctrl.Request{NamespacedName: name})
}</span>
<span class="cov0" title="0">return result</span>
}
// reconcileDiscovery ensures that config.JoinConfiguration.Discovery is properly set for the joining node.
// The implementation func respect user provided discovery configurations, but in case some of them are missing, a valid BootstrapToken object
// is automatically injected into config.JoinConfiguration.Discovery.
// This allows to simplify configuration UX, by providing the option to delegate to CABPK the configuration of kubeadm join discovery.
func (r *KubeadmConfigReconciler) reconcileDiscovery(ctx context.Context, cluster *clusterv1.Cluster, config *bootstrapv1.KubeadmConfig, certificates secret.Certificates) error <span class="cov8" title="1">{
log := r.Log.WithValues("kubeadmconfig", fmt.Sprintf("%s/%s", config.Namespace, config.Name))
// if config already contains a file discovery configuration, respect it without further validations
if config.Spec.JoinConfiguration.Discovery.File != nil </span><span class="cov8" title="1">{
return nil
}</span>
// otherwise it is necessary to ensure token discovery is properly configured
<span class="cov8" title="1">if config.Spec.JoinConfiguration.Discovery.BootstrapToken == nil </span><span class="cov8" title="1">{
config.Spec.JoinConfiguration.Discovery.BootstrapToken = &amp;kubeadmv1beta1.BootstrapTokenDiscovery{}
}</span>
// calculate the ca cert hashes if they are not already set
<span class="cov8" title="1">if len(config.Spec.JoinConfiguration.Discovery.BootstrapToken.CACertHashes) == 0 </span><span class="cov8" title="1">{
hashes, err := certificates.GetByPurpose(secret.ClusterCA).Hashes()
if err != nil </span><span class="cov0" title="0">{
log.Error(err, "Unable to generate Cluster CA certificate hashes")
return err
}</span>
<span class="cov8" title="1">config.Spec.JoinConfiguration.Discovery.BootstrapToken.CACertHashes = hashes</span>
}
// if BootstrapToken already contains an APIServerEndpoint, respect it; otherwise inject the APIServerEndpoint endpoint defined in cluster status
<span class="cov8" title="1">apiServerEndpoint := config.Spec.JoinConfiguration.Discovery.BootstrapToken.APIServerEndpoint
if apiServerEndpoint == "" </span><span class="cov8" title="1">{
if cluster.Spec.ControlPlaneEndpoint.IsZero() </span><span class="cov8" title="1">{
return errors.Wrap(&amp;capierrors.RequeueAfterError{RequeueAfter: 10 * time.Second}, "Waiting for Cluster Controller to set Cluster.Spec.ControlPlaneEndpoint")
}</span>
<span class="cov8" title="1">apiServerEndpoint = cluster.Spec.ControlPlaneEndpoint.String()
config.Spec.JoinConfiguration.Discovery.BootstrapToken.APIServerEndpoint = apiServerEndpoint
log.Info("Altering JoinConfiguration.Discovery.BootstrapToken", "APIServerEndpoint", apiServerEndpoint)</span>
}
// if BootstrapToken already contains a token, respect it; otherwise create a new bootstrap token for the node to join
<span class="cov8" title="1">if config.Spec.JoinConfiguration.Discovery.BootstrapToken.Token == "" </span><span class="cov8" title="1">{
remoteClient, err := r.remoteClientGetter(ctx, r.Client, util.ObjectKey(cluster), r.scheme)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">token, err := createToken(remoteClient)
if err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to create new bootstrap token")
}</span>
<span class="cov8" title="1">config.Spec.JoinConfiguration.Discovery.BootstrapToken.Token = token
log.Info("Altering JoinConfiguration.Discovery.BootstrapToken", "Token", token)</span>
}
// If the BootstrapToken does not contain any CACertHashes then force skip CA Verification
<span class="cov8" title="1">if len(config.Spec.JoinConfiguration.Discovery.BootstrapToken.CACertHashes) == 0 </span><span class="cov0" title="0">{
log.Info("No CAs were provided. Falling back to insecure discover method by skipping CA Cert validation")
config.Spec.JoinConfiguration.Discovery.BootstrapToken.UnsafeSkipCAVerification = true
}</span>
<span class="cov8" title="1">return nil</span>
}
// reconcileTopLevelObjectSettings injects into config.ClusterConfiguration values from top level objects like cluster and machine.
// The implementation func respect user provided config values, but in case some of them are missing, values from top level objects are used.
func (r *KubeadmConfigReconciler) reconcileTopLevelObjectSettings(cluster *clusterv1.Cluster, machine *clusterv1.Machine, config *bootstrapv1.KubeadmConfig) <span class="cov8" title="1">{
log := r.Log.WithValues("kubeadmconfig", fmt.Sprintf("%s/%s", config.Namespace, config.Name))
// If there is no ControlPlaneEndpoint defined in ClusterConfiguration but
// there is a ControlPlaneEndpoint defined at Cluster level (e.g. the load balancer endpoint),
// then use Cluster's ControlPlaneEndpoint as a control plane endpoint for the Kubernetes cluster.
if config.Spec.ClusterConfiguration.ControlPlaneEndpoint == "" &amp;&amp; !cluster.Spec.ControlPlaneEndpoint.IsZero() </span><span class="cov8" title="1">{
config.Spec.ClusterConfiguration.ControlPlaneEndpoint = cluster.Spec.ControlPlaneEndpoint.String()
log.Info("Altering ClusterConfiguration", "ControlPlaneEndpoint", config.Spec.ClusterConfiguration.ControlPlaneEndpoint)
}</span>
// If there are no ClusterName defined in ClusterConfiguration, use Cluster.Name
<span class="cov8" title="1">if config.Spec.ClusterConfiguration.ClusterName == "" </span><span class="cov8" title="1">{
config.Spec.ClusterConfiguration.ClusterName = cluster.Name
log.Info("Altering ClusterConfiguration", "ClusterName", config.Spec.ClusterConfiguration.ClusterName)
}</span>
// If there are no Network settings defined in ClusterConfiguration, use ClusterNetwork settings, if defined
<span class="cov8" title="1">if cluster.Spec.ClusterNetwork != nil </span><span class="cov8" title="1">{
if config.Spec.ClusterConfiguration.Networking.DNSDomain == "" &amp;&amp; cluster.Spec.ClusterNetwork.ServiceDomain != "" </span><span class="cov8" title="1">{
config.Spec.ClusterConfiguration.Networking.DNSDomain = cluster.Spec.ClusterNetwork.ServiceDomain
log.Info("Altering ClusterConfiguration", "DNSDomain", config.Spec.ClusterConfiguration.Networking.DNSDomain)
}</span>
<span class="cov8" title="1">if config.Spec.ClusterConfiguration.Networking.ServiceSubnet == "" &amp;&amp;
cluster.Spec.ClusterNetwork.Services != nil &amp;&amp;
len(cluster.Spec.ClusterNetwork.Services.CIDRBlocks) &gt; 0 </span><span class="cov8" title="1">{
config.Spec.ClusterConfiguration.Networking.ServiceSubnet = cluster.Spec.ClusterNetwork.Services.String()
log.Info("Altering ClusterConfiguration", "ServiceSubnet", config.Spec.ClusterConfiguration.Networking.ServiceSubnet)
}</span>
<span class="cov8" title="1">if config.Spec.ClusterConfiguration.Networking.PodSubnet == "" &amp;&amp;
cluster.Spec.ClusterNetwork.Pods != nil &amp;&amp;
len(cluster.Spec.ClusterNetwork.Pods.CIDRBlocks) &gt; 0 </span><span class="cov8" title="1">{
config.Spec.ClusterConfiguration.Networking.PodSubnet = cluster.Spec.ClusterNetwork.Pods.String()
log.Info("Altering ClusterConfiguration", "PodSubnet", config.Spec.ClusterConfiguration.Networking.PodSubnet)
}</span>
}
// If there are no KubernetesVersion settings defined in ClusterConfiguration, use Version from machine, if defined
<span class="cov8" title="1">if config.Spec.ClusterConfiguration.KubernetesVersion == "" &amp;&amp; machine.Spec.Version != nil </span><span class="cov8" title="1">{
config.Spec.ClusterConfiguration.KubernetesVersion = *machine.Spec.Version
log.Info("Altering ClusterConfiguration", "KubernetesVersion", config.Spec.ClusterConfiguration.KubernetesVersion)
}</span>
}
// storeBootstrapData creates a new secret with the data passed in as input,
// sets the reference in the configuration status and ready to true.
func (r *KubeadmConfigReconciler) storeBootstrapData(ctx context.Context, scope *Scope, data []byte) error <span class="cov8" title="1">{
secret := &amp;corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: scope.Config.Name,
Namespace: scope.Config.Namespace,
Labels: map[string]string{
clusterv1.ClusterLabelName: scope.Cluster.Name,
},
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: bootstrapv1.GroupVersion.String(),
Kind: "KubeadmConfig",
Name: scope.Config.Name,
UID: scope.Config.UID,
Controller: pointer.BoolPtr(true),
},
},
},
Data: map[string][]byte{
"value": data,
},
Type: clusterv1.ClusterSecretType,
}
// as secret creation and scope.Config status patch are not atomic operations
// it is possible that secret creation happens but the config.Status patches are not applied
if err := r.Client.Create(ctx, secret); err != nil </span><span class="cov8" title="1">{
if !apierrors.IsAlreadyExists(err) </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to create bootstrap data secret for KubeadmConfig %s/%s", scope.Config.Namespace, scope.Config.Name)
}</span>
<span class="cov8" title="1">r.Log.Info("bootstrap data secret for KubeadmConfig already exists", "secret", secret.Name, "KubeadmConfig", scope.Config.Name)</span>
}
<span class="cov8" title="1">scope.Config.Status.DataSecretName = pointer.StringPtr(secret.Name)
scope.Config.Status.Ready = true
conditions.MarkTrue(scope.Config, bootstrapv1.DataSecretAvailableCondition)
return nil</span>
}
</pre>
<pre class="file" id="file42" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 controllers
import (
"context"
"time"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
bootstraputil "k8s.io/cluster-bootstrap/token/util"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var (
// DefaultTokenTTL is the amount of time a bootstrap token (and therefore a KubeadmConfig) will be valid
DefaultTokenTTL = 15 * time.Minute
)
// createToken attempts to create a token with the given ID.
func createToken(c client.Client) (string, error) <span class="cov8" title="1">{
token, err := bootstraputil.GenerateBootstrapToken()
if err != nil </span><span class="cov0" title="0">{
return "", errors.Wrap(err, "unable to generate bootstrap token")
}</span>
<span class="cov8" title="1">substrs := bootstraputil.BootstrapTokenRegexp.FindStringSubmatch(token)
if len(substrs) != 3 </span><span class="cov0" title="0">{
return "", errors.Errorf("the bootstrap token %q was not of the form %q", token, bootstrapapi.BootstrapTokenPattern)
}</span>
<span class="cov8" title="1">tokenID := substrs[1]
tokenSecret := substrs[2]
secretName := bootstraputil.BootstrapTokenSecretName(tokenID)
secretToken := &amp;v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: metav1.NamespaceSystem,
},
Type: bootstrapapi.SecretTypeBootstrapToken,
Data: map[string][]byte{
bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
bootstrapapi.BootstrapTokenExpirationKey: []byte(time.Now().UTC().Add(DefaultTokenTTL).Format(time.RFC3339)),
bootstrapapi.BootstrapTokenUsageSigningKey: []byte("true"),
bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
bootstrapapi.BootstrapTokenExtraGroupsKey: []byte("system:bootstrappers:kubeadm:default-node-token"),
bootstrapapi.BootstrapTokenDescriptionKey: []byte("token generated by cluster-api-bootstrap-provider-kubeadm"),
},
}
if err = c.Create(context.TODO(), secretToken); err != nil </span><span class="cov0" title="0">{
return "", err
}</span>
<span class="cov8" title="1">return token, nil</span>
}
// refreshToken extends the TTL for an existing token
func refreshToken(c client.Client, token string) error <span class="cov8" title="1">{
substrs := bootstraputil.BootstrapTokenRegexp.FindStringSubmatch(token)
if len(substrs) != 3 </span><span class="cov0" title="0">{
return errors.Errorf("the bootstrap token %q was not of the form %q", token, bootstrapapi.BootstrapTokenPattern)
}</span>
<span class="cov8" title="1">tokenID := substrs[1]
secretName := bootstraputil.BootstrapTokenSecretName(tokenID)
secret := &amp;v1.Secret{}
if err := c.Get(context.TODO(), client.ObjectKey{Name: secretName, Namespace: metav1.NamespaceSystem}, secret); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if secret.Data == nil </span><span class="cov0" title="0">{
return errors.Errorf("Invalid bootstrap secret %q, remove the token from the kubadm config to re-create", secretName)
}</span>
<span class="cov8" title="1">secret.Data[bootstrapapi.BootstrapTokenExpirationKey] = []byte(time.Now().UTC().Add(DefaultTokenTTL).Format(time.RFC3339))
return c.Update(context.TODO(), secret)</span>
}
</pre>
<pre class="file" id="file43" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cloudinit
import (
"bytes"
"fmt"
"text/template"
"github.com/pkg/errors"
bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3"
)
const (
standardJoinCommand = "kubeadm join --config /tmp/kubeadm-join-config.yaml %s"
retriableJoinScriptName = "/usr/local/bin/kubeadm-bootstrap-script"
retriableJoinScriptOwner = "root"
retriableJoinScriptPermissions = "0755"
cloudConfigHeader = `## template: jinja
#cloud-config
`
)
// BaseUserData is shared across all the various types of files written to disk.
type BaseUserData struct {
Header string
PreKubeadmCommands []string
PostKubeadmCommands []string
AdditionalFiles []bootstrapv1.File
WriteFiles []bootstrapv1.File
Users []bootstrapv1.User
NTP *bootstrapv1.NTP
DiskSetup *bootstrapv1.DiskSetup
Mounts []bootstrapv1.MountPoints
ControlPlane bool
UseExperimentalRetry bool
KubeadmCommand string
KubeadmVerbosity string
}
func (input *BaseUserData) prepare() error <span class="cov0" title="0">{
input.Header = cloudConfigHeader
input.WriteFiles = append(input.WriteFiles, input.AdditionalFiles...)
input.KubeadmCommand = fmt.Sprintf(standardJoinCommand, input.KubeadmVerbosity)
if input.UseExperimentalRetry </span><span class="cov0" title="0">{
input.KubeadmCommand = retriableJoinScriptName
joinScriptFile, err := generateBootstrapScript(input)
if err != nil </span><span class="cov0" title="0">{
return errors.Wrap(err, "failed to generate user data for machine joining control plane")
}</span>
<span class="cov0" title="0">input.WriteFiles = append(input.WriteFiles, *joinScriptFile)</span>
}
<span class="cov0" title="0">return nil</span>
}
func generate(kind string, tpl string, data interface{}) ([]byte, error) <span class="cov8" title="1">{
tm := template.New(kind).Funcs(defaultTemplateFuncMap)
if _, err := tm.Parse(filesTemplate); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to parse files template")
}</span>
<span class="cov8" title="1">if _, err := tm.Parse(commandsTemplate); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to parse commands template")
}</span>
<span class="cov8" title="1">if _, err := tm.Parse(ntpTemplate); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to parse ntp template")
}</span>
<span class="cov8" title="1">if _, err := tm.Parse(usersTemplate); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to parse users template")
}</span>
<span class="cov8" title="1">if _, err := tm.Parse(diskSetupTemplate); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to parse users template")
}</span>
<span class="cov8" title="1">if _, err := tm.Parse(fsSetupTemplate); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to parse users template")
}</span>
<span class="cov8" title="1">if _, err := tm.Parse(mountsTemplate); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to parse users template")
}</span>
<span class="cov8" title="1">t, err := tm.Parse(tpl)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to parse %s template", kind)
}</span>
<span class="cov8" title="1">var out bytes.Buffer
if err := t.Execute(&amp;out, data); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to generate %s template", kind)
}</span>
<span class="cov8" title="1">return out.Bytes(), nil</span>
}
func generateBootstrapScript(input interface{}) (*bootstrapv1.File, error) <span class="cov0" title="0">{
scriptBytes, err := bootstrapKubeadmInternalCloudinitKubeadmBootstrapScriptShBytes()
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "couldn't read bootstrap script")
}</span>
<span class="cov0" title="0">joinScript, err := generate("JoinScript", string(scriptBytes), input)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to bootstrap script for machine joins")
}</span>
<span class="cov0" title="0">return &amp;bootstrapv1.File{
Path: retriableJoinScriptName,
Owner: retriableJoinScriptOwner,
Permissions: retriableJoinScriptPermissions,
Content: string(joinScript),
}, nil</span>
}
</pre>
<pre class="file" id="file44" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cloudinit
import (
"sigs.k8s.io/cluster-api/util/secret"
)
const (
controlPlaneCloudInit = `{{.Header}}
{{template "files" .WriteFiles}}
- path: /tmp/kubeadm.yaml
owner: root:root
permissions: '0640'
content: |
---
{{.ClusterConfiguration | Indent 6}}
---
{{.InitConfiguration | Indent 6}}
runcmd:
{{- template "commands" .PreKubeadmCommands }}
- 'kubeadm init --config /tmp/kubeadm.yaml {{.KubeadmVerbosity}}'
{{- template "commands" .PostKubeadmCommands }}
{{- template "ntp" .NTP }}
{{- template "users" .Users }}
{{- template "disk_setup" .DiskSetup}}
{{- template "fs_setup" .DiskSetup}}
{{- template "mounts" .Mounts}}
`
)
// ControlPlaneInput defines the context to generate a controlplane instance user data.
type ControlPlaneInput struct {
BaseUserData
secret.Certificates
ClusterConfiguration string
InitConfiguration string
}
// NewInitControlPlane returns the user data string to be used on a controlplane instance.
func NewInitControlPlane(input *ControlPlaneInput) ([]byte, error) <span class="cov8" title="1">{
input.Header = cloudConfigHeader
input.WriteFiles = input.Certificates.AsFiles()
input.WriteFiles = append(input.WriteFiles, input.AdditionalFiles...)
userData, err := generate("InitControlplane", controlPlaneCloudInit, input)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">return userData, nil</span>
}
</pre>
<pre class="file" id="file45" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cloudinit
import (
"github.com/pkg/errors"
"sigs.k8s.io/cluster-api/util/secret"
)
const (
controlPlaneJoinCloudInit = `{{.Header}}
{{template "files" .WriteFiles}}
- path: /tmp/kubeadm-join-config.yaml
owner: root:root
permissions: '0640'
content: |
{{.JoinConfiguration | Indent 6}}
runcmd:
{{- template "commands" .PreKubeadmCommands }}
- {{ .KubeadmCommand }}
{{- template "commands" .PostKubeadmCommands }}
{{- template "ntp" .NTP }}
{{- template "users" .Users }}
{{- template "disk_setup" .DiskSetup}}
{{- template "fs_setup" .DiskSetup}}
{{- template "mounts" .Mounts}}
`
)
// ControlPlaneJoinInput defines context to generate controlplane instance user data for control plane node join.
type ControlPlaneJoinInput struct {
BaseUserData
secret.Certificates
BootstrapToken string
JoinConfiguration string
}
// NewJoinControlPlane returns the user data string to be used on a new control plane instance.
func NewJoinControlPlane(input *ControlPlaneJoinInput) ([]byte, error) <span class="cov0" title="0">{
// TODO: Consider validating that the correct certificates exist. It is different for external/stacked etcd
input.WriteFiles = input.Certificates.AsFiles()
input.ControlPlane = true
if err := input.prepare(); err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">userData, err := generate("JoinControlplane", controlPlaneJoinCloudInit, input)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to generate user data for machine joining control plane")
}</span>
<span class="cov0" title="0">return userData, err</span>
}
</pre>
<pre class="file" id="file46" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cloudinit
const (
nodeCloudInit = `{{.Header}}
{{template "files" .WriteFiles}}
- path: /tmp/kubeadm-join-config.yaml
owner: root:root
permissions: '0640'
content: |
---
{{.JoinConfiguration | Indent 6}}
runcmd:
{{- template "commands" .PreKubeadmCommands }}
- {{ .KubeadmCommand }}
{{- template "commands" .PostKubeadmCommands }}
{{- template "ntp" .NTP }}
{{- template "users" .Users }}
{{- template "disk_setup" .DiskSetup}}
{{- template "fs_setup" .DiskSetup}}
{{- template "mounts" .Mounts}}
`
)
// NodeInput defines the context to generate a node user data.
type NodeInput struct {
BaseUserData
JoinConfiguration string
}
// NewNode returns the user data string to be used on a node instance.
func NewNode(input *NodeInput) ([]byte, error) <span class="cov0" title="0">{
if err := input.prepare(); err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">input.Header = cloudConfigHeader
input.WriteFiles = append(input.WriteFiles, input.AdditionalFiles...)
return generate("Node", nodeCloudInit, input)</span>
}
</pre>
<pre class="file" id="file47" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cloudinit
import (
"strings"
"text/template"
)
var (
defaultTemplateFuncMap = template.FuncMap{
"Indent": templateYAMLIndent,
}
)
func templateYAMLIndent(i int, input string) string <span class="cov8" title="1">{
split := strings.Split(input, "\n")
ident := "\n" + strings.Repeat(" ", i)
return strings.Repeat(" ", i) + strings.Join(split, ident)
}</span>
</pre>
<pre class="file" id="file48" style="display: none">/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated for package cloudinit by go-bindata DO NOT EDIT. (@generated)
// sources:
// bootstrap/kubeadm/internal/cloudinit/kubeadm-bootstrap-script.sh
package cloudinit
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
func bindataRead(data []byte, name string) ([]byte, error) <span class="cov0" title="0">{
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil </span><span class="cov0" title="0">{
return nil, fmt.Errorf("Read %q: %v", name, err)
}</span>
<span class="cov0" title="0">var buf bytes.Buffer
_, err = io.Copy(&amp;buf, gz)
clErr := gz.Close()
if err != nil </span><span class="cov0" title="0">{
return nil, fmt.Errorf("Read %q: %v", name, err)
}</span>
<span class="cov0" title="0">if clErr != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">return buf.Bytes(), nil</span>
}
type asset struct {
bytes []byte
info os.FileInfo
}
type bindataFileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
// Name return file name
func (fi bindataFileInfo) Name() string <span class="cov0" title="0">{
return fi.name
}</span>
// Size return file size
func (fi bindataFileInfo) Size() int64 <span class="cov0" title="0">{
return fi.size
}</span>
// Mode return file mode
func (fi bindataFileInfo) Mode() os.FileMode <span class="cov0" title="0">{
return fi.mode
}</span>
// Mode return file modify time
func (fi bindataFileInfo) ModTime() time.Time <span class="cov0" title="0">{
return fi.modTime
}</span>
// IsDir return file whether a directory
func (fi bindataFileInfo) IsDir() bool <span class="cov0" title="0">{
return fi.mode&amp;os.ModeDir != 0
}</span>
// Sys return file is sys mode
func (fi bindataFileInfo) Sys() interface{} <span class="cov0" title="0">{
return nil
}</span>
var _bootstrapKubeadmInternalCloudinitKubeadmBootstrapScriptSh = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x57\x61\x6f\x1a\x31\x12\xfd\xbe\xbf\xe2\x05\xd0\x35\x69\xb2\x40\xa8\x7a\xaa\x12\x71\x77\x5c\xda\xea\x50\x7b\x49\x15\xd2\x56\x55\x55\x45\x66\x77\x76\xd7\x87\xd7\xde\xda\xde\x10\x44\xf3\xdf\x4f\xf6\x2e\x04\x02\x24\x6d\xee\xf8\xb4\xb2\x67\xde\xcc\xbc\x79\x1e\x9b\xe6\x5e\x67\xcc\x65\x67\xcc\x4c\x16\x34\x71\xa6\x8a\x99\xe6\x69\x66\xd1\xeb\xf6\xba\xb8\xca\x08\x1f\xca\x31\x69\x49\x96\x0c\x06\xa5\xcd\x94\x36\xed\xa0\x19\x34\xf1\x91\x47\x24\x0d\xc5\x28\x65\x4c\x1a\x36\x23\x0c\x0a\x16\x65\xb4\xd8\x39\xc2\x17\xd2\x86\x2b\x89\x5e\xbb\x8b\x7d\x67\xd0\xa8\xb7\x1a\x07\xa7\x41\x13\x33\x55\x22\x67\x33\x48\x65\x51\x1a\x82\xcd\xb8\x41\xc2\x05\x81\x6e\x23\x2a\x2c\xb8\x44\xa4\xf2\x42\x70\x26\x23\xc2\x94\xdb\xcc\x87\xa9\x41\xda\x41\x13\xdf\x6a\x08\x35\xb6\x8c\x4b\x30\x44\xaa\x98\x41\x25\xab\x76\x60\xd6\x27\xec\x7e\x99\xb5\xc5\x49\xa7\x33\x9d\x4e\xdb\xcc\x27\xdb\x56\x3a\xed\x88\xca\xd0\x74\x3e\x0e\xcf\xde\x9d\x8f\xde\x85\xbd\x76\xd7\xbb\x7c\x96\x82\x8c\x81\xa6\x9f\x25\xd7\x14\x63\x3c\x03\x2b\x0a\xc1\x23\x36\x16\x04\xc1\xa6\x50\x1a\x2c\xd5\x44\x31\xac\x72\xf9\x4e\x35\xb7\x5c\xa6\x47\x30\x2a\xb1\x53\xa6\x29\x68\x22\xe6\xc6\x6a\x3e\x2e\xed\x1a\x59\x8b\xec\xb8\x59\x33\x50\x12\x4c\xa2\x31\x18\x61\x38\x6a\xe0\x9f\x83\xd1\x70\x74\x14\x34\xf1\x75\x78\xf5\xaf\x8b\xcf\x57\xf8\x3a\xb8\xbc\x1c\x9c\x5f\x0d\xdf\x8d\x70\x71\x89\xb3\x8b\xf3\xb7\xc3\xab\xe1\xc5\xf9\x08\x17\xef\x31\x38\xff\x86\x0f\xc3\xf3\xb7\x47\x20\x6e\x33\xd2\xa0\xdb\x42\xbb\xfc\x95\x06\x77\x34\x52\xec\x38\x1b\x11\xad\x25\x90\xa8\x2a\x21\x53\x50\xc4\x13\x1e\x41\x30\x99\x96\x2c\x25\xa4\xea\x86\xb4\xe4\x32\x45\x41\x3a\xe7\xc6\x35\xd3\x80\xc9\x38\x68\x42\xf0\x9c\x5b\x66\xfd\xca\x46\x51\xed\xc0\x09\x44\xa5\xae\x14\xd2\xda\x91\x24\x63\xd0\x2d\xb7\x2e\x81\x81\x4e\xcd\x89\x6f\x48\xeb\x18\xff\x26\x63\x5c\x2c\xab\x20\x54\x7a\xdf\x64\xef\x56\x19\xf5\xbc\x0e\x2b\x9c\x48\xc5\xde\x56\x93\x2d\xb5\x0c\x84\x4a\x4f\x4e\xfc\xce\xb5\x43\xdf\x3f\xc0\x3c\x00\x84\x8a\x98\x40\x5e\x21\xf7\x1b\xad\xf9\xf1\x5d\x63\xb9\xec\x10\xdc\x5a\xef\xae\x11\xf8\xc5\x05\x02\x1a\xad\x79\xed\xe3\xcd\x9b\x98\xcf\xc1\x13\xb4\xcf\x94\xb4\x5a\x89\x4f\x82\x49\xc2\xdd\xdd\xc2\x89\xcb\x44\xa1\x71\x49\xb9\xba\x71\x14\xe5\x94\x8f\x49\x23\xd1\x2a\x47\x24\x4a\x63\x49\xc3\x58\x66\x4b\xe3\xc0\x26\xe5\x98\x58\x9c\x43\x93\x21\x8b\x30\x41\x59\xc4\xcc\x52\x58\x5b\x86\x95\x25\x7e\xfd\x82\xd5\x25\xed\x08\x41\x36\x8a\xeb\x38\x5b\x31\xb5\x33\xa4\xd0\x99\x85\x75\x3a\xf7\x80\xbe\x1c\x92\xf1\x96\x0a\x0c\x59\x27\xda\x05\xe0\x56\xec\x07\x99\xd5\x8c\xd5\xe9\xb7\x6f\xc3\xc9\x1b\xd3\xe6\x6a\xe9\x37\x56\xca\x1a\xab\x59\x01\x13\x69\x5e\x58\xb4\xba\xbe\xff\x2e\x8c\xef\x71\x5d\x70\x6b\xee\xfa\xe1\xf9\x76\xdb\xae\x07\xf5\xc2\x5d\x50\x75\xd7\x94\x51\x44\xc6\xac\xf7\x77\x99\xfc\x1f\x25\x90\x70\xc9\x4d\x46\xf1\x32\x5a\xd7\x45\x79\xa0\xd4\x71\x69\x31\x21\x2a\x90\x2a\x2e\xd3\xf6\x8a\xc4\x1e\x57\x97\xe5\x39\x19\xcb\xf2\xa2\xdf\xda\x77\xad\x45\x18\x72\xa3\xc2\x37\x7f\xed\x1e\xf7\x0d\x45\x4a\xc6\xe6\xc0\xc5\x8d\x32\x85\xc6\xde\xde\x1e\xbe\xb7\xe6\x4b\x9f\xbb\x1f\xf0\x38\xf8\xdb\x5f\x7a\x01\x60\x32\x9e\xd8\x00\xfe\x68\xd6\x81\x4e\x11\xab\xc0\x8d\xb0\x0a\xc0\x7d\xad\xc8\xb5\xf6\x8b\x95\xa4\xaa\xa4\x4f\x9a\x4b\x0b\xb6\xa0\x59\x70\x49\x6d\xe0\xbd\xd2\x39\xb3\xb6\x9a\x56\x26\x53\x53\x94\x05\xfc\xdc\x34\x56\x13\xcb\xdd\xe4\x54\xa5\x2d\x4a\x5b\xd7\xed\x48\xae\xcb\xfe\xa3\xfa\x0e\x0f\x0f\xb7\xd6\xf7\x9c\xda\x56\xea\x8a\x32\x8a\x26\xd7\x75\x8b\xaf\x23\x95\xe7\x4c\xc6\x6b\x6d\xa9\xd7\x1e\x3b\xf4\x40\xc4\x0c\x2d\x94\x07\x2e\x03\xa0\xd1\x6d\x1c\xf8\x0c\x56\xa4\x75\x7f\x04\x0a\xa5\x1d\x67\xb5\x12\x93\x52\x80\x6e\x29\x2a\xdd\xf0\xf3\x65\x38\x28\x1f\xd6\xa3\x03\xa7\xa7\x0e\xf2\x78\x15\xb2\x3e\x2f\x1b\x98\x09\xe3\x82\x62\xb0\xc8\x81\xed\x9b\x83\x47\xf0\x7a\xbf\x83\x57\x68\x4a\x84\xbf\xc0\x3d\x57\xb5\xa6\xe3\x52\xbb\x83\xb7\x1d\xf7\xd5\x06\xee\x75\x75\x14\x37\xc0\x6f\x98\xe0\xb1\x9f\xf9\x35\xee\xce\x64\x5f\xfe\x46\xaa\xa5\x9c\x48\x35\x5d\x40\x2d\xda\xb1\x13\x92\x0c\x8b\x9c\x06\x92\x52\x7a\xb2\xdc\x15\xa0\x67\xe1\xba\x08\x64\xbf\xbb\xec\xf9\x42\x26\xf5\x55\x01\x94\xd2\x72\x81\xef\x68\x49\x84\x29\xe1\x35\x7e\x2c\x85\xb7\xd2\x76\x5d\x4a\x7f\xe5\xbd\x68\xbd\x7c\x51\x85\x6f\xc2\x64\x24\x44\x45\x68\xcc\x8d\xbb\xfc\xfb\xa3\xb3\xe3\xee\x9b\x57\x7e\xbf\xd1\xfa\x47\x03\x61\x18\x29\x99\xf0\xb4\xdf\xb1\x79\xd1\xa9\x63\x87\xff\x51\x5c\xd6\x1b\xed\x19\xcb\x05\xe6\xf3\xf6\x87\x6a\xef\x0b\xe9\xb1\x32\xdc\xce\xfc\x3c\xc6\x83\x74\xfb\xad\xbf\xfb\xd5\xad\x8a\x47\xc3\x27\xe7\x86\xe5\xba\x57\xcd\x17\x4f\x5c\x95\x0f\xf7\x10\xd2\x4f\x74\x5d\xd1\x36\x23\xe9\x0d\x81\xb1\x26\x36\xf1\xdf\x09\xaf\x8b\xfd\x4a\x60\x42\xa8\xe9\x8a\x96\x7c\x8b\x8c\x1b\x1a\x05\x33\xe6\xa9\x18\xbd\xa7\x62\xc8\x7e\x6b\x7f\x5f\xe2\x10\xc7\x07\x95\x4e\x8c\x70\x03\xf7\xf8\xf5\xe2\xa8\xef\x86\x97\xf4\xa0\x84\x0d\xd5\x5a\xa5\x90\x33\x39\xab\x93\x3e\x5a\x5c\x3b\x8e\x9a\x84\x57\xd3\x71\xc7\xc5\xbe\x94\x96\x13\x96\xd2\x61\xcc\x29\xdc\x36\x64\x36\x94\xf5\x88\x7c\x1e\x17\xcf\xff\x43\x3a\xdb\x84\xf3\x0c\xd9\x3c\x9f\xf1\x84\x59\x26\x2a\xba\x37\xd9\x5e\x7d\x76\x04\x6b\x47\x76\x79\x55\xbb\x4a\x51\x64\x6e\x28\xdf\x4b\x2e\x0c\x79\x2a\x95\xa6\x70\xb9\x14\x56\x0d\xed\xbf\xe5\x7a\x70\xc3\xb8\x70\x4c\x86\xee\xb1\x13\x4e\x96\x7f\x51\xc2\x9c\x49\x9e\x90\xb1\x66\x77\x97\x9f\x4c\x22\xaa\x1c\xc2\xc2\x79\xb8\xf8\x05\xd3\x84\x58\x4d\xa5\x50\x2c\x0e\x23\xd2\xd6\x3c\x17\xe5\x7f\x72\x76\x86\x95\x22\x9e\x1d\x7e\x75\x75\xad\x37\x4f\x02\xba\x25\x41\xd6\xbd\x54\xb5\xdd\xcd\xee\xe6\xd1\x79\x3a\x3b\xbf\xe1\x5e\xad\x7f\x5a\x96\xdf\xa8\x5f\xd2\xd5\x4b\xe7\x59\x08\x39\xd3\x93\x70\x37\x35\x9b\xef\xd0\xe0\xbf\x01\x00\x00\xff\xff\x20\x29\xc4\xf7\x36\x0f\x00\x00")
func bootstrapKubeadmInternalCloudinitKubeadmBootstrapScriptShBytes() ([]byte, error) <span class="cov0" title="0">{
return bindataRead(
_bootstrapKubeadmInternalCloudinitKubeadmBootstrapScriptSh,
"bootstrap/kubeadm/internal/cloudinit/kubeadm-bootstrap-script.sh",
)
}</span>
func bootstrapKubeadmInternalCloudinitKubeadmBootstrapScriptSh() (*asset, error) <span class="cov0" title="0">{
bytes, err := bootstrapKubeadmInternalCloudinitKubeadmBootstrapScriptShBytes()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">info := bindataFileInfo{name: "bootstrap/kubeadm/internal/cloudinit/kubeadm-bootstrap-script.sh", size: 3894, mode: os.FileMode(420), modTime: time.Unix(1, 0)}
a := &amp;asset{bytes: bytes, info: info}
return a, nil</span>
}
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) <span class="cov0" title="0">{
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok </span><span class="cov0" title="0">{
a, err := f()
if err != nil </span><span class="cov0" title="0">{
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
}</span>
<span class="cov0" title="0">return a.bytes, nil</span>
}
<span class="cov0" title="0">return nil, fmt.Errorf("Asset %s not found", name)</span>
}
// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte <span class="cov0" title="0">{
a, err := Asset(name)
if err != nil </span><span class="cov0" title="0">{
panic("asset: Asset(" + name + "): " + err.Error())</span>
}
<span class="cov0" title="0">return a</span>
}
// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) <span class="cov0" title="0">{
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok </span><span class="cov0" title="0">{
a, err := f()
if err != nil </span><span class="cov0" title="0">{
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
}</span>
<span class="cov0" title="0">return a.info, nil</span>
}
<span class="cov0" title="0">return nil, fmt.Errorf("AssetInfo %s not found", name)</span>
}
// AssetNames returns the names of the assets.
func AssetNames() []string <span class="cov0" title="0">{
names := make([]string, 0, len(_bindata))
for name := range _bindata </span><span class="cov0" title="0">{
names = append(names, name)
}</span>
<span class="cov0" title="0">return names</span>
}
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"bootstrap/kubeadm/internal/cloudinit/kubeadm-bootstrap-script.sh": bootstrapKubeadmInternalCloudinitKubeadmBootstrapScriptSh,
}
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) <span class="cov0" title="0">{
node := _bintree
if len(name) != 0 </span><span class="cov0" title="0">{
cannonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(cannonicalName, "/")
for _, p := range pathList </span><span class="cov0" title="0">{
node = node.Children[p]
if node == nil </span><span class="cov0" title="0">{
return nil, fmt.Errorf("Asset %s not found", name)
}</span>
}
}
<span class="cov0" title="0">if node.Func != nil </span><span class="cov0" title="0">{
return nil, fmt.Errorf("Asset %s not found", name)
}</span>
<span class="cov0" title="0">rv := make([]string, 0, len(node.Children))
for childName := range node.Children </span><span class="cov0" title="0">{
rv = append(rv, childName)
}</span>
<span class="cov0" title="0">return rv, nil</span>
}
type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &amp;bintree{nil, map[string]*bintree{
"bootstrap": &amp;bintree{nil, map[string]*bintree{
"kubeadm": &amp;bintree{nil, map[string]*bintree{
"internal": &amp;bintree{nil, map[string]*bintree{
"cloudinit": &amp;bintree{nil, map[string]*bintree{
"kubeadm-bootstrap-script.sh": &amp;bintree{bootstrapKubeadmInternalCloudinitKubeadmBootstrapScriptSh, map[string]*bintree{}},
}},
}},
}},
}},
}}
// RestoreAsset restores an asset under the given directory
func RestoreAsset(dir, name string) error <span class="cov0" title="0">{
data, err := Asset(name)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">info, err := AssetInfo(name)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
// RestoreAssets restores an asset under the given directory recursively
func RestoreAssets(dir, name string) error <span class="cov0" title="0">{
children, err := AssetDir(name)
// File
if err != nil </span><span class="cov0" title="0">{
return RestoreAsset(dir, name)
}</span>
// Dir
<span class="cov0" title="0">for _, child := range children </span><span class="cov0" title="0">{
err = RestoreAssets(dir, filepath.Join(name, child))
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
<span class="cov0" title="0">return nil</span>
}
func _filePath(dir, name string) string <span class="cov0" title="0">{
cannonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
}</span>
</pre>
<pre class="file" id="file49" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 locking
import (
"context"
"encoding/json"
"fmt"
"github.com/go-logr/logr"
"github.com/pkg/errors"
apicorev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const semaphoreInformationKey = "lock-information"
// ControlPlaneInitMutex uses a ConfigMap to synchronize cluster initialization.
type ControlPlaneInitMutex struct {
log logr.Logger
client client.Client
}
// NewControlPlaneInitMutex returns a lock that can be held by a control plane node before init.
func NewControlPlaneInitMutex(log logr.Logger, client client.Client) *ControlPlaneInitMutex <span class="cov0" title="0">{
return &amp;ControlPlaneInitMutex{
log: log,
client: client,
}
}</span>
// Lock allows a control plane node to be the first and only node to run kubeadm init
func (c *ControlPlaneInitMutex) Lock(ctx context.Context, cluster *clusterv1.Cluster, machine *clusterv1.Machine) bool <span class="cov8" title="1">{
sema := newSemaphore()
cmName := configMapName(cluster.Name)
log := c.log.WithValues("namespace", cluster.Namespace, "cluster-name", cluster.Name, "configmap-name", cmName, "machine-name", machine.Name)
err := c.client.Get(ctx, client.ObjectKey{
Namespace: cluster.Namespace,
Name: cmName,
}, sema.ConfigMap)
switch </span>{
case apierrors.IsNotFound(err):<span class="cov8" title="1">
break</span>
case err != nil:<span class="cov0" title="0">
log.Error(err, "Failed to acquire lock")
return false</span>
default:<span class="cov8" title="1"> // successfully found an existing config map
info, err := sema.information()
if err != nil </span><span class="cov8" title="1">{
log.Error(err, "Failed to get information about the existing lock")
return false
}</span>
// the machine requesting the lock is the machine that created the lock, therefore the lock is acquired
<span class="cov8" title="1">if info.MachineName == machine.Name </span><span class="cov0" title="0">{
return true
}</span>
<span class="cov8" title="1">log.Info("Waiting on another machine to initialize", "init-machine", info.MachineName)
return false</span>
}
// Adds owner reference, namespace and name
<span class="cov8" title="1">sema.setMetadata(cluster)
// Adds the additional information
if err := sema.setInformation(&amp;information{MachineName: machine.Name}); err != nil </span><span class="cov0" title="0">{
log.Error(err, "Failed to acquire lock while setting semaphore information")
return false
}</span>
<span class="cov8" title="1">log.Info("Attempting to acquire the lock")
err = c.client.Create(ctx, sema.ConfigMap)
switch </span>{
case apierrors.IsAlreadyExists(err):<span class="cov8" title="1">
log.Info("Cannot acquire the lock. The lock has been acquired by someone else")
return false</span>
case err != nil:<span class="cov8" title="1">
log.Error(err, "Error acquiring the lock")
return false</span>
default:<span class="cov8" title="1">
return true</span>
}
}
// Unlock releases the lock
func (c *ControlPlaneInitMutex) Unlock(ctx context.Context, cluster *clusterv1.Cluster) bool <span class="cov8" title="1">{
sema := newSemaphore()
cmName := configMapName(cluster.Name)
log := c.log.WithValues("namespace", cluster.Namespace, "cluster-name", cluster.Name, "configmap-name", cmName)
log.Info("Checking for lock")
err := c.client.Get(ctx, client.ObjectKey{
Namespace: cluster.Namespace,
Name: cmName,
}, sema.ConfigMap)
switch </span>{
case apierrors.IsNotFound(err):<span class="cov8" title="1">
log.Info("Control plane init lock not found, it may have been released already")
return true</span>
case err != nil:<span class="cov8" title="1">
log.Error(err, "Error unlocking the control plane init lock")
return false</span>
default:<span class="cov8" title="1">
// Delete the config map semaphore if there is no error fetching it
if err := c.client.Delete(ctx, sema.ConfigMap); err != nil </span><span class="cov8" title="1">{
if apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
return true
}</span>
<span class="cov8" title="1">log.Error(err, "Error deleting the config map underlying the control plane init lock")
return false</span>
}
<span class="cov0" title="0">return true</span>
}
}
type information struct {
MachineName string `json:"machineName"`
}
type semaphore struct {
*apicorev1.ConfigMap
}
func newSemaphore() *semaphore <span class="cov8" title="1">{
return &amp;semaphore{&amp;apicorev1.ConfigMap{}}
}</span>
func configMapName(clusterName string) string <span class="cov8" title="1">{
return fmt.Sprintf("%s-lock", clusterName)
}</span>
func (s semaphore) information() (*information, error) <span class="cov8" title="1">{
li := &amp;information{}
if err := json.Unmarshal([]byte(s.Data[semaphoreInformationKey]), li); err != nil </span><span class="cov8" title="1">{
return nil, errors.Wrap(err, "failed to unmarshal semaphore information")
}</span>
<span class="cov8" title="1">return li, nil</span>
}
func (s semaphore) setInformation(information *information) error <span class="cov8" title="1">{
b, err := json.Marshal(information)
if err != nil </span><span class="cov0" title="0">{
return errors.Wrap(err, "failed to marshal semaphore information")
}</span>
<span class="cov8" title="1">s.Data = map[string]string{}
s.Data[semaphoreInformationKey] = string(b)
return nil</span>
}
func (s *semaphore) setMetadata(cluster *clusterv1.Cluster) <span class="cov8" title="1">{
s.ObjectMeta = metav1.ObjectMeta{
Namespace: cluster.Namespace,
Name: configMapName(cluster.Name),
Labels: map[string]string{
clusterv1.ClusterLabelName: cluster.Name,
},
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: cluster.APIVersion,
Kind: cluster.Kind,
Name: cluster.Name,
UID: cluster.UID,
},
},
}
}</span>
</pre>
<pre class="file" id="file50" style="display: none">/*
Copyright 2018 The Kubernetes Authors.
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 v1beta1
import (
"fmt"
"strings"
"github.com/pkg/errors"
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
bootstraputil "k8s.io/cluster-bootstrap/token/util"
)
// BootstrapTokenString is a token of the format abcdef.abcdef0123456789 that is used
// for both validation of the practically of the API server from a joining node's point
// of view and as an authentication method for the node in the bootstrap phase of
// "kubeadm join". This token is and should be short-lived
type BootstrapTokenString struct {
ID string `json:"-"`
Secret string `json:"-"`
}
// MarshalJSON implements the json.Marshaler interface.
func (bts BootstrapTokenString) MarshalJSON() ([]byte, error) <span class="cov8" title="1">{
return []byte(fmt.Sprintf(`"%s"`, bts.String())), nil
}</span>
// UnmarshalJSON implements the json.Unmarshaller interface.
func (bts *BootstrapTokenString) UnmarshalJSON(b []byte) error <span class="cov8" title="1">{
// If the token is represented as "", just return quickly without an error
if len(b) == 0 </span><span class="cov0" title="0">{
return nil
}</span>
// Remove unnecessary " characters coming from the JSON parser
<span class="cov8" title="1">token := strings.Replace(string(b), `"`, ``, -1)
// Convert the string Token to a BootstrapTokenString object
newbts, err := NewBootstrapTokenString(token)
if err != nil </span><span class="cov8" title="1">{
return err
}</span>
<span class="cov8" title="1">bts.ID = newbts.ID
bts.Secret = newbts.Secret
return nil</span>
}
// String returns the string representation of the BootstrapTokenString
func (bts BootstrapTokenString) String() string <span class="cov8" title="1">{
if len(bts.ID) &gt; 0 &amp;&amp; len(bts.Secret) &gt; 0 </span><span class="cov8" title="1">{
return bootstraputil.TokenFromIDAndSecret(bts.ID, bts.Secret)
}</span>
<span class="cov0" title="0">return ""</span>
}
// NewBootstrapTokenString converts the given Bootstrap Token as a string
// to the BootstrapTokenString object used for serialization/deserialization
// and internal usage. It also automatically validates that the given token
// is of the right format
func NewBootstrapTokenString(token string) (*BootstrapTokenString, error) <span class="cov8" title="1">{
substrs := bootstraputil.BootstrapTokenRegexp.FindStringSubmatch(token)
// TODO: Add a constant for the 3 value here, and explain better why it's needed (other than because how the regexp parsin works)
if len(substrs) != 3 </span><span class="cov8" title="1">{
return nil, errors.Errorf("the bootstrap token %q was not of the form %q", token, bootstrapapi.BootstrapTokenPattern)
}</span>
<span class="cov8" title="1">return &amp;BootstrapTokenString{ID: substrs[1], Secret: substrs[2]}, nil</span>
}
// NewBootstrapTokenStringFromIDAndSecret is a wrapper around NewBootstrapTokenString
// that allows the caller to specify the ID and Secret separately
func NewBootstrapTokenStringFromIDAndSecret(id, secret string) (*BootstrapTokenString, error) <span class="cov8" title="1">{
return NewBootstrapTokenString(bootstraputil.TokenFromIDAndSecret(id, secret))
}</span>
</pre>
<pre class="file" id="file51" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1beta1
import (
"github.com/pkg/errors"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
// GetCodecs returns a type that can be used to deserialize most kubeadm
// configuration types.
func GetCodecs() serializer.CodecFactory <span class="cov0" title="0">{
sb := &amp;scheme.Builder{GroupVersion: GroupVersion}
sb.Register(&amp;JoinConfiguration{}, &amp;InitConfiguration{}, &amp;ClusterConfiguration{})
kubeadmScheme, err := sb.Build()
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov0" title="0">return serializer.NewCodecFactory(kubeadmScheme)</span>
}
// ConfigurationToYAML converts a kubeadm configuration type to its YAML
// representation.
func ConfigurationToYAML(obj runtime.Object) (string, error) <span class="cov0" title="0">{
initcfg, err := MarshalToYamlForCodecs(obj, GroupVersion, GetCodecs())
if err != nil </span><span class="cov0" title="0">{
return "", errors.Wrap(err, "failed to marshal configuration")
}</span>
<span class="cov0" title="0">return string(initcfg), nil</span>
}
// MarshalToYamlForCodecs marshals an object into yaml using the specified codec
// TODO: Is specifying the gv really needed here?
// TODO: Can we support json out of the box easily here?
func MarshalToYamlForCodecs(obj runtime.Object, gv runtime.GroupVersioner, codecs serializer.CodecFactory) ([]byte, error) <span class="cov0" title="0">{
mediaType := "application/yaml"
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
if !ok </span><span class="cov0" title="0">{
return []byte{}, errors.Errorf("unsupported media type %q", mediaType)
}</span>
<span class="cov0" title="0">encoder := codecs.EncoderForVersion(info.Serializer, gv)
return runtime.Encode(encoder, obj)</span>
}
</pre>
<pre class="file" id="file52" style="display: none">// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1beta1
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *APIEndpoint) DeepCopyInto(out *APIEndpoint) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIEndpoint.
func (in *APIEndpoint) DeepCopy() *APIEndpoint <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(APIEndpoint)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *APIServer) DeepCopyInto(out *APIServer) <span class="cov0" title="0">{
*out = *in
in.ControlPlaneComponent.DeepCopyInto(&amp;out.ControlPlaneComponent)
if in.CertSANs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.CertSANs, &amp;out.CertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.TimeoutForControlPlane != nil </span><span class="cov0" title="0">{
in, out := &amp;in.TimeoutForControlPlane, &amp;out.TimeoutForControlPlane
*out = new(v1.Duration)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIServer.
func (in *APIServer) DeepCopy() *APIServer <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(APIServer)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapToken) DeepCopyInto(out *BootstrapToken) <span class="cov0" title="0">{
*out = *in
if in.Token != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Token, &amp;out.Token
*out = new(BootstrapTokenString)
**out = **in
}</span>
<span class="cov0" title="0">if in.TTL != nil </span><span class="cov0" title="0">{
in, out := &amp;in.TTL, &amp;out.TTL
*out = new(v1.Duration)
**out = **in
}</span>
<span class="cov0" title="0">if in.Expires != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Expires, &amp;out.Expires
*out = (*in).DeepCopy()
}</span>
<span class="cov0" title="0">if in.Usages != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Usages, &amp;out.Usages
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.Groups != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Groups, &amp;out.Groups
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapToken.
func (in *BootstrapToken) DeepCopy() *BootstrapToken <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(BootstrapToken)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) <span class="cov0" title="0">{
*out = *in
if in.CACertHashes != nil </span><span class="cov0" title="0">{
in, out := &amp;in.CACertHashes, &amp;out.CACertHashes
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapTokenDiscovery.
func (in *BootstrapTokenDiscovery) DeepCopy() *BootstrapTokenDiscovery <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(BootstrapTokenDiscovery)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenString) DeepCopyInto(out *BootstrapTokenString) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapTokenString.
func (in *BootstrapTokenString) DeepCopy() *BootstrapTokenString <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(BootstrapTokenString)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterConfiguration) DeepCopyInto(out *ClusterConfiguration) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.Etcd.DeepCopyInto(&amp;out.Etcd)
out.Networking = in.Networking
in.APIServer.DeepCopyInto(&amp;out.APIServer)
in.ControllerManager.DeepCopyInto(&amp;out.ControllerManager)
in.Scheduler.DeepCopyInto(&amp;out.Scheduler)
out.DNS = in.DNS
if in.FeatureGates != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FeatureGates, &amp;out.FeatureGates
*out = make(map[string]bool, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfiguration.
func (in *ClusterConfiguration) DeepCopy() *ClusterConfiguration <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterConfiguration)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ClusterConfiguration) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
if in.APIEndpoints != nil </span><span class="cov0" title="0">{
in, out := &amp;in.APIEndpoints, &amp;out.APIEndpoints
*out = make(map[string]APIEndpoint, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus.
func (in *ClusterStatus) DeepCopy() *ClusterStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ClusterStatus) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ControlPlaneComponent) DeepCopyInto(out *ControlPlaneComponent) <span class="cov0" title="0">{
*out = *in
if in.ExtraArgs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ExtraArgs, &amp;out.ExtraArgs
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
<span class="cov0" title="0">if in.ExtraVolumes != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ExtraVolumes, &amp;out.ExtraVolumes
*out = make([]HostPathMount, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneComponent.
func (in *ControlPlaneComponent) DeepCopy() *ControlPlaneComponent <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ControlPlaneComponent)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DNS) DeepCopyInto(out *DNS) <span class="cov0" title="0">{
*out = *in
out.ImageMeta = in.ImageMeta
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNS.
func (in *DNS) DeepCopy() *DNS <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(DNS)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Discovery) DeepCopyInto(out *Discovery) <span class="cov0" title="0">{
*out = *in
if in.BootstrapToken != nil </span><span class="cov0" title="0">{
in, out := &amp;in.BootstrapToken, &amp;out.BootstrapToken
*out = new(BootstrapTokenDiscovery)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.File != nil </span><span class="cov0" title="0">{
in, out := &amp;in.File, &amp;out.File
*out = new(FileDiscovery)
**out = **in
}</span>
<span class="cov0" title="0">if in.Timeout != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Timeout, &amp;out.Timeout
*out = new(v1.Duration)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Discovery.
func (in *Discovery) DeepCopy() *Discovery <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Discovery)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Etcd) DeepCopyInto(out *Etcd) <span class="cov0" title="0">{
*out = *in
if in.Local != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Local, &amp;out.Local
*out = new(LocalEtcd)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.External != nil </span><span class="cov0" title="0">{
in, out := &amp;in.External, &amp;out.External
*out = new(ExternalEtcd)
(*in).DeepCopyInto(*out)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Etcd.
func (in *Etcd) DeepCopy() *Etcd <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Etcd)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExternalEtcd) DeepCopyInto(out *ExternalEtcd) <span class="cov0" title="0">{
*out = *in
if in.Endpoints != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Endpoints, &amp;out.Endpoints
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalEtcd.
func (in *ExternalEtcd) DeepCopy() *ExternalEtcd <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ExternalEtcd)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FileDiscovery) DeepCopyInto(out *FileDiscovery) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileDiscovery.
func (in *FileDiscovery) DeepCopy() *FileDiscovery <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(FileDiscovery)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HostPathMount) DeepCopyInto(out *HostPathMount) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostPathMount.
func (in *HostPathMount) DeepCopy() *HostPathMount <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(HostPathMount)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImageMeta) DeepCopyInto(out *ImageMeta) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageMeta.
func (in *ImageMeta) DeepCopy() *ImageMeta <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ImageMeta)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *InitConfiguration) DeepCopyInto(out *InitConfiguration) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
if in.BootstrapTokens != nil </span><span class="cov0" title="0">{
in, out := &amp;in.BootstrapTokens, &amp;out.BootstrapTokens
*out = make([]BootstrapToken, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
<span class="cov0" title="0">in.NodeRegistration.DeepCopyInto(&amp;out.NodeRegistration)
out.LocalAPIEndpoint = in.LocalAPIEndpoint</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InitConfiguration.
func (in *InitConfiguration) DeepCopy() *InitConfiguration <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(InitConfiguration)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *InitConfiguration) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JoinConfiguration) DeepCopyInto(out *JoinConfiguration) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.NodeRegistration.DeepCopyInto(&amp;out.NodeRegistration)
in.Discovery.DeepCopyInto(&amp;out.Discovery)
if in.ControlPlane != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ControlPlane, &amp;out.ControlPlane
*out = new(JoinControlPlane)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JoinConfiguration.
func (in *JoinConfiguration) DeepCopy() *JoinConfiguration <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(JoinConfiguration)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *JoinConfiguration) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JoinControlPlane) DeepCopyInto(out *JoinControlPlane) <span class="cov0" title="0">{
*out = *in
out.LocalAPIEndpoint = in.LocalAPIEndpoint
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JoinControlPlane.
func (in *JoinControlPlane) DeepCopy() *JoinControlPlane <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(JoinControlPlane)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LocalEtcd) DeepCopyInto(out *LocalEtcd) <span class="cov0" title="0">{
*out = *in
out.ImageMeta = in.ImageMeta
if in.ExtraArgs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ExtraArgs, &amp;out.ExtraArgs
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
<span class="cov0" title="0">if in.ServerCertSANs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ServerCertSANs, &amp;out.ServerCertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.PeerCertSANs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.PeerCertSANs, &amp;out.PeerCertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalEtcd.
func (in *LocalEtcd) DeepCopy() *LocalEtcd <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(LocalEtcd)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Networking) DeepCopyInto(out *Networking) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Networking.
func (in *Networking) DeepCopy() *Networking <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Networking)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeRegistrationOptions) DeepCopyInto(out *NodeRegistrationOptions) <span class="cov0" title="0">{
*out = *in
if in.Taints != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Taints, &amp;out.Taints
*out = make([]corev1.Taint, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
<span class="cov0" title="0">if in.KubeletExtraArgs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.KubeletExtraArgs, &amp;out.KubeletExtraArgs
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRegistrationOptions.
func (in *NodeRegistrationOptions) DeepCopy() *NodeRegistrationOptions <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(NodeRegistrationOptions)
in.DeepCopyInto(out)
return out</span>
}
</pre>
<pre class="file" id="file53" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1beta2
import (
"fmt"
"strings"
"github.com/pkg/errors"
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
bootstraputil "k8s.io/cluster-bootstrap/token/util"
)
// BootstrapTokenString is a token of the format abcdef.abcdef0123456789 that is used
// for both validation of the practically of the API server from a joining node's point
// of view and as an authentication method for the node in the bootstrap phase of
// "kubeadm join". This token is and should be short-lived
type BootstrapTokenString struct {
ID string `json:"-"`
Secret string `json:"-"`
}
// MarshalJSON implements the json.Marshaler interface.
func (bts BootstrapTokenString) MarshalJSON() ([]byte, error) <span class="cov8" title="1">{
return []byte(fmt.Sprintf(`"%s"`, bts.String())), nil
}</span>
// UnmarshalJSON implements the json.Unmarshaller interface.
func (bts *BootstrapTokenString) UnmarshalJSON(b []byte) error <span class="cov8" title="1">{
// If the token is represented as "", just return quickly without an error
if len(b) == 0 </span><span class="cov0" title="0">{
return nil
}</span>
// Remove unnecessary " characters coming from the JSON parser
<span class="cov8" title="1">token := strings.Replace(string(b), `"`, ``, -1)
// Convert the string Token to a BootstrapTokenString object
newbts, err := NewBootstrapTokenString(token)
if err != nil </span><span class="cov8" title="1">{
return err
}</span>
<span class="cov8" title="1">bts.ID = newbts.ID
bts.Secret = newbts.Secret
return nil</span>
}
// String returns the string representation of the BootstrapTokenString
func (bts BootstrapTokenString) String() string <span class="cov8" title="1">{
if len(bts.ID) &gt; 0 &amp;&amp; len(bts.Secret) &gt; 0 </span><span class="cov8" title="1">{
return bootstraputil.TokenFromIDAndSecret(bts.ID, bts.Secret)
}</span>
<span class="cov0" title="0">return ""</span>
}
// NewBootstrapTokenString converts the given Bootstrap Token as a string
// to the BootstrapTokenString object used for serialization/deserialization
// and internal usage. It also automatically validates that the given token
// is of the right format
func NewBootstrapTokenString(token string) (*BootstrapTokenString, error) <span class="cov8" title="1">{
substrs := bootstraputil.BootstrapTokenRegexp.FindStringSubmatch(token)
// TODO: Add a constant for the 3 value here, and explain better why it's needed (other than because how the regexp parsin works)
if len(substrs) != 3 </span><span class="cov8" title="1">{
return nil, errors.Errorf("the bootstrap token %q was not of the form %q", token, bootstrapapi.BootstrapTokenPattern)
}</span>
<span class="cov8" title="1">return &amp;BootstrapTokenString{ID: substrs[1], Secret: substrs[2]}, nil</span>
}
// NewBootstrapTokenStringFromIDAndSecret is a wrapper around NewBootstrapTokenString
// that allows the caller to specify the ID and Secret separately
func NewBootstrapTokenStringFromIDAndSecret(id, secret string) (*BootstrapTokenString, error) <span class="cov8" title="1">{
return NewBootstrapTokenString(bootstraputil.TokenFromIDAndSecret(id, secret))
}</span>
</pre>
<pre class="file" id="file54" style="display: none">// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1beta2
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *APIEndpoint) DeepCopyInto(out *APIEndpoint) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIEndpoint.
func (in *APIEndpoint) DeepCopy() *APIEndpoint <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(APIEndpoint)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *APIServer) DeepCopyInto(out *APIServer) <span class="cov0" title="0">{
*out = *in
in.ControlPlaneComponent.DeepCopyInto(&amp;out.ControlPlaneComponent)
if in.CertSANs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.CertSANs, &amp;out.CertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.TimeoutForControlPlane != nil </span><span class="cov0" title="0">{
in, out := &amp;in.TimeoutForControlPlane, &amp;out.TimeoutForControlPlane
*out = new(v1.Duration)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIServer.
func (in *APIServer) DeepCopy() *APIServer <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(APIServer)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapToken) DeepCopyInto(out *BootstrapToken) <span class="cov0" title="0">{
*out = *in
if in.Token != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Token, &amp;out.Token
*out = new(BootstrapTokenString)
**out = **in
}</span>
<span class="cov0" title="0">if in.TTL != nil </span><span class="cov0" title="0">{
in, out := &amp;in.TTL, &amp;out.TTL
*out = new(v1.Duration)
**out = **in
}</span>
<span class="cov0" title="0">if in.Expires != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Expires, &amp;out.Expires
*out = (*in).DeepCopy()
}</span>
<span class="cov0" title="0">if in.Usages != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Usages, &amp;out.Usages
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.Groups != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Groups, &amp;out.Groups
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapToken.
func (in *BootstrapToken) DeepCopy() *BootstrapToken <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(BootstrapToken)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) <span class="cov0" title="0">{
*out = *in
if in.CACertHashes != nil </span><span class="cov0" title="0">{
in, out := &amp;in.CACertHashes, &amp;out.CACertHashes
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapTokenDiscovery.
func (in *BootstrapTokenDiscovery) DeepCopy() *BootstrapTokenDiscovery <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(BootstrapTokenDiscovery)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BootstrapTokenString) DeepCopyInto(out *BootstrapTokenString) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapTokenString.
func (in *BootstrapTokenString) DeepCopy() *BootstrapTokenString <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(BootstrapTokenString)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterConfiguration) DeepCopyInto(out *ClusterConfiguration) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.Etcd.DeepCopyInto(&amp;out.Etcd)
out.Networking = in.Networking
in.APIServer.DeepCopyInto(&amp;out.APIServer)
in.ControllerManager.DeepCopyInto(&amp;out.ControllerManager)
in.Scheduler.DeepCopyInto(&amp;out.Scheduler)
out.DNS = in.DNS
if in.FeatureGates != nil </span><span class="cov0" title="0">{
in, out := &amp;in.FeatureGates, &amp;out.FeatureGates
*out = make(map[string]bool, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfiguration.
func (in *ClusterConfiguration) DeepCopy() *ClusterConfiguration <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterConfiguration)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ClusterConfiguration) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
if in.APIEndpoints != nil </span><span class="cov0" title="0">{
in, out := &amp;in.APIEndpoints, &amp;out.APIEndpoints
*out = make(map[string]APIEndpoint, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus.
func (in *ClusterStatus) DeepCopy() *ClusterStatus <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ClusterStatus)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ClusterStatus) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ControlPlaneComponent) DeepCopyInto(out *ControlPlaneComponent) <span class="cov0" title="0">{
*out = *in
if in.ExtraArgs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ExtraArgs, &amp;out.ExtraArgs
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
<span class="cov0" title="0">if in.ExtraVolumes != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ExtraVolumes, &amp;out.ExtraVolumes
*out = make([]HostPathMount, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneComponent.
func (in *ControlPlaneComponent) DeepCopy() *ControlPlaneComponent <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ControlPlaneComponent)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DNS) DeepCopyInto(out *DNS) <span class="cov0" title="0">{
*out = *in
out.ImageMeta = in.ImageMeta
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNS.
func (in *DNS) DeepCopy() *DNS <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(DNS)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Discovery) DeepCopyInto(out *Discovery) <span class="cov0" title="0">{
*out = *in
if in.BootstrapToken != nil </span><span class="cov0" title="0">{
in, out := &amp;in.BootstrapToken, &amp;out.BootstrapToken
*out = new(BootstrapTokenDiscovery)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.File != nil </span><span class="cov0" title="0">{
in, out := &amp;in.File, &amp;out.File
*out = new(FileDiscovery)
**out = **in
}</span>
<span class="cov0" title="0">if in.Timeout != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Timeout, &amp;out.Timeout
*out = new(v1.Duration)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Discovery.
func (in *Discovery) DeepCopy() *Discovery <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Discovery)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Etcd) DeepCopyInto(out *Etcd) <span class="cov0" title="0">{
*out = *in
if in.Local != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Local, &amp;out.Local
*out = new(LocalEtcd)
(*in).DeepCopyInto(*out)
}</span>
<span class="cov0" title="0">if in.External != nil </span><span class="cov0" title="0">{
in, out := &amp;in.External, &amp;out.External
*out = new(ExternalEtcd)
(*in).DeepCopyInto(*out)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Etcd.
func (in *Etcd) DeepCopy() *Etcd <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Etcd)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExternalEtcd) DeepCopyInto(out *ExternalEtcd) <span class="cov0" title="0">{
*out = *in
if in.Endpoints != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Endpoints, &amp;out.Endpoints
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalEtcd.
func (in *ExternalEtcd) DeepCopy() *ExternalEtcd <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ExternalEtcd)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FileDiscovery) DeepCopyInto(out *FileDiscovery) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileDiscovery.
func (in *FileDiscovery) DeepCopy() *FileDiscovery <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(FileDiscovery)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HostPathMount) DeepCopyInto(out *HostPathMount) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostPathMount.
func (in *HostPathMount) DeepCopy() *HostPathMount <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(HostPathMount)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImageMeta) DeepCopyInto(out *ImageMeta) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageMeta.
func (in *ImageMeta) DeepCopy() *ImageMeta <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ImageMeta)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *InitConfiguration) DeepCopyInto(out *InitConfiguration) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
if in.BootstrapTokens != nil </span><span class="cov0" title="0">{
in, out := &amp;in.BootstrapTokens, &amp;out.BootstrapTokens
*out = make([]BootstrapToken, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
<span class="cov0" title="0">in.NodeRegistration.DeepCopyInto(&amp;out.NodeRegistration)
out.LocalAPIEndpoint = in.LocalAPIEndpoint</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InitConfiguration.
func (in *InitConfiguration) DeepCopy() *InitConfiguration <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(InitConfiguration)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *InitConfiguration) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JoinConfiguration) DeepCopyInto(out *JoinConfiguration) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.NodeRegistration.DeepCopyInto(&amp;out.NodeRegistration)
in.Discovery.DeepCopyInto(&amp;out.Discovery)
if in.ControlPlane != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ControlPlane, &amp;out.ControlPlane
*out = new(JoinControlPlane)
**out = **in
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JoinConfiguration.
func (in *JoinConfiguration) DeepCopy() *JoinConfiguration <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(JoinConfiguration)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *JoinConfiguration) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JoinControlPlane) DeepCopyInto(out *JoinControlPlane) <span class="cov0" title="0">{
*out = *in
out.LocalAPIEndpoint = in.LocalAPIEndpoint
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JoinControlPlane.
func (in *JoinControlPlane) DeepCopy() *JoinControlPlane <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(JoinControlPlane)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LocalEtcd) DeepCopyInto(out *LocalEtcd) <span class="cov0" title="0">{
*out = *in
out.ImageMeta = in.ImageMeta
if in.ExtraArgs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ExtraArgs, &amp;out.ExtraArgs
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
<span class="cov0" title="0">if in.ServerCertSANs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ServerCertSANs, &amp;out.ServerCertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
<span class="cov0" title="0">if in.PeerCertSANs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.PeerCertSANs, &amp;out.PeerCertSANs
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalEtcd.
func (in *LocalEtcd) DeepCopy() *LocalEtcd <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(LocalEtcd)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Networking) DeepCopyInto(out *Networking) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Networking.
func (in *Networking) DeepCopy() *Networking <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Networking)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeRegistrationOptions) DeepCopyInto(out *NodeRegistrationOptions) <span class="cov0" title="0">{
*out = *in
if in.Taints != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Taints, &amp;out.Taints
*out = make([]corev1.Taint, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
<span class="cov0" title="0">if in.KubeletExtraArgs != nil </span><span class="cov0" title="0">{
in, out := &amp;in.KubeletExtraArgs, &amp;out.KubeletExtraArgs
*out = make(map[string]string, len(*in))
for key, val := range *in </span><span class="cov0" title="0">{
(*out)[key] = val
}</span>
}
<span class="cov0" title="0">if in.IgnorePreflightErrors != nil </span><span class="cov0" title="0">{
in, out := &amp;in.IgnorePreflightErrors, &amp;out.IgnorePreflightErrors
*out = make([]string, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRegistrationOptions.
func (in *NodeRegistrationOptions) DeepCopy() *NodeRegistrationOptions <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(NodeRegistrationOptions)
in.DeepCopyInto(out)
return out</span>
}
</pre>
<pre class="file" id="file55" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 util
import (
"context"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
"sigs.k8s.io/cluster-api/controllers/external"
expv1 "sigs.k8s.io/cluster-api/exp/api/v1alpha3"
"sigs.k8s.io/cluster-api/feature"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// ConfigOwner provides a data interface for different config owner types.
type ConfigOwner struct {
*unstructured.Unstructured
}
// IsInfrastructureReady extracts infrastructure status from the config owner.
func (co ConfigOwner) IsInfrastructureReady() bool <span class="cov8" title="1">{
infrastructureReady, _, err := unstructured.NestedBool(co.Object, "status", "infrastructureReady")
if err != nil </span><span class="cov0" title="0">{
return false
}</span>
<span class="cov8" title="1">return infrastructureReady</span>
}
// ClusterName extracts spec.clusterName from the config owner.
func (co ConfigOwner) ClusterName() string <span class="cov8" title="1">{
clusterName, _, err := unstructured.NestedString(co.Object, "spec", "clusterName")
if err != nil </span><span class="cov0" title="0">{
return ""
}</span>
<span class="cov8" title="1">return clusterName</span>
}
// DataSecretName extracts spec.bootstrap.dataSecretName from the config owner.
func (co ConfigOwner) DataSecretName() *string <span class="cov8" title="1">{
dataSecretName, exist, err := unstructured.NestedString(co.Object, "spec", "bootstrap", "dataSecretName")
if err != nil || !exist </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov8" title="1">return &amp;dataSecretName</span>
}
// IsControlPlaneMachine checks if an unstructured object is Machine with the control plane role.
func (co ConfigOwner) IsControlPlaneMachine() bool <span class="cov8" title="1">{
if co.GetKind() != "Machine" </span><span class="cov8" title="1">{
return false
}</span>
<span class="cov8" title="1">labels := co.GetLabels()
if labels == nil </span><span class="cov0" title="0">{
return false
}</span>
<span class="cov8" title="1">_, ok := labels[clusterv1.MachineControlPlaneLabelName]
return ok</span>
}
// GetConfigOwner returns the Unstructured object owning the current resource.
func GetConfigOwner(ctx context.Context, c client.Client, obj metav1.Object) (*ConfigOwner, error) <span class="cov8" title="1">{
allowedGKs := []schema.GroupKind{
{
Group: clusterv1.GroupVersion.Group,
Kind: "Machine",
},
}
if feature.Gates.Enabled(feature.MachinePool) </span><span class="cov8" title="1">{
allowedGKs = append(allowedGKs, schema.GroupKind{
Group: expv1.GroupVersion.Group,
Kind: "MachinePool",
})
}</span>
<span class="cov8" title="1">for _, ref := range obj.GetOwnerReferences() </span><span class="cov8" title="1">{
refGV, err := schema.ParseGroupVersion(ref.APIVersion)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to parse GroupVersion from %q", ref.APIVersion)
}</span>
<span class="cov8" title="1">refGVK := refGV.WithKind(ref.Kind)
for _, gk := range allowedGKs </span><span class="cov8" title="1">{
if refGVK.Group == gk.Group &amp;&amp; refGVK.Kind == gk.Kind </span><span class="cov8" title="1">{
return GetOwnerByRef(ctx, c, &amp;corev1.ObjectReference{
APIVersion: ref.APIVersion,
Kind: ref.Kind,
Name: ref.Name,
Namespace: obj.GetNamespace(),
})
}</span>
}
}
<span class="cov8" title="1">return nil, nil</span>
}
// GetOwnerByRef finds and returns the owner by looking at the object reference.
func GetOwnerByRef(ctx context.Context, c client.Client, ref *corev1.ObjectReference) (*ConfigOwner, error) <span class="cov8" title="1">{
obj, err := external.Get(ctx, c, ref, ref.Namespace)
if err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
<span class="cov8" title="1">return &amp;ConfigOwner{obj}, nil</span>
}
</pre>
<pre class="file" id="file56" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import "fmt"
const (
// ClusterctlLabelName is applied to all components managed by clusterctl.
ClusterctlLabelName = "clusterctl.cluster.x-k8s.io"
// ClusterctlCoreLabelName is applied to all the core objects managed by clusterctl.
ClusterctlCoreLabelName = "clusterctl.cluster.x-k8s.io/core"
// ClusterctlResourceLifecyleLabelName describes the lifecyle for a specific resource.
//
// Example: resources shared between instances of the same provider: CRDs,
// ValidatingWebhookConfiguration, MutatingWebhookConfiguration, and so on.
ClusterctlResourceLifecyleLabelName = "clusterctl.cluster.x-k8s.io/lifecycle"
)
// ResourceLifecycle configures the lifecycle of a resource
type ResourceLifecycle string
const (
// ResourceLifecycleShared is used to indicate that a resource is shared between
// multiple instances of a provider.
ResourceLifecycleShared = ResourceLifecycle("shared")
)
// ManifestLabel returns the cluster.x-k8s.io/provider label value for a provider/type.
//
// Note: the label uniquely describes the provider type and its kind (e.g. bootstrap-kubeadm);
// it's not meant to be used to describe each instance of a particular provider.
func ManifestLabel(name string, providerType ProviderType) string <span class="cov8" title="1">{
switch providerType </span>{
case CoreProviderType:<span class="cov8" title="1">
return name</span>
case BootstrapProviderType:<span class="cov8" title="1">
return fmt.Sprintf("bootstrap-%s", name)</span>
case ControlPlaneProviderType:<span class="cov8" title="1">
return fmt.Sprintf("control-plane-%s", name)</span>
case InfrastructureProviderType:<span class="cov8" title="1">
return fmt.Sprintf("infrastructure-%s", name)</span>
default:<span class="cov0" title="0">
return fmt.Sprintf("unknown-type-%s", name)</span>
}
}
</pre>
<pre class="file" id="file57" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/version"
)
// +kubebuilder:object:root=true
// Metadata for a provider repository
type Metadata struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// +optional
ReleaseSeries []ReleaseSeries `json:"releaseSeries"`
}
// ReleaseSeries maps a provider release series (major/minor) with a API Version of Cluster API (contract).
type ReleaseSeries struct {
// Major version of the release series
Major uint `json:"major,omitempty"`
// Minor version of the release series
Minor uint `json:"minor,omitempty"`
// Contract defines the Cluster API contract supported by this series.
//
// The value is an API Version, e.g. `v1alpha3`.
Contract string `json:"contract,omitempty"`
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;Metadata{})
}</span>
// GetReleaseSeriesForVersion returns the release series for a given version.
func (m *Metadata) GetReleaseSeriesForVersion(version *version.Version) *ReleaseSeries <span class="cov0" title="0">{
for _, releaseSeries := range m.ReleaseSeries </span><span class="cov0" title="0">{
if version.Major() == releaseSeries.Major &amp;&amp; version.Minor() == releaseSeries.Minor </span><span class="cov0" title="0">{
return &amp;releaseSeries
}</span>
}
<span class="cov0" title="0">return nil</span>
}
</pre>
<pre class="file" id="file58" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 v1alpha3
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
// +kubebuilder:resource:path=providers,scope=Namespaced,categories=cluster-api
// +kubebuilder:storageversion
// +kubebuilder:object:root=true
// +kubebuilder:printcolumn:name="Type",type="string",JSONPath=".provider"
// +kubebuilder:printcolumn:name="Provider",type="string",JSONPath=".type"
// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".version"
// +kubebuilder:printcolumn:name="Watch Namespace",type="string",JSONPath=".watchedNamespace"
// Provider defines an entry in the provider inventory.
type Provider struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// ProviderName indicates the name of the provider.
// +optional
ProviderName string `json:"providerName,omitempty"`
// Type indicates the type of the provider.
// See ProviderType for a list of supported values
// +optional
Type string `json:"type,omitempty"`
// Version indicates the component version.
// +optional
Version string `json:"version,omitempty"`
// WatchedNamespace indicates the namespace where the provider controller is is watching.
// if empty the provider controller is watching for objects in all namespaces.
// +optional
WatchedNamespace string `json:"watchedNamespace,omitempty"`
}
// ManifestLabel returns the cluster.x-k8s.io/provider label value for an entry in the provider inventory.
// Please note that this label uniquely identifies the provider, e.g. bootstrap-kubeadm, but not the instances of
// the provider, e.g. namespace-1/bootstrap-kubeadm and namespace-2/bootstrap-kubeadm
func (p *Provider) ManifestLabel() string <span class="cov8" title="1">{
return ManifestLabel(p.ProviderName, p.GetProviderType())
}</span>
// InstanceName return the a name that uniquely identifies an entry in the provider inventory.
// The instanceName is composed by the ManifestLabel and by the namespace where the provider is installed;
// the resulting value uniquely identify a provider instance because clusterctl does not support multiple
// instances of the same provider to be installed in the same namespace.
func (p *Provider) InstanceName() string <span class="cov0" title="0">{
return types.NamespacedName{Namespace: p.Namespace, Name: p.ManifestLabel()}.String()
}</span>
// HasWatchingOverlapWith returns true if the provider has an overlapping watching namespace with another provider.
func (p *Provider) HasWatchingOverlapWith(other Provider) bool <span class="cov0" title="0">{
return p.WatchedNamespace == "" || p.WatchedNamespace == other.WatchedNamespace || other.WatchedNamespace == ""
}</span>
// SameAs returns true if two providers have the same ProviderName and Type.
// Please note that there could be many instances of the same provider.
func (p *Provider) SameAs(other Provider) bool <span class="cov0" title="0">{
return p.ProviderName == other.ProviderName &amp;&amp; p.Type == other.Type
}</span>
// Equals returns true if two providers are identical (same name, provider name, type, version etc.).
func (p *Provider) Equals(other Provider) bool <span class="cov0" title="0">{
return p.Name == other.Name &amp;&amp;
p.Namespace == other.Namespace &amp;&amp;
p.ProviderName == other.ProviderName &amp;&amp;
p.Type == other.Type &amp;&amp;
p.WatchedNamespace == other.WatchedNamespace &amp;&amp;
p.Version == other.Version
}</span>
// GetProviderType parse the Provider.Type string field and return the typed representation.
func (p *Provider) GetProviderType() ProviderType <span class="cov8" title="1">{
switch t := ProviderType(p.Type); t </span>{
case
CoreProviderType,
BootstrapProviderType,
InfrastructureProviderType,
ControlPlaneProviderType:<span class="cov8" title="1">
return t</span>
default:<span class="cov0" title="0">
return ProviderTypeUnknown</span>
}
}
// ProviderType is a string representation of a Provider type.
type ProviderType string
const (
// CoreProviderType is a type reserved for Cluster API core repository.
CoreProviderType = ProviderType("CoreProvider")
// BootstrapProviderType is the type associated with codebases that provide
// bootstrapping capabilities.
BootstrapProviderType = ProviderType("BootstrapProvider")
// InfrastructureProviderType is the type associated with codebases that provide
// infrastructure capabilities.
InfrastructureProviderType = ProviderType("InfrastructureProvider")
// ControlPlaneProviderType is the type associated with codebases that provide
// control-plane capabilities.
ControlPlaneProviderType = ProviderType("ControlPlaneProvider")
// ProviderTypeUnknown is used when the type is unknown.
ProviderTypeUnknown = ProviderType("")
)
// Order return an integer that can be used to sort ProviderType values.
func (p ProviderType) Order() int <span class="cov0" title="0">{
switch p </span>{
case CoreProviderType:<span class="cov0" title="0">
return 0</span>
case BootstrapProviderType:<span class="cov0" title="0">
return 1</span>
case ControlPlaneProviderType:<span class="cov0" title="0">
return 2</span>
case InfrastructureProviderType:<span class="cov0" title="0">
return 3</span>
default:<span class="cov0" title="0">
return 4</span>
}
}
// +kubebuilder:object:root=true
// ProviderList contains a list of Provider
type ProviderList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Provider `json:"items"`
}
func (l *ProviderList) FilterByNamespace(namespace string) []Provider <span class="cov0" title="0">{
return l.filterBy(func(p Provider) bool </span><span class="cov0" title="0">{
return p.Namespace == namespace
}</span>)
}
func (l *ProviderList) FilterByProviderNameAndType(provider string, providerType ProviderType) []Provider <span class="cov0" title="0">{
return l.filterBy(func(p Provider) bool </span><span class="cov0" title="0">{
return p.ProviderName == provider &amp;&amp; p.Type == string(providerType)
}</span>)
}
func (l *ProviderList) FilterByType(providerType ProviderType) []Provider <span class="cov0" title="0">{
return l.filterBy(func(p Provider) bool </span><span class="cov0" title="0">{
return p.GetProviderType() == providerType
}</span>)
}
func (l *ProviderList) FilterCore() []Provider <span class="cov0" title="0">{
return l.filterBy(func(p Provider) bool </span><span class="cov0" title="0">{
return p.GetProviderType() == CoreProviderType
}</span>)
}
func (l *ProviderList) FilterNonCore() []Provider <span class="cov0" title="0">{
return l.filterBy(func(p Provider) bool </span><span class="cov0" title="0">{
return p.GetProviderType() != CoreProviderType
}</span>)
}
func (l *ProviderList) filterBy(predicate func(p Provider) bool) []Provider <span class="cov0" title="0">{
ret := []Provider{}
for _, i := range l.Items </span><span class="cov0" title="0">{
if predicate(i) </span><span class="cov0" title="0">{
ret = append(ret, i)
}</span>
}
<span class="cov0" title="0">return ret</span>
}
func init() <span class="cov8" title="1">{
SchemeBuilder.Register(&amp;Provider{}, &amp;ProviderList{})
}</span>
</pre>
<pre class="file" id="file59" style="display: none">// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1alpha3
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Metadata) DeepCopyInto(out *Metadata) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
if in.ReleaseSeries != nil </span><span class="cov0" title="0">{
in, out := &amp;in.ReleaseSeries, &amp;out.ReleaseSeries
*out = make([]ReleaseSeries, len(*in))
copy(*out, *in)
}</span>
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Metadata.
func (in *Metadata) DeepCopy() *Metadata <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Metadata)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Metadata) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Provider) DeepCopyInto(out *Provider) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&amp;out.ObjectMeta)
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Provider.
func (in *Provider) DeepCopy() *Provider <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(Provider)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Provider) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProviderList) DeepCopyInto(out *ProviderList) <span class="cov0" title="0">{
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&amp;out.ListMeta)
if in.Items != nil </span><span class="cov0" title="0">{
in, out := &amp;in.Items, &amp;out.Items
*out = make([]Provider, len(*in))
for i := range *in </span><span class="cov0" title="0">{
(*in)[i].DeepCopyInto(&amp;(*out)[i])
}</span>
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderList.
func (in *ProviderList) DeepCopy() *ProviderList <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ProviderList)
in.DeepCopyInto(out)
return out</span>
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ProviderList) DeepCopyObject() runtime.Object <span class="cov0" title="0">{
if c := in.DeepCopy(); c != nil </span><span class="cov0" title="0">{
return c
}</span>
<span class="cov0" title="0">return nil</span>
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReleaseSeries) DeepCopyInto(out *ReleaseSeries) <span class="cov0" title="0">{
*out = *in
}</span>
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReleaseSeries.
func (in *ReleaseSeries) DeepCopy() *ReleaseSeries <span class="cov0" title="0">{
if in == nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">out := new(ReleaseSeries)
in.DeepCopyInto(out)
return out</span>
}
</pre>
<pre class="file" id="file60" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 client
import (
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
)
// Client is exposes the clusterctl high-level client library.
type Client interface {
// GetProvidersConfig returns the list of providers configured for this instance of clusterctl.
GetProvidersConfig() ([]Provider, error)
// GetProviderComponents returns the provider components for a given provider with options including targetNamespace, watchingNamespace.
GetProviderComponents(provider string, providerType clusterctlv1.ProviderType, options ComponentsOptions) (Components, error)
// Init initializes a management cluster by adding the requested list of providers.
Init(options InitOptions) ([]Components, error)
// InitImages returns the list of images required for executing the init command.
InitImages(options InitOptions) ([]string, error)
// GetClusterTemplate returns a workload cluster template.
GetClusterTemplate(options GetClusterTemplateOptions) (Template, error)
// Delete deletes providers from a management cluster.
Delete(options DeleteOptions) error
// Move moves all the Cluster API objects existing in a namespace (or from all the namespaces if empty) to a target management cluster.
Move(options MoveOptions) error
// PlanUpgrade returns a set of suggested Upgrade plans for the cluster, and more specifically:
// - Each management group gets separated upgrade plans.
// - For each management group, an upgrade plan is generated for each API Version of Cluster API (contract) available, e.g.
// - Upgrade to the latest version in the the v1alpha2 series: ....
// - Upgrade to the latest version in the the v1alpha3 series: ....
PlanUpgrade(options PlanUpgradeOptions) ([]UpgradePlan, error)
// ApplyUpgrade executes an upgrade plan.
ApplyUpgrade(options ApplyUpgradeOptions) error
}
// clusterctlClient implements Client.
type clusterctlClient struct {
configClient config.Client
repositoryClientFactory RepositoryClientFactory
clusterClientFactory ClusterClientFactory
}
// RepositoryClientFactoryInput represents the inputs required by the
// RepositoryClientFactory
type RepositoryClientFactoryInput struct {
provider Provider
processor Processor
}
type RepositoryClientFactory func(RepositoryClientFactoryInput) (repository.Client, error)
// ClusterClientFactoryInput reporesents the inputs required by the
// ClusterClientFactory
type ClusterClientFactoryInput struct {
kubeconfig Kubeconfig
processor Processor
}
type ClusterClientFactory func(ClusterClientFactoryInput) (cluster.Client, error)
// Ensure clusterctlClient implements Client.
var _ Client = &amp;clusterctlClient{}
// Option is a configuration option supplied to New
type Option func(*clusterctlClient)
// InjectConfig allows to override the default configuration client used by clusterctl.
func InjectConfig(config config.Client) Option <span class="cov8" title="1">{
return func(c *clusterctlClient) </span><span class="cov8" title="1">{
c.configClient = config
}</span>
}
// InjectRepositoryFactory allows to override the default factory used for creating
// RepositoryClient objects.
func InjectRepositoryFactory(factory RepositoryClientFactory) Option <span class="cov8" title="1">{
return func(c *clusterctlClient) </span><span class="cov8" title="1">{
c.repositoryClientFactory = factory
}</span>
}
// InjectClusterClientFactory allows to override the default factory used for creating
// ClusterClient objects.
func InjectClusterClientFactory(factory ClusterClientFactory) Option <span class="cov8" title="1">{
return func(c *clusterctlClient) </span><span class="cov8" title="1">{
c.clusterClientFactory = factory
}</span>
}
// New returns a configClient.
func New(path string, options ...Option) (Client, error) <span class="cov0" title="0">{
return newClusterctlClient(path, options...)
}</span>
func newClusterctlClient(path string, options ...Option) (*clusterctlClient, error) <span class="cov8" title="1">{
client := &amp;clusterctlClient{}
for _, o := range options </span><span class="cov8" title="1">{
o(client)
}</span>
// if there is an injected config, use it, otherwise use the default one
// provided by the config low level library.
<span class="cov8" title="1">if client.configClient == nil </span><span class="cov0" title="0">{
c, err := config.New(path)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">client.configClient = c</span>
}
// if there is an injected RepositoryFactory, use it, otherwise use a default one.
<span class="cov8" title="1">if client.repositoryClientFactory == nil </span><span class="cov0" title="0">{
client.repositoryClientFactory = defaultRepositoryFactory(client.configClient)
}</span>
// if there is an injected ClusterFactory, use it, otherwise use a default one.
<span class="cov8" title="1">if client.clusterClientFactory == nil </span><span class="cov0" title="0">{
client.clusterClientFactory = defaultClusterFactory(client.configClient)
}</span>
<span class="cov8" title="1">return client, nil</span>
}
// defaultRepositoryFactory is a RepositoryClientFactory func the uses the default client provided by the repository low level library.
func defaultRepositoryFactory(configClient config.Client) RepositoryClientFactory <span class="cov0" title="0">{
return func(input RepositoryClientFactoryInput) (repository.Client, error) </span><span class="cov0" title="0">{
return repository.New(
input.provider,
configClient,
repository.InjectYamlProcessor(input.processor),
)
}</span>
}
// defaultClusterFactory is a ClusterClientFactory func the uses the default client provided by the cluster low level library.
func defaultClusterFactory(configClient config.Client) ClusterClientFactory <span class="cov0" title="0">{
return func(input ClusterClientFactoryInput) (cluster.Client, error) </span><span class="cov0" title="0">{
return cluster.New(
// Kubeconfig is a type alias to cluster.Kubeconfig
cluster.Kubeconfig(input.kubeconfig),
configClient,
cluster.InjectYamlProcessor(input.processor),
), nil
}</span>
}
</pre>
<pre class="file" id="file61" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cluster
import (
"time"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
manifests "sigs.k8s.io/cluster-api/cmd/clusterctl/config"
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
utilresource "sigs.k8s.io/cluster-api/util/resource"
utilyaml "sigs.k8s.io/cluster-api/util/yaml"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
embeddedCertManagerManifestPath = "cmd/clusterctl/config/assets/cert-manager.yaml"
waitCertManagerInterval = 1 * time.Second
waitCertManagerDefaultTimeout = 10 * time.Minute
certManagerImageComponent = "cert-manager"
timeoutConfigKey = "cert-manager-timeout"
)
// CertManagerClient has methods to work with cert-manager components in the cluster.
type CertManagerClient interface {
// EnsureWebhook makes sure the cert-manager Webhook is Available in a cluster:
// this is a requirement to install a new provider
EnsureWebhook() error
// Images return the list of images required for installing the cert-manager.
Images() ([]string, error)
}
// certManagerClient implements CertManagerClient .
type certManagerClient struct {
configClient config.Client
proxy Proxy
pollImmediateWaiter PollImmediateWaiter
}
// Ensure certManagerClient implements the CertManagerClient interface.
var _ CertManagerClient = &amp;certManagerClient{}
// newCertMangerClient returns a certManagerClient.
func newCertMangerClient(configClient config.Client, proxy Proxy, pollImmediateWaiter PollImmediateWaiter) *certManagerClient <span class="cov8" title="1">{
return &amp;certManagerClient{
configClient: configClient,
proxy: proxy,
pollImmediateWaiter: pollImmediateWaiter,
}
}</span>
// Images return the list of images required for installing the cert-manager.
func (cm *certManagerClient) Images() ([]string, error) <span class="cov0" title="0">{
// Checks if the cert-manager web-hook already exists, if yes, no additional images are required for the web-hook.
// Nb. we are ignoring the error so this operation can support listing images even if there is no an existing management cluster;
// in case there is no an existing management cluster, we assume there is no web-hook installed in the cluster.
hasWebhook, _ := cm.hasWebhook()
if hasWebhook </span><span class="cov0" title="0">{
return []string{}, nil
}</span>
// Gets the cert-manager objects from the embedded assets.
<span class="cov0" title="0">objs, err := cm.getManifestObjs()
if err != nil </span><span class="cov0" title="0">{
return []string{}, nil
}</span>
<span class="cov0" title="0">images, err := util.InspectImages(objs)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">return images, nil</span>
}
// EnsureWebhook makes sure the cert-manager Web-hook is Available in a cluster:
// this is a requirement to install a new provider
// Nb. In order to provide a simpler out-of-the box experience, the cert-manager manifest
// is embedded in the clusterctl binary.
func (cm *certManagerClient) EnsureWebhook() error <span class="cov0" title="0">{
log := logf.Log
// Checks if the cert-manager web-hook already exists, if yes, exit immediately
hasWebhook, err := cm.hasWebhook()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if hasWebhook </span><span class="cov0" title="0">{
return nil
}</span>
// Otherwise install cert-manager
<span class="cov0" title="0">log.Info("Installing cert-manager")
// Gets the cert-manager objects from the embedded assets.
objs, err := cm.getManifestObjs()
if err != nil </span><span class="cov0" title="0">{
return nil
}</span>
// installs the web-hook
<span class="cov0" title="0">createCertManagerBackoff := newWriteBackoff()
objs = utilresource.SortForCreate(objs)
for i := range objs </span><span class="cov0" title="0">{
o := objs[i]
log.V(5).Info("Creating", logf.UnstructuredToValues(o)...)
// Create the Kubernetes object.
// Nb. The operation is wrapped in a retry loop to make ensureCerts more resilient to unexpected conditions.
if err := retryWithExponentialBackoff(createCertManagerBackoff, func() error </span><span class="cov0" title="0">{
return cm.createObj(o)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
}
// Waits for for the cert-manager web-hook to be available.
<span class="cov0" title="0">log.Info("Waiting for cert-manager to be available...")
if err := cm.pollImmediateWaiter(waitCertManagerInterval, cm.getWaitTimeout(), func() (bool, error) </span><span class="cov0" title="0">{
webhook, err := cm.getWebhook()
if err != nil </span><span class="cov0" title="0">{
//Nb. we are ignoring the error so the pollImmediateWaiter will execute another retry
return false, nil
}</span>
<span class="cov0" title="0">if webhook == nil </span><span class="cov0" title="0">{
return false, nil
}</span>
<span class="cov0" title="0">isWebhookAvailable, err := cm.isWebhookAvailable(webhook)
if err != nil </span><span class="cov0" title="0">{
return false, err
}</span>
<span class="cov0" title="0">return isWebhookAvailable, nil</span>
}); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
func (cm *certManagerClient) getWaitTimeout() time.Duration <span class="cov8" title="1">{
log := logf.Log
timeout, err := cm.configClient.Variables().Get(timeoutConfigKey)
if err != nil </span><span class="cov0" title="0">{
return waitCertManagerDefaultTimeout
}</span>
<span class="cov8" title="1">timeoutDuration, err := time.ParseDuration(timeout)
if err != nil </span><span class="cov8" title="1">{
log.Info("Invalid value set for ", timeoutConfigKey, timeout)
return waitCertManagerDefaultTimeout
}</span>
<span class="cov8" title="1">return timeoutDuration</span>
}
// getManifestObjs gets the cert-manager manifest, convert to unstructured objects, and fix images
func (cm *certManagerClient) getManifestObjs() ([]unstructured.Unstructured, error) <span class="cov8" title="1">{
yaml, err := manifests.Asset(embeddedCertManagerManifestPath)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">objs, err := utilyaml.ToUnstructured(yaml)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to parse yaml for cert-manager manifest")
}</span>
<span class="cov8" title="1">objs, err = util.FixImages(objs, func(image string) (string, error) </span><span class="cov8" title="1">{
return cm.configClient.ImageMeta().AlterImage(certManagerImageComponent, image)
}</span>)
<span class="cov8" title="1">if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to apply image override to the cert-manager manifest")
}</span>
<span class="cov8" title="1">return objs, nil</span>
}
func (cm *certManagerClient) createObj(o unstructured.Unstructured) error <span class="cov0" title="0">{
c, err := cm.proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">labels := o.GetLabels()
if labels == nil </span><span class="cov0" title="0">{
labels = map[string]string{}
}</span>
<span class="cov0" title="0">labels[clusterctlv1.ClusterctlCoreLabelName] = "cert-manager"
o.SetLabels(labels)
if err = c.Create(ctx, &amp;o); err != nil </span><span class="cov0" title="0">{
if apierrors.IsAlreadyExists(err) </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">return errors.Wrapf(err, "failed to create cert-manager component: %s, %s/%s", o.GroupVersionKind(), o.GetNamespace(), o.GetName())</span>
}
<span class="cov0" title="0">return nil</span>
}
// getWebhook returns the cert-manager Webhook or nil if it does not exists.
func (cm *certManagerClient) getWebhook() (*unstructured.Unstructured, error) <span class="cov0" title="0">{
c, err := cm.proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">webhook := &amp;unstructured.Unstructured{}
webhook.SetAPIVersion("apiregistration.k8s.io/v1beta1")
webhook.SetKind("APIService")
webhook.SetName("v1beta1.webhook.cert-manager.io")
key, err := client.ObjectKeyFromObject(webhook)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">err = c.Get(ctx, key, webhook)
if err != nil </span><span class="cov0" title="0">{
if !apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">return nil, nil</span>
}
<span class="cov0" title="0">return webhook, nil</span>
}
// hasWebhook returns true if there is already a web-hook in the cluster
func (cm *certManagerClient) hasWebhook() (bool, error) <span class="cov0" title="0">{
// Checks if the cert-manager web-hook already exists, if yes, no additional images are required
webhook, err := cm.getWebhook()
if err != nil </span><span class="cov0" title="0">{
return false, errors.Wrap(err, "failed to check if the cert-manager web-hook exists")
}</span>
<span class="cov0" title="0">if webhook != nil </span><span class="cov0" title="0">{
return true, nil
}</span>
<span class="cov0" title="0">return false, nil</span>
}
// isWebhookAvailable returns true if the cert-manager web-hook has the condition type:Available with status:True.
// This is required to check the web-hook is working and ready to accept requests.
func (cm *certManagerClient) isWebhookAvailable(webhook *unstructured.Unstructured) (bool, error) <span class="cov0" title="0">{
conditions, found, err := unstructured.NestedSlice(webhook.Object, "status", "conditions")
if err != nil </span><span class="cov0" title="0">{
return false, errors.Wrap(err, "invalid cert-manager web-hook: failed to get conditions")
}</span>
// if status.conditions does not exists, we assume the web-hook is still starting
<span class="cov0" title="0">if !found </span><span class="cov0" title="0">{
return false, nil
}</span>
// look for the condition with type:Available and status:True or return false
<span class="cov0" title="0">for _, condition := range conditions </span><span class="cov0" title="0">{
conditionMap, ok := condition.(map[string]interface{})
if !ok </span><span class="cov0" title="0">{
return false, errors.Wrap(err, "invalid cert-manager web-hook: failed to parse conditions")
}</span>
<span class="cov0" title="0">conditionType, ok := conditionMap["type"]
if !ok </span><span class="cov0" title="0">{
return false, errors.Wrap(err, "invalid cert-manager web-hook: there are conditions without the type field")
}</span>
<span class="cov0" title="0">if conditionType != "Available" </span><span class="cov0" title="0">{
continue</span>
}
<span class="cov0" title="0">conditionStatus, ok := conditionMap["status"]
if !ok </span><span class="cov0" title="0">{
return false, errors.Wrapf(err, "invalid cert-manager web-hook: there %q condition does not have the status field", "Available")
}</span>
<span class="cov0" title="0">if conditionStatus == "True" </span><span class="cov0" title="0">{
return true, nil
}</span>
<span class="cov0" title="0">return false, nil</span>
}
<span class="cov0" title="0">return false, nil</span>
}
</pre>
<pre class="file" id="file62" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cluster
import (
"context"
"time"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/rest"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
yaml "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
minimumKubernetesVersion = "v1.16.0"
)
var (
ctx = context.TODO()
)
// Kubeconfig is a type that specifies inputs related to the actual
// kubeconfig.
type Kubeconfig struct {
// Path to the kubeconfig file
Path string
// Specify context within the kubeconfig file. If empty, cluster client
// will use the current context.
Context string
}
// Client is used to interact with a management cluster.
// A management cluster contains following categories of objects:
// - provider components (e.g. the CRDs, controllers, RBAC)
// - provider inventory items (e.g. the list of installed providers/versions)
// - provider objects (e.g. clusters, AWS clusters, machines etc.)
type Client interface {
// Kubeconfig returns the kubeconfig used to access to a management cluster.
Kubeconfig() Kubeconfig
// Proxy return the Proxy used for operating objects in the management cluster.
Proxy() Proxy
// CertManager returns a CertManagerClient that can be user for
// operating the cert-manager components in the cluster.
CertManager() CertManagerClient
// ProviderComponents returns a ComponentsClient object that can be user for
// operating provider components objects in the management cluster (e.g. the CRDs, controllers, RBAC).
ProviderComponents() ComponentsClient
// ProviderInventory returns a InventoryClient object that can be user for
// operating provider inventory stored in the management cluster (e.g. the list of installed providers/versions).
ProviderInventory() InventoryClient
// ProviderInstaller returns a ProviderInstaller that enforces consistency rules for provider installation,
// trying to prevent e.g. controllers fighting for objects, inconsistent versions, etc.
ProviderInstaller() ProviderInstaller
// ObjectMover returns an ObjectMover that implements support for moving Cluster API objects (e.g. clusters, AWS clusters, machines, etc.).
// from one management cluster to another management cluster.
ObjectMover() ObjectMover
// ProviderUpgrader returns a ProviderUpgrader that supports upgrading Cluster API providers.
ProviderUpgrader() ProviderUpgrader
// Template has methods to work with templates stored in the cluster.
Template() TemplateClient
}
// PollImmediateWaiter tries a condition func until it returns true, an error, or the timeout is reached.
type PollImmediateWaiter func(interval, timeout time.Duration, condition wait.ConditionFunc) error
// clusterClient implements Client.
type clusterClient struct {
configClient config.Client
kubeconfig Kubeconfig
proxy Proxy
repositoryClientFactory RepositoryClientFactory
pollImmediateWaiter PollImmediateWaiter
processor yaml.Processor
}
type RepositoryClientFactory func(provider config.Provider, configClient config.Client, options ...repository.Option) (repository.Client, error)
// ensure clusterClient implements Client.
var _ Client = &amp;clusterClient{}
func (c *clusterClient) Kubeconfig() Kubeconfig <span class="cov0" title="0">{
return c.kubeconfig
}</span>
func (c *clusterClient) Proxy() Proxy <span class="cov0" title="0">{
return c.proxy
}</span>
func (c *clusterClient) CertManager() CertManagerClient <span class="cov0" title="0">{
return newCertMangerClient(c.configClient, c.proxy, c.pollImmediateWaiter)
}</span>
func (c *clusterClient) ProviderComponents() ComponentsClient <span class="cov0" title="0">{
return newComponentsClient(c.proxy)
}</span>
func (c *clusterClient) ProviderInventory() InventoryClient <span class="cov0" title="0">{
return newInventoryClient(c.proxy, c.pollImmediateWaiter)
}</span>
func (c *clusterClient) ProviderInstaller() ProviderInstaller <span class="cov0" title="0">{
return newProviderInstaller(c.configClient, c.repositoryClientFactory, c.proxy, c.ProviderInventory(), c.ProviderComponents())
}</span>
func (c *clusterClient) ObjectMover() ObjectMover <span class="cov0" title="0">{
return newObjectMover(c.proxy, c.ProviderInventory())
}</span>
func (c *clusterClient) ProviderUpgrader() ProviderUpgrader <span class="cov0" title="0">{
return newProviderUpgrader(c.configClient, c.repositoryClientFactory, c.ProviderInventory(), c.ProviderComponents())
}</span>
func (c *clusterClient) Template() TemplateClient <span class="cov0" title="0">{
return newTemplateClient(TemplateClientInput{c.proxy, c.configClient, c.processor})
}</span>
// Option is a configuration option supplied to New
type Option func(*clusterClient)
// InjectProxy allows to override the default proxy used by clusterctl.
func InjectProxy(proxy Proxy) Option <span class="cov0" title="0">{
return func(c *clusterClient) </span><span class="cov0" title="0">{
c.proxy = proxy
}</span>
}
// InjectRepositoryFactory allows to override the default factory used for creating
// RepositoryClient objects.
func InjectRepositoryFactory(factory RepositoryClientFactory) Option <span class="cov0" title="0">{
return func(c *clusterClient) </span><span class="cov0" title="0">{
c.repositoryClientFactory = factory
}</span>
}
// InjectPollImmediateWaiter allows to override the default PollImmediateWaiter used by clusterctl.
func InjectPollImmediateWaiter(pollImmediateWaiter PollImmediateWaiter) Option <span class="cov0" title="0">{
return func(c *clusterClient) </span><span class="cov0" title="0">{
c.pollImmediateWaiter = pollImmediateWaiter
}</span>
}
// InjectYamlProcessor allows you to override the yaml processor that the
// cluster client uses. By default, the SimpleProcessor is used. This is
// true even if a nil processor is injected.
func InjectYamlProcessor(p yaml.Processor) Option <span class="cov8" title="1">{
return func(c *clusterClient) </span><span class="cov8" title="1">{
if p != nil </span><span class="cov8" title="1">{
c.processor = p
}</span>
}
}
// New returns a cluster.Client.
func New(kubeconfig Kubeconfig, configClient config.Client, options ...Option) Client <span class="cov0" title="0">{
return newClusterClient(kubeconfig, configClient, options...)
}</span>
func newClusterClient(kubeconfig Kubeconfig, configClient config.Client, options ...Option) *clusterClient <span class="cov8" title="1">{
client := &amp;clusterClient{
configClient: configClient,
kubeconfig: kubeconfig,
processor: yaml.NewSimpleProcessor(),
}
for _, o := range options </span><span class="cov8" title="1">{
o(client)
}</span>
// if there is an injected proxy, use it, otherwise use a default one
<span class="cov8" title="1">if client.proxy == nil </span><span class="cov8" title="1">{
client.proxy = newProxy(client.kubeconfig)
}</span>
// if there is an injected repositoryClientFactory, use it, otherwise use the default one
<span class="cov8" title="1">if client.repositoryClientFactory == nil </span><span class="cov8" title="1">{
client.repositoryClientFactory = repository.New
}</span>
// if there is an injected PollImmediateWaiter, use it, otherwise use the default one
<span class="cov8" title="1">if client.pollImmediateWaiter == nil </span><span class="cov8" title="1">{
client.pollImmediateWaiter = wait.PollImmediate
}</span>
<span class="cov8" title="1">return client</span>
}
type Proxy interface {
// GetConfig returns the rest.Config
GetConfig() (*rest.Config, error)
// CurrentNamespace returns the namespace from the current context in the kubeconfig file
CurrentNamespace() (string, error)
// ValidateKubernetesVersion returns an error if management cluster version less than minimumKubernetesVersion
ValidateKubernetesVersion() error
// NewClient returns a new controller runtime Client object for working on the management cluster
NewClient() (client.Client, error)
// ListResources returns all the Kubernetes objects with the given labels existing the listed namespaces.
ListResources(labels map[string]string, namespaces ...string) ([]unstructured.Unstructured, error)
}
// retryWithExponentialBackoff repeats an operation until it passes or the exponential backoff times out.
func retryWithExponentialBackoff(opts wait.Backoff, operation func() error) error <span class="cov8" title="1">{
log := logf.Log
i := 0
err := wait.ExponentialBackoff(opts, func() (bool, error) </span><span class="cov8" title="1">{
i++
if err := operation(); err != nil </span><span class="cov0" title="0">{
if i &lt; opts.Steps </span><span class="cov0" title="0">{
log.V(5).Info("Operation failed, retrying with backoff", "Cause", err.Error())
return false, nil
}</span>
<span class="cov0" title="0">return false, err</span>
}
<span class="cov8" title="1">return true, nil</span>
})
<span class="cov8" title="1">if err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "action failed after %d attempts", i)
}</span>
<span class="cov8" title="1">return nil</span>
}
// newWriteBackoff creates a new API Machinery backoff parameter set suitable for use with clusterctl write operations.
func newWriteBackoff() wait.Backoff <span class="cov8" title="1">{
// Return a exponential backoff configuration which returns durations for a total time of ~40s.
// Example: 0, .5s, 1.2s, 2.3s, 4s, 6s, 10s, 16s, 24s, 37s
// Jitter is added as a random fraction of the duration multiplied by the jitter factor.
return wait.Backoff{
Duration: 500 * time.Millisecond,
Factor: 1.5,
Steps: 10,
Jitter: 0.4,
}
}</span>
// newConnectBackoff creates a new API Machinery backoff parameter set suitable for use when clusterctl connect to a cluster.
func newConnectBackoff() wait.Backoff <span class="cov0" title="0">{
// Return a exponential backoff configuration which returns durations for a total time of ~15s.
// Example: 0, .25s, .6s, 1.2, 2.1s, 3.4s, 5.5s, 8s, 12s
// Jitter is added as a random fraction of the duration multiplied by the jitter factor.
return wait.Backoff{
Duration: 250 * time.Millisecond,
Factor: 1.5,
Steps: 9,
Jitter: 0.1,
}
}</span>
// newReadBackoff creates a new API Machinery backoff parameter set suitable for use with clusterctl read operations.
func newReadBackoff() wait.Backoff <span class="cov8" title="1">{
// Return a exponential backoff configuration which returns durations for a total time of ~15s.
// Example: 0, .25s, .6s, 1.2, 2.1s, 3.4s, 5.5s, 8s, 12s
// Jitter is added as a random fraction of the duration multiplied by the jitter factor.
return wait.Backoff{
Duration: 250 * time.Millisecond,
Factor: 1.5,
Steps: 9,
Jitter: 0.1,
}
}</span>
</pre>
<pre class="file" id="file63" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cluster
import (
"fmt"
"strings"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
kerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
"sigs.k8s.io/controller-runtime/pkg/client"
)
type DeleteOptions struct {
Provider clusterctlv1.Provider
IncludeNamespace bool
IncludeCRDs bool
}
// ComponentsClient has methods to work with provider components in the cluster.
type ComponentsClient interface {
// Create creates the provider components in the management cluster.
Create(objs []unstructured.Unstructured) error
// Delete deletes the provider components from the management cluster.
// The operation is designed to prevent accidental deletion of user created objects, so
// it is required to explicitly opt-in for the deletion of the namespace where the provider components are hosted
// and for the deletion of the provider's CRDs.
Delete(options DeleteOptions) error
}
// providerComponents implements ComponentsClient.
type providerComponents struct {
proxy Proxy
}
func (p *providerComponents) Create(objs []unstructured.Unstructured) error <span class="cov0" title="0">{
createComponentObjectBackoff := newWriteBackoff()
for i := range objs </span><span class="cov0" title="0">{
obj := objs[i]
// Create the Kubernetes object.
// Nb. The operation is wrapped in a retry loop to make Create more resilient to unexpected conditions.
if err := retryWithExponentialBackoff(createComponentObjectBackoff, func() error </span><span class="cov0" title="0">{
return p.createObj(obj)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
}
<span class="cov0" title="0">return nil</span>
}
func (p *providerComponents) createObj(obj unstructured.Unstructured) error <span class="cov0" title="0">{
log := logf.Log
c, err := p.proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// check if the component already exists, and eventually update it
<span class="cov0" title="0">currentR := &amp;unstructured.Unstructured{}
currentR.SetGroupVersionKind(obj.GroupVersionKind())
key := client.ObjectKey{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}
if err := c.Get(ctx, key, currentR); err != nil </span><span class="cov0" title="0">{
if !apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to get current provider object")
}</span>
//if it does not exists, create the component
<span class="cov0" title="0">log.V(5).Info("Creating", logf.UnstructuredToValues(obj)...)
if err := c.Create(ctx, &amp;obj); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to create provider object %s, %s/%s", obj.GroupVersionKind(), obj.GetNamespace(), obj.GetName())
}</span>
<span class="cov0" title="0">return nil</span>
}
// otherwise update the component
// NB. we are using client.Merge PatchOption so the new objects gets compared with the current one server side
<span class="cov0" title="0">log.V(5).Info("Patching", logf.UnstructuredToValues(obj)...)
obj.SetResourceVersion(currentR.GetResourceVersion())
if err := c.Patch(ctx, &amp;obj, client.Merge); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to patch provider object")
}</span>
<span class="cov0" title="0">return nil</span>
}
func (p *providerComponents) Delete(options DeleteOptions) error <span class="cov8" title="1">{
log := logf.Log
log.Info("Deleting", "Provider", options.Provider.Name, "Version", options.Provider.Version, "TargetNamespace", options.Provider.Namespace)
// Fetch all the components belonging to a provider.
// We want that the delete operation is able to clean-up everything in a the most common use case that is
// single-tenant management clusters. However, the downside of this is that this operation might be destructive
// in multi-tenant scenario, because a single operation could delete both instance specific and shared CRDs/web-hook components.
// This is considered acceptable because we are considering the multi-tenant scenario an advanced use case, and the assumption
// is that user in this case understand the potential impacts of this operation.
// TODO: in future we can eventually block delete --IncludeCRDs in case more than one instance of a provider exists
labels := map[string]string{
clusterctlv1.ClusterctlLabelName: "",
clusterv1.ProviderLabelName: options.Provider.ManifestLabel(),
}
namespaces := []string{options.Provider.Namespace}
if options.IncludeCRDs </span><span class="cov8" title="1">{
namespaces = append(namespaces, repository.WebhookNamespaceName)
}</span>
<span class="cov8" title="1">resources, err := p.proxy.ListResources(labels, namespaces...)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Filter the resources according to the delete options
<span class="cov8" title="1">resourcesToDelete := []unstructured.Unstructured{}
namespacesToDelete := sets.NewString()
instanceNamespacePrefix := fmt.Sprintf("%s-", options.Provider.Namespace)
for _, obj := range resources </span><span class="cov8" title="1">{
// If the CRDs (and by extensions, all the shared resources) should NOT be deleted, skip it;
// NB. Skipping CRDs deletion ensures that also the objects of Kind defined in the CRDs Kind are not deleted.
isSharedResource := util.IsSharedResource(obj)
if !options.IncludeCRDs &amp;&amp; isSharedResource </span><span class="cov8" title="1">{
continue</span>
}
// If the resource is a namespace
<span class="cov8" title="1">isNamespace := obj.GroupVersionKind().Kind == "Namespace"
if isNamespace </span><span class="cov8" title="1">{
// Skip all the namespaces not related to the provider instance being processed.
if obj.GetName() != options.Provider.Namespace </span><span class="cov0" title="0">{
continue</span>
}
// If the Namespace should NOT be deleted, skip it, otherwise keep track of the namespaces we are deleting;
// NB. Skipping Namespaces deletion ensures that also the objects hosted in the namespace but without the "clusterctl.cluster.x-k8s.io" and the "cluster.x-k8s.io/provider" label are not deleted.
<span class="cov8" title="1">if !options.IncludeNamespace </span><span class="cov8" title="1">{
continue</span>
}
<span class="cov8" title="1">namespacesToDelete.Insert(obj.GetName())</span>
}
// If not a shared resource or not a namespace
<span class="cov8" title="1">if !isSharedResource &amp;&amp; !isNamespace </span><span class="cov8" title="1">{
// If the resource is a cluster resource, skip it if the resource name does not start with the instance prefix.
// This is required because there are cluster resources like e.g. ClusterRoles and ClusterRoleBinding, which are instance specific;
// During the installation, clusterctl adds the instance namespace prefix to such resources (see fixRBAC), and so we can rely
// on that for deleting only the global resources belonging the the instance we are processing.
if util.IsClusterResource(obj.GetKind()) </span><span class="cov8" title="1">{
if !strings.HasPrefix(obj.GetName(), instanceNamespacePrefix) </span><span class="cov8" title="1">{
continue</span>
}
}
}
<span class="cov8" title="1">resourcesToDelete = append(resourcesToDelete, obj)</span>
}
// Delete all the provider components.
<span class="cov8" title="1">cs, err := p.proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">errList := []error{}
for i := range resourcesToDelete </span><span class="cov8" title="1">{
obj := resourcesToDelete[i]
// if the objects is in a namespace that is going to be deleted, skip deletion
// because everything that is contained in the namespace will be deleted by the Namespace controller
if namespacesToDelete.Has(obj.GetNamespace()) </span><span class="cov8" title="1">{
continue</span>
}
// Otherwise delete the object
<span class="cov8" title="1">log.V(5).Info("Deleting", logf.UnstructuredToValues(obj)...)
if err := cs.Delete(ctx, &amp;obj); err != nil </span><span class="cov0" title="0">{
if apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
// Tolerate IsNotFound error that might happen because we are not enforcing a deletion order
// that considers relation across objects (e.g. Deployments -&gt; ReplicaSets -&gt; Pods)
continue</span>
}
<span class="cov0" title="0">errList = append(errList, errors.Wrapf(err, "Error deleting object %s, %s/%s", obj.GroupVersionKind(), obj.GetNamespace(), obj.GetName()))</span>
}
}
<span class="cov8" title="1">return kerrors.NewAggregate(errList)</span>
}
// newComponentsClient returns a providerComponents.
func newComponentsClient(proxy Proxy) *providerComponents <span class="cov8" title="1">{
return &amp;providerComponents{
proxy: proxy,
}
}</span>
</pre>
<pre class="file" id="file64" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cluster
import (
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/version"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
)
// ProviderInstaller defines methods for enforcing consistency rules for provider installation.
type ProviderInstaller interface {
// Add adds a provider to the install queue.
// NB. By deferring the installation, the installer service can perform validation of the target state of the management cluster
// before actually starting the installation of new providers.
Add(repository.Components)
// Install performs the installation of the providers ready in the install queue.
Install() ([]repository.Components, error)
// Validate performs steps to validate a management cluster by looking at the current state and the providers in the queue.
// The following checks are performed in order to ensure a fully operational cluster:
// - There must be only one instance of the same provider per namespace
// - Instances of the same provider must not be fighting for objects (no watching overlap)
// - Providers must combine in valid management groups
// - All the providers must belong to one/only one management groups
// - All the providers in a management group must support the same API Version of Cluster API (contract)
Validate() error
// Images returns the list of images required for installing the providers ready in the install queue.
Images() []string
}
// providerInstaller implements ProviderInstaller
type providerInstaller struct {
configClient config.Client
repositoryClientFactory RepositoryClientFactory
proxy Proxy
providerComponents ComponentsClient
providerInventory InventoryClient
installQueue []repository.Components
}
var _ ProviderInstaller = &amp;providerInstaller{}
func (i *providerInstaller) Add(components repository.Components) <span class="cov0" title="0">{
i.installQueue = append(i.installQueue, components)
}</span>
func (i *providerInstaller) Install() ([]repository.Components, error) <span class="cov0" title="0">{
ret := make([]repository.Components, 0, len(i.installQueue))
for _, components := range i.installQueue </span><span class="cov0" title="0">{
if err := installComponentsAndUpdateInventory(components, i.providerComponents, i.providerInventory); err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">ret = append(ret, components)</span>
}
<span class="cov0" title="0">return ret, nil</span>
}
func installComponentsAndUpdateInventory(components repository.Components, providerComponents ComponentsClient, providerInventory InventoryClient) error <span class="cov0" title="0">{
log := logf.Log
log.Info("Installing", "Provider", components.ManifestLabel(), "Version", components.Version(), "TargetNamespace", components.TargetNamespace())
inventoryObject := components.InventoryObject()
// Check the list of providers currently in the cluster and decide if to install shared components (CRDs, web-hooks) or not.
// We are required to install shared components in two cases:
// - when this is the first instance of the provider being installed.
// - when the version of the provider being installed is newer than the max version already installed in the cluster.
// Nb. this assumes the newer version of shared components are fully retro-compatible.
providerList, err := providerInventory.List()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">installSharedComponents, err := shouldInstallSharedComponents(providerList, inventoryObject)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">if installSharedComponents </span><span class="cov0" title="0">{
log.V(1).Info("Creating shared objects", "Provider", components.ManifestLabel(), "Version", components.Version())
// TODO: currently shared components overrides existing shared components. As a future improvement we should
// consider if to delete (preserving CRDs) before installing so there will be no left-overs in case the list of resources changes
if err := providerComponents.Create(components.SharedObjs()); err != nil </span><span class="cov0" title="0">{
return err
}</span>
} else<span class="cov0" title="0"> {
log.V(1).Info("Shared objects already up to date", "Provider", components.ManifestLabel())
}</span>
// Then always install the instance specific objects and the then inventory item for the provider
<span class="cov0" title="0">log.V(1).Info("Creating instance objects", "Provider", components.ManifestLabel(), "Version", components.Version(), "TargetNamespace", components.TargetNamespace())
if err := providerComponents.Create(components.InstanceObjs()); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">log.V(1).Info("Creating inventory entry", "Provider", components.ManifestLabel(), "Version", components.Version(), "TargetNamespace", components.TargetNamespace())
if err := providerInventory.Create(inventoryObject); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
// shouldInstallSharedComponents checks if it is required to install shared components for a provider.
func shouldInstallSharedComponents(providerList *clusterctlv1.ProviderList, provider clusterctlv1.Provider) (bool, error) <span class="cov8" title="1">{
// Get the max version of the provider already installed in the cluster.
var maxVersion *version.Version
for _, other := range providerList.FilterByProviderNameAndType(provider.ProviderName, provider.GetProviderType()) </span><span class="cov8" title="1">{
otherVersion, err := version.ParseSemantic(other.Version)
if err != nil </span><span class="cov0" title="0">{
return false, errors.Wrapf(err, "failed to parse version for the %s provider", other.InstanceName())
}</span>
<span class="cov8" title="1">if maxVersion == nil || otherVersion.AtLeast(maxVersion) </span><span class="cov8" title="1">{
maxVersion = otherVersion
}</span>
}
// If there is no max version, this is the first instance of the provider being installed, so it is required
// to install the shared components.
<span class="cov8" title="1">if maxVersion == nil </span><span class="cov8" title="1">{
return true, nil
}</span>
// If the installed version is newer or equal than than the version of the provider being installed,
// return false because we should not down grade the shared components.
<span class="cov8" title="1">providerVersion, err := version.ParseSemantic(provider.Version)
if err != nil </span><span class="cov0" title="0">{
return false, errors.Wrapf(err, "failed to parse version for the %s provider", provider.InstanceName())
}</span>
<span class="cov8" title="1">if maxVersion.AtLeast(providerVersion) </span><span class="cov8" title="1">{
return false, nil
}</span>
// Otherwise, the version of the provider being installed is newer that the current max version, so it is
// required to install also the new version of shared components.
<span class="cov8" title="1">return true, nil</span>
}
func (i *providerInstaller) Validate() error <span class="cov8" title="1">{
// Get the list of providers currently in the cluster.
providerList, err := i.providerInventory.List()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Starts simulating what will be the resulting management cluster by adding to the list the providers in the installQueue.
// During this operation following checks are performed:
// - There must be only one instance of the same provider per namespace
// - Instances of the same provider must not be fighting for objects (no watching overlap)
<span class="cov8" title="1">for _, components := range i.installQueue </span><span class="cov8" title="1">{
if providerList, err = simulateInstall(providerList, components); err != nil </span><span class="cov8" title="1">{
return errors.Wrapf(err, "installing provider %q can lead to a non functioning management cluster", components.ManifestLabel())
}</span>
}
// Now that the provider list contains all the providers that are scheduled for install, gets the resulting management groups.
// During this operation following check is performed:
// - Providers must combine in valid management groups
// - All the providers must belong to one/only one management group
<span class="cov8" title="1">managementGroups, err := deriveManagementGroups(providerList)
if err != nil </span><span class="cov8" title="1">{
return err
}</span>
// Checks if all the providers supports the same API Version of Cluster API (contract) of the corresponding management group.
<span class="cov8" title="1">providerInstanceContracts := map[string]string{}
for _, components := range i.installQueue </span><span class="cov8" title="1">{
provider := components.InventoryObject()
// Gets the management group the providers belongs to, and then retrieve the API Version of Cluster API (contract)
// all the providers in the management group must support.
managementGroup := managementGroups.FindManagementGroupByProviderInstanceName(provider.InstanceName())
managementGroupContract, err := i.getProviderContract(providerInstanceContracts, managementGroup.CoreProvider)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Gets the API Version of Cluster API (contract) the provider support and compare it with the management group contract.
<span class="cov8" title="1">providerContract, err := i.getProviderContract(providerInstanceContracts, provider)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if providerContract != managementGroupContract </span><span class="cov8" title="1">{
return errors.Errorf("installing provider %q can lead to a non functioning management cluster: the target version for the provider supports the %s API Version of Cluster API (contract), while the management group is using %s", components.ManifestLabel(), providerContract, managementGroupContract)
}</span>
}
<span class="cov8" title="1">return nil</span>
}
// getProviderContract returns the API Version of Cluster API (contract) for a provider instance.
func (i *providerInstaller) getProviderContract(providerInstanceContracts map[string]string, provider clusterctlv1.Provider) (string, error) <span class="cov8" title="1">{
// If the contract for the provider instance is already known, return it.
if contract, ok := providerInstanceContracts[provider.InstanceName()]; ok </span><span class="cov8" title="1">{
return contract, nil
}</span>
// Otherwise get the contract for the providers instance.
// Gets the providers metadata.
<span class="cov8" title="1">configRepository, err := i.configClient.Providers().Get(provider.ProviderName, provider.GetProviderType())
if err != nil </span><span class="cov0" title="0">{
return "", err
}</span>
<span class="cov8" title="1">providerRepository, err := i.repositoryClientFactory(configRepository, i.configClient)
if err != nil </span><span class="cov0" title="0">{
return "", err
}</span>
<span class="cov8" title="1">latestMetadata, err := providerRepository.Metadata(provider.Version).Get()
if err != nil </span><span class="cov0" title="0">{
return "", err
}</span>
// Gets the contract for the current release.
<span class="cov8" title="1">currentVersion, err := version.ParseSemantic(provider.Version)
if err != nil </span><span class="cov0" title="0">{
return "", errors.Wrapf(err, "failed to parse current version for the %s provider", provider.InstanceName())
}</span>
<span class="cov8" title="1">releaseSeries := latestMetadata.GetReleaseSeriesForVersion(currentVersion)
if releaseSeries == nil </span><span class="cov0" title="0">{
return "", errors.Errorf("invalid provider metadata: version %s for the provider %s does not match any release series", provider.Version, provider.InstanceName())
}</span>
<span class="cov8" title="1">providerInstanceContracts[provider.InstanceName()] = releaseSeries.Contract
return releaseSeries.Contract, nil</span>
}
// simulateInstall adds a provider to the list of providers in a cluster (without installing it).
func simulateInstall(providerList *clusterctlv1.ProviderList, components repository.Components) (*clusterctlv1.ProviderList, error) <span class="cov8" title="1">{
provider := components.InventoryObject()
existingInstances := providerList.FilterByProviderNameAndType(provider.ProviderName, provider.GetProviderType())
// Target Namespace check
// Installing two instances of the same provider in the same namespace won't be supported
for _, i := range existingInstances </span><span class="cov8" title="1">{
if i.Namespace == provider.Namespace </span><span class="cov8" title="1">{
return providerList, errors.Errorf("there is already an instance of the %q provider installed in the %q namespace", provider.ManifestLabel(), provider.Namespace)
}</span>
}
// Watching Namespace check:
// If we are going to install an instance of a provider watching objects in namespaces already controlled by other providers
// then there will be providers fighting for objects...
<span class="cov8" title="1">for _, i := range existingInstances </span><span class="cov8" title="1">{
if i.HasWatchingOverlapWith(provider) </span><span class="cov8" title="1">{
return providerList, errors.Errorf("the new instance of the %q provider is going to watch for objects in the namespace %q that is already controlled by other instances of the same provider", provider.ManifestLabel(), provider.WatchedNamespace)
}</span>
}
<span class="cov8" title="1">providerList.Items = append(providerList.Items, provider)
return providerList, nil</span>
}
func (i *providerInstaller) Images() []string <span class="cov0" title="0">{
ret := sets.NewString()
for _, components := range i.installQueue </span><span class="cov0" title="0">{
ret = ret.Insert(components.Images()...)
}</span>
<span class="cov0" title="0">return ret.List()</span>
}
func newProviderInstaller(configClient config.Client, repositoryClientFactory RepositoryClientFactory, proxy Proxy, providerMetadata InventoryClient, providerComponents ComponentsClient) *providerInstaller <span class="cov0" title="0">{
return &amp;providerInstaller{
configClient: configClient,
repositoryClientFactory: repositoryClientFactory,
proxy: proxy,
providerComponents: providerComponents,
providerInventory: providerMetadata,
}
}</span>
</pre>
<pre class="file" id="file65" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cluster
import (
"time"
"github.com/pkg/errors"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/sets"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/config"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
utilyaml "sigs.k8s.io/cluster-api/util/yaml"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
embeddedCustomResourceDefinitionPath = "cmd/clusterctl/config/manifest/clusterctl-api.yaml"
waitInventoryCRDInterval = 250 * time.Millisecond
waitInventoryCRDTimeout = 1 * time.Minute
)
// InventoryClient exposes methods to interface with a cluster's provider inventory.
type InventoryClient interface {
// EnsureCustomResourceDefinitions installs the CRD required for creating inventory items, if necessary.
// Nb. In order to provide a simpler out-of-the box experience, the inventory CRD
// is embedded in the clusterctl binary.
EnsureCustomResourceDefinitions() error
// Create an inventory item for a provider instance installed in the cluster.
Create(clusterctlv1.Provider) error
// List returns the inventory items for all the provider instances installed in the cluster.
List() (*clusterctlv1.ProviderList, error)
// GetDefaultProviderName returns the default provider for a given ProviderType.
// In case there is only a single provider for a given type, e.g. only the AWS infrastructure Provider, it returns
// this as the default provider; In case there are more provider of the same type, there is no default provider.
GetDefaultProviderName(providerType clusterctlv1.ProviderType) (string, error)
// GetDefaultProviderVersion returns the default version for a given provider.
// In case there is only a single version installed for a given provider, e.g. only the v0.4.1 version for the AWS provider, it returns
// this as the default version; In case there are more version installed for the same provider, there is no default provider version.
GetDefaultProviderVersion(provider string, providerType clusterctlv1.ProviderType) (string, error)
// GetDefaultProviderNamespace returns the default namespace for a given provider.
// In case there is only a single instance for a given provider, e.g. only the AWS provider in the capa-system namespace, it returns
// this as the default namespace; In case there are more instances for the same provider installed in different namespaces, there is no default provider namespace.
GetDefaultProviderNamespace(provider string, providerType clusterctlv1.ProviderType) (string, error)
// GetManagementGroups returns the list of management groups defined in the management cluster.
GetManagementGroups() (ManagementGroupList, error)
}
// inventoryClient implements InventoryClient.
type inventoryClient struct {
proxy Proxy
pollImmediateWaiter PollImmediateWaiter
}
// ensure inventoryClient implements InventoryClient.
var _ InventoryClient = &amp;inventoryClient{}
// newInventoryClient returns a inventoryClient.
func newInventoryClient(proxy Proxy, pollImmediateWaiter PollImmediateWaiter) *inventoryClient <span class="cov8" title="1">{
return &amp;inventoryClient{
proxy: proxy,
pollImmediateWaiter: pollImmediateWaiter,
}
}</span>
func (p *inventoryClient) EnsureCustomResourceDefinitions() error <span class="cov8" title="1">{
log := logf.Log
if err := p.proxy.ValidateKubernetesVersion(); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Being this the first connection of many clusterctl operations, we want to fail fast if there is no
// connectivity to the cluster, so we try to get a client as a first thing.
// NB. NewClient has an internal retry loop that should mitigate temporary connection glitch; here we are
// trying to detect persistent connection problems (&gt;10s) before entering in longer retry loops while executing
// clusterctl operations.
<span class="cov8" title="1">_, err := p.proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Check the CRDs already exists, if yes, exit immediately.
// Nb. The operation is wrapped in a retry loop to make EnsureCustomResourceDefinitions more resilient to unexpected conditions.
<span class="cov8" title="1">var crdIsIstalled bool
listInventoryBackoff := newReadBackoff()
if err := retryWithExponentialBackoff(listInventoryBackoff, func() error </span><span class="cov8" title="1">{
var err error
crdIsIstalled, err = checkInventoryCRDs(p.proxy)
return err
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if crdIsIstalled </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov0" title="0">log.V(1).Info("Installing the clusterctl inventory CRD")
// Get the CRDs manifest from the embedded assets.
yaml, err := config.Asset(embeddedCustomResourceDefinitionPath)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Transform the yaml in a list of objects.
<span class="cov0" title="0">objs, err := utilyaml.ToUnstructured(yaml)
if err != nil </span><span class="cov0" title="0">{
return errors.Wrap(err, "failed to parse yaml for clusterctl inventory CRDs")
}</span>
// Install the CRDs.
<span class="cov0" title="0">createInventoryObjectBackoff := newWriteBackoff()
for i := range objs </span><span class="cov0" title="0">{
o := objs[i]
log.V(5).Info("Creating", logf.UnstructuredToValues(o)...)
// Create the Kubernetes object.
// Nb. The operation is wrapped in a retry loop to make EnsureCustomResourceDefinitions more resilient to unexpected conditions.
if err := retryWithExponentialBackoff(createInventoryObjectBackoff, func() error </span><span class="cov0" title="0">{
return p.createObj(o)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
// If the object is a CRDs, waits for it being Established.
<span class="cov0" title="0">if apiextensionsv1.SchemeGroupVersion.WithKind("CustomResourceDefinition").GroupKind() == o.GroupVersionKind().GroupKind() </span><span class="cov0" title="0">{
crdKey, err := client.ObjectKeyFromObject(&amp;o)
if err != nil </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">if err := p.pollImmediateWaiter(waitInventoryCRDInterval, waitInventoryCRDTimeout, func() (bool, error) </span><span class="cov0" title="0">{
c, err := p.proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return false, err
}</span>
<span class="cov0" title="0">crd := &amp;apiextensionsv1.CustomResourceDefinition{}
if err := c.Get(ctx, crdKey, crd); err != nil </span><span class="cov0" title="0">{
return false, err
}</span>
<span class="cov0" title="0">for _, c := range crd.Status.Conditions </span><span class="cov0" title="0">{
if c.Type == apiextensionsv1.Established &amp;&amp; c.Status == apiextensionsv1.ConditionTrue </span><span class="cov0" title="0">{
return true, nil
}</span>
}
<span class="cov0" title="0">return false, nil</span>
}); err != nil <span class="cov0" title="0">{
return errors.Wrapf(err, "failed to scale deployment")
}</span>
}
}
<span class="cov0" title="0">return nil</span>
}
// checkInventoryCRDs checks if the inventory CRDs are installed in the cluster.
func checkInventoryCRDs(proxy Proxy) (bool, error) <span class="cov8" title="1">{
c, err := proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return false, err
}</span>
<span class="cov8" title="1">l := &amp;clusterctlv1.ProviderList{}
if err = c.List(ctx, l); err == nil </span><span class="cov8" title="1">{
return true, nil
}</span>
<span class="cov0" title="0">if !apimeta.IsNoMatchError(err) </span><span class="cov0" title="0">{
return false, errors.Wrap(err, "failed to check if the clusterctl inventory CRD exists")
}</span>
<span class="cov0" title="0">return false, nil</span>
}
func (p *inventoryClient) createObj(o unstructured.Unstructured) error <span class="cov0" title="0">{
c, err := p.proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">labels := o.GetLabels()
if labels == nil </span><span class="cov0" title="0">{
labels = map[string]string{}
}</span>
<span class="cov0" title="0">labels[clusterctlv1.ClusterctlCoreLabelName] = "inventory"
o.SetLabels(labels)
if err := c.Create(ctx, &amp;o); err != nil </span><span class="cov0" title="0">{
if apierrors.IsAlreadyExists(err) </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">return errors.Wrapf(err, "failed to create clusterctl inventory CRDs component: %s, %s/%s", o.GroupVersionKind(), o.GetNamespace(), o.GetName())</span>
}
<span class="cov0" title="0">return nil</span>
}
func (p *inventoryClient) Create(m clusterctlv1.Provider) error <span class="cov8" title="1">{
// Create the Kubernetes object.
createInventoryObjectBackoff := newWriteBackoff()
return retryWithExponentialBackoff(createInventoryObjectBackoff, func() error </span><span class="cov8" title="1">{
cl, err := p.proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">currentProvider := &amp;clusterctlv1.Provider{}
key := client.ObjectKey{
Namespace: m.Namespace,
Name: m.Name,
}
if err := cl.Get(ctx, key, currentProvider); err != nil </span><span class="cov8" title="1">{
if !apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to get current provider object")
}</span>
//if it does not exists, create the provider object
<span class="cov8" title="1">if err := cl.Create(ctx, &amp;m); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to create provider object")
}</span>
<span class="cov8" title="1">return nil</span>
}
// otherwise patch the provider object
// NB. we are using client.Merge PatchOption so the new objects gets compared with the current one server side
<span class="cov8" title="1">m.SetResourceVersion(currentProvider.GetResourceVersion())
if err := cl.Patch(ctx, &amp;m, client.Merge); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to patch provider object")
}</span>
<span class="cov8" title="1">return nil</span>
})
}
func (p *inventoryClient) List() (*clusterctlv1.ProviderList, error) <span class="cov8" title="1">{
providerList := &amp;clusterctlv1.ProviderList{}
listProvidersBackoff := newReadBackoff()
if err := retryWithExponentialBackoff(listProvidersBackoff, func() error </span><span class="cov8" title="1">{
return listProviders(p.proxy, providerList)
}</span>); err != nil <span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">return providerList, nil</span>
}
// listProviders retrieves the list of provider inventory objects.
func listProviders(proxy Proxy, providerList *clusterctlv1.ProviderList) error <span class="cov8" title="1">{
cl, err := proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := cl.List(ctx, providerList); err != nil </span><span class="cov0" title="0">{
return errors.Wrap(err, "failed get providers")
}</span>
<span class="cov8" title="1">return nil</span>
}
func (p *inventoryClient) GetDefaultProviderName(providerType clusterctlv1.ProviderType) (string, error) <span class="cov0" title="0">{
providerList, err := p.List()
if err != nil </span><span class="cov0" title="0">{
return "", err
}</span>
// Group the providers by name, because we consider more instance of the same provider not relevant for the answer.
<span class="cov0" title="0">names := sets.NewString()
for _, p := range providerList.FilterByType(providerType) </span><span class="cov0" title="0">{
names.Insert(p.ProviderName)
}</span>
// If there is only one provider, this is the default
<span class="cov0" title="0">if names.Len() == 1 </span><span class="cov0" title="0">{
return names.List()[0], nil
}</span>
// There is no provider or more than one provider of this type; in both cases, a default provider name cannot be decided.
<span class="cov0" title="0">return "", nil</span>
}
func (p *inventoryClient) GetDefaultProviderVersion(provider string, providerType clusterctlv1.ProviderType) (string, error) <span class="cov0" title="0">{
providerList, err := p.List()
if err != nil </span><span class="cov0" title="0">{
return "", err
}</span>
// Group the provider instances by version.
<span class="cov0" title="0">versions := sets.NewString()
for _, p := range providerList.FilterByProviderNameAndType(provider, providerType) </span><span class="cov0" title="0">{
versions.Insert(p.Version)
}</span>
<span class="cov0" title="0">if versions.Len() == 1 </span><span class="cov0" title="0">{
return versions.List()[0], nil
}</span>
// There is no version installed or more than one version installed for this provider; in both cases, a default version for this provider cannot be decided.
<span class="cov0" title="0">return "", nil</span>
}
func (p *inventoryClient) GetDefaultProviderNamespace(provider string, providerType clusterctlv1.ProviderType) (string, error) <span class="cov0" title="0">{
providerList, err := p.List()
if err != nil </span><span class="cov0" title="0">{
return "", err
}</span>
// Group the providers by namespace
<span class="cov0" title="0">namespaces := sets.NewString()
for _, p := range providerList.FilterByProviderNameAndType(provider, providerType) </span><span class="cov0" title="0">{
namespaces.Insert(p.Namespace)
}</span>
<span class="cov0" title="0">if namespaces.Len() == 1 </span><span class="cov0" title="0">{
return namespaces.List()[0], nil
}</span>
// There is no provider or more than one namespace for this provider; in both cases, a default provider namespace cannot be decided.
<span class="cov0" title="0">return "", nil</span>
}
</pre>
<pre class="file" id="file66" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 cluster
import (
"strings"
"github.com/pkg/errors"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
)
// ManagementGroup is a group of providers composed by a CoreProvider and a set of Bootstrap/ControlPlane/Infrastructure providers
// watching objects in the same namespace. For example, a management group can be used for upgrades, in order to ensure all the providers
// in a management group support the same API Version of Cluster API (contract).
type ManagementGroup struct {
CoreProvider clusterctlv1.Provider
Providers []clusterctlv1.Provider
}
// Equals return true if two management groups have the same core provider.
func (mg *ManagementGroup) Equals(other *ManagementGroup) bool <span class="cov0" title="0">{
return mg.CoreProvider.Equals(other.CoreProvider)
}</span>
// GetProviderByInstanceName returns a specific provider instance.
func (mg *ManagementGroup) GetProviderByInstanceName(instanceName string) *clusterctlv1.Provider <span class="cov8" title="1">{
for _, provider := range mg.Providers </span><span class="cov8" title="1">{
if provider.InstanceName() == instanceName </span><span class="cov8" title="1">{
return &amp;provider
}</span>
}
<span class="cov0" title="0">return nil</span>
}
// ManagementGroupList defines a list of management groups
type ManagementGroupList []ManagementGroup
// FindManagementGroupByProviderInstanceName return the management group that hosts a given provider.
func (ml *ManagementGroupList) FindManagementGroupByProviderInstanceName(instanceName string) *ManagementGroup <span class="cov8" title="1">{
for _, managementGroup := range *ml </span><span class="cov8" title="1">{
if p := managementGroup.GetProviderByInstanceName(instanceName); p != nil </span><span class="cov8" title="1">{
return &amp;managementGroup
}</span>
}
<span class="cov0" title="0">return nil</span>
}
// deriveManagementGroups derives the management groups from a list of providers.
func deriveManagementGroups(providerList *clusterctlv1.ProviderList) (ManagementGroupList, error) <span class="cov8" title="1">{
// If any of the core providers watch the same namespace, we cannot define the management group.
if err := checkOverlappingCoreProviders(providerList); err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
// If any of the Bootstrap/ControlPlane/Infrastructure providers can't be combined with a core provider,
// or if any of the Bootstrap/ControlPlane/Infrastructure providers is watching objects controlled by more than one core provider
// we can't define a management group.
<span class="cov8" title="1">if err := checkOverlappingProviders(providerList); err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
// Composes the management group
<span class="cov8" title="1">managementGroups := ManagementGroupList{}
for _, coreProvider := range providerList.FilterCore() </span><span class="cov8" title="1">{
group := ManagementGroup{CoreProvider: coreProvider}
for _, provider := range providerList.Items </span><span class="cov8" title="1">{
if coreProvider.HasWatchingOverlapWith(provider) </span><span class="cov8" title="1">{
group.Providers = append(group.Providers, provider)
}</span>
}
<span class="cov8" title="1">managementGroups = append(managementGroups, group)</span>
}
<span class="cov8" title="1">return managementGroups, nil</span>
}
// checkOverlappingCoreProviders checks if there are core providers with overlapping watching namespaces, if yes, return error e.g.
// cluster-api in capi-system watching all namespaces and another cluster-api in capi-system2 watching capi-system2 (both are watching capi-system2)
// NB. This should not happen because init prevent the users to do so, but nevertheless we are double checking this before upgrades.
func checkOverlappingCoreProviders(providerList *clusterctlv1.ProviderList) error <span class="cov8" title="1">{
for _, provider := range providerList.FilterCore() </span><span class="cov8" title="1">{
for _, other := range providerList.FilterCore() </span><span class="cov8" title="1">{
// if the provider to compare is the same of the other provider, skip it
if provider.Equals(other) </span><span class="cov8" title="1">{
continue</span>
}
// check for overlapping namespaces
<span class="cov8" title="1">if provider.HasWatchingOverlapWith(other) </span><span class="cov8" title="1">{
return errors.Errorf("Unable to identify management groups: core providers %s and %s have overlapping watching namespaces",
provider.InstanceName(),
other.InstanceName(),
)
}</span>
}
}
<span class="cov8" title="1">return nil</span>
}
// checkOverlappingProviders checks if Bootstrap/ControlPlane/Infrastructure providers:
// 1) can't be combined with any core provider
// e.g. cluster-api in capi-system watching capi-system and aws in capa-system watching capa-system (they are watching different namespaces)
// 2) can be combined with more than one core provider
// e.g. cluster-api in capi-system1 watching all capi-system1, cluster-api in capi-system2 watching all capi-system2, aws in capa-system watching all namespaces (aws is working with both CAPI instances, but this is not a configuration supported by clusterctl)
func checkOverlappingProviders(providerList *clusterctlv1.ProviderList) error <span class="cov8" title="1">{
for _, provider := range providerList.FilterNonCore() </span><span class="cov8" title="1">{
// check for the core providers watching objects in the same namespace of the provider
var overlappingCoreProviders []string
for _, coreProvider := range providerList.FilterCore() </span><span class="cov8" title="1">{
if provider.HasWatchingOverlapWith(coreProvider) </span><span class="cov8" title="1">{
overlappingCoreProviders = append(overlappingCoreProviders, coreProvider.InstanceName())
}</span>
}
// if the provider does not overlap with any core provider, return error (it will not be part of any management group)
<span class="cov8" title="1">if len(overlappingCoreProviders) == 0 </span><span class="cov8" title="1">{
return errors.Errorf("Unable to identify management groups: provider %s can't be combined with any core provider",
provider.InstanceName(),
)
}</span>
// if the provider overlaps with more than one core provider, return error (it is part of two management groups --&gt; e.g. there could be potential upgrade conflicts)
<span class="cov8" title="1">if len(overlappingCoreProviders) &gt; 1 </span><span class="cov8" title="1">{
return errors.Errorf("Unable to identify management groups: provider %s is watching for objects in namespaces controlled by more than one core provider (%s)",
provider.InstanceName(),
strings.Join(overlappingCoreProviders, " ,"),
)
}</span>
}
<span class="cov8" title="1">return nil</span>
}
func (p *inventoryClient) GetManagementGroups() (ManagementGroupList, error) <span class="cov8" title="1">{
providerList, err := p.List()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">return deriveManagementGroups(providerList)</span>
}
</pre>
<pre class="file" id="file67" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 cluster
import (
"fmt"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
kerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/version"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// ObjectMover defines methods for moving Cluster API objects to another management cluster.
type ObjectMover interface {
// Move moves all the Cluster API objects existing in a namespace (or from all the namespaces if empty) to a target management cluster.
Move(namespace string, toCluster Client) error
}
// objectMover implements the ObjectMover interface.
type objectMover struct {
fromProxy Proxy
fromProviderInventory InventoryClient
}
// ensure objectMover implements the ObjectMover interface.
var _ ObjectMover = &amp;objectMover{}
func (o *objectMover) Move(namespace string, toCluster Client) error <span class="cov0" title="0">{
log := logf.Log
log.Info("Performing move...")
objectGraph := newObjectGraph(o.fromProxy)
// checks that all the required providers in place in the target cluster.
if err := o.checkTargetProviders(namespace, toCluster.ProviderInventory()); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Gets all the types defines by the CRDs installed by clusterctl plus the ConfigMap/Secret core types.
<span class="cov0" title="0">types, err := objectGraph.getDiscoveryTypes()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Discovery the object graph for the selected types:
// - Nodes are defined the Kubernetes objects (Clusters, Machines etc.) identified during the discovery process.
// - Edges are derived by the OwnerReferences between nodes.
<span class="cov0" title="0">if err := objectGraph.Discovery(namespace, types); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Checks if Cluster API has already completed the provisioning of the infrastructure for the objects involved in the move operation.
// This is required because if the infrastructure is provisioned, then we can reasonably assume that the objects we are moving are
// not currently waiting for long-running reconciliation loops, and so we can safely rely on the pause field on the Cluster object
// for blocking any further object reconciliation on the source objects.
<span class="cov0" title="0">if err := o.checkProvisioningCompleted(objectGraph); err != nil </span><span class="cov0" title="0">{
return err
}</span>
//TODO: consider if to add additional preflight checks ensuring the object graph is complete (no virtual nodes left)
// Move the objects to the target cluster.
<span class="cov0" title="0">if err := o.move(objectGraph, toCluster.Proxy()); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}
func newObjectMover(fromProxy Proxy, fromProviderInventory InventoryClient) *objectMover <span class="cov0" title="0">{
return &amp;objectMover{
fromProxy: fromProxy,
fromProviderInventory: fromProviderInventory,
}
}</span>
// checkProvisioningCompleted checks if Cluster API has already completed the provisioning of the infrastructure for the objects involved in the move operation.
func (o *objectMover) checkProvisioningCompleted(graph *objectGraph) error <span class="cov8" title="1">{
errList := []error{}
// Checking all the clusters have infrastructure is ready
readClusterBackoff := newReadBackoff()
clusters := graph.getClusters()
for i := range clusters </span><span class="cov8" title="1">{
cluster := clusters[i]
clusterObj := &amp;clusterv1.Cluster{}
if err := retryWithExponentialBackoff(readClusterBackoff, func() error </span><span class="cov8" title="1">{
return getClusterObj(o.fromProxy, cluster, clusterObj)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if !clusterObj.Status.InfrastructureReady </span><span class="cov8" title="1">{
errList = append(errList, errors.Errorf("cannot start the move operation while %q %s/%s is still provisioning the infrastructure", clusterObj.GroupVersionKind(), clusterObj.GetNamespace(), clusterObj.GetName()))
continue</span>
}
<span class="cov8" title="1">if !clusterObj.Status.ControlPlaneInitialized </span><span class="cov8" title="1">{
errList = append(errList, errors.Errorf("cannot start the move operation while the control plane for %q %s/%s is not yet initialized", clusterObj.GroupVersionKind(), clusterObj.GetNamespace(), clusterObj.GetName()))
continue</span>
}
<span class="cov8" title="1">if clusterObj.Spec.ControlPlaneRef != nil &amp;&amp; !clusterObj.Status.ControlPlaneReady </span><span class="cov8" title="1">{
errList = append(errList, errors.Errorf("cannot start the move operation while the control plane for %q %s/%s is not yet ready", clusterObj.GroupVersionKind(), clusterObj.GetNamespace(), clusterObj.GetName()))
continue</span>
}
}
// Checking all the machine have a NodeRef
// Nb. NodeRef is considered a better signal than InfrastructureReady, because it ensures the node in the workload cluster is up and running.
<span class="cov8" title="1">readMachinesBackoff := newReadBackoff()
machines := graph.getMachines()
for i := range machines </span><span class="cov8" title="1">{
machine := machines[i]
machineObj := &amp;clusterv1.Machine{}
if err := retryWithExponentialBackoff(readMachinesBackoff, func() error </span><span class="cov8" title="1">{
return getMachineObj(o.fromProxy, machine, machineObj)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if machineObj.Status.NodeRef == nil </span><span class="cov8" title="1">{
errList = append(errList, errors.Errorf("cannot start the move operation while %q %s/%s is still provisioning the node", machineObj.GroupVersionKind(), machineObj.GetNamespace(), machineObj.GetName()))
}</span>
}
<span class="cov8" title="1">return kerrors.NewAggregate(errList)</span>
}
// getClusterObj retrieves the the clusterObj corresponding to a node with type Cluster.
func getClusterObj(proxy Proxy, cluster *node, clusterObj *clusterv1.Cluster) error <span class="cov8" title="1">{
c, err := proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">clusterObjKey := client.ObjectKey{
Namespace: cluster.identity.Namespace,
Name: cluster.identity.Name,
}
if err := c.Get(ctx, clusterObjKey, clusterObj); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error reading %q %s/%s",
clusterObj.GroupVersionKind(), clusterObj.GetNamespace(), clusterObj.GetName())
}</span>
<span class="cov8" title="1">return nil</span>
}
// getMachineObj retrieves the the machineObj corresponding to a node with type Machine.
func getMachineObj(proxy Proxy, machine *node, machineObj *clusterv1.Machine) error <span class="cov8" title="1">{
c, err := proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">machineObjKey := client.ObjectKey{
Namespace: machine.identity.Namespace,
Name: machine.identity.Name,
}
if err := c.Get(ctx, machineObjKey, machineObj); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error reading %q %s/%s",
machineObj.GroupVersionKind(), machineObj.GetNamespace(), machineObj.GetName())
}</span>
<span class="cov8" title="1">return nil</span>
}
// Move moves all the Cluster API objects existing in a namespace (or from all the namespaces if empty) to a target management cluster
func (o *objectMover) move(graph *objectGraph, toProxy Proxy) error <span class="cov8" title="1">{
log := logf.Log
clusters := graph.getClusters()
log.Info("Moving Cluster API objects", "Clusters", len(clusters))
// Sets the pause field on the Cluster object in the source management cluster, so the controllers stop reconciling it.
log.V(1).Info("Pausing the source cluster")
if err := setClusterPause(o.fromProxy, clusters, true); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Ensure all the expected target namespaces are in place before creating objects.
<span class="cov8" title="1">log.V(1).Info("Creating target namespaces, if missing")
if err := o.ensureNamespaces(graph, toProxy); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Define the move sequence by processing the ownerReference chain, so we ensure that a Kubernetes object is moved only after its owners.
// The sequence is bases on object graph nodes, each one representing a Kubernetes object; nodes are grouped, so bulk of nodes can be moved in parallel. e.g.
// - All the Clusters should be moved first (group 1, processed in parallel)
// - All the MachineDeployments should be moved second (group 1, processed in parallel)
// - then all the MachineSets, then all the Machines, etc.
<span class="cov8" title="1">moveSequence := getMoveSequence(graph)
// Create all objects group by group, ensuring all the ownerReferences are re-created.
log.Info("Creating objects in the target cluster")
for groupIndex := 0; groupIndex &lt; len(moveSequence.groups); groupIndex++ </span><span class="cov8" title="1">{
if err := o.createGroup(moveSequence.getGroup(groupIndex), toProxy); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
// Delete all objects group by group in reverse order.
<span class="cov8" title="1">log.Info("Deleting objects from the source cluster")
for groupIndex := len(moveSequence.groups) - 1; groupIndex &gt;= 0; groupIndex-- </span><span class="cov8" title="1">{
if err := o.deleteGroup(moveSequence.getGroup(groupIndex)); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
// Reset the pause field on the Cluster object in the target management cluster, so the controllers start reconciling it.
<span class="cov8" title="1">log.V(1).Info("Resuming the target cluster")
if err := setClusterPause(toProxy, clusters, false); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// moveSequence defines a list of group of moveGroups
type moveSequence struct {
groups []moveGroup
nodesMap map[*node]empty
}
// moveGroup defines is a list of nodes read from the object graph that can be moved in parallel.
type moveGroup []*node
func (s *moveSequence) addGroup(group moveGroup) <span class="cov8" title="1">{
// Add the group
s.groups = append(s.groups, group)
// Add all the nodes in the group to the nodeMap so we can check if a node is already in the move sequence or not
for _, n := range group </span><span class="cov8" title="1">{
s.nodesMap[n] = empty{}
}</span>
}
func (s *moveSequence) hasNode(n *node) bool <span class="cov8" title="1">{
_, ok := s.nodesMap[n]
return ok
}</span>
func (s *moveSequence) getGroup(i int) moveGroup <span class="cov8" title="1">{
return s.groups[i]
}</span>
// Define the move sequence by processing the ownerReference chain.
func getMoveSequence(graph *objectGraph) *moveSequence <span class="cov8" title="1">{
moveSequence := &amp;moveSequence{
groups: []moveGroup{},
nodesMap: make(map[*node]empty),
}
for </span><span class="cov8" title="1">{
// Determine the next move group by processing all the nodes in the graph that belong to a Cluster.
// NB. it is necessary to filter out nodes not belonging to a cluster because e.g. discovery reads all the secrets,
// but only few of them are related to Clusters/Machines etc.
moveGroup := moveGroup{}
for _, n := range graph.getNodesWithClusterTenants() </span><span class="cov8" title="1">{
// If the node was already included in the moveSequence, skip it.
if moveSequence.hasNode(n) </span><span class="cov8" title="1">{
continue</span>
}
// Check if all the ownerReferences are already included in the move sequence; if yes, add the node to move group,
// otherwise skip it (the node will be re-processed in the next group).
<span class="cov8" title="1">ownersInPlace := true
for owner := range n.owners </span><span class="cov8" title="1">{
if !moveSequence.hasNode(owner) </span><span class="cov8" title="1">{
ownersInPlace = false
break</span>
}
}
<span class="cov8" title="1">for owner := range n.softOwners </span><span class="cov8" title="1">{
if !moveSequence.hasNode(owner) </span><span class="cov8" title="1">{
ownersInPlace = false
break</span>
}
}
<span class="cov8" title="1">if ownersInPlace </span><span class="cov8" title="1">{
moveGroup = append(moveGroup, n)
}</span>
}
// If the resulting move group is empty it means that all the nodes are already in the sequence, so exit.
<span class="cov8" title="1">if len(moveGroup) == 0 </span><span class="cov8" title="1">{
break</span>
}
<span class="cov8" title="1">moveSequence.addGroup(moveGroup)</span>
}
<span class="cov8" title="1">return moveSequence</span>
}
// setClusterPause sets the paused field on nodes referring to Cluster objects.
func setClusterPause(proxy Proxy, clusters []*node, value bool) error <span class="cov8" title="1">{
log := logf.Log
patch := client.RawPatch(types.MergePatchType, []byte(fmt.Sprintf("{\"spec\":{\"paused\":%t}}", value)))
setClusterPauseBackoff := newWriteBackoff()
for i := range clusters </span><span class="cov8" title="1">{
cluster := clusters[i]
log.V(5).Info("Set Cluster.Spec.Paused", "Paused", value, "Cluster", cluster.identity.Name, "Namespace", cluster.identity.Namespace)
// Nb. The operation is wrapped in a retry loop to make setClusterPause more resilient to unexpected conditions.
if err := retryWithExponentialBackoff(setClusterPauseBackoff, func() error </span><span class="cov8" title="1">{
return patchCluster(proxy, cluster, patch)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
}
<span class="cov8" title="1">return nil</span>
}
// patchCluster applies a patch to a node referring to a Cluster object.
func patchCluster(proxy Proxy, cluster *node, patch client.Patch) error <span class="cov8" title="1">{
cFrom, err := proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">clusterObj := &amp;clusterv1.Cluster{}
clusterObjKey := client.ObjectKey{
Namespace: cluster.identity.Namespace,
Name: cluster.identity.Name,
}
if err := cFrom.Get(ctx, clusterObjKey, clusterObj); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error reading %q %s/%s",
clusterObj.GroupVersionKind(), clusterObj.GetNamespace(), clusterObj.GetName())
}</span>
<span class="cov8" title="1">if err := cFrom.Patch(ctx, clusterObj, patch); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error pausing reconciliation for %q %s/%s",
clusterObj.GroupVersionKind(), clusterObj.GetNamespace(), clusterObj.GetName())
}</span>
<span class="cov8" title="1">return nil</span>
}
// ensureNamespaces ensures all the expected target namespaces are in place before creating objects.
func (o *objectMover) ensureNamespaces(graph *objectGraph, toProxy Proxy) error <span class="cov8" title="1">{
ensureNamespaceBackoff := newWriteBackoff()
namespaces := sets.NewString()
for _, node := range graph.getNodesWithClusterTenants() </span><span class="cov8" title="1">{
namespace := node.identity.Namespace
// If the namespace was already processed, skip it.
if namespaces.Has(namespace) </span><span class="cov8" title="1">{
continue</span>
}
<span class="cov8" title="1">namespaces.Insert(namespace)
if err := retryWithExponentialBackoff(ensureNamespaceBackoff, func() error </span><span class="cov8" title="1">{
return o.ensureNamespace(toProxy, namespace)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
}
<span class="cov8" title="1">return nil</span>
}
// ensureNamespace ensures a target namespaces is in place before creating objects.
func (o *objectMover) ensureNamespace(toProxy Proxy, namespace string) error <span class="cov8" title="1">{
log := logf.Log
cs, err := toProxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Otherwise check if namespace exists (also dealing with RBAC restrictions).
<span class="cov8" title="1">ns := &amp;corev1.Namespace{}
key := client.ObjectKey{
Name: namespace,
}
err = cs.Get(ctx, key, ns)
if err == nil </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov8" title="1">if apierrors.IsForbidden(err) </span><span class="cov0" title="0">{
namespaces := &amp;corev1.NamespaceList{}
namespaceExists := false
for </span><span class="cov0" title="0">{
if err := cs.List(ctx, namespaces, client.Continue(namespaces.Continue)); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">for _, ns := range namespaces.Items </span><span class="cov0" title="0">{
if ns.Name == namespace </span><span class="cov0" title="0">{
namespaceExists = true
break</span>
}
}
<span class="cov0" title="0">if namespaces.Continue == "" </span><span class="cov0" title="0">{
break</span>
}
}
<span class="cov0" title="0">if namespaceExists </span><span class="cov0" title="0">{
return nil
}</span>
}
<span class="cov8" title="1">if !apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
return err
}</span>
// If the namespace does not exists, create it.
<span class="cov8" title="1">ns = &amp;corev1.Namespace{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Namespace",
},
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
log.V(1).Info("Creating", ns.Kind, ns.Name)
if err := cs.Create(ctx, ns); err != nil &amp;&amp; !apierrors.IsAlreadyExists(err) </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
// createGroup creates all the Kubernetes objects into the target management cluster corresponding to the object graph nodes in a moveGroup.
func (o *objectMover) createGroup(group moveGroup, toProxy Proxy) error <span class="cov8" title="1">{
createTargetObjectBackoff := newWriteBackoff()
errList := []error{}
for i := range group </span><span class="cov8" title="1">{
nodeToCreate := group[i]
// Creates the Kubernetes object corresponding to the nodeToCreate.
// Nb. The operation is wrapped in a retry loop to make move more resilient to unexpected conditions.
err := retryWithExponentialBackoff(createTargetObjectBackoff, func() error </span><span class="cov8" title="1">{
return o.createTargetObject(nodeToCreate, toProxy)
}</span>)
<span class="cov8" title="1">if err != nil </span><span class="cov0" title="0">{
errList = append(errList, err)
}</span>
}
<span class="cov8" title="1">if len(errList) &gt; 0 </span><span class="cov0" title="0">{
return kerrors.NewAggregate(errList)
}</span>
<span class="cov8" title="1">return nil</span>
}
// createTargetObject creates the Kubernetes object in the target Management cluster corresponding to the object graph node, taking care of restoring the OwnerReference with the owner nodes, if any.
func (o *objectMover) createTargetObject(nodeToCreate *node, toProxy Proxy) error <span class="cov8" title="1">{
log := logf.Log
log.V(1).Info("Creating", nodeToCreate.identity.Kind, nodeToCreate.identity.Name, "Namespace", nodeToCreate.identity.Namespace)
cFrom, err := o.fromProxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Get the source object
<span class="cov8" title="1">obj := &amp;unstructured.Unstructured{}
obj.SetAPIVersion(nodeToCreate.identity.APIVersion)
obj.SetKind(nodeToCreate.identity.Kind)
objKey := client.ObjectKey{
Namespace: nodeToCreate.identity.Namespace,
Name: nodeToCreate.identity.Name,
}
if err := cFrom.Get(ctx, objKey, obj); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error reading %q %s/%s",
obj.GroupVersionKind(), obj.GetNamespace(), obj.GetName())
}</span>
// New objects cannot have a specified resource version. Clear it out.
<span class="cov8" title="1">obj.SetResourceVersion("")
// Removes current OwnerReferences
obj.SetOwnerReferences(nil)
// Recreate all the OwnerReferences using the newUID of the owner nodes.
if len(nodeToCreate.owners) &gt; 0 </span><span class="cov8" title="1">{
ownerRefs := []metav1.OwnerReference{}
for ownerNode := range nodeToCreate.owners </span><span class="cov8" title="1">{
ownerRef := metav1.OwnerReference{
APIVersion: ownerNode.identity.APIVersion,
Kind: ownerNode.identity.Kind,
Name: ownerNode.identity.Name,
UID: ownerNode.newUID, // Use the owner's newUID read from the target management cluster (instead of the UID read during discovery).
}
// Restores the attributes of the OwnerReference.
if attributes, ok := nodeToCreate.owners[ownerNode]; ok </span><span class="cov8" title="1">{
ownerRef.Controller = attributes.Controller
ownerRef.BlockOwnerDeletion = attributes.BlockOwnerDeletion
}</span>
<span class="cov8" title="1">ownerRefs = append(ownerRefs, ownerRef)</span>
}
<span class="cov8" title="1">obj.SetOwnerReferences(ownerRefs)</span>
}
// Creates the targetObj into the target management cluster.
<span class="cov8" title="1">cTo, err := toProxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := cTo.Create(ctx, obj); err != nil </span><span class="cov0" title="0">{
if !apierrors.IsAlreadyExists(err) </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error creating %q %s/%s",
obj.GroupVersionKind(), obj.GetNamespace(), obj.GetName())
}</span>
// If the object already exists, try to update it.
// Nb. This should not happen, but it is supported to make move more resilient to unexpected interrupt/restarts of the move process.
<span class="cov0" title="0">log.V(5).Info("Object already exists, updating", nodeToCreate.identity.Kind, nodeToCreate.identity.Name, "Namespace", nodeToCreate.identity.Namespace)
// Retrieve the UID and the resource version for the update.
existingTargetObj := &amp;unstructured.Unstructured{}
existingTargetObj.SetAPIVersion(obj.GetAPIVersion())
existingTargetObj.SetKind(obj.GetKind())
if err := cTo.Get(ctx, objKey, existingTargetObj); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error reading resource for %q %s/%s",
existingTargetObj.GroupVersionKind(), existingTargetObj.GetNamespace(), existingTargetObj.GetName())
}</span>
<span class="cov0" title="0">obj.SetUID(existingTargetObj.GetUID())
obj.SetResourceVersion(existingTargetObj.GetResourceVersion())
if err := cTo.Update(ctx, obj); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error updating %q %s/%s",
obj.GroupVersionKind(), obj.GetNamespace(), obj.GetName())
}</span>
}
// Stores the newUID assigned to the newly created object.
<span class="cov8" title="1">nodeToCreate.newUID = obj.GetUID()
return nil</span>
}
// deleteGroup deletes all the Kubernetes objects from the source management cluster corresponding to the object graph nodes in a moveGroup.
func (o *objectMover) deleteGroup(group moveGroup) error <span class="cov8" title="1">{
deleteSourceObjectBackoff := newWriteBackoff()
errList := []error{}
for i := range group </span><span class="cov8" title="1">{
nodeToDelete := group[i]
// Delete the Kubernetes object corresponding to the current node.
// Nb. The operation is wrapped in a retry loop to make move more resilient to unexpected conditions.
err := retryWithExponentialBackoff(deleteSourceObjectBackoff, func() error </span><span class="cov8" title="1">{
return o.deleteSourceObject(nodeToDelete)
}</span>)
<span class="cov8" title="1">if err != nil </span><span class="cov0" title="0">{
errList = append(errList, err)
}</span>
}
<span class="cov8" title="1">return kerrors.NewAggregate(errList)</span>
}
var (
removeFinalizersPatch = client.RawPatch(types.MergePatchType, []byte("{\"metadata\":{\"finalizers\":[]}}"))
)
// deleteSourceObject deletes the Kubernetes object corresponding to the node from the source management cluster, taking care of removing all the finalizers so
// the objects gets immediately deleted (force delete).
func (o *objectMover) deleteSourceObject(nodeToDelete *node) error <span class="cov8" title="1">{
log := logf.Log
log.V(1).Info("Deleting", nodeToDelete.identity.Kind, nodeToDelete.identity.Name, "Namespace", nodeToDelete.identity.Namespace)
cFrom, err := o.fromProxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Get the source object
<span class="cov8" title="1">sourceObj := &amp;unstructured.Unstructured{}
sourceObj.SetAPIVersion(nodeToDelete.identity.APIVersion)
sourceObj.SetKind(nodeToDelete.identity.Kind)
sourceObjKey := client.ObjectKey{
Namespace: nodeToDelete.identity.Namespace,
Name: nodeToDelete.identity.Name,
}
if err := cFrom.Get(ctx, sourceObjKey, sourceObj); err != nil </span><span class="cov0" title="0">{
if apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
//If the object is already deleted, move on.
log.V(5).Info("Object already deleted, skipping delete for", nodeToDelete.identity.Kind, nodeToDelete.identity.Name, "Namespace", nodeToDelete.identity.Namespace)
return nil
}</span>
<span class="cov0" title="0">return errors.Wrapf(err, "error reading %q %s/%s",
sourceObj.GroupVersionKind(), sourceObj.GetNamespace(), sourceObj.GetName())</span>
}
<span class="cov8" title="1">if len(sourceObj.GetFinalizers()) &gt; 0 </span><span class="cov0" title="0">{
if err := cFrom.Patch(ctx, sourceObj, removeFinalizersPatch); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error removing finalizers from %q %s/%s",
sourceObj.GroupVersionKind(), sourceObj.GetNamespace(), sourceObj.GetName())
}</span>
}
<span class="cov8" title="1">if err := cFrom.Delete(ctx, sourceObj); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "error deleting %q %s/%s",
sourceObj.GroupVersionKind(), sourceObj.GetNamespace(), sourceObj.GetName())
}</span>
<span class="cov8" title="1">return nil</span>
}
// checkTargetProviders checks that all the providers installed in the source cluster exists in the target cluster as well (with a version &gt;= of the current version).
func (o *objectMover) checkTargetProviders(namespace string, toInventory InventoryClient) error <span class="cov8" title="1">{
// Gets the list of providers in the source/target cluster.
fromProviders, err := o.fromProviderInventory.List()
if err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to get provider list from the source cluster")
}</span>
<span class="cov8" title="1">toProviders, err := toInventory.List()
if err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "failed to get provider list from the target cluster")
}</span>
// Checks all the providers installed in the source cluster
<span class="cov8" title="1">errList := []error{}
for _, sourceProvider := range fromProviders.Items </span><span class="cov8" title="1">{
// If we are moving objects in a namespace only, skip all the providers not watching such namespace.
if namespace != "" &amp;&amp; !(sourceProvider.WatchedNamespace == "" || sourceProvider.WatchedNamespace == namespace) </span><span class="cov0" title="0">{
continue</span>
}
<span class="cov8" title="1">sourceVersion, err := version.ParseSemantic(sourceProvider.Version)
if err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "unable to parse version %q for the %s provider in the source cluster", sourceProvider.Version, sourceProvider.InstanceName())
}</span>
// Check corresponding providers in the target cluster and gets the latest version installed.
<span class="cov8" title="1">var maxTargetVersion *version.Version
for _, targetProvider := range toProviders.Items </span><span class="cov8" title="1">{
// Skips other providers.
if !sourceProvider.SameAs(targetProvider) </span><span class="cov8" title="1">{
continue</span>
}
// If we are moving objects in all the namespaces, skip all the providers with a different watching namespace.
// NB. This introduces a constraints for move all namespaces, that the configuration of source and target provider MUST match (except for the version);
// however this is acceptable because clusterctl supports only two models of multi-tenancy (n-Infra, n-Core).
<span class="cov8" title="1">if namespace == "" &amp;&amp; !(targetProvider.WatchedNamespace == sourceProvider.WatchedNamespace) </span><span class="cov8" title="1">{
continue</span>
}
// If we are moving objects in a namespace only, skip all the providers not watching such namespace.
// NB. This means that when moving a single namespace, we use a lazy matching (the watching namespace MUST overlap; exact match is not required).
<span class="cov8" title="1">if namespace != "" &amp;&amp; !(targetProvider.WatchedNamespace == "" || targetProvider.WatchedNamespace == namespace) </span><span class="cov0" title="0">{
continue</span>
}
<span class="cov8" title="1">targetVersion, err := version.ParseSemantic(targetProvider.Version)
if err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "unable to parse version %q for the %s provider in the target cluster", targetProvider.Version, targetProvider.InstanceName())
}</span>
<span class="cov8" title="1">if maxTargetVersion == nil || maxTargetVersion.LessThan(targetVersion) </span><span class="cov8" title="1">{
maxTargetVersion = targetVersion
}</span>
}
<span class="cov8" title="1">if maxTargetVersion == nil </span><span class="cov8" title="1">{
watching := sourceProvider.WatchedNamespace
if namespace != "" </span><span class="cov0" title="0">{
watching = namespace
}</span>
<span class="cov8" title="1">errList = append(errList, errors.Errorf("provider %s watching namespace %s not found in the target cluster", sourceProvider.Name, watching))
continue</span>
}
<span class="cov8" title="1">if !maxTargetVersion.AtLeast(sourceVersion) </span><span class="cov8" title="1">{
errList = append(errList, errors.Errorf("provider %s in the target cluster is older than in the source cluster (source: %s, target: %s)", sourceProvider.Name, sourceVersion.String(), maxTargetVersion.String()))
}</span>
}
<span class="cov8" title="1">return kerrors.NewAggregate(errList)</span>
}
</pre>
<pre class="file" id="file68" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 cluster
import (
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
secretutil "sigs.k8s.io/cluster-api/util/secret"
"sigs.k8s.io/controller-runtime/pkg/client"
)
type empty struct{}
type ownerReferenceAttributes struct {
Controller *bool
BlockOwnerDeletion *bool
}
// node defines a node in the Kubernetes object graph that is visited during the discovery phase for the move operation.
type node struct {
identity corev1.ObjectReference
// owners contains the list of nodes that are owned by the current node.
owners map[*node]ownerReferenceAttributes
// softOwners contains the list of nodes that are soft-owned by the current node.
// E.g. secrets are soft-owned by a cluster via a naming convention, but without an explicit OwnerReference.
softOwners map[*node]empty
// virtual records if this node was discovered indirectly, e.g. by processing an OwnerRef, but not yet observed as a concrete object.
virtual bool
//newID stores the new UID the objects gets once created in the target cluster.
newUID types.UID
// tenantClusters define the list of Clusters which are tenant for the node, no matter if the node has a direct OwnerReference to the Cluster or if
// the node is linked to a Cluster indirectly in the OwnerReference chain.
tenantClusters map[*node]empty
}
// markObserved marks the fact that a node was observed as a concrete object.
func (n *node) markObserved() <span class="cov8" title="1">{
n.virtual = false
}</span>
func (n *node) addOwner(owner *node, attributes ownerReferenceAttributes) <span class="cov8" title="1">{
n.owners[owner] = attributes
}</span>
func (n *node) addSoftOwner(owner *node) <span class="cov8" title="1">{
n.softOwners[owner] = struct{}{}
}</span>
func (n *node) isOwnedBy(other *node) bool <span class="cov8" title="1">{
_, ok := n.owners[other]
return ok
}</span>
func (n *node) isSoftOwnedBy(other *node) bool <span class="cov8" title="1">{
_, ok := n.softOwners[other]
return ok
}</span>
// objectGraph manages the Kubernetes object graph that is generated during the discovery phase for the move operation.
type objectGraph struct {
proxy Proxy
uidToNode map[types.UID]*node
}
func newObjectGraph(proxy Proxy) *objectGraph <span class="cov8" title="1">{
return &amp;objectGraph{
proxy: proxy,
uidToNode: map[types.UID]*node{},
}
}</span>
// addObj adds a Kubernetes object to the object graph that is generated during the move discovery phase.
// During add, OwnerReferences are processed in order to create the dependency graph.
func (o *objectGraph) addObj(obj *unstructured.Unstructured) <span class="cov8" title="1">{
// Adds the node to the Graph.
newNode := o.objToNode(obj)
// Process OwnerReferences; if the owner object doe not exists yet, create a virtual node as a placeholder for it.
for _, ownerReference := range obj.GetOwnerReferences() </span><span class="cov8" title="1">{
ownerNode, ok := o.uidToNode[ownerReference.UID]
if !ok </span><span class="cov8" title="1">{
ownerNode = o.ownerToVirtualNode(ownerReference, newNode.identity.Namespace)
}</span>
<span class="cov8" title="1">newNode.addOwner(ownerNode, ownerReferenceAttributes{
Controller: ownerReference.Controller,
BlockOwnerDeletion: ownerReference.BlockOwnerDeletion,
})</span>
}
}
// ownerToVirtualNode creates a virtual node as a placeholder for the Kubernetes owner object received in input.
// The virtual node will be eventually converted to an actual node when the node will be visited during discovery.
func (o *objectGraph) ownerToVirtualNode(owner metav1.OwnerReference, namespace string) *node <span class="cov8" title="1">{
ownerNode := &amp;node{
identity: corev1.ObjectReference{
APIVersion: owner.APIVersion,
Kind: owner.Kind,
Name: owner.Name,
UID: owner.UID,
Namespace: namespace,
},
owners: make(map[*node]ownerReferenceAttributes),
softOwners: make(map[*node]empty),
tenantClusters: make(map[*node]empty),
virtual: true,
}
o.uidToNode[ownerNode.identity.UID] = ownerNode
return ownerNode
}</span>
// objToNode creates a node for the Kubernetes object received in input.
// If the node corresponding to the Kubernetes object already exists as a virtual node detected when processing OwnerReferences,
// the node is marked as Observed.
func (o *objectGraph) objToNode(obj *unstructured.Unstructured) *node <span class="cov8" title="1">{
existingNode, found := o.uidToNode[obj.GetUID()]
if found </span><span class="cov8" title="1">{
existingNode.markObserved()
return existingNode
}</span>
<span class="cov8" title="1">newNode := &amp;node{
identity: corev1.ObjectReference{
APIVersion: obj.GetAPIVersion(),
Kind: obj.GetKind(),
UID: obj.GetUID(),
Name: obj.GetName(),
Namespace: obj.GetNamespace(),
},
owners: make(map[*node]ownerReferenceAttributes),
softOwners: make(map[*node]empty),
tenantClusters: make(map[*node]empty),
virtual: false,
}
o.uidToNode[newNode.identity.UID] = newNode
return newNode</span>
}
// getDiscoveryTypes returns the list of TypeMeta to be considered for the the move discovery phase.
// This list includes all the types defines by the CRDs installed by clusterctl and the ConfigMap/Secret core types.
func (o *objectGraph) getDiscoveryTypes() ([]metav1.TypeMeta, error) <span class="cov8" title="1">{
discoveredTypes := []metav1.TypeMeta{}
crdList := &amp;apiextensionsv1.CustomResourceDefinitionList{}
getDiscoveryTypesBackoff := newReadBackoff()
if err := retryWithExponentialBackoff(getDiscoveryTypesBackoff, func() error </span><span class="cov8" title="1">{
return getCRDList(o.proxy, crdList)
}</span>); err != nil <span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">for _, crd := range crdList.Items </span><span class="cov8" title="1">{
for _, version := range crd.Spec.Versions </span><span class="cov8" title="1">{
if !version.Storage </span><span class="cov8" title="1">{
continue</span>
}
<span class="cov8" title="1">discoveredTypes = append(discoveredTypes, metav1.TypeMeta{
Kind: crd.Spec.Names.Kind,
APIVersion: metav1.GroupVersion{
Group: crd.Spec.Group,
Version: version.Name,
}.String(),
})</span>
}
}
<span class="cov8" title="1">discoveredTypes = append(discoveredTypes, metav1.TypeMeta{Kind: "Secret", APIVersion: "v1"})
discoveredTypes = append(discoveredTypes, metav1.TypeMeta{Kind: "ConfigMap", APIVersion: "v1"})
return discoveredTypes, nil</span>
}
func getCRDList(proxy Proxy, crdList *apiextensionsv1.CustomResourceDefinitionList) error <span class="cov8" title="1">{
c, err := proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := c.List(ctx, crdList, client.HasLabels{clusterctlv1.ClusterctlLabelName}); err != nil </span><span class="cov0" title="0">{
return errors.Wrap(err, "failed to get the list of CRDs required for the move discovery phase")
}</span>
<span class="cov8" title="1">return nil</span>
}
// Discovery reads all the Kubernetes objects existing in a namespace (or in all namespaces if empty) for the types received in input, and then adds
// everything to the objects graph.
func (o *objectGraph) Discovery(namespace string, types []metav1.TypeMeta) error <span class="cov8" title="1">{
log := logf.Log
log.Info("Discovering Cluster API objects")
selectors := []client.ListOption{}
if namespace != "" </span><span class="cov8" title="1">{
selectors = append(selectors, client.InNamespace(namespace))
}</span>
<span class="cov8" title="1">discoveryBackoff := newReadBackoff()
for i := range types </span><span class="cov8" title="1">{
typeMeta := types[i]
objList := new(unstructured.UnstructuredList)
if err := retryWithExponentialBackoff(discoveryBackoff, func() error </span><span class="cov8" title="1">{
return getObjList(o.proxy, typeMeta, selectors, objList)
}</span>); err != nil <span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if len(objList.Items) == 0 </span><span class="cov8" title="1">{
continue</span>
}
<span class="cov8" title="1">log.V(5).Info(typeMeta.Kind, "Count", len(objList.Items))
for i := range objList.Items </span><span class="cov8" title="1">{
obj := objList.Items[i]
o.addObj(&amp;obj)
}</span>
}
<span class="cov8" title="1">log.V(1).Info("Total objects", "Count", len(o.uidToNode))
// Completes the graph by searching for soft ownership relations such as secrets linked to the cluster
// by a naming convention (without any explicit OwnerReference).
o.setSoftOwnership()
// Completes the graph by setting for each node the list of Clusters the node belong to.
o.setClusterTenants()
return nil</span>
}
func getObjList(proxy Proxy, typeMeta metav1.TypeMeta, selectors []client.ListOption, objList *unstructured.UnstructuredList) error <span class="cov8" title="1">{
c, err := proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">objList.SetAPIVersion(typeMeta.APIVersion)
objList.SetKind(typeMeta.Kind)
if err := c.List(ctx, objList, selectors...); err != nil </span><span class="cov0" title="0">{
if apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov0" title="0">return errors.Wrapf(err, "failed to list %q resources", objList.GroupVersionKind())</span>
}
<span class="cov8" title="1">return nil</span>
}
// getClusters returns the list of Clusters existing in the object graph.
func (o *objectGraph) getClusters() []*node <span class="cov8" title="1">{
clusters := []*node{}
for _, node := range o.uidToNode </span><span class="cov8" title="1">{
if node.identity.GroupVersionKind().GroupKind() == clusterv1.GroupVersion.WithKind("Cluster").GroupKind() </span><span class="cov8" title="1">{
clusters = append(clusters, node)
}</span>
}
<span class="cov8" title="1">return clusters</span>
}
// getClusters returns the list of Secrets existing in the object graph.
func (o *objectGraph) getSecrets() []*node <span class="cov8" title="1">{
secrets := []*node{}
for _, node := range o.uidToNode </span><span class="cov8" title="1">{
if node.identity.APIVersion == "v1" &amp;&amp; node.identity.Kind == "Secret" </span><span class="cov8" title="1">{
secrets = append(secrets, node)
}</span>
}
<span class="cov8" title="1">return secrets</span>
}
// getNodes returns the list of nodes existing in the object graph.
func (o *objectGraph) getNodes() []*node <span class="cov8" title="1">{
nodes := []*node{}
for _, node := range o.uidToNode </span><span class="cov8" title="1">{
nodes = append(nodes, node)
}</span>
<span class="cov8" title="1">return nodes</span>
}
// getNodesWithClusterTenants returns the list of nodes existing in the object graph that belong at least to one Cluster.
func (o *objectGraph) getNodesWithClusterTenants() []*node <span class="cov8" title="1">{
nodes := []*node{}
for _, node := range o.uidToNode </span><span class="cov8" title="1">{
if len(node.tenantClusters) &gt; 0 </span><span class="cov8" title="1">{
nodes = append(nodes, node)
}</span>
}
<span class="cov8" title="1">return nodes</span>
}
// getMachines returns the list of Machine existing in the object graph.
func (o *objectGraph) getMachines() []*node <span class="cov8" title="1">{
machines := []*node{}
for _, node := range o.uidToNode </span><span class="cov8" title="1">{
if node.identity.GroupVersionKind().GroupKind() == clusterv1.GroupVersion.WithKind("Machine").GroupKind() </span><span class="cov8" title="1">{
machines = append(machines, node)
}</span>
}
<span class="cov8" title="1">return machines</span>
}
// setSoftOwnership searches for soft ownership relations such as secrets linked to the cluster by a naming convention (without any explicit OwnerReference).
func (o *objectGraph) setSoftOwnership() <span class="cov8" title="1">{
clusters := o.getClusters()
for _, secret := range o.getSecrets() </span><span class="cov8" title="1">{
// If the secret has at least one OwnerReference ignore it.
// NB. Cluster API generated secrets have an explicit OwnerReference to the ControlPlane or the KubeadmConfig object while user provided secrets might not have one.
if len(secret.owners) &gt; 0 </span><span class="cov8" title="1">{
continue</span>
}
// If the secret name is not a valid cluster secret name, ignore it.
<span class="cov8" title="1">secretClusterName, _, err := secretutil.ParseSecretName(secret.identity.Name)
if err != nil </span><span class="cov0" title="0">{
continue</span>
}
// If the secret is linked to a cluster, then add the cluster to the list of the secrets's softOwners.
<span class="cov8" title="1">for _, cluster := range clusters </span><span class="cov8" title="1">{
if secretClusterName == cluster.identity.Name &amp;&amp; secret.identity.Namespace == cluster.identity.Namespace </span><span class="cov8" title="1">{
secret.addSoftOwner(cluster)
}</span>
}
}
}
// setClusterTenants sets the cluster tenants for the clusters itself and all their dependent object tree.
func (o *objectGraph) setClusterTenants() <span class="cov8" title="1">{
for _, cluster := range o.getClusters() </span><span class="cov8" title="1">{
o.setClusterTenant(cluster, cluster)
}</span>
}
// setNodeTenant sets a tenant for a node and for its own dependents/sofDependents.
func (o *objectGraph) setClusterTenant(node, tenant *node) <span class="cov8" title="1">{
node.tenantClusters[tenant] = empty{}
for _, other := range o.getNodes() </span><span class="cov8" title="1">{
if other.isOwnedBy(node) || other.isSoftOwnedBy(node) </span><span class="cov8" title="1">{
o.setClusterTenant(other, tenant)
}</span>
}
}
</pre>
<pre class="file" id="file69" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 cluster
import (
"fmt"
"strings"
"time"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
utilversion "k8s.io/apimachinery/pkg/util/version"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/scheme"
"sigs.k8s.io/cluster-api/cmd/version"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var (
Scheme = scheme.Scheme
)
type proxy struct {
kubeconfig Kubeconfig
timeout time.Duration
configLoadingRules *clientcmd.ClientConfigLoadingRules
}
var _ Proxy = &amp;proxy{}
// CurrentNamespace returns the namespace for the specified context or the
// first valid context as determined by the default config loading rules.
func (k *proxy) CurrentNamespace() (string, error) <span class="cov8" title="1">{
config, err := k.configLoadingRules.Load()
if err != nil </span><span class="cov8" title="1">{
return "", errors.Wrap(err, "failed to load Kubeconfig")
}</span>
<span class="cov8" title="1">context := config.CurrentContext
// If a context is explicitly provided use that instead
if k.kubeconfig.Context != "" </span><span class="cov8" title="1">{
context = k.kubeconfig.Context
}</span>
<span class="cov8" title="1">v, ok := config.Contexts[context]
if !ok </span><span class="cov8" title="1">{
if k.kubeconfig.Path != "" </span><span class="cov8" title="1">{
return "", errors.Errorf("failed to get context %q from %q", context, k.configLoadingRules.GetExplicitFile())
}</span>
<span class="cov0" title="0">return "", errors.Errorf("failed to get context %q from %q", context, k.configLoadingRules.GetLoadingPrecedence())</span>
}
<span class="cov8" title="1">if v.Namespace != "" </span><span class="cov8" title="1">{
return v.Namespace, nil
}</span>
<span class="cov8" title="1">return "default", nil</span>
}
func (k *proxy) ValidateKubernetesVersion() error <span class="cov0" title="0">{
config, err := k.GetConfig()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">client := discovery.NewDiscoveryClientForConfigOrDie(config)
serverVersion, err := client.ServerVersion()
if err != nil </span><span class="cov0" title="0">{
return errors.Wrap(err, "failed to retrieve server version")
}</span>
<span class="cov0" title="0">compver, err := utilversion.MustParseGeneric(serverVersion.String()).Compare(minimumKubernetesVersion)
if err != nil </span><span class="cov0" title="0">{
return errors.Wrap(err, "failed to parse and compare server version")
}</span>
<span class="cov0" title="0">if compver == -1 </span><span class="cov0" title="0">{
return errors.Errorf("unsupported management cluster server version: %s - minimum required version is %s", serverVersion.String(), minimumKubernetesVersion)
}</span>
<span class="cov0" title="0">return nil</span>
}
// GetConfig returns the config for a kubernetes client.
func (k *proxy) GetConfig() (*rest.Config, error) <span class="cov8" title="1">{
config, err := k.configLoadingRules.Load()
if err != nil </span><span class="cov8" title="1">{
return nil, errors.Wrap(err, "failed to load Kubeconfig")
}</span>
<span class="cov8" title="1">configOverrides := &amp;clientcmd.ConfigOverrides{
CurrentContext: k.kubeconfig.Context,
Timeout: k.timeout.String(),
}
restConfig, err := clientcmd.NewDefaultClientConfig(*config, configOverrides).ClientConfig()
if err != nil </span><span class="cov0" title="0">{
if strings.HasPrefix(err.Error(), "invalid configuration:") </span><span class="cov0" title="0">{
return nil, errors.New(strings.Replace(err.Error(), "invalid configuration:", "invalid kubeconfig file; clusterctl requires a valid kubeconfig file to connect to the management cluster:", 1))
}</span>
<span class="cov0" title="0">return nil, err</span>
}
<span class="cov8" title="1">restConfig.UserAgent = fmt.Sprintf("clusterctl/%s (%s)", version.Get().GitVersion, version.Get().Platform)
// Set QPS and Burst to a threshold that ensures the controller runtime client/client go does't generate throttling log messages
restConfig.QPS = 20
restConfig.Burst = 100
return restConfig, nil</span>
}
func (k *proxy) NewClient() (client.Client, error) <span class="cov0" title="0">{
config, err := k.GetConfig()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">var c client.Client
// Nb. The operation is wrapped in a retry loop to make newClientSet more resilient to temporary connection problems.
connectBackoff := newConnectBackoff()
if err := retryWithExponentialBackoff(connectBackoff, func() error </span><span class="cov0" title="0">{
var err error
c, err = client.New(config, client.Options{Scheme: Scheme})
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}); err != nil <span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to connect to the management cluster")
}</span>
<span class="cov0" title="0">return c, nil</span>
}
func (k *proxy) ListResources(labels map[string]string, namespaces ...string) ([]unstructured.Unstructured, error) <span class="cov0" title="0">{
cs, err := k.newClientSet()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">c, err := k.NewClient()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// Get all the API resources in the cluster.
<span class="cov0" title="0">resourceList, err := cs.Discovery().ServerPreferredResources()
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to list api resources")
}</span>
// Select resources with list and delete methods (list is required by this method, delete by the callers of this method)
<span class="cov0" title="0">resourceList = discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"list", "delete"}}, resourceList)
var ret []unstructured.Unstructured
for _, resourceGroup := range resourceList </span><span class="cov0" title="0">{
for _, resourceKind := range resourceGroup.APIResources </span><span class="cov0" title="0">{
// Discard the resourceKind that exists in two api groups (we are excluding one of the two groups arbitrarily).
if resourceGroup.GroupVersion == "extensions/v1beta1" &amp;&amp;
(resourceKind.Name == "daemonsets" || resourceKind.Name == "deployments" || resourceKind.Name == "replicasets" || resourceKind.Name == "networkpolicies" || resourceKind.Name == "ingresses") </span><span class="cov0" title="0">{
continue</span>
}
// List all the object instances of this resourceKind with the given labels
<span class="cov0" title="0">if resourceKind.Namespaced </span><span class="cov0" title="0">{
for _, namespace := range namespaces </span><span class="cov0" title="0">{
objList, err := listObjByGVK(c, resourceGroup.GroupVersion, resourceKind.Kind, []client.ListOption{client.MatchingLabels(labels), client.InNamespace(namespace)})
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">ret = append(ret, objList.Items...)</span>
}
} else<span class="cov0" title="0"> {
objList, err := listObjByGVK(c, resourceGroup.GroupVersion, resourceKind.Kind, []client.ListOption{client.MatchingLabels(labels)})
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">ret = append(ret, objList.Items...)</span>
}
}
}
<span class="cov0" title="0">return ret, nil</span>
}
func listObjByGVK(c client.Client, groupVersion, kind string, options []client.ListOption) (*unstructured.UnstructuredList, error) <span class="cov0" title="0">{
objList := new(unstructured.UnstructuredList)
objList.SetAPIVersion(groupVersion)
objList.SetKind(kind)
if err := c.List(ctx, objList, options...); err != nil </span><span class="cov0" title="0">{
if !apierrors.IsNotFound(err) </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to list objects for the %q GroupVersionKind", objList.GroupVersionKind())
}</span>
}
<span class="cov0" title="0">return objList, nil</span>
}
type ProxyOption func(p *proxy)
func InjectProxyTimeout(t time.Duration) ProxyOption <span class="cov8" title="1">{
return func(p *proxy) </span><span class="cov8" title="1">{
p.timeout = t
}</span>
}
func InjectKubeconfigPaths(paths []string) ProxyOption <span class="cov8" title="1">{
return func(p *proxy) </span><span class="cov8" title="1">{
p.configLoadingRules.Precedence = paths
}</span>
}
func newProxy(kubeconfig Kubeconfig, opts ...ProxyOption) Proxy <span class="cov8" title="1">{
// If a kubeconfig file isn't provided, find one in the standard locations.
rules := clientcmd.NewDefaultClientConfigLoadingRules()
if kubeconfig.Path != "" </span><span class="cov8" title="1">{
rules.ExplicitPath = kubeconfig.Path
}</span>
<span class="cov8" title="1">p := &amp;proxy{
kubeconfig: kubeconfig,
timeout: 30 * time.Second,
configLoadingRules: rules,
}
for _, o := range opts </span><span class="cov8" title="1">{
o(p)
}</span>
<span class="cov8" title="1">return p</span>
}
func (k *proxy) newClientSet() (*kubernetes.Clientset, error) <span class="cov0" title="0">{
config, err := k.GetConfig()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">var cs *kubernetes.Clientset
// Nb. The operation is wrapped in a retry loop to make newClientSet more resilient to temporary connection problems.
connectBackoff := newConnectBackoff()
if err := retryWithExponentialBackoff(connectBackoff, func() error </span><span class="cov0" title="0">{
var err error
cs, err = kubernetes.NewForConfig(config)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return nil</span>
}); err != nil <span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to create the client-go client")
}</span>
<span class="cov0" title="0">return cs, nil</span>
}
</pre>
<pre class="file" id="file70" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 cluster
import (
"context"
"encoding/base64"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
"github.com/google/go-github/github"
"github.com/pkg/errors"
"golang.org/x/oauth2"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
yaml "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// TemplateClient has methods to work with templates stored in the cluster/out of the provider repository.
type TemplateClient interface {
// GetFromConfigMap returns a workload cluster template from the given ConfigMap.
GetFromConfigMap(namespace, name, dataKey, targetNamespace string, listVariablesOnly bool) (repository.Template, error)
// GetFromURL returns a workload cluster template from the given URL.
GetFromURL(templateURL, targetNamespace string, listVariablesOnly bool) (repository.Template, error)
}
// templateClient implements TemplateClient.
type templateClient struct {
proxy Proxy
configClient config.Client
gitHubClientFactory func(configVariablesClient config.VariablesClient) (*github.Client, error)
processor yaml.Processor
}
// ensure templateClient implements TemplateClient.
var _ TemplateClient = &amp;templateClient{}
type TemplateClientInput struct {
proxy Proxy
configClient config.Client
processor yaml.Processor
}
// newTemplateClient returns a templateClient.
func newTemplateClient(input TemplateClientInput) *templateClient <span class="cov8" title="1">{
return &amp;templateClient{
proxy: input.proxy,
configClient: input.configClient,
gitHubClientFactory: getGitHubClient,
processor: input.processor,
}
}</span>
func (t *templateClient) GetFromConfigMap(configMapNamespace, configMapName, configMapDataKey, targetNamespace string, listVariablesOnly bool) (repository.Template, error) <span class="cov8" title="1">{
if configMapNamespace == "" </span><span class="cov0" title="0">{
return nil, errors.New("invalid GetFromConfigMap operation: missing configMapNamespace value")
}</span>
<span class="cov8" title="1">if configMapName == "" </span><span class="cov0" title="0">{
return nil, errors.New("invalid GetFromConfigMap operation: missing configMapName value")
}</span>
<span class="cov8" title="1">c, err := t.proxy.NewClient()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">configMap := &amp;corev1.ConfigMap{}
key := client.ObjectKey{
Namespace: configMapNamespace,
Name: configMapName,
}
if err := c.Get(ctx, key, configMap); err != nil </span><span class="cov8" title="1">{
return nil, errors.Wrapf(err, "error reading ConfigMap %s/%s", configMapNamespace, configMapName)
}</span>
<span class="cov8" title="1">data, ok := configMap.Data[configMapDataKey]
if !ok </span><span class="cov8" title="1">{
return nil, errors.Errorf("the ConfigMap %s/%s does not have the %q data key", configMapNamespace, configMapName, configMapDataKey)
}</span>
<span class="cov8" title="1">return repository.NewTemplate(repository.TemplateInput{
RawArtifact: []byte(data),
ConfigVariablesClient: t.configClient.Variables(),
Processor: t.processor,
TargetNamespace: targetNamespace,
ListVariablesOnly: listVariablesOnly,
})</span>
}
func (t *templateClient) GetFromURL(templateURL, targetNamespace string, listVariablesOnly bool) (repository.Template, error) <span class="cov8" title="1">{
if templateURL == "" </span><span class="cov0" title="0">{
return nil, errors.New("invalid GetFromURL operation: missing templateURL value")
}</span>
<span class="cov8" title="1">content, err := t.getURLContent(templateURL)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "invalid GetFromURL operation")
}</span>
<span class="cov8" title="1">return repository.NewTemplate(repository.TemplateInput{
RawArtifact: content,
ConfigVariablesClient: t.configClient.Variables(),
Processor: t.processor,
TargetNamespace: targetNamespace,
ListVariablesOnly: listVariablesOnly,
})</span>
}
func (t *templateClient) getURLContent(templateURL string) ([]byte, error) <span class="cov8" title="1">{
rURL, err := url.Parse(templateURL)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to parse %q", templateURL)
}</span>
<span class="cov8" title="1">if rURL.Scheme == "https" &amp;&amp; rURL.Host == "github.com" </span><span class="cov8" title="1">{
return t.getGitHubFileContent(rURL)
}</span>
<span class="cov8" title="1">if rURL.Scheme == "file" || rURL.Scheme == "" </span><span class="cov8" title="1">{
return t.getLocalFileContent(rURL)
}</span>
<span class="cov0" title="0">return nil, errors.Errorf("unable to read content from %q. Only reading from GitHub and local file system is supported", templateURL)</span>
}
func (t *templateClient) getLocalFileContent(rURL *url.URL) ([]byte, error) <span class="cov8" title="1">{
f, err := os.Stat(rURL.Path)
if err != nil </span><span class="cov8" title="1">{
return nil, errors.Errorf("failed to read file %q", rURL.Path)
}</span>
<span class="cov8" title="1">if f.IsDir() </span><span class="cov0" title="0">{
return nil, errors.Errorf("invalid path: file %q is actually a directory", rURL.Path)
}</span>
<span class="cov8" title="1">content, err := ioutil.ReadFile(rURL.Path)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to read file %q", rURL.Path)
}</span>
<span class="cov8" title="1">return content, nil</span>
}
func (t *templateClient) getGitHubFileContent(rURL *url.URL) ([]byte, error) <span class="cov8" title="1">{
// Check if the path is in the expected format,
urlSplit := strings.Split(strings.TrimPrefix(rURL.Path, "/"), "/")
if len(urlSplit) &lt; 5 </span><span class="cov0" title="0">{
return nil, errors.Errorf(
"invalid GitHub url %q: a GitHub url should be in the form https://github.com/{owner}/{repository}/blob/{branch}/{path-to-file}", rURL,
)
}</span>
// Extract all the info from url split.
<span class="cov8" title="1">owner := urlSplit[0]
repository := urlSplit[1]
branch := urlSplit[3]
path := strings.Join(urlSplit[4:], "/")
// gets the GitHub client
client, err := t.gitHubClientFactory(t.configClient.Variables())
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// gets the file from GiHub
<span class="cov8" title="1">fileContent, _, _, err := client.Repositories.GetContents(context.TODO(), owner, repository, path, &amp;github.RepositoryContentGetOptions{Ref: branch})
if err != nil </span><span class="cov8" title="1">{
return nil, handleGithubErr(err, "failed to get %q", rURL.Path)
}</span>
<span class="cov8" title="1">if fileContent == nil </span><span class="cov0" title="0">{
return nil, errors.Errorf("%q does not return a valid file content", rURL.Path)
}</span>
<span class="cov8" title="1">if fileContent.Encoding == nil || *fileContent.Encoding != "base64" </span><span class="cov0" title="0">{
return nil, errors.Errorf("invalid encoding detected for %q. Only base64 encoding supported", rURL.Path)
}</span>
<span class="cov8" title="1">content, err := base64.StdEncoding.DecodeString(*fileContent.Content)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to decode file %q", rURL.Path)
}</span>
<span class="cov8" title="1">return content, nil</span>
}
func getGitHubClient(configVariablesClient config.VariablesClient) (*github.Client, error) <span class="cov0" title="0">{
var authenticatingHTTPClient *http.Client
if token, err := configVariablesClient.Get(config.GitHubTokenVariable); err == nil </span><span class="cov0" title="0">{
ts := oauth2.StaticTokenSource(
&amp;oauth2.Token{AccessToken: token},
)
authenticatingHTTPClient = oauth2.NewClient(context.TODO(), ts)
}</span>
<span class="cov0" title="0">return github.NewClient(authenticatingHTTPClient), nil</span>
}
// handleGithubErr wraps error messages
func handleGithubErr(err error, message string, args ...interface{}) error <span class="cov8" title="1">{
if _, ok := err.(*github.RateLimitError); ok </span><span class="cov0" title="0">{
return errors.New("rate limit for github api has been reached. Please wait one hour or get a personal API tokens a assign it to the GITHUB_TOKEN environment variable")
}</span>
<span class="cov8" title="1">return errors.Wrapf(err, message, args...)</span>
}
</pre>
<pre class="file" id="file71" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 cluster
import (
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/version"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
)
// ProviderUpgrader defines methods for supporting provider upgrade.
type ProviderUpgrader interface {
// Plan returns a set of suggested Upgrade plans for the cluster, and more specifically:
// - Each management group gets separated upgrade plans.
// - For each management group, an upgrade plan will be generated for each API Version of Cluster API (contract) available, e.g.
// - Upgrade to the latest version in the the v1alpha2 series: ....
// - Upgrade to the latest version in the the v1alpha3 series: ....
Plan() ([]UpgradePlan, error)
// ApplyPlan executes an upgrade following an UpgradePlan generated by clusterctl.
ApplyPlan(coreProvider clusterctlv1.Provider, clusterAPIVersion string) error
// ApplyCustomPlan plan executes an upgrade using the UpgradeItems provided by the user.
ApplyCustomPlan(coreProvider clusterctlv1.Provider, providersToUpgrade ...UpgradeItem) error
}
// UpgradePlan defines a list of possible upgrade targets for a management group.
type UpgradePlan struct {
Contract string
CoreProvider clusterctlv1.Provider
Providers []UpgradeItem
}
// UpgradeRef returns a string identifying the upgrade plan; this string is derived by the core provider which is
// unique for each management group.
func (u *UpgradePlan) UpgradeRef() string <span class="cov0" title="0">{
return u.CoreProvider.InstanceName()
}</span>
// isPartialUpgrade returns true if at least one upgradeItem in the plan does not have a target version.
func (u *UpgradePlan) isPartialUpgrade() bool <span class="cov8" title="1">{
for _, i := range u.Providers </span><span class="cov8" title="1">{
if i.NextVersion == "" </span><span class="cov8" title="1">{
return true
}</span>
}
<span class="cov8" title="1">return false</span>
}
// UpgradeItem defines a possible upgrade target for a provider in the management group.
type UpgradeItem struct {
clusterctlv1.Provider
NextVersion string
}
// UpgradeRef returns a string identifying the upgrade item; this string is derived by the provider.
func (u *UpgradeItem) UpgradeRef() string <span class="cov0" title="0">{
return u.InstanceName()
}</span>
type providerUpgrader struct {
configClient config.Client
repositoryClientFactory RepositoryClientFactory
providerInventory InventoryClient
providerComponents ComponentsClient
}
var _ ProviderUpgrader = &amp;providerUpgrader{}
func (u *providerUpgrader) Plan() ([]UpgradePlan, error) <span class="cov8" title="1">{
log := logf.Log
log.Info("Checking new release availability...")
managementGroups, err := u.providerInventory.GetManagementGroups()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">var ret []UpgradePlan
for _, managementGroup := range managementGroups </span><span class="cov8" title="1">{
// The core provider is driving all the plan logic for each management group, because all the providers
// in a management group are expected to support the same API Version of Cluster API (contract).
// e.g if the core provider supports v1alpha3, all the providers in the same management group should support v1alpha3 as well;
// all the providers in the management group can upgrade to the latest release supporting v1alpha3, or if available,
// or if available, all the providers in the management group can upgrade to the latest release supporting v1alpha4.
// Gets the upgrade info for the core provider.
coreUpgradeInfo, err := u.getUpgradeInfo(managementGroup.CoreProvider)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// Identifies the API Version of Cluster API (contract) that we should consider for the management group update (Nb. the core provider is driving the entire management group).
// This includes the current contract (e.g. v1alpha3) and the new one available, if any.
<span class="cov8" title="1">contractsForUpgrade := coreUpgradeInfo.getContractsForUpgrade()
if len(contractsForUpgrade) == 0 </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "Invalid metadata: unable to find th API Version of Cluster API (contract) supported by the %s provider", managementGroup.CoreProvider.InstanceName())
}</span>
// Creates an UpgradePlan for each contract considered for upgrades; each upgrade plans contains
// an UpgradeItem for each provider defining the next available version with the target contract, if available.
// e.g. v1alpha3, cluster-api --&gt; v0.3.2, kubeadm bootstrap --&gt; v0.3.2, aws --&gt; v0.5.4
// e.g. v1alpha4, cluster-api --&gt; v0.4.1, kubeadm bootstrap --&gt; v0.4.1, aws --&gt; v0.6.2
<span class="cov8" title="1">for _, contract := range contractsForUpgrade </span><span class="cov8" title="1">{
upgradePlan, err := u.getUpgradePlan(managementGroup, contract)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// If the upgrade plan is partial (at least one upgradeItem in the plan does not have a target version) and
// the upgrade plan requires a change of the contract for this management group, then drop it
// (all the provider in a management group are required to change contract at the same time).
<span class="cov8" title="1">if upgradePlan.isPartialUpgrade() &amp;&amp; coreUpgradeInfo.currentContract != contract </span><span class="cov8" title="1">{
continue</span>
}
<span class="cov8" title="1">ret = append(ret, *upgradePlan)</span>
}
}
<span class="cov8" title="1">return ret, nil</span>
}
func (u *providerUpgrader) ApplyPlan(coreProvider clusterctlv1.Provider, contract string) error <span class="cov0" title="0">{
log := logf.Log
log.Info("Performing upgrade...")
// Retrieves the management group.
managementGroup, err := u.getManagementGroup(coreProvider)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Gets the upgrade plan for the selected management group/API Version of Cluster API (contract).
<span class="cov0" title="0">upgradePlan, err := u.getUpgradePlan(*managementGroup, contract)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Do the upgrade
<span class="cov0" title="0">return u.doUpgrade(upgradePlan)</span>
}
func (u *providerUpgrader) ApplyCustomPlan(coreProvider clusterctlv1.Provider, upgradeItems ...UpgradeItem) error <span class="cov0" title="0">{
log := logf.Log
log.Info("Performing upgrade...")
// Create a custom upgrade plan from the upgrade items, taking care of ensuring all the providers in a management
// group are consistent with the API Version of Cluster API (contract).
upgradePlan, err := u.createCustomPlan(coreProvider, upgradeItems)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Do the upgrade
<span class="cov0" title="0">return u.doUpgrade(upgradePlan)</span>
}
// getUpgradePlan returns the upgrade plan for a specific managementGroup/contract
// NB. this function is used both for upgrade plan and upgrade apply.
func (u *providerUpgrader) getUpgradePlan(managementGroup ManagementGroup, contract string) (*UpgradePlan, error) <span class="cov8" title="1">{
upgradeItems := []UpgradeItem{}
for _, provider := range managementGroup.Providers </span><span class="cov8" title="1">{
// Gets the upgrade info for the provider.
providerUpgradeInfo, err := u.getUpgradeInfo(provider)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// Identifies the next available version with the target contract for the provider, if available.
<span class="cov8" title="1">nextVersion := providerUpgradeInfo.getLatestNextVersion(contract)
// Append the upgrade item for the provider/with the target contract.
upgradeItems = append(upgradeItems, UpgradeItem{
Provider: provider,
NextVersion: versionTag(nextVersion),
})</span>
}
<span class="cov8" title="1">return &amp;UpgradePlan{
Contract: contract,
CoreProvider: managementGroup.CoreProvider,
Providers: upgradeItems,
}, nil</span>
}
// getManagementGroup returns the management group for a core provider.
func (u *providerUpgrader) getManagementGroup(coreProvider clusterctlv1.Provider) (*ManagementGroup, error) <span class="cov8" title="1">{
managementGroups, err := u.providerInventory.GetManagementGroups()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">managementGroup := managementGroups.FindManagementGroupByProviderInstanceName(coreProvider.InstanceName())
if managementGroup == nil </span><span class="cov0" title="0">{
return nil, errors.Errorf("unable to identify %s/%s the management group", coreProvider.Namespace, coreProvider.ProviderName)
}</span>
<span class="cov8" title="1">return managementGroup, nil</span>
}
// createCustomPlan creates a custom upgrade plan from a set of upgrade items, taking care of ensuring all the providers
// in a management group are consistent with the API Version of Cluster API (contract).
func (u *providerUpgrader) createCustomPlan(coreProvider clusterctlv1.Provider, upgradeItems []UpgradeItem) (*UpgradePlan, error) <span class="cov8" title="1">{
// Retrieves the management group.
managementGroup, err := u.getManagementGroup(coreProvider)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// Gets the API Version of Cluster API (contract).
// The this is required to ensure all the providers in a management group are consistent with the contract supported by the core provider.
// e.g if the core provider is v1alpha3, all the provider in the same management group should be v1alpha3 as well.
// The target contract is derived from the current version of the core provider, or, if the core provider is included in the upgrade list,
// from its target version.
<span class="cov8" title="1">targetCoreProviderVersion := managementGroup.CoreProvider.Version
for _, providerToUpgrade := range upgradeItems </span><span class="cov8" title="1">{
if providerToUpgrade.InstanceName() == managementGroup.CoreProvider.InstanceName() </span><span class="cov8" title="1">{
targetCoreProviderVersion = providerToUpgrade.NextVersion
break</span>
}
}
<span class="cov8" title="1">targetContract, err := u.getProviderContractByVersion(managementGroup.CoreProvider, targetCoreProviderVersion)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// Builds the custom upgrade plan, by adding all the upgrade items after checking consistency with the targetContract.
<span class="cov8" title="1">upgradeInstanceNames := sets.NewString()
upgradePlan := &amp;UpgradePlan{
CoreProvider: managementGroup.CoreProvider,
Contract: targetContract,
}
for _, upgradeItem := range upgradeItems </span><span class="cov8" title="1">{
// Match the upgrade item with the corresponding provider in the management group
provider := managementGroup.GetProviderByInstanceName(upgradeItem.InstanceName())
if provider == nil </span><span class="cov0" title="0">{
return nil, errors.Errorf("unable to complete that upgrade: the provider %s in not part of the %s management group", upgradeItem.InstanceName(), coreProvider.InstanceName())
}</span>
// Retrieves the contract that is supported by the target version of the provider.
<span class="cov8" title="1">contract, err := u.getProviderContractByVersion(*provider, upgradeItem.NextVersion)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">if contract != targetContract </span><span class="cov8" title="1">{
return nil, errors.Errorf("unable to complete that upgrade: the target version for the provider %s supports the %s API Version of Cluster API (contract), while the management group is using %s", upgradeItem.InstanceName(), contract, targetContract)
}</span>
<span class="cov8" title="1">upgradePlan.Providers = append(upgradePlan.Providers, upgradeItem)
upgradeInstanceNames.Insert(upgradeItem.InstanceName())</span>
}
// Before doing upgrades, checks if other providers in the management group are lagging behind the target contract.
<span class="cov8" title="1">for _, provider := range managementGroup.Providers </span><span class="cov8" title="1">{
// skip providers already included in the upgrade plan
if upgradeInstanceNames.Has(provider.InstanceName()) </span><span class="cov8" title="1">{
continue</span>
}
// Retrieves the contract that is supported by the current version of the provider.
<span class="cov8" title="1">contract, err := u.getProviderContractByVersion(provider, provider.Version)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">if contract != targetContract </span><span class="cov8" title="1">{
return nil, errors.Errorf("unable to complete that upgrade: the provider %s supports the %s API Version of Cluster API (contract), while the management group is being updated to %s. Please include the %[1]s provider in the upgrade", provider.InstanceName(), contract, targetContract)
}</span>
}
<span class="cov8" title="1">return upgradePlan, nil</span>
}
// getProviderContractByVersion returns the contract that a provider will support if updated to the given target version.
func (u *providerUpgrader) getProviderContractByVersion(provider clusterctlv1.Provider, targetVersion string) (string, error) <span class="cov8" title="1">{
targetSemVersion, err := version.ParseSemantic(targetVersion)
if err != nil </span><span class="cov0" title="0">{
return "", errors.Wrapf(err, "failed to parse target version for the %s provider", provider.InstanceName())
}</span>
// Gets the metadata for the core Provider
<span class="cov8" title="1">upgradeInfo, err := u.getUpgradeInfo(provider)
if err != nil </span><span class="cov0" title="0">{
return "", err
}</span>
<span class="cov8" title="1">releaseSeries := upgradeInfo.metadata.GetReleaseSeriesForVersion(targetSemVersion)
if releaseSeries == nil </span><span class="cov0" title="0">{
return "", errors.Errorf("invalid target version: version %s for the provider %s does not match any release series", targetVersion, provider.InstanceName())
}</span>
<span class="cov8" title="1">return releaseSeries.Contract, nil</span>
}
// getUpgradeComponents returns the provider components for the selected target version.
func (u *providerUpgrader) getUpgradeComponents(provider UpgradeItem) (repository.Components, error) <span class="cov0" title="0">{
configRepository, err := u.configClient.Providers().Get(provider.ProviderName, provider.GetProviderType())
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">providerRepository, err := u.repositoryClientFactory(configRepository, u.configClient)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">options := repository.ComponentsOptions{
Version: provider.NextVersion,
TargetNamespace: provider.Namespace,
WatchingNamespace: provider.WatchedNamespace,
}
components, err := providerRepository.Components().Get(options)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">return components, nil</span>
}
func (u *providerUpgrader) doUpgrade(upgradePlan *UpgradePlan) error <span class="cov0" title="0">{
log := logf.Log
log.Info("Performing upgrade...")
for _, upgradeItem := range upgradePlan.Providers </span><span class="cov0" title="0">{
// If there is not a specified next version, skip it (we are already up-to-date).
if upgradeItem.NextVersion == "" </span><span class="cov0" title="0">{
continue</span>
}
<span class="cov0" title="0">log.Info("Upgrading", "Provider", upgradeItem.InstanceName(), "CurrentVersion", upgradeItem.Version, "TargetVersion", upgradeItem.NextVersion)
// Gets the provider components for the target version.
components, err := u.getUpgradeComponents(upgradeItem)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Delete the provider, preserving CRD and namespace.
<span class="cov0" title="0">if err := u.providerComponents.Delete(DeleteOptions{
Provider: upgradeItem.Provider,
IncludeNamespace: false,
IncludeCRDs: false,
}); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Install the new version of the provider components.
<span class="cov0" title="0">if err := installComponentsAndUpdateInventory(components, u.providerComponents, u.providerInventory); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
<span class="cov0" title="0">return nil</span>
}
func newProviderUpgrader(configClient config.Client, repositoryClientFactory RepositoryClientFactory, providerInventory InventoryClient, providerComponents ComponentsClient) *providerUpgrader <span class="cov0" title="0">{
return &amp;providerUpgrader{
configClient: configClient,
repositoryClientFactory: repositoryClientFactory,
providerInventory: providerInventory,
providerComponents: providerComponents,
}
}</span>
</pre>
<pre class="file" id="file72" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 cluster
import (
"fmt"
"sort"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/version"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
)
// upgradeInfo holds all the information required for taking upgrade decisions for a provider
type upgradeInfo struct {
// metadata holds the information about releaseSeries and the link between release series and the API Version of Cluster API (contract).
// e.g. release series 0.5.x for the AWS provider --&gt; v1alpha3
metadata *clusterctlv1.Metadata
// currentVersion of the provider
currentVersion *version.Version
// currentContract of the provider
currentContract string
// nextVersions return the list of versions available for upgrades, defined as the list of version available in the provider repository
// greater than the currentVersion.
nextVersions []version.Version
}
// getUpgradeInfo returns all the info required for taking upgrade decisions for a provider.
func (u *providerUpgrader) getUpgradeInfo(provider clusterctlv1.Provider) (*upgradeInfo, error) <span class="cov8" title="1">{
// Gets the list of versions available in the provider repository.
configRepository, err := u.configClient.Providers().Get(provider.ProviderName, provider.GetProviderType())
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">providerRepository, err := u.repositoryClientFactory(configRepository, u.configClient)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">repositoryVersions, err := providerRepository.GetVersions()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">if len(repositoryVersions) == 0 </span><span class="cov0" title="0">{
return nil, errors.Errorf("failed to get available versions for the %s provider", provider.InstanceName())
}</span>
// Pick the provider's latest version available in the repository and use it to get the most recent metadata for the provider.
<span class="cov8" title="1">var latestVersion *version.Version
for _, availableVersion := range repositoryVersions </span><span class="cov8" title="1">{
availableSemVersion, err := version.ParseSemantic(availableVersion)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to parse available version for the %s provider", provider.InstanceName())
}</span>
<span class="cov8" title="1">if latestVersion == nil || latestVersion.LessThan(availableSemVersion) </span><span class="cov8" title="1">{
latestVersion = availableSemVersion
}</span>
}
<span class="cov8" title="1">latestMetadata, err := providerRepository.Metadata(versionTag(latestVersion)).Get()
if err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
// Get current provider version and check if the releaseSeries defined in metadata includes it.
<span class="cov8" title="1">currentVersion, err := version.ParseSemantic(provider.Version)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to parse current version for the %s provider", provider.InstanceName())
}</span>
<span class="cov8" title="1">if latestMetadata.GetReleaseSeriesForVersion(currentVersion) == nil </span><span class="cov8" title="1">{
return nil, errors.Errorf("invalid provider metadata: version %s (the current version) for the provider %s does not match any release series", provider.Version, provider.InstanceName())
}</span>
// Filters the versions to be considered for upgrading the provider (next versions) and checks if the releaseSeries defined in metadata includes all of them.
<span class="cov8" title="1">nextVersions := []version.Version{}
for _, repositoryVersion := range repositoryVersions </span><span class="cov8" title="1">{
// we are ignoring the conversion error here because a first check already passed above
repositorySemVersion, _ := version.ParseSemantic(repositoryVersion)
// Drop the nextVersion version if older or equal that the current version
// NB. Using !LessThan because version does not implements a GreaterThan method.
if !currentVersion.LessThan(repositorySemVersion) </span><span class="cov8" title="1">{
continue</span>
}
<span class="cov8" title="1">if latestMetadata.GetReleaseSeriesForVersion(repositorySemVersion) == nil </span><span class="cov8" title="1">{
return nil, errors.Errorf("invalid provider metadata: version %s (one of the available versions) for the provider %s does not match any release series", repositoryVersion, provider.InstanceName())
}</span>
<span class="cov8" title="1">nextVersions = append(nextVersions, *repositorySemVersion)</span>
}
<span class="cov8" title="1">return newUpgradeInfo(latestMetadata, currentVersion, nextVersions), nil</span>
}
func newUpgradeInfo(metadata *clusterctlv1.Metadata, currentVersion *version.Version, nextVersions []version.Version) *upgradeInfo <span class="cov8" title="1">{
// Sorts release series; this ensures also an implicit ordering of API Version of Cluster API (contract).
sort.Slice(metadata.ReleaseSeries, func(i, j int) bool </span><span class="cov8" title="1">{
return metadata.ReleaseSeries[i].Major &lt; metadata.ReleaseSeries[j].Major ||
(metadata.ReleaseSeries[i].Major == metadata.ReleaseSeries[j].Major &amp;&amp; metadata.ReleaseSeries[i].Minor &lt; metadata.ReleaseSeries[j].Minor)
}</span>)
// Sorts nextVersions.
<span class="cov8" title="1">sort.Slice(nextVersions, func(i, j int) bool </span><span class="cov8" title="1">{
return nextVersions[i].LessThan(&amp;nextVersions[j])
}</span>)
// Gets the current contract for the provider
// Please note this should never be empty, because getUpgradeInfo ensures the releaseSeries defined in metadata includes the current version.
<span class="cov8" title="1">currentContract := ""
if currentReleaseSeries := metadata.GetReleaseSeriesForVersion(currentVersion); currentReleaseSeries != nil </span><span class="cov8" title="1">{
currentContract = currentReleaseSeries.Contract
}</span>
<span class="cov8" title="1">return &amp;upgradeInfo{
metadata: metadata,
currentVersion: currentVersion,
currentContract: currentContract,
nextVersions: nextVersions,
}</span>
}
// getContractsForUpgrade return the list of API Version of Cluster API (contract) version available for a provider upgrade. e.g.
// - If the current version of the provider support v1alpha3 contract (the latest), it returns v1alpha3
// - If the current version of the provider support v1alpha3 contract but there is also the v1alpha4 contract available, it returns v1alpha3, v1alpha4
func (i *upgradeInfo) getContractsForUpgrade() []string <span class="cov8" title="1">{
contractsForUpgrade := sets.NewString()
for _, releaseSeries := range i.metadata.ReleaseSeries </span><span class="cov8" title="1">{
// Drop the release series if older than the current version, because not relevant for upgrade.
if i.currentVersion.Major() &gt; releaseSeries.Major || (i.currentVersion.Major() == releaseSeries.Major &amp;&amp; i.currentVersion.Minor() &gt; releaseSeries.Minor) </span><span class="cov8" title="1">{
continue</span>
}
<span class="cov8" title="1">contractsForUpgrade.Insert(releaseSeries.Contract)</span>
}
<span class="cov8" title="1">return contractsForUpgrade.List()</span>
}
// getLatestNextVersion returns the next available version for a provider within the target API Version of Cluster API (contract).
// the next available version is tha latest version available in the for the target contract version.
func (i *upgradeInfo) getLatestNextVersion(contract string) *version.Version <span class="cov8" title="1">{
var latestNextVersion *version.Version
for _, releaseSeries := range i.metadata.ReleaseSeries </span><span class="cov8" title="1">{
// Skip the release series if not linked with the target contract version version
if releaseSeries.Contract != contract </span><span class="cov8" title="1">{
continue</span>
}
<span class="cov8" title="1">for j := range i.nextVersions </span><span class="cov8" title="1">{
nextVersion := &amp;i.nextVersions[j]
// Drop the nextVersion version if not linked with the current release series
if nextVersion.Major() != releaseSeries.Major || nextVersion.Minor() != releaseSeries.Minor </span><span class="cov8" title="1">{
continue</span>
}
// Drop the nextVersion if older that the latestNextVersion selected so far
<span class="cov8" title="1">if latestNextVersion == nil || latestNextVersion.LessThan(nextVersion) </span><span class="cov8" title="1">{
latestNextVersion = nextVersion
}</span>
}
}
<span class="cov8" title="1">return latestNextVersion</span>
}
// versionTag converts a version to a RepositoryTag
func versionTag(version *version.Version) string <span class="cov8" title="1">{
if version == nil </span><span class="cov8" title="1">{
return ""
}</span>
<span class="cov8" title="1">return fmt.Sprintf("v%s", version.String())</span>
}
</pre>
<pre class="file" id="file73" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 client
import (
"strings"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/validation"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
)
// getComponentsByName is a utility method that returns components
// for a given provider with options including targetNamespace, and watchingNamespace.
func (c *clusterctlClient) getComponentsByName(provider string, providerType clusterctlv1.ProviderType, options repository.ComponentsOptions) (repository.Components, error) <span class="cov8" title="1">{
// Parse the abbreviated syntax for name[:version]
name, version, err := parseProviderName(provider)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">options.Version = version
// Gets the provider configuration (that includes the location of the provider repository)
providerConfig, err := c.configClient.Providers().Get(name, providerType)
if err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
// Get a client for the provider repository and read the provider components;
// during the process, provider components will be processed performing variable substitution, customization of target
// and watching namespace etc.
// Currently we are not supporting custom yaml processors for the provider
// components. So we revert to using the default SimpleYamlProcessor.
<span class="cov8" title="1">repositoryClientFactory, err := c.repositoryClientFactory(RepositoryClientFactoryInput{provider: providerConfig})
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">components, err := repositoryClientFactory.Components().Get(options)
if err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
<span class="cov8" title="1">return components, nil</span>
}
// parseProviderName defines a utility function that parses the abbreviated syntax for name[:version]
func parseProviderName(provider string) (name string, version string, err error) <span class="cov8" title="1">{
t := strings.Split(strings.ToLower(provider), ":")
if len(t) &gt; 2 </span><span class="cov0" title="0">{
return "", "", errors.Errorf("invalid provider name %q. Provider name should be in the form name[:version]", provider)
}</span>
<span class="cov8" title="1">if t[0] == "" </span><span class="cov0" title="0">{
return "", "", errors.Errorf("invalid provider name %q. Provider name should be in the form name[:version] and name cannot be empty", provider)
}</span>
<span class="cov8" title="1">name = t[0]
if err := validateDNS1123Label(name); err != nil </span><span class="cov0" title="0">{
return "", "", errors.Wrapf(err, "invalid provider name %q. Provider name should be in the form name[:version] and the name should be valid", provider)
}</span>
<span class="cov8" title="1">version = ""
if len(t) &gt; 1 </span><span class="cov8" title="1">{
if t[1] == "" </span><span class="cov0" title="0">{
return "", "", errors.Errorf("invalid provider name %q. Provider name should be in the form name[:version] and version cannot be empty", provider)
}</span>
<span class="cov8" title="1">version = t[1]</span>
}
<span class="cov8" title="1">return name, version, nil</span>
}
func validateDNS1123Label(label string) error <span class="cov8" title="1">{
errs := validation.IsDNS1123Label(label)
if len(errs) != 0 </span><span class="cov8" title="1">{
return errors.New(strings.Join(errs, "; "))
}</span>
<span class="cov8" title="1">return nil</span>
}
func validateDNS1123Domanin(subdomain string) error <span class="cov8" title="1">{
errs := validation.IsDNS1123Subdomain(subdomain)
if len(errs) != 0 </span><span class="cov0" title="0">{
return errors.New(strings.Join(errs, "; "))
}</span>
<span class="cov8" title="1">return nil</span>
}
</pre>
<pre class="file" id="file74" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 client
import (
"strconv"
"k8s.io/utils/pointer"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/version"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
)
func (c *clusterctlClient) GetProvidersConfig() ([]Provider, error) <span class="cov8" title="1">{
r, err := c.configClient.Providers().List()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// Provider is an alias for config.Provider; this makes the conversion
<span class="cov8" title="1">rr := make([]Provider, len(r))
for i, provider := range r </span><span class="cov8" title="1">{
rr[i] = provider
}</span>
<span class="cov8" title="1">return rr, nil</span>
}
func (c *clusterctlClient) GetProviderComponents(provider string, providerType clusterctlv1.ProviderType, options ComponentsOptions) (Components, error) <span class="cov8" title="1">{
// ComponentsOptions is an alias for repository.ComponentsOptions; this makes the conversion
inputOptions := repository.ComponentsOptions{
Version: options.Version,
TargetNamespace: options.TargetNamespace,
WatchingNamespace: options.WatchingNamespace,
SkipVariables: options.SkipVariables,
}
components, err := c.getComponentsByName(provider, providerType, inputOptions)
if err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
<span class="cov8" title="1">return components, nil</span>
}
// GetClusterTemplateOptions carries the options supported by GetClusterTemplate.
type GetClusterTemplateOptions struct {
// Kubeconfig defines the kubeconfig to use for accessing the management cluster. If empty,
// default rules for kubeconfig discovery will be used.
Kubeconfig Kubeconfig
// ProviderRepositorySource to be used for reading the workload cluster template from a provider repository;
// only one template source can be used at time; if not other source will be set, a ProviderRepositorySource
// will be generated inferring values from the cluster.
ProviderRepositorySource *ProviderRepositorySourceOptions
// URLSource to be used for reading the workload cluster template; only one template source can be used at time.
URLSource *URLSourceOptions
// ConfigMapSource to be used for reading the workload cluster template; only one template source can be used at time.
ConfigMapSource *ConfigMapSourceOptions
// TargetNamespace where the objects describing the workload cluster should be deployed. If unspecified,
// the current namespace will be used.
TargetNamespace string
// ClusterName to be used for the workload cluster.
ClusterName string
// KubernetesVersion to use for the workload cluster. If unspecified, the value from os env variables
// or the .cluster-api/clusterctl.yaml config file will be used.
KubernetesVersion string
// ControlPlaneMachineCount defines the number of control plane machines to be added to the workload cluster.
// It can be set through the cli flag, CONTROL_PLANE_MACHINE_COUNT environment variable or will default to 1
ControlPlaneMachineCount *int64
// WorkerMachineCount defines number of worker machines to be added to the workload cluster.
// It can be set through the cli flag, WORKER_MACHINE_COUNT environment variable or will default to 0
WorkerMachineCount *int64
// ListVariablesOnly sets the GetClusterTemplate method to return the list of variables expected by the template
// without executing any further processing.
ListVariablesOnly bool
// YamlProcessor defines the yaml processor to use for the cluster
// template processing. If not defined, SimpleProcessor will be used.
YamlProcessor Processor
}
// numSources return the number of template sources currently set on a GetClusterTemplateOptions.
func (o *GetClusterTemplateOptions) numSources() int <span class="cov8" title="1">{
numSources := 0
if o.ProviderRepositorySource != nil </span><span class="cov8" title="1">{
numSources++
}</span>
<span class="cov8" title="1">if o.ConfigMapSource != nil </span><span class="cov8" title="1">{
numSources++
}</span>
<span class="cov8" title="1">if o.URLSource != nil </span><span class="cov8" title="1">{
numSources++
}</span>
<span class="cov8" title="1">return numSources</span>
}
// ProviderRepositorySourceOptions defines the options to be used when reading a workload cluster template
// from a provider repository.
type ProviderRepositorySourceOptions struct {
// InfrastructureProvider to read the workload cluster template from. If unspecified, the default
// infrastructure provider will be used if no other sources are specified.
InfrastructureProvider string
// Flavor defines The workload cluster template variant to be used when reading from the infrastructure
// provider repository. If unspecified, the default cluster template will be used.
Flavor string
}
// URLSourceOptions defines the options to be used when reading a workload cluster template from an URL.
type URLSourceOptions struct {
// URL to read the workload cluster template from.
URL string
}
// DefaultCustomTemplateConfigMapKey where the workload cluster template is hosted.
const DefaultCustomTemplateConfigMapKey = "template"
// ConfigMapSourceOptions defines the options to be used when reading a workload cluster template from a ConfigMap.
type ConfigMapSourceOptions struct {
// Namespace where the ConfigMap exists. If unspecified, the current namespace will be used.
Namespace string
// Name to read the workload cluster template from.
Name string
// DataKey where the workload cluster template is hosted. If unspecified, the
// DefaultCustomTemplateConfigMapKey will be used.
DataKey string
}
func (c *clusterctlClient) GetClusterTemplate(options GetClusterTemplateOptions) (Template, error) <span class="cov8" title="1">{
// Checks that no more than on source is set
numsSource := options.numSources()
if numsSource &gt; 1 </span><span class="cov0" title="0">{
return nil, errors.New("invalid cluster template source: only one template can be used at time")
}</span>
// If no source is set, defaults to using an empty ProviderRepositorySource so values will be
// inferred from the cluster inventory.
<span class="cov8" title="1">if numsSource == 0 </span><span class="cov0" title="0">{
options.ProviderRepositorySource = &amp;ProviderRepositorySourceOptions{}
}</span>
// Gets the client for the current management cluster
<span class="cov8" title="1">cluster, err := c.clusterClientFactory(ClusterClientFactoryInput{options.Kubeconfig, options.YamlProcessor})
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// If the option specifying the targetNamespace is empty, try to detect it.
<span class="cov8" title="1">if options.TargetNamespace == "" </span><span class="cov8" title="1">{
currentNamespace, err := cluster.Proxy().CurrentNamespace()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">if currentNamespace == "" </span><span class="cov0" title="0">{
return nil, errors.New("failed to identify the current namespace. Please specify a target namespace")
}</span>
<span class="cov8" title="1">options.TargetNamespace = currentNamespace</span>
}
// Inject some of the templateOptions into the configClient so they can be consumed as a variables from the template.
<span class="cov8" title="1">if err := c.templateOptionsToVariables(options); err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// Gets the workload cluster template from the selected source
<span class="cov8" title="1">if options.ProviderRepositorySource != nil </span><span class="cov8" title="1">{
return c.getTemplateFromRepository(cluster, options)
}</span>
<span class="cov8" title="1">if options.ConfigMapSource != nil </span><span class="cov8" title="1">{
return c.getTemplateFromConfigMap(cluster, *options.ConfigMapSource, options.TargetNamespace, options.ListVariablesOnly)
}</span>
<span class="cov8" title="1">if options.URLSource != nil </span><span class="cov8" title="1">{
return c.getTemplateFromURL(cluster, *options.URLSource, options.TargetNamespace, options.ListVariablesOnly)
}</span>
<span class="cov0" title="0">return nil, errors.New("unable to read custom template. Please specify a template source")</span>
}
// getTemplateFromRepository returns a workload cluster template from a provider repository.
func (c *clusterctlClient) getTemplateFromRepository(cluster cluster.Client, options GetClusterTemplateOptions) (Template, error) <span class="cov8" title="1">{
source := *options.ProviderRepositorySource
targetNamespace := options.TargetNamespace
listVariablesOnly := options.ListVariablesOnly
processor := options.YamlProcessor
// If the option specifying the name of the infrastructure provider to get templates from is empty, try to detect it.
provider := source.InfrastructureProvider
ensureCustomResourceDefinitions := false
if provider == "" </span><span class="cov8" title="1">{
// ensure the custom resource definitions required by clusterctl are in place
if err := cluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to identify the default infrastructure provider. Please specify an infrastructure provider")
}</span>
<span class="cov8" title="1">ensureCustomResourceDefinitions = true
defaultProviderName, err := cluster.ProviderInventory().GetDefaultProviderName(clusterctlv1.InfrastructureProviderType)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">if defaultProviderName == "" </span><span class="cov0" title="0">{
return nil, errors.New("failed to identify the default infrastructure provider. Please specify an infrastructure provider")
}</span>
<span class="cov8" title="1">provider = defaultProviderName</span>
}
// parse the abbreviated syntax for name[:version]
<span class="cov8" title="1">name, version, err := parseProviderName(provider)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// If the version of the infrastructure provider to get templates from is empty, try to detect it.
<span class="cov8" title="1">if version == "" </span><span class="cov8" title="1">{
// ensure the custom resource definitions required by clusterctl are in place (if not already done)
if !ensureCustomResourceDefinitions </span><span class="cov0" title="0">{
if err := cluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to identify the default version for the provider %q. Please specify a version", name)
}</span>
}
<span class="cov8" title="1">defaultProviderVersion, err := cluster.ProviderInventory().GetDefaultProviderVersion(name, clusterctlv1.InfrastructureProviderType)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">if defaultProviderVersion == "" </span><span class="cov0" title="0">{
return nil, errors.Errorf("failed to identify the default version for the provider %q. Please specify a version", name)
}</span>
<span class="cov8" title="1">version = defaultProviderVersion</span>
}
// Get the template from the template repository.
<span class="cov8" title="1">providerConfig, err := c.configClient.Providers().Get(name, clusterctlv1.InfrastructureProviderType)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">repo, err := c.repositoryClientFactory(RepositoryClientFactoryInput{provider: providerConfig, processor: processor})
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">template, err := repo.Templates(version).Get(source.Flavor, targetNamespace, listVariablesOnly)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">return template, nil</span>
}
// getTemplateFromConfigMap returns a workload cluster template from a ConfigMap.
func (c *clusterctlClient) getTemplateFromConfigMap(cluster cluster.Client, source ConfigMapSourceOptions, targetNamespace string, listVariablesOnly bool) (Template, error) <span class="cov8" title="1">{
// If the option specifying the configMapNamespace is empty, default it to the current namespace.
if source.Namespace == "" </span><span class="cov0" title="0">{
currentNamespace, err := cluster.Proxy().CurrentNamespace()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">source.Namespace = currentNamespace</span>
}
// If the option specifying the configMapDataKey is empty, default it.
<span class="cov8" title="1">if source.DataKey == "" </span><span class="cov0" title="0">{
source.DataKey = DefaultCustomTemplateConfigMapKey
}</span>
<span class="cov8" title="1">return cluster.Template().GetFromConfigMap(source.Namespace, source.Name, source.DataKey, targetNamespace, listVariablesOnly)</span>
}
// getTemplateFromURL returns a workload cluster template from an URL.
func (c *clusterctlClient) getTemplateFromURL(cluster cluster.Client, source URLSourceOptions, targetNamespace string, listVariablesOnly bool) (Template, error) <span class="cov8" title="1">{
return cluster.Template().GetFromURL(source.URL, targetNamespace, listVariablesOnly)
}</span>
// templateOptionsToVariables injects some of the templateOptions to the configClient so they can be consumed as a variables from the template.
func (c *clusterctlClient) templateOptionsToVariables(options GetClusterTemplateOptions) error <span class="cov8" title="1">{
// the TargetNamespace, if valid, can be used in templates using the ${ NAMESPACE } variable.
if err := validateDNS1123Label(options.TargetNamespace); err != nil </span><span class="cov8" title="1">{
return errors.Wrapf(err, "invalid target-namespace")
}</span>
<span class="cov8" title="1">c.configClient.Variables().Set("NAMESPACE", options.TargetNamespace)
// the ClusterName, if valid, can be used in templates using the ${ CLUSTER_NAME } variable.
if err := validateDNS1123Domanin(options.ClusterName); err != nil </span><span class="cov0" title="0">{
return errors.Wrapf(err, "invalid cluster name")
}</span>
<span class="cov8" title="1">c.configClient.Variables().Set("CLUSTER_NAME", options.ClusterName)
// the KubernetesVersion, if valid, can be used in templates using the ${ KUBERNETES_VERSION } variable.
// NB. in case the KubernetesVersion from the templateOptions is empty, we are not setting any values so the
// configClient is going to search into os env variables/the clusterctl config file as a fallback options.
if options.KubernetesVersion != "" </span><span class="cov8" title="1">{
if _, err := version.ParseSemantic(options.KubernetesVersion); err != nil </span><span class="cov8" title="1">{
return errors.Errorf("invalid KubernetesVersion. Please use a semantic version number")
}</span>
<span class="cov8" title="1">c.configClient.Variables().Set("KUBERNETES_VERSION", options.KubernetesVersion)</span>
}
// the ControlPlaneMachineCount, if valid, can be used in templates using the ${ CONTROL_PLANE_MACHINE_COUNT } variable.
<span class="cov8" title="1">if options.ControlPlaneMachineCount == nil </span><span class="cov8" title="1">{
// Check if set through env variable and default to 1 otherwise
if v, err := c.configClient.Variables().Get("CONTROL_PLANE_MACHINE_COUNT"); err != nil </span><span class="cov8" title="1">{
options.ControlPlaneMachineCount = pointer.Int64Ptr(1)
}</span> else<span class="cov8" title="1"> {
i, err := strconv.ParseInt(v, 10, 64)
if err != nil </span><span class="cov0" title="0">{
return errors.Errorf("invalid value for CONTROL_PLANE_MACHINE_COUNT set")
}</span>
<span class="cov8" title="1">options.ControlPlaneMachineCount = &amp;i</span>
}
}
<span class="cov8" title="1">if *options.ControlPlaneMachineCount &lt; 1 </span><span class="cov8" title="1">{
return errors.Errorf("invalid ControlPlaneMachineCount. Please use a number greater or equal than 1")
}</span>
<span class="cov8" title="1">c.configClient.Variables().Set("CONTROL_PLANE_MACHINE_COUNT", strconv.FormatInt(*options.ControlPlaneMachineCount, 10))
// the WorkerMachineCount, if valid, can be used in templates using the ${ WORKER_MACHINE_COUNT } variable.
if options.WorkerMachineCount == nil </span><span class="cov8" title="1">{
// Check if set through env variable and default to 0 otherwise
if v, err := c.configClient.Variables().Get("WORKER_MACHINE_COUNT"); err != nil </span><span class="cov8" title="1">{
options.WorkerMachineCount = pointer.Int64Ptr(0)
}</span> else<span class="cov8" title="1"> {
i, err := strconv.ParseInt(v, 10, 64)
if err != nil </span><span class="cov0" title="0">{
return errors.Errorf("invalid value for WORKER_MACHINE_COUNT set")
}</span>
<span class="cov8" title="1">options.WorkerMachineCount = &amp;i</span>
}
}
<span class="cov8" title="1">if *options.WorkerMachineCount &lt; 0 </span><span class="cov8" title="1">{
return errors.Errorf("invalid WorkerMachineCount. Please use a number greater or equal than 0")
}</span>
<span class="cov8" title="1">c.configClient.Variables().Set("WORKER_MACHINE_COUNT", strconv.FormatInt(*options.WorkerMachineCount, 10))
return nil</span>
}
</pre>
<pre class="file" id="file75" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 config
import (
"github.com/pkg/errors"
)
// Client is used to interact with the clusterctl configurations.
// Clusterctl v2 handles the following configurations:
// 1. The configuration of the providers (name, type and URL of the provider repository)
// 2. Variables used when installing providers/creating clusters. Variables can be read from the environment or from the config file
// 3. The configuration about image overrides
type Client interface {
// Providers provide access to provider configurations.
Providers() ProvidersClient
// Variables provide access to environment variables and/or variables defined in the clusterctl configuration file.
Variables() VariablesClient
// ImageMeta provide access to to image meta configurations.
ImageMeta() ImageMetaClient
}
// configClient implements Client.
type configClient struct {
reader Reader
}
// ensure configClient implements Client.
var _ Client = &amp;configClient{}
func (c *configClient) Providers() ProvidersClient <span class="cov0" title="0">{
return newProvidersClient(c.reader)
}</span>
func (c *configClient) Variables() VariablesClient <span class="cov0" title="0">{
return newVariablesClient(c.reader)
}</span>
func (c *configClient) ImageMeta() ImageMetaClient <span class="cov0" title="0">{
return newImageMetaClient(c.reader)
}</span>
// Option is a configuration option supplied to New
type Option func(*configClient)
// InjectReader allows to override the default configuration reader used by clusterctl.
func InjectReader(reader Reader) Option <span class="cov0" title="0">{
return func(c *configClient) </span><span class="cov0" title="0">{
c.reader = reader
}</span>
}
// New returns a Client for interacting with the clusterctl configuration.
func New(path string, options ...Option) (Client, error) <span class="cov0" title="0">{
return newConfigClient(path, options...)
}</span>
func newConfigClient(path string, options ...Option) (*configClient, error) <span class="cov0" title="0">{
client := &amp;configClient{}
for _, o := range options </span><span class="cov0" title="0">{
o(client)
}</span>
// if there is an injected reader, use it, otherwise use a default one
<span class="cov0" title="0">if client.reader == nil </span><span class="cov0" title="0">{
client.reader = newViperReader()
if err := client.reader.Init(path); err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "failed to initialize the configuration reader")
}</span>
}
<span class="cov0" title="0">return client, nil</span>
}
// Reader define the behaviours of a configuration reader.
type Reader interface {
// Init allows to initialize the configuration reader.
Init(path string) error
// Get returns a configuration value of type string.
// In case the configuration value does not exists, it returns an error.
Get(key string) (string, error)
// Set allows to set an explicit override for a config value.
// e.g. It is used to set an override from a flag value over environment/config file variables.
Set(key, value string)
// UnmarshalKey reads a configuration value and unmarshals it into the provided value object.
UnmarshalKey(key string, value interface{}) error
}
</pre>
<pre class="file" id="file76" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 config
import (
"strings"
"github.com/pkg/errors"
"sigs.k8s.io/cluster-api/util/container"
)
const (
imagesConfigKey = "images"
allImageConfig = "all"
)
// ImageMetaClient has methods to work with image meta configurations.
type ImageMetaClient interface {
// AlterImage alters an image name according to the current image override configurations.
AlterImage(component, image string) (string, error)
}
// imageMetaClient implements ImageMetaClient.
type imageMetaClient struct {
reader Reader
imageMetaCache map[string]*imageMeta
}
// ensure imageMetaClient implements ImageMetaClient.
var _ ImageMetaClient = &amp;imageMetaClient{}
func newImageMetaClient(reader Reader) *imageMetaClient <span class="cov8" title="1">{
return &amp;imageMetaClient{
reader: reader,
imageMetaCache: map[string]*imageMeta{},
}
}</span>
func (p *imageMetaClient) AlterImage(component, image string) (string, error) <span class="cov8" title="1">{
// Gets the image meta that applies to the selected component; if none, returns early
meta, err := p.getImageMetaByComponent(component)
if err != nil </span><span class="cov8" title="1">{
return "", err
}</span>
<span class="cov8" title="1">if meta == nil </span><span class="cov8" title="1">{
return image, nil
}</span>
// Apply the image meta to image name
<span class="cov8" title="1">return meta.ApplyToImage(image)</span>
}
// getImageMetaByComponent returns the image meta that applies to the selected component
func (p *imageMetaClient) getImageMetaByComponent(component string) (*imageMeta, error) <span class="cov8" title="1">{
// if the image meta for the component is already known, return it
if im, ok := p.imageMetaCache[component]; ok </span><span class="cov0" title="0">{
return im, nil
}</span>
// Otherwise read the image override configurations.
<span class="cov8" title="1">var meta map[string]imageMeta
if err := p.reader.UnmarshalKey(imagesConfigKey, &amp;meta); err != nil </span><span class="cov8" title="1">{
return nil, errors.Wrap(err, "failed to unmarshal image override configurations")
}</span>
// If there are not image override configurations, return.
<span class="cov8" title="1">if meta == nil </span><span class="cov8" title="1">{
p.imageMetaCache[component] = nil
return nil, nil
}</span>
// Gets the image configuration and to the specific component, and returns the union of the two.
<span class="cov8" title="1">m := &amp;imageMeta{}
if allMeta, ok := meta[allImageConfig]; ok </span><span class="cov8" title="1">{
m.Union(&amp;allMeta)
}</span>
<span class="cov8" title="1">if componentMeta, ok := meta[component]; ok </span><span class="cov8" title="1">{
m.Union(&amp;componentMeta)
}</span>
<span class="cov8" title="1">p.imageMetaCache[component] = m
return m, nil</span>
}
// imageMeta allows to define transformations to apply to the image contained in the YAML manifests.
type imageMeta struct {
// repository sets the container registry to pull images from.
Repository string `json:"repository,omitempty"`
// Tag allows to specify a tag for the images.
Tag string `json:"tag,omitempty"`
}
// Union allows to merge two imageMeta transformation; in case both the imageMeta defines new values for the same field,
// the other transformation takes precedence on the existing one.
func (i *imageMeta) Union(other *imageMeta) <span class="cov8" title="1">{
if other.Repository != "" </span><span class="cov8" title="1">{
i.Repository = other.Repository
}</span>
<span class="cov8" title="1">if other.Tag != "" </span><span class="cov8" title="1">{
i.Tag = other.Tag
}</span>
}
// ApplyToImage changes an image name applying the transformations defined in the current imageMeta.
func (i *imageMeta) ApplyToImage(image string) (string, error) <span class="cov8" title="1">{
newImage, err := container.ImageFromString(image)
if err != nil </span><span class="cov8" title="1">{
return "", err
}</span>
// apply transformations
<span class="cov8" title="1">if i.Repository != "" </span><span class="cov8" title="1">{
newImage.Repository = strings.TrimSuffix(i.Repository, "/")
}</span>
<span class="cov8" title="1">if i.Tag != "" </span><span class="cov8" title="1">{
newImage.Tag = i.Tag
}</span>
// returns the resulting image name
<span class="cov8" title="1">return newImage.String(), nil</span>
}
</pre>
<pre class="file" id="file77" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 config
import (
"encoding/json"
"path/filepath"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
)
// Provider defines a provider configuration.
type Provider interface {
// Name returns the name of the provider.
Name() string
// Type returns the type of the provider.
Type() clusterctlv1.ProviderType
// URL returns the name of the provider repository.
URL() string
// SameAs returns true if two providers have the same name and type.
// Please note that this uniquely identifies a provider configuration, but not the provider instances in the cluster
// because it is possible to create many instances of the same provider.
SameAs(other Provider) bool
// ManifestLabel returns the cluster.x-k8s.io/provider label value for a provider.
// Please note that this label uniquely identifies the provider, e.g. bootstrap-kubeadm, but not the instances of
// the provider, e.g. namespace-1/bootstrap-kubeadm and namespace-2/bootstrap-kubeadm
ManifestLabel() string
// Less func can be used to ensure a consist order of provider lists.
Less(other Provider) bool
}
// provider implements provider
type provider struct {
name string
url string
providerType clusterctlv1.ProviderType
}
// ensure provider implements provider
var _ Provider = &amp;provider{}
func (p *provider) Name() string <span class="cov8" title="1">{
return p.name
}</span>
func (p *provider) URL() string <span class="cov8" title="1">{
return p.url
}</span>
func (p *provider) Type() clusterctlv1.ProviderType <span class="cov8" title="1">{
return p.providerType
}</span>
func (p *provider) SameAs(other Provider) bool <span class="cov8" title="1">{
return p.name == other.Name() &amp;&amp; p.providerType == other.Type()
}</span>
func (p *provider) ManifestLabel() string <span class="cov0" title="0">{
return clusterctlv1.ManifestLabel(p.name, p.Type())
}</span>
func (p *provider) Less(other Provider) bool <span class="cov8" title="1">{
return p.providerType.Order() &lt; other.Type().Order() ||
(p.providerType.Order() == other.Type().Order() &amp;&amp; p.name &lt; other.Name())
}</span>
func NewProvider(name string, url string, ttype clusterctlv1.ProviderType) Provider <span class="cov8" title="1">{
return &amp;provider{
name: name,
url: url,
providerType: ttype,
}
}</span>
func (p provider) MarshalJSON() ([]byte, error) <span class="cov0" title="0">{
dir, file := filepath.Split(p.url)
j, err := json.Marshal(struct {
Name string
ProviderType clusterctlv1.ProviderType
URL string
File string
}{
Name: p.name,
ProviderType: p.providerType,
URL: dir,
File: file,
})
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov0" title="0">return j, nil</span>
}
</pre>
<pre class="file" id="file78" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 config
import (
"net/url"
"sort"
"strings"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/validation"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
)
const (
// Core providers
ClusterAPIProviderName = "cluster-api"
// Infra providers
AWSProviderName = "aws"
AzureProviderName = "azure"
Metal3ProviderName = "metal3"
OpenStackProviderName = "openstack"
PacketProviderName = "packet"
VSphereProviderName = "vsphere"
// Bootstrap providers
KubeadmBootstrapProviderName = "kubeadm"
TalosBootstrapProviderName = "talos"
// ControlPlane providers
KubeadmControlPlaneProviderName = "kubeadm"
TalosControlPlaneProviderName = "talos"
// Other
ProvidersConfigKey = "providers"
)
// ProvidersClient has methods to work with provider configurations.
type ProvidersClient interface {
// List returns all the provider configurations, including provider configurations hard-coded in clusterctl
// and user-defined provider configurations read from the clusterctl configuration file.
// In case of conflict, user-defined provider override the hard-coded configurations.
List() ([]Provider, error)
// Get returns the configuration for the provider with a given name/type.
// In case the name/type does not correspond to any existing provider, an error is returned.
Get(name string, providerType clusterctlv1.ProviderType) (Provider, error)
}
// providersClient implements ProvidersClient.
type providersClient struct {
reader Reader
}
// ensure providersClient implements ProvidersClient.
var _ ProvidersClient = &amp;providersClient{}
func newProvidersClient(reader Reader) *providersClient <span class="cov0" title="0">{
return &amp;providersClient{
reader: reader,
}
}</span>
func (p *providersClient) defaults() []Provider <span class="cov8" title="1">{
// clusterctl includes a predefined list of Cluster API providers sponsored by SIG-cluster-lifecycle to provide users the simplest
// out-of-box experience. This is an opt-in feature; other providers can be added by using the clusterctl configuration file.
// if you are a developer of a SIG-cluster-lifecycle project, you can send a PR to extend the following list.
defaults := []Provider{
// cluster API core provider
&amp;provider{
name: ClusterAPIProviderName,
url: "https://github.com/kubernetes-sigs/cluster-api/releases/latest/core-components.yaml",
providerType: clusterctlv1.CoreProviderType,
},
// Infrastructure providers
&amp;provider{
name: AWSProviderName,
url: "https://github.com/kubernetes-sigs/cluster-api-provider-aws/releases/latest/infrastructure-components.yaml",
providerType: clusterctlv1.InfrastructureProviderType,
},
&amp;provider{
name: AzureProviderName,
url: "https://github.com/kubernetes-sigs/cluster-api-provider-azure/releases/latest/infrastructure-components.yaml",
providerType: clusterctlv1.InfrastructureProviderType,
},
&amp;provider{
name: PacketProviderName,
url: "https://github.com/kubernetes-sigs/cluster-api-provider-packet/releases/latest/infrastructure-components.yaml",
providerType: clusterctlv1.InfrastructureProviderType,
},
&amp;provider{
name: Metal3ProviderName,
url: "https://github.com/metal3-io/cluster-api-provider-metal3/releases/latest/infrastructure-components.yaml",
providerType: clusterctlv1.InfrastructureProviderType,
},
&amp;provider{
name: OpenStackProviderName,
url: "https://github.com/kubernetes-sigs/cluster-api-provider-openstack/releases/latest/infrastructure-components.yaml",
providerType: clusterctlv1.InfrastructureProviderType,
},
&amp;provider{
name: VSphereProviderName,
url: "https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/releases/latest/infrastructure-components.yaml",
providerType: clusterctlv1.InfrastructureProviderType,
},
// Bootstrap providers
&amp;provider{
name: KubeadmBootstrapProviderName,
url: "https://github.com/kubernetes-sigs/cluster-api/releases/latest/bootstrap-components.yaml",
providerType: clusterctlv1.BootstrapProviderType,
},
&amp;provider{
name: TalosBootstrapProviderName,
url: "https://github.com/talos-systems/cluster-api-bootstrap-provider-talos/releases/latest/bootstrap-components.yaml",
providerType: clusterctlv1.BootstrapProviderType,
},
// ControlPlane providers
&amp;provider{
name: KubeadmControlPlaneProviderName,
url: "https://github.com/kubernetes-sigs/cluster-api/releases/latest/control-plane-components.yaml",
providerType: clusterctlv1.ControlPlaneProviderType,
},
&amp;provider{
name: TalosControlPlaneProviderName,
url: "https://github.com/talos-systems/cluster-api-control-plane-provider-talos/releases/latest/control-plane-components.yaml",
providerType: clusterctlv1.ControlPlaneProviderType,
},
}
return defaults
}</span>
// configProvider mirrors config.Provider interface and allows serialization of the corresponding info
type configProvider struct {
Name string `json:"name,omitempty"`
URL string `json:"url,omitempty"`
Type clusterctlv1.ProviderType `json:"type,omitempty"`
}
func (p *providersClient) List() ([]Provider, error) <span class="cov8" title="1">{
// Creates a maps with all the defaults provider configurations
providers := p.defaults()
// Gets user defined provider configurations, validate them, and merges with
// hard-coded configurations handling conflicts (user defined take precedence on hard-coded)
userDefinedProviders := []configProvider{}
if err := p.reader.UnmarshalKey(ProvidersConfigKey, &amp;userDefinedProviders); err != nil </span><span class="cov8" title="1">{
return nil, errors.Wrap(err, "failed to unmarshal providers from the clusterctl configuration file")
}</span>
<span class="cov8" title="1">for _, u := range userDefinedProviders </span><span class="cov8" title="1">{
provider := NewProvider(u.Name, u.URL, u.Type)
if err := validateProvider(provider); err != nil </span><span class="cov8" title="1">{
return nil, errors.Wrapf(err, "error validating configuration for the %s with name %s. Please fix the providers value in clusterctl configuration file", provider.Type(), provider.Name())
}</span>
<span class="cov8" title="1">override := false
for i := range providers </span><span class="cov8" title="1">{
if providers[i].SameAs(provider) </span><span class="cov8" title="1">{
providers[i] = provider
override = true
}</span>
}
<span class="cov8" title="1">if !override </span><span class="cov8" title="1">{
providers = append(providers, provider)
}</span>
}
// ensure provider configurations are consistently sorted
<span class="cov8" title="1">sort.Slice(providers, func(i, j int) bool </span><span class="cov8" title="1">{
return providers[i].Less(providers[j])
}</span>)
<span class="cov8" title="1">return providers, nil</span>
}
func (p *providersClient) Get(name string, providerType clusterctlv1.ProviderType) (Provider, error) <span class="cov8" title="1">{
l, err := p.List()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">provider := NewProvider(name, "", providerType) //Nb. Having the url empty is fine because the url is not considered by SameAs.
for _, r := range l </span><span class="cov8" title="1">{
if r.SameAs(provider) </span><span class="cov8" title="1">{
return r, nil
}</span>
}
<span class="cov8" title="1">return nil, errors.Errorf("failed to get configuration for the %s with name %s. Please check the provider name and/or add configuration for new providers using the .clusterctl config file", providerType, name)</span>
}
func validateProvider(r Provider) error <span class="cov8" title="1">{
if r.Name() == "" </span><span class="cov8" title="1">{
return errors.New("name value cannot be empty")
}</span>
<span class="cov8" title="1">if (r.Name() == ClusterAPIProviderName) != (r.Type() == clusterctlv1.CoreProviderType) </span><span class="cov8" title="1">{
return errors.Errorf("name %s must be used with the %s type (name: %s, type: %s)", ClusterAPIProviderName, clusterctlv1.CoreProviderType, r.Name(), r.Type())
}</span>
<span class="cov8" title="1">errMsgs := validation.IsDNS1123Subdomain(r.Name())
if len(errMsgs) != 0 </span><span class="cov8" title="1">{
return errors.Errorf("invalid provider name: %s", strings.Join(errMsgs, "; "))
}</span>
<span class="cov8" title="1">if r.URL() == "" </span><span class="cov8" title="1">{
return errors.New("provider URL value cannot be empty")
}</span>
<span class="cov8" title="1">_, err := url.Parse(r.URL())
if err != nil </span><span class="cov8" title="1">{
return errors.Wrap(err, "error parsing provider URL")
}</span>
<span class="cov8" title="1">switch r.Type() </span>{
case clusterctlv1.CoreProviderType,
clusterctlv1.BootstrapProviderType,
clusterctlv1.InfrastructureProviderType,
clusterctlv1.ControlPlaneProviderType:<span class="cov8" title="1">
break</span>
default:<span class="cov8" title="1">
return errors.Errorf("invalid provider type. Allowed values are [%s, %s, %s, %s]",
clusterctlv1.CoreProviderType,
clusterctlv1.BootstrapProviderType,
clusterctlv1.InfrastructureProviderType,
clusterctlv1.ControlPlaneProviderType)</span>
}
<span class="cov8" title="1">return nil</span>
}
</pre>
<pre class="file" id="file79" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 config
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/pkg/errors"
"github.com/spf13/viper"
"k8s.io/client-go/util/homedir"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
)
const (
// ConfigFolder defines the name of the config folder under $home
ConfigFolder = ".cluster-api"
// ConfigName defines the name of the config file under ConfigFolder
ConfigName = "clusterctl"
)
// viperReader implements Reader using viper as backend for reading from environment variables
// and from a clusterctl config file.
type viperReader struct {
configPaths []string
}
type viperReaderOption func(*viperReader)
func InjectConfigPaths(configPaths []string) viperReaderOption <span class="cov8" title="1">{
return func(vr *viperReader) </span><span class="cov8" title="1">{
vr.configPaths = configPaths
}</span>
}
// newViperReader returns a viperReader.
func newViperReader(opts ...viperReaderOption) Reader <span class="cov8" title="1">{
vr := &amp;viperReader{
configPaths: []string{filepath.Join(homedir.HomeDir(), ConfigFolder)},
}
for _, o := range opts </span><span class="cov8" title="1">{
o(vr)
}</span>
<span class="cov8" title="1">return vr</span>
}
// Init initialize the viperReader.
func (v *viperReader) Init(path string) error <span class="cov8" title="1">{
log := logf.Log
// Configure viper for reading environment variables as well, and more specifically:
// AutomaticEnv force viper to check for an environment variable any time a viper.Get request is made.
// It will check for a environment variable with a name matching the key uppercased; in case name use the - delimiter,
// the SetEnvKeyReplacer forces matching to name use the _ delimiter instead (- is not allowed in linux env variable names).
replacer := strings.NewReplacer("-", "_")
viper.SetEnvKeyReplacer(replacer)
viper.AllowEmptyEnv(true)
viper.AutomaticEnv()
// Reads the clusterctl config file
if path != "" </span><span class="cov8" title="1">{
if _, err := os.Stat(path); err != nil </span><span class="cov8" title="1">{
return err
}</span>
// Use path file from the flag.
<span class="cov8" title="1">viper.SetConfigFile(path)</span>
} else<span class="cov8" title="1"> {
// Checks if there is a default .cluster-api/clusterctl{.extension} file in home directory
if !v.checkDefaultConfig() </span><span class="cov8" title="1">{
// since there is no default config to read from, just skip
// reading in config
log.V(5).Info("No default config file available")
return nil
}</span>
// Configure viper for reading .cluster-api/clusterctl{.extension} in home directory
<span class="cov0" title="0">viper.SetConfigName(ConfigName)
for _, p := range v.configPaths </span><span class="cov0" title="0">{
viper.AddConfigPath(p)
}</span>
}
<span class="cov8" title="1">if err := viper.ReadInConfig(); err != nil </span><span class="cov8" title="1">{
return err
}</span>
<span class="cov8" title="1">log.V(5).Info("Using configuration", "File", viper.ConfigFileUsed())
return nil</span>
}
func (v *viperReader) Get(key string) (string, error) <span class="cov8" title="1">{
if viper.Get(key) == nil </span><span class="cov8" title="1">{
return "", errors.Errorf("Failed to get value for variable %q. Please set the variable value using os env variables or using the .clusterctl config file", key)
}</span>
<span class="cov8" title="1">return viper.GetString(key), nil</span>
}
func (v *viperReader) Set(key, value string) <span class="cov8" title="1">{
viper.Set(key, value)
}</span>
func (v *viperReader) UnmarshalKey(key string, rawval interface{}) error <span class="cov0" title="0">{
return viper.UnmarshalKey(key, rawval)
}</span>
// checkDefaultConfig checks the existence of the default config.
// Returns true if it finds a supported config file in the available config
// folders.
func (v *viperReader) checkDefaultConfig() bool <span class="cov8" title="1">{
for _, path := range v.configPaths </span><span class="cov8" title="1">{
for _, ext := range viper.SupportedExts </span><span class="cov8" title="1">{
f := filepath.Join(path, fmt.Sprintf("%s.%s", ConfigName, ext))
_, err := os.Stat(f)
if err == nil </span><span class="cov8" title="1">{
return true
}</span>
}
}
<span class="cov8" title="1">return false</span>
}
</pre>
<pre class="file" id="file80" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 config
const (
// GitHubTokenVariable defines a variable hosting the GitHub access token
GitHubTokenVariable = "github-token"
)
// VariablesClient has methods to work with environment variables and with variables defined in the clusterctl configuration file.
type VariablesClient interface {
// Get returns a variable value. If the variable is not defined an error is returned.
// In case the same variable is defined both within the environment variables and clusterctl configuration file,
// the environment variables value takes precedence.
Get(key string) (string, error)
// Set allows to set an explicit override for a config value.
// e.g. It is used to set an override from a flag value over environment/config file variables.
Set(key, values string)
}
// variablesClient implements VariablesClient.
type variablesClient struct {
reader Reader
}
// ensure variablesClient implements VariablesClient.
var _ VariablesClient = &amp;variablesClient{}
func newVariablesClient(reader Reader) *variablesClient <span class="cov0" title="0">{
return &amp;variablesClient{
reader: reader,
}
}</span>
func (p *variablesClient) Get(key string) (string, error) <span class="cov8" title="1">{
return p.reader.Get(key)
}</span>
func (p *variablesClient) Set(key, value string) <span class="cov0" title="0">{
p.reader.Set(key, value)
}</span>
</pre>
<pre class="file" id="file81" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 client
import (
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
)
// DeleteOptions carries the options supported by Delete.
type DeleteOptions struct {
// Kubeconfig defines the kubeconfig to use for accessing the management cluster. If empty,
// default rules for kubeconfig discovery will be used.
Kubeconfig Kubeconfig
// Namespace where the provider to be deleted lives. If unspecified, the namespace name will be inferred
// from the current configuration.
Namespace string
// CoreProvider version (e.g. cluster-api:v0.3.0) to add to the management cluster. If unspecified, the
// cluster-api core provider's latest release is used.
CoreProvider string
// BootstrapProviders and versions (e.g. kubeadm:v0.3.0) to add to the management cluster.
// If unspecified, the kubeadm bootstrap provider's latest release is used.
BootstrapProviders []string
// InfrastructureProviders and versions (e.g. aws:v0.5.0) to add to the management cluster.
InfrastructureProviders []string
// ControlPlaneProviders and versions (e.g. kubeadm:v0.3.0) to add to the management cluster.
// If unspecified, the kubeadm control plane provider latest release is used.
ControlPlaneProviders []string
// DeleteAll set for deletion of all the providers.
DeleteAll bool
// IncludeNamespace forces the deletion of the namespace where the providers are hosted
// (and of all the contained objects).
IncludeNamespace bool
// IncludeCRDs forces the deletion of the provider's CRDs (and of all the related objects).
// By Extension, this forces the deletion of all the resources shared among provider instances, like e.g. web-hooks.
IncludeCRDs bool
}
func (c *clusterctlClient) Delete(options DeleteOptions) error <span class="cov8" title="1">{
clusterClient, err := c.clusterClientFactory(ClusterClientFactoryInput{kubeconfig: options.Kubeconfig})
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">if err := clusterClient.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Get the list of installed providers.
<span class="cov8" title="1">installedProviders, err := clusterClient.ProviderInventory().List()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Prepare the list of providers to delete.
<span class="cov8" title="1">var providersToDelete []clusterctlv1.Provider
if options.DeleteAll </span><span class="cov8" title="1">{
providersToDelete = installedProviders.Items
}</span> else<span class="cov8" title="1"> {
// Otherwise we are deleting only a subset of providers.
var providers []clusterctlv1.Provider
providers = appendProviders(providers, clusterctlv1.CoreProviderType, options.CoreProvider)
providers = appendProviders(providers, clusterctlv1.BootstrapProviderType, options.BootstrapProviders...)
providers = appendProviders(providers, clusterctlv1.ControlPlaneProviderType, options.ControlPlaneProviders...)
providers = appendProviders(providers, clusterctlv1.InfrastructureProviderType, options.InfrastructureProviders...)
for _, provider := range providers </span><span class="cov8" title="1">{
// Parse the abbreviated syntax for name[:version]
name, _, err := parseProviderName(provider.Name)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// If the namespace where the provider is installed is not provided, try to detect it
<span class="cov8" title="1">provider.Namespace = options.Namespace
if provider.Namespace == "" </span><span class="cov8" title="1">{
provider.Namespace, err = clusterClient.ProviderInventory().GetDefaultProviderNamespace(provider.ProviderName, provider.GetProviderType())
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
// if there are more instance of a providers, it is not possible to get a default namespace for the provider,
// so we should return and ask for it.
<span class="cov8" title="1">if provider.Namespace == "" </span><span class="cov0" title="0">{
return errors.Errorf("Unable to find default namespace for the %q provider. Please specify the provider's namespace", name)
}</span>
}
// Check the provider/type/namespace tuple actually matches one of the installed provider instances.
<span class="cov8" title="1">found := false
for _, ip := range installedProviders.Items </span><span class="cov8" title="1">{
if ip.InstanceName() == provider.InstanceName() </span><span class="cov8" title="1">{
found = true
providersToDelete = append(providersToDelete, ip)
break</span>
}
}
<span class="cov8" title="1">if found </span><span class="cov8" title="1">{
break</span>
}
// In case the provider does not match any installed providers, we still force deletion
// so the user can do 'delete' without removing CRD and after some time 'delete --delete-crd' (same for the namespace).
<span class="cov0" title="0">providersToDelete = append(providersToDelete, provider)</span>
}
}
// Delete the selected providers
<span class="cov8" title="1">for _, provider := range providersToDelete </span><span class="cov8" title="1">{
if err := clusterClient.ProviderComponents().Delete(cluster.DeleteOptions{Provider: provider, IncludeNamespace: options.IncludeNamespace, IncludeCRDs: options.IncludeCRDs}); err != nil </span><span class="cov0" title="0">{
return err
}</span>
}
<span class="cov8" title="1">return nil</span>
}
func appendProviders(list []clusterctlv1.Provider, providerType clusterctlv1.ProviderType, names ...string) []clusterctlv1.Provider <span class="cov8" title="1">{
for _, name := range names </span><span class="cov8" title="1">{
if name == "" </span><span class="cov8" title="1">{
continue</span>
}
<span class="cov8" title="1">list = append(list, clusterctlv1.Provider{
ObjectMeta: metav1.ObjectMeta{
Name: clusterctlv1.ManifestLabel(name, providerType),
},
ProviderName: name,
Type: string(providerType),
})</span>
}
<span class="cov8" title="1">return list</span>
}
</pre>
<pre class="file" id="file82" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 client
import (
"sort"
"github.com/pkg/errors"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
)
const NoopProvider = "-"
// InitOptions carries the options supported by Init.
type InitOptions struct {
// Kubeconfig defines the kubeconfig to use for accessing the management cluster. If empty,
// default rules for kubeconfig discovery will be used.
Kubeconfig Kubeconfig
// CoreProvider version (e.g. cluster-api:v0.3.0) to add to the management cluster. If unspecified, the
// cluster-api core provider's latest release is used.
CoreProvider string
// BootstrapProviders and versions (e.g. kubeadm:v0.3.0) to add to the management cluster.
// If unspecified, the kubeadm bootstrap provider's latest release is used.
BootstrapProviders []string
// InfrastructureProviders and versions (e.g. aws:v0.5.0) to add to the management cluster.
InfrastructureProviders []string
// ControlPlaneProviders and versions (e.g. kubeadm:v0.3.0) to add to the management cluster.
// If unspecified, the kubeadm control plane provider latest release is used.
ControlPlaneProviders []string
// TargetNamespace defines the namespace where the providers should be deployed. If unspecified, each provider
// will be installed in a provider's default namespace.
TargetNamespace string
// WatchingNamespace defines the namespace the providers should watch to reconcile Cluster API objects.
// If unspecified, the providers watches for Cluster API objects across all namespaces.
WatchingNamespace string
// LogUsageInstructions instructs the init command to print the usage instructions in case of first run.
LogUsageInstructions bool
// skipVariables skips variable parsing in the provider components yaml.
// It is set to true for listing images of provider components.
skipVariables bool
}
// Init initializes a management cluster by adding the requested list of providers.
func (c *clusterctlClient) Init(options InitOptions) ([]Components, error) <span class="cov8" title="1">{
log := logf.Log
// gets access to the management cluster
cluster, err := c.clusterClientFactory(ClusterClientFactoryInput{kubeconfig: options.Kubeconfig})
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// ensure the custom resource definitions required by clusterctl are in place
<span class="cov8" title="1">if err := cluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// checks if the cluster already contains a Core provider.
// if not we consider this the first time init is executed, and thus we enforce the installation of a core provider,
// a bootstrap provider and a control-plane provider (if not already explicitly requested by the user)
<span class="cov8" title="1">log.Info("Fetching providers")
firstRun := c.addDefaultProviders(cluster, &amp;options)
// create an installer service, add the requested providers to the install queue and then perform validation
// of the target state of the management cluster before starting the installation.
installer, err := c.setupInstaller(cluster, options)
if err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
// Before installing the providers, validates the management cluster resulting by the planned installation. The following checks are performed:
// - There should be only one instance of the same provider per namespace.
// - Instances of the same provider should not be fighting for objects (no watching overlap).
// - Providers combines in valid management groups
// - All the providers should belong to one/only one management groups
// - All the providers in a management group must support the same API Version of Cluster API (contract)
<span class="cov8" title="1">if err := installer.Validate(); err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// Before installing the providers, ensure the cert-manager Webhook is in place.
<span class="cov8" title="1">if err := cluster.CertManager().EnsureWebhook(); err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">components, err := installer.Install()
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
// If this is the firstRun, then log the usage instructions.
<span class="cov8" title="1">if firstRun &amp;&amp; options.LogUsageInstructions </span><span class="cov0" title="0">{
log.Info("")
log.Info("Your management cluster has been initialized successfully!")
log.Info("")
log.Info("You can now create your first workload cluster by running the following:")
log.Info("")
log.Info(" clusterctl config cluster [name] --kubernetes-version [version] | kubectl apply -f -")
log.Info("")
}</span>
// Components is an alias for repository.Components; this makes the conversion from the two types
<span class="cov8" title="1">aliasComponents := make([]Components, len(components))
for i, components := range components </span><span class="cov8" title="1">{
aliasComponents[i] = components
}</span>
<span class="cov8" title="1">return aliasComponents, nil</span>
}
// Init returns the list of images required for init.
func (c *clusterctlClient) InitImages(options InitOptions) ([]string, error) <span class="cov8" title="1">{
// gets access to the management cluster
cluster, err := c.clusterClientFactory(ClusterClientFactoryInput{kubeconfig: options.Kubeconfig})
if err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
// checks if the cluster already contains a Core provider.
// if not we consider this the first time init is executed, and thus we enforce the installation of a core provider,
// a bootstrap provider and a control-plane provider (if not already explicitly requested by the user)
<span class="cov8" title="1">c.addDefaultProviders(cluster, &amp;options)
// skip variable parsing when listing images
options.skipVariables = true
// create an installer service, add the requested providers to the install queue and then perform validation
// of the target state of the management cluster before starting the installation.
installer, err := c.setupInstaller(cluster, options)
if err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
// Gets the list of container images required for the cert-manager (if not already installed).
<span class="cov8" title="1">images, err := cluster.CertManager().Images()
if err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
// Appends the list of container images required for the selected providers.
<span class="cov8" title="1">images = append(images, installer.Images()...)
sort.Strings(images)
return images, nil</span>
}
func (c *clusterctlClient) setupInstaller(cluster cluster.Client, options InitOptions) (cluster.ProviderInstaller, error) <span class="cov8" title="1">{
installer := cluster.ProviderInstaller()
addOptions := addToInstallerOptions{
installer: installer,
targetNamespace: options.TargetNamespace,
watchingNamespace: options.WatchingNamespace,
skipVariables: options.skipVariables,
}
if options.CoreProvider != "" </span><span class="cov8" title="1">{
if err := c.addToInstaller(addOptions, clusterctlv1.CoreProviderType, options.CoreProvider); err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
}
<span class="cov8" title="1">if err := c.addToInstaller(addOptions, clusterctlv1.BootstrapProviderType, options.BootstrapProviders...); err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
<span class="cov8" title="1">if err := c.addToInstaller(addOptions, clusterctlv1.ControlPlaneProviderType, options.ControlPlaneProviders...); err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
<span class="cov8" title="1">if err := c.addToInstaller(addOptions, clusterctlv1.InfrastructureProviderType, options.InfrastructureProviders...); err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
<span class="cov8" title="1">return installer, nil</span>
}
func (c *clusterctlClient) addDefaultProviders(cluster cluster.Client, options *InitOptions) bool <span class="cov8" title="1">{
firstRun := false
// Check if there is already a core provider installed in the cluster
// Nb. we are ignoring the error so this operation can support listing images even if there is no an existing management cluster;
// in case there is no an existing management cluster, we assume there are no core providers installed in the cluster.
currentCoreProvider, _ := cluster.ProviderInventory().GetDefaultProviderName(clusterctlv1.CoreProviderType)
// If there are no core providers installed in the cluster, consider this a first run and add default providers to the list
// of providers to be installed.
if currentCoreProvider == "" </span><span class="cov8" title="1">{
firstRun = true
if options.CoreProvider == "" </span><span class="cov8" title="1">{
options.CoreProvider = config.ClusterAPIProviderName
}</span>
<span class="cov8" title="1">if len(options.BootstrapProviders) == 0 </span><span class="cov8" title="1">{
options.BootstrapProviders = append(options.BootstrapProviders, config.KubeadmBootstrapProviderName)
}</span>
<span class="cov8" title="1">if len(options.ControlPlaneProviders) == 0 </span><span class="cov8" title="1">{
options.ControlPlaneProviders = append(options.ControlPlaneProviders, config.KubeadmControlPlaneProviderName)
}</span>
}
<span class="cov8" title="1">return firstRun</span>
}
type addToInstallerOptions struct {
installer cluster.ProviderInstaller
targetNamespace string
watchingNamespace string
skipVariables bool
}
// addToInstaller adds the components to the install queue and checks that the actual provider type match the target group
func (c *clusterctlClient) addToInstaller(options addToInstallerOptions, providerType clusterctlv1.ProviderType, providers ...string) error <span class="cov8" title="1">{
for _, provider := range providers </span><span class="cov8" title="1">{
// It is possible to opt-out from automatic installation of bootstrap/control-plane providers using '-' as a provider name (NoopProvider).
if provider == NoopProvider </span><span class="cov8" title="1">{
if providerType == clusterctlv1.CoreProviderType </span><span class="cov8" title="1">{
return errors.New("the '-' value can not be used for the core provider")
}</span>
<span class="cov8" title="1">continue</span>
}
<span class="cov8" title="1">componentsOptions := repository.ComponentsOptions{
TargetNamespace: options.targetNamespace,
WatchingNamespace: options.watchingNamespace,
SkipVariables: options.skipVariables,
}
components, err := c.getComponentsByName(provider, providerType, componentsOptions)
if err != nil </span><span class="cov8" title="1">{
return errors.Wrapf(err, "failed to get provider components for the %q provider", provider)
}</span>
<span class="cov8" title="1">if components.Type() != providerType </span><span class="cov0" title="0">{
return errors.Errorf("can't use %q provider as an %q, it is a %q", provider, providerType, components.Type())
}</span>
<span class="cov8" title="1">options.installer.Add(components)</span>
}
<span class="cov8" title="1">return nil</span>
}
</pre>
<pre class="file" id="file83" style="display: none">/*
Copyright 2020 The Kubernetes Authors.
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 client
// MoveOptions carries the options supported by move.
type MoveOptions struct {
// FromKubeconfig defines the kubeconfig to use for accessing the source management cluster. If empty,
// default rules for kubeconfig discovery will be used.
FromKubeconfig Kubeconfig
// ToKubeconfig defines the kubeconfig to use for accessing the target management cluster. If empty,
// default rules for kubeconfig discovery will be used.
ToKubeconfig Kubeconfig
// Namespace where the objects describing the workload cluster exists. If unspecified, the current
// namespace will be used.
Namespace string
}
func (c *clusterctlClient) Move(options MoveOptions) error <span class="cov8" title="1">{
// Get the client for interacting with the source management cluster.
fromCluster, err := c.clusterClientFactory(ClusterClientFactoryInput{kubeconfig: options.FromKubeconfig})
if err != nil </span><span class="cov8" title="1">{
return err
}</span>
// Ensures the custom resource definitions required by clusterctl are in place.
<span class="cov8" title="1">if err := fromCluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// Get the client for interacting with the target management cluster.
<span class="cov8" title="1">toCluster, err := c.clusterClientFactory(ClusterClientFactoryInput{kubeconfig: options.ToKubeconfig})
if err != nil </span><span class="cov8" title="1">{
return err
}</span>
// Ensures the custom resource definitions required by clusterctl are in place
<span class="cov8" title="1">if err := toCluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil </span><span class="cov0" title="0">{
return err
}</span>
// If the option specifying the Namespace is empty, try to detect it.
<span class="cov8" title="1">if options.Namespace == "" </span><span class="cov8" title="1">{
currentNamespace, err := fromCluster.Proxy().CurrentNamespace()
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">options.Namespace = currentNamespace</span>
}
<span class="cov8" title="1">if err := fromCluster.ObjectMover().Move(options.Namespace, toCluster); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return nil</span>
}
</pre>
<pre class="file" id="file84" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 repository
import (
"net/url"
"github.com/pkg/errors"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
yaml "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
)
// Client is used to interact with provider repositories.
// Provider repository are expected to contain two types of YAML files:
// - YAML files defining the provider components (CRD, Controller, RBAC etc.)
// - YAML files defining the cluster templates (Cluster, Machines)
type Client interface {
config.Provider
// GetVersion return the list of versions that are available in a provider repository
GetVersions() ([]string, error)
// Components provide access to YAML file for creating provider components.
Components() ComponentsClient
// Templates provide access to YAML file for generating workload cluster templates.
// Please note that templates are expected to exist for the infrastructure providers only.
Templates(version string) TemplateClient
// Metadata provide access to YAML with the provider's metadata.
Metadata(version string) MetadataClient
}
// repositoryClient implements Client.
type repositoryClient struct {
config.Provider
configClient config.Client
repository Repository
processor yaml.Processor
}
// ensure repositoryClient implements Client.
var _ Client = &amp;repositoryClient{}
func (c *repositoryClient) GetVersions() ([]string, error) <span class="cov0" title="0">{
return c.repository.GetVersions()
}</span>
func (c *repositoryClient) Components() ComponentsClient <span class="cov0" title="0">{
return newComponentsClient(c.Provider, c.repository, c.configClient)
}</span>
func (c *repositoryClient) Templates(version string) TemplateClient <span class="cov0" title="0">{
return newTemplateClient(TemplateClientInput{version, c.Provider, c.repository, c.configClient.Variables(), c.processor})
}</span>
func (c *repositoryClient) Metadata(version string) MetadataClient <span class="cov0" title="0">{
return newMetadataClient(c.Provider, version, c.repository, c.configClient.Variables())
}</span>
// Option is a configuration option supplied to New
type Option func(*repositoryClient)
// InjectRepository allows to override the repository implementation to use;
// by default, the repository implementation to use is created according to the
// repository URL.
func InjectRepository(repository Repository) Option <span class="cov8" title="1">{
return func(c *repositoryClient) </span><span class="cov8" title="1">{
c.repository = repository
}</span>
}
// InjectYamlProcessor allows you to override the yaml processor that the
// repository client uses. By default, the SimpleProcessor is used. This is
// true even if a nil processor is injected.
func InjectYamlProcessor(p yaml.Processor) Option <span class="cov8" title="1">{
return func(c *repositoryClient) </span><span class="cov8" title="1">{
if p != nil </span><span class="cov8" title="1">{
c.processor = p
}</span>
}
}
// New returns a Client.
func New(provider config.Provider, configClient config.Client, options ...Option) (Client, error) <span class="cov0" title="0">{
return newRepositoryClient(provider, configClient, options...)
}</span>
func newRepositoryClient(provider config.Provider, configClient config.Client, options ...Option) (*repositoryClient, error) <span class="cov8" title="1">{
client := &amp;repositoryClient{
Provider: provider,
configClient: configClient,
processor: yaml.NewSimpleProcessor(),
}
for _, o := range options </span><span class="cov8" title="1">{
o(client)
}</span>
// if there is an injected repository, use it, otherwise use a default one
<span class="cov8" title="1">if client.repository == nil </span><span class="cov8" title="1">{
r, err := repositoryFactory(provider, configClient.Variables())
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrapf(err, "failed to get repository client for the %s with name %s", provider.Type(), provider.Name())
}</span>
<span class="cov8" title="1">client.repository = r</span>
}
<span class="cov8" title="1">return client, nil</span>
}
// Repository defines the behavior of a repository implementation.
// clusterctl is designed to support different repository types; each repository implementation should be aware of
// the provider version they are hosting, and possibly to host more than one version.
type Repository interface {
// DefaultVersion returns the default provider version returned by a repository.
// In case the repository URL points to latest, this method returns the current latest version; in other cases
// it returns the version of the provider hosted in the repository.
DefaultVersion() string
// RootPath returns the path inside the repository where the YAML file for creating provider components and
// the YAML file for generating workload cluster templates are stored.
// This value is derived from the repository URL; all the paths returned by this interface should be relative to this path.
RootPath() string
// ComponentsPath return the path (a folder name or file name) of the YAML file for creating provider components.
// This value is derived from the repository URL.
ComponentsPath() string
// GetFile return a file for a given provider version.
GetFile(version string, path string) ([]byte, error)
// GetVersion return the list of versions that are available in a provider repository
GetVersions() ([]string, error)
}
var _ Repository = &amp;test.FakeRepository{}
//repositoryFactory returns the repository implementation corresponding to the provider URL.
func repositoryFactory(providerConfig config.Provider, configVariablesClient config.VariablesClient) (Repository, error) <span class="cov8" title="1">{
// parse the repository url
rURL, err := url.Parse(providerConfig.URL())
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Errorf("failed to parse repository url %q", providerConfig.URL())
}</span>
// if the url is a github repository
<span class="cov8" title="1">if rURL.Scheme == httpsScheme &amp;&amp; rURL.Host == githubDomain </span><span class="cov0" title="0">{
repo, err := newGitHubRepository(providerConfig, configVariablesClient)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "error creating the GitHub repository client")
}</span>
<span class="cov0" title="0">return repo, err</span>
}
// if the url is a local filesystem repository
<span class="cov8" title="1">if rURL.Scheme == "file" || rURL.Scheme == "" </span><span class="cov8" title="1">{
repo, err := newLocalRepository(providerConfig, configVariablesClient)
if err != nil </span><span class="cov0" title="0">{
return nil, errors.Wrap(err, "error creating the local filesystem repository client")
}</span>
<span class="cov8" title="1">return repo, err</span>
}
<span class="cov0" title="0">return nil, errors.Errorf("invalid provider url. there are no provider implementation for %q schema", rURL.Scheme)</span>
}
</pre>
<pre class="file" id="file85" style="display: none">/*
Copyright 2019 The Kubernetes Authors.
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 repository
import (
"fmt"
"strings"
"github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
yaml "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/scheme"
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util"
utilyaml "sigs.k8s.io/cluster-api/util/yaml"
)
const (
namespaceKind = "Namespace"
clusterRoleKind = "ClusterRole"
clusterRoleBindingKind = "ClusterRoleBinding"
roleBindingKind = "RoleBinding"
validatingWebhookConfigurationKind = "ValidatingWebhookConfiguration"
mutatingWebhookConfigurationKind = "MutatingWebhookConfiguration"
customResourceDefinitionKind = "CustomResourceDefinition"
deploymentKind = "Deployment"
WebhookNamespaceName = "capi-webhook-system"
controllerContainerName = "manager"
namespaceArgPrefix = "--namespace="
)
// Components wraps a YAML file that defines the provider components
// to be installed in a management cluster (CRD, Controller, RBAC etc.)
// It is important to notice that clusterctl applies a set of processing steps to the “raw” component YAML read
// from the provider repositories:
// 1. Checks for all the variables in the component YAML file and replace with corresponding config values
// 2. Ensure all the provider components are deployed in the target namespace (apply only to namespaced objects)
// 3. Ensure all the ClusterRoleBinding which are referencing namespaced objects have the name prefixed with the namespace name
// 4. Set the watching namespace for the provider controller
// 5. Adds labels to all the components in order to allow easy identification of the provider objects
type Components interface {
// configuration of the provider the provider components belongs to.
config.Provid
View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment