Implement finalizer
This commit is contained in:
		
							parent
							
								
									497ddba82d
								
							
						
					
					
						commit
						a436216d5e
					
				|  | @ -38,9 +38,17 @@ import ( | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	containerName = "runner" | 	containerName = "runner" | ||||||
|  | 	finalizerName = "runner.actions.summerwind.dev" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type RegistrationToken struct { | type GitHubRunner struct { | ||||||
|  | 	ID     int    `json:"id"` | ||||||
|  | 	Name   string `json:"name"` | ||||||
|  | 	OS     string `json:"os"` | ||||||
|  | 	Status string `json:"status"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type GitHubRegistrationToken struct { | ||||||
| 	Token     string `json:"token"` | 	Token     string `json:"token"` | ||||||
| 	ExpiresAt string `json:"expires_at"` | 	ExpiresAt string `json:"expires_at"` | ||||||
| } | } | ||||||
|  | @ -69,6 +77,48 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { | ||||||
| 		return ctrl.Result{}, client.IgnoreNotFound(err) | 		return ctrl.Result{}, client.IgnoreNotFound(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if runner.ObjectMeta.DeletionTimestamp.IsZero() { | ||||||
|  | 		finalizers, added := addFinalizer(runner.ObjectMeta.Finalizers) | ||||||
|  | 
 | ||||||
|  | 		if added { | ||||||
|  | 			newRunner := runner.DeepCopy() | ||||||
|  | 			newRunner.ObjectMeta.Finalizers = finalizers | ||||||
|  | 
 | ||||||
|  | 			if err := r.Update(ctx, newRunner); err != nil { | ||||||
|  | 				log.Error(err, "Failed to update runner") | ||||||
|  | 				return ctrl.Result{}, err | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return ctrl.Result{}, nil | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		finalizers, removed := removeFinalizer(runner.ObjectMeta.Finalizers) | ||||||
|  | 
 | ||||||
|  | 		if removed { | ||||||
|  | 			ok, err := r.unregisterRunner(ctx, runner.Spec.Repository, runner.Name) | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Error(err, "Failed to unregister runner") | ||||||
|  | 				return ctrl.Result{}, err | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if !ok { | ||||||
|  | 				log.V(1).Info("Runner no longer exists on GitHub") | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			newRunner := runner.DeepCopy() | ||||||
|  | 			newRunner.ObjectMeta.Finalizers = finalizers | ||||||
|  | 
 | ||||||
|  | 			if err := r.Update(ctx, newRunner); err != nil { | ||||||
|  | 				log.Error(err, "Failed to update runner") | ||||||
|  | 				return ctrl.Result{}, err | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			log.Info("Removed runner from GitHub", "repository", runner.Spec.Repository) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return ctrl.Result{}, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if !runner.IsRegisterable() { | 	if !runner.IsRegisterable() { | ||||||
| 		reg, err := r.newRegistration(ctx, runner.Spec.Repository) | 		reg, err := r.newRegistration(ctx, runner.Spec.Repository) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | @ -190,8 +240,8 @@ func (r *RunnerReconciler) newRegistration(ctx context.Context, repo string) (v1 | ||||||
| 	return reg, err | 	return reg, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (r *RunnerReconciler) getRegistrationToken(ctx context.Context, repo string) (RegistrationToken, error) { | func (r *RunnerReconciler) getRegistrationToken(ctx context.Context, repo string) (GitHubRegistrationToken, error) { | ||||||
| 	var regToken RegistrationToken | 	var regToken GitHubRegistrationToken | ||||||
| 
 | 
 | ||||||
| 	req, err := r.GitHubClient.NewRequest("POST", fmt.Sprintf("/repos/%s/actions/runners/registration-token", repo), nil) | 	req, err := r.GitHubClient.NewRequest("POST", fmt.Sprintf("/repos/%s/actions/runners/registration-token", repo), nil) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -210,6 +260,69 @@ func (r *RunnerReconciler) getRegistrationToken(ctx context.Context, repo string | ||||||
| 	return regToken, nil | 	return regToken, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (r *RunnerReconciler) unregisterRunner(ctx context.Context, repo, name string) (bool, error) { | ||||||
|  | 	runners, err := r.listRunners(ctx, repo) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	id := 0 | ||||||
|  | 	for _, runner := range runners { | ||||||
|  | 		if runner.Name == name { | ||||||
|  | 			id = runner.ID | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if id == 0 { | ||||||
|  | 		return false, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := r.removeRunner(ctx, repo, id); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *RunnerReconciler) listRunners(ctx context.Context, repo string) ([]GitHubRunner, error) { | ||||||
|  | 	runners := []GitHubRunner{} | ||||||
|  | 
 | ||||||
|  | 	req, err := r.GitHubClient.NewRequest("GET", fmt.Sprintf("/repos/%s/actions/runners", repo), nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return runners, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	res, err := r.GitHubClient.Do(ctx, req, &runners) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return runners, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if res.StatusCode != 200 { | ||||||
|  | 		return runners, fmt.Errorf("unexpected status: %d", res.StatusCode) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return runners, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *RunnerReconciler) removeRunner(ctx context.Context, repo string, id int) error { | ||||||
|  | 	req, err := r.GitHubClient.NewRequest("DELETE", fmt.Sprintf("/repos/%s/actions/runners/%d", repo, id), nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	res, err := r.GitHubClient.Do(ctx, req, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if res.StatusCode != 204 { | ||||||
|  | 		return fmt.Errorf("unexpected status: %d", res.StatusCode) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) { | func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) { | ||||||
| 	var ( | 	var ( | ||||||
| 		privileged bool  = true | 		privileged bool  = true | ||||||
|  | @ -297,3 +410,33 @@ func (r *RunnerReconciler) SetupWithManager(mgr ctrl.Manager) error { | ||||||
| 		Owns(&corev1.Pod{}). | 		Owns(&corev1.Pod{}). | ||||||
| 		Complete(r) | 		Complete(r) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func addFinalizer(finalizers []string) ([]string, bool) { | ||||||
|  | 	exists := false | ||||||
|  | 	for _, name := range finalizers { | ||||||
|  | 		if name == finalizerName { | ||||||
|  | 			exists = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if exists { | ||||||
|  | 		return finalizers, false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return append(finalizers, finalizerName), true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func removeFinalizer(finalizers []string) ([]string, bool) { | ||||||
|  | 	removed := false | ||||||
|  | 	result := []string{} | ||||||
|  | 
 | ||||||
|  | 	for _, name := range finalizers { | ||||||
|  | 		if name == finalizerName { | ||||||
|  | 			removed = true | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		result = append(result, name) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return result, removed | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue