diff --git a/components/codeflare/codeflare.go b/components/codeflare/codeflare.go index e2c93fb711b..6d2df29413a 100644 --- a/components/codeflare/codeflare.go +++ b/components/codeflare/codeflare.go @@ -57,7 +57,13 @@ func (c *CodeFlare) GetComponentName() string { return ComponentName } -func (c *CodeFlare) ReconcileComponent(ctx context.Context, cli client.Client, logger logr.Logger, owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, _ bool) error { +func (c *CodeFlare) ReconcileComponent(ctx context.Context, + cli client.Client, + logger logr.Logger, + owner metav1.Object, + dscispec *dsciv1.DSCInitializationSpec, + platform cluster.Platform, + _ bool) error { l := c.ConfigComponentLogger(logger, ComponentName, dscispec) var imageParamMap = map[string]string{ "codeflare-operator-controller-image": "RELATED_IMAGE_ODH_CODEFLARE_OPERATOR_IMAGE", // no need mcad, embedded in cfo @@ -66,14 +72,11 @@ func (c *CodeFlare) ReconcileComponent(ctx context.Context, cli client.Client, l enabled := c.GetManagementState() == operatorv1.Managed monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } + if enabled { if c.DevFlags != nil { // Download manifests and update paths - if err = c.OverrideManifests(string(platform)); err != nil { + if err := c.OverrideManifests(string(platform)); err != nil { return err } } @@ -115,10 +118,10 @@ func (c *CodeFlare) ReconcileComponent(ctx context.Context, cli client.Client, l } // inject prometheus codeflare*.rules in to /opt/manifests/monitoring/prometheus/prometheus-configs.yaml - if err = c.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, ComponentName); err != nil { + if err := c.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, ComponentName); err != nil { return err } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), dscispec.Monitoring.Namespace, "prometheus", true); err != nil { diff --git a/components/component.go b/components/component.go index 9384fd1bf0f..0657b6344e6 100644 --- a/components/component.go +++ b/components/component.go @@ -15,6 +15,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" + "github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster" "github.com/opendatahub-io/opendatahub-operator/v2/pkg/common" ) @@ -83,7 +84,7 @@ type ManifestsConfig struct { type ComponentInterface interface { ReconcileComponent(ctx context.Context, cli client.Client, logger logr.Logger, - owner metav1.Object, DSCISpec *dsciv1.DSCInitializationSpec, currentComponentStatus bool) error + owner metav1.Object, DSCISpec *dsciv1.DSCInitializationSpec, platform cluster.Platform, currentComponentStatus bool) error Cleanup(cli client.Client, DSCISpec *dsciv1.DSCInitializationSpec) error GetComponentName() string GetManagementState() operatorv1.ManagementState diff --git a/components/dashboard/dashboard.go b/components/dashboard/dashboard.go index ad16b19ecf7..634ef9f173d 100644 --- a/components/dashboard/dashboard.go +++ b/components/dashboard/dashboard.go @@ -87,13 +87,11 @@ func (d *Dashboard) ReconcileComponent(ctx context.Context, logger logr.Logger, owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, + platform cluster.Platform, currentComponentExist bool, ) error { var l logr.Logger - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } + if platform == cluster.SelfManagedRhods || platform == cluster.ManagedRhods { l = d.ConfigComponentLogger(logger, ComponentNameSupported, dscispec) } else { @@ -183,7 +181,7 @@ func (d *Dashboard) ReconcileComponent(ctx context.Context, if err := d.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, ComponentNameSupported); err != nil { return err } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), dscispec.Monitoring.Namespace, "prometheus", true); err != nil { @@ -194,11 +192,11 @@ func (d *Dashboard) ReconcileComponent(ctx context.Context, return nil default: // base - if err = deploy.DeployManifestsFromPath(cli, owner, Path, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { + if err := deploy.DeployManifestsFromPath(cli, owner, Path, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { return err } // ISV - if err = deploy.DeployManifestsFromPath(cli, owner, PathISV, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { + if err := deploy.DeployManifestsFromPath(cli, owner, PathISV, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { return err } // consolelink diff --git a/components/datasciencepipelines/datasciencepipelines.go b/components/datasciencepipelines/datasciencepipelines.go index 9eada443c65..0344ba039af 100644 --- a/components/datasciencepipelines/datasciencepipelines.go +++ b/components/datasciencepipelines/datasciencepipelines.go @@ -65,6 +65,7 @@ func (d *DataSciencePipelines) ReconcileComponent(ctx context.Context, logger logr.Logger, owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, + platform cluster.Platform, _ bool, ) error { l := d.ConfigComponentLogger(logger, ComponentName, dscispec) @@ -90,14 +91,10 @@ func (d *DataSciencePipelines) ReconcileComponent(ctx context.Context, enabled := d.GetManagementState() == operatorv1.Managed monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } if enabled { if d.DevFlags != nil { // Download manifests and update paths - if err = d.OverrideManifests(string(platform)); err != nil { + if err := d.OverrideManifests(string(platform)); err != nil { return err } } @@ -119,7 +116,7 @@ func (d *DataSciencePipelines) ReconcileComponent(ctx context.Context, if platform == cluster.OpenDataHub || platform == "" { manifestsPath = filepath.Join(OverlayPath, "odh") } - if err = deploy.DeployManifestsFromPath(cli, owner, manifestsPath, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { + if err := deploy.DeployManifestsFromPath(cli, owner, manifestsPath, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { return err } l.Info("apply manifests done") @@ -138,7 +135,7 @@ func (d *DataSciencePipelines) ReconcileComponent(ctx context.Context, if err := d.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, ComponentName); err != nil { return err } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), dscispec.Monitoring.Namespace, "prometheus", true); err != nil { diff --git a/components/kserve/kserve.go b/components/kserve/kserve.go index 6e99c05a7ec..f0f51c1a7ed 100644 --- a/components/kserve/kserve.go +++ b/components/kserve/kserve.go @@ -94,7 +94,7 @@ func (k *Kserve) GetComponentName() string { } func (k *Kserve) ReconcileComponent(ctx context.Context, cli client.Client, - logger logr.Logger, owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, _ bool) error { + logger logr.Logger, owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, platform cluster.Platform, _ bool) error { l := k.ConfigComponentLogger(logger, ComponentName, dscispec) // paramMap for Kserve to use. var imageParamMap = map[string]string{} @@ -106,10 +106,6 @@ func (k *Kserve) ReconcileComponent(ctx context.Context, cli client.Client, enabled := k.GetManagementState() == operatorv1.Managed monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } if !enabled { if err := k.removeServerlessFeatures(dscispec); err != nil { @@ -122,7 +118,7 @@ func (k *Kserve) ReconcileComponent(ctx context.Context, cli client.Client, } if k.DevFlags != nil { // Download manifests and update paths - if err = k.OverrideManifests(string(platform)); err != nil { + if err := k.OverrideManifests(string(platform)); err != nil { return err } } @@ -135,7 +131,7 @@ func (k *Kserve) ReconcileComponent(ctx context.Context, cli client.Client, } } - if err = k.configureServiceMesh(cli, dscispec); err != nil { + if err := k.configureServiceMesh(cli, dscispec); err != nil { return fmt.Errorf("failed configuring service mesh while reconciling kserve component. cause: %w", err) } diff --git a/components/kueue/kueue.go b/components/kueue/kueue.go index 1c9cf4bfc19..32f358608ec 100644 --- a/components/kueue/kueue.go +++ b/components/kueue/kueue.go @@ -54,7 +54,7 @@ func (k *Kueue) GetComponentName() string { } func (k *Kueue) ReconcileComponent(ctx context.Context, cli client.Client, logger logr.Logger, - owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, _ bool) error { + owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, platform cluster.Platform, _ bool) error { l := k.ConfigComponentLogger(logger, ComponentName, dscispec) var imageParamMap = map[string]string{ "odh-kueue-controller-image": "RELATED_IMAGE_ODH_KUEUE_CONTROLLER_IMAGE", // new kueue image @@ -62,15 +62,10 @@ func (k *Kueue) ReconcileComponent(ctx context.Context, cli client.Client, logge enabled := k.GetManagementState() == operatorv1.Managed monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } - if enabled { if k.DevFlags != nil { // Download manifests and update paths - if err = k.OverrideManifests(string(platform)); err != nil { + if err := k.OverrideManifests(string(platform)); err != nil { return err } } @@ -97,7 +92,7 @@ func (k *Kueue) ReconcileComponent(ctx context.Context, cli client.Client, logge if err := k.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, ComponentName); err != nil { return err } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), dscispec.Monitoring.Namespace, "prometheus", true); err != nil { diff --git a/components/modelmeshserving/modelmeshserving.go b/components/modelmeshserving/modelmeshserving.go index e53007ce579..989c255fa94 100644 --- a/components/modelmeshserving/modelmeshserving.go +++ b/components/modelmeshserving/modelmeshserving.go @@ -76,6 +76,7 @@ func (m *ModelMeshServing) ReconcileComponent(ctx context.Context, logger logr.Logger, owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, + platform cluster.Platform, _ bool, ) error { l := m.ConfigComponentLogger(logger, ComponentName, dscispec) @@ -94,16 +95,12 @@ func (m *ModelMeshServing) ReconcileComponent(ctx context.Context, enabled := m.GetManagementState() == operatorv1.Managed monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } // Update Default rolebinding if enabled { if m.DevFlags != nil { // Download manifests and update paths - if err = m.OverrideManifests(string(platform)); err != nil { + if err := m.OverrideManifests(string(platform)); err != nil { return err } } @@ -123,7 +120,7 @@ func (m *ModelMeshServing) ReconcileComponent(ctx context.Context, } } - if err = deploy.DeployManifestsFromPath(cli, owner, Path, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { + if err := deploy.DeployManifestsFromPath(cli, owner, Path, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { return fmt.Errorf("failed to apply manifests from %s : %w", Path, err) } l.WithValues("Path", Path).Info("apply manifests done for modelmesh") @@ -165,7 +162,7 @@ func (m *ModelMeshServing) ReconcileComponent(ctx context.Context, if err := m.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, DependentComponentName); err != nil { return err } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), dscispec.Monitoring.Namespace, "prometheus", true); err != nil { diff --git a/components/ray/ray.go b/components/ray/ray.go index 723cb51264f..12bdb5b240e 100644 --- a/components/ray/ray.go +++ b/components/ray/ray.go @@ -55,7 +55,7 @@ func (r *Ray) GetComponentName() string { } func (r *Ray) ReconcileComponent(ctx context.Context, cli client.Client, logger logr.Logger, - owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, _ bool) error { + owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, platform cluster.Platform, _ bool) error { l := r.ConfigComponentLogger(logger, ComponentName, dscispec) var imageParamMap = map[string]string{ @@ -65,15 +65,11 @@ func (r *Ray) ReconcileComponent(ctx context.Context, cli client.Client, logger enabled := r.GetManagementState() == operatorv1.Managed monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } if enabled { if r.DevFlags != nil { // Download manifests and update paths - if err = r.OverrideManifests(string(platform)); err != nil { + if err := r.OverrideManifests(string(platform)); err != nil { return err } } @@ -100,7 +96,7 @@ func (r *Ray) ReconcileComponent(ctx context.Context, cli client.Client, logger if err := r.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, ComponentName); err != nil { return err } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), dscispec.Monitoring.Namespace, "prometheus", true); err != nil { diff --git a/components/trainingoperator/trainingoperator.go b/components/trainingoperator/trainingoperator.go index 284c675c69d..212de8143a8 100644 --- a/components/trainingoperator/trainingoperator.go +++ b/components/trainingoperator/trainingoperator.go @@ -55,7 +55,7 @@ func (r *TrainingOperator) GetComponentName() string { } func (r *TrainingOperator) ReconcileComponent(ctx context.Context, cli client.Client, logger logr.Logger, - owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, _ bool) error { + owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, platform cluster.Platform, _ bool) error { l := r.ConfigComponentLogger(logger, ComponentName, dscispec) var imageParamMap = map[string]string{ "odh-training-operator-controller-image": "RELATED_IMAGE_ODH_TRAINING_OPERATOR_IMAGE", @@ -64,15 +64,11 @@ func (r *TrainingOperator) ReconcileComponent(ctx context.Context, cli client.Cl enabled := r.GetManagementState() == operatorv1.Managed monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } if enabled { if r.DevFlags != nil { // Download manifests and update paths - if err = r.OverrideManifests(string(platform)); err != nil { + if err := r.OverrideManifests(string(platform)); err != nil { return err } } @@ -99,7 +95,7 @@ func (r *TrainingOperator) ReconcileComponent(ctx context.Context, cli client.Cl if err := r.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, ComponentName); err != nil { return err } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), dscispec.Monitoring.Namespace, "prometheus", true); err != nil { diff --git a/components/trustyai/trustyai.go b/components/trustyai/trustyai.go index b47d06dd198..3f7a4bed7c4 100644 --- a/components/trustyai/trustyai.go +++ b/components/trustyai/trustyai.go @@ -55,7 +55,7 @@ func (t *TrustyAI) GetComponentName() string { } func (t *TrustyAI) ReconcileComponent(ctx context.Context, cli client.Client, logger logr.Logger, - owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, _ bool) error { + owner metav1.Object, dscispec *dsciv1.DSCInitializationSpec, platform cluster.Platform, _ bool) error { var imageParamMap = map[string]string{ "trustyaiServiceImage": "RELATED_IMAGE_ODH_TRUSTYAI_SERVICE_IMAGE", "trustyaiOperatorImage": "RELATED_IMAGE_ODH_TRUSTYAI_SERVICE_OPERATOR_IMAGE", @@ -65,15 +65,10 @@ func (t *TrustyAI) ReconcileComponent(ctx context.Context, cli client.Client, lo enabled := t.GetManagementState() == operatorv1.Managed monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } - if enabled { if t.DevFlags != nil { // Download manifests and update paths - if err = t.OverrideManifests(string(platform)); err != nil { + if err := t.OverrideManifests(string(platform)); err != nil { return err } } @@ -100,7 +95,7 @@ func (t *TrustyAI) ReconcileComponent(ctx context.Context, cli client.Client, lo if err := t.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, ComponentName); err != nil { return err } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), dscispec.Monitoring.Namespace, "prometheus", true); err != nil { diff --git a/components/workbenches/workbenches.go b/components/workbenches/workbenches.go index 13344757a70..133d040080f 100644 --- a/components/workbenches/workbenches.go +++ b/components/workbenches/workbenches.go @@ -97,7 +97,7 @@ func (w *Workbenches) GetComponentName() string { } func (w *Workbenches) ReconcileComponent(ctx context.Context, cli client.Client, logger logr.Logger, - owner metav1.Object, dscispec *dsci.DSCInitializationSpec, _ bool) error { + owner metav1.Object, dscispec *dsci.DSCInitializationSpec, platform cluster.Platform, _ bool) error { l := w.ConfigComponentLogger(logger, ComponentName, dscispec) var imageParamMap = map[string]string{ "odh-notebook-controller-image": "RELATED_IMAGE_ODH_NOTEBOOK_CONTROLLER_IMAGE", @@ -108,17 +108,12 @@ func (w *Workbenches) ReconcileComponent(ctx context.Context, cli client.Client, // Create rhods-notebooks namespace in managed platforms enabled := w.GetManagementState() == operatorv1.Managed monitoringEnabled := dscispec.Monitoring.ManagementState == operatorv1.Managed - platform, err := cluster.GetPlatform(cli) - if err != nil { - return err - } - // Set default notebooks namespace // Create rhods-notebooks namespace in managed platforms if enabled { if w.DevFlags != nil { // Download manifests and update paths - if err = w.OverrideManifests(string(platform)); err != nil { + if err := w.OverrideManifests(string(platform)); err != nil { return err } } @@ -131,12 +126,12 @@ func (w *Workbenches) ReconcileComponent(ctx context.Context, cli client.Client, } } // Update Default rolebinding - err = cluster.UpdatePodSecurityRolebinding(ctx, cli, dscispec.ApplicationsNamespace, "notebook-controller-service-account") + err := cluster.UpdatePodSecurityRolebinding(ctx, cli, dscispec.ApplicationsNamespace, "notebook-controller-service-account") if err != nil { return err } } - if err = deploy.DeployManifestsFromPath(cli, owner, notebookControllerPath, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { + if err := deploy.DeployManifestsFromPath(cli, owner, notebookControllerPath, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { return fmt.Errorf("failed to apply manifetss %s: %w", notebookControllerPath, err) } l.WithValues("Path", notebookControllerPath).Info("apply manifests done NBC") @@ -165,7 +160,7 @@ func (w *Workbenches) ReconcileComponent(ctx context.Context, cli client.Client, var manifestsPath string if platform == cluster.OpenDataHub || platform == "" { // only for ODH after transit to kubeflow repo - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, kfnotebookControllerPath, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { @@ -175,7 +170,7 @@ func (w *Workbenches) ReconcileComponent(ctx context.Context, cli client.Client, } else { manifestsPath = notebookImagesPathSupported } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, manifestsPath, dscispec.ApplicationsNamespace, ComponentName, enabled); err != nil { @@ -195,7 +190,7 @@ func (w *Workbenches) ReconcileComponent(ctx context.Context, cli client.Client, if err := w.UpdatePrometheusConfig(cli, enabled && monitoringEnabled, ComponentName); err != nil { return err } - if err = deploy.DeployManifestsFromPath(cli, owner, + if err := deploy.DeployManifestsFromPath(cli, owner, filepath.Join(deploy.DefaultManifestPath, "monitoring", "prometheus", "apps"), dscispec.Monitoring.Namespace, "prometheus", true); err != nil { diff --git a/controllers/datasciencecluster/datasciencecluster_controller.go b/controllers/datasciencecluster/datasciencecluster_controller.go index 78f510261ca..3c91a215bbd 100644 --- a/controllers/datasciencecluster/datasciencecluster_controller.go +++ b/controllers/datasciencecluster/datasciencecluster_controller.go @@ -322,7 +322,13 @@ func (r *DataScienceClusterReconciler) reconcileSubComponent(ctx context.Context } } // Reconcile component - err := component.ReconcileComponent(ctx, r.Client, r.Log, instance, r.DataScienceCluster.DSCISpec, installedComponentValue) + // Get platform + platform, err := cluster.GetPlatform(r.Client) + if err != nil { + r.Log.Error(err, "Failed to determine platform") + return instance, err + } + err = component.ReconcileComponent(ctx, r.Client, r.Log, instance, r.DataScienceCluster.DSCISpec, platform, installedComponentValue) if err != nil { // reconciliation failed: log errors, raise event and update status accordingly diff --git a/go.mod b/go.mod index a3e208ec921..dfa09de74d2 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/opendatahub-io/opendatahub-operator/v2 go 1.20 require ( + github.com/blang/semver/v4 v4.0.0 github.com/ghodss/yaml v1.0.0 github.com/go-logr/logr v1.4.1 github.com/hashicorp/go-multierror v1.1.1 @@ -32,7 +33,6 @@ require ( require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect