Skip to content

Commit a043254

Browse files
committedApr 9, 2020
fix(load): shouldn't clear bundle/csv field from non-default heads
previously, adding a bundle cleared out all non-default channel head contents.
1 parent dff86de commit a043254

11 files changed

+6017
-98
lines changed
 

‎bundles/prometheus.0.15.0-stable/manifests/alertmanager.crd.yaml

+2,398
Large diffs are not rendered by default.

‎bundles/prometheus.0.15.0-stable/manifests/prometheus.crd.yaml

+2,971
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
#! parse-kind: ClusterServiceVersion
2+
apiVersion: operators.coreos.com/v1alpha1
3+
kind: ClusterServiceVersion
4+
metadata:
5+
name: prometheusoperator.0.15.0-stable
6+
namespace: placeholder
7+
annotations:
8+
tectonic-visibility: ocs
9+
alm-examples: '[{"apiVersion":"monitoring.coreos.com/v1","kind":"Prometheus","metadata":{"name":"example","labels":{"prometheus":"k8s"}},"spec":{"replicas":2,"version":"v1.7.0","serviceAccountName":"prometheus-k8s","serviceMonitorSelector":{"matchExpressions":[{"key":"k8s-app","operator":"Exists"}]},"ruleSelector":{"matchLabels":{"role":"prometheus-rulefiles","prometheus":"k8s"}},"resources":{"requests":{"memory":"400Mi"}},"alerting":{"alertmanagers":[{"namespace":"monitoring","name":"alertmanager-main","port":"web"}]}}},{"apiVersion":"monitoring.coreos.com/v1","kind":"ServiceMonitor","metadata":{"name":"example","labels":{"k8s-app":"prometheus"}},"spec":{"selector":{"matchLabels":{"k8s-app":"prometheus","prometheus":"k8s"}},"namespaceSelector":{"matchNames":["monitoring"]},"endpoints":[{"port":"web","interval":"30s"}]}},{"apiVersion":"monitoring.coreos.com/v1","kind":"Alertmanager","metadata":{"name":"alertmanager-main"},"spec":{"replicas":3}}]'
10+
spec:
11+
replaces: prometheusoperator.0.14.0
12+
displayName: Prometheus
13+
description: |
14+
An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.
15+
16+
_The Prometheus Open Cloud Service is Public Alpha. The goal before Beta is for additional user testing and minor bug fixes._
17+
18+
### Monitoring applications
19+
20+
Prometheus scrapes your application metrics based on targets maintained in a ServiceMonitor object. When alerts need to be sent, they are processsed by an AlertManager.
21+
22+
[Read the complete guide to monitoring applications with the Prometheus Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/prometheus-ocs.html)
23+
24+
### Supported Features
25+
26+
27+
**High availability**
28+
29+
30+
Multiple instances are run across failure zones and data is replicated. This keeps your monitoring available during an outage, when you need it most.
31+
32+
33+
**Updates via automated operations**
34+
35+
36+
New Prometheus versions are deployed using a rolling update with no downtime, making it easy to stay up to date.
37+
38+
39+
**Handles the dynamic nature of containers**
40+
41+
42+
Alerting rules are attached to groups of containers instead of individual instances, which is ideal for the highly dynamic nature of container deployment.
43+
44+
keywords: ['prometheus', 'monitoring', 'tsdb', 'alerting']
45+
46+
maintainers:
47+
- name: CoreOS, Inc
48+
email: support@coreos.com
49+
50+
provider:
51+
name: CoreOS, Inc
52+
53+
links:
54+
- name: Prometheus
55+
url: https://www.prometheus.io/
56+
- name: Documentation
57+
url: https://coreos.com/operators/prometheus/docs/latest/
58+
- name: Prometheus Operator Source Code
59+
url: https://github.com/coreos/prometheus-operator
60+
61+
labels:
62+
alm-status-descriptors: prometheusoperator.0.15.0
63+
alm-owner-prometheus: prometheusoperator
64+
65+
selector:
66+
matchLabels:
67+
alm-owner-prometheus: prometheusoperator
68+
69+
icon:
70+
- base64data: PHN2ZyB3aWR0aD0iMjQ5MCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDI1NyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTEyOC4wMDEuNjY3QzU3LjMxMS42NjcgMCA1Ny45NzEgMCAxMjguNjY0YzAgNzAuNjkgNTcuMzExIDEyNy45OTggMTI4LjAwMSAxMjcuOTk4UzI1NiAxOTkuMzU0IDI1NiAxMjguNjY0QzI1NiA1Ny45NyAxOTguNjg5LjY2NyAxMjguMDAxLjY2N3ptMCAyMzkuNTZjLTIwLjExMiAwLTM2LjQxOS0xMy40MzUtMzYuNDE5LTMwLjAwNGg3Mi44MzhjMCAxNi41NjYtMTYuMzA2IDMwLjAwNC0zNi40MTkgMzAuMDA0em02MC4xNTMtMzkuOTRINjcuODQyVjE3OC40N2gxMjAuMzE0djIxLjgxNmgtLjAwMnptLS40MzItMzMuMDQ1SDY4LjE4NWMtLjM5OC0uNDU4LS44MDQtLjkxLTEuMTg4LTEuMzc1LTEyLjMxNS0xNC45NTQtMTUuMjE2LTIyLjc2LTE4LjAzMi0zMC43MTYtLjA0OC0uMjYyIDE0LjkzMyAzLjA2IDI1LjU1NiA1LjQ1IDAgMCA1LjQ2NiAxLjI2NSAxMy40NTggMi43MjItNy42NzMtOC45OTQtMTIuMjMtMjAuNDI4LTEyLjIzLTMyLjExNiAwLTI1LjY1OCAxOS42OC00OC4wNzkgMTIuNTgtNjYuMjAxIDYuOTEuNTYyIDE0LjMgMTQuNTgzIDE0LjggMzYuNTA1IDcuMzQ2LTEwLjE1MiAxMC40Mi0yOC42OSAxMC40Mi00MC4wNTYgMC0xMS43NjkgNy43NTUtMjUuNDQgMTUuNTEyLTI1LjkwNy02LjkxNSAxMS4zOTYgMS43OSAyMS4xNjUgOS41MyA0NS40IDIuOTAyIDkuMTAzIDIuNTMyIDI0LjQyMyA0Ljc3MiAzNC4xMzguNzQ0LTIwLjE3OCA0LjIxMy00OS42MiAxNy4wMTQtNTkuNzg0LTUuNjQ3IDEyLjguODM2IDI4LjgxOCA1LjI3IDM2LjUxOCA3LjE1NCAxMi40MjQgMTEuNDkgMjEuODM2IDExLjQ5IDM5LjYzOCAwIDExLjkzNi00LjQwNyAyMy4xNzMtMTEuODQgMzEuOTU4IDguNDUyLTEuNTg2IDE0LjI4OS0zLjAxNiAxNC4yODktMy4wMTZsMjcuNDUtNS4zNTVjLjAwMi0uMDAyLTMuOTg3IDE2LjQwMS0xOS4zMTQgMzIuMTk3eiIgZmlsbD0iI0RBNEUzMSIvPjwvc3ZnPg==
71+
mediatype: image/svg+xml
72+
73+
install:
74+
strategy: deployment
75+
spec:
76+
permissions:
77+
- serviceAccountName: prometheus-k8s
78+
rules:
79+
- apiGroups: [""]
80+
resources:
81+
- nodes
82+
- services
83+
- endpoints
84+
- pods
85+
verbs: ["get", "list", "watch"]
86+
- apiGroups: [""]
87+
resources:
88+
- configmaps
89+
verbs: ["get"]
90+
- serviceAccountName: prometheus-operator-0-14-0
91+
rules:
92+
- apiGroups:
93+
- apiextensions.k8s.io
94+
resources:
95+
- customresourcedefinitions
96+
verbs: ["get", "list"]
97+
- apiGroups:
98+
- monitoring.coreos.com
99+
resources:
100+
- alertmanagers
101+
- prometheuses
102+
- servicemonitors
103+
verbs:
104+
- "*"
105+
- apiGroups:
106+
- apps
107+
resources:
108+
- statefulsets
109+
verbs: ["*"]
110+
- apiGroups: [""]
111+
resources:
112+
- configmaps
113+
- secrets
114+
verbs: ["*"]
115+
- apiGroups: [""]
116+
resources:
117+
- pods
118+
verbs: ["list", "delete"]
119+
- apiGroups: [""]
120+
resources:
121+
- services
122+
- endpoints
123+
verbs: ["get", "create", "update"]
124+
- apiGroups: [""]
125+
resources:
126+
- nodes
127+
verbs: ["list", "watch"]
128+
- apiGroups: [""]
129+
resources:
130+
- namespaces
131+
verbs: ['list']
132+
deployments:
133+
- name: prometheus-operator
134+
spec:
135+
replicas: 1
136+
selector:
137+
matchLabels:
138+
k8s-app: prometheus-operator
139+
template:
140+
metadata:
141+
labels:
142+
k8s-app: prometheus-operator
143+
spec:
144+
serviceAccount: prometheus-operator-0-14-0
145+
containers:
146+
- name: prometheus-operator
147+
image: quay.io/coreos/prometheus-operator@sha256:0e92dd9b5789c4b13d53e1319d0a6375bcca4caaf0d698af61198061222a576d
148+
command:
149+
- sh
150+
- -c
151+
- >
152+
/bin/operator --namespace=$K8S_NAMESPACE --crd-apigroup monitoring.coreos.com
153+
--labels alm-status-descriptors=prometheusoperator.0.15.0,alm-owner-prometheus=prometheusoperator
154+
--kubelet-service=kube-system/kubelet
155+
--config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1
156+
env:
157+
- name: K8S_NAMESPACE
158+
valueFrom:
159+
fieldRef:
160+
fieldPath: metadata.namespace
161+
ports:
162+
- containerPort: 8080
163+
name: http
164+
resources:
165+
limits:
166+
cpu: 200m
167+
memory: 100Mi
168+
requests:
169+
cpu: 100m
170+
memory: 50Mi
171+
maturity: alpha
172+
version: 0.15.0
173+
customresourcedefinitions:
174+
owned:
175+
- name: prometheuses.monitoring.coreos.com
176+
version: v1
177+
kind: Prometheus
178+
displayName: Prometheus
179+
description: A running Prometheus instance
180+
resources:
181+
- kind: StatefulSet
182+
version: v1beta2
183+
- kind: Pod
184+
version: v1
185+
specDescriptors:
186+
- description: Desired number of Pods for the cluster
187+
displayName: Size
188+
path: replicas
189+
x-descriptors:
190+
- 'urn:alm:descriptor:com.tectonic.ui:podCount'
191+
- description: A selector for the ConfigMaps from which to load rule files
192+
displayName: Rule Config Map Selector
193+
path: ruleSelector
194+
x-descriptors:
195+
- 'urn:alm:descriptor:com.tectonic.ui:selector:core:v1:ConfigMap'
196+
- description: ServiceMonitors to be selected for target discovery
197+
displayName: Service Monitor Selector
198+
path: serviceMonitorSelector
199+
x-descriptors:
200+
- 'urn:alm:descriptor:com.tectonic.ui:selector:monitoring.coreos.com:v1:ServiceMonitor'
201+
- description: The ServiceAccount to use to run the Prometheus pods
202+
displayName: Service Account
203+
path: serviceAccountName
204+
x-descriptors:
205+
- 'urn:alm:descriptor:io.kubernetes:ServiceAccount'
206+
- description: Limits describes the minimum/maximum amount of compute resources required/allowed
207+
displayName: Resource Requirements
208+
path: resources
209+
x-descriptors:
210+
- 'urn:alm:descriptor:com.tectonic.ui:resourceRequirements'
211+
statusDescriptors:
212+
- description: The current number of Pods for the cluster
213+
displayName: Cluster Size
214+
path: replicas
215+
- path: prometheusSelector
216+
displayName: Prometheus Service Selector
217+
description: Label selector to find the service that routes to this prometheus
218+
x-descriptors:
219+
- 'urn:alm:descriptor:label:selector'
220+
- name: servicemonitors.monitoring.coreos.com
221+
version: v1
222+
kind: ServiceMonitor
223+
displayName: Service Monitor
224+
description: Configures prometheus to monitor a particular k8s service
225+
resources:
226+
- kind: Pod
227+
version: v1
228+
specDescriptors:
229+
- description: Selector to select which namespaces the Endpoints objects are discovered from
230+
displayName: Monitoring Namespaces
231+
path: namespaceSelector
232+
x-descriptors:
233+
- 'urn:alm:descriptor:com.tectonic.ui:namespaceSelector'
234+
- description: The label to use to retrieve the job name from
235+
displayName: Job Label
236+
path: jobLabel
237+
x-descriptors:
238+
- 'urn:alm:descriptor:com.tectonic.ui:label'
239+
- description: A list of endpoints allowed as part of this ServiceMonitor
240+
displayName: Endpoints
241+
path: endpoints
242+
x-descriptors:
243+
- 'urn:alm:descriptor:com.tectonic.ui:endpointList'
244+
- name: alertmanagers.monitoring.coreos.com
245+
version: v1
246+
kind: Alertmanager
247+
displayName: Alert Manager
248+
description: Configures an Alert Manager for the namespace
249+
resources:
250+
- kind: StatefulSet
251+
version: v1beta2
252+
- kind: Pod
253+
version: v1
254+
specDescriptors:
255+
- description: Desired number of Pods for the cluster
256+
displayName: Size
257+
path: replicas
258+
x-descriptors:
259+
- 'urn:alm:descriptor:com.tectonic.ui:podCount'
260+
- description: Limits describes the minimum/maximum amount of compute resources required/allowed
261+
displayName: Resource Requirements
262+
path: resources
263+
x-descriptors:
264+
- 'urn:alm:descriptor:com.tectonic.ui:resourceRequirements'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: prometheusrules.monitoring.coreos.com
5+
spec:
6+
group: monitoring.coreos.com
7+
names:
8+
kind: PrometheusRule
9+
plural: prometheusrules
10+
scope: Namespaced
11+
validation:
12+
openAPIV3Schema:
13+
properties:
14+
spec:
15+
description: PrometheusRuleSpec contains specification parameters for a
16+
Rule.
17+
properties:
18+
groups:
19+
description: Content of Prometheus rule file
20+
items:
21+
description: RuleGroup is a list of sequentially evaluated recording
22+
and alerting rules.
23+
properties:
24+
interval:
25+
type: string
26+
name:
27+
type: string
28+
rules:
29+
items:
30+
description: Rule describes an alerting or recording rule.
31+
properties:
32+
alert:
33+
type: string
34+
annotations:
35+
type: object
36+
expr:
37+
type: string
38+
for:
39+
type: string
40+
labels:
41+
type: object
42+
record:
43+
type: string
44+
required:
45+
- expr
46+
type: array
47+
required:
48+
- name
49+
- rules
50+
type: array
51+
version: v1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: servicemonitors.monitoring.coreos.com
5+
spec:
6+
group: monitoring.coreos.com
7+
names:
8+
kind: ServiceMonitor
9+
plural: servicemonitors
10+
scope: Namespaced
11+
validation:
12+
openAPIV3Schema:
13+
properties:
14+
spec:
15+
description: ServiceMonitorSpec contains specification parameters for a
16+
ServiceMonitor.
17+
properties:
18+
endpoints:
19+
description: A list of endpoints allowed as part of this ServiceMonitor.
20+
items:
21+
description: Endpoint defines a scrapeable endpoint serving Prometheus
22+
metrics.
23+
properties:
24+
basicAuth:
25+
description: 'BasicAuth allow an endpoint to authenticate over
26+
basic authentication More info: https://prometheus.io/docs/operating/configuration/#endpoints'
27+
properties:
28+
password:
29+
description: SecretKeySelector selects a key of a Secret.
30+
properties:
31+
key:
32+
description: The key of the secret to select from. Must
33+
be a valid secret key.
34+
type: string
35+
name:
36+
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
37+
type: string
38+
optional:
39+
description: Specify whether the Secret or it's key must
40+
be defined
41+
type: boolean
42+
required:
43+
- key
44+
username:
45+
description: SecretKeySelector selects a key of a Secret.
46+
properties:
47+
key:
48+
description: The key of the secret to select from. Must
49+
be a valid secret key.
50+
type: string
51+
name:
52+
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
53+
type: string
54+
optional:
55+
description: Specify whether the Secret or it's key must
56+
be defined
57+
type: boolean
58+
required:
59+
- key
60+
bearerTokenFile:
61+
description: File to read bearer token for scraping targets.
62+
type: string
63+
honorLabels:
64+
description: HonorLabels chooses the metric's labels on collisions
65+
with target labels.
66+
type: boolean
67+
interval:
68+
description: Interval at which metrics should be scraped
69+
type: string
70+
metricRelabelings:
71+
description: MetricRelabelConfigs to apply to samples before ingestion.
72+
items:
73+
description: 'RelabelConfig allows dynamic rewriting of the
74+
label set, being applied to samples before ingestion. It defines
75+
`<metric_relabel_configs>`-section of Prometheus configuration.
76+
More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
77+
properties:
78+
action:
79+
description: Action to perform based on regex matching.
80+
Default is 'replace'
81+
type: string
82+
modulus:
83+
description: Modulus to take of the hash of the source label
84+
values.
85+
format: int64
86+
type: integer
87+
regex:
88+
description: Regular expression against which the extracted
89+
value is matched. defailt is '(.*)'
90+
type: string
91+
replacement:
92+
description: Replacement value against which a regex replace
93+
is performed if the regular expression matches. Regex
94+
capture groups are available. Default is '$1'
95+
type: string
96+
separator:
97+
description: Separator placed between concatenated source
98+
label values. default is ';'.
99+
type: string
100+
sourceLabels:
101+
description: The source labels select values from existing
102+
labels. Their content is concatenated using the configured
103+
separator and matched against the configured regular expression
104+
for the replace, keep, and drop actions.
105+
items:
106+
type: string
107+
type: array
108+
targetLabel:
109+
description: Label to which the resulting value is written
110+
in a replace action. It is mandatory for replace actions.
111+
Regex capture groups are available.
112+
type: string
113+
type: array
114+
params:
115+
description: Optional HTTP URL parameters
116+
type: object
117+
path:
118+
description: HTTP path to scrape for metrics.
119+
type: string
120+
port:
121+
description: Name of the service port this endpoint refers to.
122+
Mutually exclusive with targetPort.
123+
type: string
124+
proxyUrl:
125+
description: ProxyURL eg http://proxyserver:2195 Directs scrapes
126+
to proxy through this endpoint.
127+
type: string
128+
scheme:
129+
description: HTTP scheme to use for scraping.
130+
type: string
131+
scrapeTimeout:
132+
description: Timeout after which the scrape is ended
133+
type: string
134+
targetPort:
135+
anyOf:
136+
- type: string
137+
- type: integer
138+
tlsConfig:
139+
description: TLSConfig specifies TLS configuration parameters.
140+
properties:
141+
caFile:
142+
description: The CA cert to use for the targets.
143+
type: string
144+
certFile:
145+
description: The client cert file for the targets.
146+
type: string
147+
insecureSkipVerify:
148+
description: Disable target certificate validation.
149+
type: boolean
150+
keyFile:
151+
description: The client key file for the targets.
152+
type: string
153+
serverName:
154+
description: Used to verify the hostname for the targets.
155+
type: string
156+
type: array
157+
jobLabel:
158+
description: The label to use to retrieve the job name from.
159+
type: string
160+
namespaceSelector:
161+
description: A selector for selecting namespaces either selecting all
162+
namespaces or a list of namespaces.
163+
properties:
164+
any:
165+
description: Boolean describing whether all namespaces are selected
166+
in contrast to a list restricting them.
167+
type: boolean
168+
matchNames:
169+
description: List of namespace names.
170+
items:
171+
type: string
172+
type: array
173+
selector:
174+
description: A label selector is a label query over a set of resources.
175+
The result of matchLabels and matchExpressions are ANDed. An empty
176+
label selector matches all objects. A null label selector matches
177+
no objects.
178+
properties:
179+
matchExpressions:
180+
description: matchExpressions is a list of label selector requirements.
181+
The requirements are ANDed.
182+
items:
183+
description: A label selector requirement is a selector that contains
184+
values, a key, and an operator that relates the key and values.
185+
properties:
186+
key:
187+
description: key is the label key that the selector applies
188+
to.
189+
type: string
190+
operator:
191+
description: operator represents a key's relationship to a
192+
set of values. Valid operators are In, NotIn, Exists and
193+
DoesNotExist.
194+
type: string
195+
values:
196+
description: values is an array of string values. If the operator
197+
is In or NotIn, the values array must be non-empty. If the
198+
operator is Exists or DoesNotExist, the values array must
199+
be empty. This array is replaced during a strategic merge
200+
patch.
201+
items:
202+
type: string
203+
type: array
204+
required:
205+
- key
206+
- operator
207+
type: array
208+
matchLabels:
209+
description: matchLabels is a map of {key,value} pairs. A single
210+
{key,value} in the matchLabels map is equivalent to an element
211+
of matchExpressions, whose key field is "key", the operator is
212+
"In", and the values array contains only "value". The requirements
213+
are ANDed.
214+
type: object
215+
targetLabels:
216+
description: TargetLabels transfers labels on the Kubernetes Service
217+
onto the target.
218+
items:
219+
type: string
220+
type: array
221+
required:
222+
- endpoints
223+
- selector
224+
version: v1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
annotations:
2+
operators.operatorframework.io.bundle.package.v1: "prometheus"
3+
operators.operatorframework.io.bundle.channels.v1: "stable"
4+
operators.operatorframework.io.bundle.channel.default.v1: "stable"

‎pkg/registry/interface.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type Load interface {
1212
AddPackageChannels(manifest PackageManifest) error
1313
AddBundlePackageChannels(manifest PackageManifest, bundle *Bundle) error
1414
RemovePackage(packageName string) error
15-
ClearNonDefaultBundles(packageName string) error
15+
ClearNonHeadBundles() error
1616
}
1717

1818
type Query interface {

‎pkg/registry/populator.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func (i *DirectoryPopulator) loadManifests(manifests string, annotationsFile *An
126126
}
127127

128128
// Finally let's delete all the old bundles
129-
if err = i.loader.ClearNonDefaultBundles(annotationsFile.GetName()); err != nil {
129+
if err = i.loader.ClearNonHeadBundles(); err != nil {
130130
return fmt.Errorf("Error deleting previous bundles: %s", err)
131131
}
132132

‎pkg/registry/populator_test.go

+90
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,52 @@ func TestImageLoading(t *testing.T) {
304304
},
305305
wantErr: false,
306306
},
307+
{
308+
name: "TwoChannel/OneChannelIsASubset",
309+
initImages: []img{
310+
{
311+
// this is in the "preview" channel
312+
ref: image.SimpleReference("quay.io/prometheus/operator:0.14.0"),
313+
dir: "../../bundles/prometheus.0.14.0",
314+
},
315+
},
316+
addImage: img{
317+
// this is in the "stable" channel and replaces v0.14.0
318+
ref: image.SimpleReference("quay.io/prometheus/operator:0.15.0-stable"),
319+
dir: "../../bundles/prometheus.0.15.0-stable",
320+
},
321+
wantPackages: []*registry.Package{
322+
{
323+
Name: "prometheus",
324+
DefaultChannel: "stable",
325+
Channels: map[string]registry.Channel{
326+
"preview": {
327+
Head: registry.BundleKey{
328+
BundlePath: "quay.io/prometheus/operator:0.14.0",
329+
Version: "0.14.0",
330+
CsvName: "prometheusoperator.0.14.0",
331+
},
332+
Nodes: map[registry.BundleKey]map[registry.BundleKey]struct{}{
333+
{BundlePath: "quay.io/prometheus/operator:0.14.0", Version: "0.14.0", CsvName: "prometheusoperator.0.14.0"}: {},
334+
},
335+
},
336+
"stable": {
337+
Head: registry.BundleKey{
338+
BundlePath: "quay.io/prometheus/operator:0.15.0-stable",
339+
Version: "0.15.0",
340+
CsvName: "prometheusoperator.0.15.0-stable",
341+
},
342+
Nodes: map[registry.BundleKey]map[registry.BundleKey]struct{}{
343+
{BundlePath: "quay.io/prometheus/operator:0.15.0-stable", Version: "0.15.0", CsvName: "prometheusoperator.0.15.0-stable"}: {
344+
{BundlePath: "quay.io/prometheus/operator:0.14.0", Version: "0.14.0", CsvName: "prometheusoperator.0.14.0"}: struct{}{},
345+
},
346+
{BundlePath: "quay.io/prometheus/operator:0.14.0", Version: "0.14.0", CsvName: "prometheusoperator.0.14.0"}: {}},
347+
},
348+
},
349+
},
350+
},
351+
wantErr: false,
352+
},
307353
}
308354
for _, tt := range tests {
309355
t.Run(tt.name, func(t *testing.T) {
@@ -329,6 +375,7 @@ func TestImageLoading(t *testing.T) {
329375
require.NoError(t, err)
330376
require.Equal(t, p, result)
331377
}
378+
CheckInvariants(t, db)
332379
})
333380
}
334381
}
@@ -339,3 +386,46 @@ func EqualBundles(t *testing.T, expected, actual api.Bundle) {
339386
expected.RequiredApis, expected.ProvidedApis, actual.RequiredApis, actual.ProvidedApis = nil, nil, nil, nil
340387
require.EqualValues(t, expected, actual)
341388
}
389+
390+
func CheckInvariants(t *testing.T, db *sql.DB) {
391+
CheckChannelHeadsHaveDescriptions(t, db)
392+
CheckBundlesHaveContentsIfNoPath(t, db)
393+
}
394+
395+
func CheckChannelHeadsHaveDescriptions(t *testing.T, db *sql.DB) {
396+
// check channel heads have csv / bundle
397+
rows, err := db.Query(`
398+
select operatorbundle.name,length(operatorbundle.csv),length(operatorbundle.bundle) from operatorbundle
399+
join channel on channel.head_operatorbundle_name = operatorbundle.name`)
400+
require.NoError(t, err)
401+
402+
for rows.Next() {
403+
var name sql.NullString
404+
var csvlen sql.NullInt64
405+
var bundlelen sql.NullInt64
406+
err := rows.Scan(&name, &csvlen, &bundlelen)
407+
require.NoError(t, err)
408+
t.Logf("channel head %s has csvlen %d and bundlelen %d", name.String, csvlen.Int64, bundlelen.Int64)
409+
require.NotZero(t, csvlen.Int64, "length of csv for %s should not be zero, it is a channel head", name.String)
410+
require.NotZero(t, bundlelen.Int64, "length of bundle for %s should not be zero, it is a channel head", name.String)
411+
}
412+
}
413+
414+
func CheckBundlesHaveContentsIfNoPath(t *testing.T, db *sql.DB) {
415+
// check that any bundle entry has csv/bundle content unpacked if there is no bundlepath
416+
rows, err := db.Query(`
417+
select name,length(csv),length(bundle) from operatorbundle
418+
where bundlepath="" or bundlepath=null`)
419+
require.NoError(t, err)
420+
421+
for rows.Next() {
422+
var name sql.NullString
423+
var csvlen sql.NullInt64
424+
var bundlelen sql.NullInt64
425+
err := rows.Scan(&name, &csvlen, &bundlelen)
426+
require.NoError(t, err)
427+
t.Logf("bundle %s has csvlen %d and bundlelen %d", name.String, csvlen.Int64, bundlelen.Int64)
428+
require.NotZero(t, csvlen.Int64, "length of csv for %s should not be zero, it has no bundle path", name.String)
429+
require.NotZero(t, bundlelen.Int64, "length of bundle for %s should not be zero, it has no bundle path", name.String)
430+
}
431+
}

‎pkg/sqlite/load.go

+11-94
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ func (s *SQLLoader) addPackageChannels(tx *sql.Tx, manifest registry.PackageMani
416416
return utilerrors.NewAggregate(errs)
417417
}
418418

419-
func (s *SQLLoader) ClearNonDefaultBundles(packageName string) error {
419+
func (s *SQLLoader) ClearNonHeadBundles() error {
420420
tx, err := s.db.Begin()
421421
if err != nil {
422422
return err
@@ -425,109 +425,26 @@ func (s *SQLLoader) ClearNonDefaultBundles(packageName string) error {
425425
tx.Rollback()
426426
}()
427427

428-
// First find the default channel for the package
429-
getDefChan, err := tx.Prepare(fmt.Sprintf("select default_channel from package where name='%s'", packageName))
428+
removeNonHeadBundles, err := tx.Prepare(`
429+
update operatorbundle set bundle = null, csv = null
430+
where (bundlepath != null or bundlepath != "")
431+
and name not in (
432+
select operatorbundle.name from operatorbundle
433+
join channel on channel.head_operatorbundle_name = operatorbundle.name
434+
)
435+
`)
430436
if err != nil {
431437
return err
432438
}
433-
defer getDefChan.Close()
439+
defer removeNonHeadBundles.Close()
434440

435-
defaultChannelRows, err := getDefChan.Query()
441+
_, err = removeNonHeadBundles.Exec()
436442
if err != nil {
437443
return err
438444
}
439-
defer defaultChannelRows.Close()
440-
441-
if !defaultChannelRows.Next() {
442-
return fmt.Errorf("no default channel found for package %s", packageName)
443-
}
444-
var defaultChannel sql.NullString
445-
if err := defaultChannelRows.Scan(&defaultChannel); err != nil {
446-
return err
447-
}
448-
449-
// Then get the head of the default channel
450-
getChanHead, err := tx.Prepare(fmt.Sprintf("select head_operatorbundle_name from channel where name='%s'", defaultChannel.String))
451-
if err != nil {
452-
return err
453-
}
454-
defer getChanHead.Close()
455-
456-
chanHeadRows, err := getChanHead.Query()
457-
if err != nil {
458-
return err
459-
}
460-
defer chanHeadRows.Close()
461-
462-
if !chanHeadRows.Next() {
463-
return fmt.Errorf("no channel head found for default channel %s", defaultChannel.String)
464-
}
465-
var defChanHead sql.NullString
466-
if err := chanHeadRows.Scan(&defChanHead); err != nil {
467-
return err
468-
}
469-
470-
// Now get all the bundles that are not the head of the default channel
471-
getChannelBundles, err := tx.Prepare(fmt.Sprintf("SELECT operatorbundle_name FROM channel_entry WHERE package_name='%s' AND operatorbundle_name!='%s'", packageName, defChanHead.String))
472-
if err != nil {
473-
return err
474-
}
475-
defer getChanHead.Close()
476-
477-
chanBundleRows, err := getChannelBundles.Query()
478-
if err != nil {
479-
return err
480-
}
481-
defer chanBundleRows.Close()
482-
483-
bundles := make(map[string]struct{}, 0)
484-
for chanBundleRows.Next() {
485-
var bundleToUpdate sql.NullString
486-
if err := chanBundleRows.Scan(&bundleToUpdate); err != nil {
487-
return err
488-
}
489-
bundles[bundleToUpdate.String] = struct{}{}
490-
}
491-
492-
if len(bundles) > 0 {
493-
bundlePredicates := []string{}
494-
for bundle := range bundles {
495-
bundlePredicates = append(bundlePredicates, fmt.Sprintf("name = '%s'", bundle))
496-
}
497-
498-
var transactionPredicate string
499-
if len(bundlePredicates) == 1 {
500-
transactionPredicate = fmt.Sprintf("WHERE %s AND bundlepath != \"\"", bundlePredicates[0])
501-
} else {
502-
transactionPredicate = fmt.Sprintf("WHERE (%s) AND bundlepath != \"\"", strings.Join(bundlePredicates, " OR "))
503-
}
504-
505-
removeOldBundles, err := tx.Prepare(fmt.Sprintf("UPDATE operatorbundle SET bundle = null, csv = null %s", transactionPredicate))
506-
if err != nil {
507-
return err
508-
}
509-
510-
_, err = removeOldBundles.Exec()
511-
if err != nil {
512-
return fmt.Errorf("Unable to remove previous bundles: %s", err)
513-
}
514-
}
515-
516445
return tx.Commit()
517446
}
518447

519-
func SplitCRDName(crdName string) (plural, group string, err error) {
520-
pluralGroup := strings.SplitN(crdName, ".", 2)
521-
if len(pluralGroup) != 2 {
522-
err = fmt.Errorf("can't split bad CRD name %s", crdName)
523-
return
524-
}
525-
526-
plural = pluralGroup[0]
527-
group = pluralGroup[1]
528-
return
529-
}
530-
531448
func (s *SQLLoader) getBundleSkipsReplaces(tx *sql.Tx, bundleName string) (replaces string, skips []string, err error) {
532449
getReplacesAndSkips, err := tx.Prepare(`
533450
SELECT replaces, skips

‎pkg/sqlite/load_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ func TestAddPackageChannels(t *testing.T) {
154154
}
155155
}
156156

157-
func TestClearNonDefaultBundles(t *testing.T) {
157+
func TestClearNonHeadBundles(t *testing.T) {
158158
db, cleanup := CreateTestDb(t)
159159
defer cleanup()
160160
store, err := NewSQLLiteLoader(db)
@@ -187,7 +187,7 @@ func TestClearNonDefaultBundles(t *testing.T) {
187187
require.NoError(t, err)
188188

189189
// Clear everything but the default bundle
190-
require.NoError(t, store.ClearNonDefaultBundles(pkg))
190+
require.NoError(t, store.ClearNonHeadBundles())
191191

192192
// Internal node without bundle path should keep its manifests
193193
querier := NewSQLLiteQuerierFromDb(db)

0 commit comments

Comments
 (0)
Please sign in to comment.