-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathoperator.go
More file actions
140 lines (129 loc) · 4.52 KB
/
Copy pathoperator.go
File metadata and controls
140 lines (129 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package profile
import (
"fmt"
"time"
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/apiextensions"
metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/meta/v1"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
const (
catalogSourceRedHat = "redhat-operators"
catalogSourceCertified = "certified-operators"
)
// operatorInstall describes how to install an OLM operator on the cluster.
type operatorInstall struct {
// resourcePrefix is used for Pulumi resource naming (e.g. "main-virt-").
resourcePrefix string
// namespace where the Subscription (and optional OG) are created.
namespace string
// nsName is a dynamic namespace name for prerequisite gating via ApplyT.
// When nil, pulumi.String(namespace) is used.
nsName pulumi.StringInput
// ogName is the OperatorGroup name. When non-empty, a dedicated Namespace
// and OperatorGroup are created for this operator.
ogName string
// ogTargetNS are the OG targetNamespaces. nil means AllNamespaces mode.
ogTargetNS []string
// subName is the Subscription metadata.name.
subName string
// packageName is the operator package name in the catalog.
packageName string
// channel is the subscription channel (defaults to "stable").
channel string
// catalogSource is the OLM catalog source (e.g. "certified-operators").
// Defaults to "redhat-operators" when empty.
catalogSource string
// csvPrefix is the CSV name prefix used for prefix-matching during wait.
csvPrefix string
// csvNamespace overrides where to look for the CSV; empty uses namespace.
csvNamespace string
// extraDeps are additional Pulumi resources the Subscription depends on.
extraDeps []pulumi.Resource
}
// installOperator creates the namespace (optional), OperatorGroup (optional),
// Subscription, and waits for the CSV to succeed.
// Returns a StringOutput that resolves when the operator is fully installed.
func installOperator(ctx *pulumi.Context, args *DeployArgs, oi operatorInstall) (pulumi.StringOutput, error) {
goCtx := ctx.Context()
channel := oi.channel
if channel == "" {
channel = "stable"
}
catalogSource := oi.catalogSource
if catalogSource == "" {
catalogSource = catalogSourceRedHat
}
deps := append([]pulumi.Resource{}, args.Deps...)
deps = append(deps, oi.extraDeps...)
// If ogName is provided, create a dedicated namespace and OperatorGroup.
if oi.ogName != "" {
nsName := oi.nsName
if nsName == nil {
nsName = pulumi.String(oi.namespace)
}
ns, err := args.newNamespace(ctx, oi.resourcePrefix+"ns", nsName, pulumi.DependsOn(deps))
if err != nil {
return pulumi.StringOutput{}, err
}
ogSpec := map[string]interface{}{}
if oi.ogTargetNS != nil {
ogSpec["targetNamespaces"] = oi.ogTargetNS
}
og, err := apiextensions.NewCustomResource(ctx, oi.resourcePrefix+"og",
&apiextensions.CustomResourceArgs{
ApiVersion: pulumi.String("operators.coreos.com/v1"),
Kind: pulumi.String("OperatorGroup"),
Metadata: &metav1.ObjectMetaArgs{
Name: pulumi.String(oi.ogName),
Namespace: pulumi.String(oi.namespace),
},
OtherFields: map[string]interface{}{
"spec": ogSpec,
},
},
args.k8sOpts(pulumi.DependsOn([]pulumi.Resource{ns}))...)
if err != nil {
return pulumi.StringOutput{}, err
}
deps = []pulumi.Resource{og}
}
// Create Subscription
sub, err := apiextensions.NewCustomResource(ctx, oi.resourcePrefix+"sub",
&apiextensions.CustomResourceArgs{
ApiVersion: pulumi.String("operators.coreos.com/v1alpha1"),
Kind: pulumi.String("Subscription"),
Metadata: &metav1.ObjectMetaArgs{
Name: pulumi.String(oi.subName),
Namespace: pulumi.String(oi.namespace),
},
OtherFields: map[string]interface{}{
"spec": map[string]interface{}{
"source": catalogSource,
"sourceNamespace": "openshift-marketplace",
"name": oi.packageName,
"channel": channel,
"installPlanApproval": "Automatic",
},
},
},
args.k8sOpts(pulumi.DependsOn(deps))...)
if err != nil {
return pulumi.StringOutput{}, err
}
// Wait for CSV to succeed
csvNS := oi.csvNamespace
if csvNS == "" {
csvNS = oi.namespace
}
ready := pulumi.All(sub.ID(), args.Kubeconfig).ApplyT(
func(allArgs []interface{}) (string, error) {
kc := allArgs[1].(string)
if err := waitForCRCondition(goCtx, kc, csvGVR,
csvNS, oi.csvPrefix,
"phase", "", "Succeeded", 20*time.Minute, true); err != nil {
return "", fmt.Errorf("waiting for %s CSV: %w", oi.csvPrefix, err)
}
return "ready", nil
}).(pulumi.StringOutput)
return ready, nil
}