@@ -24,6 +24,7 @@ type OperatorInstall struct {
2424
2525 Package string
2626 Channel string
27+ StartingCSV string
2728 Approval subscription.ApprovalValue
2829 InstallMode operator.InstallMode
2930 InstallTimeout time.Duration
@@ -40,6 +41,7 @@ func NewOperatorInstall(cfg *Configuration) *OperatorInstall {
4041func (i * OperatorInstall ) BindFlags (fs * pflag.FlagSet ) {
4142 fs .StringVarP (& i .Channel , "channel" , "c" , "" , "subscription channel" )
4243 fs .VarP (& i .Approval , "approval" , "a" , fmt .Sprintf ("approval (%s or %s)" , v1alpha1 .ApprovalManual , v1alpha1 .ApprovalAutomatic ))
44+ fs .StringVarP (& i .StartingCSV , "starting-csv" , "s" , "" , "install specific csv for operator" )
4345 fs .VarP (& i .InstallMode , "install-mode" , "i" , "install mode" )
4446 fs .DurationVarP (& i .InstallTimeout , "timeout" , "t" , time .Minute , "the amount of time to wait before cancelling the install" )
4547 fs .DurationVar (& i .CleanupTimeout , "cleanup-timeout" , time .Minute , "the amount to time to wait before cancelling cleanup" )
@@ -82,69 +84,26 @@ func (i *OperatorInstall) Run(ctx context.Context) (*v1alpha1.ClusterServiceVers
8284 return nil , err
8385 }
8486
85- opts := []subscription.Option {}
86- opts = append (opts , subscription .InstallPlanApproval (i .Approval .Approval ))
87-
88- subKey := types.NamespacedName {
89- Namespace : i .config .Namespace ,
90- Name : i .Package ,
91- }
92- sourceKey := types.NamespacedName {
93- Namespace : pm .Status .CatalogSourceNamespace ,
94- Name : pm .Status .CatalogSource ,
95- }
96- sub := subscription .Build (subKey , i .Channel , sourceKey , opts ... )
97- if err := i .config .Client .Create (ctx , sub ); err != nil {
98- return nil , fmt .Errorf ("create subscription: %v" , err )
87+ sub , err := i .createSubscription (ctx , pm )
88+ if err != nil {
89+ return nil , err
9990 }
10091 log .Printf ("subscription %q created" , sub .Name )
10192
102- // We need to approve the initial install plan
103- if i .Approval .Approval == v1alpha1 .ApprovalManual {
104- if err := wait .PollImmediateUntil (time .Millisecond * 250 , func () (bool , error ) {
105- if err := i .config .Client .Get (ctx , subKey , sub ); err != nil {
106- return false , err
107- }
108- if sub .Status .InstallPlanRef != nil {
109- return true , nil
110- }
111- return false , nil
112- }, ctx .Done ()); err != nil {
113- return nil , fmt .Errorf ("waiting for subscription install plan to exist: %v" , err )
114- }
115-
116- ip := v1alpha1.InstallPlan {}
117- ipKey := types.NamespacedName {
118- Namespace : sub .Status .InstallPlanRef .Namespace ,
119- Name : sub .Status .InstallPlanRef .Name ,
120- }
121- if err := i .config .Client .Get (ctx , ipKey , & ip ); err != nil {
122- return nil , fmt .Errorf ("get install plan: %v" , err )
123- }
124- ip .Spec .Approved = true
125- if err := i .config .Client .Update (ctx , & ip ); err != nil {
126- return nil , fmt .Errorf ("approve install plan: %v" , err )
127- }
93+ ip , err := i .getInstallPlan (ctx , sub )
94+ if err != nil {
95+ return nil , err
12896 }
12997
130- if err := wait .PollImmediateUntil (time .Millisecond * 250 , func () (bool , error ) {
131- if err := i .config .Client .Get (ctx , subKey , sub ); err != nil {
132- return false , err
133- }
134- if sub .Status .State == v1alpha1 .SubscriptionStateAtLatest {
135- return true , nil
98+ // We need to approve the initial install plan
99+ if i .Approval .Approval == v1alpha1 .ApprovalManual {
100+ if err := i .approveInstallPlan (ctx , ip ); err != nil {
101+ return nil , err
136102 }
137- return false , nil
138- }, ctx .Done ()); err != nil {
139- return nil , fmt .Errorf ("waiting for subscription state \" AtLatestKnown\" : %v" , err )
140103 }
141104
142- csvKey := types.NamespacedName {
143- Namespace : i .config .Namespace ,
144- Name : sub .Status .InstalledCSV ,
145- }
146- csv := & v1alpha1.ClusterServiceVersion {}
147- if err := i .config .Client .Get (ctx , csvKey , csv ); err != nil {
105+ csv , err := i .getCSV (ctx , ip )
106+ if err != nil {
148107 return nil , fmt .Errorf ("get clusterserviceversion: %v" , err )
149108 }
150109 return csv , nil
@@ -249,6 +208,101 @@ func (i *OperatorInstall) getPackageChannel(pm *operatorsv1.PackageManifest) (*o
249208 return packageChannel , nil
250209}
251210
211+ func (i * OperatorInstall ) createSubscription (ctx context.Context , pm * operatorsv1.PackageManifest ) (* v1alpha1.Subscription , error ) {
212+ opts := []subscription.Option {
213+ subscription .InstallPlanApproval (i .Approval .Approval ),
214+ }
215+ if i .StartingCSV != "" {
216+ opts = append (opts , subscription .StartingCSV (i .StartingCSV ))
217+ }
218+
219+ subKey := types.NamespacedName {
220+ Namespace : i .config .Namespace ,
221+ Name : i .Package ,
222+ }
223+ sourceKey := types.NamespacedName {
224+ Namespace : pm .Status .CatalogSourceNamespace ,
225+ Name : pm .Status .CatalogSource ,
226+ }
227+ sub := subscription .Build (subKey , i .Channel , sourceKey , opts ... )
228+ if err := i .config .Client .Create (ctx , sub ); err != nil {
229+ return nil , fmt .Errorf ("create subscription: %v" , err )
230+
231+ }
232+ return sub , nil
233+ }
234+
235+ func (i * OperatorInstall ) getInstallPlan (ctx context.Context , sub * v1alpha1.Subscription ) (* v1alpha1.InstallPlan , error ) {
236+ subKey := types.NamespacedName {
237+ Namespace : sub .GetNamespace (),
238+ Name : sub .GetName (),
239+ }
240+ if err := wait .PollImmediateUntil (time .Millisecond * 250 , func () (bool , error ) {
241+ if err := i .config .Client .Get (ctx , subKey , sub ); err != nil {
242+ return false , err
243+ }
244+ if sub .Status .InstallPlanRef != nil {
245+ return true , nil
246+ }
247+ return false , nil
248+ }, ctx .Done ()); err != nil {
249+ return nil , fmt .Errorf ("waiting for install plan to exist: %v" , err )
250+ }
251+
252+ ip := v1alpha1.InstallPlan {}
253+ ipKey := types.NamespacedName {
254+ Namespace : sub .Status .InstallPlanRef .Namespace ,
255+ Name : sub .Status .InstallPlanRef .Name ,
256+ }
257+ if err := i .config .Client .Get (ctx , ipKey , & ip ); err != nil {
258+ return nil , fmt .Errorf ("get install plan: %v" , err )
259+ }
260+ return & ip , nil
261+ }
262+
263+ func (i * OperatorInstall ) approveInstallPlan (ctx context.Context , ip * v1alpha1.InstallPlan ) error {
264+ ip .Spec .Approved = true
265+ if err := i .config .Client .Update (ctx , ip ); err != nil {
266+ return fmt .Errorf ("approve install plan: %v" , err )
267+ }
268+ return nil
269+ }
270+
271+ func (i * OperatorInstall ) getCSV (ctx context.Context , ip * v1alpha1.InstallPlan ) (* v1alpha1.ClusterServiceVersion , error ) {
272+ ipKey := types.NamespacedName {
273+ Namespace : ip .GetNamespace (),
274+ Name : ip .GetName (),
275+ }
276+ if err := wait .PollImmediateUntil (time .Millisecond * 250 , func () (bool , error ) {
277+ if err := i .config .Client .Get (ctx , ipKey , ip ); err != nil {
278+ return false , err
279+ }
280+ if ip .Status .Phase == v1alpha1 .InstallPlanPhaseComplete {
281+ return true , nil
282+ }
283+ return false , nil
284+ }, ctx .Done ()); err != nil {
285+ return nil , fmt .Errorf ("waiting for operator installation to complete: %v" , err )
286+ }
287+
288+ csvKey := types.NamespacedName {
289+ Namespace : i .config .Namespace ,
290+ }
291+ for _ , s := range ip .Status .Plan {
292+ if s .Resource .Kind == "ClusterServiceVersion" {
293+ csvKey .Name = s .Resource .Name
294+ }
295+ }
296+ if csvKey .Name == "" {
297+ return nil , fmt .Errorf ("could not find installed CSV in install plan" )
298+ }
299+ csv := & v1alpha1.ClusterServiceVersion {}
300+ if err := i .config .Client .Get (ctx , csvKey , csv ); err != nil {
301+ return nil , fmt .Errorf ("get clusterserviceversion: %v" , err )
302+ }
303+ return csv , nil
304+ }
305+
252306func (i * OperatorInstall ) cleanup (ctx context.Context , sub * v1alpha1.Subscription ) {
253307 if err := i .config .Client .Delete (ctx , sub ); err != nil {
254308 log .Printf ("delete subscription %q: %v" , sub .Name , err )
0 commit comments