Skip to content

Commit

Permalink
fix: validates CONTROL_PLANE_ENDPOINT_IP and NUTANIX_ENDPOINT are dis…
Browse files Browse the repository at this point in the history
…tinct
  • Loading branch information
manoj-nutanix committed Dec 9, 2024
1 parent 11bff42 commit 4651c5b
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
123 changes: 123 additions & 0 deletions pkg/webhook/cluster/nutanix_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2024 Nutanix. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package cluster

import (
"context"
"fmt"
"net"
"net/http"
"net/url"

v1 "k8s.io/api/admission/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/variables"
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/utils"
)

type nutanixValidator struct {
client ctrlclient.Client
decoder admission.Decoder
}

func NewNutanixValidator(
client ctrlclient.Client, decoder admission.Decoder,
) *nutanixValidator {
return &nutanixValidator{
client: client,
decoder: decoder,
}
}

func (a *nutanixValidator) Validator() admission.HandlerFunc {
return a.validate
}

func (a *nutanixValidator) validate(
ctx context.Context,
req admission.Request,
) admission.Response {
if req.Operation == v1.Delete {
return admission.Allowed("")
}

cluster := &clusterv1.Cluster{}
err := a.decoder.Decode(req, cluster)
if err != nil {
return admission.Errored(http.StatusBadRequest, err)
}

if cluster.Spec.Topology == nil {
return admission.Allowed("")
}

if utils.GetProvider(cluster) != "nutanix" {
return admission.Allowed("")
}

clusterConfig, err := variables.UnmarshalClusterConfigVariable(cluster.Spec.Topology.Variables)
if err != nil {
return admission.Denied(
fmt.Errorf("failed to unmarshal cluster topology variable %q: %w",
v1alpha1.ClusterConfigVariableName,
err).Error(),
)
}

if clusterConfig.Nutanix != nil {
// Check if Prism Central and Control Plane IP are same.
if err := checkIfPrismCentralAndControlPlaneIPSame(
clusterConfig.Nutanix.PrismCentralEndpoint.URL,
clusterConfig.Nutanix.ControlPlaneEndpoint.Host,
); err != nil {
return admission.Denied(err.Error())
}
}

return admission.Allowed("")
}

// checkIfPrismCentralAndControlPlaneIPSame checks if Prism Central and Control Plane IP are same.
// It compares strictly IP addresses(no FQDN) and doesn't involve any network calls.
// This is a temporary check until we have a better way to handle this by reserving IPs
// using IPAM provider.
func checkIfPrismCentralAndControlPlaneIPSame(
pcRawURL string,
controlPlaneEndpointHost string,
) error {
controlPlaneEndpointIP := net.ParseIP(controlPlaneEndpointHost)
if controlPlaneEndpointIP == nil {
// controlPlaneEndpointIP is strictly accepted as an IP address from user so
// if it is not an IP address, it is invalid.
return fmt.Errorf("invalid Nutanix control plane endpoint IP %q",
controlPlaneEndpointHost)
}

pcURL, err := url.ParseRequestURI(pcRawURL)
if err != nil {
return fmt.Errorf("failed to parse Prism Central URL %q: %w",
pcURL,
err)
}

pcHost, _, err := net.SplitHostPort(pcURL.Host)
if err != nil {
return fmt.Errorf("failed to parse Prism Central host %q: %w",
pcURL.Host,
err)
}

pcIP := net.ParseIP(pcHost)
// PC URL can contain IP/FQDN, so compare only if PC is an IP address.
if pcIP != nil && pcIP.Equal(controlPlaneEndpointIP) {
return fmt.Errorf("prism central and control plane endpoint cannot have the same IP %q",
pcIP)
}

return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ import (
func NewValidator(client ctrlclient.Client, decoder admission.Decoder) admission.Handler {
return admission.MultiValidatingHandler(
NewClusterUUIDLabeler(client, decoder).Validator(),
NewNutanixValidator(client, decoder).Validator(),
)
}

0 comments on commit 4651c5b

Please sign in to comment.