diff --git a/app/deployer/connector/astra_connect_test.go b/app/deployer/connector/astra_connect_test.go index 2e9296c9..0198e90d 100644 --- a/app/deployer/connector/astra_connect_test.go +++ b/app/deployer/connector/astra_connect_test.go @@ -24,6 +24,9 @@ func TestAstraConnectGetDeploymentObjects(t *testing.T) { Namespace: "test-namespace", }, Spec: v1.AstraConnectorSpec{ + AutoSupport: v1.AutoSupport{Enrolled: true, + URL: "https://my-asup"}, + ImageRegistry: v1.ImageRegistry{ Name: "test-registry", Secret: "test-secret", @@ -119,6 +122,9 @@ func DummyAstraConnector() v1.AstraConnector { Image: "test-image", Replicas: 1, }, + AutoSupport: v1.AutoSupport{ + Enrolled: true, + URL: "https://my-asup"}, }, } } diff --git a/app/deployer/neptune/neptuneV2.go b/app/deployer/neptune/neptuneV2.go index 37c08ea6..d847e7bc 100644 --- a/app/deployer/neptune/neptuneV2.go +++ b/app/deployer/neptune/neptuneV2.go @@ -7,6 +7,7 @@ package neptune import ( "context" "fmt" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "os" "path/filepath" "strings" @@ -315,3 +316,22 @@ func (n NeptuneClientDeployerV2) GetRoleBindingObjects(m *v1.AstraConnector, ctx func (n NeptuneClientDeployerV2) GetClusterRoleBindingObjects(m *v1.AstraConnector, ctx context.Context) ([]client.Object, error) { return nil, nil } + +func GetASUPControllerObject(asupEnabled bool) client.Object { + + cr := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "management.astra.netapp.io/v1alpha1", + "kind": "AutoSupportBundleSchedule", + "metadata": map[string]interface{}{ + "name": "autosupportbundleschedule-123", + }, + "spec": map[string]interface{}{ + "enabled": asupEnabled, + }, + }, + } + + return cr + +} diff --git a/app/deployer/neptune/neptune_test.go b/app/deployer/neptune/neptune_test.go index 3920c386..a8f159e7 100644 --- a/app/deployer/neptune/neptune_test.go +++ b/app/deployer/neptune/neptune_test.go @@ -27,6 +27,9 @@ func createNeptuneDeployer() (neptune.NeptuneClientDeployer, *v1.AstraConnector, Namespace: "test-namespace", }, Spec: v1.AstraConnectorSpec{ + AutoSupport: v1.AutoSupport{ + Enrolled: true, + URL: "https://my-asup"}, ImageRegistry: v1.ImageRegistry{ Secret: "test-secret", }, @@ -50,6 +53,9 @@ func createNeptuneDeployerV2() (neptune.NeptuneClientDeployerV2, *v1.AstraConnec Namespace: "test-namespace", }, Spec: v1.AstraConnectorSpec{ + AutoSupport: v1.AutoSupport{ + Enrolled: true, + URL: "https://my-asup"}, ImageRegistry: v1.ImageRegistry{ Secret: "test-secret", }, diff --git a/app/register/register_test.go b/app/register/register_test.go index e62ec125..42febdae 100644 --- a/app/register/register_test.go +++ b/app/register/register_test.go @@ -86,6 +86,9 @@ func createClusterRegister(astraConnectorInput AstraConnectorInput) (register.Cl Astra: v1.Astra{ TokenRef: apiTokenSecret, }, + AutoSupport: v1.AutoSupport{ + Enrolled: true, + URL: "https://my-asup"}, ImageRegistry: v1.ImageRegistry{ Name: "test-registry", Secret: "test-secret", diff --git a/details/operator-sdk/api/v1/astraconnector_types.go b/details/operator-sdk/api/v1/astraconnector_types.go index 45d6a371..3ff4dfaa 100644 --- a/details/operator-sdk/api/v1/astraconnector_types.go +++ b/details/operator-sdk/api/v1/astraconnector_types.go @@ -22,6 +22,17 @@ type Astra struct { Unregister bool `json:"unregister,omitempty"` } +// AutoSupport defines how the customer interacts with NetApp ActiveIQ. +type AutoSupport struct { + // Enrolled determines if you want to send anonymous data to NetApp for support purposes. + // +kubebuilder:default:=true + Enrolled bool `json:"enrolled"` + + // URL determines where the anonymous data will be sent + // +kubebuilder:default:="https://216.240.31.151/put/AsupPut-setenv" + URL string `json:"url,omitempty"` +} + type NatsSyncClient struct { CloudBridgeURL string `json:"cloudBridgeURL,omitempty"` // +kubebuilder:validation:Optional @@ -60,6 +71,14 @@ type AstraConnectorSpec struct { AstraConnect AstraConnect `json:"astraConnect,omitempty"` Neptune Neptune `json:"neptune"` ImageRegistry ImageRegistry `json:"imageRegistry,omitempty"` + + // AutoSupport indicates willingness to participate in NetApp's proactive support application, NetApp Active IQ. + // An internet connection is required (port 442) and all support data is anonymized. + // The default election is true and indicates support data will be sent to NetApp. + // An empty or blank election is the same as a default election. + // Air gapped installations should enter false. + // +kubebuilder:validation:Required + AutoSupport AutoSupport `json:"autoSupport"` } // AstraConnectorStatus defines the observed state of AstraConnector diff --git a/details/operator-sdk/controllers/astraconnector_controller_test.go b/details/operator-sdk/controllers/astraconnector_controller_test.go index 9ed42e76..e22429cd 100644 --- a/details/operator-sdk/controllers/astraconnector_controller_test.go +++ b/details/operator-sdk/controllers/astraconnector_controller_test.go @@ -90,6 +90,9 @@ var _ = Describe("Astraconnector controller", func() { Namespace: namespace.Name, }, Spec: v1.AstraConnectorSpec{ + AutoSupport: v1.AutoSupport{ + Enrolled: false, + }, ImageRegistry: v1.ImageRegistry{ Name: "test-registry", Secret: "test-secret", diff --git a/details/operator-sdk/controllers/connector.go b/details/operator-sdk/controllers/connector.go index 43605c9d..eeb1216d 100644 --- a/details/operator-sdk/controllers/connector.go +++ b/details/operator-sdk/controllers/connector.go @@ -2,7 +2,10 @@ package controllers import ( "context" + "github.com/NetApp-Polaris/astra-connector-operator/details/k8s" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "net/http" + "sigs.k8s.io/controller-runtime/pkg/client" "time" corev1 "k8s.io/api/core/v1" @@ -34,6 +37,16 @@ func (r *AstraConnectorController) deployConnector(ctx context.Context, } } + if natsSyncClientStatus.AstraConnectorID == "" { + err := createASUPCR(ctx, astraConnector, r.Client, "123") + if err != nil { + log.Error(err, FailedASUPCreation) + natsSyncClientStatus.Status = FailedASUPCreation + _ = r.updateAstraConnectorStatus(ctx, astraConnector, *natsSyncClientStatus) + return ctrl.Result{RequeueAfter: time.Minute * conf.Config.ErrorTimeout()}, err + } + } + // Let's register the cluster now registerUtil := register.NewClusterRegisterUtil(astraConnector, &http.Client{}, r.Client, log, context.Background()) registered := false @@ -122,6 +135,16 @@ func (r *AstraConnectorController) deployConnector(ctx context.Context, natsSyncClientStatus.Status = UnregisterNSClient } + if natsSyncClientStatus.Registered == "true" && natsSyncClientStatus.AstraConnectorID != "" { + err = createASUPCR(ctx, astraConnector, r.Client, natsSyncClientStatus.AstraConnectorID) + if err != nil { + log.Error(err, FailedASUPCreation) + natsSyncClientStatus.Status = FailedASUPCreation + _ = r.updateAstraConnectorStatus(ctx, astraConnector, *natsSyncClientStatus) + return ctrl.Result{RequeueAfter: time.Minute * conf.Config.ErrorTimeout()}, err + } + } + // No need to requeue due to success return ctrl.Result{}, nil } @@ -136,3 +159,25 @@ func (r *AstraConnectorController) deleteConnectorClusterScopedResources(ctx con r.deleteClusterScopedResources(ctx, deployer, astraConnector) } } + +func createASUPCR(ctx context.Context, astraConnector *v1.AstraConnector, client client.Client, astraConnectorID string) error { + log := ctrllog.FromContext(ctx) + k8sUtil := k8s.NewK8sUtil(client, log) + + cr := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "management.astra.netapp.io/v1alpha1", + "kind": "AutoSupportBundleSchedule", + "metadata": map[string]interface{}{ + "name": "asupbundleschedule-" + astraConnectorID, + "namespace": astraConnector.Namespace, + }, + "spec": map[string]interface{}{ + "enabled": astraConnector.Spec.AutoSupport.Enrolled, + }, + }, + } + + return k8sUtil.CreateOrUpdateResource(ctx, cr, astraConnector) + +} diff --git a/details/operator-sdk/controllers/neptune.go b/details/operator-sdk/controllers/neptune.go index d4cb1da8..5b3f346e 100644 --- a/details/operator-sdk/controllers/neptune.go +++ b/details/operator-sdk/controllers/neptune.go @@ -26,6 +26,8 @@ func (r *AstraConnectorController) deployNeptune(ctx context.Context, return ctrl.Result{RequeueAfter: time.Minute * conf.Config.ErrorTimeout()}, err } + // let's deploy the ASUP controller if user wants automatic asups + // No need to requeue due to success return ctrl.Result{}, nil } diff --git a/details/operator-sdk/controllers/status_strings.go b/details/operator-sdk/controllers/status_strings.go index ae5f9c60..ced48ca7 100644 --- a/details/operator-sdk/controllers/status_strings.go +++ b/details/operator-sdk/controllers/status_strings.go @@ -33,6 +33,7 @@ const ( FailedRegisterNSClient = "Failed to register natsSyncClient" UnregisterNSClient = "Unregistered natsSyncClient" FailedUnRegisterNSClient = "Failed to unregister natsSyncClient" + FailedASUPCreation = "Failed to create ASUP CR" DeployedComponents = "Deployed all the connector components" UnregisterFromAstra = "Unregistered the cluster with Astra" diff --git a/util/go_util_test.go b/util/go_util_test.go index bfd1c386..440b6092 100644 --- a/util/go_util_test.go +++ b/util/go_util_test.go @@ -22,6 +22,8 @@ func createAstraConnector() *v1.AstraConnector { AccountId: "test-account-id", ClusterName: "test-cluster-name", }, + AutoSupport: v1.AutoSupport{Enrolled: true, + URL: "https://my-asup"}, NatsSyncClient: v1.NatsSyncClient{ CloudBridgeURL: "test-url", },