operator-sdk init --domain=seaweedfs.com

This commit is contained in:
Chris Lu 2020-10-14 19:51:59 -07:00
parent fe54fbbaa4
commit 45d81b6928
32 changed files with 0 additions and 1745 deletions

View File

@ -1,10 +1,6 @@
domain: seaweedfs.com
layout: go.kubebuilder.io/v2
repo: github.com/seaweedfs/seaweedfs-operator
resources:
- group: seaweed
kind: Seaweed
version: v1
version: 3-alpha
plugins:
go.operator-sdk.io/v2-alpha: {}

View File

@ -1,22 +0,0 @@
# SeaweedFS Operator
## Installation
## Development
Follow the instructions in https://sdk.operatorframework.io/docs/building-operators/golang/quickstart/
```
$ git clone https://github.com/seaweedfs/seaweedfs-operator
$ cd seaweedfs-operator
# register the CRD with the Kubernetes
$ make install
# run the operator locally outside the Kubernetes cluster
$ make run ENABLE_WEBHOOKS=false
# From another terminal in the same directory
$ kubectl apply -f config/samples/seaweed_v1_seaweed.yaml
```

View File

@ -1,36 +0,0 @@
/*
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 v1 contains API Schema definitions for the seaweed v1 API group
// +kubebuilder:object:generate=true
// +groupName=seaweed.seaweedfs.com
package v1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "seaweed.seaweedfs.com", Version: "v1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)

View File

@ -1,73 +0,0 @@
/*
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 v1
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.
// SeaweedSpec defines the desired state of Seaweed
type SeaweedSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// MetricsAddress is Prometheus gateway address
MetricsAddress string `json:"metricsAddress,omitempty"`
// VolumeServerCount is the number of volume servers, default to 1
VolumeServerCount int `json:"volumeServerCount,omitempty"`
// FilerCount is the number of filers, default to 1
FilerCount int `json:"filerCount,omitempty"`
// S3Count is the number of s3, default to 1
S3Count int `json:"s3Count,omitempty"`
}
// SeaweedStatus defines the observed state of Seaweed
type SeaweedStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
}
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// Seaweed is the Schema for the seaweeds API
type Seaweed struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec SeaweedSpec `json:"spec,omitempty"`
Status SeaweedStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// SeaweedList contains a list of Seaweed
type SeaweedList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Seaweed `json:"items"`
}
func init() {
SchemeBuilder.Register(&Seaweed{}, &SeaweedList{})
}

View File

@ -1,114 +0,0 @@
// +build !ignore_autogenerated
/*
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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Seaweed) DeepCopyInto(out *Seaweed) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
out.Status = in.Status
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Seaweed.
func (in *Seaweed) DeepCopy() *Seaweed {
if in == nil {
return nil
}
out := new(Seaweed)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Seaweed) 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 *SeaweedList) DeepCopyInto(out *SeaweedList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Seaweed, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeaweedList.
func (in *SeaweedList) DeepCopy() *SeaweedList {
if in == nil {
return nil
}
out := new(SeaweedList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *SeaweedList) 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 *SeaweedSpec) DeepCopyInto(out *SeaweedSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeaweedSpec.
func (in *SeaweedSpec) DeepCopy() *SeaweedSpec {
if in == nil {
return nil
}
out := new(SeaweedSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SeaweedStatus) DeepCopyInto(out *SeaweedStatus) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeaweedStatus.
func (in *SeaweedStatus) DeepCopy() *SeaweedStatus {
if in == nil {
return nil
}
out := new(SeaweedStatus)
in.DeepCopyInto(out)
return out
}

View File

@ -1,67 +0,0 @@
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.3.0
creationTimestamp: null
name: seaweeds.seaweed.seaweedfs.com
spec:
group: seaweed.seaweedfs.com
names:
kind: Seaweed
listKind: SeaweedList
plural: seaweeds
singular: seaweed
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
description: Seaweed is the Schema for the seaweeds 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: SeaweedSpec defines the desired state of Seaweed
properties:
filerCount:
description: FilerCount is the number of filers, default to 1
type: integer
metricsAddress:
description: MetricsAddress is Prometheus gateway address
type: string
s3Count:
description: S3Count is the number of s3, default to 1
type: integer
volumeServerCount:
description: VolumeServerCount is the number of volume servers, default
to 1
type: integer
type: object
status:
description: SeaweedStatus defines the observed state of Seaweed
type: object
type: object
version: v1
versions:
- name: v1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -1,21 +0,0 @@
# This kustomization.yaml is not intended to be run by itself,
# since it depends on service name and namespace that are out of this kustomize package.
# It should be run by config/default
resources:
- bases/seaweed.seaweedfs.com_seaweeds.yaml
# +kubebuilder:scaffold:crdkustomizeresource
patchesStrategicMerge:
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
# patches here are for enabling the conversion webhook for each CRD
#- patches/webhook_in_seaweeds.yaml
# +kubebuilder:scaffold:crdkustomizewebhookpatch
# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
# patches here are for enabling the CA injection for each CRD
#- patches/cainjection_in_seaweeds.yaml
# +kubebuilder:scaffold:crdkustomizecainjectionpatch
# the following config is for teaching kustomize how to do kustomization for CRDs.
configurations:
- kustomizeconfig.yaml

View File

@ -1,17 +0,0 @@
# This file is for teaching kustomize how to substitute name and namespace reference in CRD
nameReference:
- kind: Service
version: v1
fieldSpecs:
- kind: CustomResourceDefinition
group: apiextensions.k8s.io
path: spec/conversion/webhookClientConfig/service/name
namespace:
- kind: CustomResourceDefinition
group: apiextensions.k8s.io
path: spec/conversion/webhookClientConfig/service/namespace
create: false
varReference:
- path: metadata/annotations

View File

@ -1,8 +0,0 @@
# 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: seaweeds.seaweed.seaweedfs.com

View File

@ -1,17 +0,0 @@
# 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: seaweeds.seaweed.seaweedfs.com
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

View File

@ -1,28 +0,0 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
- seaweed.seaweedfs.com
resources:
- seaweeds
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- seaweed.seaweedfs.com
resources:
- seaweeds/status
verbs:
- get
- patch
- update

View File

@ -1,24 +0,0 @@
# permissions for end users to edit seaweeds.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: seaweed-editor-role
rules:
- apiGroups:
- seaweed.seaweedfs.com
resources:
- seaweeds
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- seaweed.seaweedfs.com
resources:
- seaweeds/status
verbs:
- get

View File

@ -1,20 +0,0 @@
# permissions for end users to view seaweeds.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: seaweed-viewer-role
rules:
- apiGroups:
- seaweed.seaweedfs.com
resources:
- seaweeds
verbs:
- get
- list
- watch
- apiGroups:
- seaweed.seaweedfs.com
resources:
- seaweeds/status
verbs:
- get

View File

@ -1,3 +0,0 @@
## This file is auto-generated, do not modify ##
resources:
- seaweed_v1_seaweed.yaml

View File

@ -1,7 +0,0 @@
apiVersion: seaweed.seaweedfs.com/v1
kind: Seaweed
metadata:
name: seaweed1
spec:
# Add fields here
foo: bar

View File

@ -1,82 +0,0 @@
package controllers
import (
"context"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) ensureFilerServers(seaweedCR *seaweedv1.Seaweed) (done bool, result ctrl.Result, err error) {
_ = context.Background()
_ = r.Log.WithValues("seaweed", seaweedCR.Name)
if done, result, err = r.ensureFilerStatefulSet(seaweedCR); done {
return done, result, err
}
if done, result, err = r.ensureFilerService(seaweedCR); done {
return done, result, err
}
return false, ctrl.Result{}, nil
}
func (r *SeaweedReconciler) ensureFilerStatefulSet(seaweedCR *seaweedv1.Seaweed) (bool, ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("sw-filer-statefulset", seaweedCR.Name)
filerStatefulSet := &appsv1.StatefulSet{}
err := r.Get(ctx, types.NamespacedName{Name: seaweedCR.Name + "-filer", Namespace: seaweedCR.Namespace}, filerStatefulSet)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.createFilerStatefulSet(seaweedCR)
log.Info("Creating a new filer statefulset", "Namespace", dep.Namespace, "Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create new filer statefulset", "Namespace", dep.Namespace, "Name", dep.Name)
return true, ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
return false, ctrl.Result{}, nil
} else if err != nil {
log.Error(err, "Failed to get filer statefulset")
return true, ctrl.Result{}, err
}
log.Info("Get filer stateful set " + filerStatefulSet.Name)
return false, ctrl.Result{}, nil
}
func (r *SeaweedReconciler) ensureFilerService(seaweedCR *seaweedv1.Seaweed) (bool, ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("sw-filer-service", seaweedCR.Name)
volumeServerService := &corev1.Service{}
err := r.Get(ctx, types.NamespacedName{Name: seaweedCR.Name + "-filer", Namespace: seaweedCR.Namespace}, volumeServerService)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.createFilerService(seaweedCR)
log.Info("Creating a new filer service", "Namespace", dep.Namespace, "Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create new filer service", "Namespace", dep.Namespace, "Name", dep.Name)
return true, ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
return false, ctrl.Result{}, nil
} else if err != nil {
log.Error(err, "Failed to get filer server service")
return true, ctrl.Result{}, err
}
log.Info("Get filer service " + volumeServerService.Name)
return false, ctrl.Result{}, nil
}
func labelsForFiler(name string) map[string]string {
return map[string]string{"app": "seaweedfs", "role": "filer", "name": name}
}

View File

@ -1,50 +0,0 @@
package controllers
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) createFilerService(m *seaweedv1.Seaweed) *corev1.Service {
labels := labelsForFiler(m.Name)
dep := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name + "-filer",
Namespace: m.Namespace,
Labels: labels,
Annotations: map[string]string{
"service.alpha.kubernetes.io/tolerate-unready-endpoints": "true",
},
},
Spec: corev1.ServiceSpec{
ClusterIP: "None",
PublishNotReadyAddresses: true,
Ports: []corev1.ServicePort{
{
Name: "swfs-filer",
Protocol: corev1.Protocol("TCP"),
Port: 8888,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 8888,
},
},
{
Name: "swfs-volume-grpc",
Protocol: corev1.Protocol("TCP"),
Port: 18888,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 18888,
},
},
},
Selector: labels,
},
}
return dep
}

View File

@ -1,134 +0,0 @@
package controllers
import (
"fmt"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) createFilerStatefulSet(m *seaweedv1.Seaweed) *appsv1.StatefulSet {
labels := labelsForFiler(m.Name)
replicas := int32(m.Spec.FilerCount)
rollingUpdatePartition := int32(0)
enableServiceLinks := false
dep := &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name + "-filer",
Namespace: m.Namespace,
},
Spec: appsv1.StatefulSetSpec{
ServiceName: m.Name + "-filer",
PodManagementPolicy: appsv1.ParallelPodManagement,
Replicas: &replicas,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
Partition: &rollingUpdatePartition,
},
},
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
EnableServiceLinks: &enableServiceLinks,
Containers: []corev1.Container{{
Name: "seaweedfs",
Image: "chrislusf/seaweedfs:latest",
ImagePullPolicy: corev1.PullIfNotPresent,
Env: []corev1.EnvVar{
{
Name: "POD_IP",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "status.podIP",
},
},
},
{
Name: "POD_NAME",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.name",
},
},
},
{
Name: "NAMESPACE",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.namespace",
},
},
},
},
Command: []string{
"/bin/sh",
"-ec",
fmt.Sprintf("weed filer -port=8888 %s %s",
fmt.Sprintf("-ip=$(POD_NAME).%s-filer", m.Name),
fmt.Sprintf("-peers=%s-master-0.%s-master:9333,%s-master-1.%s-master:9333,%s-master-2.%s-master:9333",
m.Name, m.Name, m.Name, m.Name, m.Name, m.Name),
),
},
Ports: []corev1.ContainerPort{
{
ContainerPort: 8888,
Name: "swfs-filer",
},
{
ContainerPort: 18888,
},
},
/*
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/cluster/status",
Port: intstr.IntOrString{
Type: 0,
IntVal: 9333,
},
Scheme: "http",
},
},
InitialDelaySeconds: 5,
TimeoutSeconds: 0,
PeriodSeconds: 15,
SuccessThreshold: 2,
FailureThreshold: 100,
},
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/cluster/status",
Port: intstr.IntOrString{
Type: 0,
IntVal: 9333,
},
Scheme: "http",
},
},
InitialDelaySeconds: 20,
TimeoutSeconds: 0,
PeriodSeconds: 10,
SuccessThreshold: 1,
FailureThreshold: 6,
},
*/
}},
},
},
},
}
return dep
}

View File

@ -1,90 +0,0 @@
package controllers
import (
"context"
"time"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
const (
MasterClusterSize = 3
)
func (r *SeaweedReconciler) ensureMaster(seaweedCR *seaweedv1.Seaweed) (done bool, result ctrl.Result, err error) {
_ = context.Background()
_ = r.Log.WithValues("seaweed", seaweedCR.Name)
if done, result, err = r.ensureMasterService(seaweedCR); done {
return done, result, err
}
if done, result, err = r.ensureMasterStatefulSet(seaweedCR); done {
return done, result, err
}
return false, ctrl.Result{}, nil
}
func (r *SeaweedReconciler) ensureMasterStatefulSet(seaweedCR *seaweedv1.Seaweed) (bool, ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("sw-master-statefulset", seaweedCR.Name)
masterStatefulSet := &appsv1.StatefulSet{}
err := r.Get(ctx, types.NamespacedName{Name: seaweedCR.Name + "-master", Namespace: seaweedCR.Namespace}, masterStatefulSet)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.createMasterStatefulSet(seaweedCR)
log.Info("Creating a new master statefulset", "Namespace", dep.Namespace, "Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create new statefulset", "Namespace", dep.Namespace, "Name", dep.Name)
return true, ctrl.Result{}, err
}
// sleep 60 seconds for DNS to have pod IP addresses ready
time.Sleep(time.Minute)
// Deployment created successfully - return and requeue
return false, ctrl.Result{}, nil
} else if err != nil {
log.Error(err, "Failed to get Deployment")
return true, ctrl.Result{}, err
}
log.Info("Get master stateful set " + masterStatefulSet.Name)
return false, ctrl.Result{}, nil
}
func (r *SeaweedReconciler) ensureMasterService(seaweedCR *seaweedv1.Seaweed) (bool, ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("sw-master-service", seaweedCR.Name)
masterService := &corev1.Service{}
err := r.Get(ctx, types.NamespacedName{Name: seaweedCR.Name + "-master", Namespace: seaweedCR.Namespace}, masterService)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.createMasterService(seaweedCR)
log.Info("Creating a new master service", "Namespace", dep.Namespace, "Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create master service", "Namespace", dep.Namespace, "Name", dep.Name)
return true, ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
return false, ctrl.Result{}, nil
} else if err != nil {
log.Error(err, "Failed to get master service", "Namespace", seaweedCR.Namespace, "Name", seaweedCR.Name+"-master")
return true, ctrl.Result{}, err
}
log.Info("Get master service " + masterService.Name)
return false, ctrl.Result{}, nil
}
func labelsForMaster(name string) map[string]string {
return map[string]string{"app": "seaweedfs", "role": "master", "name": name}
}

View File

@ -1,52 +0,0 @@
package controllers
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) createMasterService(m *seaweedv1.Seaweed) *corev1.Service {
labels := labelsForMaster(m.Name)
dep := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name + "-master",
Namespace: m.Namespace,
Labels: labels,
Annotations: map[string]string{
"service.alpha.kubernetes.io/tolerate-unready-endpoints": "true",
},
},
Spec: corev1.ServiceSpec{
ClusterIP: "None",
PublishNotReadyAddresses: true,
Ports: []corev1.ServicePort{
{
Name: "swfs-master",
Protocol: corev1.Protocol("TCP"),
Port: 9333,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 9333,
},
},
{
Name: "swfs-master-grpc",
Protocol: corev1.Protocol("TCP"),
Port: 19333,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 19333,
},
},
},
Selector: labels,
},
}
// Set master instance as the owner and controller
// ctrl.SetControllerReference(m, dep, r.Scheme)
return dep
}

View File

@ -1,150 +0,0 @@
package controllers
import (
"fmt"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) createMasterStatefulSet(m *seaweedv1.Seaweed) *appsv1.StatefulSet {
labels := labelsForMaster(m.Name)
replicas := int32(MasterClusterSize)
rollingUpdatePartition := int32(0)
enableServiceLinks := false
dep := &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name + "-master",
Namespace: m.Namespace,
},
Spec: appsv1.StatefulSetSpec{
ServiceName: m.Name + "-master",
PodManagementPolicy: appsv1.ParallelPodManagement,
Replicas: &replicas,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
Partition: &rollingUpdatePartition,
},
},
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
/*
Affinity: &corev1.Affinity{
PodAntiAffinity: &corev1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: labels,
},
TopologyKey: "kubernetes.io/hostname",
},
},
},
},
*/
EnableServiceLinks: &enableServiceLinks,
Containers: []corev1.Container{{
Name: "seaweedfs",
Image: "chrislusf/seaweedfs:latest",
ImagePullPolicy: corev1.PullIfNotPresent,
Env: []corev1.EnvVar{
{
Name: "POD_IP",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "status.podIP",
},
},
},
{
Name: "POD_NAME",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.name",
},
},
},
{
Name: "NAMESPACE",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.namespace",
},
},
},
},
Command: []string{
"/bin/sh",
"-ec",
fmt.Sprintf("sleep 60; weed master -volumePreallocate -volumeSizeLimitMB=1000 %s %s",
fmt.Sprintf("-ip=$(POD_NAME).%s-master", m.Name),
fmt.Sprintf("-peers=%s-master-0.%s-master:9333,%s-master-1.%s-master:9333,%s-master-2.%s-master:9333",
m.Name, m.Name, m.Name, m.Name, m.Name, m.Name),
),
},
Ports: []corev1.ContainerPort{
{
ContainerPort: 9333,
Name: "swfs-master",
},
{
ContainerPort: 19333,
},
},
/*
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/cluster/status",
Port: intstr.IntOrString{
Type: 0,
IntVal: 9333,
},
Scheme: "http",
},
},
InitialDelaySeconds: 5,
TimeoutSeconds: 0,
PeriodSeconds: 15,
SuccessThreshold: 2,
FailureThreshold: 100,
},
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/cluster/status",
Port: intstr.IntOrString{
Type: 0,
IntVal: 9333,
},
Scheme: "http",
},
},
InitialDelaySeconds: 20,
TimeoutSeconds: 0,
PeriodSeconds: 10,
SuccessThreshold: 1,
FailureThreshold: 6,
},
*/
}},
},
},
},
}
// Set master instance as the owner and controller
// ctrl.SetControllerReference(m, dep, r.Scheme)
return dep
}

View File

@ -1,82 +0,0 @@
package controllers
import (
"context"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) ensureS3Servers(seaweedCR *seaweedv1.Seaweed) (done bool, result ctrl.Result, err error) {
_ = context.Background()
_ = r.Log.WithValues("seaweed", seaweedCR.Name)
if done, result, err = r.ensureS3Deployment(seaweedCR); done {
return done, result, err
}
if done, result, err = r.ensureS3Service(seaweedCR); done {
return done, result, err
}
return false, ctrl.Result{}, nil
}
func (r *SeaweedReconciler) ensureS3Deployment(seaweedCR *seaweedv1.Seaweed) (bool, ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("sw-s3-statefulset", seaweedCR.Name)
s3Deployment := &appsv1.Deployment{}
err := r.Get(ctx, types.NamespacedName{Name: seaweedCR.Name + "-s3", Namespace: seaweedCR.Namespace}, s3Deployment)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.createS3Deployment(seaweedCR)
log.Info("Creating a new s3 deployment", "Namespace", dep.Namespace, "Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create new s3 statefulset", "Namespace", dep.Namespace, "Name", dep.Name)
return true, ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
return false, ctrl.Result{}, nil
} else if err != nil {
log.Error(err, "Failed to get s3 statefulset")
return true, ctrl.Result{}, err
}
log.Info("Get s3 stateful set " + s3Deployment.Name)
return false, ctrl.Result{}, nil
}
func (r *SeaweedReconciler) ensureS3Service(seaweedCR *seaweedv1.Seaweed) (bool, ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("sw-filer-service", seaweedCR.Name)
s3Service := &corev1.Service{}
err := r.Get(ctx, types.NamespacedName{Name: seaweedCR.Name + "-s3", Namespace: seaweedCR.Namespace}, s3Service)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.createS3Service(seaweedCR)
log.Info("Creating a new s3 service", "Namespace", dep.Namespace, "Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create new s3 service", "Namespace", dep.Namespace, "Name", dep.Name)
return true, ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
return false, ctrl.Result{}, nil
} else if err != nil {
log.Error(err, "Failed to get s3 server service")
return true, ctrl.Result{}, err
}
log.Info("Get s3 service " + s3Service.Name)
return false, ctrl.Result{}, nil
}
func labelsForS3(name string) map[string]string {
return map[string]string{"app": "seaweedfs", "role": "s3", "name": name}
}

View File

@ -1,123 +0,0 @@
package controllers
import (
"fmt"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) createS3Deployment(m *seaweedv1.Seaweed) *appsv1.Deployment {
labels := labelsForS3(m.Name)
replicas := int32(m.Spec.S3Count)
enableServiceLinks := false
dep := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name + "-s3",
Namespace: m.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
EnableServiceLinks: &enableServiceLinks,
Containers: []corev1.Container{{
Name: "seaweedfs",
Image: "chrislusf/seaweedfs:latest",
ImagePullPolicy: corev1.PullIfNotPresent,
Env: []corev1.EnvVar{
{
Name: "POD_IP",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "status.podIP",
},
},
},
{
Name: "POD_NAME",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.name",
},
},
},
{
Name: "NAMESPACE",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.namespace",
},
},
},
},
Command: []string{
"/bin/sh",
"-ec",
fmt.Sprintf("weed s3 -port=8333 %s",
fmt.Sprintf("-filer=$(POD_NAME).%s-filer:8888", m.Name),
),
},
Ports: []corev1.ContainerPort{
{
ContainerPort: 8333,
Name: "swfs-s3",
},
{
ContainerPort: 18333,
},
},
/*
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/cluster/status",
Port: intstr.IntOrString{
Type: 0,
IntVal: 9333,
},
Scheme: "http",
},
},
InitialDelaySeconds: 5,
TimeoutSeconds: 0,
PeriodSeconds: 15,
SuccessThreshold: 2,
FailureThreshold: 100,
},
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/cluster/status",
Port: intstr.IntOrString{
Type: 0,
IntVal: 9333,
},
Scheme: "http",
},
},
InitialDelaySeconds: 20,
TimeoutSeconds: 0,
PeriodSeconds: 10,
SuccessThreshold: 1,
FailureThreshold: 6,
},
*/
}},
},
},
},
}
return dep
}

View File

@ -1,36 +0,0 @@
package controllers
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) createS3Service(m *seaweedv1.Seaweed) *corev1.Service {
labels := labelsForS3(m.Name)
dep := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name + "-s3",
Namespace: m.Namespace,
Labels: labels,
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Name: "swfs-s3",
Protocol: corev1.Protocol("TCP"),
Port: 8333,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 8333,
},
},
},
Selector: labels,
},
}
return dep
}

View File

@ -1,82 +0,0 @@
package controllers
import (
"context"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) ensureVolumeServers(seaweedCR *seaweedv1.Seaweed) (done bool, result ctrl.Result, err error) {
_ = context.Background()
_ = r.Log.WithValues("seaweed", seaweedCR.Name)
if done, result, err = r.ensureVolumeServerStatefulSet(seaweedCR); done {
return done, result, err
}
if done, result, err = r.ensureVolumeServerService(seaweedCR); done {
return done, result, err
}
return false, ctrl.Result{}, nil
}
func (r *SeaweedReconciler) ensureVolumeServerStatefulSet(seaweedCR *seaweedv1.Seaweed) (bool, ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("sw-volume-statefulset", seaweedCR.Name)
volumeServerStatefulSet := &appsv1.StatefulSet{}
err := r.Get(ctx, types.NamespacedName{Name: seaweedCR.Name + "-volume", Namespace: seaweedCR.Namespace}, volumeServerStatefulSet)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.createVolumeServerStatefulSet(seaweedCR)
log.Info("Creating a new volume statefulset", "Namespace", dep.Namespace, "Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create new volume statefulset", "Namespace", dep.Namespace, "Name", dep.Name)
return true, ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
return false, ctrl.Result{}, nil
} else if err != nil {
log.Error(err, "Failed to get volume server statefulset")
return true, ctrl.Result{}, err
}
log.Info("Get volume stateful set " + volumeServerStatefulSet.Name)
return false, ctrl.Result{}, nil
}
func (r *SeaweedReconciler) ensureVolumeServerService(seaweedCR *seaweedv1.Seaweed) (bool, ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("sw-volume-service", seaweedCR.Name)
volumeServerService := &corev1.Service{}
err := r.Get(ctx, types.NamespacedName{Name: seaweedCR.Name + "-volume", Namespace: seaweedCR.Namespace}, volumeServerService)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.createVolumeServerService(seaweedCR)
log.Info("Creating a new volume service", "Namespace", dep.Namespace, "Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create new volume service", "Namespace", dep.Namespace, "Name", dep.Name)
return true, ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
return false, ctrl.Result{}, nil
} else if err != nil {
log.Error(err, "Failed to get volume server service")
return true, ctrl.Result{}, err
}
log.Info("Get volume service " + volumeServerService.Name)
return false, ctrl.Result{}, nil
}
func labelsForVolumeServer(name string) map[string]string {
return map[string]string{"app": "seaweedfs", "role": "volume", "name": name}
}

View File

@ -1,50 +0,0 @@
package controllers
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) createVolumeServerService(m *seaweedv1.Seaweed) *corev1.Service {
labels := labelsForVolumeServer(m.Name)
dep := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name + "-volume",
Namespace: m.Namespace,
Labels: labels,
Annotations: map[string]string{
"service.alpha.kubernetes.io/tolerate-unready-endpoints": "true",
},
},
Spec: corev1.ServiceSpec{
ClusterIP: "None",
PublishNotReadyAddresses: true,
Ports: []corev1.ServicePort{
{
Name: "swfs-volume",
Protocol: corev1.Protocol("TCP"),
Port: 8444,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 8444,
},
},
{
Name: "swfs-volume-grpc",
Protocol: corev1.Protocol("TCP"),
Port: 18444,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 18444,
},
},
},
Selector: labels,
},
}
return dep
}

View File

@ -1,134 +0,0 @@
package controllers
import (
"fmt"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
func (r *SeaweedReconciler) createVolumeServerStatefulSet(m *seaweedv1.Seaweed) *appsv1.StatefulSet {
labels := labelsForVolumeServer(m.Name)
replicas := int32(m.Spec.VolumeServerCount)
rollingUpdatePartition := int32(0)
enableServiceLinks := false
dep := &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name + "-volume",
Namespace: m.Namespace,
},
Spec: appsv1.StatefulSetSpec{
ServiceName: m.Name + "-volume",
PodManagementPolicy: appsv1.ParallelPodManagement,
Replicas: &replicas,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
Partition: &rollingUpdatePartition,
},
},
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
EnableServiceLinks: &enableServiceLinks,
Containers: []corev1.Container{{
Name: "seaweedfs",
Image: "chrislusf/seaweedfs:latest",
ImagePullPolicy: corev1.PullIfNotPresent,
Env: []corev1.EnvVar{
{
Name: "POD_IP",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "status.podIP",
},
},
},
{
Name: "POD_NAME",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.name",
},
},
},
{
Name: "NAMESPACE",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.namespace",
},
},
},
},
Command: []string{
"/bin/sh",
"-ec",
fmt.Sprintf("weed volume -port=8444 -max=0 %s %s",
fmt.Sprintf("-ip=$(POD_NAME).%s-volume", m.Name),
fmt.Sprintf("-mserver=%s-master-0.%s-master:9333,%s-master-1.%s-master:9333,%s-master-2.%s-master:9333",
m.Name, m.Name, m.Name, m.Name, m.Name, m.Name),
),
},
Ports: []corev1.ContainerPort{
{
ContainerPort: 8444,
Name: "swfs-volume",
},
{
ContainerPort: 18444,
},
},
/*
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/cluster/status",
Port: intstr.IntOrString{
Type: 0,
IntVal: 9333,
},
Scheme: "http",
},
},
InitialDelaySeconds: 5,
TimeoutSeconds: 0,
PeriodSeconds: 15,
SuccessThreshold: 2,
FailureThreshold: 100,
},
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/cluster/status",
Port: intstr.IntOrString{
Type: 0,
IntVal: 9333,
},
Scheme: "http",
},
},
InitialDelaySeconds: 20,
TimeoutSeconds: 0,
PeriodSeconds: 10,
SuccessThreshold: 1,
FailureThreshold: 6,
},
*/
}},
},
},
},
}
return dep
}

View File

@ -1,107 +0,0 @@
/*
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"
"time"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
)
// SeaweedReconciler reconciles a Seaweed object
type SeaweedReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
}
// +kubebuilder:rbac:groups=seaweed.seaweedfs.com,resources=seaweeds,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=seaweed.seaweedfs.com,resources=seaweeds/status,verbs=get;update;patch
func (r *SeaweedReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("seaweed", req.NamespacedName)
log.Info("start Reconcile ...")
seaweedCR, done, result, err := r.findSeaweedCustomResourceInstance(ctx, log, req)
if done {
return result, err
}
// temporary
if seaweedCR.Spec.VolumeServerCount == 0 {
seaweedCR.Spec.VolumeServerCount = 1
}
if seaweedCR.Spec.FilerCount == 0 {
seaweedCR.Spec.FilerCount = 1
}
if seaweedCR.Spec.S3Count == 0 {
seaweedCR.Spec.S3Count = 1
}
if done, result, err = r.ensureMaster(seaweedCR); done {
return result, err
}
if done, result, err = r.ensureVolumeServers(seaweedCR); done {
return result, err
}
if done, result, err = r.ensureFilerServers(seaweedCR); done {
return result, err
}
if done, result, err = r.ensureS3Servers(seaweedCR); done {
return result, err
}
return ctrl.Result{}, nil
}
func (r *SeaweedReconciler) findSeaweedCustomResourceInstance(ctx context.Context, log logr.Logger, req ctrl.Request) (*seaweedv1.Seaweed, bool, ctrl.Result, error) {
// fetch the master instance
seaweedCR := &seaweedv1.Seaweed{}
err := r.Get(ctx, req.NamespacedName, seaweedCR)
if err != nil {
if errors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// Return and don't requeue
log.Info("Seaweed CR not found. Ignoring since object must be deleted")
return nil, true, ctrl.Result{RequeueAfter: time.Second * 5}, nil
}
// Error reading the object - requeue the request.
log.Error(err, "Failed to get SeaweedCR")
return nil, true, ctrl.Result{}, err
}
log.Info("Get master " + seaweedCR.Name)
return seaweedCR, false, ctrl.Result{}, nil
}
func (r *SeaweedReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&seaweedv1.Seaweed{}).
Complete(r)
}

View File

@ -1,81 +0,0 @@
/*
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 (
"path/filepath"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"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"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
// +kubebuilder:scaffold:imports
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t,
"Controller Suite",
[]Reporter{printer.NewlineReporter{}})
}
var _ = BeforeSuite(func(done Done) {
logf.SetLogger(zap.LoggerTo(GinkgoWriter, true))
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
}
var err error
cfg, err = testEnv.Start()
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
err = seaweedv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
// +kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient).ToNot(BeNil())
close(done)
}, 60)
var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).ToNot(HaveOccurred())
})

4
go.mod
View File

@ -3,10 +3,6 @@ module github.com/seaweedfs/seaweedfs-operator
go 1.13
require (
github.com/go-logr/logr v0.1.0
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
k8s.io/api v0.18.2
k8s.io/apimachinery v0.18.2
k8s.io/client-go v0.18.2
sigs.k8s.io/controller-runtime v0.6.0

12
main.go
View File

@ -26,9 +26,6 @@ import (
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
seaweedv1 "github.com/seaweedfs/seaweedfs-operator/api/v1"
"github.com/seaweedfs/seaweedfs-operator/controllers"
// +kubebuilder:scaffold:imports
)
@ -40,7 +37,6 @@ var (
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(seaweedv1.AddToScheme(scheme))
// +kubebuilder:scaffold:scheme
}
@ -67,14 +63,6 @@ func main() {
os.Exit(1)
}
if err = (&controllers.SeaweedReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Seaweed"),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Seaweed")
os.Exit(1)
}
// +kubebuilder:scaffold:builder
setupLog.Info("starting manager")

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="CheckStyle-IDEA-Module">
<option name="configuration">
<map />
</option>
</component>
<component name="Go" enabled="true" />
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>