From ca27bf4df851c3abf01958dd6da6ac071f63bfa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20S=C4=99k?= Date: Thu, 10 Jan 2019 14:44:30 +0100 Subject: [PATCH] Add base configuration groovy scripts job --- Gopkg.lock | 235 ++++++++++++++++-- .../jenkins/configuration/base/reconcile.go | 65 +++-- .../jenkins/configuration/base/resources.go | 4 +- .../resources/base_configuration_configmap.go | 180 +++++++++++--- .../resources/init_configuration_configmap.go | 13 +- .../configuration/base/resources/meta.go | 7 +- .../configuration/base/resources/pod.go | 23 +- .../base/resources/scripts_configmap.go | 9 +- .../configuration/base/resources/secret.go | 3 +- .../jenkins/configuration/user/reconcile.go | 27 +- pkg/controller/jenkins/constants/constants.go | 7 + pkg/controller/jenkins/constants/labels.go | 10 + pkg/controller/jenkins/groovy/groovy.go | 59 ++--- pkg/controller/jenkins/handler.go | 53 ++++ pkg/controller/jenkins/jenkins_controller.go | 12 +- 15 files changed, 545 insertions(+), 162 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 93c143ad..10dbae69 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,256 +2,331 @@ [[projects]] + digest = "1:8713dd3229c46881bb56b24fa3b581a0faab01d12e2d973a830965c24061e449" name = "cloud.google.com/go" packages = ["compute/metadata"] + pruneopts = "NT" revision = "1fd54cf41e6e0e178ffe3c52b0e2260281f603e3" version = "v0.32.0" [[projects]] + digest = "1:75d2b55b13298745ec068057251d05d65bbae0a668201fe45ad6986551a55601" name = "github.com/BurntSushi/toml" packages = ["."] + pruneopts = "NT" revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005" version = "v0.3.1" [[projects]] + digest = "1:d8ebbd207f3d3266d4423ce4860c9f3794956306ded6c7ba312ecc69cdfbf04c" name = "github.com/PuerkitoBio/purell" packages = ["."] + pruneopts = "NT" revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4" version = "v1.1.0" [[projects]] branch = "master" + digest = "1:8098cd40cd09879efbf12e33bcd51ead4a66006ac802cd563a66c4f3373b9727" name = "github.com/PuerkitoBio/urlesc" packages = ["."] + pruneopts = "NT" revision = "de5bf2ad457846296e2031421a34e2568e304e35" [[projects]] + digest = "1:8d13c70d5898b091728540686c696baee0d64013b8e43089da80621a49410391" name = "github.com/bndr/gojenkins" packages = ["."] + pruneopts = "NT" revision = "de43c03cf849dd63a9737df6e05791c7a176c93d" [[projects]] + digest = "1:4b8b5811da6970495e04d1f4e98bb89518cc3cfc3b3f456bdb876ed7b6c74049" name = "github.com/davecgh/go-spew" packages = ["spew"] + pruneopts = "NT" revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" version = "v1.1.1" [[projects]] + digest = "1:707c9f4ee70cc3bb941cf5803d9b8e725bc02277a96301ac8e537510a712ec7c" name = "github.com/docker/distribution" packages = [ "digest", - "reference" + "reference", ] + pruneopts = "NT" revision = "48294d928ced5dd9b378f7fd7c6f5da3ff3f2c89" version = "v2.6.2" [[projects]] + digest = "1:e6f888d4be8ec0f05c50e2aba83da4948b58045dee54d03be81fa74ea673302c" name = "github.com/emicklei/go-restful" packages = [ ".", - "log" + "log", ] + pruneopts = "NT" revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0" version = "v2.8.0" [[projects]] + digest = "1:81466b4218bf6adddac2572a30ac733a9255919bc2f470b4827a317bd4ee1756" name = "github.com/ghodss/yaml" packages = ["."] + pruneopts = "NT" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:d421af4c4fe51d399667d573982d663fe1fa67020a88d3ae43466ebfe8e2b5c9" name = "github.com/go-logr/logr" packages = ["."] + pruneopts = "NT" revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e" [[projects]] + digest = "1:340497a512995aa69c0add901d79a2096b3449d35a44a6f1f1115091a9f8c687" name = "github.com/go-logr/zapr" packages = ["."] + pruneopts = "NT" revision = "7536572e8d55209135cd5e7ccf7fce43dca217ab" version = "v0.1.0" [[projects]] + digest = "1:260f7ebefc63024c8dfe2c9f1a2935a89fa4213637a1f522f592f80c001cc441" name = "github.com/go-openapi/jsonpointer" packages = ["."] + pruneopts = "NT" revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004" version = "v0.17.2" [[projects]] + digest = "1:98abd61947ff5c7c6fcfec5473d02a4821ed3a2dd99a4fbfdb7925b0dd745546" name = "github.com/go-openapi/jsonreference" packages = ["."] + pruneopts = "NT" revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3" version = "v0.17.2" [[projects]] branch = "master" + digest = "1:dfab391de021809e0041f0ab5648da6b74dd16a685472a1b8c3dc06b3dca1ee2" name = "github.com/go-openapi/spec" packages = ["."] + pruneopts = "NT" revision = "5bae59e25b21498baea7f9d46e9c147ec106a42e" [[projects]] + digest = "1:983f95b2fae6fe8fdd361738325ed6090f4f3bd15ce4db745e899fb5b0fdfc46" name = "github.com/go-openapi/swag" packages = ["."] + pruneopts = "NT" revision = "5899d5c5e619fda5fa86e14795a835f473ca284c" version = "v0.17.2" [[projects]] + digest = "1:4fb6ac9e2e67130ed8c5db4154684b390c1c0ce213ba3f4532b7edc614f78999" name = "github.com/gobuffalo/envy" packages = ["."] + pruneopts = "NT" revision = "801d7253ade1f895f74596b9a96147ed2d3b087e" version = "v1.6.11" [[projects]] + digest = "1:2a9d5e367df8c95e780975ca1dd4010bef8e39a3777066d3880ce274b39d4b5a" name = "github.com/gogo/protobuf" packages = [ "proto", - "sortkeys" + "sortkeys", ] + pruneopts = "NT" revision = "636bf0302bc95575d69441b25a2603156ffdddf1" version = "v1.1.1" [[projects]] branch = "master" + digest = "1:e2b86e41f3d669fc36b50d31d32d22c8ac656c75aa5ea89717ce7177e134ff2a" name = "github.com/golang/glog" packages = ["."] + pruneopts = "NT" revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" [[projects]] branch = "master" + digest = "1:aaedc94233e56ed57cdb04e3abfacc85c90c14082b62e3cdbe8ea72fc06ee035" name = "github.com/golang/groupcache" packages = ["lru"] + pruneopts = "NT" revision = "c65c006176ff7ff98bb916961c7abbc6b0afc0aa" [[projects]] + digest = "1:3bc9b1450cb2386fcd3b9dad1b9a59ea877fe14ddf3c66bda4670f5e91b61b3f" name = "github.com/golang/mock" packages = ["gomock"] + pruneopts = "NT" revision = "51421b967af1f557f93a59e0057aaf15ca02e29c" version = "v1.2.0" [[projects]] + digest = "1:d7cb4458ea8782e6efacd8f4940796ec559c90833509c436f40c4085b98156dd" name = "github.com/golang/protobuf" packages = [ "proto", "ptypes", "ptypes/any", "ptypes/duration", - "ptypes/timestamp" + "ptypes/timestamp", ] + pruneopts = "NT" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" version = "v1.2.0" [[projects]] branch = "master" + digest = "1:05f95ffdfcf651bdb0f05b40b69e7f5663047f8da75c72d58728acb59b5cc107" name = "github.com/google/btree" packages = ["."] + pruneopts = "NT" revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306" [[projects]] branch = "master" + digest = "1:52c5834e2bebac9030c97cc0798ac11c3aa8a39f098aeb419f142533da6cd3cc" name = "github.com/google/gofuzz" packages = ["."] + pruneopts = "NT" revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" [[projects]] + digest = "1:a1578f7323eca2b88021fdc9a79a99833d40b12c32a5ea4f284e2fad19ea2657" name = "github.com/google/uuid" packages = ["."] + pruneopts = "NT" revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" version = "v1.0.0" [[projects]] + digest = "1:289332c13b80edfefc88397cce5266c16845dcf204fa2f6ac7e464ee4c7f6e96" name = "github.com/googleapis/gnostic" packages = [ "OpenAPIv2", "compiler", - "extensions" + "extensions", ] + pruneopts = "NT" revision = "7c663266750e7d82587642f65e60bc4083f1f84e" version = "v0.2.0" [[projects]] branch = "master" + digest = "1:2a2caa63899dae26ed3e4510b806549fd416d94db24ad68279daa62881b26488" name = "github.com/gregjones/httpcache" packages = [ ".", - "diskcache" + "diskcache", ] + pruneopts = "NT" revision = "9cad4c3443a7200dd6400aef47183728de563a38" [[projects]] + digest = "1:b42cde0e1f3c816dd57f57f7bbcf05ca40263ad96f168714c130c611fc0856a6" name = "github.com/hashicorp/golang-lru" packages = [ ".", - "simplelru" + "simplelru", ] + pruneopts = "NT" revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" version = "v0.5.0" [[projects]] + digest = "1:9a52adf44086cead3b384e5d0dbf7a1c1cce65e67552ee3383a8561c42a18cd3" name = "github.com/imdario/mergo" packages = ["."] + pruneopts = "NT" revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4" version = "v0.3.6" [[projects]] + digest = "1:f5b9328966ccea0970b1d15075698eff0ddb3e75889560aad2e9f76b289b536a" name = "github.com/joho/godotenv" packages = ["."] + pruneopts = "NT" revision = "23d116af351c84513e1946b527c88823e476be13" version = "v1.3.0" [[projects]] + digest = "1:1d39c063244ad17c4b18e8da1551163b6ffb52bd1640a49a8ec5c3b7bf4dbd5d" name = "github.com/json-iterator/go" packages = ["."] + pruneopts = "NT" revision = "1624edc4454b8682399def8740d46db5e4362ba4" version = "v1.1.5" [[projects]] + digest = "1:4059c14e87a2de3a434430340521b5feece186c1469eff0834c29a63870de3ed" name = "github.com/konsorten/go-windows-terminal-sequences" packages = ["."] + pruneopts = "NT" revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" version = "v1.0.1" [[projects]] branch = "master" + digest = "1:7d9fcac7f1228470c4ea0ee31cdfb662a758c44df691e39b3e76c11d3e12ba8f" name = "github.com/mailru/easyjson" packages = [ "buffer", "jlexer", - "jwriter" + "jwriter", ] + pruneopts = "NT" revision = "60711f1a8329503b04e1c88535f419d0bb440bff" [[projects]] + digest = "1:56dbf15e091bf7926cb33a57cb6bdfc658fc6d3498d2f76f10a97ce7856f1fde" name = "github.com/markbates/inflect" packages = ["."] + pruneopts = "NT" revision = "24b83195037b3bc61fcda2d28b7b0518bce293b6" version = "v1.0.4" [[projects]] branch = "master" + digest = "1:0e9bfc47ab9941ecc3344e580baca5deb4091177e84dd9773b48b38ec26b93d5" name = "github.com/mattbaird/jsonpatch" packages = ["."] + pruneopts = "NT" revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f" [[projects]] + digest = "1:2f42fa12d6911c7b7659738758631bec870b7e9b4c6be5444f963cdcfccc191f" name = "github.com/modern-go/concurrent" packages = ["."] + pruneopts = "NT" revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" version = "1.0.3" [[projects]] + digest = "1:c6aca19413b13dc59c220ad7430329e2ec454cc310bc6d8de2c7e2b93c18a0f6" name = "github.com/modern-go/reflect2" packages = ["."] + pruneopts = "NT" revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" version = "1.0.1" [[projects]] + digest = "1:f3f95a7e55bd970e2d59af0131202401493016a7a90978cd1c4b7137d128bc1a" name = "github.com/mrtazz/checkmake" packages = ["logger"] + pruneopts = "NT" revision = "53de3e70f28d26a6450a845505c43165cb150b72" version = "0.1.0" [[projects]] + digest = "1:121b82bf82f859edc43cc6ce42df4e231881874f576e48ba75b062fb1a2efc80" name = "github.com/operator-framework/operator-sdk" packages = [ "internal/util/fileutil", @@ -263,85 +338,109 @@ "pkg/scaffold/input", "pkg/test", "pkg/test/e2eutil", - "version" + "version", ] + pruneopts = "NT" revision = "175a82edae514f57f597110af5447d3f9b1c0fc3" version = "v0.2.0" [[projects]] + digest = "1:93b1d84c5fa6d1ea52f4114c37714cddd84d5b78f151b62bb101128dd51399bf" name = "github.com/pborman/uuid" packages = ["."] + pruneopts = "NT" revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1" version = "v1.2" [[projects]] branch = "master" + digest = "1:bf2ac97824a7221eb16b096aecc1c390d4c8a4e49524386aaa2e2dd215cbfb31" name = "github.com/petar/GoLLRB" packages = ["llrb"] + pruneopts = "NT" revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" [[projects]] + digest = "1:e4e9e026b8e4c5630205cd0208efb491b40ad40552e57f7a646bb8a46896077b" name = "github.com/peterbourgon/diskv" packages = ["."] + pruneopts = "NT" revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" version = "v2.0.1" [[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" name = "github.com/pmezard/go-difflib" packages = ["difflib"] + pruneopts = "NT" revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" [[projects]] + digest = "1:4e63570205b765959739e2ef37add1d229cab7dbf70d80341a0608816120493b" name = "github.com/rogpeppe/go-internal" packages = [ "modfile", "module", - "semver" + "semver", ] + pruneopts = "NT" revision = "d87f08a7d80821c797ffc8eb8f4e01675f378736" version = "v1.0.0" [[projects]] + digest = "1:cd2f2cba5b7ffafd0412fb647ff4bcff170292de57270f05fbbf391e3eb9566b" name = "github.com/sirupsen/logrus" packages = ["."] + pruneopts = "NT" revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95" version = "v1.2.0" [[projects]] + digest = "1:2a7c79c506479dc73c0100982a40bacc89e06d96dc458eb41c9b6aa44d9e0b6d" name = "github.com/spf13/afero" packages = [ ".", - "mem" + "mem", ] + pruneopts = "NT" revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd" version = "v1.1.2" [[projects]] + digest = "1:9d8420bbf131d1618bde6530af37c3799340d3762cc47210c1d9532a4c3a2779" name = "github.com/spf13/pflag" packages = ["."] + pruneopts = "NT" revision = "298182f68c66c05229eb03ac171abe6e309ee79a" version = "v1.0.3" [[projects]] + digest = "1:4af061277c04a7660e082acc2020f4c66d2c21dfc62e0242ffa1d2120cdfb4ec" name = "github.com/stretchr/testify" packages = ["assert"] + pruneopts = "NT" revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" version = "v1.2.2" [[projects]] + digest = "1:22f696cee54865fb8e9ff91df7b633f6b8f22037a8015253c6b6a71ca82219c7" name = "go.uber.org/atomic" packages = ["."] + pruneopts = "NT" revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289" version = "v1.3.2" [[projects]] + digest = "1:58ca93bdf81bac106ded02226b5395a0595d5346cdc4caa8d9c1f3a5f8f9976e" name = "go.uber.org/multierr" packages = ["."] + pruneopts = "NT" revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" version = "v1.1.0" [[projects]] + digest = "1:572fa4496563920f3e3107a2294cf2621d6cc4ffd03403fb6397b1bab9fa082a" name = "go.uber.org/zap" packages = [ ".", @@ -349,19 +448,23 @@ "internal/bufferpool", "internal/color", "internal/exit", - "zapcore" + "zapcore", ] + pruneopts = "NT" revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982" version = "v1.9.1" [[projects]] branch = "master" + digest = "1:47924c7ab4b3a18145d150e535525f582a07511e5452c4e1a5b79d883c2a429f" name = "golang.org/x/crypto" packages = ["ssh/terminal"] + pruneopts = "NT" revision = "4d3f4d9ffa16a13f451c3b2999e9c49e9750bf06" [[projects]] branch = "master" + digest = "1:a7fcf4f3e5247a06ad4c28108f0bc1d4ab980a1a0567e7790260cf2d3d77f37d" name = "golang.org/x/net" packages = [ "context", @@ -371,32 +474,38 @@ "http/httpguts", "http2", "http2/hpack", - "idna" + "idna", ] + pruneopts = "NT" revision = "c10e9556a7bc0e7c942242b606f0acf024ad5d6a" [[projects]] branch = "master" + digest = "1:b17011812136abe011d81b40b30470808df923687e831760511d878408d208df" name = "golang.org/x/oauth2" packages = [ ".", "google", "internal", "jws", - "jwt" + "jwt", ] + pruneopts = "NT" revision = "e0f2c55a7fc7d04742e0eef7918aa2389b0e1919" [[projects]] branch = "master" + digest = "1:04b92b5bc6c1031cc9083fbc2fdeda90f3a69b7c1bf5eed6bbf9a3563d946c6e" name = "golang.org/x/sys" packages = [ "unix", - "windows" + "windows", ] + pruneopts = "NT" revision = "9b800f95dbbc54abff0acf7ee32d88ba4e328c89" [[projects]] + digest = "1:8c74f97396ed63cc2ef04ebb5fc37bb032871b8fd890a25991ed40974b00cd2a" name = "golang.org/x/text" packages = [ "collate", @@ -413,29 +522,35 @@ "unicode/cldr", "unicode/norm", "unicode/rangetable", - "width" + "width", ] + pruneopts = "NT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:c9e7a4b4d47c0ed205d257648b0e5b0440880cb728506e318f8ac7cd36270bc4" name = "golang.org/x/time" packages = ["rate"] + pruneopts = "NT" revision = "fbb02b2291d28baffd63558aa44b4b56f178d650" [[projects]] branch = "master" + digest = "1:d9646d2cb3517e532bcc75614352e589c5f26e6d1b8ae2587eaef0c7c60cea3a" name = "golang.org/x/tools" packages = [ "go/ast/astutil", "imports", "internal/fastwalk", - "internal/gopathwalk" + "internal/gopathwalk", ] + pruneopts = "NT" revision = "92b943e6bff73e0dfe9e975d94043d8f31067b06" [[projects]] + digest = "1:2a4972ee51c3b9dfafbb3451fa0552e7a198d9d12c721bfc492050fe2f72e0f6" name = "google.golang.org/appengine" packages = [ ".", @@ -447,24 +562,30 @@ "internal/modules", "internal/remote_api", "internal/urlfetch", - "urlfetch" + "urlfetch", ] + pruneopts = "NT" revision = "4a4468ece617fc8205e99368fa2200e9d1fad421" version = "v1.3.0" [[projects]] + digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a" name = "gopkg.in/inf.v0" packages = ["."] + pruneopts = "NT" revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" version = "v0.9.1" [[projects]] + digest = "1:7c95b35057a0ff2e19f707173cc1a947fa43a6eb5c4d300d196ece0334046082" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "NT" revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" version = "v2.2.1" [[projects]] + digest = "1:f11e5753e619f411a51a49d60d39b2bc4da6766f5f0af2e2291daa6a3d9385d5" name = "k8s.io/api" packages = [ "admission/v1beta1", @@ -496,20 +617,24 @@ "settings/v1alpha1", "storage/v1", "storage/v1alpha1", - "storage/v1beta1" + "storage/v1beta1", ] + pruneopts = "NT" revision = "2d6f90ab1293a1fb871cf149423ebb72aa7423aa" [[projects]] + digest = "1:117a407949aaaad9f7fbe3da8d6c2055f2c223ac0cbebd39f47ff71899622a91" name = "k8s.io/apiextensions-apiserver" packages = [ "pkg/apis/apiextensions", "pkg/apis/apiextensions/v1beta1", - "pkg/client/clientset/clientset/scheme" + "pkg/client/clientset/clientset/scheme", ] + pruneopts = "NT" revision = "408db4a50408e2149acbd657bceb2480c13cb0a4" [[projects]] + digest = "1:b07bf863262aae765494d60f0d524483f211b29f9bb27d445a79c13af8676bf2" name = "k8s.io/apimachinery" packages = [ "pkg/api/errors", @@ -553,11 +678,13 @@ "pkg/version", "pkg/watch", "third_party/forked/golang/json", - "third_party/forked/golang/reflect" + "third_party/forked/golang/reflect", ] + pruneopts = "NT" revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae" [[projects]] + digest = "1:1689a49a3ebc6e379849181f1e0899fccf143cab47586078721818bdcdb712bc" name = "k8s.io/client-go" packages = [ "discovery", @@ -626,11 +753,13 @@ "util/integer", "util/jsonpath", "util/retry", - "util/workqueue" + "util/workqueue", ] + pruneopts = "NT" revision = "1f13a808da65775f22cbf47862c4e5898d8f4ca1" [[projects]] + digest = "1:8ab487a323486c8bbbaa3b689850487fdccc6cbea8690620e083b2d230a4447e" name = "k8s.io/code-generator" packages = [ "cmd/client-gen", @@ -656,12 +785,14 @@ "cmd/lister-gen/generators", "cmd/openapi-gen", "cmd/openapi-gen/args", - "pkg/util" + "pkg/util", ] + pruneopts = "T" revision = "6702109cc68eb6fe6350b83e14407c8d7309fd1a" [[projects]] branch = "master" + digest = "1:c84b5ef38d786290246a9cc791a48b6ed890cd32468179a51a91492161ec6d65" name = "k8s.io/gengo" packages = [ "args", @@ -671,11 +802,13 @@ "generator", "namer", "parser", - "types" + "types", ] + pruneopts = "NT" revision = "7338e4bfd6915369a1375890db1bbda0158c9863" [[projects]] + digest = "1:c48a795cd7048bb1888273bc604b6e69b22f9b8089c3df65f77cc527757b515c" name = "k8s.io/kube-openapi" packages = [ "cmd/openapi-gen/args", @@ -683,11 +816,13 @@ "pkg/generators", "pkg/generators/rules", "pkg/util/proto", - "pkg/util/sets" + "pkg/util/sets", ] + pruneopts = "NT" revision = "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803" [[projects]] + digest = "1:d1b7a6ed45c957e6308759f31fdbff8063741ecb08b7c3b6d67f0c9f4357b2ae" name = "sigs.k8s.io/controller-runtime" packages = [ "pkg/cache", @@ -716,14 +851,60 @@ "pkg/source/internal", "pkg/webhook/admission", "pkg/webhook/admission/types", - "pkg/webhook/types" + "pkg/webhook/types", ] + pruneopts = "NT" revision = "5fd1e9e9fac5261e9ad9d47c375afc014fc31d21" version = "v0.1.7" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "073db7fa0bb4439632fe9a166630b1d2408eccac76cb24a7b57daab6027087cf" + input-imports = [ + "github.com/bndr/gojenkins", + "github.com/docker/distribution/reference", + "github.com/go-logr/logr", + "github.com/golang/mock/gomock", + "github.com/mrtazz/checkmake/logger", + "github.com/operator-framework/operator-sdk/pkg/k8sutil", + "github.com/operator-framework/operator-sdk/pkg/leader", + "github.com/operator-framework/operator-sdk/pkg/ready", + "github.com/operator-framework/operator-sdk/pkg/test", + "github.com/operator-framework/operator-sdk/pkg/test/e2eutil", + "github.com/operator-framework/operator-sdk/version", + "github.com/stretchr/testify/assert", + "k8s.io/api/core/v1", + "k8s.io/apimachinery/pkg/api/errors", + "k8s.io/apimachinery/pkg/api/resource", + "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/apimachinery/pkg/labels", + "k8s.io/apimachinery/pkg/runtime", + "k8s.io/apimachinery/pkg/runtime/schema", + "k8s.io/apimachinery/pkg/types", + "k8s.io/apimachinery/pkg/util/intstr", + "k8s.io/apimachinery/pkg/util/wait", + "k8s.io/client-go/kubernetes/scheme", + "k8s.io/client-go/plugin/pkg/client/auth/gcp", + "k8s.io/code-generator/cmd/client-gen", + "k8s.io/code-generator/cmd/conversion-gen", + "k8s.io/code-generator/cmd/deepcopy-gen", + "k8s.io/code-generator/cmd/defaulter-gen", + "k8s.io/code-generator/cmd/informer-gen", + "k8s.io/code-generator/cmd/lister-gen", + "k8s.io/code-generator/cmd/openapi-gen", + "k8s.io/gengo/args", + "sigs.k8s.io/controller-runtime/pkg/client", + "sigs.k8s.io/controller-runtime/pkg/client/config", + "sigs.k8s.io/controller-runtime/pkg/client/fake", + "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/runtime/log", + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme", + "sigs.k8s.io/controller-runtime/pkg/runtime/signals", + "sigs.k8s.io/controller-runtime/pkg/source", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/pkg/controller/jenkins/configuration/base/reconcile.go b/pkg/controller/jenkins/configuration/base/reconcile.go index 25d6e5c3..ea2476d7 100644 --- a/pkg/controller/jenkins/configuration/base/reconcile.go +++ b/pkg/controller/jenkins/configuration/base/reconcile.go @@ -9,6 +9,9 @@ import ( virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" jenkinsclient "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/client" "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/base/resources" + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/user/theme" + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/constants" + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/groovy" "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/plugin" "github.com/VirtusLab/jenkins-operator/pkg/log" @@ -64,6 +67,11 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (*reconcile.Result, jenk } r.logger.V(log.VDebug).Info("Scripts config map is present") + if err := r.createInitConfigurationConfigMap(metaObject); err != nil { + return &reconcile.Result{}, nil, err + } + r.logger.V(log.VDebug).Info("Init configuration config map is present") + if err := r.createBaseConfigurationConfigMap(metaObject); err != nil { return &reconcile.Result{}, nil, err } @@ -113,7 +121,8 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (*reconcile.Result, jenk } } - return nil, jenkinsClient, nil + result, err = r.baseConfiguration(jenkinsClient) + return result, jenkinsClient, err } func (r *ReconcileJenkinsBaseConfiguration) verifyBasePlugins(jenkinsClient jenkinsclient.Jenkins) (bool, error) { @@ -183,6 +192,14 @@ func (r *ReconcileJenkinsBaseConfiguration) createScriptsConfigMap(meta metav1.O return r.createOrUpdateResource(scripts) } +func (r *ReconcileJenkinsBaseConfiguration) createInitConfigurationConfigMap(meta metav1.ObjectMeta) error { + scripts, err := resources.NewInitConfigurationConfigMap(meta, r.jenkins) + if err != nil { + return err + } + return r.createOrUpdateResource(scripts) +} + func (r *ReconcileJenkinsBaseConfiguration) createBaseConfigurationConfigMap(meta metav1.ObjectMeta) error { scripts, err := resources.NewBaseConfigurationConfigMap(meta, r.jenkins) if err != nil { @@ -220,12 +237,10 @@ func (r *ReconcileJenkinsBaseConfiguration) createJenkinsMasterPod(meta metav1.O if err != nil { return nil, err } - if r.jenkins.Status.BaseConfigurationCompletedTime != nil { - r.jenkins.Status.BaseConfigurationCompletedTime = nil - err = r.updateResource(r.jenkins) - if err != nil { - return nil, err - } + r.jenkins.Status = virtuslabv1alpha1.JenkinsStatus{} + err = r.updateResource(r.jenkins) + if err != nil { + return nil, err } return nil, nil } else if err != nil && !errors.IsNotFound(err) { @@ -238,25 +253,25 @@ func (r *ReconcileJenkinsBaseConfiguration) createJenkinsMasterPod(meta metav1.O (currentJenkinsMasterPod.Status.Phase == corev1.PodFailed || currentJenkinsMasterPod.Status.Phase == corev1.PodSucceeded || currentJenkinsMasterPod.Status.Phase == corev1.PodUnknown) { - r.logger.Info(fmt.Sprintf("Invalid Jenkins pod phase %v, recreating pod", currentJenkinsMasterPod.Status.Phase)) + r.logger.Info(fmt.Sprintf("Invalid Jenkins pod phase '%+v', recreating pod", currentJenkinsMasterPod.Status.Phase)) recreatePod = true } if currentJenkinsMasterPod != nil && r.jenkins.Spec.Master.Image != currentJenkinsMasterPod.Spec.Containers[0].Image { - r.logger.Info(fmt.Sprintf("Jenkins image has changed to %v, recreating pod", r.jenkins.Spec.Master.Image)) + r.logger.Info(fmt.Sprintf("Jenkins image has changed to '%+v', recreating pod", r.jenkins.Spec.Master.Image)) recreatePod = true } if currentJenkinsMasterPod != nil && len(r.jenkins.Spec.Master.Annotations) > 0 && !reflect.DeepEqual(r.jenkins.Spec.Master.Annotations, currentJenkinsMasterPod.ObjectMeta.Annotations) { - r.logger.Info(fmt.Sprintf("Jenkins pod annotations have changed to %v, recreating pod", r.jenkins.Spec.Master.Annotations)) + r.logger.Info(fmt.Sprintf("Jenkins pod annotations have changed to '%+v', recreating pod", r.jenkins.Spec.Master.Annotations)) recreatePod = true } if currentJenkinsMasterPod != nil && !reflect.DeepEqual(r.jenkins.Spec.Master.Resources, currentJenkinsMasterPod.Spec.Containers[0].Resources) { - r.logger.Info(fmt.Sprintf("Jenkins pod resources have changed to %v, recreating pod", r.jenkins.Spec.Master.Resources)) + r.logger.Info(fmt.Sprintf("Jenkins pod resources have changed to '%+v', recreating pod", r.jenkins.Spec.Master.Resources)) recreatePod = true } @@ -278,18 +293,18 @@ func (r *ReconcileJenkinsBaseConfiguration) waitForJenkins(meta metav1.ObjectMet } if jenkinsMasterPodStatus.ObjectMeta.DeletionTimestamp != nil { - r.logger.Info("Jenkins master pod is terminating") + r.logger.V(log.VDebug).Info("Jenkins master pod is terminating") return &reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}, nil } if jenkinsMasterPodStatus.Status.Phase != corev1.PodRunning { - r.logger.Info("Jenkins master pod not ready") + r.logger.V(log.VDebug).Info("Jenkins master pod not ready") return &reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}, nil } for _, containerStatus := range jenkinsMasterPodStatus.Status.ContainerStatuses { if !containerStatus.Ready { - r.logger.Info("Jenkins master pod not ready, readiness probe failed") + r.logger.V(log.VDebug).Info("Jenkins master pod not ready, readiness probe failed") return &reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}, nil } } @@ -357,3 +372,25 @@ func (r *ReconcileJenkinsBaseConfiguration) getJenkinsClient(meta metav1.ObjectM string(credentialsSecret.Data[resources.OperatorCredentialsSecretUserNameKey]), string(credentialsSecret.Data[resources.OperatorCredentialsSecretTokenKey])) } + +func (r *ReconcileJenkinsBaseConfiguration) baseConfiguration(jenkinsClient jenkinsclient.Jenkins) (*reconcile.Result, error) { + groovyClient := groovy.New(jenkinsClient, r.client, r.logger, fmt.Sprintf("%s-base-configuration", constants.OperatorName), resources.JenkinsBaseConfigurationVolumePath) + + err := groovyClient.ConfigureGroovyJob() + if err != nil { + return &reconcile.Result{}, err + } + + // set custom jenkins theme + done, err := groovyClient.EnsureGroovyJob(theme.SetThemeGroovyScript, r.jenkins) + if err != nil { + return &reconcile.Result{}, err + } + + // build not finished yet - requeue reconciliation loop with timeout + if !done { + return &reconcile.Result{Requeue: true, RequeueAfter: time.Second * 10}, nil + } + + return nil, nil +} diff --git a/pkg/controller/jenkins/configuration/base/resources.go b/pkg/controller/jenkins/configuration/base/resources.go index 2d157f18..6286ca79 100644 --- a/pkg/controller/jenkins/configuration/base/resources.go +++ b/pkg/controller/jenkins/configuration/base/resources.go @@ -30,7 +30,7 @@ func (r *ReconcileJenkinsBaseConfiguration) updateResource(obj metav1.Object) er return fmt.Errorf("is not a %T a runtime.Object", obj) } - // Set Jenkins instance as the owner and controller, don't check error(can be already set) + // set Jenkins instance as the owner and controller, don't check error(can be already set) _ = controllerutil.SetControllerReference(r.jenkins, obj, r.scheme) return r.client.Update(context.TODO(), runtimeObj) @@ -42,7 +42,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createOrUpdateResource(obj metav1.Ob return fmt.Errorf("is not a %T a runtime.Object", obj) } - // Set Jenkins instance as the owner and controller, don't check error(can be already set) + // set Jenkins instance as the owner and controller, don't check error(can be already set) _ = controllerutil.SetControllerReference(r.jenkins, obj, r.scheme) err := r.client.Create(context.TODO(), runtimeObj) diff --git a/pkg/controller/jenkins/configuration/base/resources/base_configuration_configmap.go b/pkg/controller/jenkins/configuration/base/resources/base_configuration_configmap.go index 5ede315e..e6a722a8 100644 --- a/pkg/controller/jenkins/configuration/base/resources/base_configuration_configmap.go +++ b/pkg/controller/jenkins/configuration/base/resources/base_configuration_configmap.go @@ -2,72 +2,172 @@ package resources import ( "fmt" - "text/template" virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" - "github.com/VirtusLab/jenkins-operator/pkg/controller/render" + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/constants" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -const createOperatorUserFileName = "createOperatorUser.groovy" +const basicSettingsFmt = `import jenkins.model.Jenkins +import jenkins.model.JenkinsLocationConfiguration +import hudson.model.Node.Mode -var createOperatorUserGroovyFmtTemplate = template.Must(template.New(createOperatorUserFileName).Parse(` -import hudson.security.* - -def jenkins = jenkins.model.Jenkins.getInstance() - -def hudsonRealm = new HudsonPrivateSecurityRealm(false) -hudsonRealm.createAccount( - new File('{{ .OperatorCredentialsPath }}/{{ .OperatorUserNameFile }}').text, - new File('{{ .OperatorCredentialsPath }}/{{ .OperatorPasswordFile }}').text) -jenkins.setSecurityRealm(hudsonRealm) - -def strategy = new FullControlOnceLoggedInAuthorizationStrategy() -strategy.setAllowAnonymousRead(false) -jenkins.setAuthorizationStrategy(strategy) +def jenkins = Jenkins.instance +//Number of jobs that run simultaneously on master, currently only backup and SeedJob. +jenkins.setNumExecutors(%d) +//Jobs must specify that they want to run on master +jenkins.setMode(Mode.EXCLUSIVE) jenkins.save() -`)) -func buildCreateJenkinsOperatorUserGroovyScript() (*string, error) { - data := struct { - OperatorCredentialsPath string - OperatorUserNameFile string - OperatorPasswordFile string - }{ - OperatorCredentialsPath: jenkinsOperatorCredentialsVolumePath, - OperatorUserNameFile: OperatorCredentialsSecretUserNameKey, - OperatorPasswordFile: OperatorCredentialsSecretPasswordKey, - } +` - output, err := render.Render(createOperatorUserGroovyFmtTemplate, data) - if err != nil { - return nil, err - } +const enableCSRF = `import hudson.security.csrf.DefaultCrumbIssuer +import jenkins.model.Jenkins - return &output, nil +def jenkins = Jenkins.instance + +if (jenkins.getCrumbIssuer() == null) { + jenkins.setCrumbIssuer(new DefaultCrumbIssuer(true)) + jenkins.save() + println('CSRF Protection enabled.') +} else { + println('CSRF Protection already configured.') } +` + +const disableUsageStats = `import jenkins.model.Jenkins + +def jenkins = Jenkins.instance + +if (jenkins.isUsageStatisticsCollected()) { + jenkins.setNoUsageStatistics(true) + jenkins.save() + println('Jenkins usage stats submitting disabled.') +} else { + println('Nothing changed. Usage stats are not submitted to the Jenkins project.') +} +` + +const enableMasterAccessControl = `import jenkins.security.s2m.AdminWhitelistRule +import jenkins.model.Jenkins + +// see https://wiki.jenkins-ci.org/display/JENKINS/Slave+To+Master+Access+Control +def jenkins = Jenkins.instance +jenkins.getInjector() + .getInstance(AdminWhitelistRule.class) + .setMasterKillSwitch(false) // for real though, false equals enabled.......... +jenkins.save() +` + +const disableInsecureFeatures = ` +import jenkins.* +import jenkins.model.* +import hudson.model.* +import jenkins.security.s2m.* + +def jenkins = Jenkins.instance + +println("Disabling insecure Jenkins features...") + +println("Disabling insecure protocols...") +println("Old protocols: [" + jenkins.getAgentProtocols().join(", ") + "]") +HashSet newProtocols = new HashSet<>(jenkins.getAgentProtocols()) +newProtocols.removeAll(Arrays.asList("JNLP3-connect", "JNLP2-connect", "JNLP-connect", "CLI-connect")) +println("New protocols: [" + newProtocols.join(", ") + "]") +jenkins.setAgentProtocols(newProtocols) + +println("Disabling CLI access of /cli URL...") +def remove = { list -> + list.each { item -> + if (item.getClass().name.contains("CLIAction")) { + println("Removing extension ${item.getClass().name}") + list.remove(item) + } + } +} +remove(jenkins.getExtensionList(RootAction.class)) +remove(jenkins.actions) + +println("Disable CLI completely...") +CLI.get().setEnabled(false) +println("CLI disabled") + +jenkins.save() +` + +const configureKubernetesPluginFmt = `import com.cloudbees.plugins.credentials.CredentialsScope +import com.cloudbees.plugins.credentials.SystemCredentialsProvider +import com.cloudbees.plugins.credentials.domains.Domain +import jenkins.model.Jenkins +import org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud +import org.csanchez.jenkins.plugins.kubernetes.ServiceAccountCredential + +def kubernetesCredentialsId = 'kubernetes-namespace-token' +def jenkins = Jenkins.getInstance() + +ServiceAccountCredential serviceAccountCredential = new ServiceAccountCredential( + CredentialsScope.GLOBAL, + kubernetesCredentialsId, + "Kubernetes Namespace Token" +) +SystemCredentialsProvider.getInstance().getStore().addCredentials(Domain.global(), serviceAccountCredential) + +KubernetesCloud kubernetes = new KubernetesCloud("kubernetes") +kubernetes.setServerUrl("https://kubernetes.default") +kubernetes.setNamespace("%s") +kubernetes.setCredentialsId(kubernetesCredentialsId) +kubernetes.setJenkinsUrl("http://%s:%d") +kubernetes.setRetentionTimeout(15) +jenkins.clouds.add(kubernetes) + +jenkins.save() +` + +const configureTheme = ` +import jenkins.* +import jenkins.model.* +import hudson.* +import hudson.model.* +import org.jenkinsci.plugins.simpletheme.ThemeElement +import org.jenkinsci.plugins.simpletheme.CssTextThemeElement +import org.jenkinsci.plugins.simpletheme.CssUrlThemeElement + +Jenkins jenkins = Jenkins.getInstance() + +def decorator = Jenkins.instance.getDescriptorByType(org.codefirst.SimpleThemeDecorator.class) + +List configElements = new ArrayList<>(); +configElements.add(new CssTextThemeElement("DEFAULT")); +configElements.add(new CssUrlThemeElement("https://cdn.rawgit.com/afonsof/jenkins-material-theme/gh-pages/dist/material-light-green.css")); +decorator.setElements(configElements); +decorator.save(); + +jenkins.save() +` // GetBaseConfigurationConfigMapName returns name of Kubernetes config map used to base configuration func GetBaseConfigurationConfigMapName(jenkins *virtuslabv1alpha1.Jenkins) string { - return fmt.Sprintf("jenkins-operator-base-configuration-%s", jenkins.ObjectMeta.Name) + return fmt.Sprintf("%s-base-configuration-%s", constants.OperatorName, jenkins.ObjectMeta.Name) } // NewBaseConfigurationConfigMap builds Kubernetes config map used to base configuration func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *virtuslabv1alpha1.Jenkins) (*corev1.ConfigMap, error) { meta.Name = GetBaseConfigurationConfigMapName(jenkins) - createJenkinsOperatorUserGroovy, err := buildCreateJenkinsOperatorUserGroovyScript() - if err != nil { - return nil, err - } - return &corev1.ConfigMap{ TypeMeta: buildConfigMapTypeMeta(), ObjectMeta: meta, Data: map[string]string{ - createOperatorUserFileName: *createJenkinsOperatorUserGroovy, + "1-basic-settings.groovy": fmt.Sprintf(basicSettingsFmt, constants.DefaultAmountOfExecutors), + "2-enable-csrf.groovy": enableCSRF, + "3-disable-usage-stats.groovy": disableUsageStats, + "4-enable-master-access-control.groovy": enableMasterAccessControl, + "5-disable-insecure-features.groovy": disableInsecureFeatures, + "6-configure-kubernetes-plugin.groovy": fmt.Sprintf(configureKubernetesPluginFmt, + jenkins.ObjectMeta.Namespace, GetResourceName(jenkins), HTTPPortInt), + "7-configure-theme.groovy": configureTheme, }, }, nil } diff --git a/pkg/controller/jenkins/configuration/base/resources/init_configuration_configmap.go b/pkg/controller/jenkins/configuration/base/resources/init_configuration_configmap.go index 5ede315e..e44c3bec 100644 --- a/pkg/controller/jenkins/configuration/base/resources/init_configuration_configmap.go +++ b/pkg/controller/jenkins/configuration/base/resources/init_configuration_configmap.go @@ -2,6 +2,7 @@ package resources import ( "fmt" + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/constants" "text/template" virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" @@ -49,14 +50,14 @@ func buildCreateJenkinsOperatorUserGroovyScript() (*string, error) { return &output, nil } -// GetBaseConfigurationConfigMapName returns name of Kubernetes config map used to base configuration -func GetBaseConfigurationConfigMapName(jenkins *virtuslabv1alpha1.Jenkins) string { - return fmt.Sprintf("jenkins-operator-base-configuration-%s", jenkins.ObjectMeta.Name) +// GetInitConfigurationConfigMapName returns name of Kubernetes config map used to init configuration +func GetInitConfigurationConfigMapName(jenkins *virtuslabv1alpha1.Jenkins) string { + return fmt.Sprintf("%s-init-configuration-%s", constants.OperatorName, jenkins.ObjectMeta.Name) } -// NewBaseConfigurationConfigMap builds Kubernetes config map used to base configuration -func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *virtuslabv1alpha1.Jenkins) (*corev1.ConfigMap, error) { - meta.Name = GetBaseConfigurationConfigMapName(jenkins) +// NewInitConfigurationConfigMap builds Kubernetes config map used to init configuration +func NewInitConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *virtuslabv1alpha1.Jenkins) (*corev1.ConfigMap, error) { + meta.Name = GetInitConfigurationConfigMapName(jenkins) createJenkinsOperatorUserGroovy, err := buildCreateJenkinsOperatorUserGroovyScript() if err != nil { diff --git a/pkg/controller/jenkins/configuration/base/resources/meta.go b/pkg/controller/jenkins/configuration/base/resources/meta.go index 8a8281b4..9e0d5216 100644 --- a/pkg/controller/jenkins/configuration/base/resources/meta.go +++ b/pkg/controller/jenkins/configuration/base/resources/meta.go @@ -2,6 +2,7 @@ package resources import ( "fmt" + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/constants" virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" @@ -20,12 +21,12 @@ func NewResourceObjectMeta(jenkins *virtuslabv1alpha1.Jenkins) metav1.ObjectMeta // BuildResourceLabels returns labels for all Kubernetes resources created by operator func BuildResourceLabels(jenkins *virtuslabv1alpha1.Jenkins) map[string]string { return map[string]string{ - "app": "jenkins-master", - "jenkins-cr": jenkins.Name, + constants.LabelAppKey: constants.LabelAppValue, + constants.LabelJenkinsCRKey: jenkins.Name, } } // GetResourceName returns name of Kubernetes resource base on Jenkins CR func GetResourceName(jenkins *virtuslabv1alpha1.Jenkins) string { - return fmt.Sprintf("jenkins-operator-%s", jenkins.ObjectMeta.Name) + return fmt.Sprintf("%s-%s", constants.LabelAppValue, jenkins.ObjectMeta.Name) } diff --git a/pkg/controller/jenkins/configuration/base/resources/pod.go b/pkg/controller/jenkins/configuration/base/resources/pod.go index bbbbe9a7..cdce8828 100644 --- a/pkg/controller/jenkins/configuration/base/resources/pod.go +++ b/pkg/controller/jenkins/configuration/base/resources/pod.go @@ -21,8 +21,12 @@ const ( jenkinsOperatorCredentialsVolumeName = "operator-credentials" jenkinsOperatorCredentialsVolumePath = "/var/jenkins/operator-credentials" + jenkinsInitConfigurationVolumeName = "init-configuration" + jenkinsInitConfigurationVolumePath = "/var/jenkins/init-configuration" + jenkinsBaseConfigurationVolumeName = "base-configuration" - jenkinsBaseConfigurationVolumePath = "/var/jenkins/base-configuration" + // JenkinsBaseConfigurationVolumePath is a path where are groovy scripts used to configure Jenkins + JenkinsBaseConfigurationVolumePath = "/var/jenkins/base-configuration" httpPortName = "http" slavePortName = "slavelistener" @@ -122,9 +126,14 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *virtuslabv1alpha MountPath: jenkinsScriptsVolumePath, ReadOnly: true, }, + { + Name: jenkinsInitConfigurationVolumeName, + MountPath: jenkinsInitConfigurationVolumePath, + ReadOnly: true, + }, { Name: jenkinsBaseConfigurationVolumeName, - MountPath: jenkinsBaseConfigurationVolumePath, + MountPath: JenkinsBaseConfigurationVolumePath, ReadOnly: true, }, { @@ -152,6 +161,16 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *virtuslabv1alpha }, }, }, + { + Name: jenkinsInitConfigurationVolumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: GetInitConfigurationConfigMapName(jenkins), + }, + }, + }, + }, { Name: jenkinsBaseConfigurationVolumeName, VolumeSource: corev1.VolumeSource{ diff --git a/pkg/controller/jenkins/configuration/base/resources/scripts_configmap.go b/pkg/controller/jenkins/configuration/base/resources/scripts_configmap.go index 48d059b0..6f29e124 100644 --- a/pkg/controller/jenkins/configuration/base/resources/scripts_configmap.go +++ b/pkg/controller/jenkins/configuration/base/resources/scripts_configmap.go @@ -5,6 +5,7 @@ import ( "text/template" virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/constants" "github.com/VirtusLab/jenkins-operator/pkg/controller/render" corev1 "k8s.io/api/core/v1" @@ -245,7 +246,7 @@ set -x # https://wiki.jenkins.io/display/JENKINS/Post-initialization+script mkdir -p {{ .JenkinsHomePath }}/init.groovy.d -cp -n {{ .BaseConfigurationPath }}/*.groovy {{ .JenkinsHomePath }}/init.groovy.d +cp -n {{ .InitConfigurationPath }}/*.groovy {{ .JenkinsHomePath }}/init.groovy.d mkdir -p {{ .JenkinsHomePath }}/scripts cp {{ .JenkinsScriptsVolumePath }}/*.sh {{ .JenkinsHomePath }}/scripts @@ -274,13 +275,13 @@ func buildConfigMapTypeMeta() metav1.TypeMeta { func buildInitBashScript(pluginsToInstall map[string][]string) (*string, error) { data := struct { JenkinsHomePath string - BaseConfigurationPath string + InitConfigurationPath string InstallPluginsCommand string JenkinsScriptsVolumePath string Plugins map[string][]string }{ JenkinsHomePath: jenkinsHomePath, - BaseConfigurationPath: jenkinsBaseConfigurationVolumePath, + InitConfigurationPath: jenkinsInitConfigurationVolumePath, Plugins: pluginsToInstall, InstallPluginsCommand: installPluginsCommand, JenkinsScriptsVolumePath: jenkinsScriptsVolumePath, @@ -295,7 +296,7 @@ func buildInitBashScript(pluginsToInstall map[string][]string) (*string, error) } func getScriptsConfigMapName(jenkins *virtuslabv1alpha1.Jenkins) string { - return fmt.Sprintf("jenkins-operator-scripts-%s", jenkins.ObjectMeta.Name) + return fmt.Sprintf("%s-scripts-%s", constants.OperatorName, jenkins.ObjectMeta.Name) } // NewScriptsConfigMap builds Kubernetes config map used to store scripts diff --git a/pkg/controller/jenkins/configuration/base/resources/secret.go b/pkg/controller/jenkins/configuration/base/resources/secret.go index 4c247922..00e7091e 100644 --- a/pkg/controller/jenkins/configuration/base/resources/secret.go +++ b/pkg/controller/jenkins/configuration/base/resources/secret.go @@ -2,6 +2,7 @@ package resources import ( "fmt" + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/constants" virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" @@ -32,7 +33,7 @@ func buildSecretTypeMeta() metav1.TypeMeta { // GetOperatorCredentialsSecretName returns name of Kubernetes secret used to store jenkins operator credentials // to allow calls to Jenkins API func GetOperatorCredentialsSecretName(jenkins *virtuslabv1alpha1.Jenkins) string { - return fmt.Sprintf("jenkins-operator-credentials-%s", jenkins.Name) + return fmt.Sprintf("%s-credentials-%s", constants.OperatorName, jenkins.Name) } // NewOperatorCredentialsSecret builds the Kubernetes secret used to store jenkins operator credentials diff --git a/pkg/controller/jenkins/configuration/user/reconcile.go b/pkg/controller/jenkins/configuration/user/reconcile.go index df102fe4..34f602d2 100644 --- a/pkg/controller/jenkins/configuration/user/reconcile.go +++ b/pkg/controller/jenkins/configuration/user/reconcile.go @@ -6,8 +6,6 @@ import ( virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" jenkinsclient "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/client" "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/user/seedjobs" - "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/user/theme" - "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/groovy" "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/jobs" "github.com/go-logr/logr" @@ -42,8 +40,7 @@ func (r *ReconcileUserConfiguration) Reconcile() (*reconcile.Result, error) { return result, err } - // reconcile custom groovy scripts - return r.reconcileCustomGroovy() + return nil, nil } func (r *ReconcileUserConfiguration) reconcileSeedJobs() (*reconcile.Result, error) { @@ -67,25 +64,3 @@ func (r *ReconcileUserConfiguration) reconcileSeedJobs() (*reconcile.Result, err } return nil, nil } - -func (r *ReconcileUserConfiguration) reconcileCustomGroovy() (*reconcile.Result, error) { - groovyClient := groovy.New(r.jenkinsClient, r.k8sClient, r.logger) - - err := groovyClient.ConfigureGroovyJob() - if err != nil { - return &reconcile.Result{}, err - } - - // set custom jenkins theme - done, err := groovyClient.EnsureGroovyJob(theme.SetThemeGroovyScript, r.jenkins) - if err != nil { - return &reconcile.Result{}, err - } - - // build not finished yet - requeue reconciliation loop with timeout - if !done { - return &reconcile.Result{Requeue: true, RequeueAfter: time.Second * 10}, nil - } - - return nil, nil -} diff --git a/pkg/controller/jenkins/constants/constants.go b/pkg/controller/jenkins/constants/constants.go index 1255fc8b..4c97d4a6 100644 --- a/pkg/controller/jenkins/constants/constants.go +++ b/pkg/controller/jenkins/constants/constants.go @@ -1 +1,8 @@ package constants + +const ( + // OperatorName is a operator name + OperatorName = "jenkins-operator" + // DefaultAmountOfExecutors is the default amount of Jenkins executors + DefaultAmountOfExecutors = 3 +) diff --git a/pkg/controller/jenkins/constants/labels.go b/pkg/controller/jenkins/constants/labels.go index 1255fc8b..93b478b0 100644 --- a/pkg/controller/jenkins/constants/labels.go +++ b/pkg/controller/jenkins/constants/labels.go @@ -1 +1,11 @@ package constants + +const ( + LabelAppKey = "app" + LabelAppValue = OperatorName + + LabelWatchKey = "watch" + LabelWatchValue = "true" + + LabelJenkinsCRKey = "jenkins-cr" +) diff --git a/pkg/controller/jenkins/groovy/groovy.go b/pkg/controller/jenkins/groovy/groovy.go index 7d5c6cf5..433db96b 100644 --- a/pkg/controller/jenkins/groovy/groovy.go +++ b/pkg/controller/jenkins/groovy/groovy.go @@ -3,6 +3,7 @@ package groovy import ( "crypto/sha256" "encoding/base64" + "fmt" virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" jenkinsclient "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/client" @@ -12,32 +13,29 @@ import ( k8s "sigs.k8s.io/controller-runtime/pkg/client" ) -const ( - // ExecuteGroovyJobName this is the fixed execute groovy job name - ExecuteGroovyJobName = "Execute Groovy Scripts" - - groovyScriptParameterName = "GROOVY_SCRIPT" -) - // Groovy defines API for groovy scripts execution via jenkins job type Groovy struct { jenkinsClient jenkinsclient.Jenkins k8sClient k8s.Client logger logr.Logger + jobName string + scriptsPath string } // New creates new instance of Groovy -func New(jenkinsClient jenkinsclient.Jenkins, k8sClient k8s.Client, logger logr.Logger) *Groovy { +func New(jenkinsClient jenkinsclient.Jenkins, k8sClient k8s.Client, logger logr.Logger, jobName, scriptsPath string) *Groovy { return &Groovy{ jenkinsClient: jenkinsClient, k8sClient: k8sClient, logger: logger, + jobName: jobName, + scriptsPath: scriptsPath, } } // ConfigureGroovyJob configures jenkins job for executing groovy scripts func (g *Groovy) ConfigureGroovyJob() error { - _, err := g.jenkinsClient.CreateOrUpdateJob(groovyJobConfigXML, ExecuteGroovyJobName) + _, err := g.jenkinsClient.CreateOrUpdateJob(fmt.Sprintf(configurationJobXMLFmt, g.scriptsPath, g.scriptsPath), g.jobName) if err != nil { return err } @@ -53,43 +51,32 @@ func (g *Groovy) EnsureGroovyJob(groovyScript string, jenkins *virtuslabv1alpha1 hash.Write([]byte(groovyScript)) encodedHash := base64.URLEncoding.EncodeToString(hash.Sum(nil)) - parameters := map[string]string{ - groovyScriptParameterName: groovyScript, - } - - done, err := jobsClient.EnsureBuildJob(ExecuteGroovyJobName, encodedHash, parameters, jenkins, true) + done, err := jobsClient.EnsureBuildJob(g.jobName, encodedHash, map[string]string{}, jenkins, true) if err != nil { return false, err } return done, nil } -// FIXME(antoniaklja) use mask-password plugin for params.GROOVY_SCRIPT -// TODO add groovy script name -var groovyJobConfigXML = ` - +const configurationJobXMLFmt = ` + false - - - - - ` + groovyScriptParameterName + ` - - - false - - - - - - +node('master') { + def scriptsText = sh(script: 'ls %s', returnStdout: true).trim() + def scripts = [] + scripts.addAll(scriptsText.tokenize('\n')) + for(script in scripts) { + stage(script) { + load "%s/${script}" + } + } +} false diff --git a/pkg/controller/jenkins/handler.go b/pkg/controller/jenkins/handler.go index 44adaafe..1f655f19 100644 --- a/pkg/controller/jenkins/handler.go +++ b/pkg/controller/jenkins/handler.go @@ -1 +1,54 @@ package jenkins + +import ( + "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/constants" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// enqueueRequestForJenkins enqueues a Request for secrets and configmaps created by jenkins-operator. +type enqueueRequestForJenkins struct{} + +func (e *enqueueRequestForJenkins) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) { + if req := e.getOwnerReconcileRequests(evt.Meta); req != nil { + q.Add(req) + } +} + +func (e *enqueueRequestForJenkins) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) { + if req := e.getOwnerReconcileRequests(evt.MetaOld); req != nil { + q.Add(*req) + } + if req := e.getOwnerReconcileRequests(evt.MetaNew); req != nil { + q.Add(*req) + } +} + +func (e *enqueueRequestForJenkins) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) { + if req := e.getOwnerReconcileRequests(evt.Meta); req != nil { + q.Add(*req) + } +} + +func (e *enqueueRequestForJenkins) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) { + if req := e.getOwnerReconcileRequests(evt.Meta); req != nil { + q.Add(*req) + } +} + +func (e *enqueueRequestForJenkins) getOwnerReconcileRequests(object metav1.Object) *reconcile.Request { + if object.GetLabels()[constants.LabelAppKey] == constants.LabelAppValue && + object.GetLabels()[constants.LabelWatchKey] == constants.LabelWatchValue && + len(object.GetLabels()[constants.LabelJenkinsCRKey]) > 0 { + return &reconcile.Request{NamespacedName: types.NamespacedName{ + Namespace: object.GetNamespace(), + Name: object.GetLabels()[constants.LabelJenkinsCRKey], + }} + } + + return nil +} diff --git a/pkg/controller/jenkins/jenkins_controller.go b/pkg/controller/jenkins/jenkins_controller.go index b5100558..5eddbe03 100644 --- a/pkg/controller/jenkins/jenkins_controller.go +++ b/pkg/controller/jenkins/jenkins_controller.go @@ -52,7 +52,6 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return err } - // TODO 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, @@ -62,6 +61,17 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return err } + jenkinsHandler := &enqueueRequestForJenkins{} + err = c.Watch(&source.Kind{Type: &corev1.Secret{}}, jenkinsHandler) + if err != nil { + return err + } + + err = c.Watch(&source.Kind{Type: &corev1.ConfigMap{}}, jenkinsHandler) + if err != nil { + return err + } + return nil }