From 583d6fa4d298255823f192490daed25c10618111 Mon Sep 17 00:00:00 2001 From: jessicagreben Date: Fri, 4 Jan 2019 20:56:30 -0800 Subject: [PATCH 1/5] im ugly but i work --- Gopkg.lock | 160 +++--------------- main.go | 57 ++++++- pkg/kube/clientset.go | 61 +++++++ pkg/validator/pod.go | 5 +- .../github.com/mitchellh/go-homedir/LICENSE | 21 +++ .../github.com/mitchellh/go-homedir/README.md | 14 ++ vendor/github.com/mitchellh/go-homedir/go.mod | 1 + .../mitchellh/go-homedir/homedir.go | 157 +++++++++++++++++ 8 files changed, 336 insertions(+), 140 deletions(-) create mode 100644 pkg/kube/clientset.go create mode 100644 vendor/github.com/mitchellh/go-homedir/LICENSE create mode 100644 vendor/github.com/mitchellh/go-homedir/README.md create mode 100644 vendor/github.com/mitchellh/go-homedir/go.mod create mode 100644 vendor/github.com/mitchellh/go-homedir/homedir.go diff --git a/Gopkg.lock b/Gopkg.lock index 74f698dc5..1bb6aa301 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,311 +2,248 @@ [[projects]] - digest = "1:5ad08b0e14866764a6d7475eb11c9cf05cad9a52c442593bdfa544703ff77f61" name = "cloud.google.com/go" packages = ["compute/metadata"] - pruneopts = "UT" revision = "0ebda48a7f143b1cce9eb37a8c1106ac762a3430" version = "v0.34.0" [[projects]] branch = "master" - digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d" name = "github.com/beorn7/perks" packages = ["quantile"] - pruneopts = "UT" revision = "3a771d992973f24aa725d07868b467d1ddfceafb" [[projects]] - digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" name = "github.com/davecgh/go-spew" packages = ["spew"] - pruneopts = "UT" revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" version = "v1.1.1" [[projects]] - digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda" name = "github.com/ghodss/yaml" packages = ["."] - pruneopts = "UT" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" version = "v1.0.0" [[projects]] branch = "master" - digest = "1:edd2fa4578eb086265db78a9201d15e76b298dfd0d5c379da83e9c61712cf6df" name = "github.com/go-logr/logr" packages = ["."] - pruneopts = "UT" revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e" [[projects]] - digest = "1:ce43ad4015e7cdad3f0e8f2c8339439dd4470859a828d2a6988b0f713699e94a" name = "github.com/go-logr/zapr" packages = ["."] - pruneopts = "UT" revision = "7536572e8d55209135cd5e7ccf7fce43dca217ab" version = "v0.1.0" [[projects]] - digest = "1:b402bb9a24d108a9405a6f34675091b036c8b056aac843bf6ef2389a65c5cf48" name = "github.com/gogo/protobuf" packages = [ "proto", - "sortkeys", + "sortkeys" ] - pruneopts = "UT" revision = "4cbf7e384e768b4e01799441fdf2a706a5635ae7" version = "v1.2.0" [[projects]] branch = "master" - digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467" name = "github.com/golang/glog" packages = ["."] - pruneopts = "UT" revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" [[projects]] branch = "master" - digest = "1:3fb07f8e222402962fa190eb060608b34eddfb64562a18e2167df2de0ece85d8" name = "github.com/golang/groupcache" packages = ["lru"] - pruneopts = "UT" revision = "c65c006176ff7ff98bb916961c7abbc6b0afc0aa" [[projects]] - digest = "1:4c0989ca0bcd10799064318923b9bc2db6b4d6338dd75f3f2d86c3511aaaf5cf" name = "github.com/golang/protobuf" packages = [ "proto", "ptypes", "ptypes/any", "ptypes/duration", - "ptypes/timestamp", + "ptypes/timestamp" ] - pruneopts = "UT" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" version = "v1.2.0" [[projects]] branch = "master" - digest = "1:0bfbe13936953a98ae3cfe8ed6670d396ad81edf069a806d2f6515d7bb6950df" name = "github.com/google/btree" packages = ["."] - pruneopts = "UT" revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306" [[projects]] branch = "master" - digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb" name = "github.com/google/gofuzz" packages = ["."] - pruneopts = "UT" revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" [[projects]] - digest = "1:236d7e1bdb50d8f68559af37dbcf9d142d56b431c9b2176d41e2a009b664cda8" name = "github.com/google/uuid" packages = ["."] - pruneopts = "UT" revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8" version = "v1.1.0" [[projects]] - digest = "1:65c4414eeb350c47b8de71110150d0ea8a281835b1f386eacaa3ad7325929c21" name = "github.com/googleapis/gnostic" packages = [ "OpenAPIv2", "compiler", - "extensions", + "extensions" ] - pruneopts = "UT" revision = "7c663266750e7d82587642f65e60bc4083f1f84e" version = "v0.2.0" [[projects]] branch = "master" - digest = "1:86c1210529e69d69860f2bb3ee9ccce0b595aa3f9165e7dd1388e5c612915888" name = "github.com/gregjones/httpcache" packages = [ ".", - "diskcache", + "diskcache" ] - pruneopts = "UT" revision = "c63ab54fda8f77302f8d414e19933f2b6026a089" [[projects]] - digest = "1:8ec8d88c248041a6df5f6574b87bc00e7e0b493881dad2e7ef47b11dc69093b5" name = "github.com/hashicorp/golang-lru" packages = [ ".", - "simplelru", + "simplelru" ] - pruneopts = "UT" revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" version = "v0.5.0" [[projects]] - digest = "1:8eb1de8112c9924d59bf1d3e5c26f5eaa2bfc2a5fcbb92dc1c2e4546d695f277" name = "github.com/imdario/mergo" packages = ["."] - pruneopts = "UT" revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4" version = "v0.3.6" [[projects]] - digest = "1:3e551bbb3a7c0ab2a2bf4660e7fcad16db089fdcfbb44b0199e62838038623ea" name = "github.com/json-iterator/go" packages = ["."] - pruneopts = "UT" revision = "1624edc4454b8682399def8740d46db5e4362ba4" version = "v1.1.5" [[projects]] branch = "master" - digest = "1:fc2b04b0069d6b10bdef96d278fe20c345794009685ed3c8c7f1a6dc023eefec" name = "github.com/mattbaird/jsonpatch" packages = ["."] - pruneopts = "UT" revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f" [[projects]] - digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc" name = "github.com/matttproud/golang_protobuf_extensions" packages = ["pbutil"] - pruneopts = "UT" revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" version = "v1.0.1" [[projects]] - digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563" + name = "github.com/mitchellh/go-homedir" + packages = ["."] + revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4" + version = "v1.0.0" + +[[projects]] name = "github.com/modern-go/concurrent" packages = ["."] - pruneopts = "UT" revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" version = "1.0.3" [[projects]] - digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855" name = "github.com/modern-go/reflect2" packages = ["."] - pruneopts = "UT" revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" version = "1.0.1" [[projects]] - digest = "1:e5d0bd87abc2781d14e274807a470acd180f0499f8bf5bb18606e9ec22ad9de9" name = "github.com/pborman/uuid" packages = ["."] - pruneopts = "UT" revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1" version = "v1.2" [[projects]] branch = "master" - digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2" name = "github.com/petar/GoLLRB" packages = ["llrb"] - pruneopts = "UT" revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" [[projects]] - digest = "1:0e7775ebbcf00d8dd28ac663614af924411c868dca3d5aa762af0fae3808d852" name = "github.com/peterbourgon/diskv" packages = ["."] - pruneopts = "UT" revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" version = "v2.0.1" [[projects]] - digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" name = "github.com/pmezard/go-difflib" packages = ["difflib"] - pruneopts = "UT" revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" [[projects]] - digest = "1:93a746f1060a8acbcf69344862b2ceced80f854170e1caae089b2834c5fbf7f4" name = "github.com/prometheus/client_golang" packages = [ "prometheus", "prometheus/internal", - "prometheus/promhttp", + "prometheus/promhttp" ] - pruneopts = "UT" revision = "505eaef017263e299324067d40ca2c48f6a2cf50" version = "v0.9.2" [[projects]] branch = "master" - digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4" name = "github.com/prometheus/client_model" packages = ["go"] - pruneopts = "UT" revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f" [[projects]] branch = "master" - digest = "1:33c81bf709f084827a560e14415b1d7001a6d1d6fa4bec2cc2e60b84ecbc0e0a" name = "github.com/prometheus/common" packages = [ "expfmt", "internal/bitbucket.org/ww/goautoneg", - "model", + "model" ] - pruneopts = "UT" revision = "67670fe90761d7ff18ec1d640135e53b9198328f" [[projects]] branch = "master" - digest = "1:d39e7c7677b161c2dd4c635a2ac196460608c7d8ba5337cc8cae5825a2681f8f" name = "github.com/prometheus/procfs" packages = [ ".", "internal/util", "nfs", - "xfs", + "xfs" ] - pruneopts = "UT" revision = "1dc9a6cbc91aacc3e8b2d63db4d2e957a5394ac4" [[projects]] - digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2" name = "github.com/spf13/pflag" packages = ["."] - pruneopts = "UT" revision = "298182f68c66c05229eb03ac171abe6e309ee79a" version = "v1.0.3" [[projects]] - digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83" name = "github.com/stretchr/testify" packages = ["assert"] - pruneopts = "UT" revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" version = "v1.2.2" [[projects]] - digest = "1:3c1a69cdae3501bf75e76d0d86dc6f2b0a7421bc205c0cb7b96b19eed464a34d" name = "go.uber.org/atomic" packages = ["."] - pruneopts = "UT" revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289" version = "v1.3.2" [[projects]] - digest = "1:60bf2a5e347af463c42ed31a493d817f8a72f102543060ed992754e689805d1a" name = "go.uber.org/multierr" packages = ["."] - pruneopts = "UT" revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" version = "v1.1.0" [[projects]] - digest = "1:c52caf7bd44f92e54627a31b85baf06a68333a196b3d8d241480a774733dcf8b" name = "go.uber.org/zap" packages = [ ".", @@ -314,23 +251,19 @@ "internal/bufferpool", "internal/color", "internal/exit", - "zapcore", + "zapcore" ] - pruneopts = "UT" revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982" version = "v1.9.1" [[projects]] branch = "master" - digest = "1:38f553aff0273ad6f367cb0a0f8b6eecbaef8dc6cb8b50e57b6a81c1d5b1e332" name = "golang.org/x/crypto" packages = ["ssh/terminal"] - pruneopts = "UT" revision = "505ab145d0a99da450461ae2c1a9f6cd10d1f447" [[projects]] branch = "master" - digest = "1:37f4a0712bbf9b111cf2951fe0efeea300ce87f7915047d4d1d5806a256ca634" name = "golang.org/x/net" packages = [ "context", @@ -338,38 +271,32 @@ "http/httpguts", "http2", "http2/hpack", - "idna", + "idna" ] - pruneopts = "UT" revision = "e147a9138326bc0e9d4e179541ffd8af41cff8a9" [[projects]] branch = "master" - digest = "1:23443edff0740e348959763085df98400dcfd85528d7771bb0ce9f5f2754ff4a" name = "golang.org/x/oauth2" packages = [ ".", "google", "internal", "jws", - "jwt", + "jwt" ] - pruneopts = "UT" revision = "d668ce993890a79bda886613ee587a69dd5da7a6" [[projects]] branch = "master" - digest = "1:ba8cbf57cfd92d5f8592b4aca1a35d92c162363d32aeabd5b12555f8896635e7" name = "golang.org/x/sys" packages = [ "unix", - "windows", + "windows" ] - pruneopts = "UT" revision = "074acd46bca67915925527c07849494d115e7c43" [[projects]] - digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" name = "golang.org/x/text" packages = [ "collate", @@ -385,22 +312,18 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable", + "unicode/rangetable" ] - pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" - digest = "1:9fdc2b55e8e0fafe4b41884091e51e77344f7dc511c5acedcfd98200003bff90" name = "golang.org/x/time" packages = ["rate"] - pruneopts = "UT" revision = "85acf8d2951cb2a3bde7632f9ff273ef0379bcbd" [[projects]] - digest = "1:d2a8db567a76203e3b41c1f632d86485ffd57f8e650a0d1b19d240671c2fddd7" name = "google.golang.org/appengine" packages = [ ".", @@ -412,30 +335,24 @@ "internal/modules", "internal/remote_api", "internal/urlfetch", - "urlfetch", + "urlfetch" ] - pruneopts = "UT" revision = "4a4468ece617fc8205e99368fa2200e9d1fad421" version = "v1.3.0" [[projects]] - digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a" name = "gopkg.in/inf.v0" packages = ["."] - pruneopts = "UT" revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" version = "v0.9.1" [[projects]] - digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96" name = "gopkg.in/yaml.v2" packages = ["."] - pruneopts = "UT" revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" version = "v2.2.2" [[projects]] - digest = "1:26a67eb988225c6a0600c1af0b35e795ac4d23a9c40a7aa178fa2adc0670f1f7" name = "k8s.io/api" packages = [ "admission/v1beta1", @@ -469,14 +386,12 @@ "settings/v1alpha1", "storage/v1", "storage/v1alpha1", - "storage/v1beta1", + "storage/v1beta1" ] - pruneopts = "UT" revision = "b503174bad5991eb66f18247f52e41c3258f6348" version = "kubernetes-1.12.3" [[projects]] - digest = "1:f9e57fe82defaffc4b08beec93c4257edce482b124989c8239b7fc6077e8b020" name = "k8s.io/apimachinery" packages = [ "pkg/api/errors", @@ -521,14 +436,12 @@ "pkg/version", "pkg/watch", "third_party/forked/golang/json", - "third_party/forked/golang/reflect", + "third_party/forked/golang/reflect" ] - pruneopts = "UT" revision = "eddba98df674a16931d2d4ba75edc3a389bf633a" version = "kubernetes-1.12.3" [[projects]] - digest = "1:5f848f56ec4519db7b85807938720b273d12574cb025c95c688d944ce8b96236" name = "k8s.io/client-go" packages = [ "discovery", @@ -596,22 +509,18 @@ "util/homedir", "util/integer", "util/jsonpath", - "util/retry", + "util/retry" ] - pruneopts = "UT" revision = "d082d5923d3cc0bfbb066ee5fbdea3d0ca79acf8" version = "kubernetes-1.12.3" [[projects]] branch = "master" - digest = "1:03a96603922fc1f6895ae083e1e16d943b55ef0656b56965351bd87e7d90485f" name = "k8s.io/kube-openapi" packages = ["pkg/util/proto"] - pruneopts = "UT" revision = "0317810137be915b9cf888946c6e115c1bfac693" [[projects]] - digest = "1:ccfdc36595beda0f5eec48594fd0baaa71471076cc0f3a2af06d66d577ff509c" name = "sigs.k8s.io/controller-runtime" packages = [ "pkg/cache", @@ -636,33 +545,14 @@ "pkg/webhook/internal/cert/generator", "pkg/webhook/internal/cert/writer", "pkg/webhook/internal/cert/writer/atomic", - "pkg/webhook/types", + "pkg/webhook/types" ] - pruneopts = "UT" revision = "c63ebda0bf4be5f0a8abd4003e4ea546032545ba" version = "v0.1.8" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - input-imports = [ - "github.com/stretchr/testify/assert", - "k8s.io/api/admissionregistration/v1beta1", - "k8s.io/api/core/v1", - "k8s.io/apimachinery/pkg/api/resource", - "k8s.io/apimachinery/pkg/types", - "k8s.io/apimachinery/pkg/util/yaml", - "k8s.io/client-go/plugin/pkg/client/auth/gcp", - "sigs.k8s.io/controller-runtime/pkg/client", - "sigs.k8s.io/controller-runtime/pkg/client/config", - "sigs.k8s.io/controller-runtime/pkg/manager", - "sigs.k8s.io/controller-runtime/pkg/runtime/inject", - "sigs.k8s.io/controller-runtime/pkg/runtime/log", - "sigs.k8s.io/controller-runtime/pkg/runtime/signals", - "sigs.k8s.io/controller-runtime/pkg/webhook", - "sigs.k8s.io/controller-runtime/pkg/webhook/admission", - "sigs.k8s.io/controller-runtime/pkg/webhook/admission/builder", - "sigs.k8s.io/controller-runtime/pkg/webhook/admission/types", - ] + inputs-digest = "cf1e4b6e9f0553ae9252b9f5fe069f3e8cfe142991689fa2cbe6d0d99df01c12" solver-name = "gps-cdcl" solver-version = 1 diff --git a/main.go b/main.go index babe17e4d..1940eb109 100644 --- a/main.go +++ b/main.go @@ -15,13 +15,18 @@ package main import ( + "encoding/json" "flag" + glog "log" + "net/http" "os" conf "github.com/reactiveops/fairwinds/pkg/config" + "github.com/reactiveops/fairwinds/pkg/kube" "github.com/reactiveops/fairwinds/pkg/validator" admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" apitypes "k8s.io/apimachinery/pkg/types" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" "sigs.k8s.io/controller-runtime/pkg/client/config" @@ -37,19 +42,65 @@ var FairwindsName = "fairwinds" var log = logf.Log.WithName(FairwindsName) func main() { + dashboard := flag.Bool("dashboard", false, "Runs the webserver for Fairwinds dashboard.") + webhook := flag.Bool("webhook", false, "Runs the webhook webserver.") + var disableWebhookConfigInstaller bool flag.BoolVar(&disableWebhookConfigInstaller, "disable-webhook-config-installer", false, "disable the installer in the webhook server, so it won't install webhook configuration resources during bootstrapping") flag.Parse() - logf.SetLogger(logf.ZapLogger(false)) - entryLog := log.WithName("entrypoint") c, err := conf.ParseFile("config.yml") if err != nil { - entryLog.Error(err, "parse config err") + return + } + + if *webhook { + startWebhookServer(c, disableWebhookConfigInstaller) } + if *dashboard { + startDashboardServer(c) + } +} + +// containers: +// name: example-123 +// checks: +// - name: Resource Requests +// valid: true +// - name: Resource Limits +// valid: false +// message: "CPU resource limit is too low (expected: 1m, actual: nil)" + +func startDashboardServer(c conf.Configuration) { + http.HandleFunc("/validate", func(w http.ResponseWriter, r *http.Request) { validateHandler(w, r, c) }) + glog.Println("Starting Fairwinds dashboard webserver on port 8080.") + glog.Fatal(http.ListenAndServe(":8080", nil)) +} + +func validateHandler(w http.ResponseWriter, r *http.Request, c conf.Configuration) { + var results []validator.Results + pods, err := kube.CoreV1API.Pods("").List(metav1.ListOptions{}) + if err != nil { + return + } + glog.Println("pods count:", len(pods.Items)) + for _, pod := range pods.Items { + result := validator.ValidatePods(c, &pod, validator.Results{}) + results = append(results, result) + } + // aggregate results + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(results) +} + +func startWebhookServer(c conf.Configuration, disableWebhookConfigInstaller bool) { + logf.SetLogger(logf.ZapLogger(false)) + entryLog := log.WithName("entrypoint") + // Setup a Manager entryLog.Info("setting up manager") mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{}) diff --git a/pkg/kube/clientset.go b/pkg/kube/clientset.go new file mode 100644 index 000000000..2bf1695c1 --- /dev/null +++ b/pkg/kube/clientset.go @@ -0,0 +1,61 @@ +package kube + +import ( + "fmt" + "os" + "path/filepath" + + homedir "github.com/mitchellh/go-homedir" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" +) + +// createClientset loads kubeconfig and setups the connection to the k8s api. +func createClientset() *kubernetes.Clientset { + kubeconfig := getKubeConfig() + config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) + if err != nil { + fmt.Println("Error:", err) + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + fmt.Println("Error:", err) + } + + return clientset +} + +// getKubeConfig returns a valid kubeconfig path. +func getKubeConfig() string { + var path string + + if os.Getenv("KUBECONFIG") != "" { + path = os.Getenv("KUBECONFIG") + return path + } + + if home, err := homedir.Dir(); err == nil { + path = filepath.Join(home, ".kube", "config") + } + + if _, err := os.Stat(path); err != nil { + // No kubeconfig exists, therefor return an emtpy string to + // indicate that this web server is running inside the cluster. + return "" + } + return path +} + +var clientset = createClientset() + +// Kubernetes version 1.11 APIs + +// CoreV1API exports the v1 Core API client. +var CoreV1API = clientset.CoreV1() + +// AutoscalingV1API exports the v1 Autoscaling API client. +var AutoscalingV1API = clientset.AutoscalingV1() + +// AppsV1API exports the v1 Apps API client. +var AppsV1API = clientset.AppsV1() diff --git a/pkg/validator/pod.go b/pkg/validator/pod.go index 6d0d57d49..772efe4c4 100644 --- a/pkg/validator/pod.go +++ b/pkg/validator/pod.go @@ -48,13 +48,14 @@ func (v *PodValidator) Handle(ctx context.Context, req types.Request) types.Resp return admission.ErrorResponse(http.StatusBadRequest, err) } - results := validatePods(v.Config, pod, Results{}) + results := ValidatePods(v.Config, pod, Results{}) allowed, reason := results.Format() return admission.ValidationResponse(allowed, reason) } -func validatePods(conf conf.Configuration, pod *corev1.Pod, results Results) Results { +// ValidatePods does x. +func ValidatePods(conf conf.Configuration, pod *corev1.Pod, results Results) Results { for _, container := range pod.Spec.InitContainers { results.InitContainerValidations = append( results.InitContainerValidations, diff --git a/vendor/github.com/mitchellh/go-homedir/LICENSE b/vendor/github.com/mitchellh/go-homedir/LICENSE new file mode 100644 index 000000000..f9c841a51 --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-homedir/README.md b/vendor/github.com/mitchellh/go-homedir/README.md new file mode 100644 index 000000000..d70706d5b --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/README.md @@ -0,0 +1,14 @@ +# go-homedir + +This is a Go library for detecting the user's home directory without +the use of cgo, so the library can be used in cross-compilation environments. + +Usage is incredibly simple, just call `homedir.Dir()` to get the home directory +for a user, and `homedir.Expand()` to expand the `~` in a path to the home +directory. + +**Why not just use `os/user`?** The built-in `os/user` package requires +cgo on Darwin systems. This means that any Go code that uses that package +cannot cross compile. But 99% of the time the use for `os/user` is just to +retrieve the home directory, which we can do for the current user without +cgo. This library does that, enabling cross-compilation. diff --git a/vendor/github.com/mitchellh/go-homedir/go.mod b/vendor/github.com/mitchellh/go-homedir/go.mod new file mode 100644 index 000000000..7efa09a04 --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/go.mod @@ -0,0 +1 @@ +module github.com/mitchellh/go-homedir diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go new file mode 100644 index 000000000..fb87bef94 --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/homedir.go @@ -0,0 +1,157 @@ +package homedir + +import ( + "bytes" + "errors" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" +) + +// DisableCache will disable caching of the home directory. Caching is enabled +// by default. +var DisableCache bool + +var homedirCache string +var cacheLock sync.RWMutex + +// Dir returns the home directory for the executing user. +// +// This uses an OS-specific method for discovering the home directory. +// An error is returned if a home directory cannot be detected. +func Dir() (string, error) { + if !DisableCache { + cacheLock.RLock() + cached := homedirCache + cacheLock.RUnlock() + if cached != "" { + return cached, nil + } + } + + cacheLock.Lock() + defer cacheLock.Unlock() + + var result string + var err error + if runtime.GOOS == "windows" { + result, err = dirWindows() + } else { + // Unix-like system, so just assume Unix + result, err = dirUnix() + } + + if err != nil { + return "", err + } + homedirCache = result + return result, nil +} + +// Expand expands the path to include the home directory if the path +// is prefixed with `~`. If it isn't prefixed with `~`, the path is +// returned as-is. +func Expand(path string) (string, error) { + if len(path) == 0 { + return path, nil + } + + if path[0] != '~' { + return path, nil + } + + if len(path) > 1 && path[1] != '/' && path[1] != '\\' { + return "", errors.New("cannot expand user-specific home dir") + } + + dir, err := Dir() + if err != nil { + return "", err + } + + return filepath.Join(dir, path[1:]), nil +} + +func dirUnix() (string, error) { + homeEnv := "HOME" + if runtime.GOOS == "plan9" { + // On plan9, env vars are lowercase. + homeEnv = "home" + } + + // First prefer the HOME environmental variable + if home := os.Getenv(homeEnv); home != "" { + return home, nil + } + + var stdout bytes.Buffer + + // If that fails, try OS specific commands + if runtime.GOOS == "darwin" { + cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) + cmd.Stdout = &stdout + if err := cmd.Run(); err == nil { + result := strings.TrimSpace(stdout.String()) + if result != "" { + return result, nil + } + } + } else { + cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + // If the error is ErrNotFound, we ignore it. Otherwise, return it. + if err != exec.ErrNotFound { + return "", err + } + } else { + if passwd := strings.TrimSpace(stdout.String()); passwd != "" { + // username:password:uid:gid:gecos:home:shell + passwdParts := strings.SplitN(passwd, ":", 7) + if len(passwdParts) > 5 { + return passwdParts[5], nil + } + } + } + } + + // If all else fails, try the shell + stdout.Reset() + cmd := exec.Command("sh", "-c", "cd && pwd") + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + return "", err + } + + result := strings.TrimSpace(stdout.String()) + if result == "" { + return "", errors.New("blank output when reading home directory") + } + + return result, nil +} + +func dirWindows() (string, error) { + // First prefer the HOME environmental variable + if home := os.Getenv("HOME"); home != "" { + return home, nil + } + + // Prefer standard environment variable USERPROFILE + if home := os.Getenv("USERPROFILE"); home != "" { + return home, nil + } + + drive := os.Getenv("HOMEDRIVE") + path := os.Getenv("HOMEPATH") + home := drive + path + if drive == "" || path == "" { + return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank") + } + + return home, nil +} From 3eea0a82c0aa79e2970e0962dbb3a15d77324810 Mon Sep 17 00:00:00 2001 From: jessicagreben Date: Fri, 4 Jan 2019 21:11:34 -0800 Subject: [PATCH 2/5] make a little more pretty --- main.go | 10 ---------- pkg/kube/clientset.go | 20 ++++++++++---------- pkg/validator/pod.go | 2 +- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/main.go b/main.go index 1940eb109..a2371f823 100644 --- a/main.go +++ b/main.go @@ -65,15 +65,6 @@ func main() { } } -// containers: -// name: example-123 -// checks: -// - name: Resource Requests -// valid: true -// - name: Resource Limits -// valid: false -// message: "CPU resource limit is too low (expected: 1m, actual: nil)" - func startDashboardServer(c conf.Configuration) { http.HandleFunc("/validate", func(w http.ResponseWriter, r *http.Request) { validateHandler(w, r, c) }) glog.Println("Starting Fairwinds dashboard webserver on port 8080.") @@ -91,7 +82,6 @@ func validateHandler(w http.ResponseWriter, r *http.Request, c conf.Configuratio result := validator.ValidatePods(c, &pod, validator.Results{}) results = append(results, result) } - // aggregate results w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(results) diff --git a/pkg/kube/clientset.go b/pkg/kube/clientset.go index 2bf1695c1..f0beb9a4e 100644 --- a/pkg/kube/clientset.go +++ b/pkg/kube/clientset.go @@ -7,13 +7,21 @@ import ( homedir "github.com/mitchellh/go-homedir" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" ) -// createClientset loads kubeconfig and setups the connection to the k8s api. func createClientset() *kubernetes.Clientset { + var err error + var config *rest.Config kubeconfig := getKubeConfig() - config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) + + switch kubeconfig { + case "": + config, err = rest.InClusterConfig() + default: + config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) + } if err != nil { fmt.Println("Error:", err) } @@ -22,11 +30,9 @@ func createClientset() *kubernetes.Clientset { if err != nil { fmt.Println("Error:", err) } - return clientset } -// getKubeConfig returns a valid kubeconfig path. func getKubeConfig() string { var path string @@ -53,9 +59,3 @@ var clientset = createClientset() // CoreV1API exports the v1 Core API client. var CoreV1API = clientset.CoreV1() - -// AutoscalingV1API exports the v1 Autoscaling API client. -var AutoscalingV1API = clientset.AutoscalingV1() - -// AppsV1API exports the v1 Apps API client. -var AppsV1API = clientset.AppsV1() diff --git a/pkg/validator/pod.go b/pkg/validator/pod.go index 772efe4c4..9737aaae8 100644 --- a/pkg/validator/pod.go +++ b/pkg/validator/pod.go @@ -54,7 +54,7 @@ func (v *PodValidator) Handle(ctx context.Context, req types.Request) types.Resp return admission.ValidationResponse(allowed, reason) } -// ValidatePods does x. +// ValidatePods does validates that each pod conforms to the Fairwinds config. func ValidatePods(conf conf.Configuration, pod *corev1.Pod, results Results) Results { for _, container := range pod.Spec.InitContainers { results.InitContainerValidations = append( From 1a768e094a314a4e3e32f6caaf74e64c173074b1 Mon Sep 17 00:00:00 2001 From: jessicagreben Date: Fri, 4 Jan 2019 21:23:54 -0800 Subject: [PATCH 3/5] add 2nd container to k8s config --- deploy/all.yaml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/deploy/all.yaml b/deploy/all.yaml index 14226e516..6c142dd68 100644 --- a/deploy/all.yaml +++ b/deploy/all.yaml @@ -106,8 +106,9 @@ spec: spec: serviceAccountName: fairwinds containers: - - name: fairwinds - image: quay.io/reactiveops/fairwinds + - name: webhook + image: quay.io/jessgreb/fairwinds + command: ["fairwinds", "--webhook"] imagePullPolicy: Always resources: limits: @@ -123,6 +124,24 @@ spec: mountPath: /opt/app/config.yml subPath: config.yml readOnly: true + - name: dashboard + image: quay.io/jessgreb/fairwinds + command: ["fairwinds", "--dashboard"] + imagePullPolicy: Always + ports: + - containerPort: 8080 + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + volumeMounts: + - name: fairwinds + mountPath: /opt/app/config.yml + subPath: config.yml + readOnly: true volumes: - name: fairwinds configMap: From 9701ec4569403c55acd4f47e7718cd23244d0b80 Mon Sep 17 00:00:00 2001 From: jessicagreben Date: Fri, 4 Jan 2019 21:29:20 -0800 Subject: [PATCH 4/5] fix quay container name --- deploy/all.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/all.yaml b/deploy/all.yaml index 6c142dd68..cf23d3bcc 100644 --- a/deploy/all.yaml +++ b/deploy/all.yaml @@ -107,7 +107,7 @@ spec: serviceAccountName: fairwinds containers: - name: webhook - image: quay.io/jessgreb/fairwinds + image: quay.io/reactiveops/fairwinds command: ["fairwinds", "--webhook"] imagePullPolicy: Always resources: @@ -125,7 +125,7 @@ spec: subPath: config.yml readOnly: true - name: dashboard - image: quay.io/jessgreb/fairwinds + image: quay.io/reactiveops/fairwinds command: ["fairwinds", "--dashboard"] imagePullPolicy: Always ports: From 442b59d28a91b3b8760f6509d42ba103379fb04b Mon Sep 17 00:00:00 2001 From: jessicagreben Date: Sat, 26 Jan 2019 12:00:32 -0800 Subject: [PATCH 5/5] remove dup get kubeconf --- .gitignore | 1 + pkg/kube/clientset.go | 44 +++---------------------------------------- 2 files changed, 4 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 01c52021f..e62eda10e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.dll *.so *.dylib +fairwinds # Test binary, build with `go test -c` *.test diff --git a/pkg/kube/clientset.go b/pkg/kube/clientset.go index f0beb9a4e..21caee5b4 100644 --- a/pkg/kube/clientset.go +++ b/pkg/kube/clientset.go @@ -2,60 +2,22 @@ package kube import ( "fmt" - "os" - "path/filepath" - homedir "github.com/mitchellh/go-homedir" "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client/config" ) func createClientset() *kubernetes.Clientset { - var err error - var config *rest.Config - kubeconfig := getKubeConfig() + kubeConf := config.GetConfigOrDie() - switch kubeconfig { - case "": - config, err = rest.InClusterConfig() - default: - config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) - } - if err != nil { - fmt.Println("Error:", err) - } - - clientset, err := kubernetes.NewForConfig(config) + clientset, err := kubernetes.NewForConfig(kubeConf) if err != nil { fmt.Println("Error:", err) } return clientset } -func getKubeConfig() string { - var path string - - if os.Getenv("KUBECONFIG") != "" { - path = os.Getenv("KUBECONFIG") - return path - } - - if home, err := homedir.Dir(); err == nil { - path = filepath.Join(home, ".kube", "config") - } - - if _, err := os.Stat(path); err != nil { - // No kubeconfig exists, therefor return an emtpy string to - // indicate that this web server is running inside the cluster. - return "" - } - return path -} - var clientset = createClientset() -// Kubernetes version 1.11 APIs - // CoreV1API exports the v1 Core API client. var CoreV1API = clientset.CoreV1()