CNFStatus CRD Controller 52/4052/1
authorHuifeng Le <huifeng.le@intel.com>
Thu, 14 Jan 2021 07:24:15 +0000 (15:24 +0800)
committerHuifeng Le <huifeng.le@intel.com>
Thu, 14 Jan 2021 07:30:15 +0000 (15:30 +0800)
Add CNFStatus CRD controller to query CNF status periodically

Signed-off-by: Huifeng Le <huifeng.le@intel.com>
Change-Id: I86a7fca4fd9248a22cadda30babde4346ea29bd8

Signed-off-by: Huifeng Le <huifeng.le@intel.com>
Change-Id: Ie5ed1f5d5ad87c367ad0a3342105515a44725558
Signed-off-by: Huifeng Le <huifeng.le@intel.com>
14 files changed:
platform/crd-ctrlr/examples/sdewan-controller.yaml
platform/crd-ctrlr/src/PROJECT
platform/crd-ctrlr/src/api/v1alpha1/cnfstatus_types.go [new file with mode: 0644]
platform/crd-ctrlr/src/api/v1alpha1/zz_generated.deepcopy.go
platform/crd-ctrlr/src/config/crd/bases/batch.sdewan.akraino.org_cnfstatuses.yaml [new file with mode: 0644]
platform/crd-ctrlr/src/config/crd/kustomization.yaml
platform/crd-ctrlr/src/config/crd/patches/cainjection_in_cnfstatuses.yaml [new file with mode: 0644]
platform/crd-ctrlr/src/config/crd/patches/webhook_in_cnfstatuses.yaml [new file with mode: 0644]
platform/crd-ctrlr/src/config/rbac/cnfstatus_editor_role.yaml [new file with mode: 0644]
platform/crd-ctrlr/src/config/rbac/cnfstatus_viewer_role.yaml [new file with mode: 0644]
platform/crd-ctrlr/src/config/samples/batch_v1alpha1_cnfstatus.yaml [new file with mode: 0644]
platform/crd-ctrlr/src/controllers/cnfstatus_controller.go [new file with mode: 0644]
platform/crd-ctrlr/src/main.go
platform/crd-ctrlr/src/openwrt/status.go [new file with mode: 0644]

index 174e1b4..48edbb1 100644 (file)
@@ -75,6 +75,82 @@ status:
 ---
 apiVersion: apiextensions.k8s.io/v1beta1
 kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.2.5
+  creationTimestamp: null
+  name: cnfstatuses.batch.sdewan.akraino.org
+spec:
+  group: batch.sdewan.akraino.org
+  names:
+    kind: CNFStatus
+    listKind: CNFStatusList
+    plural: cnfstatuses
+    singular: cnfstatus
+  scope: Namespaced
+  subresources:
+    status: {}
+  validation:
+    openAPIV3Schema:
+      description: CNFStatus is the Schema for the cnfstatuses API
+      properties:
+        apiVersion:
+          description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+          type: string
+        kind:
+          description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+          type: string
+        metadata:
+          type: object
+        spec:
+          description: CNFStatusSpec defines the desired state of CNFStatus
+          type: object
+        status:
+          description: CNFStatusStatus defines the observed state of CNFStatus
+          properties:
+            appliedGeneration:
+              description: 'INSERT ADDITIONAL STATUS FIELD - define observed state of cluster Important: Run "make" to regenerate code after modifying this file'
+              format: int64
+              type: integer
+            appliedTime:
+              format: date-time
+              type: string
+            information:
+              items:
+                description: CNFStatusInformation defines the runtime information of a CMF
+                properties:
+                  ip:
+                    type: string
+                  name:
+                    type: string
+                  namespace:
+                    type: string
+                  node:
+                    type: string
+                  purpose:
+                    type: string
+                  status:
+                    type: string
+                required:
+                - name
+                type: object
+              type: array
+          type: object
+      type: object
+  version: v1alpha1
+  versions:
+  - name: v1alpha1
+    served: true
+    storage: true
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
 metadata:
   annotations:
     controller-gen.kubebuilder.io/version: v0.2.5
index 7c4a411..26c2994 100644 (file)
@@ -37,4 +37,7 @@ resources:
 - group: batch
   kind: SdewanApplication
   version: v1alpha1
+- group: batch
+  kind: CNFStatus
+  version: v1alpha1
 version: "2"
diff --git a/platform/crd-ctrlr/src/api/v1alpha1/cnfstatus_types.go b/platform/crd-ctrlr/src/api/v1alpha1/cnfstatus_types.go
new file mode 100644 (file)
index 0000000..927b527
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
+// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
+
+// CNFStatusSpec defines the desired state of CNFStatus
+type CNFStatusSpec struct {
+       // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+       // Important: Run "make" to regenerate code after modifying this file
+}
+
+// CNFStatusInformation defines the runtime information of a CMF
+type CNFStatusInformation struct {
+       Name      string `json:"name"`
+       NameSpace string `json:"namespace,omitempty"`
+       Node      string `json:"node,omitempty"`
+       Purpose   string `json:"purpose,omitempty"`
+       IP        string `json:"ip,omitempty"`
+       Status    string `json:"status,omitempty"`
+}
+
+// CNFStatusStatus defines the observed state of CNFStatus
+type CNFStatusStatus struct {
+       // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+       // Important: Run "make" to regenerate code after modifying this file
+       // +optional
+       AppliedGeneration int64 `json:"appliedGeneration,omitempty"`
+       // +optional
+       AppliedTime *metav1.Time `json:"appliedTime,omitempty"`
+       // +optional
+       Information []CNFStatusInformation `json:"information,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:subresource:status
+
+// CNFStatus is the Schema for the cnfstatuses API
+type CNFStatus struct {
+       metav1.TypeMeta   `json:",inline"`
+       metav1.ObjectMeta `json:"metadata,omitempty"`
+
+       Spec   CNFStatusSpec   `json:"spec,omitempty"`
+       Status CNFStatusStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// CNFStatusList contains a list of CNFStatus
+type CNFStatusList struct {
+       metav1.TypeMeta `json:",inline"`
+       metav1.ListMeta `json:"metadata,omitempty"`
+       Items           []CNFStatus `json:"items"`
+}
+
+func init() {
+       SchemeBuilder.Register(&CNFStatus{}, &CNFStatusList{})
+}
index ed719e7..9a21a7a 100644 (file)
@@ -142,6 +142,119 @@ func (in *CNFServiceSpec) DeepCopy() *CNFServiceSpec {
        return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CNFStatus) DeepCopyInto(out *CNFStatus) {
+       *out = *in
+       out.TypeMeta = in.TypeMeta
+       in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+       out.Spec = in.Spec
+       in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatus.
+func (in *CNFStatus) DeepCopy() *CNFStatus {
+       if in == nil {
+               return nil
+       }
+       out := new(CNFStatus)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *CNFStatus) DeepCopyObject() runtime.Object {
+       if c := in.DeepCopy(); c != nil {
+               return c
+       }
+       return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CNFStatusInformation) DeepCopyInto(out *CNFStatusInformation) {
+       *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatusInformation.
+func (in *CNFStatusInformation) DeepCopy() *CNFStatusInformation {
+       if in == nil {
+               return nil
+       }
+       out := new(CNFStatusInformation)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CNFStatusList) DeepCopyInto(out *CNFStatusList) {
+       *out = *in
+       out.TypeMeta = in.TypeMeta
+       in.ListMeta.DeepCopyInto(&out.ListMeta)
+       if in.Items != nil {
+               in, out := &in.Items, &out.Items
+               *out = make([]CNFStatus, len(*in))
+               for i := range *in {
+                       (*in)[i].DeepCopyInto(&(*out)[i])
+               }
+       }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatusList.
+func (in *CNFStatusList) DeepCopy() *CNFStatusList {
+       if in == nil {
+               return nil
+       }
+       out := new(CNFStatusList)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *CNFStatusList) DeepCopyObject() runtime.Object {
+       if c := in.DeepCopy(); c != nil {
+               return c
+       }
+       return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CNFStatusSpec) DeepCopyInto(out *CNFStatusSpec) {
+       *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatusSpec.
+func (in *CNFStatusSpec) DeepCopy() *CNFStatusSpec {
+       if in == nil {
+               return nil
+       }
+       out := new(CNFStatusSpec)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *CNFStatusStatus) DeepCopyInto(out *CNFStatusStatus) {
+       *out = *in
+       if in.AppliedTime != nil {
+               in, out := &in.AppliedTime, &out.AppliedTime
+               *out = (*in).DeepCopy()
+       }
+       if in.Information != nil {
+               in, out := &in.Information, &out.Information
+               *out = make([]CNFStatusInformation, len(*in))
+               copy(*out, *in)
+       }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNFStatusStatus.
+func (in *CNFStatusStatus) DeepCopy() *CNFStatusStatus {
+       if in == nil {
+               return nil
+       }
+       out := new(CNFStatusStatus)
+       in.DeepCopyInto(out)
+       return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Connection) DeepCopyInto(out *Connection) {
        *out = *in
diff --git a/platform/crd-ctrlr/src/config/crd/bases/batch.sdewan.akraino.org_cnfstatuses.yaml b/platform/crd-ctrlr/src/config/crd/bases/batch.sdewan.akraino.org_cnfstatuses.yaml
new file mode 100644 (file)
index 0000000..2a24a62
--- /dev/null
@@ -0,0 +1,84 @@
+
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.2.5
+  creationTimestamp: null
+  name: cnfstatuses.batch.sdewan.akraino.org
+spec:
+  group: batch.sdewan.akraino.org
+  names:
+    kind: CNFStatus
+    listKind: CNFStatusList
+    plural: cnfstatuses
+    singular: cnfstatus
+  scope: Namespaced
+  subresources:
+    status: {}
+  validation:
+    openAPIV3Schema:
+      description: CNFStatus is the Schema for the cnfstatuses API
+      properties:
+        apiVersion:
+          description: 'APIVersion defines the versioned schema of this representation
+            of an object. Servers should convert recognized schemas to the latest
+            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+          type: string
+        kind:
+          description: 'Kind is a string value representing the REST resource this
+            object represents. Servers may infer this from the endpoint the client
+            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+          type: string
+        metadata:
+          type: object
+        spec:
+          description: CNFStatusSpec defines the desired state of CNFStatus
+          type: object
+        status:
+          description: CNFStatusStatus defines the observed state of CNFStatus
+          properties:
+            appliedGeneration:
+              description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
+                of cluster Important: Run "make" to regenerate code after modifying
+                this file'
+              format: int64
+              type: integer
+            appliedTime:
+              format: date-time
+              type: string
+            information:
+              items:
+                description: CNFStatusInformation defines the runtime information
+                  of a CMF
+                properties:
+                  ip:
+                    type: string
+                  name:
+                    type: string
+                  namespace:
+                    type: string
+                  node:
+                    type: string
+                  purpose:
+                    type: string
+                  status:
+                    type: string
+                required:
+                - name
+                type: object
+              type: array
+          type: object
+      type: object
+  version: v1alpha1
+  versions:
+  - name: v1alpha1
+    served: true
+    storage: true
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
index 279ef89..54a6b47 100644 (file)
@@ -14,6 +14,7 @@ resources:
 - bases/batch.sdewan.akraino.org_ipsecsites.yaml
 - bases/batch.sdewan.akraino.org_cnfservices.yaml
 - bases/batch.sdewan.akraino.org_sdewanapplications.yaml
+- bases/batch.sdewan.akraino.org_cnfstatuses.yaml
 # +kubebuilder:scaffold:crdkustomizeresource
 
 patchesStrategicMerge:
@@ -31,6 +32,7 @@ patchesStrategicMerge:
 #- patches/webhook_in_ipsecsites.yaml
 #- patches/webhook_in_cnfservices.yaml
 #- patches/webhook_in_sdewanapplications.yaml
+#- patches/webhook_in_cnfstatuses.yaml
 # +kubebuilder:scaffold:crdkustomizewebhookpatch
 
 # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
@@ -47,6 +49,7 @@ patchesStrategicMerge:
 #- patches/cainjection_in_ipsecsites.yaml
 #- patches/cainjection_in_cnfservices.yaml
 #- patches/cainjection_in_sdewanapplications.yaml
+#- patches/cainjection_in_cnfstatuses.yaml
 # +kubebuilder:scaffold:crdkustomizecainjectionpatch
 
 # the following config is for teaching kustomize how to do kustomization for CRDs.
diff --git a/platform/crd-ctrlr/src/config/crd/patches/cainjection_in_cnfstatuses.yaml b/platform/crd-ctrlr/src/config/crd/patches/cainjection_in_cnfstatuses.yaml
new file mode 100644 (file)
index 0000000..5a10441
--- /dev/null
@@ -0,0 +1,8 @@
+# The following patch adds a directive for certmanager to inject CA into the CRD
+# CRD conversion requires k8s 1.13 or later.
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
+  name: cnfstatuses.batch.sdewan.akraino.org
diff --git a/platform/crd-ctrlr/src/config/crd/patches/webhook_in_cnfstatuses.yaml b/platform/crd-ctrlr/src/config/crd/patches/webhook_in_cnfstatuses.yaml
new file mode 100644 (file)
index 0000000..ba8d604
--- /dev/null
@@ -0,0 +1,17 @@
+# The following patch enables conversion webhook for CRD
+# CRD conversion requires k8s 1.13 or later.
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: cnfstatuses.batch.sdewan.akraino.org
+spec:
+  conversion:
+    strategy: Webhook
+    webhookClientConfig:
+      # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
+      # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
+      caBundle: Cg==
+      service:
+        namespace: system
+        name: webhook-service
+        path: /convert
diff --git a/platform/crd-ctrlr/src/config/rbac/cnfstatus_editor_role.yaml b/platform/crd-ctrlr/src/config/rbac/cnfstatus_editor_role.yaml
new file mode 100644 (file)
index 0000000..2449136
--- /dev/null
@@ -0,0 +1,24 @@
+# permissions for end users to edit cnfstatuses.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: cnfstatus-editor-role
+rules:
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - cnfstatuses
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - cnfstatuses/status
+  verbs:
+  - get
diff --git a/platform/crd-ctrlr/src/config/rbac/cnfstatus_viewer_role.yaml b/platform/crd-ctrlr/src/config/rbac/cnfstatus_viewer_role.yaml
new file mode 100644 (file)
index 0000000..5d1b5b6
--- /dev/null
@@ -0,0 +1,20 @@
+# permissions for end users to view cnfstatuses.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: cnfstatus-viewer-role
+rules:
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - cnfstatuses
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - batch.sdewan.akraino.org
+  resources:
+  - cnfstatuses/status
+  verbs:
+  - get
diff --git a/platform/crd-ctrlr/src/config/samples/batch_v1alpha1_cnfstatus.yaml b/platform/crd-ctrlr/src/config/samples/batch_v1alpha1_cnfstatus.yaml
new file mode 100644 (file)
index 0000000..3c93896
--- /dev/null
@@ -0,0 +1,6 @@
+apiVersion: batch.sdewan.akraino.org/v1alpha1
+kind: CNFStatus
+metadata:
+  name: cnfstatus-sample
+spec:
+  # Add fields here
diff --git a/platform/crd-ctrlr/src/controllers/cnfstatus_controller.go b/platform/crd-ctrlr/src/controllers/cnfstatus_controller.go
new file mode 100644 (file)
index 0000000..eb20943
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controllers
+
+import (
+       "context"
+       "encoding/json"
+       "github.com/go-logr/logr"
+       "time"
+
+       corev1 "k8s.io/api/core/v1"
+       errs "k8s.io/apimachinery/pkg/api/errors"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/util/wait"
+       batchv1alpha1 "sdewan.akraino.org/sdewan/api/v1alpha1"
+       "sdewan.akraino.org/sdewan/openwrt"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       "sync"
+)
+
+var cnfCRNameSpace = "sdewan-system"
+var cnfCRName = "cnf-status"
+var inQueryStatus = false
+
+// SdewanCNFStatusController: query CNF status periodically
+type SdewanCNFStatusController struct {
+       client.Client
+       Log           logr.Logger
+       CheckInterval time.Duration
+       mux           sync.Mutex
+}
+
+func (r *SdewanCNFStatusController) SetupWithManager() error {
+       go wait.Until(r.SafeQuery, r.CheckInterval, wait.NeverStop)
+
+       return nil
+}
+
+func (r *SdewanCNFStatusController) GetInstance(ctx context.Context) (*batchv1alpha1.CNFStatus, error) {
+       instance := &batchv1alpha1.CNFStatus{}
+       err := r.Get(ctx, client.ObjectKey{
+               Namespace: cnfCRNameSpace,
+               Name:      cnfCRName,
+       }, instance)
+
+       if errs.IsNotFound(err) {
+               // No instance, create the instance
+               r.Log.Info("Create New CNFStatus CR")
+               instance = &batchv1alpha1.CNFStatus{
+                       ObjectMeta: metav1.ObjectMeta{
+                               Name:      cnfCRName,
+                               Namespace: cnfCRNameSpace,
+                       },
+                       Spec: batchv1alpha1.CNFStatusSpec{},
+               }
+
+               err = r.Create(ctx, instance)
+               if err != nil {
+                       return &batchv1alpha1.CNFStatus{}, err
+               }
+       }
+
+       return instance, nil
+}
+
+// Query CNFStatus information
+func (r *SdewanCNFStatusController) SafeQuery() {
+       doQuery := true
+       r.mux.Lock()
+       if inQueryStatus == false {
+               inQueryStatus = true
+       } else {
+               doQuery = false
+       }
+       r.mux.Unlock()
+
+       if doQuery {
+               r.query()
+
+               r.mux.Lock()
+               inQueryStatus = false
+               r.mux.Unlock()
+       }
+}
+
+func (r *SdewanCNFStatusController) query() {
+       ctx := context.Background()
+
+       instance, err := r.GetInstance(ctx)
+       if err != nil {
+               r.Log.Info(err.Error())
+       } else {
+               r.Log.Info("Query CNFStatus CR Instance: " + instance.ObjectMeta.Name)
+       }
+
+       // Set Status infomration
+       instance.Status.AppliedGeneration = instance.Generation
+       instance.Status.AppliedTime = &metav1.Time{Time: time.Now()}
+       instance.Status.Information = []batchv1alpha1.CNFStatusInformation{}
+
+       cnfPodList := &corev1.PodList{}
+       err = r.List(ctx, cnfPodList, client.HasLabels{"sdewanPurpose"})
+       if err != nil {
+               r.Log.Info(err.Error())
+               return
+       }
+
+       for _, cnfPod := range cnfPodList.Items {
+               info := &batchv1alpha1.CNFStatusInformation{}
+               info.Name = cnfPod.ObjectMeta.Name
+               info.NameSpace = cnfPod.ObjectMeta.Namespace
+               info.Node = cnfPod.Spec.NodeName
+               info.Purpose = cnfPod.ObjectMeta.Labels["sdewanPurpose"]
+               info.IP = cnfPod.Status.PodIP
+
+               // Get CNF Status
+               clientInfo := &openwrt.OpenwrtClientInfo{Ip: info.IP, User: "root", Password: ""}
+               openwrtClient := openwrt.GetOpenwrtClient(*clientInfo)
+               status_client := openwrt.StatusClient{OpenwrtClient: openwrtClient}
+               cnf_status, err := status_client.GetStatus()
+               if err != nil {
+                       info.Status = "Not Available"
+               } else {
+                       p_data, _ := json.Marshal(cnf_status)
+                       info.Status = string(p_data)
+               }
+               instance.Status.Information = append(instance.Status.Information, *info)
+       }
+
+       // Update the CNFStatus CR
+       err = r.Status().Update(ctx, instance)
+       if err != nil {
+               r.Log.Info(err.Error())
+       }
+}
index c50c83d..beb3dee 100644 (file)
@@ -20,6 +20,7 @@ import (
        "flag"
        "fmt"
        "os"
+       "time"
 
        corev1 "k8s.io/api/core/v1"
        rbacv1 "k8s.io/api/rbac/v1"
@@ -50,9 +51,12 @@ func init() {
 func main() {
        var metricsAddr string
        var enableLeaderElection bool
+       var checkInterval int
        flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
        flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
                "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
+       flag.IntVar(&checkInterval, "check-interval", 30,
+               "The check interval for query of CNF Status (seconds)")
        flag.Parse()
 
        ctrl.SetLogger(zap.New(func(o *zap.Options) {
@@ -227,6 +231,16 @@ func main() {
        }
        // +kubebuilder:scaffold:builder
 
+       setupLog.Info("start CNFStatusController to query CNF status periodicly")
+       if err = (&controllers.SdewanCNFStatusController{
+               Client:        mgr.GetClient(),
+               Log:           ctrl.Log.WithName("controllers").WithName("SdewanCNFStatus"),
+               CheckInterval: time.Duration(checkInterval) * time.Second,
+       }).SetupWithManager(); err != nil {
+               setupLog.Error(err, "unable to create controller", "controller", "SdewanCNFStatus")
+               os.Exit(1)
+       }
+
        setupLog.Info("starting manager")
        if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
                setupLog.Error(err, "problem running manager")
diff --git a/platform/crd-ctrlr/src/openwrt/status.go b/platform/crd-ctrlr/src/openwrt/status.go
new file mode 100644 (file)
index 0000000..5c4b59e
--- /dev/null
@@ -0,0 +1,55 @@
+package openwrt
+
+import (
+       "encoding/json"
+)
+
+const (
+       statusBaseURL = "sdewan/v1/"
+)
+
+type StatusClient struct {
+       OpenwrtClient *openwrtClient
+}
+
+// Status Info
+type SdewanModuleStatus struct {
+       Name   string      `json:"name"`
+       Status interface{} `json:"status"`
+}
+
+func (o *SdewanModuleStatus) GetName() string {
+       return o.Name
+}
+
+// Status APIs
+// get status
+func (m *StatusClient) GetStatus() (*[]SdewanModuleStatus, error) {
+       response, err := m.OpenwrtClient.Get(statusBaseURL + "status")
+       if err != nil {
+               return nil, err
+       }
+
+       var sdewanStatus []SdewanModuleStatus
+       err = json.Unmarshal([]byte(response), &sdewanStatus)
+       if err != nil {
+               return nil, err
+       }
+
+       return &sdewanStatus, nil
+}
+
+func (m *StatusClient) GetModuleStatus(mname string) (*SdewanModuleStatus, error) {
+       response, err := m.OpenwrtClient.Get(statusBaseURL + "status/" + mname)
+       if err != nil {
+               return nil, err
+       }
+
+       var sdewanModuleStatus SdewanModuleStatus
+       err = json.Unmarshal([]byte(response), &sdewanModuleStatus)
+       if err != nil {
+               return nil, err
+       }
+
+       return &sdewanModuleStatus, nil
+}