Skip to content

Commit 505477e

Browse files
committed
feat: adds a validation hook
1 parent 89af502 commit 505477e

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

api/variables/variables.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package variables
5+
6+
import (
7+
"encoding/json"
8+
"fmt"
9+
10+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
11+
)
12+
13+
func UnmarshalRuntimeVariable[T any](runtimeVariable *runtimehooksv1.Variable, obj *T) error {
14+
err := json.Unmarshal(runtimeVariable.Value.Raw, obj)
15+
if err != nil {
16+
return fmt.Errorf("error unmarshalling variable: %w", err)
17+
}
18+
19+
return nil
20+
}
21+
22+
//nolint:gocritic // no need for named results
23+
func GetRuntimhookVariableByName(
24+
name string,
25+
variables []runtimehooksv1.Variable,
26+
) (*runtimehooksv1.Variable, int) {
27+
for i, runtimevar := range variables {
28+
if runtimevar.Name == name {
29+
return &runtimevar, i
30+
}
31+
}
32+
return nil, -1
33+
}

cmd/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
dockermutation "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/mutation"
3535
dockerworkerconfig "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/workerconfig"
3636
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle"
37+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/validation"
3738
nutanixclusterconfig "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig"
3839
nutanixmutation "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation"
3940
nutanixworkerconfig "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/workerconfig"
@@ -84,6 +85,7 @@ func main() {
8485

8586
genericLifecycleHandlers := lifecycle.New(globalOptions)
8687

88+
validationHandlers := validation.New()
8789
// Initialize and parse command line flags.
8890
logs.AddFlags(pflag.CommandLine, logs.SkipLoggingConfigurationFlags())
8991
logsv1.AddFlags(logOptions, pflag.CommandLine)
@@ -142,6 +144,7 @@ func main() {
142144
}
143145

144146
var allHandlers []handlers.Named
147+
allHandlers = append(allHandlers, validationHandlers.AllHandlers(mgr)...)
145148
allHandlers = append(allHandlers, genericLifecycleHandlers.AllHandlers(mgr)...)
146149
allHandlers = append(allHandlers, awsMetaHandlers...)
147150
allHandlers = append(allHandlers, dockerMetaHandlers...)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package validation
5+
6+
import (
7+
"sigs.k8s.io/controller-runtime/pkg/manager"
8+
9+
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers"
10+
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/validation/helm"
11+
)
12+
13+
type Handlers struct{}
14+
15+
func New() *Handlers {
16+
return &Handlers{}
17+
}
18+
19+
func (h *Handlers) AllHandlers(mgr manager.Manager) []handlers.Named {
20+
validationHandler := helm.New(mgr.GetClient())
21+
return []handlers.Named{
22+
validationHandler,
23+
}
24+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package helm
5+
6+
import (
7+
"context"
8+
"crypto/tls"
9+
"fmt"
10+
"net/http"
11+
12+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
13+
ctrl "sigs.k8s.io/controller-runtime"
14+
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
15+
16+
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
17+
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables"
18+
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig"
19+
)
20+
21+
type HelmRegistryValidator struct {
22+
client ctrlclient.Client
23+
variableName string
24+
}
25+
26+
func New(
27+
c ctrlclient.Client,
28+
) *HelmRegistryValidator {
29+
return &HelmRegistryValidator{
30+
client: c,
31+
variableName: clusterconfig.MetaVariableName,
32+
}
33+
}
34+
35+
func (h *HelmRegistryValidator) Name() string {
36+
return "HelmRegistryValidator"
37+
}
38+
39+
func (h *HelmRegistryValidator) ValidateTopology(
40+
ctx context.Context,
41+
req *runtimehooksv1.ValidateTopologyRequest,
42+
res *runtimehooksv1.ValidateTopologyResponse,
43+
) {
44+
log := ctrl.LoggerFrom(ctx)
45+
clusterVar, ind := variables.GetRuntimhookVariableByName(h.variableName, req.Variables)
46+
if ind == -1 {
47+
log.V(5).Info(fmt.Sprintf("did not find variable %s in %v", h.variableName, req.Variables))
48+
return
49+
}
50+
var cluster v1alpha1.ClusterConfig
51+
if err := variables.UnmarshalRuntimeVariable[v1alpha1.ClusterConfig](clusterVar, &cluster); err != nil {
52+
failString := fmt.Sprintf("failed to unmarshal variable %v to clusterConfig", clusterVar)
53+
log.Error(err, failString)
54+
res.SetStatus(runtimehooksv1.ResponseStatusFailure)
55+
res.SetMessage(failString)
56+
return
57+
}
58+
helmChartRepo := cluster.Spec.Addons.HelmChartRepository
59+
cl := &http.Client{
60+
Transport: &http.Transport{
61+
//nolint:gosec // this is done because customers can occasionally have self signed
62+
// or no certificates to OCI registries
63+
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
64+
},
65+
}
66+
resp, err := cl.Get(fmt.Sprintf("%s/v2", *helmChartRepo))
67+
if err != nil {
68+
failString := fmt.Sprintf("failed to ping provided helm registry %s", *helmChartRepo)
69+
log.Error(err, failString)
70+
res.SetStatus(runtimehooksv1.ResponseStatusFailure)
71+
res.SetMessage(failString)
72+
return
73+
}
74+
defer resp.Body.Close()
75+
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusUnauthorized {
76+
res.SetStatus(runtimehooksv1.ResponseStatusSuccess)
77+
return
78+
}
79+
failString := fmt.Sprintf(
80+
"failed to get 401 or 200 response from hitting registry: %s got status: %d",
81+
*helmChartRepo,
82+
resp.StatusCode,
83+
)
84+
log.Error(err, failString)
85+
res.SetStatus(runtimehooksv1.ResponseStatusFailure)
86+
res.SetMessage(failString)
87+
}

0 commit comments

Comments
 (0)