• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

operator-framework / operator-sdk / 12323500562

13 Dec 2024 09:44PM UTC coverage: 34.569%. First build
12323500562

Pull #6878

github

acornett21
k8s 1.31 work

Signed-off-by: Adam D. Cornett <adc@redhat.com>
Pull Request #6878: k8s 1.31 work

9 of 22 new or added lines in 15 files covered. (40.91%)

4766 of 13787 relevant lines covered (34.57%)

13.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/internal/olm/client/status.go
1
// Copyright 2019 The Operator-SDK Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
// Package olm provides an API to install, uninstall, and check the
16
// status of an Operator Lifecycle Manager installation.
17
// TODO: move to OLM repository?
18
package client
19

20
import (
21
        "bytes"
22
        "context"
23
        "errors"
24
        "fmt"
25
        "sort"
26
        "text/tabwriter"
27

28
        "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
29
        apierrors "k8s.io/apimachinery/pkg/api/errors"
30
        "k8s.io/apimachinery/pkg/api/meta"
31
        "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
32
        "k8s.io/apimachinery/pkg/runtime"
33
        "k8s.io/apimachinery/pkg/runtime/schema"
34
        "k8s.io/apimachinery/pkg/types"
35
        apiutilerrors "k8s.io/apimachinery/pkg/util/errors"
36
        "k8s.io/utils/set"
37
        "sigs.k8s.io/controller-runtime/pkg/client"
38
)
39

40
type Status struct {
41
        Resources []ResourceStatus
42
}
43

44
type ResourceStatus struct {
45
        NamespacedName types.NamespacedName
46
        Resource       *unstructured.Unstructured
47
        GVK            schema.GroupVersionKind
48
        Error          error
49

50
        requestObject runtime.Object // Needed for context on errors from requests on an object.
51
}
52

53
func (c Client) GetObjectsStatus(ctx context.Context, objs ...client.Object) Status {
×
54
        var rss []ResourceStatus
×
55
        for _, obj := range objs {
×
56
                gvk := obj.GetObjectKind().GroupVersionKind()
×
57
                nn := types.NamespacedName{
×
58
                        Namespace: obj.GetNamespace(),
×
59
                        Name:      obj.GetName(),
×
60
                }
×
61
                rs := ResourceStatus{
×
62
                        NamespacedName: nn,
×
63
                        GVK:            gvk,
×
64
                        requestObject:  obj,
×
65
                }
×
66
                u := unstructured.Unstructured{}
×
67
                u.SetGroupVersionKind(gvk)
×
68
                err := c.KubeClient.Get(ctx, nn, &u)
×
69
                if err != nil {
×
70
                        rs.Error = fmt.Errorf("error getting resource %q with GVK %q: %w", nn, gvk, err)
×
71
                }
×
72
                if rs.Error == nil {
×
73
                        rs.Resource = &u
×
74
                }
×
75
                rss = append(rss, rs)
×
76
        }
77

78
        return Status{Resources: rss}
×
79
}
80

81
// HasInstalledResources only returns true if at least one resource in s
82
// was returned successfully by the API server. A resource error status
83
// containing any error except "not found", or "no kind match" errors
84
// for Custom Resources, will result in HasInstalledResources returning
85
// false and the error.
86
func (s Status) HasInstalledResources() (bool, error) {
×
87
        errs := []error{}
×
88
        crdKindSet, err := s.getCRDKindSet()
×
89
        if err != nil {
×
90
                return false, fmt.Errorf("error getting set of CRD kinds in resources: %v", err)
×
91
        }
×
92
        // Sort resources by whether they're installed or not to get consistent
93
        // return values.
NEW
94
        sort.Slice(s.Resources, func(i int, _ int) bool {
×
95
                return s.Resources[i].Resource != nil
×
96
        })
×
97
        for _, r := range s.Resources {
×
98
                if r.Resource != nil {
×
99
                        return true, nil
×
100
                } else if r.Error != nil && !apierrors.IsNotFound(r.Error) {
×
101
                        // We know the error is not a "resource not found" error at this point.
×
102
                        // It still may be the equivalent for a CR, "no kind match", if its
×
103
                        // corresponding CRD has been deleted already. We want to make sure
×
104
                        // we're only allowing "no kind match" errors to be skipped for CR's
×
105
                        // since we do not know if a kind is a CR kind, hence checking
×
106
                        // crdKindSet for existence of a resource's kind.
×
107
                        nkmerr := &meta.NoKindMatchError{}
×
108
                        if !errors.As(r.Error, &nkmerr) || !crdKindSet.Has(r.GVK.Kind) {
×
109
                                errs = append(errs, r.Error)
×
110
                        }
×
111
                }
112
        }
113
        return false, apiutilerrors.NewAggregate(errs)
×
114
}
115

116
// getCRDKindSet returns the set of all kinds specified by all CRDs in s.
117
func (s Status) getCRDKindSet() (set.Set[string], error) {
×
118
        crdKindSet := set.New[string]()
×
119
        for _, r := range s.Resources {
×
120
                if r.GVK.Kind == "CustomResourceDefinition" {
×
121
                        u := &unstructured.Unstructured{}
×
122
                        switch v := r.requestObject.(type) {
×
123
                        case *unstructured.Unstructured:
×
124
                                u = v
×
125
                        default:
×
126
                                uObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&v)
×
127
                                if err != nil {
×
128
                                        return nil, err
×
129
                                }
×
130
                                // Other fields are not important, just the CRD kind.
131
                                u.Object = uObj
×
132
                        }
133
                        // Use unversioned CustomResourceDefinition to avoid implementing cast
134
                        // for all versions.
135
                        crd := &apiextensions.CustomResourceDefinition{}
×
136
                        err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &crd)
×
137
                        if err != nil {
×
138
                                return nil, err
×
139
                        }
×
140
                        crdKindSet.Insert(crd.Spec.Names.Kind)
×
141
                }
142
        }
143
        return crdKindSet, nil
×
144
}
145

146
func (s Status) String() string {
×
147
        out := &bytes.Buffer{}
×
148
        tw := tabwriter.NewWriter(out, 8, 4, 4, ' ', 0)
×
149
        fmt.Fprintf(tw, "NAME\tNAMESPACE\tKIND\tSTATUS\n")
×
150
        for _, r := range s.Resources {
×
151
                nn := r.NamespacedName
×
152
                kind := r.GVK.Kind
×
153
                var status string
×
154
                if r.Error != nil {
×
155
                        status = r.Error.Error()
×
156
                } else if r.Resource != nil {
×
157
                        status = "Installed"
×
158
                } else {
×
159
                        status = "Unknown"
×
160
                }
×
161
                fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", nn.Name, nn.Namespace, kind, status)
×
162
        }
163
        tw.Flush()
×
164

×
165
        return out.String()
×
166
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc