Skip to content
/*
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 cron
import (
"fmt"
"github.com/presslabs/controller-util/syncer"
batchv1beta1 "k8s.io/api/batch/v1beta1"
corev1 "k8s.io/api/core/v1"
common "git.indie.host/nextcloud-operator/components/common"
interfaces "git.indie.host/nextcloud-operator/interfaces"
)
type Component struct {
Name string
*common.Common
CronJob batchv1beta1.CronJob
}
func CreateAndInit(common *common.Common) *Component {
c := &Component{}
c.Name = "cron"
c.Common = common
labels := c.Labels("cronjob")
c.CronJob.SetLabels(labels)
objects := c.GetObjects()
for _, o := range objects {
o.SetName(c.GetName())
o.SetNamespace(c.Owner.Namespace)
o.SetLabels(labels)
}
return c
}
func (c *Component) NewCronJobSyncer(r interfaces.Reconcile) syncer.Interface {
return syncer.NewObjectSyncer("CronJob", c.Owner, &c.CronJob, r.GetClient(), r.GetScheme(), c.MutateCronJob)
}
func (c *Component) MutateCronJob() error {
c.Settings.MutatePod(&c.CronJob.Spec.JobTemplate.Spec.Template)
c.Runtime.MutatePod(&c.CronJob.Spec.JobTemplate.Spec.Template)
c.CronJob.Spec.Schedule = "*/15 * * * *"
c.CronJob.Spec.JobTemplate.ObjectMeta = c.CronJob.ObjectMeta
c.CronJob.Spec.JobTemplate.Spec.Template.ObjectMeta = c.CronJob.ObjectMeta
c.CronJob.Spec.JobTemplate.Spec.Template.Spec.RestartPolicy = corev1.RestartPolicyNever
args := []string{"/usr/local/bin/php", "/var/www/html/cron.php"}
c.CronJob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Args = args
return nil
}
func (c *Component) GetName() string {
return fmt.Sprintf("%s-%s", c.Owner.Name, c.Name)
}
func (c *Component) GetObjects() []interfaces.Object {
return []interfaces.Object{
&c.CronJob,
}
}
/*
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 web
import (
"github.com/presslabs/controller-util/syncer"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
interfaces "git.indie.host/nextcloud-operator/interfaces"
)
func (component *Component) NewDeploymentSyncer(r interfaces.Reconcile) syncer.Interface {
return syncer.NewObjectSyncer("Deployment", component.Owner, &component.Deployment, r.GetClient(), r.GetScheme(), component.MutateDeployment)
}
func (component *Component) MutateDeployment() error {
// component.Settings.MutateDeployment(&component.Deployment)
component.Runtime.MutateDeployment(&component.Deployment)
labels := component.Labels("web")
component.Deployment.Spec.Template.ObjectMeta = component.Deployment.ObjectMeta
component.Deployment.Spec.Selector = metav1.SetAsLabelSelector(labels)
component.Deployment.Spec.Template.Spec.Containers[0].VolumeMounts = component.GenContainerVolumeMounts()
component.Deployment.Spec.Template.Spec.Volumes = component.GenContainerVolumes()
return nil
}
func (c *Component) GenContainerVolumeMounts() []corev1.VolumeMount {
var mounts []corev1.VolumeMount
mount := corev1.VolumeMount{
Name: "nginx",
MountPath: "/etc/nginx/nginx.conf",
SubPath: "nginx.conf",
}
mounts = append(mounts, mount)
return mounts
}
func (c *Component) GenContainerVolumes() []corev1.Volume {
var volumes []corev1.Volume
volume := corev1.Volume{
Name: "nginx",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: c.GetName(),
},
},
},
}
volumes = append(volumes, volume)
return volumes
}
/*
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 web
import (
"github.com/presslabs/controller-util/syncer"
"k8s.io/apimachinery/pkg/util/intstr"
networking "k8s.io/api/networking/v1beta1"
interfaces "git.indie.host/nextcloud-operator/interfaces"
)
func (c *Component) NewIngressSyncer(r interfaces.Reconcile) syncer.Interface {
return syncer.NewObjectSyncer("Ingress", c.Owner, &c.Ingress, r.GetClient(), r.GetScheme(), c.MutateIngress)
}
func (c *Component) MutateIngress() error {
c.Runtime.MutateIngress(&c.Ingress)
bk := networking.IngressBackend{
ServiceName: "test",
ServicePort: intstr.FromString("http"),
}
bkpaths := []networking.HTTPIngressPath{
{
Path: "/",
Backend: bk,
},
}
rules := []networking.IngressRule{}
for _, d := range c.Runtime.Hosts {
rules = append(rules, networking.IngressRule{
Host: string(d),
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: bkpaths,
},
},
})
}
// fmt.Println(component.Ingress)
c.Ingress.Spec.Rules = rules
return nil
}
/*
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 web
import (
"fmt"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1beta1"
appsv1beta1 "git.indie.host/nextcloud-operator/api/v1beta1"
common "git.indie.host/nextcloud-operator/components/common"
interfaces "git.indie.host/nextcloud-operator/interfaces"
"k8s.io/apimachinery/pkg/labels"
)
type Component struct {
Name string
Owner *appsv1beta1.Nextcloud
Settings *appsv1beta1.Settings
Runtime *appsv1beta1.Runtime
Deployment appsv1.Deployment
Service corev1.Service
Ingress networking.Ingress
ConfigMap corev1.ConfigMap
}
func CreateAndInit(common *common.Common) *Component {
c := &Component{}
c.Name = "web"
c.Owner = common.Owner
c.Runtime = &c.Owner.Spec.Web.Runtime
c.Settings = &c.Owner.Spec.Web.Settings
c.SetDefaults()
labels := c.Labels("web")
objects := c.GetObjects()
for _, o := range objects {
o.SetName(c.GetName())
o.SetNamespace(c.Owner.Namespace)
o.SetLabels(labels)
}
return c
}
func (c *Component) GetName() string {
return fmt.Sprintf("%s-%s", c.Owner.Name, c.Name)
}
func (c *Component) Labels(component string) labels.Set {
partOf := "nextcloud"
// if o.ObjectMeta.Labels != nil && len(o.ObjectMeta.Labels["app.kubernetes.io/part-of"]) > 0 {
// partOf = o.ObjectMeta.Labels["app.kubernetes.io/part-of"]
// }
labels := labels.Set{
"app.kubernetes.io/name": "nextcloud",
"app.kubernetes.io/part-of": partOf,
"app.kubernetes.io/instance": c.Owner.ObjectMeta.Name,
// "app.kubernetes.io/version": c.Owner.Spec.AppVersion,
"app.kubernetes.io/component": component,
"app.kubernetes.io/managed-by": "nextcloud-operator.libre.sh",
}
return labels
}
func (c *Component) GetObjects() []interfaces.Object {
return []interfaces.Object{
&c.ConfigMap,
&c.Deployment,
&c.Service,
&c.Ingress,
}
}
func (c *Component) SetDefaults() {
if len(c.Runtime.Image) == 0 {
c.Runtime.Image = "indiehosters/nextcloud-web"
}
if len(c.Runtime.ServiceType) == 0 {
c.Runtime.ServiceType = "ClusterIP"
}
if c.Runtime.Ports == nil {
ports := []corev1.ContainerPort{
{
Name: "http",
ContainerPort: int32(80),
Protocol: "TCP",
},
}
c.Runtime.Ports = ports
}
}
# This patch add annotation to admission webhook config and
# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
apiVersion: admissionregistration.k8s.io/v1beta1
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: MutatingWebhookConfiguration
metadata:
name: mutating-webhook-configuration
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
---
apiVersion: admissionregistration.k8s.io/v1beta1
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingWebhookConfiguration
metadata:
name: validating-webhook-configuration
......
apiVersion: apps.libre.sh/v1alpha1
kind: Nextcloud
metadata:
name: nextcloud-sample
spec:
# Add fields here
version: "16"
app:
deployment:
replicas: 2
command:
- php-fpm
web:
deployment:
command:
- php-fpm
# cli:
# command:
# - sh
# - "-c"
# - "sleep 10"
# args:
settings:
app:
createOptions:
generate: envFile
database:
# database:
host:
value: "nextcloud-pg"
# port:
# type:
# username:
# password:
objectStore:
bucket:
value: nextcloud-bucket
host:
value: "https://standard.indie.host"
# port:
# autocreate:
# ssl:
# region:
# pathStyle:
accessKeyID:
ref: bucket-creds
refType: secret
fromKey: AWS_ACCESS_KEY_ID
secretAccessKey:
ref: bucket-creds
refType: secret
fromKey: AWS_SECRET_ACCESS_KEY
\ No newline at end of file
apiVersion: apps.libre.sh/v1beta1
kind: Nextcloud
metadata:
name: nextcloud-sample
spec:
# Add fields here
version: "16"
app:
enabled: true
settings:
parameters:
envVar:
DEFAULT_LANGUAGE: fr
DEFAULT_LOCALE: fr
runtime:
image: test/nextcloud
ingressAnnotations:
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-body-size: 5g
hosts:
- cloud.myhost.tld
# tlsSecretRef:
replicas: 2
serviceType: ClusterIP
web:
enabled: true
runtime:
image: test/nextcloud-web
ingressAnnotations:
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-body-size: 5g
hosts:
- cloud.myhost.tld
# tlsSecretRef:
replicas: 2
serviceType: ClusterIP
database:
enabled: true
settings:
parameters:
envVar:
DB_NAME: foo
DB_HOST: postgres_host
DB_PORT: "5432"
DB_TYPE: pgsql
secrets:
- name: database-secret
value: DB_USER
key: username
- name: database-secret
value: DB_PASSWORD
key: password
objectStore:
enabled: true
settings:
secrets:
- name: s3-secret
parameters:
envVar:
OBJECTSTORE_S3_BUCKET: mybucket
OBJECTSTORE_S3_AUTOCREATE: "true"
OBJECTSTORE_HOST: myhost
OBJECTSTORE_S3_PORT: "443"
OBJECTSTORE_S3_SSL: "true"
OBJECTSTORE_S3_REGION: default
redis:
enabled: true
settings:
parameters:
envVar:
REDIS_HOST: redis_host
REDIS_PORT: "1234"
......@@ -20,29 +20,23 @@ import (
"fmt"
"github.com/go-logr/logr"
"github.com/presslabs/controller-util/syncer"
appsv1 "k8s.io/api/apps/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/record"
"k8s.libre.sh/application"
"k8s.libre.sh/objects"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/presslabs/controller-util/syncer"
appsv1alpha1 "git.indie.host/operators/nextcloud-operator/api/v1alpha1"
"git.indie.host/operators/nextcloud-operator/util"
appsv1beta1 "git.indie.host/nextcloud-operator/api/v1beta1"
application "git.indie.host/nextcloud-operator/components/app"
"git.indie.host/nextcloud-operator/components/cli"
"git.indie.host/nextcloud-operator/components/common"
cron "git.indie.host/nextcloud-operator/components/cron"
"git.indie.host/nextcloud-operator/components/web"
"git.indie.host/nextcloud-operator/util"
oplib "github.com/redhat-cop/operator-utils/pkg/util"
)
// NextcloudReconciler reconciles a Nextcloud object
type NextcloudReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Recorder record.EventRecorder
Log logr.Logger
application.ReconcilerBase
}
func ignoreNotFound(err error) error {
......@@ -52,21 +46,19 @@ func ignoreNotFound(err error) error {
return err
}
func (r *NextcloudReconciler) GetClient() client.Client { return r.Client }
func (r *NextcloudReconciler) GetScheme() *runtime.Scheme { return r.Scheme }
func (r *NextcloudReconciler) GetRecorder() record.EventRecorder { return r.Recorder }
func (r *NextcloudReconciler) GetLogger() logr.Logger { return r.Log }
func (r *NextcloudReconciler) GetLogger() logr.Logger { return r.Log }
// +kubebuilder:rbac:groups=apps.libre.sh,resources=nextclouds,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=apps.libre.sh,resources=nextclouds/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=batch,resources=jobs/status,verbs=get
func (r *NextcloudReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("nextcloud", req.NamespacedName)
log.Info("reconciling")
app := &appsv1beta1.Nextcloud{}
if err := r.Get(ctx, req.NamespacedName, app); err != nil {
app := &appsv1alpha1.Nextcloud{}
if err := r.GetClient().Get(ctx, req.NamespacedName, app); err != nil {
log.Error(err, "unable to fetch Nextcloud")
// we'll ignore not-found errors, since they can't be fixed by an immediate
// requeue (we'll need to wait for a new notification), and we can get them
......@@ -74,61 +66,84 @@ func (r *NextcloudReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
return ctrl.Result{}, ignoreNotFound(err)
}
// var phase appsv1beta1.Phase
// Initiatilize & Defaults
app.Init()
app.SetDefaultMeta()
app.SetDefaults()
// Create and Init Settings
sett, err := application.CreateAndInitSettings(app, r)
phase, err := util.GetAppPhase(app.Status, app.Spec.Version)
if err != nil {
return ctrl.Result{}, err
}
fmt.Println(phase)
common := common.CreateAndInit(app)
// Init Components
cpts := app.GetComponents()
application.InitComponentsFromSettings(cpts, sett)
componentApp := application.CreateAndInit(common)
componentCron := cron.CreateAndInit(common)
componentWeb := web.CreateAndInit(common)
componentCLI := cli.CreateAndInit(common)
// Syncers
syncers := make(map[string]map[int]syncer.Interface)
settingsSyncers := make(map[int]syncer.Interface)
syncers["settings"] = settingsSyncers
appSyncers := []syncer.Interface{
componentApp.NewSecretSyncer(r),
componentApp.NewDeploymentSyncer(r),
componentApp.NewServiceSyncer(r),
// Settings Object Syncers
for _, s := range sett {
for k, obj := range s.GetObjects() {
settingsSyncers[k] = objects.NewObjectSyncer(obj, app, r)
}
}
cronSyncers := []syncer.Interface{
componentCron.NewCronJobSyncer(r),
}
// Migration, installer or upgrader component
var phase appsv1alpha1.Phase
webSyncers := []syncer.Interface{
componentWeb.NewConfigMapSyncer(r),
componentWeb.NewDeploymentSyncer(r),
componentWeb.NewIngressSyncer(r),
componentWeb.NewServiceSyncer(r),
phase, err = util.GetAppPhase(app.Status, app.Spec.Version)
if err != nil {
return ctrl.Result{}, err
}
err = r.sync(appSyncers)
err = r.sync(cronSyncers)
switch phase {
case appsv1alpha1.PhaseInstalling:
cpts["cli"].(*appsv1alpha1.CLI).Job.Args = []string{"install"}
fmt.Println(cpts["cli"].(*appsv1alpha1.CLI).Job.Args)
case appsv1alpha1.PhaseUpgrading:
cpts["cli"].(*appsv1alpha1.CLI).Job.Args = []string{"upgrade"}
default:
delete(cpts, "cli")
}
if phase == appsv1beta1.PhaseInstalling || phase == appsv1beta1.PhaseRunning {
jobSyncers := []syncer.Interface{
componentCLI.NewJobSyncer(r),
}
// Components Object Syncers
for _, c := range cpts {
syncers[c.GetComponent()] = application.NewObjectSyncersFromComponent(c, r, app)
err = r.sync(jobSyncers)
}
err = r.sync(webSyncers)
cptsOrder := app.GetComponentsSyncOrder()
err = application.Sync(ctx, r, syncers, cptsOrder)
if err != nil {
return ctrl.Result{}, err
}
settingsStatus := appsv1alpha1.SettingsStatus{}
if app.Status.Settings == nil {
app.Status.Settings = make(map[string]appsv1alpha1.SettingsStatus)
}
for _, s := range sett {
// Update Status
if len(s.GetConfig().GetSources()) > 0 {
settingsStatus.Sources = s.GetConfig().GetSources()
app.Status.Settings[s.GetMeta().GetComponent()] = settingsStatus
}
}
// Reconcile status
app.Status.Version = app.Spec.Version
app.Status.Phase = appsv1beta1.PhaseRunning
app.Status.Phase = appsv1alpha1.PhaseRunning
oldStatus := app.Status.DeepCopy()
if oldStatus != &app.Status {
if err := r.Status().Update(ctx, app); err != nil {
if err := r.GetClient().Status().Update(ctx, app); err != nil {
return ctrl.Result{}, err
}
}
......@@ -137,16 +152,10 @@ func (r *NextcloudReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
}
func (r *NextcloudReconciler) SetupWithManager(mgr ctrl.Manager) error {
dep := &appsv1.Deployment{}
return ctrl.NewControllerManagedBy(mgr).
For(&appsv1beta1.Nextcloud{}).
For(&appsv1alpha1.Nextcloud{}).
Owns(dep).
WithEventFilter(oplib.ResourceGenerationOrFinalizerChangedPredicate{}).
Complete(r)
}
func (r *NextcloudReconciler) sync(syncers []syncer.Interface) error {
for _, s := range syncers {
if err := syncer.Sync(context.TODO(), s, r.Recorder); err != nil {
return err
}
}
return nil
}
......@@ -22,11 +22,12 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
appsv1beta1 "git.indie.host/nextcloud-operator/api/v1beta1"
appsv1alpha1 "git.indie.host/operators/nextcloud-operator/api/v1alpha1"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
// +kubebuilder:scaffold:imports
......@@ -44,7 +45,7 @@ func TestAPIs(t *testing.T) {
RunSpecsWithDefaultAndCustomReporters(t,
"Controller Suite",
[]Reporter{envtest.NewlineReporter{}})
[]Reporter{printer.NewlineReporter{}})
}
var _ = BeforeSuite(func(done Done) {
......@@ -60,7 +61,7 @@ var _ = BeforeSuite(func(done Done) {
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
err = appsv1beta1.AddToScheme(scheme.Scheme)
err = appsv1alpha1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
// +kubebuilder:scaffold:scheme
......
module git.indie.host/nextcloud-operator
module git.indie.host/operators/nextcloud-operator
go 1.13
require (
github.com/go-logr/logr v0.1.0
github.com/hashicorp/go-version v1.2.0
github.com/imdario/mergo v0.3.8
github.com/onsi/ginkgo v1.10.2
github.com/onsi/gomega v1.7.0
github.com/presslabs/controller-util v0.2.0
k8s.io/api v0.17.0
k8s.io/apiextensions-apiserver v0.0.0 // indirect
k8s.io/apimachinery v0.17.0
k8s.io/client-go v0.17.0
sigs.k8s.io/controller-runtime v0.4.0
github.com/onsi/ginkgo v1.12.0
github.com/onsi/gomega v1.9.0
github.com/presslabs/controller-util v0.2.2
github.com/redhat-cop/operator-utils v0.2.4
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect
k8s.io/api v0.18.2
k8s.io/apimachinery v0.18.2
k8s.io/client-go v12.0.0+incompatible
k8s.libre.sh v0.0.0-20200512221307-33a77e4357d3
sigs.k8s.io/controller-runtime v0.6.0
)
replace (
k8s.io/api => k8s.io/api v0.17.0
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.17.0
k8s.io/apimachinery => k8s.io/apimachinery v0.17.0
k8s.io/apiserver => k8s.io/apiserver v0.17.0
k8s.io/cli-runtime => k8s.io/cli-runtime v0.17.0
k8s.io/client-go => k8s.io/client-go v0.17.0
k8s.io/cloud-provider => k8s.io/cloud-provider v0.17.0
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.17.0
k8s.io/code-generator => k8s.io/code-generator v0.17.0
k8s.io/component-base => k8s.io/component-base v0.17.0
k8s.io/cri-api => k8s.io/cri-api v0.17.0
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.17.0
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.17.0
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.17.0
k8s.io/kube-proxy => k8s.io/kube-proxy v0.17.0
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.17.0
k8s.io/kubectl => k8s.io/kubectl v0.17.0
k8s.io/kubelet => k8s.io/kubelet v0.17.0
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.17.0
k8s.io/metrics => k8s.io/metrics v0.17.0
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.17.0
)
replace git.indie.host/operators/nextcloud-operator => ./
replace k8s.libre.sh => ./../application/
replace k8s.io/client-go => k8s.io/client-go v0.18.2
This diff is collapsed.
/*
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 interfaces
import (
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Reconcile is the interface for Reconcile object structs . This
// interface can be used to pass around Reconcile structs commonly
// used in Operators.
//
// Note however that by default Reconcile structs generated using
// Operator SDK do not implement this interface. Add following
// functions to implement this interface.
//
// func (r *ReconcileObject) GetClient() client.Client { return r.client }
// func (r *ReconcileObject) GetScheme() *runtime.Scheme { return r.scheme }
// func (r *ReconcileObject) GetScheme() *runtime.Recorder { return r.recorder }
//
// The Reconcile object structs must implement this interface to use
// Operatorlib functions.
type Reconcile interface {
// Getter function for reconcile client
GetClient() client.Client
// Getter function for reconcile Scheme
GetScheme() *runtime.Scheme
// Getter function for reconcile Scheme
GetRecorder() record.EventRecorder
// Getter function for reconcile Scheme
//GetLogger() logr.Logger
}
// Object is the interface which all Kubernetes objects
// implements. This interface can be used to pass around any
// Kubernetes Object. This helps keep the functions more generic and
// less tied to the specific Objects.
type Object interface {
// The object needs to implement Meta Object interface from API
// machinery. This interface is used for various Client operations
// on Kubernetes objects.
metav1.Object
// The object needs to implement Runtime Object interface from API
// machinery.
runtime.Object
}
type EnvSource interface {
GetLocalObjectReference() corev1.LocalObjectReference
GetValue() string
GetKey() string
}
......@@ -19,12 +19,14 @@ import (
"flag"
"os"
appsv1beta1 "git.indie.host/nextcloud-operator/api/v1beta1"
"git.indie.host/nextcloud-operator/controllers"
appsv1alpha1 "git.indie.host/operators/nextcloud-operator/api/v1alpha1"
"git.indie.host/operators/nextcloud-operator/controllers"
batchv1 "k8s.io/api/batch/v1"
networking "k8s.io/api/networking/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"k8s.libre.sh/application"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
// +kubebuilder:scaffold:imports
......@@ -35,17 +37,19 @@ var (
setupLog = ctrl.Log.WithName("setup")
)
const controllerName = "nextcloud-controller"
func init() {
_ = clientgoscheme.AddToScheme(scheme)
_ = appsv1beta1.AddToScheme(scheme)
_ = appsv1alpha1.AddToScheme(scheme)
_ = networking.AddToScheme(scheme)
_ = batchv1.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
// _ = appsv1.AddToScheme(scheme)
// _ = corev1.AddToScheme(scheme)
// _ = extv1beta1.AddToScheme(scheme)
// _ = batchv1beta1.AddToScheme(scheme)
// _ = batchv1.AddToScheme(scheme)
// _ = extv1alpha1.AddToScheme(scheme)
// _ = batchv1alpha1.AddToScheme(scheme)
// _ = monitoringv1.AddToScheme(scheme)
}
......@@ -74,9 +78,9 @@ func main() {
}
if err = (&controllers.NextcloudReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Nextcloud"),
Scheme: mgr.GetScheme(),
// ReconcilerBase: oplibutil.NewReconcilerBase(mgr.GetClient(), mgr.GetScheme(), mgr.GetConfig(), mgr.GetEventRecorderFor(controllerName)),
ReconcilerBase: application.NewReconcilerBase(mgr.GetClient(), mgr.GetScheme(), mgr.GetConfig(), mgr.GetEventRecorderFor(controllerName)),
Log: ctrl.Log.WithName("controllers").WithName("Nextcloud"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Nextcloud")
os.Exit(1)
......
package util
import (
appsv1beta1 "git.indie.host/nextcloud-operator/api/v1beta1"
appsv1alpha1 "git.indie.host/operators/nextcloud-operator/api/v1alpha1"
version "github.com/hashicorp/go-version"
)
//. TOFIX get install status and desired status, if status =! nil ??
func GetAppPhase(status appsv1beta1.NextcloudStatus, desiredVersion string) (appsv1beta1.Phase, error) {
func GetAppPhase(status appsv1alpha1.NextcloudStatus, desiredVersion string) (appsv1alpha1.Phase, error) {
// get nextcloud installed version in status
if len(status.Version) == 0 {
return appsv1beta1.PhaseInstalling, nil
return appsv1alpha1.PhaseInstalling, nil
}
v1, err := version.NewVersion(status.Version)
// get nextcloud desired version in spec
v2, err := version.NewVersion(desiredVersion)
if err != nil {
return appsv1beta1.PhaseFailed, err
return appsv1alpha1.PhaseFailed, err
}
// compare current version from status with desired from spec
c := v1.Compare(v2)
switch {
// current version is greater than desired, no downgrade
case c == 1:
return appsv1beta1.PhaseFailed, nil
return appsv1alpha1.PhaseFailed, nil
// current version lower than desired, upgrade job
case c == -1:
return appsv1beta1.PhaseUpgrading, nil
return appsv1alpha1.PhaseUpgrading, nil
// current version and desired are the same, normal start
case c == 0:
return appsv1beta1.PhaseCreating, nil
return appsv1alpha1.PhaseCreating, nil
}
return appsv1beta1.PhaseNone, nil
return appsv1alpha1.PhaseNone, nil
}