Skip to content

Commit 17a9c00

Browse files
committed
update: cleanup unnecessary upgrade logic
- remove functions and calls not needed for 3.1 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 e31a7c0 commit 17a9c00

File tree

6 files changed

+247
-436
lines changed

6 files changed

+247
-436
lines changed

cmd/main.go

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

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

263263
secretCache, err := createSecretCacheConfig(ctx, setupClient, platform)
264264
if err != nil {

pkg/cluster/cluster_config.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,46 @@ func GetRelease() common.Release {
9090
return clusterConfig.Release
9191
}
9292

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

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("unexisting path to delete: %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)