Skip to content

Commit 00e434d

Browse files
authored
feat(app): impl part of app controller (#322)
1 parent f105553 commit 00e434d

File tree

6 files changed

+172
-79
lines changed

6 files changed

+172
-79
lines changed

controllers/application/api/v1/application_types.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ limitations under the License.
1717
package v1
1818

1919
import (
20-
v1 "github.com/labring/laf/controllers/runtime/api/v1"
2120
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
runtimev1 "laf/controllers/runtime/api/v1"
2222
)
2323

2424
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
@@ -41,6 +41,12 @@ type ApplicationSpec struct {
4141
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
4242
// Important: Run "make" to regenerate code after modifying this file
4343

44+
// AppId
45+
//+kubebuilder:validation:MinLength=3
46+
//+kubebuilder:validation:MaxLength=24
47+
//+kubebuilder:validation:Required
48+
AppId string `json:"appid"`
49+
4450
// State of the application
4551
//+kubebuilder:validation:Enum=Running;Stopped;
4652
//+kubebuilder:validation:Required
@@ -61,20 +67,14 @@ type ApplicationStatus struct {
6167
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
6268
// Important: Run "make" to regenerate code after modifying this file
6369

64-
// AppId
65-
//+kubebuilder:validation:MinLength=3
66-
//+kubebuilder:validation:MaxLength=24
67-
//+kubebuilder:validation:Required
68-
AppId string `json:"appid"`
69-
70-
// State of the application
71-
Phase ApplicationState `json:"state,omitempty"`
72-
7370
// Bundle of the application
74-
Bundle BundleSpec `json:"bundle,omitempty"`
71+
Bundle Bundle `json:"bundle,omitempty"`
7572

7673
// Runtime of the application
77-
Runtime v1.RuntimeSpec `json:"runtime,omitempty"`
74+
Runtime runtimev1.Runtime `json:"runtime,omitempty"`
75+
76+
// State of the application
77+
Phase ApplicationState `json:"state,omitempty"`
7878

7979
// Conditions:
8080
// - type: DatabaseCreated

controllers/application/controllers/application_controller.go

+122-2
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ package controllers
1818

1919
import (
2020
"context"
21+
runtimev1 "laf/controllers/runtime/api/v1"
22+
"laf/pkg/common"
23+
"laf/pkg/util"
2124

2225
"k8s.io/apimachinery/pkg/runtime"
2326
ctrl "sigs.k8s.io/controller-runtime"
2427
"sigs.k8s.io/controller-runtime/pkg/client"
2528
"sigs.k8s.io/controller-runtime/pkg/log"
2629

27-
applicationv1 "github.com/labring/laf/controllers/application/api/v1"
30+
applicationv1 "laf/controllers/application/api/v1"
2831
)
2932

3033
const ApplicationFinalizer = "application.finalizers.laf.dev"
@@ -51,7 +54,124 @@ type ApplicationReconciler struct {
5154
func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
5255
_ = log.FromContext(ctx)
5356

54-
// TODO(user): your logic here
57+
// get the application
58+
application := &applicationv1.Application{}
59+
err := r.Get(ctx, req.NamespacedName, application)
60+
if err != nil {
61+
return ctrl.Result{}, client.IgnoreNotFound(err)
62+
}
63+
64+
// deal with the deletion
65+
if !application.ObjectMeta.DeletionTimestamp.IsZero() {
66+
return r.delete(ctx, application)
67+
}
68+
69+
return r.apply(ctx, application)
70+
}
71+
72+
// apply is called when the application is created or updated
73+
func (r *ApplicationReconciler) apply(ctx context.Context, application *applicationv1.Application) (ctrl.Result, error) {
74+
_log := log.FromContext(ctx)
75+
76+
// check if the finalizer is present
77+
if !util.ContainsString(application.ObjectMeta.Finalizers, ApplicationFinalizer) {
78+
application.ObjectMeta.Finalizers = append(application.ObjectMeta.Finalizers, ApplicationFinalizer)
79+
err := r.Update(ctx, application)
80+
if err != nil {
81+
return ctrl.Result{}, err
82+
}
83+
84+
_log.Info("finalizer added")
85+
}
86+
87+
// reconcile runtime
88+
if application.Status.Runtime.Name != application.Spec.RuntimeName {
89+
err := r.reconcileRuntime(ctx, application)
90+
if err != nil {
91+
return ctrl.Result{}, err
92+
}
93+
_log.Info("runtime reconciled")
94+
return ctrl.Result{}, nil
95+
}
96+
97+
// reconcile bundle
98+
if application.Status.Bundle.Name != application.Spec.BundleName {
99+
if err := r.reconcileBundle(ctx, application); err != nil {
100+
return ctrl.Result{}, err
101+
}
102+
_log.Info("bundle reconciled")
103+
return ctrl.Result{}, nil
104+
}
105+
106+
// reconcile phase of application
107+
if application.Status.Phase != application.Spec.State {
108+
if err := r.reconcilePhase(ctx, application); err != nil {
109+
return ctrl.Result{}, err
110+
}
111+
_log.Info("phase reconciled")
112+
return ctrl.Result{}, nil
113+
}
114+
115+
return ctrl.Result{}, nil
116+
}
117+
118+
// reconcilePhase reconciles the phase of the application
119+
func (r *ApplicationReconciler) reconcilePhase(ctx context.Context, application *applicationv1.Application) error {
120+
// TODO
121+
122+
return nil
123+
}
124+
125+
// reconcileRuntime reconciles the runtime of the application
126+
func (r *ApplicationReconciler) reconcileRuntime(ctx context.Context, application *applicationv1.Application) error {
127+
// get runtime by name
128+
rt := &runtimev1.Runtime{}
129+
err := r.Get(ctx, client.ObjectKey{
130+
Namespace: common.GetSystemNamespace(),
131+
Name: application.Spec.RuntimeName,
132+
}, rt)
133+
if err != nil {
134+
return err
135+
}
136+
137+
// update the status
138+
application.Status.Runtime = *rt
139+
err = r.Status().Update(ctx, application)
140+
return err
141+
}
142+
143+
// reconcileBundle reconciles the bundle of the application
144+
func (r *ApplicationReconciler) reconcileBundle(ctx context.Context, application *applicationv1.Application) error {
145+
// get bundle by name
146+
bundle := &applicationv1.Bundle{}
147+
err := r.Get(ctx, client.ObjectKey{
148+
Namespace: common.GetSystemNamespace(),
149+
Name: application.Spec.BundleName,
150+
}, bundle)
151+
if err != nil {
152+
return err
153+
}
154+
155+
// update the status
156+
application.Status.Bundle = *bundle
157+
err = r.Status().Update(ctx, application)
158+
return err
159+
}
160+
161+
// delete is called when the application is deleted
162+
func (r *ApplicationReconciler) delete(ctx context.Context, application *applicationv1.Application) (ctrl.Result, error) {
163+
164+
// TODO: delete the application
165+
if true {
166+
return ctrl.Result{}, nil
167+
}
168+
169+
// remove the finalizer
170+
application.ObjectMeta.Finalizers = util.RemoveString(application.ObjectMeta.Finalizers, ApplicationFinalizer)
171+
err := r.Update(ctx, application)
172+
if err != nil {
173+
return ctrl.Result{}, err
174+
}
55175

56176
return ctrl.Result{}, nil
57177
}

controllers/application/controllers/creationform_controller.go

+13-38
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@ package controllers
1919
import (
2020
"context"
2121
applicationv1 "github.com/labring/laf/controllers/application/api/v1"
22-
gonanoid "github.com/matoous/go-nanoid/v2"
2322
v1 "k8s.io/api/core/v1"
2423
"k8s.io/apimachinery/pkg/runtime"
24+
"laf/pkg/common"
2525
"laf/pkg/util"
26-
"os"
2726
ctrl "sigs.k8s.io/controller-runtime"
2827
"sigs.k8s.io/controller-runtime/pkg/client"
2928
"sigs.k8s.io/controller-runtime/pkg/log"
30-
"strconv"
3129
)
3230

3331
const creationFormFinalizer = "creationform.finalizers.laf.dev"
@@ -70,7 +68,7 @@ func (r *CreationFormReconciler) Reconcile(ctx context.Context, req ctrl.Request
7068

7169
// apply the form
7270
func (r *CreationFormReconciler) apply(ctx context.Context, form *applicationv1.CreationForm) (ctrl.Result, error) {
73-
log := log.FromContext(ctx)
71+
_log := log.FromContext(ctx)
7472

7573
// add finalizer if not present
7674
if !util.ContainsString(form.ObjectMeta.Finalizers, creationFormFinalizer) {
@@ -79,21 +77,22 @@ func (r *CreationFormReconciler) apply(ctx context.Context, form *applicationv1.
7977
return ctrl.Result{}, err
8078
}
8179

82-
log.Info("Added finalizer to form")
80+
_log.Info("Added finalizer to form")
81+
return ctrl.Result{}, nil
8382
}
8483

8584
// TODO: validate the form spec: bundle, runtime
8685

8786
// reconcile the namespace
8887
if form.Status.Namespace == "" {
89-
appid, err := GenerateAppId()
88+
appid, err := common.GenerateAppId()
9089
if err != nil {
9190
return ctrl.Result{}, err
9291
}
9392

9493
// create the namespace
9594
var namespace v1.Namespace
96-
namespace.Name = GetAppNamespacePrefix() + appid
95+
namespace.Name = common.GetApplicationNamespace(appid)
9796
namespace.Labels = map[string]string{
9897
"laf.dev/appid": appid,
9998
"laf.dev/namespace.type": "app",
@@ -103,7 +102,7 @@ func (r *CreationFormReconciler) apply(ctx context.Context, form *applicationv1.
103102
return ctrl.Result{}, err
104103
}
105104

106-
log.Info("Created namespace for app")
105+
_log.Info("Created namespace for app")
107106

108107
form.Status.AppId = appid
109108
form.Status.Namespace = namespace.Name
@@ -112,7 +111,7 @@ func (r *CreationFormReconciler) apply(ctx context.Context, form *applicationv1.
112111
return ctrl.Result{}, err
113112
}
114113

115-
log.Info("Updated form status: fill the namespace")
114+
_log.Info("Updated form status: fill the namespace")
116115
return ctrl.Result{}, nil
117116
}
118117

@@ -128,6 +127,8 @@ func (r *CreationFormReconciler) apply(ctx context.Context, form *applicationv1.
128127
app.Annotations = map[string]string{
129128
"laf.dev/name": form.Spec.DisplayName,
130129
}
130+
131+
app.Spec.AppId = form.Status.AppId
131132
app.Spec.State = applicationv1.ApplicationStateRunning
132133
app.Spec.BundleName = form.Spec.BundleName
133134
app.Spec.RuntimeName = form.Spec.RuntimeName
@@ -136,21 +137,21 @@ func (r *CreationFormReconciler) apply(ctx context.Context, form *applicationv1.
136137
return ctrl.Result{}, err
137138
}
138139

139-
log.Info("Created app")
140+
_log.Info("Created app")
140141

141142
form.Status.Created = true
142143
if err := r.Status().Update(ctx, form); err != nil {
143144
return ctrl.Result{}, err
144145
}
145146

146-
log.Info("Updated form status")
147+
_log.Info("Updated form status")
147148
} else {
148149
// delete the form
149150
if err := r.Delete(ctx, form); err != nil {
150151
return ctrl.Result{}, err
151152
}
152153

153-
log.Info("Deleted form")
154+
_log.Info("Deleted form")
154155
}
155156

156157
return ctrl.Result{}, nil
@@ -176,29 +177,3 @@ func (r *CreationFormReconciler) SetupWithManager(mgr ctrl.Manager) error {
176177
For(&applicationv1.CreationForm{}).
177178
Complete(r)
178179
}
179-
180-
// GetAppNamespacePrefix returns the app namespace prefix
181-
func GetAppNamespacePrefix() string {
182-
prefix := ""
183-
if prefixStr := os.Getenv("APP_NAMESPACE_PREFIX"); prefixStr != "" {
184-
prefix = prefixStr
185-
}
186-
return prefix
187-
}
188-
189-
// GenerateAppId generates app id
190-
func GenerateAppId() (string, error) {
191-
const alphabet = "23456789abcdefghijklmnopqrstuvwxyz"
192-
size := 6
193-
194-
// get size from env
195-
if sizeStr := os.Getenv("APPID_LENGTH"); sizeStr != "" {
196-
int64, err := strconv.ParseInt(sizeStr, 10, 64)
197-
if err == nil {
198-
size = int(int64)
199-
}
200-
}
201-
202-
appid, err := gonanoid.Generate(alphabet, size)
203-
return appid, err
204-
}

0 commit comments

Comments
 (0)