Skip to content

Commit 33b225b

Browse files
authored
Merge branch 'master' into remove_kubeconfig_flag
2 parents 9c77995 + ab923b3 commit 33b225b

File tree

7 files changed

+415
-16
lines changed

7 files changed

+415
-16
lines changed

pkg/controller/registry/grpc/source_test.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ type FakeSourceSyncer struct {
5050
History map[registry.CatalogKey][]connectivity.State
5151

5252
sync.Mutex
53-
expectedEvents int
54-
done chan struct{}
53+
expectedReadies int
54+
done chan struct{}
5555
}
5656

5757
func (f *FakeSourceSyncer) sync(state SourceState) {
@@ -60,18 +60,20 @@ func (f *FakeSourceSyncer) sync(state SourceState) {
6060
f.History[state.Key] = []connectivity.State{}
6161
}
6262
f.History[state.Key] = append(f.History[state.Key], state.State)
63-
f.expectedEvents--
64-
if f.expectedEvents == 0 {
63+
if state.State == connectivity.Ready {
64+
f.expectedReadies--
65+
}
66+
if f.expectedReadies == 0 {
6567
f.done <- struct{}{}
6668
}
6769
f.Unlock()
6870
}
6971

70-
func NewFakeSourceSyncer(expectedEvents int) *FakeSourceSyncer {
72+
func NewFakeSourceSyncer(expectedReadies int) *FakeSourceSyncer {
7173
return &FakeSourceSyncer{
72-
History: map[registry.CatalogKey][]connectivity.State{},
73-
expectedEvents: expectedEvents,
74-
done: make(chan struct{}),
74+
History: map[registry.CatalogKey][]connectivity.State{},
75+
expectedReadies: expectedReadies,
76+
done: make(chan struct{}),
7577
}
7678
}
7779

@@ -84,21 +86,19 @@ func TestConnectionEvents(t *testing.T) {
8486
test := func(tt testcase) func(t *testing.T) {
8587
return func(t *testing.T) {
8688
// start server for each catalog
87-
totalEvents := 0
8889
addresses := map[registry.CatalogKey]string{}
8990

90-
for catalog, events := range tt.expectedHistory {
91-
totalEvents += len(events)
91+
for catalog := range tt.expectedHistory {
9292
serve, address, stop := server(&fakes.FakeQuery{})
9393
addresses[catalog] = address
9494
go serve()
9595
defer stop()
9696
}
9797

9898
// start source manager
99-
syncer := NewFakeSourceSyncer(totalEvents)
99+
syncer := NewFakeSourceSyncer(len(tt.expectedHistory))
100100
sources := NewSourceStore(logrus.New(), 1*time.Second, 5*time.Second, syncer.sync)
101-
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
101+
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
102102
defer cancel()
103103
sources.Start(ctx)
104104

@@ -115,7 +115,13 @@ func TestConnectionEvents(t *testing.T) {
115115
for catalog, events := range tt.expectedHistory {
116116
recordedEvents := syncer.History[catalog]
117117
for i := 0; i < len(recordedEvents); i++ {
118-
require.Equal(t, (events[i]).String(), (recordedEvents[i]).String())
118+
found := false
119+
for _, event := range events {
120+
if event.String() == recordedEvents[i].String() {
121+
found = true
122+
}
123+
}
124+
require.True(t, found)
119125
}
120126
}
121127
}

test/e2e/csv_e2e_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4423,8 +4423,6 @@ var _ = Describe("Disabling copied CSVs", func() {
44234423

44244424
var singleInstance = int32(1)
44254425

4426-
type cleanupFunc func()
4427-
44284426
var immediateDeleteGracePeriod int64 = 0
44294427

44304428
func findLastEvent(events *corev1.EventList) (event corev1.Event) {

test/e2e/fbc_provider.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package e2e
2+
3+
import (
4+
"io/ioutil"
5+
)
6+
7+
type FileBasedCatalogProvider interface {
8+
GetCatalog() string
9+
}
10+
11+
type fileBasedFileBasedCatalogProvider struct {
12+
fbc string
13+
}
14+
15+
func NewFileBasedFiledBasedCatalogProvider(path string) (FileBasedCatalogProvider, error) {
16+
data, err := ioutil.ReadFile(path)
17+
if err != nil {
18+
return nil, err
19+
}
20+
21+
return &fileBasedFileBasedCatalogProvider{
22+
fbc: string(data),
23+
}, nil
24+
}
25+
26+
func (f *fileBasedFileBasedCatalogProvider) GetCatalog() string {
27+
return f.fbc
28+
}

test/e2e/magic_catalog.go

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
8+
corev1 "k8s.io/api/core/v1"
9+
k8serror "k8s.io/apimachinery/pkg/api/errors"
10+
"k8s.io/apimachinery/pkg/api/resource"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/util/intstr"
13+
k8scontrollerclient "sigs.k8s.io/controller-runtime/pkg/client"
14+
)
15+
16+
const (
17+
olmCatalogLabel string = "olm.catalogSource"
18+
catalogMountPath string = "/opt/olm"
19+
catalogServicePort int32 = 50051
20+
catalogReadyState string = "READY"
21+
)
22+
23+
type MagicCatalog interface {
24+
DeployCatalog(ctx context.Context) error
25+
UndeployCatalog(ctx context.Context) []error
26+
}
27+
28+
type magicCatalog struct {
29+
fileBasedCatalog FileBasedCatalogProvider
30+
kubeClient k8scontrollerclient.Client
31+
namespace string
32+
name string
33+
configMapName string
34+
serviceName string
35+
podName string
36+
}
37+
38+
// NewMagicCatalog creates an object that can deploy an arbitrary file-based catalog given by the FileBasedCatalogProvider
39+
// Keep in mind that there are limits to the configMaps. So, the catalogs need to be relatively simple
40+
func NewMagicCatalog(kubeClient k8scontrollerclient.Client, namespace string, catalogName string, provider FileBasedCatalogProvider) MagicCatalog {
41+
return &magicCatalog{
42+
fileBasedCatalog: provider,
43+
kubeClient: kubeClient,
44+
namespace: namespace,
45+
name: catalogName,
46+
configMapName: catalogName + "-configmap",
47+
serviceName: catalogName + "-svc",
48+
podName: catalogName + "-pod",
49+
}
50+
}
51+
52+
func (c *magicCatalog) DeployCatalog(ctx context.Context) error {
53+
54+
catalogSource := c.makeCatalogSource()
55+
resourcesInOrderOfDeployment := []k8scontrollerclient.Object{
56+
c.makeConfigMap(),
57+
c.makeCatalogSourcePod(),
58+
c.makeCatalogService(),
59+
catalogSource,
60+
}
61+
62+
for _, res := range resourcesInOrderOfDeployment {
63+
err := c.kubeClient.Create(ctx, res)
64+
if err != nil {
65+
return c.cleanUpAfter(ctx, err)
66+
}
67+
}
68+
69+
// wait for catalog source to become ready
70+
err := waitFor(func() (bool, error) {
71+
err := c.kubeClient.Get(ctx, k8scontrollerclient.ObjectKey{
72+
Name: catalogSource.GetName(),
73+
Namespace: catalogSource.GetNamespace(),
74+
}, catalogSource)
75+
76+
if err != nil || catalogSource.Status.GRPCConnectionState == nil {
77+
return false, err
78+
}
79+
80+
state := catalogSource.Status.GRPCConnectionState.LastObservedState
81+
82+
if state != catalogReadyState {
83+
return false, nil
84+
} else {
85+
return true, nil
86+
}
87+
})
88+
89+
if err != nil {
90+
return c.cleanUpAfter(ctx, err)
91+
}
92+
93+
return nil
94+
}
95+
96+
func (c *magicCatalog) UndeployCatalog(ctx context.Context) []error {
97+
var errs []error = nil
98+
99+
resourcesInOrderOfDeletion := []k8scontrollerclient.Object{
100+
c.makeCatalogSource(),
101+
c.makeCatalogService(),
102+
c.makeCatalogSourcePod(),
103+
c.makeConfigMap(),
104+
}
105+
106+
// try to delete all resourcesInOrderOfDeletion even if errors are
107+
// encountered through deletion.
108+
for _, res := range resourcesInOrderOfDeletion {
109+
err := c.kubeClient.Delete(ctx, res)
110+
111+
// ignore not found errors
112+
if err != nil && !k8serror.IsNotFound(err) {
113+
if errs == nil {
114+
errs = make([]error, 0)
115+
}
116+
errs = append(errs, err)
117+
}
118+
}
119+
120+
return errs
121+
}
122+
123+
func (c *magicCatalog) cleanUpAfter(ctx context.Context, err error) error {
124+
cleanupErr := c.UndeployCatalog(ctx)
125+
if cleanupErr != nil {
126+
return fmt.Errorf("the following cleanup errors occurred: '%s' after an error deploying the configmap: '%s' ", cleanupErr, err)
127+
}
128+
return err
129+
}
130+
131+
func (c *magicCatalog) makeCatalogService() *corev1.Service {
132+
return &corev1.Service{
133+
ObjectMeta: metav1.ObjectMeta{
134+
Name: c.serviceName,
135+
Namespace: c.namespace,
136+
},
137+
Spec: corev1.ServiceSpec{
138+
Ports: []corev1.ServicePort{
139+
{
140+
Name: "grpc",
141+
Port: catalogServicePort,
142+
Protocol: "TCP",
143+
TargetPort: intstr.FromInt(int(catalogServicePort)),
144+
},
145+
},
146+
Selector: c.makeCatalogSourcePodLabels(),
147+
},
148+
}
149+
}
150+
151+
func (c *magicCatalog) makeConfigMap() *corev1.ConfigMap {
152+
isImmutable := true
153+
return &corev1.ConfigMap{
154+
ObjectMeta: metav1.ObjectMeta{
155+
Name: c.configMapName,
156+
Namespace: c.namespace,
157+
},
158+
Immutable: &isImmutable,
159+
Data: map[string]string{
160+
"catalog.json": c.fileBasedCatalog.GetCatalog(),
161+
// due to the way files get mounted to pods from configMaps
162+
// it is important to add _this_ .indexignore
163+
//
164+
// The mount folder will look something like this:
165+
// /opt/olm
166+
// |--> ..2021_12_15_02_01_11.729011450
167+
// |--> catalog.json
168+
// |--> .indexignore
169+
// |--> ..data -> ..2021_12_15_02_01_11.729011450
170+
// |--> catalog.json -> ..data/catalog.json
171+
// |--> .indexignore -> ..data/.indexignore
172+
// Adding '**/..*' to the .indexignore ensures the
173+
// '..2021_12_15_02_01_11.729011450' and ' ..data' directories are ignored.
174+
// Otherwise, opm will pick up on both catalog.json files and fail with a conflicts (duplicate packages)
175+
".indexignore": "**/\\.\\.*\n",
176+
},
177+
}
178+
}
179+
180+
func (c *magicCatalog) makeCatalogSource() *operatorsv1alpha1.CatalogSource {
181+
return &operatorsv1alpha1.CatalogSource{
182+
ObjectMeta: metav1.ObjectMeta{
183+
Name: c.name,
184+
Namespace: c.namespace,
185+
},
186+
Spec: operatorsv1alpha1.CatalogSourceSpec{
187+
SourceType: operatorsv1alpha1.SourceTypeGrpc,
188+
Address: fmt.Sprintf("%s.%s.svc:50051", c.serviceName, c.namespace),
189+
},
190+
}
191+
}
192+
193+
func (c *magicCatalog) makeCatalogSourcePod() *corev1.Pod {
194+
195+
const (
196+
image = "quay.io/operator-framework/upstream-opm-builder"
197+
readinessDelay int32 = 5
198+
livenessDelay int32 = 10
199+
volumeMountName string = "fbc-catalog"
200+
)
201+
202+
readOnlyRootFilesystem := false
203+
204+
return &corev1.Pod{
205+
ObjectMeta: metav1.ObjectMeta{
206+
Name: c.podName,
207+
Namespace: c.namespace,
208+
Labels: c.makeCatalogSourcePodLabels(),
209+
},
210+
Spec: corev1.PodSpec{
211+
Containers: []corev1.Container{
212+
{
213+
Name: "catalog",
214+
Image: image,
215+
Command: []string{"opm", "serve", catalogMountPath},
216+
Ports: []corev1.ContainerPort{
217+
{
218+
Name: "grpc",
219+
ContainerPort: 50051,
220+
},
221+
},
222+
ReadinessProbe: &corev1.Probe{
223+
Handler: corev1.Handler{
224+
Exec: &corev1.ExecAction{
225+
Command: []string{"grpc_health_probe", "-addr=:50051"},
226+
},
227+
},
228+
InitialDelaySeconds: readinessDelay,
229+
TimeoutSeconds: 5,
230+
},
231+
LivenessProbe: &corev1.Probe{
232+
Handler: corev1.Handler{
233+
Exec: &corev1.ExecAction{
234+
Command: []string{"grpc_health_probe", "-addr=:50051"},
235+
},
236+
},
237+
InitialDelaySeconds: livenessDelay,
238+
TimeoutSeconds: 5,
239+
},
240+
Resources: corev1.ResourceRequirements{
241+
Requests: corev1.ResourceList{
242+
corev1.ResourceCPU: resource.MustParse("10m"),
243+
corev1.ResourceMemory: resource.MustParse("50Mi"),
244+
},
245+
},
246+
SecurityContext: &corev1.SecurityContext{
247+
ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
248+
},
249+
ImagePullPolicy: corev1.PullAlways,
250+
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
251+
VolumeMounts: []corev1.VolumeMount{
252+
{
253+
Name: volumeMountName,
254+
MountPath: catalogMountPath,
255+
ReadOnly: true,
256+
},
257+
},
258+
},
259+
},
260+
Volumes: []corev1.Volume{
261+
{
262+
Name: volumeMountName,
263+
VolumeSource: corev1.VolumeSource{
264+
ConfigMap: &corev1.ConfigMapVolumeSource{
265+
LocalObjectReference: corev1.LocalObjectReference{
266+
Name: c.configMapName,
267+
},
268+
},
269+
},
270+
},
271+
},
272+
},
273+
}
274+
}
275+
276+
func (c *magicCatalog) makeCatalogSourcePodLabels() map[string]string {
277+
return map[string]string{
278+
olmCatalogLabel: c.name,
279+
}
280+
}

0 commit comments

Comments
 (0)