Skip to content

Commit

Permalink
Merge pull request #7 from prksu/use-create-or-update-func
Browse files Browse the repository at this point in the history
Use create or update func from controller-runtime
  • Loading branch information
prksu-bot authored Jan 2, 2020
2 parents 3353f7b + 0ba59d0 commit cc60b48
Show file tree
Hide file tree
Showing 8 changed files with 364 additions and 347 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module fossil.or.id/ghost-operator
go 1.13

require (
github.com/go-logr/logr v0.1.0
github.com/go-openapi/spec v0.19.2
github.com/operator-framework/operator-sdk v0.13.0
github.com/spf13/pflag v1.0.5
Expand Down
38 changes: 38 additions & 0 deletions pkg/controller/ghostapp/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2019 Fossil Dev
//
// 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 ghostapp

import (
ghostv1alpha1 "fossil.or.id/ghost-operator/pkg/apis/ghost/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func commonLabelFromCR(cr *ghostv1alpha1.GhostApp) map[string]string {
return map[string]string{
"app.kubernetes.io/name": "ghostapp",
"app.kubernetes.io/instance": cr.GetName(),
}
}

func commonLabelSelectorFromCR(cr *ghostv1alpha1.GhostApp) *metav1.LabelSelector {
return &metav1.LabelSelector{
MatchLabels: commonLabelFromCR(cr),
}
}

func configMapNameFromCR(cr *ghostv1alpha1.GhostApp) string { return cr.GetName() + "-ghost-config" }
func persistentVolumeClaimNameFromCR(cr *ghostv1alpha1.GhostApp) string {
return cr.GetName() + "-ghost-content-pvc"
}
51 changes: 51 additions & 0 deletions pkg/controller/ghostapp/configmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2019 Fossil Dev
//
// 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 ghostapp

import (
"context"
"encoding/json"

ghostv1alpha1 "fossil.or.id/ghost-operator/pkg/apis/ghost/v1alpha1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

func (r *ReconcileGhostApp) CreateOrUpdateConfigMap(cr *ghostv1alpha1.GhostApp) error {
configdata := make(map[string]string)
config, _ := json.MarshalIndent(cr.Spec.Config, "", " ")
configdata["config.json"] = string(config)

cm := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: configMapNameFromCR(cr),
Namespace: cr.GetNamespace(),
Labels: commonLabelFromCR(cr),
},
}

op, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, cm, func() error {
if err := controllerutil.SetControllerReference(cr, cm, r.scheme); err != nil {
return err
}

cm.Data = configdata
return nil
})

r.logger.Info("Reconciling ConfigMap", "Operation.Result", op)
return err
}
133 changes: 133 additions & 0 deletions pkg/controller/ghostapp/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright 2019 Fossil Dev
//
// 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 ghostapp

import (
"context"

ghostv1alpha1 "fossil.or.id/ghost-operator/pkg/apis/ghost/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

func (r *ReconcileGhostApp) CreateOrUpdateDeployment(cr *ghostv1alpha1.GhostApp) error {
dep := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: cr.GetName(),
Namespace: cr.GetNamespace(),
Labels: commonLabelFromCR(cr),
},
}

op, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, dep, func() error {
if dep.ObjectMeta.CreationTimestamp.IsZero() {
// Set label selector only when deployment has never been created
dep.Spec.Selector = commonLabelSelectorFromCR(cr)
}

if err := controllerutil.SetControllerReference(cr, dep, r.scheme); err != nil {
return err
}

dep.Spec.Replicas = cr.Spec.Replicas
dep.Spec.Template = corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: commonLabelFromCR(cr),
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "ghost",
Image: cr.Spec.Image,
ImagePullPolicy: corev1.PullIfNotPresent,
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: int32(2368),
},
},
Lifecycle: &corev1.Lifecycle{
PostStart: &corev1.Handler{
Exec: &corev1.ExecAction{
Command: []string{"/bin/sh", "-c", "ln -sf /etc/ghost/config/config.json /var/lib/ghost/config.production.json"},
},
},
},
VolumeMounts: r.newVolumeMountForCR(cr),
},
},
Volumes: r.newVolumeForCR(cr),
},
}
return nil
})

r.logger.Info("Reconciling Deployment", "Operation.Result", op)
return err
}

func (r *ReconcileGhostApp) newVolumeForCR(cr *ghostv1alpha1.GhostApp) []corev1.Volume {
var volume []corev1.Volume
volume = append(volume, corev1.Volume{
Name: "ghost-config",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: configMapNameFromCR(cr),
},
},
},
})

var ghostContentSource corev1.VolumeSource
if cr.Spec.Persistent.Enabled {
ghostContentSource = corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: persistentVolumeClaimNameFromCR(cr),
},
}
} else {
ghostContentSource = corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
}
}

volume = append(volume, corev1.Volume{
Name: "ghost-content",
VolumeSource: ghostContentSource,
})

return volume
}

func (r *ReconcileGhostApp) newVolumeMountForCR(cr *ghostv1alpha1.GhostApp) []corev1.VolumeMount {
var volumeMount []corev1.VolumeMount

volumeMount = append(volumeMount, corev1.VolumeMount{
Name: "ghost-config",
ReadOnly: true,
MountPath: "/etc/ghost/config",
})
volumeMount = append(volumeMount, corev1.VolumeMount{
Name: "ghost-content",
ReadOnly: false,
MountPath: "/var/lib/ghost/content",
})

return volumeMount

}
Loading

0 comments on commit cc60b48

Please sign in to comment.