diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 00000000..e7be5c67 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,604 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "cloud.google.com/go" + packages = ["compute/metadata"] + revision = "debcad1964693daf8ef4bc06292d7e828e075130" + version = "v0.31.0" + +[[projects]] + name = "github.com/PuerkitoBio/purell" + packages = ["."] + revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4" + version = "v1.1.0" + +[[projects]] + branch = "master" + name = "github.com/PuerkitoBio/urlesc" + packages = ["."] + revision = "de5bf2ad457846296e2031421a34e2568e304e35" + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" + version = "v1.1.1" + +[[projects]] + name = "github.com/emicklei/go-restful" + packages = [ + ".", + "log" + ] + revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0" + version = "v2.8.0" + +[[projects]] + name = "github.com/ghodss/yaml" + packages = ["."] + revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" + version = "v1.0.0" + +[[projects]] + branch = "master" + name = "github.com/go-logr/logr" + packages = ["."] + revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e" + +[[projects]] + branch = "master" + name = "github.com/go-logr/zapr" + packages = ["."] + revision = "7536572e8d55209135cd5e7ccf7fce43dca217ab" + +[[projects]] + name = "github.com/go-openapi/jsonpointer" + packages = ["."] + revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004" + version = "v0.17.1" + +[[projects]] + name = "github.com/go-openapi/jsonreference" + packages = ["."] + revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3" + version = "v0.17.1" + +[[projects]] + name = "github.com/go-openapi/spec" + packages = ["."] + revision = "5bae59e25b21498baea7f9d46e9c147ec106a42e" + version = "v0.17.1" + +[[projects]] + name = "github.com/go-openapi/swag" + packages = ["."] + revision = "5899d5c5e619fda5fa86e14795a835f473ca284c" + version = "v0.17.1" + +[[projects]] + name = "github.com/gogo/protobuf" + packages = [ + "proto", + "sortkeys" + ] + revision = "636bf0302bc95575d69441b25a2603156ffdddf1" + version = "v1.1.1" + +[[projects]] + branch = "master" + name = "github.com/golang/glog" + packages = ["."] + revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" + +[[projects]] + branch = "master" + name = "github.com/golang/groupcache" + packages = ["lru"] + revision = "6f2cf27854a4a29e3811b0371547be335d411b8b" + +[[projects]] + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp" + ] + revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" + version = "v1.2.0" + +[[projects]] + branch = "master" + name = "github.com/google/btree" + packages = ["."] + revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306" + +[[projects]] + branch = "master" + name = "github.com/google/gofuzz" + packages = ["."] + revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" + +[[projects]] + name = "github.com/google/uuid" + packages = ["."] + revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" + version = "v1.0.0" + +[[projects]] + name = "github.com/googleapis/gnostic" + packages = [ + "OpenAPIv2", + "compiler", + "extensions" + ] + revision = "7c663266750e7d82587642f65e60bc4083f1f84e" + version = "v0.2.0" + +[[projects]] + branch = "master" + name = "github.com/gregjones/httpcache" + packages = [ + ".", + "diskcache" + ] + revision = "9cad4c3443a7200dd6400aef47183728de563a38" + +[[projects]] + name = "github.com/hashicorp/golang-lru" + packages = [ + ".", + "simplelru" + ] + revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" + version = "v0.5.0" + +[[projects]] + name = "github.com/imdario/mergo" + packages = ["."] + revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4" + version = "v0.3.6" + +[[projects]] + name = "github.com/json-iterator/go" + packages = ["."] + revision = "1624edc4454b8682399def8740d46db5e4362ba4" + version = "v1.1.5" + +[[projects]] + branch = "master" + name = "github.com/mailru/easyjson" + packages = [ + "buffer", + "jlexer", + "jwriter" + ] + revision = "60711f1a8329503b04e1c88535f419d0bb440bff" + +[[projects]] + branch = "master" + name = "github.com/mattbaird/jsonpatch" + packages = ["."] + revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f" + +[[projects]] + name = "github.com/modern-go/concurrent" + packages = ["."] + revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" + version = "1.0.3" + +[[projects]] + name = "github.com/modern-go/reflect2" + packages = ["."] + revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" + version = "1.0.1" + +[[projects]] + branch = "master" + name = "github.com/operator-framework/operator-sdk" + packages = [ + "pkg/util/k8sutil", + "version" + ] + revision = "d4a6b28b3249a1f07068406cc48679f525d07cfc" + +[[projects]] + name = "github.com/pborman/uuid" + packages = ["."] + revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1" + version = "v1.2" + +[[projects]] + branch = "master" + name = "github.com/petar/GoLLRB" + packages = ["llrb"] + revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" + +[[projects]] + name = "github.com/peterbourgon/diskv" + packages = ["."] + revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" + version = "v2.0.1" + +[[projects]] + name = "github.com/spf13/pflag" + packages = ["."] + revision = "298182f68c66c05229eb03ac171abe6e309ee79a" + version = "v1.0.3" + +[[projects]] + name = "go.uber.org/atomic" + packages = ["."] + revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289" + version = "v1.3.2" + +[[projects]] + name = "go.uber.org/multierr" + packages = ["."] + revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" + version = "v1.1.0" + +[[projects]] + name = "go.uber.org/zap" + packages = [ + ".", + "buffer", + "internal/bufferpool", + "internal/color", + "internal/exit", + "zapcore" + ] + revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982" + version = "v1.9.1" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + revision = "0c41d7ab0a0ee717d4590a44bcb987dfd9e183eb" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = [ + "context", + "context/ctxhttp", + "http/httpguts", + "http2", + "http2/hpack", + "idna" + ] + revision = "9b4f9f5ad5197c79fd623a3638e70d8b26cef344" + +[[projects]] + branch = "master" + name = "golang.org/x/oauth2" + packages = [ + ".", + "google", + "internal", + "jws", + "jwt" + ] + revision = "9dcd33a902f40452422c2367fefcb95b54f9f8f8" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows" + ] + revision = "44b849a8bc13eb42e95e6c6c5e360481b73ec710" + +[[projects]] + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + "width" + ] + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + branch = "master" + name = "golang.org/x/time" + packages = ["rate"] + revision = "fbb02b2291d28baffd63558aa44b4b56f178d650" + +[[projects]] + branch = "master" + name = "golang.org/x/tools" + packages = [ + "go/ast/astutil", + "imports", + "internal/fastwalk", + "internal/gopathwalk" + ] + revision = "40a48ad93fbe707101afb2099b738471f70594ec" + +[[projects]] + name = "google.golang.org/appengine" + packages = [ + ".", + "internal", + "internal/app_identity", + "internal/base", + "internal/datastore", + "internal/log", + "internal/modules", + "internal/remote_api", + "internal/urlfetch", + "urlfetch" + ] + revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06" + version = "v1.2.0" + +[[projects]] + name = "gopkg.in/inf.v0" + packages = ["."] + revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" + version = "v0.9.1" + +[[projects]] + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + +[[projects]] + name = "k8s.io/api" + packages = [ + "admission/v1beta1", + "admissionregistration/v1alpha1", + "admissionregistration/v1beta1", + "apps/v1", + "apps/v1beta1", + "apps/v1beta2", + "authentication/v1", + "authentication/v1beta1", + "authorization/v1", + "authorization/v1beta1", + "autoscaling/v1", + "autoscaling/v2beta1", + "batch/v1", + "batch/v1beta1", + "batch/v2alpha1", + "certificates/v1beta1", + "core/v1", + "events/v1beta1", + "extensions/v1beta1", + "networking/v1", + "policy/v1beta1", + "rbac/v1", + "rbac/v1alpha1", + "rbac/v1beta1", + "scheduling/v1alpha1", + "scheduling/v1beta1", + "settings/v1alpha1", + "storage/v1", + "storage/v1alpha1", + "storage/v1beta1" + ] + revision = "2d6f90ab1293a1fb871cf149423ebb72aa7423aa" + +[[projects]] + name = "k8s.io/apimachinery" + packages = [ + "pkg/api/errors", + "pkg/api/meta", + "pkg/api/resource", + "pkg/apis/meta/internalversion", + "pkg/apis/meta/v1", + "pkg/apis/meta/v1/unstructured", + "pkg/apis/meta/v1beta1", + "pkg/conversion", + "pkg/conversion/queryparams", + "pkg/fields", + "pkg/labels", + "pkg/runtime", + "pkg/runtime/schema", + "pkg/runtime/serializer", + "pkg/runtime/serializer/json", + "pkg/runtime/serializer/protobuf", + "pkg/runtime/serializer/recognizer", + "pkg/runtime/serializer/streaming", + "pkg/runtime/serializer/versioning", + "pkg/selection", + "pkg/types", + "pkg/util/cache", + "pkg/util/clock", + "pkg/util/diff", + "pkg/util/errors", + "pkg/util/framer", + "pkg/util/intstr", + "pkg/util/json", + "pkg/util/mergepatch", + "pkg/util/net", + "pkg/util/runtime", + "pkg/util/sets", + "pkg/util/strategicpatch", + "pkg/util/uuid", + "pkg/util/validation", + "pkg/util/validation/field", + "pkg/util/wait", + "pkg/util/yaml", + "pkg/version", + "pkg/watch", + "third_party/forked/golang/json", + "third_party/forked/golang/reflect" + ] + revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae" + +[[projects]] + name = "k8s.io/client-go" + packages = [ + "discovery", + "dynamic", + "kubernetes", + "kubernetes/scheme", + "kubernetes/typed/admissionregistration/v1alpha1", + "kubernetes/typed/admissionregistration/v1beta1", + "kubernetes/typed/apps/v1", + "kubernetes/typed/apps/v1beta1", + "kubernetes/typed/apps/v1beta2", + "kubernetes/typed/authentication/v1", + "kubernetes/typed/authentication/v1beta1", + "kubernetes/typed/authorization/v1", + "kubernetes/typed/authorization/v1beta1", + "kubernetes/typed/autoscaling/v1", + "kubernetes/typed/autoscaling/v2beta1", + "kubernetes/typed/batch/v1", + "kubernetes/typed/batch/v1beta1", + "kubernetes/typed/batch/v2alpha1", + "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/core/v1", + "kubernetes/typed/events/v1beta1", + "kubernetes/typed/extensions/v1beta1", + "kubernetes/typed/networking/v1", + "kubernetes/typed/policy/v1beta1", + "kubernetes/typed/rbac/v1", + "kubernetes/typed/rbac/v1alpha1", + "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/scheduling/v1alpha1", + "kubernetes/typed/scheduling/v1beta1", + "kubernetes/typed/settings/v1alpha1", + "kubernetes/typed/storage/v1", + "kubernetes/typed/storage/v1alpha1", + "kubernetes/typed/storage/v1beta1", + "pkg/apis/clientauthentication", + "pkg/apis/clientauthentication/v1alpha1", + "pkg/apis/clientauthentication/v1beta1", + "pkg/version", + "plugin/pkg/client/auth/exec", + "plugin/pkg/client/auth/gcp", + "rest", + "rest/watch", + "restmapper", + "third_party/forked/golang/template", + "tools/auth", + "tools/cache", + "tools/clientcmd", + "tools/clientcmd/api", + "tools/clientcmd/api/latest", + "tools/clientcmd/api/v1", + "tools/leaderelection", + "tools/leaderelection/resourcelock", + "tools/metrics", + "tools/pager", + "tools/record", + "tools/reference", + "transport", + "util/buffer", + "util/cert", + "util/connrotation", + "util/flowcontrol", + "util/homedir", + "util/integer", + "util/jsonpath", + "util/retry" + ] + revision = "1f13a808da65775f22cbf47862c4e5898d8f4ca1" + +[[projects]] + name = "k8s.io/code-generator" + packages = [ + "cmd/client-gen", + "cmd/client-gen/args", + "cmd/client-gen/generators", + "cmd/client-gen/generators/fake", + "cmd/client-gen/generators/scheme", + "cmd/client-gen/generators/util", + "cmd/client-gen/path", + "cmd/client-gen/types", + "cmd/conversion-gen", + "cmd/conversion-gen/args", + "cmd/conversion-gen/generators", + "cmd/deepcopy-gen", + "cmd/deepcopy-gen/args", + "cmd/defaulter-gen", + "cmd/defaulter-gen/args", + "cmd/informer-gen", + "cmd/informer-gen/args", + "cmd/informer-gen/generators", + "cmd/lister-gen", + "cmd/lister-gen/args", + "cmd/lister-gen/generators", + "cmd/openapi-gen", + "cmd/openapi-gen/args", + "pkg/util" + ] + revision = "6702109cc68eb6fe6350b83e14407c8d7309fd1a" + +[[projects]] + branch = "master" + name = "k8s.io/gengo" + packages = [ + "args", + "examples/deepcopy-gen/generators", + "examples/defaulter-gen/generators", + "examples/set-gen/sets", + "generator", + "namer", + "parser", + "types" + ] + revision = "7338e4bfd6915369a1375890db1bbda0158c9863" + +[[projects]] + branch = "master" + name = "k8s.io/kube-openapi" + packages = [ + "cmd/openapi-gen/args", + "pkg/common", + "pkg/generators", + "pkg/generators/rules", + "pkg/util/proto", + "pkg/util/sets" + ] + revision = "96e8bb74ecdddb93a882ef95d2b8ec49e93168ee" + +[[projects]] + name = "sigs.k8s.io/controller-runtime" + packages = [ + "pkg/cache", + "pkg/cache/internal", + "pkg/client", + "pkg/client/apiutil", + "pkg/client/config", + "pkg/internal/recorder", + "pkg/leaderelection", + "pkg/manager", + "pkg/patch", + "pkg/recorder", + "pkg/runtime/inject", + "pkg/runtime/log", + "pkg/runtime/signals", + "pkg/webhook/admission", + "pkg/webhook/admission/types", + "pkg/webhook/types" + ] + revision = "53fc44b56078cd095b11bd44cfa0288ee4cf718f" + version = "v0.1.4" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "9770b0fb0242b365a1b827dd7a2b2d675d9f86e7d80565012a2df243730476a2" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 00000000..a9f53a28 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,54 @@ +# Force dep to vendor the code generators, which aren't imported just used at dev time. +required = [ + "k8s.io/code-generator/cmd/defaulter-gen", + "k8s.io/code-generator/cmd/deepcopy-gen", + "k8s.io/code-generator/cmd/conversion-gen", + "k8s.io/code-generator/cmd/client-gen", + "k8s.io/code-generator/cmd/lister-gen", + "k8s.io/code-generator/cmd/informer-gen", + "k8s.io/code-generator/cmd/openapi-gen", + "k8s.io/gengo/args", +] + +[[override]] + name = "k8s.io/code-generator" + # revision for tag "kubernetes-1.11.2" + revision = "6702109cc68eb6fe6350b83e14407c8d7309fd1a" + +[[override]] + name = "k8s.io/api" + # revision for tag "kubernetes-1.11.2" + revision = "2d6f90ab1293a1fb871cf149423ebb72aa7423aa" + +[[override]] + name = "k8s.io/apiextensions-apiserver" + # revision for tag "kubernetes-1.11.2" + revision = "408db4a50408e2149acbd657bceb2480c13cb0a4" + +[[override]] + name = "k8s.io/apimachinery" + # revision for tag "kubernetes-1.11.2" + revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae" + +[[override]] + name = "k8s.io/client-go" + # revision for tag "kubernetes-1.11.2" + revision = "1f13a808da65775f22cbf47862c4e5898d8f4ca1" + +[[override]] + name = "sigs.k8s.io/controller-runtime" + version = "v0.1.4" + +[[constraint]] + name = "github.com/operator-framework/operator-sdk" + # The version rule is used for a specific release and the master branch for in between releases. + branch = "master" #osdk_branch_annotation + # version = "=v0.0.6" #osdk_version_annotation + +[prune] + go-tests = true + non-go = true + + [[prune.project]] + name = "k8s.io/code-generator" + non-go = false diff --git a/build/Dockerfile b/build/Dockerfile new file mode 100644 index 00000000..ad1d7e32 --- /dev/null +++ b/build/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:3.6 + +USER nobody + +ADD build/_output/bin/jenkins-operator /usr/local/bin/jenkins-operator diff --git a/cmd/manager/main.go b/cmd/manager/main.go new file mode 100644 index 00000000..526164c1 --- /dev/null +++ b/cmd/manager/main.go @@ -0,0 +1,64 @@ +package main + +import ( + "flag" + "log" + "runtime" + + "github.com/VirtusLab/jenkins-operator/pkg/apis" + "github.com/VirtusLab/jenkins-operator/pkg/controller" + k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" + sdkVersion "github.com/operator-framework/operator-sdk/version" + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/runtime/signals" +) + +func printVersion() { + log.Printf("Go Version: %s", runtime.Version()) + log.Printf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) + log.Printf("operator-sdk Version: %v", sdkVersion.Version) +} + +func main() { + printVersion() + flag.Parse() + + namespace, err := k8sutil.GetWatchNamespace() + if err != nil { + log.Fatalf("failed to get watch namespace: %v", err) + } + + // TODO: Expose metrics port after SDK uses controller-runtime's dynamic client + // sdk.ExposeMetricsPort() + + // Get a config to talk to the apiserver + cfg, err := config.GetConfig() + if err != nil { + log.Fatal(err) + } + + // Create a new Cmd to provide shared dependencies and start components + mgr, err := manager.New(cfg, manager.Options{Namespace: namespace}) + if err != nil { + log.Fatal(err) + } + + log.Print("Registering Components.") + + // Setup Scheme for all resources + if err := apis.AddToScheme(mgr.GetScheme()); err != nil { + log.Fatal(err) + } + + // Setup all Controllers + if err := controller.AddToManager(mgr); err != nil { + log.Fatal(err) + } + + log.Print("Starting the Cmd.") + + // Start the Cmd + log.Fatal(mgr.Start(signals.SetupSignalHandler())) +} diff --git a/deploy/crds/virtuslab_v1alpha1_jenkins_cr.yaml b/deploy/crds/virtuslab_v1alpha1_jenkins_cr.yaml new file mode 100644 index 00000000..c5b319a4 --- /dev/null +++ b/deploy/crds/virtuslab_v1alpha1_jenkins_cr.yaml @@ -0,0 +1,7 @@ +apiVersion: virtuslab.com/v1alpha1 +kind: Jenkins +metadata: + name: example-jenkins +spec: + # Add fields here + size: 3 diff --git a/deploy/crds/virtuslab_v1alpha1_jenkins_crd.yaml b/deploy/crds/virtuslab_v1alpha1_jenkins_crd.yaml new file mode 100644 index 00000000..deecc881 --- /dev/null +++ b/deploy/crds/virtuslab_v1alpha1_jenkins_crd.yaml @@ -0,0 +1,13 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: jenkins.virtuslab.com +spec: + group: virtuslab.com + names: + kind: Jenkins + listKind: JenkinsList + plural: jenkins + singular: jenkins + scope: Namespaced + version: v1alpha1 diff --git a/deploy/operator.yaml b/deploy/operator.yaml new file mode 100644 index 00000000..b2c53a68 --- /dev/null +++ b/deploy/operator.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: jenkins-operator +spec: + replicas: 1 + selector: + matchLabels: + name: jenkins-operator + template: + metadata: + labels: + name: jenkins-operator + spec: + serviceAccountName: jenkins-operator + containers: + - name: jenkins-operator + # Replace this with the built image name + image: REPLACE_IMAGE + ports: + - containerPort: 60000 + name: metrics + command: + - jenkins-operator + imagePullPolicy: Always + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: "jenkins-operator" diff --git a/deploy/role.yaml b/deploy/role.yaml new file mode 100644 index 00000000..f345ebe6 --- /dev/null +++ b/deploy/role.yaml @@ -0,0 +1,40 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + creationTimestamp: null + name: jenkins-operator +rules: +- apiGroups: + - "" + resources: + - pods + - services + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + verbs: + - '*' +- apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - '*' +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - get + - create +- apiGroups: + - virtuslab.com + resources: + - '*' + verbs: + - '*' diff --git a/deploy/role_binding.yaml b/deploy/role_binding.yaml new file mode 100644 index 00000000..775f0a7a --- /dev/null +++ b/deploy/role_binding.yaml @@ -0,0 +1,11 @@ +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: jenkins-operator +subjects: +- kind: ServiceAccount + name: jenkins-operator +roleRef: + kind: Role + name: jenkins-operator + apiGroup: rbac.authorization.k8s.io diff --git a/deploy/service_account.yaml b/deploy/service_account.yaml new file mode 100644 index 00000000..ce3f76f1 --- /dev/null +++ b/deploy/service_account.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: jenkins-operator diff --git a/pkg/apis/addtoscheme_virtuslab_v1alpha1.go b/pkg/apis/addtoscheme_virtuslab_v1alpha1.go new file mode 100644 index 00000000..2bd42c32 --- /dev/null +++ b/pkg/apis/addtoscheme_virtuslab_v1alpha1.go @@ -0,0 +1,10 @@ +package apis + +import ( + "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme) +} diff --git a/pkg/apis/apis.go b/pkg/apis/apis.go new file mode 100644 index 00000000..07dc9616 --- /dev/null +++ b/pkg/apis/apis.go @@ -0,0 +1,13 @@ +package apis + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// AddToSchemes may be used to add all resources defined in the project to a Scheme +var AddToSchemes runtime.SchemeBuilder + +// AddToScheme adds all Resources to the Scheme +func AddToScheme(s *runtime.Scheme) error { + return AddToSchemes.AddToScheme(s) +} diff --git a/pkg/apis/virtuslab/v1alpha1/doc.go b/pkg/apis/virtuslab/v1alpha1/doc.go new file mode 100644 index 00000000..2b8825d0 --- /dev/null +++ b/pkg/apis/virtuslab/v1alpha1/doc.go @@ -0,0 +1,4 @@ +// Package v1alpha1 contains API Schema definitions for the virtuslab v1alpha1 API group +// +k8s:deepcopy-gen=package,register +// +groupName=virtuslab.com +package v1alpha1 diff --git a/pkg/apis/virtuslab/v1alpha1/jenkins_types.go b/pkg/apis/virtuslab/v1alpha1/jenkins_types.go new file mode 100644 index 00000000..2c6828a4 --- /dev/null +++ b/pkg/apis/virtuslab/v1alpha1/jenkins_types.go @@ -0,0 +1,45 @@ +package v1alpha1 + +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. + +// JenkinsSpec defines the desired state of Jenkins +type JenkinsSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file +} + +// JenkinsStatus defines the observed state of Jenkins +type JenkinsStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Jenkins is the Schema for the jenkins API +// +k8s:openapi-gen=true +type Jenkins struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec JenkinsSpec `json:"spec,omitempty"` + Status JenkinsStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// JenkinsList contains a list of Jenkins +type JenkinsList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Jenkins `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Jenkins{}, &JenkinsList{}) +} diff --git a/pkg/apis/virtuslab/v1alpha1/register.go b/pkg/apis/virtuslab/v1alpha1/register.go new file mode 100644 index 00000000..2469c2e0 --- /dev/null +++ b/pkg/apis/virtuslab/v1alpha1/register.go @@ -0,0 +1,19 @@ +// NOTE: Boilerplate only. Ignore this file. + +// Package v1alpha1 contains API Schema definitions for the virtuslab v1alpha1 API group +// +k8s:deepcopy-gen=package,register +// +groupName=virtuslab.com +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "virtuslab.com", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +) diff --git a/pkg/apis/virtuslab/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/virtuslab/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..fd1aeed6 --- /dev/null +++ b/pkg/apis/virtuslab/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,118 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +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 deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +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 *Jenkins) DeepCopyInto(out *Jenkins) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Jenkins. +func (in *Jenkins) DeepCopy() *Jenkins { + if in == nil { + return nil + } + out := new(Jenkins) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Jenkins) 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 *JenkinsList) DeepCopyInto(out *JenkinsList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Jenkins, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsList. +func (in *JenkinsList) DeepCopy() *JenkinsList { + if in == nil { + return nil + } + out := new(JenkinsList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *JenkinsList) 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 *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsSpec. +func (in *JenkinsSpec) DeepCopy() *JenkinsSpec { + if in == nil { + return nil + } + out := new(JenkinsSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JenkinsStatus) DeepCopyInto(out *JenkinsStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsStatus. +func (in *JenkinsStatus) DeepCopy() *JenkinsStatus { + if in == nil { + return nil + } + out := new(JenkinsStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/controller/add_jenkins.go b/pkg/controller/add_jenkins.go new file mode 100644 index 00000000..cac62ffc --- /dev/null +++ b/pkg/controller/add_jenkins.go @@ -0,0 +1,10 @@ +package controller + +import ( + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, jenkins.Add) +} diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go new file mode 100644 index 00000000..7c069f3e --- /dev/null +++ b/pkg/controller/controller.go @@ -0,0 +1,18 @@ +package controller + +import ( + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +// AddToManagerFuncs is a list of functions to add all Controllers to the Manager +var AddToManagerFuncs []func(manager.Manager) error + +// AddToManager adds all Controllers to the Manager +func AddToManager(m manager.Manager) error { + for _, f := range AddToManagerFuncs { + if err := f(m); err != nil { + return err + } + } + return nil +} diff --git a/pkg/controller/jenkins/jenkins_controller.go b/pkg/controller/jenkins/jenkins_controller.go new file mode 100644 index 00000000..0bdbd0b8 --- /dev/null +++ b/pkg/controller/jenkins/jenkins_controller.go @@ -0,0 +1,149 @@ +package jenkins + +import ( + "context" + "log" + + virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new Jenkins Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileJenkins{client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("jenkins-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to primary resource Jenkins + err = c.Watch(&source.Kind{Type: &virtuslabv1alpha1.Jenkins{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create that are owned by the primary resource + // Watch for changes to secondary resource Pods and requeue the owner Jenkins + err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &virtuslabv1alpha1.Jenkins{}, + }) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &ReconcileJenkins{} + +// ReconcileJenkins reconciles a Jenkins object +type ReconcileJenkins struct { + // This client, initialized using mgr.Client() above, is a split client + // that reads objects from the cache and writes to the apiserver + client client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a Jenkins object and makes changes based on the state read +// and what is in the Jenkins.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. This example creates +// a Pod as an example +// Note: +// The Controller will requeue the Request to be processed again if the returned error is non-nil or +// Result.Requeue is true, otherwise upon completion it will remove the work from the queue. +func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Result, error) { + log.Printf("Reconciling Jenkins %s/%s\n", request.Namespace, request.Name) + + // Fetch the Jenkins instance + instance := &virtuslabv1alpha1.Jenkins{} + err := r.client.Get(context.TODO(), request.NamespacedName, instance) + 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 + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + // Define a new Pod object + pod := newPodForCR(instance) + + // Set Jenkins instance as the owner and controller + if err := controllerutil.SetControllerReference(instance, pod, r.scheme); err != nil { + return reconcile.Result{}, err + } + + // Check if this Pod already exists + found := &corev1.Pod{} + err = r.client.Get(context.TODO(), types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, found) + if err != nil && errors.IsNotFound(err) { + log.Printf("Creating a new Pod %s/%s\n", pod.Namespace, pod.Name) + err = r.client.Create(context.TODO(), pod) + if err != nil { + return reconcile.Result{}, err + } + + // Pod created successfully - don't requeue + return reconcile.Result{}, nil + } else if err != nil { + return reconcile.Result{}, err + } + + // Pod already exists - don't requeue + log.Printf("Skip reconcile: Pod %s/%s already exists", found.Namespace, found.Name) + return reconcile.Result{}, nil +} + +// newPodForCR returns a busybox pod with the same name/namespace as the cr +func newPodForCR(cr *virtuslabv1alpha1.Jenkins) *corev1.Pod { + labels := map[string]string{ + "app": cr.Name, + } + return &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: cr.Name + "-pod", + Namespace: cr.Namespace, + Labels: labels, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "busybox", + Image: "busybox", + Command: []string{"sleep", "3600"}, + }, + }, + }, + } +} diff --git a/version/version.go b/version/version.go new file mode 100644 index 00000000..e3e130bf --- /dev/null +++ b/version/version.go @@ -0,0 +1,5 @@ +package version + +var ( + Version = "0.0.1" +)