diff --git a/acp/client.go b/acp/client.go index c87047da1..5ff8d06dd 100644 --- a/acp/client.go +++ b/acp/client.go @@ -55,6 +55,29 @@ func newClient(restAPI REST, acpEnabled bool) TridentACP { return &client{restAPI, acpEnabled} } +func (c *client) GetVersion(ctx context.Context) (*version.Version, error) { + Logc(ctx).Debug("Getting Trident-ACP version.") + + if !c.acpEnabled { + Logc(ctx).Warning("ACP not enabled.") + return nil, nil + } + + acpVersion, err := c.restClient.GetVersion(ctx) + if err != nil { + Logc(ctx).Error("Could not get Trident-ACP version.") + return nil, err + } + + if acpVersion == nil { + Logc(ctx).Error("No version in response from Trident-ACP REST API.") + return nil, fmt.Errorf("no version in response from Trident-ACP REST API") + } + + Logc(ctx).WithField("version", acpVersion.String()).Debug("Received Trident-ACP version.") + return acpVersion, nil +} + func (c *client) GetVersionWithBackoff(ctx context.Context) (*version.Version, error) { Logc(ctx).Debug("Checking if Trident-ACP REST API is responsive.") var v *version.Version diff --git a/acp/types.go b/acp/types.go index 75698ddac..37277657e 100644 --- a/acp/types.go +++ b/acp/types.go @@ -13,6 +13,7 @@ import ( // TridentACP is a set of methods for exposing Trident-ACP REST APIs to Trident. type TridentACP interface { + GetVersion(context.Context) (*version.Version, error) GetVersionWithBackoff(context.Context) (*version.Version, error) IsFeatureEnabled(context.Context, string) error } diff --git a/cli/api/types.go b/cli/api/types.go index f3f0c68b3..87e8325d6 100644 --- a/cli/api/types.go +++ b/cli/api/types.go @@ -68,8 +68,9 @@ type Version struct { } type VersionResponse struct { - Server Version `json:"server"` - Client Version `json:"client"` + Server Version `json:"server"` + Client Version `json:"client"` + ACPServer Version `json:"acpServer,omitempty"` } type ClientVersionResponse struct { diff --git a/cli/cmd/version.go b/cli/cmd/version.go index edb144c3b..328bb3458 100644 --- a/cli/cmd/version.go +++ b/cli/cmd/version.go @@ -60,12 +60,24 @@ var versionCmd = &cobra.Command{ return err } + // Add the ACP version + var parsedACPServerVersion *versionutils.Version + if serverVersion.ACPVersion != "" { + parsedACPServerVersion, err = versionutils.ParseDate(serverVersion.ACPVersion) + if err != nil { + return err + } + } + // Add the client version, which is always hardcoded at compile time - versions := addClientVersion(parsedServerVersion) + versions := addClientVersion(parsedServerVersion, parsedACPServerVersion) // Add the server's Go version versions.Server.GoVersion = serverVersion.GoVersion + // TODO: Add the ACP server's Go version + // versions.ACPServer.GoVersion = serverVersion.GoVersion + writeVersions(versions) } @@ -118,8 +130,9 @@ func getVersionFromTunnel() (rest.GetVersionResponse, error) { } version := rest.GetVersionResponse{ - Version: tunnelVersionResponse.Server.Version, - GoVersion: tunnelVersionResponse.Server.GoVersion, + Version: tunnelVersionResponse.Server.Version, + GoVersion: tunnelVersionResponse.Server.GoVersion, + ACPVersion: tunnelVersionResponse.ACPServer.Version, } return version, nil } @@ -140,7 +153,7 @@ func getClientVersion() *api.ClientVersionResponse { } // addClientVersion accepts the server version and fills in the client version -func addClientVersion(serverVersion *versionutils.Version) *api.VersionResponse { +func addClientVersion(serverVersion, acpServerVersion *versionutils.Version) *api.VersionResponse { versions := api.VersionResponse{} versions.Server.Version = serverVersion.String() @@ -151,6 +164,16 @@ func addClientVersion(serverVersion *versionutils.Version) *api.VersionResponse versions.Server.BuildMetadata = serverVersion.BuildMetadata() versions.Server.APIVersion = config.OrchestratorAPIVersion + if acpServerVersion != nil { + versions.ACPServer.Version = acpServerVersion.String() + versions.ACPServer.MajorVersion = acpServerVersion.MajorVersion() + versions.ACPServer.MinorVersion = acpServerVersion.MinorVersion() + versions.ACPServer.PatchVersion = acpServerVersion.PatchVersion() + versions.ACPServer.PreRelease = acpServerVersion.PreRelease() + versions.ACPServer.BuildMetadata = acpServerVersion.BuildMetadata() + versions.ACPServer.APIVersion = config.OrchestratorAPIVersion + } + versions.Client = getClientVersion().Client return &versions @@ -195,13 +218,21 @@ func writeVersionTable(version *api.ClientVersionResponse) { func writeVersionsTable(versions *api.VersionResponse) { table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"Server Version", "Client Version"}) - - table.Append([]string{ - versions.Server.Version, - versions.Client.Version, - }) - + if versions.ACPServer.Version != "" { + table.SetHeader([]string{"Server Version", "Client Version", "ACP Version"}) + table.Append([]string{ + versions.Server.Version, + versions.Client.Version, + versions.ACPServer.Version, + }) + } else { + table.SetHeader([]string{"Server Version", "Client Version"}) + + table.Append([]string{ + versions.Server.Version, + versions.Client.Version, + }) + } table.Render() } diff --git a/frontend/rest/controller_handlers.go b/frontend/rest/controller_handlers.go index 6ccd1e2e1..2ed3ee06e 100644 --- a/frontend/rest/controller_handlers.go +++ b/frontend/rest/controller_handlers.go @@ -13,6 +13,7 @@ import ( "github.com/google/uuid" "github.com/gorilla/mux" + "github.com/netapp/trident/acp" "github.com/netapp/trident/config" "github.com/netapp/trident/frontend" "github.com/netapp/trident/frontend/common" @@ -244,9 +245,10 @@ func (r *AddBackendResponse) logFailure(ctx context.Context) { } type GetVersionResponse struct { - Version string `json:"version"` - GoVersion string `json:"goVersion"` - Error string `json:"error,omitempty"` + Version string `json:"version"` + GoVersion string `json:"goVersion"` + Error string `json:"error,omitempty"` + ACPVersion string `json:"acpVersion,omitempty"` } func GetVersion(w http.ResponseWriter, r *http.Request) { @@ -261,11 +263,28 @@ func GetVersion(w http.ResponseWriter, r *http.Request) { response.Error = err.Error() } response.Version = version + + response.ACPVersion = GetACPVersion(ctx) return httpStatusCodeForGetUpdateList(err) }, ) } +func GetACPVersion(ctx context.Context) string { + version, err := acp.API().GetVersion(ctx) + if err != nil { + Logc(ctx).WithError(err).Error("Could not get trident-acp version.") + return "" + } + + if version == nil { + Logc(ctx).WithError(err).Error("trident-acp version is empty.") + return "" + } + + return version.String() +} + func AddBackend(w http.ResponseWriter, r *http.Request) { response := &AddBackendResponse{} AddGeneric(w, r, response, @@ -351,7 +370,8 @@ func UpdateBackendState(w http.ResponseWriter, r *http.Request) { } ctx := GenerateRequestContext(r.Context(), "", "", WorkflowBackendUpdate, LogLayerRESTFrontend) - backend, err := orchestrator.UpdateBackendState(ctx, vars["backend"], request.BackendState, request.UserBackendState) + backend, err := orchestrator.UpdateBackendState(ctx, vars["backend"], request.BackendState, + request.UserBackendState) if err != nil { updateResponse.Error = err.Error() } @@ -622,7 +642,8 @@ func volumeLUKSPassphraseNamesUpdater(_ http.ResponseWriter, r *http.Request, re err = orchestrator.UpdateVolumeLUKSPassphraseNames(r.Context(), vars["volume"], passphraseNames) if err != nil { - response.setError(fmt.Errorf("failed to update LUKS passphrase names for volume %s: %s", vars["volume"], err.Error())) + response.setError(fmt.Errorf("failed to update LUKS passphrase names for volume %s: %s", vars["volume"], + err.Error())) if errors.IsNotFoundError(err) { return http.StatusNotFound } diff --git a/mocks/mock_acp/mock_acp.go b/mocks/mock_acp/mock_acp.go index dfa2ad93a..8b0a141b2 100644 --- a/mocks/mock_acp/mock_acp.go +++ b/mocks/mock_acp/mock_acp.go @@ -35,6 +35,21 @@ func (m *MockTridentACP) EXPECT() *MockTridentACPMockRecorder { return m.recorder } +// GetVersion mocks base method. +func (m *MockTridentACP) GetVersion(arg0 context.Context) (*version.Version, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetVersion", arg0) + ret0, _ := ret[0].(*version.Version) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetVersion indicates an expected call of GetVersion. +func (mr *MockTridentACPMockRecorder) GetVersion(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVersion", reflect.TypeOf((*MockTridentACP)(nil).GetVersion), arg0) +} + // GetVersionWithBackoff mocks base method. func (m *MockTridentACP) GetVersionWithBackoff(arg0 context.Context) (*version.Version, error) { m.ctrl.T.Helper() diff --git a/mocks/mock_operator/mock_controllers/mock_orchestrator/mock_installer/mock_installer.go b/mocks/mock_operator/mock_controllers/mock_orchestrator/mock_installer/mock_installer.go index c71d1a34e..ac61402b1 100644 --- a/mocks/mock_operator/mock_controllers/mock_orchestrator/mock_installer/mock_installer.go +++ b/mocks/mock_operator/mock_controllers/mock_orchestrator/mock_installer/mock_installer.go @@ -59,14 +59,29 @@ func (mr *MockTridentInstallerMockRecorder) CreateOrPatchCRD(arg0, arg1, arg2 in return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrPatchCRD", reflect.TypeOf((*MockTridentInstaller)(nil).CreateOrPatchCRD), arg0, arg1, arg2) } +// GetACPVersion mocks base method. +func (m *MockTridentInstaller) GetACPVersion() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetACPVersion") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetACPVersion indicates an expected call of GetACPVersion. +func (mr *MockTridentInstallerMockRecorder) GetACPVersion() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetACPVersion", reflect.TypeOf((*MockTridentInstaller)(nil).GetACPVersion)) +} + // InstallOrPatchTrident mocks base method. -func (m *MockTridentInstaller) InstallOrPatchTrident(arg0 v1.TridentOrchestrator, arg1 string, arg2, arg3 bool) (*v1.TridentOrchestratorSpecValues, string, error) { +func (m *MockTridentInstaller) InstallOrPatchTrident(arg0 v1.TridentOrchestrator, arg1 string, arg2, arg3 bool) (*v1.TridentOrchestratorSpecValues, string, string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "InstallOrPatchTrident", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(*v1.TridentOrchestratorSpecValues) ret1, _ := ret[1].(string) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret2, _ := ret[2].(string) + ret3, _ := ret[3].(error) + return ret0, ret1, ret2, ret3 } // InstallOrPatchTrident indicates an expected call of InstallOrPatchTrident. diff --git a/operator/controllers/orchestrator/controller.go b/operator/controllers/orchestrator/controller.go index 5d22ed1c3..12b760da4 100644 --- a/operator/controllers/orchestrator/controller.go +++ b/operator/controllers/orchestrator/controller.go @@ -703,7 +703,7 @@ func (c *Controller) reconcileTridentNotPresent() error { statusMessage := "Installing Trident" newTridentCR, err := c.updateTorcEventAndStatus(tridentCR, debugMessage, statusMessage, - string(AppStatusInstalling), "", tridentCR.Spec.Namespace, corev1.EventTypeNormal, nil) + string(AppStatusInstalling), "", "", tridentCR.Spec.Namespace, corev1.EventTypeNormal, nil) if err != nil { return errors.ReconcileFailedError( "unable to update status of the CR '%v' to installing", tridentCR.Name) @@ -892,7 +892,7 @@ func (c *Controller) controllingCRBasedReconcile( statusMessage := "Uninstalled Trident" + crdNote + UninstallationNote if _, crErr := c.updateTorcEventAndStatus(controllingCR, debugMessage, statusMessage, - string(AppStatusUninstalled), "", controllingCR.Status.Namespace, corev1.EventTypeNormal, + string(AppStatusUninstalled), "", "", controllingCR.Status.Namespace, corev1.EventTypeNormal, nil); crErr != nil { Log().Error(crErr) } @@ -907,7 +907,8 @@ func (c *Controller) controllingCRBasedReconcile( // Get current Version information, to update CRs with the correct version information and in K8s case // identify if update might be required (for installation only) due to change in K8s version. - currentInstalledTridentVersion, tridentK8sConfigVersion, err := c.getCurrentTridentAndK8sVersion(controllingCR) + currentInstalledTridentVersion, tridentK8sConfigVersion, currentInstalledACPVersion, + err := c.getCurrentTridentAndK8sVersion(controllingCR) if err != nil { // Failed to identify current trident version and K8s version Log().WithFields(LogFields{ @@ -924,7 +925,8 @@ func (c *Controller) controllingCRBasedReconcile( statusMessage := fmt.Sprintf("Failed to detect installed Trident resources; err: %s", err.Error()) if _, crErr := c.updateTorcEventAndStatus(controllingCR, debugMessage, statusMessage, string(AppStatusFailed), - controllingCR.Status.Version, controllingCR.Status.Namespace, corev1.EventTypeWarning, + controllingCR.Status.Version, currentInstalledACPVersion, controllingCR.Status.Namespace, + corev1.EventTypeWarning, &controllingCR.Status.CurrentInstallationParams); crErr != nil { Log().Error(crErr) } @@ -958,7 +960,8 @@ func (c *Controller) controllingCRBasedReconcile( controllingCR.Spec.Namespace) if _, crErr := c.updateTorcEventAndStatus(controllingCR, debugMessage, errorMessage, string(AppStatusFailed), - currentInstalledTridentVersion, currentInstallationNamespace, corev1.EventTypeWarning, + currentInstalledTridentVersion, currentInstalledACPVersion, currentInstallationNamespace, + corev1.EventTypeWarning, &controllingCR.Status.CurrentInstallationParams); crErr != nil { Log().Error(crErr) } @@ -990,7 +993,8 @@ func (c *Controller) controllingCRBasedReconcile( controllingCRName := controllingCR.Name controllingCR, err = c.updateTorcEventAndStatus(controllingCR, debugMessage, statusMessage, - string(AppStatusUpdating), currentInstalledTridentVersion, currentInstallationNamespace, + string(AppStatusUpdating), currentInstalledTridentVersion, currentInstalledACPVersion, + currentInstallationNamespace, eventType, &controllingCR.Status.CurrentInstallationParams) if err != nil { return errors.ReconcileFailedError( @@ -1018,7 +1022,7 @@ func (c *Controller) controllingCRBasedReconcile( func (c *Controller) installTridentAndUpdateStatus(tridentCR netappv1.TridentOrchestrator, currentInstalledTridentVersion, warningMessage string, shouldUpdate bool, ) error { - var identifiedTridentVersion string + var identifiedTridentVersion, identifiedACPVersion string var identifiedSpecValues *netappv1.TridentOrchestratorSpecValues // Install or Patch or Update Trident @@ -1027,7 +1031,7 @@ func (c *Controller) installTridentAndUpdateStatus(tridentCR netappv1.TridentOrc return errors.WrapWithReconcileFailedError(err, "reconcile failed") } - if identifiedSpecValues, identifiedTridentVersion, err = i.InstallOrPatchTrident(tridentCR, + if identifiedSpecValues, identifiedTridentVersion, identifiedACPVersion, err = i.InstallOrPatchTrident(tridentCR, currentInstalledTridentVersion, shouldUpdate, c.crdUpdateNeeded); err != nil { // Update status of the tridentCR to `Failed` debugMessage := "Updating Trident Orchestrator CR after failed installation." @@ -1038,7 +1042,7 @@ func (c *Controller) installTridentAndUpdateStatus(tridentCR netappv1.TridentOrc } if _, crErr := c.updateTorcEventAndStatus(&tridentCR, debugMessage, statusMessage, - string(AppStatusFailed), "", tridentCR.Spec.Namespace, corev1.EventTypeWarning, + string(AppStatusFailed), "", "", tridentCR.Spec.Namespace, corev1.EventTypeWarning, identifiedSpecValues); crErr != nil { Log().Error(crErr) } @@ -1059,24 +1063,25 @@ func (c *Controller) installTridentAndUpdateStatus(tridentCR netappv1.TridentOrc eventType = corev1.EventTypeWarning } + // TODO: may need to check if ACP version needs to be bumped _, err = c.updateTorcEventAndStatus(&tridentCR, debugMessage, statusMessage, string(AppStatusInstalled), - identifiedTridentVersion, tridentCR.Spec.Namespace, eventType, identifiedSpecValues) + identifiedTridentVersion, identifiedACPVersion, tridentCR.Spec.Namespace, eventType, + identifiedSpecValues) return err } // uninstallTridentAndUpdateStatus uninstalls Trident and updates status of the ControllingCR accordingly // based on success or failure -func (c *Controller) uninstallTridentAndUpdateStatus(tridentCR netappv1.TridentOrchestrator, - currentInstalledTridentVersion string) (*netappv1. - TridentOrchestrator, error, -) { +func (c *Controller) uninstallTridentAndUpdateStatus( + tridentCR netappv1.TridentOrchestrator, currentInstalledTridentVersion string, +) (*netappv1.TridentOrchestrator, error) { // Update status of the tridentCR to `Uninstalling` debugMessage := "Updating TridentOrchestrator CR before uninstallation" statusMessage := "Uninstalling Trident" newTridentCR, err := c.updateTorcEventAndStatus(&tridentCR, debugMessage, statusMessage, string(AppStatusUninstalling), - currentInstalledTridentVersion, tridentCR.Status.Namespace, corev1.EventTypeNormal, + currentInstalledTridentVersion, tridentCR.Status.ACPVersion, tridentCR.Status.Namespace, corev1.EventTypeNormal, &tridentCR.Status.CurrentInstallationParams) if err != nil { return nil, errors.ReconcileFailedError( @@ -1090,7 +1095,8 @@ func (c *Controller) uninstallTridentAndUpdateStatus(tridentCR netappv1.TridentO statusMessage := fmt.Sprintf("Failed to uninstall Trident; err: %s", err.Error()) if _, crErr := c.updateTorcEventAndStatus(newTridentCR, debugMessage, statusMessage, string(AppStatusFailed), - currentInstalledTridentVersion, tridentCR.Status.Namespace, corev1.EventTypeWarning, + currentInstalledTridentVersion, tridentCR.Status.ACPVersion, tridentCR.Status.Namespace, + corev1.EventTypeWarning, &tridentCR.Status.CurrentInstallationParams); crErr != nil { Log().Error(crErr) } @@ -1113,7 +1119,7 @@ func (c *Controller) uninstallTridentAndUpdateStatus(tridentCR netappv1.TridentO statusMessage = "Uninstalled Trident" + crdNote + UninstallationNote return c.updateTorcEventAndStatus(newTridentCR, debugMessage, statusMessage, - string(AppStatusUninstalled), "", newTridentCR.Status.Namespace, corev1.EventTypeNormal, nil) + string(AppStatusUninstalled), "", "", newTridentCR.Status.Namespace, corev1.EventTypeNormal, nil) } // uninstallTridentAll uninstalls Trident CSI, Trident CSI Preview, Trident Legacy @@ -1293,7 +1299,8 @@ func (c *Controller) updateAllCRs(message string) error { var debugMessage string for _, cr := range allCRs { debugMessage = "Updating " + cr.Name + " TridentOrchestrator CR." - _, err = c.updateTorcEventAndStatus(cr, debugMessage, message, string(AppStatusError), "", cr.Spec.Namespace, + _, err = c.updateTorcEventAndStatus(cr, debugMessage, message, string(AppStatusError), "", "", + cr.Spec.Namespace, corev1.EventTypeWarning, nil) } @@ -1316,7 +1323,7 @@ func (c *Controller) updateOtherCRs(controllingCRName string) error { statusMessage := fmt.Sprintf("Trident is bound to another CR '%v'", controllingCRName) - _, err = c.updateTorcEventAndStatus(cr, debugMessage, statusMessage, string(AppStatusError), "", + _, err = c.updateTorcEventAndStatus(cr, debugMessage, statusMessage, string(AppStatusError), "", "", cr.Spec.Namespace, corev1.EventTypeWarning, nil) } } @@ -1326,13 +1333,14 @@ func (c *Controller) updateOtherCRs(controllingCRName string) error { // updateLogAndStatus updates the event logs and status of a TridentOrchestrator CR (if required) func (c *Controller) updateTorcEventAndStatus( - tridentCR *netappv1.TridentOrchestrator, debugMessage, message, status, version, namespace, eventType string, + tridentCR *netappv1.TridentOrchestrator, debugMessage, message, status, version, acpVersion, namespace, + eventType string, specValues *netappv1.TridentOrchestratorSpecValues, ) (torcCR *netappv1.TridentOrchestrator, err error) { var logEvent bool if torcCR, logEvent, err = c.updateTridentOrchestratorCRStatus(tridentCR, debugMessage, message, status, - version, namespace, specValues); err != nil { + version, acpVersion, namespace, specValues); err != nil { return } @@ -1346,7 +1354,7 @@ func (c *Controller) updateTorcEventAndStatus( // updateTridentOrchestratorCRStatus updates the status of a CR if required func (c *Controller) updateTridentOrchestratorCRStatus( - tridentCR *netappv1.TridentOrchestrator, debugMessage, message, status, version, namespace string, + tridentCR *netappv1.TridentOrchestrator, debugMessage, message, status, version, acpVersion, namespace string, specValues *netappv1.TridentOrchestratorSpecValues, ) (*netappv1.TridentOrchestrator, bool, error) { logFields := LogFields{"tridentOrchestratorCR": tridentCR.Name} @@ -1365,8 +1373,7 @@ func (c *Controller) updateTridentOrchestratorCRStatus( Version: version, Namespace: namespace, CurrentInstallationParams: installParams, - // TODO (victorir): This is a placeholder version for ACP. - ACPVersion: version, + ACPVersion: acpVersion, } if reflect.DeepEqual(tridentCR.Status, newStatusDetails) { @@ -1498,7 +1505,7 @@ func (c *Controller) removeNonTorcBasedCSIInstallation(tridentCR *netappv1.Tride Log().Error(failureMessage) if _, crErr := c.updateTorcEventAndStatus(tridentCR, debugMessage, failureMessage, - string(AppStatusFailed), "", tridentCR.Spec.Namespace, corev1.EventTypeWarning, nil); crErr != nil { + string(AppStatusFailed), "", "", tridentCR.Spec.Namespace, corev1.EventTypeWarning, nil); crErr != nil { Log().Error(crErr) } @@ -1522,18 +1529,19 @@ func (c *Controller) removeNonTorcBasedCSIInstallation(tridentCR *netappv1.Tride // getCurrentTridentAndK8sVersion reports current Trident version installed and K8s version according // to which Trident was installed -func (c *Controller) getCurrentTridentAndK8sVersion(tridentCR *netappv1.TridentOrchestrator) (string, string, error) { +func (c *Controller) getCurrentTridentAndK8sVersion(tridentCR *netappv1.TridentOrchestrator) (string, string, string, error) { var currentTridentVersionString string + var currentACPVersionString string var currentK8sVersionString string i, err := installer.NewInstaller(c.KubeConfig, tridentCR.Status.Namespace, tridentCR.Spec.K8sTimeout) if err != nil { - return "", "", err + return "", "", "", err } currentDeployment, _, _, err := i.TridentDeploymentInformation(installer.TridentCSILabel) if err != nil { - return "", "", err + return "", "", "", err } if currentDeployment != nil { @@ -1543,7 +1551,7 @@ func (c *Controller) getCurrentTridentAndK8sVersion(tridentCR *netappv1.TridentO // For a case where deployment may have been deleted check for daemonset version also currentDaemonSet, _, _, err := i.TridentDaemonSetInformation() if err != nil { - return "", "", err + return "", "", "", err } if currentDaemonSet != nil { @@ -1551,8 +1559,9 @@ func (c *Controller) getCurrentTridentAndK8sVersion(tridentCR *netappv1.TridentO currentK8sVersionString = currentDaemonSet.Labels[installer.K8sVersionLabelKey] } } + currentACPVersionString = i.GetACPVersion() - return currentTridentVersionString, currentK8sVersionString, nil + return currentTridentVersionString, currentK8sVersionString, currentACPVersionString, nil } // validateCurrentK8sVersion identifies any changes in the K8s version, if it is valid, and if not valid should diff --git a/operator/controllers/orchestrator/installer/installer.go b/operator/controllers/orchestrator/installer/installer.go index 8e5dcff32..2aaed584b 100644 --- a/operator/controllers/orchestrator/installer/installer.go +++ b/operator/controllers/orchestrator/installer/installer.go @@ -464,14 +464,14 @@ func (i *Installer) setInstallationParams( func (i *Installer) InstallOrPatchTrident( cr netappv1.TridentOrchestrator, currentInstallationVersion string, k8sUpdateNeeded, crdUpdateNeeded bool, -) (*netappv1.TridentOrchestratorSpecValues, string, error) { +) (*netappv1.TridentOrchestratorSpecValues, string, string, error) { var returnError error reuseServiceAccountMap := make(map[string]bool) // Set installation params controllingCRDetails, labels, tridentUpdateNeeded, err := i.setInstallationParams(cr, currentInstallationVersion) if err != nil { - return nil, "", err + return nil, "", "", err } // Remove any leftover transient Trident @@ -491,25 +491,25 @@ func (i *Installer) InstallOrPatchTrident( // Create namespace, if one does not exist if returnError = i.createOrPatchTridentInstallationNamespace(); returnError != nil { - return nil, "", returnError + return nil, "", "", returnError } // Create or patch or update the RBAC objects if reuseServiceAccountMap, returnError = i.createRBACObjects(controllingCRDetails, labels, shouldUpdate); returnError != nil { - return nil, "", returnError + return nil, "", "", returnError } // Create CRDs and ensure they are established returnError = i.createAndEnsureCRDs(crdUpdateNeeded) if returnError != nil { returnError = fmt.Errorf("failed to create the Trident CRDs; %v", returnError) - return nil, "", returnError + return nil, "", "", returnError } // Patch the CRD definitions with finalizers to protect them if returnError = i.client.AddFinalizerToCRDs(CRDnames); returnError != nil { - return nil, "", fmt.Errorf("failed to add finalizers for Trident CRDs %v; err: %v", CRDnames, returnError) + return nil, "", "", fmt.Errorf("failed to add finalizers for Trident CRDs %v; err: %v", CRDnames, returnError) } // Create or patch or update the RBAC PSPs @@ -517,7 +517,7 @@ func (i *Installer) InstallOrPatchTrident( returnError = i.createOrPatchTridentPodSecurityPolicy(controllingCRDetails, labels, shouldUpdate) if returnError != nil { returnError = fmt.Errorf("failed to create the Trident pod security policy; %v", returnError) - return nil, "", returnError + return nil, "", "", returnError } } @@ -525,42 +525,42 @@ func (i *Installer) InstallOrPatchTrident( returnError = i.createOrPatchK8sCSIDriver(controllingCRDetails, labels, shouldUpdate) if returnError != nil { returnError = fmt.Errorf("failed to create the Kubernetes CSI Driver object; %v", returnError) - return nil, "", returnError + return nil, "", "", returnError } // Create or patch or update the Trident Service returnError = i.createOrPatchTridentService(controllingCRDetails, labels, shouldUpdate) if returnError != nil { returnError = fmt.Errorf("failed to create the Trident Service; %v", returnError) - return nil, "", returnError + return nil, "", "", returnError } // Create or update the Trident Secret returnError = i.createOrPatchTridentProtocolSecret(controllingCRDetails, labels, shouldUpdate) if returnError != nil { returnError = fmt.Errorf("failed to create the Trident Protocol Secret; %v", returnError) - return nil, "", returnError + return nil, "", "", returnError } // Create or update the Trident Encryption Secret returnError = i.createOrConsumeTridentEncryptionSecret(controllingCRDetails, labels, shouldUpdate) if returnError != nil { returnError = fmt.Errorf("failed to create the Trident Encryption Secret; %v", returnError) - return nil, "", returnError + return nil, "", "", returnError } // Create or update the Trident Resource Quota returnError = i.createOrPatchTridentResourceQuota(controllingCRDetails, labels, shouldUpdate) if returnError != nil { returnError = fmt.Errorf("failed to create the Trident Resource Quota; %v", returnError) - return nil, "", returnError + return nil, "", "", returnError } // Create or update the Trident CSI deployment returnError = i.createOrPatchTridentDeployment(controllingCRDetails, labels, shouldUpdate, reuseServiceAccountMap) if returnError != nil { returnError = fmt.Errorf("failed to create the Trident Deployment; %v", returnError) - return nil, "", returnError + return nil, "", "", returnError } returnError = i.createOrPatchTridentDaemonSet(controllingCRDetails, labels, shouldUpdate, reuseServiceAccountMap, @@ -568,7 +568,7 @@ func (i *Installer) InstallOrPatchTrident( if returnError != nil { returnError = fmt.Errorf("failed to create or patch Trident daemonset %s; %v", getDaemonSetName(false), returnError) - return nil, "", returnError + return nil, "", "", returnError } // Create or update the Trident CSI daemonset @@ -579,7 +579,7 @@ func (i *Installer) InstallOrPatchTrident( if returnError != nil { returnError = fmt.Errorf("failed to create or patch Trident daemonset %s; %v", getDaemonSetName(true), returnError) - return nil, "", returnError + return nil, "", "", returnError } } @@ -588,16 +588,18 @@ func (i *Installer) InstallOrPatchTrident( tridentPod, returnError = i.waitForTridentPod() if returnError != nil { - return nil, "", returnError + return nil, "", "", returnError } // Wait for Trident REST interface to be available returnError = i.waitForRESTInterface(tridentPod.Name) if returnError != nil { returnError = fmt.Errorf("%v; use 'tridentctl logs' to learn more", returnError) - return nil, "", returnError + return nil, "", "", returnError } + acpVersion := i.GetACPVersion() + identifiedSpecValues := netappv1.TridentOrchestratorSpecValues{ EnableForceDetach: strconv.FormatBool(enableForceDetach), DisableAuditLog: strconv.FormatBool(disableAuditLog), @@ -628,10 +630,11 @@ func (i *Installer) InstallOrPatchTrident( } Log().WithFields(LogFields{ - "namespace": i.namespace, - "version": labels[TridentVersionLabelKey], + "namespace": i.namespace, + "version": labels[TridentVersionLabelKey], + "ACP version": acpVersion, }).Info("Trident is installed.") - return &identifiedSpecValues, labels[TridentVersionLabelKey], nil + return &identifiedSpecValues, labels[TridentVersionLabelKey], acpVersion, nil } // createCRDs creates and establishes each of the CRDs individually @@ -691,6 +694,8 @@ func (i *Installer) createCRDs(performOperationOnce bool) error { // TODO: Once Trident v22.01 approaches EOL or CRD versioning schema is established, // // re-evaluate if performOperationOnce is necessary. +// +// TODO (victorir): use this to patch version CRD after bootstrap func (i *Installer) CreateOrPatchCRD(crdName, crdYAML string, performOperationOnce bool) error { var currentCRD *apiextensionv1.CustomResourceDefinition var err error @@ -1688,7 +1693,8 @@ func (i *Installer) waitForRESTInterface(tridentPodName string) error { } if err != nil { - Log().Errorf("Trident REST interface was not available after %3.2f seconds; err: %v", totalWaitTime.Seconds(), + Log().Errorf("Trident REST interface was not available after %3.2f seconds; err: %v", + totalWaitTime.Seconds(), err) return err } @@ -1707,6 +1713,50 @@ func (i *Installer) waitForRESTInterface(tridentPodName string) error { return nil } +func (i *Installer) GetACPVersion() string { + var acpVersion, controllerServer string + if useIPv6 { + controllerServer = "[::1]:8000" + } else { + controllerServer = "127.0.0.1:8000" + } + + tridentPod, returnError := i.waitForTridentPod() + if returnError != nil { + return "" + } + + cliCommand := []string{"tridentctl", "-s", controllerServer, "version", "-o", "json"} + versionJSON, err := i.client.Exec(tridentPod.Name, TridentContainer, cliCommand) + if err != nil { + if len(versionJSON) > 0 { + err = fmt.Errorf("%v; %s", err, strings.TrimSpace(string(versionJSON))) + Log().WithError(err) + } + return acpVersion + } + + var versionResponse api.VersionResponse + err = json.Unmarshal(versionJSON, &versionResponse) + if err != nil { + return acpVersion + } + + acpVersionWithMetadata := versionResponse.ACPServer.Version + if acpVersionWithMetadata != "" { + versionInfo, err := versionutils.ParseDate(acpVersionWithMetadata) + if err != nil { + Log().WithField("acpVersion", acpVersionWithMetadata).Errorf("unable to parse ACP version") + acpVersion = acpVersionWithMetadata + } else { + acpVersion = versionInfo.ShortStringWithRelease() + } + Log().WithField("acpVersion", acpVersion).Info("trident-acp is up.") + } + + return acpVersion +} + // getTridentClientVersionInfo takes trident image name and identifies the Trident client version func (i *Installer) getTridentClientVersionInfo( imageName string, controllingCRDetails map[string]string, diff --git a/operator/controllers/orchestrator/installer/types.go b/operator/controllers/orchestrator/installer/types.go index 3cd8fae72..db6858b5e 100644 --- a/operator/controllers/orchestrator/installer/types.go +++ b/operator/controllers/orchestrator/installer/types.go @@ -23,11 +23,12 @@ type TridentInstaller interface { CreateOrPatchCRD(crdName, crdYAML string, performOperationOnce bool) error InstallOrPatchTrident( cr v15.TridentOrchestrator, currentInstallationVersion string, shouldUpdate, crdUpdateNeeded bool, - ) (*v15.TridentOrchestratorSpecValues, string, error) + ) (*v15.TridentOrchestratorSpecValues, string, string, error) ObliviateCRDs() error TridentDeploymentInformation(deploymentLabel string) (*appsv1.Deployment, []appsv1.Deployment, bool, error) TridentDaemonSetInformation() (*appsv1.DaemonSet, []appsv1.DaemonSet, bool, error) UninstallTrident() error + GetACPVersion() string } // ExtendedK8sClient extends the vanilla k8s client Interface and is responsible for enabling the TridentInstaller.