Skip to content

Commit 17f6efb

Browse files
committed
update: cleanup unnecessary upgrade logic
- remove functions and calls not needed for 3.2 (should be removed in 3.0 already) jupyterhub resource cleanup rbac for modelreg envoyfilter patch for serving watson resource docs patch odhdashboardconfig for trusty enablement - move and cleanup function for AP to HWP migration Signed-off-by: Wen Zhou <[email protected]>
1 parent 0ea2f33 commit 17f6efb

File tree

6 files changed

+246
-435
lines changed

6 files changed

+246
-435
lines changed

cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ func main() { //nolint:funlen,maintidx,gocyclo
256256
}
257257

258258
// get old release version before we create default DSCI CR
259-
oldReleaseVersion, _ := upgrade.GetDeployedRelease(ctx, setupClient)
259+
oldReleaseVersion, _ := cluster.GetDeployedRelease(ctx, setupClient)
260260

261261
secretCache, err := createSecretCacheConfig(platform)
262262
if err != nil {

pkg/cluster/cluster_config.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,46 @@ func GetRelease() common.Release {
9898
return clusterConfig.Release
9999
}
100100

101+
// GetDeployedRelease retrieves the currently deployed release version from the cluster.
102+
// It first attempts to get the release from the DSCInitialization (DSCI) instance,
103+
// and if not found, falls back to the DataScienceCluster (DSC) instance.
104+
//
105+
// This function is useful during upgrades to determine what version is currently deployed
106+
// before applying any changes.
107+
//
108+
// Parameters:
109+
// - ctx: The context for the request
110+
// - cli: The Kubernetes client used to retrieve resources
111+
//
112+
// Returns:
113+
// - common.Release: The deployed release information, or an empty Release if not found
114+
// - error: An error if the retrieval fails for reasons other than "not found"
115+
func GetDeployedRelease(ctx context.Context, cli client.Client) (common.Release, error) {
116+
dsciInstance, err := GetDSCI(ctx, cli)
117+
switch {
118+
case k8serr.IsNotFound(err):
119+
break
120+
case err != nil:
121+
return common.Release{}, err
122+
default:
123+
return dsciInstance.Status.Release, nil
124+
}
125+
126+
// no DSCI CR found, try with DSC CR
127+
dscInstances, err := GetDSC(ctx, cli)
128+
switch {
129+
case k8serr.IsNotFound(err):
130+
break
131+
case err != nil:
132+
return common.Release{}, err
133+
default:
134+
return dscInstances.Status.Release, nil
135+
}
136+
137+
// could be a clean installation or both CRs are deleted already
138+
return common.Release{}, nil
139+
}
140+
101141
func GetClusterInfo() ClusterInfo {
102142
return clusterConfig.ClusterInfo
103143
}

pkg/cluster/resources.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,25 @@ func GetHardwareProfile(ctx context.Context, cli client.Client, name, namespace
173173
return hwProfile, nil
174174
}
175175

176+
// CreateHardwareProfile creates a HardwareProfile resource in the cluster.
177+
// If the resource already exists, it returns nil (idempotent operation).
178+
//
179+
// Parameters:
180+
// - ctx: The context for the request
181+
// - cli: The Kubernetes client used to create the resource
182+
// - hwp: The HardwareProfile to create
183+
//
184+
// Returns:
185+
// - error: An error if the creation fails for reasons other than "already exists"
186+
func CreateHardwareProfile(ctx context.Context, cli client.Client, hwp *infrav1.HardwareProfile) error {
187+
if err := cli.Create(ctx, hwp); err != nil {
188+
if !k8serr.IsAlreadyExists(err) {
189+
return fmt.Errorf("failed to create HardwareProfile '%s/%s': %w", hwp.Namespace, hwp.Name, err)
190+
}
191+
}
192+
return nil
193+
}
194+
176195
// UpdatePodSecurityRolebinding update default rolebinding which is created in applications namespace by manifests
177196
// being used by different components and SRE monitoring.
178197
func UpdatePodSecurityRolebinding(ctx context.Context, cli client.Client, namespace string, serviceAccountsList ...string) error {

pkg/resources/resources.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import (
1111
"slices"
1212

1313
"github.com/davecgh/go-spew/spew"
14+
"github.com/hashicorp/go-multierror"
1415
routev1 "github.com/openshift/api/route/v1"
1516
"gopkg.in/yaml.v3"
1617
corev1 "k8s.io/api/core/v1"
1718
k8serr "k8s.io/apimachinery/pkg/api/errors"
19+
"k8s.io/apimachinery/pkg/api/meta"
1820
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1921
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2022
"k8s.io/apimachinery/pkg/runtime"
@@ -23,10 +25,23 @@ import (
2325
"k8s.io/client-go/discovery"
2426
"sigs.k8s.io/controller-runtime/pkg/client"
2527
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
28+
logf "sigs.k8s.io/controller-runtime/pkg/log"
2629
)
2730

2831
const PlatformFieldOwner = "platform.opendatahub.io"
2932

33+
// ResourceSpec defines a specification for identifying and filtering Kubernetes resources
34+
// based on their GroupVersionKind, namespace, and field values.
35+
type ResourceSpec struct {
36+
Gvk schema.GroupVersionKind
37+
Namespace string
38+
// FieldPath specifies the path to the field for filtering, like ["metadata", "name"]
39+
FieldPath []string
40+
// FilterValues contains the values to match against the field - if the field value
41+
// matches any of these values, the resource will be processed (e.g., deleted)
42+
FilterValues []string
43+
}
44+
3045
func ToUnstructured(obj any) (*unstructured.Unstructured, error) {
3146
data, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
3247
if err != nil {
@@ -631,3 +646,95 @@ func ListAvailableAPIResources(
631646

632647
return items, nil
633648
}
649+
650+
// DeleteResources iterates through a list of ResourceSpec and deletes matching Kubernetes resources.
651+
// It collects all errors encountered during deletion and returns them as a multierror.
652+
//
653+
// Parameters:
654+
// - ctx: The context for the operation
655+
// - c: The Kubernetes client used to list and delete resources
656+
// - resources: A slice of ResourceSpec defining which resources to delete
657+
//
658+
// Returns:
659+
// - error: A multierror containing all errors encountered, or nil if all deletions succeeded
660+
func DeleteResources(ctx context.Context, c client.Client, resources []ResourceSpec) error {
661+
var errors *multierror.Error
662+
663+
for _, res := range resources {
664+
err := DeleteOneResource(ctx, c, res)
665+
errors = multierror.Append(errors, err)
666+
}
667+
668+
return errors.ErrorOrNil()
669+
}
670+
671+
// DeleteOneResource deletes all Kubernetes resources matching the given ResourceSpec.
672+
// It lists resources of the specified GVK in the given namespace, filters them based on
673+
// the field path and values, and deletes matching resources.
674+
//
675+
// Parameters:
676+
// - ctx: The context for the operation
677+
// - c: The Kubernetes client used to list and delete resources
678+
// - res: The ResourceSpec defining which resources to delete
679+
//
680+
// Returns:
681+
// - error: An error if the operation fails, or nil on success
682+
func DeleteOneResource(ctx context.Context, c client.Client, res ResourceSpec) error {
683+
log := logf.FromContext(ctx)
684+
list := &unstructured.UnstructuredList{}
685+
list.SetGroupVersionKind(res.Gvk)
686+
687+
err := c.List(ctx, list, client.InNamespace(res.Namespace))
688+
if err != nil {
689+
if meta.IsNoMatchError(err) {
690+
log.Info("CRD not found, will not delete", "gvk", res.Gvk.String())
691+
return nil
692+
}
693+
return fmt.Errorf("failed to list %s: %w", res.Gvk.Kind, err)
694+
}
695+
696+
for _, item := range list.Items {
697+
v, ok, err := unstructured.NestedString(item.Object, res.FieldPath...)
698+
if err != nil {
699+
return fmt.Errorf("failed to get field %v for %s %s/%s: %w", res.FieldPath, res.Gvk.Kind, res.Namespace, item.GetName(), err)
700+
}
701+
702+
if !ok {
703+
return fmt.Errorf("nonexistent field path: %v", res.FieldPath)
704+
}
705+
706+
for _, targetValue := range res.FilterValues {
707+
if v == targetValue {
708+
err = c.Delete(ctx, &item)
709+
if err != nil {
710+
return fmt.Errorf("failed to delete %s %s/%s: %w", res.Gvk.Kind, res.Namespace, item.GetName(), err)
711+
}
712+
log.Info("Deleted object", "name", item.GetName(), "gvk", res.Gvk.String(), "namespace", res.Namespace)
713+
}
714+
}
715+
}
716+
717+
return nil
718+
}
719+
720+
// UnsetOwnerReferences removes all owner references from a Kubernetes object and updates it.
721+
// This is useful when you need to orphan a resource from its owner.
722+
//
723+
// Parameters:
724+
// - ctx: The context for the operation
725+
// - cli: The Kubernetes client used to update the resource
726+
// - instanceName: The name of the instance (used for error reporting)
727+
// - odhObject: The unstructured object whose owner references should be removed
728+
//
729+
// Returns:
730+
// - error: An error if the update operation fails, or nil if there are no owner references or update succeeds
731+
func UnsetOwnerReferences(ctx context.Context, cli client.Client, instanceName string, odhObject *unstructured.Unstructured) error {
732+
if odhObject.GetOwnerReferences() != nil {
733+
// set to nil as updates
734+
odhObject.SetOwnerReferences(nil)
735+
if err := cli.Update(ctx, odhObject); err != nil {
736+
return fmt.Errorf("error unset ownerreference for CR %s : %w", instanceName, err)
737+
}
738+
}
739+
return nil
740+
}

0 commit comments

Comments
 (0)