This is an automated email from the ASF dual-hosted git repository.

pingsutw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new 3fc12adc SUBMARINE-1286. Install grafana
3fc12adc is described below

commit 3fc12adc9da1768c60e8c273a41d08210f8c82a7
Author: jeff-901 <[email protected]>
AuthorDate: Mon Jul 4 22:32:12 2022 +0800

    SUBMARINE-1286. Install grafana
    
    ### What is this PR for?
    Install grafana by using grafana original image
    
    ### What type of PR is it?
    Feature
    
    ### Todos
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/SUBMARINE-1286
    
    ### How should this be tested?
    go to http://{istio ingress ip}/grafana
    
    ### Screenshots (if appropriate)
    
![image](https://user-images.githubusercontent.com/54139205/174744181-7b38c5b1-7309-4be9-a61a-15286dc3a927.png)
    
    ### Questions:
    * Do the license files need updating? No
    * Are there breaking changes for older versions? No
    * Does this need new documentation? No
    
    Author: jeff-901 <[email protected]>
    
    Signed-off-by: Kevin <[email protected]>
    
    Closes #970 from jeff-901/SUBMARINE-1286 and squashes the following commits:
    
    a7d4661c [jeff-901] set database
    c99c29f4 [jeff-901] reset file permission
    41b60684 [jeff-901] install grafana
    fed79026 [jeff-901] grafana ingress
    122abe3c [jeff-901] install grafana
---
 dev-support/docker-images/database/startup.sh      |   3 +
 .../artifacts/submarine/submarine-grafana.yaml     | 118 +++++++++++++
 .../artifacts/submarine/submarine-ingress.yaml     |   8 +
 submarine-cloud-v2/main.go                         |   1 +
 submarine-cloud-v2/pkg/controller/controller.go    |  11 ++
 .../pkg/controller/controller_builder.go           |   2 +
 .../pkg/controller/controller_builder_config.go    |   8 +
 .../pkg/controller/controller_event_handlers.go    |  17 ++
 submarine-cloud-v2/pkg/controller/parser.go        |  11 ++
 .../pkg/controller/submarine_grafana.go            | 182 +++++++++++++++++++++
 10 files changed, 361 insertions(+)

diff --git a/dev-support/docker-images/database/startup.sh 
b/dev-support/docker-images/database/startup.sh
index c52fc936..af917c98 100755
--- a/dev-support/docker-images/database/startup.sh
+++ b/dev-support/docker-images/database/startup.sh
@@ -36,4 +36,7 @@ use metastore; source /tmp/database/metastore.sql;
 CREATE DATABASE mlflowdb;
 CREATE USER 'mlflow'@'%' IDENTIFIED BY 'password';
 GRANT ALL PRIVILEGES ON * . * TO 'mlflow'@'%';
+CREATE DATABASE grafana;
+CREATE USER 'grafana'@'%' IDENTIFIED BY 'password';
+GRANT ALL PRIVILEGES ON * . * TO 'grafana'@'%';
 EOF
diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-grafana.yaml 
b/submarine-cloud-v2/artifacts/submarine/submarine-grafana.yaml
new file mode 100644
index 00000000..3a42735c
--- /dev/null
+++ b/submarine-cloud-v2/artifacts/submarine/submarine-grafana.yaml
@@ -0,0 +1,118 @@
+---
+# Source: submarine/templates/submarine-mlflow.yaml
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: submarine-grafana-config
+data:
+  grafana.ini: |
+    [server]
+    root_url = http://submarine-grafana-service/grafana/
+    serve_from_sub_path = true
+    [database]
+    type = mysql
+    name = grafana
+    host = submarine-database:3306
+    user = grafana
+    password = password
+    url = mysql://grafana:password@submarine-database:3306/grafana
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: submarine-grafana-pvc
+spec:
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app: submarine-grafana
+  name: submarine-grafana
+spec:
+  selector:
+    matchLabels:
+      app: submarine-grafana
+  template:
+    metadata:
+      labels:
+        app: submarine-grafana
+    spec:
+      securityContext:
+        fsGroup: 472
+        supplementalGroups:
+          - 0
+      containers:
+        - name: submarine-grafana
+          image: grafana/grafana:8.3.1
+          imagePullPolicy: IfNotPresent
+          ports:
+            - containerPort: 3000
+              name: http-grafana
+              protocol: TCP
+          readinessProbe:
+            failureThreshold: 3
+            httpGet:
+              path: /robots.txt
+              port: 3000
+              scheme: HTTP
+            initialDelaySeconds: 10
+            periodSeconds: 30
+            successThreshold: 1
+            timeoutSeconds: 2
+          livenessProbe:
+            failureThreshold: 3
+            initialDelaySeconds: 30
+            periodSeconds: 10
+            successThreshold: 1
+            tcpSocket:
+              port: 3000
+            timeoutSeconds: 1
+          volumeMounts:
+            - mountPath: /var/lib/grafana
+              name: submarine-grafana-pv
+            - mountPath: /etc/grafana
+              name: submarine-grafana-config
+      volumes:
+        - name: submarine-grafana-pv
+          persistentVolumeClaim:
+            claimName: submarine-grafana-pvc
+        - name: submarine-grafana-config
+          configMap:
+            name: submarine-grafana-config
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: submarine-grafana-service
+  labels:
+    app: submarine-grafana
+spec:
+  ports:
+    - port: 3000
+      targetPort: 3000
+      protocol: TCP
+      targetPort: http-grafana
+  selector:
+    app: submarine-grafana
diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-ingress.yaml 
b/submarine-cloud-v2/artifacts/submarine/submarine-ingress.yaml
index 73f4c842..f60f7989 100644
--- a/submarine-cloud-v2/artifacts/submarine/submarine-ingress.yaml
+++ b/submarine-cloud-v2/artifacts/submarine/submarine-ingress.yaml
@@ -49,6 +49,14 @@ spec:
             host: submarine-minio-service
             port:
               number: 9000
+    - match:
+        - uri:
+            prefix: /grafana
+      route:
+        - destination:
+            host: submarine-grafana-service
+            port:
+              number: 3000
     - route:
         - destination:
             host: submarine-server
diff --git a/submarine-cloud-v2/main.go b/submarine-cloud-v2/main.go
index f977ae93..48a90357 100644
--- a/submarine-cloud-v2/main.go
+++ b/submarine-cloud-v2/main.go
@@ -155,6 +155,7 @@ func NewSubmarineController(
                WithServiceInformer(kubeInformerFactory.Core().V1().Services()).
                
WithServiceAccountInformer(kubeInformerFactory.Core().V1().ServiceAccounts()).
                
WithPersistentVolumeClaimInformer(kubeInformerFactory.Core().V1().PersistentVolumeClaims()).
+               
WithConfigMapClaimInformer(kubeInformerFactory.Core().V1().ConfigMaps()).
                
WithIngressInformer(kubeInformerFactory.Extensions().V1beta1().Ingresses()).
                // 
WithIngressRouteInformer(traefikInformerFactory.Traefik().V1alpha1().IngressRoutes()).
                
WithVirtualServiceInformer(istioInformerFactory.Networking().V1alpha3().VirtualServices()).
diff --git a/submarine-cloud-v2/pkg/controller/controller.go 
b/submarine-cloud-v2/pkg/controller/controller.go
index 10117c99..0e31156b 100644
--- a/submarine-cloud-v2/pkg/controller/controller.go
+++ b/submarine-cloud-v2/pkg/controller/controller.go
@@ -79,10 +79,15 @@ const (
        minioPvcName                = minioName + "-pvc"
        minioServiceName            = minioName + "-service"
        minioIngressRouteName       = minioName + "-ingressroute"
+       grafanaName                 = "submarine-grafana"
+       grafanaPvcName              = grafanaName + "-pvc"
+       grafanaServiceName          = grafanaName + "-service"
+       grafanaConfigMapName        = grafanaName + "-config"
        artifactPath                = "./artifacts/submarine/"
        databaseYamlPath            = artifactPath + "submarine-database.yaml"
        ingressYamlPath             = artifactPath + "submarine-ingress.yaml"
        minioYamlPath               = artifactPath + "submarine-minio.yaml"
+       grafanaYamlPath             = artifactPath + "submarine-grafana.yaml"
        mlflowYamlPath              = artifactPath + "submarine-mlflow.yaml"
        serverYamlPath              = artifactPath + "submarine-server.yaml"
        tensorboardYamlPath         = artifactPath + 
"submarine-tensorboard.yaml"
@@ -142,6 +147,7 @@ type Controller struct {
        serviceaccountLister        corelisters.ServiceAccountLister
        serviceLister               corelisters.ServiceLister
        persistentvolumeclaimLister corelisters.PersistentVolumeClaimLister
+       configMapLister             corelisters.ConfigMapLister
        ingressLister               extlisters.IngressLister
        // ingressrouteLister          traefiklisters.IngressRouteLister
        virtualServiceLister istioListers.VirtualServiceLister
@@ -512,6 +518,11 @@ func (c *Controller) createSubmarine(submarine 
*v1alpha1.Submarine) error {
                return err
        }
 
+       err = c.createSubmarineGrafana(submarine)
+       if err != nil && !errors.IsAlreadyExists(err) {
+               return err
+       }
+
        return nil
 }
 
diff --git a/submarine-cloud-v2/pkg/controller/controller_builder.go 
b/submarine-cloud-v2/pkg/controller/controller_builder.go
index 192fea4e..6c34f8b9 100644
--- a/submarine-cloud-v2/pkg/controller/controller_builder.go
+++ b/submarine-cloud-v2/pkg/controller/controller_builder.go
@@ -90,6 +90,7 @@ func (cb *ControllerBuilder) addListers() *ControllerBuilder {
        cb.controller.serviceLister = cb.config.serviceInformer.Lister()
        cb.controller.serviceaccountLister = 
cb.config.serviceaccountInformer.Lister()
        cb.controller.persistentvolumeclaimLister = 
cb.config.persistentvolumeclaimInformer.Lister()
+       cb.controller.configMapLister = cb.config.configMapInformer.Lister()
        cb.controller.ingressLister = cb.config.ingressInformer.Lister()
        // cb.controller.ingressrouteLister = 
cb.config.ingressrouteInformer.Lister()
        cb.controller.virtualServiceLister = 
cb.config.virtualServiceInformer.Lister()
@@ -111,6 +112,7 @@ func (cb *ControllerBuilder) addEventHandlers() 
*ControllerBuilder {
        cb.addServiceEventHandlers()
        cb.addServiceAccountEventHandlers()
        cb.addPersistentVolumeClaimEventHandlers()
+       cb.addConfigMapEventHandlers()
        cb.addIngressEventHandlers()
        // cb.addIngressRouteEventHandlers()
        cb.addRoleEventHandlers()
diff --git a/submarine-cloud-v2/pkg/controller/controller_builder_config.go 
b/submarine-cloud-v2/pkg/controller/controller_builder_config.go
index b8a2dcc9..91b8100b 100644
--- a/submarine-cloud-v2/pkg/controller/controller_builder_config.go
+++ b/submarine-cloud-v2/pkg/controller/controller_builder_config.go
@@ -46,6 +46,7 @@ type BuilderConfig struct {
        serviceInformer               coreinformers.ServiceInformer
        serviceaccountInformer        coreinformers.ServiceAccountInformer
        persistentvolumeclaimInformer 
coreinformers.PersistentVolumeClaimInformer
+       configMapInformer             coreinformers.ConfigMapInformer
        ingressInformer               extinformers.IngressInformer
        // ingressrouteInformer          traefikinformers.IngressRouteInformer
        virtualServiceInformer istioInformers.VirtualServiceInformer
@@ -158,6 +159,13 @@ func (bc *BuilderConfig) WithPersistentVolumeClaimInformer(
        return bc
 }
 
+func (bc *BuilderConfig) WithConfigMapClaimInformer(
+       configMapInformer coreinformers.ConfigMapInformer,
+) *BuilderConfig {
+       bc.configMapInformer = configMapInformer
+       return bc
+}
+
 func (bc *BuilderConfig) WithIngressInformer(
        ingressInformer extinformers.IngressInformer,
 ) *BuilderConfig {
diff --git a/submarine-cloud-v2/pkg/controller/controller_event_handlers.go 
b/submarine-cloud-v2/pkg/controller/controller_event_handlers.go
index 1e0036c5..20efdd81 100644
--- a/submarine-cloud-v2/pkg/controller/controller_event_handlers.go
+++ b/submarine-cloud-v2/pkg/controller/controller_event_handlers.go
@@ -122,6 +122,23 @@ func (cb *ControllerBuilder) 
addPersistentVolumeClaimEventHandlers() *Controller
        return cb
 }
 
+func (cb *ControllerBuilder) addConfigMapEventHandlers() *ControllerBuilder {
+       
cb.config.configMapInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
+               AddFunc: cb.controller.handleObject,
+               UpdateFunc: func(old, new interface{}) {
+                       newConfigMap := new.(*corev1.ConfigMap)
+                       oldConfigMap := old.(*corev1.ConfigMap)
+                       if newConfigMap.ResourceVersion == 
oldConfigMap.ResourceVersion {
+                               return
+                       }
+                       cb.controller.handleObject(new)
+               },
+               DeleteFunc: cb.controller.handleObject,
+       })
+
+       return cb
+}
+
 func (cb *ControllerBuilder) addIngressEventHandlers() *ControllerBuilder {
        
cb.config.ingressInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
                AddFunc: cb.controller.handleObject,
diff --git a/submarine-cloud-v2/pkg/controller/parser.go 
b/submarine-cloud-v2/pkg/controller/parser.go
index e844f3e8..040e64eb 100644
--- a/submarine-cloud-v2/pkg/controller/parser.go
+++ b/submarine-cloud-v2/pkg/controller/parser.go
@@ -169,6 +169,17 @@ func ParsePersistentVolumeClaimYaml(relativePath string) 
(*v1.PersistentVolumeCl
        return &pvc, nil
 }
 
+// ParseConfigMap parse ConfigMap from yaml file.
+func ParseConfigMapYaml(relativePath string) (*v1.ConfigMap, error) {
+       var configMap v1.ConfigMap
+       marshaled, err := parseYaml(relativePath, "ConfigMap")
+       if err != nil {
+               return nil, err
+       }
+       json.Unmarshal(marshaled, &configMap)
+       return &configMap, nil
+}
+
 // ParseIngressRouteYaml parse IngressRoute from yaml file.
 func ParseIngressRouteYaml(relativePath string) 
(*traefikv1alpha1.IngressRoute, error) {
        var ingressRoute traefikv1alpha1.IngressRoute
diff --git a/submarine-cloud-v2/pkg/controller/submarine_grafana.go 
b/submarine-cloud-v2/pkg/controller/submarine_grafana.go
new file mode 100644
index 00000000..90c8f2b2
--- /dev/null
+++ b/submarine-cloud-v2/pkg/controller/submarine_grafana.go
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 controller
+
+import (
+       "context"
+       "fmt"
+
+       v1alpha1 
"github.com/apache/submarine/submarine-cloud-v2/pkg/apis/submarine/v1alpha1"
+
+       appsv1 "k8s.io/api/apps/v1"
+       corev1 "k8s.io/api/core/v1"
+       "k8s.io/apimachinery/pkg/api/errors"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/klog/v2"
+)
+
+func newSubmarineGrafanaConfigMap(submarine *v1alpha1.Submarine) 
*corev1.ConfigMap {
+       configMap, err := ParseConfigMapYaml(grafanaYamlPath)
+       if err != nil {
+               klog.Info("[Error] ParseConfigMap", err)
+       }
+       configMap.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+               *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+       }
+
+       return configMap
+}
+
+func newSubmarineGrafanaPersistentVolumeClaim(submarine *v1alpha1.Submarine) 
*corev1.PersistentVolumeClaim {
+       pvc, err := ParsePersistentVolumeClaimYaml(grafanaYamlPath)
+       if err != nil {
+               klog.Info("[Error] ParsePersistentVolumeClaim", err)
+       }
+       pvc.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+               *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+       }
+
+       return pvc
+}
+
+func newSubmarineGrafanaDeployment(submarine *v1alpha1.Submarine) 
*appsv1.Deployment {
+       deployment, err := ParseDeploymentYaml(grafanaYamlPath)
+       if err != nil {
+               klog.Info("[Error] ParseDeploymentYaml", err)
+       }
+       deployment.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+               *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+       }
+
+       return deployment
+}
+
+func newSubmarineGrafanaService(submarine *v1alpha1.Submarine) *corev1.Service 
{
+       service, err := ParseServiceYaml(grafanaYamlPath)
+       if err != nil {
+               klog.Info("[Error] ParseServiceYaml", err)
+       }
+       service.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+               *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+       }
+       return service
+}
+
+// createSubmarineGrafana is a function to create submarine-grafana
+func (c *Controller) createSubmarineGrafana(submarine *v1alpha1.Submarine) 
error {
+       klog.Info("[createSubmarineGrafana]")
+
+       // Step 1: Create ConfigMap
+       configMap, err := 
c.configMapLister.ConfigMaps(submarine.Namespace).Get(grafanaConfigMapName)
+       klog.Info("     Create ConfigMap: ", configMap)
+       // If the resource doesn't exist, we'll create it
+       if errors.IsNotFound(err) {
+               klog.Info("Into not found")
+               configMap, err = 
c.kubeclientset.CoreV1().ConfigMaps(submarine.Namespace).Create(context.TODO(),
+                       newSubmarineGrafanaConfigMap(submarine),
+                       metav1.CreateOptions{})
+               if err != nil {
+                       klog.Info(err)
+               }
+               klog.Info("     Create ConfigMap: ", configMap.Name)
+       }
+       // If an error occurs during Get/Create, we'll requeue the item so we 
can
+       // attempt processing again later. This could have been caused by a
+       // temporary network failure, or any other transient reason.
+       if err != nil {
+               return err
+       }
+
+       if !metav1.IsControlledBy(configMap, submarine) {
+               msg := fmt.Sprintf(MessageResourceExists, configMap.Name)
+               c.recorder.Event(submarine, corev1.EventTypeWarning, 
ErrResourceExists, msg)
+               return fmt.Errorf(msg)
+       }
+
+       // Step 2: Create PersistentVolumeClaim
+       pvc, err := 
c.persistentvolumeclaimLister.PersistentVolumeClaims(submarine.Namespace).Get(grafanaPvcName)
+       // If the resource doesn't exist, we'll create it
+       if errors.IsNotFound(err) {
+               pvc, err = 
c.kubeclientset.CoreV1().PersistentVolumeClaims(submarine.Namespace).Create(context.TODO(),
+                       newSubmarineGrafanaPersistentVolumeClaim(submarine),
+                       metav1.CreateOptions{})
+               if err != nil {
+                       klog.Info(err)
+               }
+               klog.Info("     Create PersistentVolumeClaim: ", pvc.Name)
+       }
+       // If an error occurs during Get/Create, we'll requeue the item so we 
can
+       // attempt processing again later. This could have been caused by a
+       // temporary network failure, or any other transient reason.
+       if err != nil {
+               return err
+       }
+
+       if !metav1.IsControlledBy(pvc, submarine) {
+               msg := fmt.Sprintf(MessageResourceExists, pvc.Name)
+               c.recorder.Event(submarine, corev1.EventTypeWarning, 
ErrResourceExists, msg)
+               return fmt.Errorf(msg)
+       }
+
+       // Step 3: Create Deployment
+       deployment, err := 
c.deploymentLister.Deployments(submarine.Namespace).Get(grafanaName)
+       if errors.IsNotFound(err) {
+               deployment, err = 
c.kubeclientset.AppsV1().Deployments(submarine.Namespace).Create(context.TODO(),
 newSubmarineGrafanaDeployment(submarine), metav1.CreateOptions{})
+               if err != nil {
+                       klog.Info(err)
+               }
+               klog.Info("     Create Deployment: ", deployment.Name)
+       }
+       // If an error occurs during Get/Create, we'll requeue the item so we 
can
+       // attempt processing again later. This could have been caused by a
+       // temporary network failure, or any other transient reason.
+       if err != nil {
+               return err
+       }
+
+       if !metav1.IsControlledBy(deployment, submarine) {
+               msg := fmt.Sprintf(MessageResourceExists, deployment.Name)
+               c.recorder.Event(submarine, corev1.EventTypeWarning, 
ErrResourceExists, msg)
+               return fmt.Errorf(msg)
+       }
+
+       // Step 4: Create Service
+       service, err := 
c.serviceLister.Services(submarine.Namespace).Get(grafanaServiceName)
+       // If the resource doesn't exist, we'll create it
+       if errors.IsNotFound(err) {
+               service, err = 
c.kubeclientset.CoreV1().Services(submarine.Namespace).Create(context.TODO(), 
newSubmarineGrafanaService(submarine), metav1.CreateOptions{})
+               if err != nil {
+                       klog.Info(err)
+               }
+               klog.Info(" Create Service: ", service.Name)
+       }
+       // If an error occurs during Get/Create, we'll requeue the item so we 
can
+       // attempt processing again later. This could have been caused by a
+       // temporary network failure, or any other transient reason.
+       if err != nil {
+               return err
+       }
+
+       if !metav1.IsControlledBy(service, submarine) {
+               msg := fmt.Sprintf(MessageResourceExists, service.Name)
+               c.recorder.Event(submarine, corev1.EventTypeWarning, 
ErrResourceExists, msg)
+               return fmt.Errorf(msg)
+       }
+
+       return nil
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to