Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

https://github.com/web-servers/jws-operator/issues/58 and https://github.com/web-servers/jws-operator/issues/57 #62

Merged
merged 4 commits into from
Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.16 as builder
FROM golang:1.17 as builder

WORKDIR /workspace
# Copy the Go Modules manifests
Expand Down
6 changes: 6 additions & 0 deletions api/v1alpha1/webserver_types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1alpha1

import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand All @@ -25,6 +26,8 @@ type WebServerSpec struct {
WebImage *WebImageSpec `json:"webImage,omitempty"`
// (Deployment method 2) Imagestream
WebImageStream *WebImageStreamSpec `json:"webImageStream,omitempty"`
// Configuration of the resources used by the WebServer, ie CPU and memory, use limits and requests
Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
}

// (Deployment method 1) Application image
Expand Down Expand Up @@ -122,6 +125,8 @@ type WebServerStatus struct {
//
// Read-only.
ScalingdownPods int32 `json:"scalingdownPods"`
// selector for pods, used by HorizontalPodAutoscaler
Selector string `json:"selector"`
}

const (
Expand All @@ -147,6 +152,7 @@ type PodStatus struct {
// Web Server is the schema for the webservers API
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector
// +kubebuilder:resource:path=webservers,scope=Namespaced
type WebServer struct {
metav1.TypeMeta `json:",inline"`
Expand Down
7 changes: 7 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions config/crd/bases/web.servers.org_webservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,33 @@ spec:
format: int32
minimum: 0
type: integer
resources:
description: Configuration of the resources used by the WebServer,
ie CPU and memory, use limits and requests
properties:
limits:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: 'Limits describes the maximum amount of compute resources
allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
type: object
requests:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: 'Requests describes the minimum amount of compute
resources required. If Requests is omitted for a container,
it defaults to Limits if that is explicitly specified, otherwise
to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
type: object
type: object
useSessionClustering:
description: Use Session Clustering
type: boolean
Expand Down Expand Up @@ -215,14 +242,22 @@ spec:
\n Read-only."
format: int32
type: integer
selector:
description: selector for pods, used by HorizontalPodAutoscaler
type: string
required:
- replicas
- scalingdownPods
- selector
type: object
type: object
served: true
storage: true
subresources:
scale:
labelSelectorPath: .status.selector
specReplicasPath: .spec.replicas
statusReplicasPath: .status.replicas
status: {}
status:
acceptedNames:
Expand Down
3 changes: 3 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ rules:
- servicemonitors
verbs:
- create
- delete
- get
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
Expand Down
37 changes: 35 additions & 2 deletions controllers/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
corev1 "k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/discovery"
"k8s.io/client-go/rest"
Expand Down Expand Up @@ -404,14 +405,17 @@ func (r *WebServerReconciler) getPodList(webServer *webserversv1alpha1.WebServer
}

// generateLabelsForWeb return a map of labels that are used for identification
// of objects belonging to the particular WebServer instance
// of objects belonging to the particular WebServer instance
// NOTE: that is ONLY for application pods! (not for the builder or any helpers
func (r *WebServerReconciler) generateLabelsForWeb(webServer *webserversv1alpha1.WebServer) map[string]string {
labels := map[string]string{
"deploymentConfig": webServer.Spec.ApplicationName,
"WebServer": webServer.Name,
"application": webServer.Spec.ApplicationName,
// app.kubernetes.io/name is used for HPA selector like in wildfly
"app.kubernetes.io/name": webServer.Name,
}
// labels["app.kubernetes.io/name"] = webServer.Name
// Those are from the wildfly operator (in their Dockerfile)
// labels["app.kubernetes.io/managed-by"] = os.Getenv("LABEL_APP_MANAGED_BY")
// labels["app.openshift.io/runtime"] = os.Getenv("LABEL_APP_RUNTIME")
if webServer.Labels != nil {
Expand Down Expand Up @@ -575,7 +579,11 @@ func (r *WebServerReconciler) setUseKUBEPing(webServer *webserversv1alpha1.WebSe
}
}
if needUpdate {
log.Info("The UseKUBEPing of WebServer is being updated")
err := r.Client.Update(context.TODO(), webServer)
if err != nil {
log.Error(err, "Failed to update WebServer UseKUBEPing")
}
return true, err
}
return false, nil
Expand All @@ -592,3 +600,28 @@ func (r *WebServerReconciler) getUseKUBEPing(webServer *webserversv1alpha1.WebSe
}
return true
}

// CustomResourceDefinitionExists returns true if the CRD exists in the cluster
func CustomResourceDefinitionExists(gvk schema.GroupVersionKind, c *rest.Config) bool {
/*
cfg, err := config.GetConfig()
if err != nil {
return false
}
client, err := discovery.NewDiscoveryClientForConfig(cfg)
*/
client, err := discovery.NewDiscoveryClientForConfig(c)
if err != nil {
return false
}
api, err := client.ServerResourcesForGroupVersion(gvk.GroupVersion().String())
if err != nil {
return false
}
for _, a := range api.APIResources {
if a.Kind == gvk.Kind {
return true
}
}
return false
}
92 changes: 92 additions & 0 deletions controllers/label_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package controllers

import (
"context"
// "errors"
"fmt"
// "testing"
"time"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

// corev1 "k8s.io/api/core/v1"
// appsv1 "github.com/openshift/api/apps/v1"
kbappsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
// "k8s.io/kubectl/pkg/util/podutils"
// podv1 "k8s.io/kubernetes/pkg/api/v1/pod"
// apierrors "k8s.io/apimachinery/pkg/api/errors"
// "sigs.k8s.io/controller-runtime/pkg/client"

webserversv1alpha1 "github.com/web-servers/jws-operator/api/v1alpha1"
// webserverstests "github.com/web-servers/jws-operator/test/framework"
)

var _ = Describe("WebServer controller", func() {
Context("First Test", func() {
It("Label test", func() {
By("By creating a new WebServer")
fmt.Printf("By creating a new WebServer\n")
name := "label-test"
namespace := "default"
ctx := context.Background()
webserver := &webserversv1alpha1.WebServer{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: webserversv1alpha1.WebServerSpec{
ApplicationName: name,
Replicas: int32(2),
WebImage: &webserversv1alpha1.WebImageSpec{
ApplicationImage: "quay.io/jfclere/tomcat-demo",
},
},
}

// make sure we cleanup at the end of this test.
defer func() {
k8sClient.Delete(context.Background(), webserver)
time.Sleep(time.Second * 5)
}()

// create the webserver
Expect(k8sClient.Create(ctx, webserver)).Should(Succeed())

// Check it is started.
webserverLookupKey := types.NamespacedName{Name: name, Namespace: namespace}
createdWebserver := &webserversv1alpha1.WebServer{}
Eventually(func() bool {
err := k8sClient.Get(ctx, webserverLookupKey, createdWebserver)
if err != nil {
return false
}
return true
}, time.Second*10, time.Millisecond*250).Should(BeTrue())
fmt.Printf("new WebServer Name: %s Namespace: %s\n", createdWebserver.ObjectMeta.Name, createdWebserver.ObjectMeta.Namespace)

// Verify deployment template selector label.
deployment := &kbappsv1.Deployment{}
// deployment := &appsv1.DeploymentConfig{}
deploymentookupKey := types.NamespacedName{Name: name, Namespace: namespace}
Eventually(func() bool {
err := k8sClient.Get(ctx, deploymentookupKey, deployment)
if err != nil {
return false
}
return true
}, time.Second*10, time.Millisecond*250).Should(BeTrue())

// check the labels
stringmap := deployment.Spec.Template.GetLabels()
fmt.Println(stringmap)
Expect(deployment.Spec.Template.GetLabels()["app.kubernetes.io/name"]).Should(Equal(name))

// remove the created webserver
Expect(k8sClient.Delete(ctx, webserver)).Should(Succeed())

})
})
})
2 changes: 1 addition & 1 deletion controllers/other_basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var _ = Describe("WebServer controller", func() {
By("By creating a new WebServer")
fmt.Printf("By creating a new WebServer\n")
if !noskip {
fmt.Printf("other_basic_testy skipped\n")
fmt.Printf("other_basic_test skipped\n")
return
}
ctx := context.Background()
Expand Down
61 changes: 61 additions & 0 deletions controllers/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package controllers

import (
"context"
webserversv1alpha1 "github.com/web-servers/jws-operator/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

// GetOrCreateNewPrometheusService either returns the headless service or create
func (r *WebServerReconciler) GetOrCreateNewPrometheusService(w *webserversv1alpha1.WebServer, ctx context.Context, labels map[string]string) (*corev1.Service, error) {
service := &corev1.Service{}
if err := r.Client.Get(ctx, client.ObjectKey{
Namespace: w.Namespace,
Name: PrometeusServiceName(w),
}, service); err != nil {
if errors.IsNotFound(err) {
if err := r.Client.Create(ctx, r.generatePrometeusService(w, labels)); err != nil {
if errors.IsAlreadyExists(err) {
return nil, nil
}
return nil, err
}
return nil, nil
}
}
return service, nil
}

// generatePrometeusService returns a service exposing the prometheus port of WebServer
// Like the newAdminService of wildfly operator
func (r *WebServerReconciler) generatePrometeusService(w *webserversv1alpha1.WebServer, labels map[string]string) *corev1.Service {
headlessService := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: PrometeusServiceName(w),
Namespace: w.Namespace,
Labels: labels,
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeClusterIP,
Selector: labels,
ClusterIP: corev1.ClusterIPNone,
Ports: []corev1.ServicePort{
{
Name: "admin",
Port: 9404,
},
},
},
}
controllerutil.SetControllerReference(w, headlessService, r.Scheme)
return headlessService
}

// PrometeusServiceName returns the name of prometeus admin service
func PrometeusServiceName(w *webserversv1alpha1.WebServer) string {
return w.Name + "-admin"
}
Loading