Compare commits

...

82 Commits

Author SHA1 Message Date
Daniel Holbach
2a0ad5384d Merge pull request #113 from dholbach/prep-1.3.0
Prepare 1.3.0 release
2020-02-25 11:22:03 +01:00
Daniel Holbach
43737e35d5 Prepare 1.3.0 release
Also point out how to create the dockerhub.yaml file,
	update other release related instructions.

	closes: #97
2020-02-25 11:20:39 +01:00
Daniel Holbach
b337c9d6be Merge pull request #111 from pgroene/patch-1
Use newer version of k8s client tools
2020-02-21 18:45:14 +01:00
Daniel Holbach
95ec750a31 Merge pull request #112 from dholbach/add-release-docs
add development docs
2020-02-21 18:39:31 +01:00
Peter Groenewegen
fdc960b84d Merge pull request #1 from weaveworks/attempt-k8s-1.15
update to client-go as well
2020-02-21 09:22:43 -08:00
Daniel Holbach
72a35388a6 add development docs 2020-02-21 18:03:57 +01:00
Daniel Holbach
5dd0de8f78 update compability matrix 2020-02-21 17:03:30 +01:00
Daniel Holbach
37a5ece356 update client-go, run 'go mod tidy' 2020-02-21 16:11:44 +01:00
Daniel Holbach
7975a78025 update to latest kubectl 1.15 2020-02-21 16:11:10 +01:00
Peter Groenewegen
f86514c1e6 Use newer version of k8s client tools
The version of k8s has security vulnerabilities, updating to a newer version

Tested this this version to on our clusters
2020-02-19 07:55:03 -08:00
Bryan Boreham
f6e4062e13 Merge pull request #86 from weaveworks/tidy-modules
Update go.mod and go.sum after 'go mod vendor'
2019-11-26 17:35:54 +00:00
Praveen Adusumilli
f2ae01120a Upgrading to latest alpine (#100)
* Upgrading to latest alpine 3.10.3
2019-11-26 16:53:43 +00:00
Bryan Boreham
db7b42f5ee Merge pull request #87 from Nighthawk22/master
Added slack channel name configuration
2019-11-26 16:50:24 +00:00
Nighthawk22
5c21206bdb Merge branch 'master' into master 2019-10-28 10:56:13 +01:00
leigh capili
4beddb5338 Reboot only within time window specified on commandline (#66)
Reboot only within time window specified on commandline
2019-10-23 22:23:51 -06:00
Maximilian Zollneritsch
7944fd2639 Updated readme and daemonset with slack channel parameter 2019-09-11 14:03:13 +02:00
Maximilian Zollneritsch
d1315c691e Added slack channel name configuration 2019-09-11 13:59:09 +02:00
Bryan Boreham
57ef32d2d1 Update go.mod and go.sum after 'go mod vendor' 2019-09-05 12:28:27 +00:00
Adam Harrison
4d2b8763d3 Merge pull request #75 from weaveworks/support-k8s-1.14
Support k8s 1.14
2019-05-22 15:46:50 +01:00
Adam Harrison
b4fc6bac27 Update daemonsetlock to use AppsV1 2019-05-17 10:15:23 +01:00
Adam Harrison
423f4afc9c Update compatibility matrix 2019-05-16 17:07:17 +01:00
Adam Harrison
8d809333b3 Update embedded kubectl to v1.14.1 2019-05-16 17:07:17 +01:00
Adam Harrison
6a65a535c0 Update client-go, api, apimachinery to 1.14.x
go get k8s.io/client-go@v11.0.0
    go get k8s.io/apimachinery@release-1.14
    go get k8s.io/api@release-1.14
2019-05-16 16:15:30 +01:00
Adam Harrison
26e1ab8678 Merge pull request #74 from weaveworks/go-modules
Build with golang 1.12 and modules
2019-05-16 16:07:34 +01:00
Adam Harrison
b16c3278b3 Document how to build inside/outside GOPATH 2019-05-16 15:55:44 +01:00
Adam Harrison
ddfb4119b7 Update build instructions for go modules 2019-05-16 15:16:00 +01:00
Adam Harrison
a5a0435e41 Remove go clean
This fails with an error in module mode.
2019-05-16 15:15:32 +01:00
Adam Harrison
f41b121b14 Upgrade to go 1.12 with modules 2019-05-16 14:35:11 +01:00
Adam Harrison
97e4963583 Update docs for 1.2.0 release 2019-05-16 13:53:21 +01:00
Adam Harrison
fc94716ffe Update install instructions to use alternative dockerhub yaml 2019-05-16 11:29:26 +01:00
Adam Harrison
c20c9e987b Merge pull request #73 from weaveworks/remove-spurious-go-get
Remove spurious `go get` from Makefile
2019-05-16 11:04:13 +01:00
Adam Harrison
10443c5178 Remove spurious go get from Makefile 2019-05-16 11:00:21 +01:00
Adam Harrison
1b3d84d360 Correct master kubectl version in README 2019-05-16 10:56:41 +01:00
Adam Harrison
50136cd865 Merge pull request #57 from weaveworks/support-k8s-1.13
Support k8s 1.13
2019-05-16 10:55:59 +01:00
Adam Harrison
69b509f246 Add master to compatibility matrix 2019-05-16 10:51:51 +01:00
Adam Harrison
556789e6c7 Update embedded kubectl to v1.13.6 2019-05-16 10:51:51 +01:00
Adam Harrison
0127675514 Update client-go and transitive dependencies 2019-05-16 10:51:46 +01:00
JJ Jordan
7249f1c573 Reduce silliness 2019-04-18 18:02:13 -07:00
JJ Jordan
357687b053 Fix seconds format in parser, address (an unimportant) corner case 2019-04-18 18:00:29 -07:00
Hidde Beydals
b1370be8f3 Merge pull request #69 from weaveworks/switch-docker-hub
Move image to Docker Hub
2019-04-18 09:51:34 +02:00
Hidde Beydals
de3593799f Move image to Docker Hub 2019-04-17 13:43:47 +02:00
JJ Jordan
3a89e3e058 Add documentation section, params to daemonset, tzdata to docker container 2019-04-09 18:02:11 -07:00
JJ Jordan
972ef4240b Comment 2019-04-04 01:06:03 -07:00
JJ Jordan
334437cdc0 Improve help strings (?) 2019-04-04 01:04:39 -07:00
JJ Jordan
7d85e85db0 weekdays to use a bitmap, add (minimal) tests 2019-04-04 01:02:27 -07:00
JJ Jordan
3f6713fa65 More forgiving inputs 2019-04-02 01:28:59 -07:00
JJ Jordan
170a3a4bac Use time window 2019-04-02 01:23:33 -07:00
Matthias Radestock
521e15cc73 Merge pull request #58 from dholbach/drop-email
weave-users mailing list is closed
2019-01-08 11:58:35 +00:00
Daniel Holbach
84be7929d1 weave-users mailing list is closed: https://groups.google.com/a/weave.works/forum/#!topic/weave-users/0QXWGOPdBfY
Signed-off-by: Daniel Holbach <daniel@weave.works>
2019-01-08 08:18:21 +05:30
Adam Harrison
06b22bc3ad Merge pull request #46 from weaveworks/labelled-pods-can-block-reboots
Allow selected pods to prevent reboots
2019-01-03 11:54:43 +00:00
Adam Harrison
f6f9e7492c Allow selected pods to prevent reboots 2018-11-21 15:03:29 +00:00
Adam Harrison
114c34950b Merge pull request #41 from weaveworks/doc-compat-matrix
Document embedded kubectl/client-go versions
2018-10-30 17:06:54 +00:00
Adam Harrison
048bba446f Document embedded kubectl/client-go versions 2018-10-30 17:04:10 +00:00
Adam Harrison
dcddbfffdc Merge pull request #40 from weaveworks/1.1.0-doc-udpates
Update docs for 1.1.0 release
2018-10-30 15:17:32 +00:00
Adam Harrison
8f8cda2e74 Update docs for 1.1.0 release 2018-10-30 15:15:51 +00:00
Adam Harrison
c8bb178fb9 Merge pull request #39 from weaveworks/nsenter-host-mount-namepace
Enter host mount namespace
2018-10-30 14:40:18 +00:00
Adam Harrison
0cd450b7bc Enter host mount namespace
Use the tools installed in the host to effect reboots, and allow
the execution of commands such as `needs-restart` to determine if
reboots are required.
2018-10-30 11:58:22 +00:00
Adam Harrison
3caedb0ab8 Merge pull request #38 from weaveworks/automate-release-process
Enable CI builds on tags
2018-10-30 11:55:10 +00:00
Adam Harrison
8ed1b575d9 Enable CI builds on tags
So that creating a GitHub release triggers an appropriately versioned
build.
2018-10-30 11:31:14 +00:00
Adam Harrison
56cd1f0a49 Merge pull request #37 from weaveworks/tolerate-master-node-role
Tolerate master node-role NoSchedule taint
2018-10-26 16:12:16 +01:00
Adam Harrison
028109d203 Tolerate master node-role NoSchedule taint 2018-10-26 16:09:24 +01:00
Adam Harrison
97c58c775e Merge pull request #36 from weaveworks/support-k8s-1.12
Support k8s 1.12
2018-10-26 15:41:56 +01:00
Adam Harrison
12cd5cda87 CI build with go 1.11 2018-10-26 15:39:58 +01:00
Adam Harrison
4322c3212a Update embedded kubectl to v1.12.1 2018-10-26 12:50:08 +01:00
Adam Harrison
02d9b54125 Update client-go and transitive dependencies 2018-10-25 18:06:22 +01:00
Marcus Cobden
549be7711f Merge pull request #29 from weaveworks/drain-notify
Notify slack before draining a node
2018-09-24 10:43:10 +01:00
Marcus Cobden
ebf0fb5119 Notify slack before draining a node
Fixes #12
2018-09-04 14:37:34 +01:00
Adam Harrison
5731b98a8a Add warning to Dockerfile re: upgrading kubectl 2018-06-05 18:00:02 +01:00
Adam Harrison
efbb0c3e0d Document version compatibility in release notes 2018-06-05 17:27:26 +01:00
Adam Harrison
908998a70b Update RBAC permissions for kubectl v1.10.3 2018-06-05 17:20:57 +01:00
Adam Harrison
bc3f28d112 Move deployment manifest to apps/v1 2018-06-05 17:06:17 +01:00
Adam Harrison
826fcd2998 Bundle latest v1.10.x kubectl 2018-06-05 17:06:17 +01:00
Adam Harrison
b3f9ddf402 Bump client-go for optimum k8s 1.10 compatibility 2018-06-05 17:06:17 +01:00
Adam Harrison
c42fff3005 Create a :latest tag on build to push to minikube 2018-06-05 17:05:43 +01:00
Adam Harrison
aefc4ea498 Merge pull request #8 from weaveworks/build-on-osx
Don't call `sudo docker` when building on macOS
2018-06-05 16:28:54 +01:00
Adam Harrison
fd752b834a Merge pull request #6 from 3dinfluence/rbac_support
Update provided manifests to support a service account and RBAC
2018-06-05 16:20:28 +01:00
Adam Harrison
b2aa608294 Update permissions for kubectl 1.9.6
The permissions required by `kubectl drain` vary from version
to version; this change brings them into line with the one currently
bundled.
2018-06-05 16:16:46 +01:00
Adam Harrison
170f2ed2fb Restrict update permissions on daemonsets
Kured only needs update permissions on its own daeemonset.
2018-06-05 16:16:28 +01:00
Adam Harrison
152534fcc8 Convert to compact representation 2018-06-05 15:16:45 +01:00
Adam Harrison
741b27cd35 Revert documentation change
The manifest on master is for development, normal users should use a
released version. I'll do a release with RBAC shortly.
2018-06-05 15:14:10 +01:00
Sam Broughton
0e75f74ca8 Don't call sudo docker when building on macOS 2017-12-05 17:12:18 +00:00
David Miller
11780f008a Update provided manifests to support a service account and RBAC
- Added kured service account
- Added kured clusterrole
- Added kured clusterrolebinding
- Updated README.md documentation to include deploying with RBAC support
2017-11-23 11:48:14 -05:00
19 changed files with 886 additions and 554 deletions

View File

@@ -1,20 +1,26 @@
version: 2
jobs:
build:
working_directory: /go/src/github.com/weaveworks/kured
docker:
- image: circleci/golang:1.8
- image: circleci/golang:1.12.5
steps:
- checkout
- setup_remote_docker
- run: go get github.com/golang/dep/cmd/dep
- run: dep ensure
- run: make
- deploy:
name: Maybe push master images
name: Build and push image
command: |
if [ -z "${CIRCLE_TAG}" -a "${CIRCLE_BRANCH}" == "master" ]; then
docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" quay.io
make publish-image
echo "$DOCKER_PASS" | docker login --username "$DOCKER_USER" --password-stdin
if [ -z "${CIRCLE_TAG}" ]; then
make publish-image
else
make VERSION="${CIRCLE_TAG}" publish-image
fi
workflows:
version: 2
build:
jobs:
- build:
filters:
tags:
only: /.*/

106
DEVELOPMENT.md Normal file
View File

@@ -0,0 +1,106 @@
# Developing `kured`
We love contributions to `kured`, no matter if you are [helping out on
Slack][slack], reporting or triaging [issues][issues] or contributing code
to `kured`.
In any case, it will make sense to familiarise yourself with the main
[README][readme] to understand the different features and options, which is
helpful for testing. The "building" section in particular makes sense if
you are planning to contribute code.
[slack]: README.md#getting-help
[issues]: https://github.com/weaveworks/kured/issues
[readme]: README.md
## Updating k8s support
Whenever we want to update e.g. [`kubectl` in the
image](cmd/kured/Dockerfile), we need to consider if we update `client-go`
as well, some RBAC changes might be necessary too.
This is what it took to support Kubernetes 1.14:
<https://github.com/weaveworks/kured/pull/75>
That the process can be more involved that that can be seen in
<https://github.com/weaveworks/kured/commits/support-k8s-1.10>
Once you updated everything, make sure you update the support matrix on
the main [README][readme] as well.
## Release testing
Before `kured` is released, we want to make sure it still works fine on the
previous, current and next minor version of Kubernetes (with respect to the
embedded `client-go` & `kubectl`). For local testing e.g. `minikube` can be
sufficient.
Deploy kured in your test scenario, make sure you pass the right `image`,
update the e.g. `period` and `reboot-days` options, so you get immediate
results, if you login to a node and run:
```console
sudo touch /var/run/reboot-required
```
### Testing with `minikube`
A test-run with `minikube` could look like this:
```console
minikube start --vm-driver kvm2 --kubernetes-version <k8s-release>
# edit kured-ds.yaml to
# - point to new image
# - change e.g. period and reboot-days option for immediate results
minikube kubectl -- apply -f kured-rbac.yaml
minikube kubectl -- apply -f kured-ds.yaml
minikube kubectl -- logs daemonset.apps/kured -n kube-system -f
# In separate terminal
minikube ssh
sudo touch /var/run/reboot-required
minikube logs -f
```
Now check for the 'Commanding reboot' message and minikube going down.
Unfortunately as of today, you are going to run into
<https://github.com/kubernetes/minikube/issues/2874>. This means that
minikube won't come back easily. You will need to start minikube again.
Then you can check for the lock release.
If all the tests ran well, kured maintainers can reach out to the Weaveworks
team to get an upcoming `kured` release tested in the Dev environment for
real life testing.
## Publishing a new kured release
Check that `README.md` has an updated compatibility matrix and that the
url in the `kubectl` incantation (under "Installation") is updated to the
new version you want to release.
Now create the `kured-<release>-dockerhub.yaml` for e.g. `1.3.0`:
```sh
VERSION=1.3.0
MANIFEST="kured-$VERSION-dockerhub.yaml"
cat kured-rbac.yaml > "$MANIFEST"
cat kured-ds.yaml >> "$MANIFEST"
sed -i "s#docker.io/weaveworks/kured#docker.io/weaveworks/kured:$VERSION#g" "$MANIFEST"
```
The last thing you need to do is update the `image:` to point to the release
tag, e.g. `docker.io/weaveworks/kured:1.3.0`.
Now you can head to the Github UI, use the version number as tag and upload the
`kured-<release>-dockerhub.yaml` file.
### Release notes
Please describe what's new and noteworthy in the release notes, list the PRs
that landed and give a shout-out to everyone who contributed.
Please also note down on which releases the upcoming `kured` release was
tested on. (Check old release notes if you're unsure.)

431
Gopkg.lock generated
View File

@@ -1,431 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/PuerkitoBio/purell"
packages = ["."]
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/PuerkitoBio/urlesc"
packages = ["."]
revision = "bbf7a2afc14f93e1e0a5c06df524fbd75e5031e5"
[[projects]]
name = "github.com/asaskevich/govalidator"
packages = ["."]
revision = "73945b6115bfbbcc57d89b7316e28109364124e1"
version = "v7"
[[projects]]
branch = "master"
name = "github.com/beorn7/perks"
packages = ["quantile"]
revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
[[projects]]
branch = "master"
name = "github.com/cloudfoundry-incubator/candiedyaml"
packages = ["."]
revision = "99c3df83b51532e3615f851d8c2dbb638f5313bf"
[[projects]]
branch = "master"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d"
[[projects]]
branch = "master"
name = "github.com/docker/distribution"
packages = [
"digest",
"reference"
]
revision = "7365003236ca58bd7fa17ef1459328d13301d7d5"
[[projects]]
branch = "master"
name = "github.com/emicklei/go-restful"
packages = [
".",
"log"
]
revision = "b14c3a95fc27c52959d2eddc85066da3c14bf269"
[[projects]]
name = "github.com/emicklei/go-restful-swagger12"
packages = ["."]
revision = "dcef7f55730566d41eae5db10e7d6981829720f6"
version = "1.0.1"
[[projects]]
branch = "master"
name = "github.com/ghodss/yaml"
packages = ["."]
revision = "aa0c862057666179de291b67d9f093d12b5a8473"
[[projects]]
branch = "master"
name = "github.com/go-openapi/analysis"
packages = ["."]
revision = "8ed83f2ea9f00f945516462951a288eaa68bf0d6"
[[projects]]
branch = "master"
name = "github.com/go-openapi/errors"
packages = ["."]
revision = "03cfca65330da08a5a440053faf994a3c682b5bf"
[[projects]]
branch = "master"
name = "github.com/go-openapi/jsonpointer"
packages = ["."]
revision = "779f45308c19820f1a69e9a4cd965f496e0da10f"
[[projects]]
branch = "master"
name = "github.com/go-openapi/jsonreference"
packages = ["."]
revision = "36d33bfe519efae5632669801b180bf1a245da3b"
[[projects]]
branch = "master"
name = "github.com/go-openapi/loads"
packages = ["."]
revision = "a80dea3052f00e5f032e860dd7355cd0cc67e24d"
[[projects]]
branch = "master"
name = "github.com/go-openapi/spec"
packages = ["."]
revision = "e51c28f07047ad90caff03f6450908720d337e0c"
[[projects]]
branch = "master"
name = "github.com/go-openapi/strfmt"
packages = ["."]
revision = "610b6cacdcde6852f4de68998bd20ce1dac85b22"
[[projects]]
branch = "master"
name = "github.com/go-openapi/swag"
packages = ["."]
revision = "24ebf76d720bab64f62824d76bced3184a65490d"
[[projects]]
branch = "master"
name = "github.com/gogo/protobuf"
packages = [
"proto",
"sortkeys"
]
revision = "e33835a643a970c11ac74f6333f5f6866387a101"
[[projects]]
branch = "master"
name = "github.com/golang/glog"
packages = ["."]
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]]
branch = "master"
name = "github.com/golang/protobuf"
packages = ["proto"]
revision = "2bba0603135d7d7f5cb73b2125beeda19c09f4ef"
[[projects]]
branch = "master"
name = "github.com/google/gofuzz"
packages = ["."]
revision = "fd52762d25a41827db7ef64c43756fd4b9f7e382"
[[projects]]
branch = "master"
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
[[projects]]
branch = "master"
name = "github.com/juju/ratelimit"
packages = ["."]
revision = "5b9ff866471762aa2ab2dced63c9fb6f53921342"
[[projects]]
branch = "master"
name = "github.com/mailru/easyjson"
packages = [
"buffer",
"jlexer",
"jwriter"
]
revision = "2af9a745a611440bab0528e5ac19b2805a1c50eb"
[[projects]]
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
revision = "3247c84500bff8d9fb6d579d800f20b3e091582c"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
revision = "d0303fe809921458f417bcf828397a65db30a7e4"
[[projects]]
branch = "master"
name = "github.com/prometheus/client_golang"
packages = [
"api/prometheus",
"prometheus",
"prometheus/promhttp"
]
revision = "5636dc67ae776adf5590da7349e70fbb9559972d"
[[projects]]
branch = "master"
name = "github.com/prometheus/client_model"
packages = ["go"]
revision = "6f3806018612930941127f2a7c6c453ba2c527d2"
[[projects]]
branch = "master"
name = "github.com/prometheus/common"
packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model"
]
revision = "ebdfc6da46522d58825777cf1f90490a5b1ef1d8"
[[projects]]
branch = "master"
name = "github.com/prometheus/procfs"
packages = [
".",
"xfs"
]
revision = "e645f4e5aaa8506fc71d6edbc5c4ff02c04c46f2"
[[projects]]
name = "github.com/sirupsen/logrus"
packages = ["."]
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
version = "v1.0.5"
[[projects]]
branch = "master"
name = "github.com/spf13/cobra"
packages = ["."]
revision = "b24564e919247d7c870fe0ed3738c98d8741aca4"
[[projects]]
branch = "master"
name = "github.com/spf13/pflag"
packages = ["."]
revision = "367864438f1b1a3c7db4da06a2f55b144e6784e0"
[[projects]]
branch = "master"
name = "github.com/ugorji/go"
packages = ["codec"]
revision = "3487a5545b3d480987dfb0492035299077fab33a"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "beb2a9779c3b677077c41673505f150149fce895"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp",
"http2",
"http2/hpack",
"idna"
]
revision = "2a35e686583654a1b89ca79c4ac78cb3d6529ca3"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
]
revision = "3b87a42e500a6dc65dae1a55d0b641295971163e"
[[projects]]
branch = "master"
name = "golang.org/x/text"
packages = [
"internal/gen",
"internal/triegen",
"internal/ucd",
"transform",
"unicode/cldr",
"unicode/norm",
"width"
]
revision = "a9a820217f98f7c8a207ec1e45a874e1fe12c478"
[[projects]]
branch = "master"
name = "gopkg.in/inf.v0"
packages = ["."]
revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
[[projects]]
branch = "v2"
name = "gopkg.in/mgo.v2"
packages = [
"bson",
"internal/json"
]
revision = "3f83fa5005286a7fe593b055f0d7771a7dce4655"
[[projects]]
branch = "v2"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b"
[[projects]]
branch = "release-1.7"
name = "k8s.io/apimachinery"
packages = [
"pkg/api/equality",
"pkg/api/errors",
"pkg/api/meta",
"pkg/api/resource",
"pkg/apimachinery",
"pkg/apimachinery/announced",
"pkg/apimachinery/registered",
"pkg/apis/meta/v1",
"pkg/apis/meta/v1/unstructured",
"pkg/apis/meta/v1alpha1",
"pkg/conversion",
"pkg/conversion/queryparams",
"pkg/conversion/unstructured",
"pkg/fields",
"pkg/labels",
"pkg/openapi",
"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/clock",
"pkg/util/diff",
"pkg/util/errors",
"pkg/util/framer",
"pkg/util/intstr",
"pkg/util/json",
"pkg/util/net",
"pkg/util/rand",
"pkg/util/runtime",
"pkg/util/sets",
"pkg/util/validation",
"pkg/util/validation/field",
"pkg/util/wait",
"pkg/util/yaml",
"pkg/version",
"pkg/watch",
"third_party/forked/golang/reflect"
]
revision = "8ab5f3d8a330c2e9baaf84e39042db8d49034ae2"
[[projects]]
name = "k8s.io/client-go"
packages = [
"discovery",
"kubernetes",
"kubernetes/scheme",
"kubernetes/typed/admissionregistration/v1alpha1",
"kubernetes/typed/apps/v1beta1",
"kubernetes/typed/authentication/v1",
"kubernetes/typed/authentication/v1beta1",
"kubernetes/typed/authorization/v1",
"kubernetes/typed/authorization/v1beta1",
"kubernetes/typed/autoscaling/v1",
"kubernetes/typed/autoscaling/v2alpha1",
"kubernetes/typed/batch/v1",
"kubernetes/typed/batch/v2alpha1",
"kubernetes/typed/certificates/v1beta1",
"kubernetes/typed/core/v1",
"kubernetes/typed/extensions/v1beta1",
"kubernetes/typed/networking/v1",
"kubernetes/typed/policy/v1beta1",
"kubernetes/typed/rbac/v1alpha1",
"kubernetes/typed/rbac/v1beta1",
"kubernetes/typed/settings/v1alpha1",
"kubernetes/typed/storage/v1",
"kubernetes/typed/storage/v1beta1",
"pkg/api",
"pkg/api/v1",
"pkg/api/v1/ref",
"pkg/apis/admissionregistration",
"pkg/apis/admissionregistration/v1alpha1",
"pkg/apis/apps",
"pkg/apis/apps/v1beta1",
"pkg/apis/authentication",
"pkg/apis/authentication/v1",
"pkg/apis/authentication/v1beta1",
"pkg/apis/authorization",
"pkg/apis/authorization/v1",
"pkg/apis/authorization/v1beta1",
"pkg/apis/autoscaling",
"pkg/apis/autoscaling/v1",
"pkg/apis/autoscaling/v2alpha1",
"pkg/apis/batch",
"pkg/apis/batch/v1",
"pkg/apis/batch/v2alpha1",
"pkg/apis/certificates",
"pkg/apis/certificates/v1beta1",
"pkg/apis/extensions",
"pkg/apis/extensions/v1beta1",
"pkg/apis/networking",
"pkg/apis/networking/v1",
"pkg/apis/policy",
"pkg/apis/policy/v1beta1",
"pkg/apis/rbac",
"pkg/apis/rbac/v1alpha1",
"pkg/apis/rbac/v1beta1",
"pkg/apis/settings",
"pkg/apis/settings/v1alpha1",
"pkg/apis/storage",
"pkg/apis/storage/v1",
"pkg/apis/storage/v1beta1",
"pkg/util",
"pkg/util/parsers",
"pkg/version",
"rest",
"rest/watch",
"tools/clientcmd/api",
"tools/metrics",
"transport",
"util/cert",
"util/flowcontrol",
"util/integer"
]
revision = "d92e8497f71b7b4e0494e5bd204b48d34bd6f254"
version = "v4.0.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "029e6d2251ccbf5acdfc3bc0c36f340dc3a98511b0d7338c3e9bb167e412a155"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -1,24 +0,0 @@
[[constraint]]
name = "github.com/sirupsen/logrus"
version = "v1.0.5"
[[constraint]]
branch = "master"
name = "github.com/prometheus/client_golang"
[[constraint]]
branch = "master"
name = "github.com/prometheus/common"
[[constraint]]
branch = "master"
name = "github.com/spf13/cobra"
[[constraint]]
name = "k8s.io/client-go"
version = "v4.0.0"
[[constraint]]
name = "k8s.io/apimachinery"
branch = "release-1.7"

View File

@@ -3,15 +3,15 @@
DH_ORG=weaveworks
VERSION=$(shell git symbolic-ref --short HEAD)-$(shell git rev-parse --short HEAD)
SUDO=$(shell docker info >/dev/null 2>&1 || echo "sudo -E")
all: image
clean:
go clean
rm -f cmd/kured/kured
rm -rf ./build
godeps=$(shell go get $1 && go list -f '{{join .Deps "\n"}}' $1 | grep -v /vendor/ | xargs go list -f '{{if not .Standard}}{{ $$dep := . }}{{range .GoFiles}}{{$$dep.Dir}}/{{.}} {{end}}{{end}}')
godeps=$(shell go list -f '{{join .Deps "\n"}}' $1 | grep -v /vendor/ | xargs go list -f '{{if not .Standard}}{{ $$dep := . }}{{range .GoFiles}}{{$$dep.Dir}}/{{.}} {{end}}{{end}}')
DEPS=$(call godeps,./cmd/kured)
@@ -22,13 +22,14 @@ cmd/kured/kured: cmd/kured/*.go
build/.image.done: cmd/kured/Dockerfile cmd/kured/kured
mkdir -p build
cp $^ build
sudo -E docker build -t quay.io/$(DH_ORG)/kured:$(VERSION) -f build/Dockerfile ./build
$(SUDO) docker build -t docker.io/$(DH_ORG)/kured -f build/Dockerfile ./build
$(SUDO) docker tag docker.io/$(DH_ORG)/kured docker.io/$(DH_ORG)/kured:$(VERSION)
touch $@
image: build/.image.done
publish-image: image
sudo -E docker push quay.io/$(DH_ORG)/kured:$(VERSION)
$(SUDO) docker push docker.io/$(DH_ORG)/kured:$(VERSION)
minikube-publish: image
sudo -E docker save quay.io/$(DH_ORG)/kured:$(VERSION) | (eval $$(minikube docker-env) && docker load)
$(SUDO) docker save docker.io/$(DH_ORG)/kured | (eval $$(minikube docker-env) && docker load)

150
README.md
View File

@@ -6,7 +6,9 @@
* [Installation](#installation)
* [Configuration](#configuration)
* [Reboot Sentinel File & Period](#reboot-sentinel-file-&-period)
* [Setting a schedule](#setting-a-schedule)
* [Blocking Reboots via Alerts](#blocking-reboots-via-alerts)
* [Blocking Reboots via Pods](#blocking-reboots-via-pods)
* [Prometheus Metrics](#prometheus-metrics)
* [Slack Notifications](#slack-notifications)
* [Overriding Lock Configuration](#overriding-lock-configuration)
@@ -15,6 +17,7 @@
* [Disabling Reboots](#disabling-reboots)
* [Manual Unlock](#manual-unlock)
* [Building](#building)
* [Frequently Asked/Anticipated Questions](#frequently-askedanticipated-questions)
* [Getting Help](#getting-help)
## Introduction
@@ -26,22 +29,30 @@ indicated by the package management system of the underlying OS.
* Watches for the presence of a reboot sentinel e.g. `/var/run/reboot-required`
* Utilises a lock in the API server to ensure only one node reboots at
a time
* Optionally defers reboots in the presence of active Prometheus alerts
* Optionally defers reboots in the presence of active Prometheus alerts or selected pods
* Cordons & drains worker nodes before reboot, uncordoning them after
## Kubernetes & OS Compatibility
The daemon image contains a 1.7.x `k8s.io/client-go` and `kubectl`
binary for the purposes of maintaining the lock and draining worker
nodes. Whilst it has only been tested on a 1.7.x cluster, Kubernetes
typically has good forwards/backwards compatibility so there is a
reasonable chance it will work on adjacent versions; please file an
issue if this is not the case.
The daemon image contains versions of `k8s.io/client-go` and the
`kubectl` binary for the purposes of maintaining the lock and draining
worker nodes. Kubernetes aims to provide forwards & backwards
compatibility of one minor version between client and server:
Additionally, the image contains a `systemctl` binary from Ubuntu
16.04 in order to command reboots. Again, although this has not been
tested against other systemd distributions there is a good chance that
it will work.
| kured | kubectl | k8s.io/client-go | k8s.io/apimachinery | expected kubernetes compatibility |
|--------|---------|------------------|---------------------|-----------------------------------|
| master | 1.15.10 | v12.0.0 | release-1.15 | 1.15.x, 1.16.x, 1.17.x |
| 1.3.0 | 1.15.10 | v12.0.0 | release-1.15 | 1.15.x, 1.16.x, 1.17.x |
| 1.2.0 | 1.13.6 | v10.0.0 | release-1.13 | 1.12.x, 1.13.x, 1.14.x |
| 1.1.0 | 1.12.1 | v9.0.0 | release-1.12 | 1.11.x, 1.12.x, 1.13.x |
| 1.0.0 | 1.7.6 | v4.0.0 | release-1.7 | 1.6.x, 1.7.x, 1.8.x |
See the [release notes](https://github.com/weaveworks/kured/releases)
for specific version compatibility information, including which
combination have been formally tested.
Versions >=1.1.0 enter the host mount namespace to invoke
`systemctl reboot`, so should work on any systemd distribution.
## Installation
@@ -49,7 +60,7 @@ To obtain a default installation without Prometheus alerting interlock
or Slack notifications:
```
kubectl apply -f https://github.com/weaveworks/kured/releases/download/1.0.0/kured-ds.yaml
kubectl apply -f https://github.com/weaveworks/kured/releases/download/1.3.0/kured-1.3.0-dockerhub.yaml
```
If you want to customise the installation, download the manifest and
@@ -61,15 +72,22 @@ The following arguments can be passed to kured via the daemonset pod template:
```
Flags:
--alert-filter-regexp value alert names to ignore when checking for active alerts
--ds-name string namespace containing daemonset on which to place lock (default "kube-system")
--ds-namespace string name of daemonset on which to place lock (default "kured")
--lock-annotation string annotation in which to record locking node (default "weave.works/kured-node-lock")
--period duration reboot check period (default 1h0m0s)
--prometheus-url string Prometheus instance to probe for active alerts
--reboot-sentinel string path to file whose existence signals need to reboot (default "/var/run/reboot-required")
--slack-hook-url string slack hook URL for reboot notfications
--slack-username string slack username for reboot notfications (default "kured")
--alert-filter-regexp regexp.Regexp alert names to ignore when checking for active alerts
--blocking-pod-selector stringArray label selector identifying pods whose presence should prevent reboots
--ds-name string name of daemonset on which to place lock (default "kured")
--ds-namespace string namespace containing daemonset on which to place lock (default "kube-system")
--end-time string only reboot before this time of day (default "23:59")
-h, --help help for kured
--lock-annotation string annotation in which to record locking node (default "weave.works/kured-node-lock")
--period duration reboot check period (default 1h0m0s)
--prometheus-url string Prometheus instance to probe for active alerts
--reboot-days strings only reboot on these days (default [su,mo,tu,we,th,fr,sa])
--reboot-sentinel string path to file whose existence signals need to reboot (default "/var/run/reboot-required")
--slack-channel string slack channel for reboot notfications
--slack-hook-url string slack hook URL for reboot notfications
--slack-username string slack username for reboot notfications (default "kured")
--start-time string only reboot after this time of day (default "0:00")
--time-zone string use this timezone to calculate allowed reboot time (default "UTC")
```
### Reboot Sentinel File & Period
@@ -80,6 +98,29 @@ values with `--reboot-sentinel` and `--period`. Each replica of the
daemon uses a random offset derived from the period on startup so that
nodes don't all contend for the lock simultaneously.
### Setting a schedule
By default, kured will reboot any time it detects the sentinel, but this
may cause reboots during odd hours. While service disruption does not
normally occur, anything is possible and operators may want to restrict
reboots to predictable schedules. Use `--reboot-days`, `--start-time`,
`--end-time`, and `--time-zone` to set a schedule. For example, business
hours on the west coast USA can be specified with:
```
--reboot-days mon,tue,wed,thu,fri
--start-time 9am
--end-time 5pm
--time-zone America/Los_Angeles
```
Times can be formatted in numerous ways, including `5pm`, `5:00pm` `17:00`,
and `17`. `--time-zone` represents a Go `time.Location`, and can be `UTC`,
`Local`, or any entry in the standard Linux tz database.
Note that when using smaller time windows, you should consider shortening
the sentinel check period (`--period`).
### Blocking Reboots via Alerts
You may find it desirable to block automatic node reboots when there
@@ -97,8 +138,33 @@ will block reboots, however you can ignore specific alerts:
--alert-filter-regexp=^(RebootRequired|AnotherBenignAlert|...$
```
An important application of this filter will become apparent in the
next section.
See the section on Prometheus metrics for an important application of this
filter.
### Blocking Reboots via Pods
You can also block reboots of an _individual node_ when specific pods
are scheduled on it:
```
--blocking-pod-selector=runtime=long,cost=expensive
```
Since label selector strings use commas to express logical 'and', you can
specify this parameter multiple times for 'or':
```
--blocking-pod-selector=runtime=long,cost=expensive
--blocking-pod-selector=name=temperamental
```
In this case, the presence of either an (appropriately labelled) expensive long
running job or a known temperamental pod on a node will stop it rebooting.
> Try not to abuse this mechanism - it's better to strive for
> restartability where possible. If you do use it, make sure you set
> up a RebootRequired alert as described in the next section so that
> you can intervene manually if reboots are blocked for too long.
### Prometheus Metrics
@@ -194,17 +260,45 @@ kubectl -n kube-system annotate ds kured weave.works/kured-node-lock-
## Building
See the [CircleCI config](.circleci/config.yml) for the preferred
version of Golang. Kured now uses [Go
Modules](https://github.com/golang/go/wiki/Modules), so build
instructions vary depending on where you have checked out the
repository:
**Building outside $GOPATH:**
```
dep ensure && make
make
```
**Building inside $GOPATH:**
```
GO111MODULE=on make
```
If you are interested in contributing code to kured, please take a look at
our [development][development] docs.
[development]: DEVELOPMENT.md
## Frequently Asked/Anticipated Questions
### Why is there no `latest` tag on Docker Hub?
Use of `latest` for production deployments is bad practice - see
[here](https://kubernetes.io/docs/concepts/configuration/overview) for
details. The manifest on `master` refers to `latest` for local
development testing with minikube only; for production use choose a
versioned manifest from the [release page](https://github.com/weaveworks/kured/releases/).
## Getting Help
If you have any questions about, feedback for or problems with `kured`:
- Invite yourself to the <a href="https://weaveworks.github.io/community-slack/" target="_blank"> #weave-community </a> slack channel.
- Ask a question on the <a href="https://weave-community.slack.com/messages/general/"> #weave-community</a> slack channel.
- Send an email to <a href="mailto:weave-users@weave.works">weave-users@weave.works</a>
- <a href="https://github.com/weaveworks/kured/issues/new">File an issue.</a>
- Invite yourself to the <a href="https://slack.weave.works/" target="_blank">Weave Users Slack</a>.
- Ask a question on the [#general](https://weave-community.slack.com/messages/general/) slack channel.
- [File an issue](https://github.com/weaveworks/kured/issues/new).
Your feedback is always welcome!

View File

@@ -1,6 +1,7 @@
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/cache/apt
ADD https://storage.googleapis.com/kubernetes-release/release/v1.9.6/bin/linux/amd64/kubectl /usr/bin/kubectl
FROM alpine:3.10.3
RUN apk update && apk add ca-certificates tzdata && rm -rf /var/cache/apk/*
# NB: you may need to update RBAC permissions when upgrading kubectl - see kured-rbac.yaml for details
ADD https://storage.googleapis.com/kubernetes-release/release/v1.15.10/bin/linux/amd64/kubectl /usr/bin/kubectl
RUN chmod 0755 /usr/bin/kubectl
COPY ./kured /usr/bin/kured
ENTRYPOINT ["/usr/bin/kured"]

View File

@@ -1,6 +1,7 @@
package main
import (
"fmt"
"math/rand"
"net/http"
"os"
@@ -20,6 +21,7 @@ import (
"github.com/weaveworks/kured/pkg/daemonsetlock"
"github.com/weaveworks/kured/pkg/delaytick"
"github.com/weaveworks/kured/pkg/notifications/slack"
"github.com/weaveworks/kured/pkg/timewindow"
)
var (
@@ -35,6 +37,13 @@ var (
rebootSentinel string
slackHookURL string
slackUsername string
slackChannel string
podSelectors []string
rebootDays []string
rebootStart string
rebootEnd string
timezone string
// Metrics
rebootRequiredGauge = prometheus.NewGaugeVec(prometheus.GaugeOpts{
@@ -73,6 +82,20 @@ func main() {
"slack hook URL for reboot notfications")
rootCmd.PersistentFlags().StringVar(&slackUsername, "slack-username", "kured",
"slack username for reboot notfications")
rootCmd.PersistentFlags().StringVar(&slackChannel, "slack-channel", "",
"slack channel for reboot notfications")
rootCmd.PersistentFlags().StringArrayVar(&podSelectors, "blocking-pod-selector", nil,
"label selector identifying pods whose presence should prevent reboots")
rootCmd.PersistentFlags().StringSliceVar(&rebootDays, "reboot-days", timewindow.EveryDay,
"schedule reboot on these days")
rootCmd.PersistentFlags().StringVar(&rebootStart, "start-time", "0:00",
"schedule reboot only after this time of day")
rootCmd.PersistentFlags().StringVar(&rebootEnd, "end-time", "23:59:59",
"schedule reboot only before this time of day")
rootCmd.PersistentFlags().StringVar(&timezone, "time-zone", "UTC",
"use this timezone for schedule inputs")
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
@@ -97,16 +120,23 @@ func newCommand(name string, arg ...string) *exec.Cmd {
}
func sentinelExists() bool {
_, err := os.Stat(rebootSentinel)
switch {
case err == nil:
return true
case os.IsNotExist(err):
return false
default:
log.Fatalf("Unable to determine existence of sentinel: %v", err)
return false // unreachable; prevents compilation error
// Relies on hostPID:true and privileged:true to enter host mount space
sentinelCmd := newCommand("/usr/bin/nsenter", "-m/proc/1/ns/mnt", "--", "/usr/bin/test", "-f", rebootSentinel)
if err := sentinelCmd.Run(); err != nil {
switch err := err.(type) {
case *exec.ExitError:
// We assume a non-zero exit code means 'reboot not required', but of course
// the user could have misconfigured the sentinel command or something else
// went wrong during its execution. In that case, not entering a reboot loop
// is the right thing to do, and we are logging stdout/stderr of the command
// so it should be obvious what is wrong.
return false
default:
// Something was grossly misconfigured, such as the command path being wrong.
log.Fatalf("Error invoking sentinel command: %v", err)
}
}
return true
}
func rebootRequired() bool {
@@ -119,7 +149,7 @@ func rebootRequired() bool {
}
}
func rebootBlocked() bool {
func rebootBlocked(client *kubernetes.Clientset, nodeID string) bool {
if prometheusURL != "" {
alertNames, err := alerts.PrometheusActiveAlerts(prometheusURL, alertFilter)
if err != nil {
@@ -135,6 +165,31 @@ func rebootBlocked() bool {
return true
}
}
fieldSelector := fmt.Sprintf("spec.nodeName=%s", nodeID)
for _, labelSelector := range podSelectors {
podList, err := client.CoreV1().Pods("").List(metav1.ListOptions{
LabelSelector: labelSelector,
FieldSelector: fieldSelector,
Limit: 10})
if err != nil {
log.Warnf("Reboot blocked: pod query error: %v", err)
return true
}
if len(podList.Items) > 0 {
podNames := make([]string, 0, len(podList.Items))
for _, pod := range podList.Items {
podNames = append(podNames, pod.Name)
}
if len(podList.Continue) > 0 {
podNames = append(podNames, "...")
}
log.Warnf("Reboot blocked: matching pods: %v", podNames)
return true
}
}
return false
}
@@ -173,6 +228,13 @@ func release(lock *daemonsetlock.DaemonSetLock) {
func drain(nodeID string) {
log.Infof("Draining node %s", nodeID)
if slackHookURL != "" {
if err := slack.NotifyDrain(slackHookURL, slackUsername, slackChannel, nodeID); err != nil {
log.Warnf("Error notifying slack: %v", err)
}
}
drainCmd := newCommand("/usr/bin/kubectl", "drain",
"--ignore-daemonsets", "--delete-local-data", "--force", nodeID)
@@ -193,13 +255,13 @@ func commandReboot(nodeID string) {
log.Infof("Commanding reboot")
if slackHookURL != "" {
if err := slack.NotifyReboot(slackHookURL, slackUsername, nodeID); err != nil {
if err := slack.NotifyReboot(slackHookURL, slackUsername, slackChannel, nodeID); err != nil {
log.Warnf("Error notifying slack: %v", err)
}
}
// Relies on /var/run/dbus/system_bus_socket bind mount to talk to systemd
rebootCmd := newCommand("/bin/systemctl", "reboot")
// Relies on hostPID:true and privileged:true to enter host mount space
rebootCmd := newCommand("/usr/bin/nsenter", "-m/proc/1/ns/mnt", "/bin/systemctl", "reboot")
if err := rebootCmd.Run(); err != nil {
log.Fatalf("Error invoking reboot command: %v", err)
}
@@ -221,7 +283,7 @@ type nodeMeta struct {
Unschedulable bool `json:"unschedulable"`
}
func rebootAsRequired(nodeID string) {
func rebootAsRequired(nodeID string, window *timewindow.TimeWindow) {
config, err := rest.InClusterConfig()
if err != nil {
log.Fatal(err)
@@ -245,7 +307,7 @@ func rebootAsRequired(nodeID string) {
source := rand.NewSource(time.Now().UnixNano())
tick := delaytick.New(source, period)
for _ = range tick {
if rebootRequired() && !rebootBlocked() {
if window.Contains(time.Now()) && rebootRequired() && !rebootBlocked(client, nodeID) {
node, err := client.CoreV1().Nodes().Get(nodeID, metav1.GetOptions{})
if err != nil {
log.Fatal(err)
@@ -274,11 +336,18 @@ func root(cmd *cobra.Command, args []string) {
log.Fatal("KURED_NODE_ID environment variable required")
}
window, err := timewindow.New(rebootDays, rebootStart, rebootEnd, timezone)
if err != nil {
log.Fatalf("Failed to build time window: %v", err)
}
log.Infof("Node ID: %s", nodeID)
log.Infof("Lock Annotation: %s/%s:%s", dsNamespace, dsName, lockAnnotation)
log.Infof("Reboot Sentinel: %s every %v", rebootSentinel, period)
log.Infof("Blocking Pod Selectors: %v", podSelectors)
log.Infof("Reboot on: %v", window)
go rebootAsRequired(nodeID)
go rebootAsRequired(nodeID, window)
go maintainRebootRequiredMetric(nodeID)
http.Handle("/metrics", promhttp.Handler())

23
go.mod Normal file
View File

@@ -0,0 +1,23 @@
module github.com/weaveworks/kured
go 1.12
require (
github.com/gogo/protobuf v1.2.0 // indirect
github.com/googleapis/gnostic v0.2.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/json-iterator/go v1.1.5 // indirect
github.com/prometheus/client_golang v0.0.0-20181230203121-fb3d5cb2ad57
github.com/prometheus/common v0.0.0-20181218105931-67670fe90761
github.com/prometheus/procfs v0.0.0-20190102135031-14fa7590c24d // indirect
github.com/sirupsen/logrus v1.2.0
github.com/spf13/cobra v0.0.0-20181127133106-d2d81d9a96e2
github.com/spf13/pflag v1.0.3 // indirect
golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3 // indirect
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719
k8s.io/client-go v12.0.0+incompatible
k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5 // indirect
)

132
go.sum Normal file
View File

@@ -0,0 +1,132 @@
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.0.0-20181230203121-fb3d5cb2ad57 h1:+cstagqzfjiYrs1QrmypZRndHJafhB9W3ab/zPiwl1Q=
github.com/prometheus/client_golang v0.0.0-20181230203121-fb3d5cb2ad57/go.mod h1:PS8H/EtMiYNSR3o4jWYMuyp9FkDf2ptwxn1kTerl5EM=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20181218105931-67670fe90761 h1:z6tvbDJ5OLJ48FFmnksv04a78maSTRBUIhkdHYV5Y98=
github.com/prometheus/common v0.0.0-20181218105931-67670fe90761/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190102135031-14fa7590c24d h1:iSxvUGRUGQTUgEo5+8TqMVQoH5AdaphEIjh8AnM7TPo=
github.com/prometheus/procfs v0.0.0-20190102135031-14fa7590c24d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cobra v0.0.0-20181127133106-d2d81d9a96e2 h1:gPjqutnNhLnq5t4hT2UfL06h/mvp4je4OY7Dk71vhuk=
github.com/spf13/cobra v0.0.0-20181127133106-d2d81d9a96e2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3 h1:35ZwriXqdZtBGoFgUpW71Z7xz5o23fRpWHFAO2PlnIA=
golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181217023233-e147a9138326/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 h1:bfLnR+k0tq5Lqt6dflRLcZiz6UaXCMt3vhYJ1l4FQ80=
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
k8s.io/api v0.0.0-20190620084959-7cf5895f2711 h1:BblVYz/wE5WtBsD/Gvu54KyBUTJMflolzc5I2DTvh50=
k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A=
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719 h1:uV4S5IB5g4Nvi+TBVNf3e9L4wrirlwYJ6w88jUQxTUw=
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
k8s.io/client-go v12.0.0+incompatible h1:YlJxncpeVUC98/WMZKC3JZGk/OXQWCZjAB4Xr3B17RY=
k8s.io/client-go v12.0.0+incompatible/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k=
k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68=
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5 h1:VBM/0P5TWxwk+Nw6Z+lAw3DKgO76g90ETOiA6rfLV1Y=
k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -1,32 +1,40 @@
apiVersion: extensions/v1beta1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kured
namespace: kube-system
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kured # Must match `--ds-name`
namespace: kube-system # Must match `--ds-namespace`
spec:
selector:
matchLabels:
name: kured
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
name: kured
spec:
serviceAccountName: kured
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
hostPID: true # Facilitate entering the host mount namespace via init
restartPolicy: Always
containers:
- name: kured
image: quay.io/weaveworks/kured
image: docker.io/weaveworks/kured
# If you find yourself here wondering why there is no
# :latest tag on Docker Hub,see the FAQ in the README
imagePullPolicy: IfNotPresent
command:
- /usr/bin/kured
# args:
# - --alert-filter-regexp=^RebootRequired$
# - --ds-name=kured
# - --ds-namespace=kube-system
# - --lock-annotation=weave.works/kured-node-lock
# - --period=1h
# - --prometheus-url=http://prometheus.monitoring.svc.cluster.local
# - --reboot-sentinel=/var/run/reboot-required
# - --slack-hook-url=https://hooks.slack.com/...
# - --slack-username=prod
#
# NO USER SERVICEABLE PARTS BEYOND THIS POINT
securityContext:
privileged: true # Give permission to nsenter /proc/1/ns/mnt
env:
# Pass in the name of the node on which this pod is scheduled
# for use with drain/uncordon operations and lock acquisition
@@ -34,14 +42,22 @@ spec:
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
# Needed for two purposes:
# * Testing for the existence of /var/run/reboot-required
# * Accessing /var/run/dbus/system_bus_socket to effect reboot
- name: hostrun
mountPath: /var/run
restartPolicy: Always
volumes:
- name: hostrun
hostPath:
path: /var/run
command:
- /usr/bin/kured
# - --alert-filter-regexp=^RebootRequired$
# - --blocking-pod-selector=runtime=long,cost=expensive
# - --blocking-pod-selector=name=temperamental
# - --blocking-pod-selector=...
# - --ds-name=kured
# - --ds-namespace=kube-system
# - --end-time=23:59:59
# - --lock-annotation=weave.works/kured-node-lock
# - --period=1h
# - --prometheus-url=http://prometheus.monitoring.svc.cluster.local
# - --reboot-days=sun,mon,tue,wed,thu,fri,sat
# - --reboot-sentinel=/var/run/reboot-required
# - --slack-hook-url=https://hooks.slack.com/...
# - --slack-username=prod
# - --slack-channel=alerting
# - --start-time=0:00
# - --time-zone=UTC

63
kured-rbac.yaml Normal file
View File

@@ -0,0 +1,63 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kured
rules:
# Allow kured to read spec.unschedulable
# Allow kubectl to drain/uncordon
#
# NB: These permissions are tightly coupled to the bundled version of kubectl; the ones below
# match https://github.com/kubernetes/kubernetes/blob/v1.14.1/pkg/kubectl/cmd/drain/drain.go
#
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "patch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["list","delete","get"]
- apiGroups: ["apps"]
resources: ["daemonsets"]
verbs: ["get"]
- apiGroups: [""]
resources: ["pods/eviction"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kured
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kured
subjects:
- kind: ServiceAccount
name: kured
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: kube-system
name: kured
rules:
# Allow kured to lock/unlock itself
- apiGroups: ["apps"]
resources: ["daemonsets"]
resourceNames: ["kured"]
verbs: ["update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: kube-system
name: kured
subjects:
- kind: ServiceAccount
namespace: kube-system
name: kured
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kured

View File

@@ -7,19 +7,20 @@ import (
"sort"
"time"
"github.com/prometheus/client_golang/api/prometheus"
"github.com/prometheus/client_golang/api"
"github.com/prometheus/client_golang/api/prometheus/v1"
"github.com/prometheus/common/model"
)
// Returns a list of names of active (e.g. pending or firing) alerts, filtered
// by the supplied regexp.
func PrometheusActiveAlerts(prometheusURL string, filter *regexp.Regexp) ([]string, error) {
client, err := prometheus.New(prometheus.Config{Address: prometheusURL})
client, err := api.NewClient(api.Config{Address: prometheusURL})
if err != nil {
return nil, err
}
queryAPI := prometheus.NewQueryAPI(client)
queryAPI := v1.NewAPI(client)
value, err := queryAPI.Query(context.Background(), "ALERTS", time.Now())
if err != nil {

View File

@@ -29,7 +29,7 @@ func New(client *kubernetes.Clientset, nodeID, namespace, name, annotation strin
func (dsl *DaemonSetLock) Acquire(metadata interface{}) (acquired bool, owner string, err error) {
for {
ds, err := dsl.client.ExtensionsV1beta1().DaemonSets(dsl.namespace).Get(dsl.name, metav1.GetOptions{})
ds, err := dsl.client.AppsV1().DaemonSets(dsl.namespace).Get(dsl.name, metav1.GetOptions{})
if err != nil {
return false, "", err
}
@@ -53,7 +53,7 @@ func (dsl *DaemonSetLock) Acquire(metadata interface{}) (acquired bool, owner st
}
ds.ObjectMeta.Annotations[dsl.annotation] = string(valueBytes)
_, err = dsl.client.ExtensionsV1beta1().DaemonSets(dsl.namespace).Update(ds)
_, err = dsl.client.AppsV1().DaemonSets(dsl.namespace).Update(ds)
if err != nil {
if se, ok := err.(*errors.StatusError); ok && se.ErrStatus.Reason == metav1.StatusReasonConflict {
// Something else updated the resource between us reading and writing - try again soon
@@ -68,7 +68,7 @@ func (dsl *DaemonSetLock) Acquire(metadata interface{}) (acquired bool, owner st
}
func (dsl *DaemonSetLock) Test(metadata interface{}) (holding bool, err error) {
ds, err := dsl.client.ExtensionsV1beta1().DaemonSets(dsl.namespace).Get(dsl.name, metav1.GetOptions{})
ds, err := dsl.client.AppsV1().DaemonSets(dsl.namespace).Get(dsl.name, metav1.GetOptions{})
if err != nil {
return false, err
}
@@ -87,7 +87,7 @@ func (dsl *DaemonSetLock) Test(metadata interface{}) (holding bool, err error) {
func (dsl *DaemonSetLock) Release() error {
for {
ds, err := dsl.client.ExtensionsV1beta1().DaemonSets(dsl.namespace).Get(dsl.name, metav1.GetOptions{})
ds, err := dsl.client.AppsV1().DaemonSets(dsl.namespace).Get(dsl.name, metav1.GetOptions{})
if err != nil {
return err
}
@@ -107,7 +107,7 @@ func (dsl *DaemonSetLock) Release() error {
delete(ds.ObjectMeta.Annotations, dsl.annotation)
_, err = dsl.client.ExtensionsV1beta1().DaemonSets(dsl.namespace).Update(ds)
_, err = dsl.client.AppsV1().DaemonSets(dsl.namespace).Update(ds)
if err != nil {
if se, ok := err.(*errors.StatusError); ok && se.ErrStatus.Reason == metav1.StatusReasonConflict {
// Something else updated the resource between us reading and writing - try again soon

View File

@@ -15,12 +15,14 @@ var (
type body struct {
Text string `json:"text,omitempty"`
Username string `json:"username,omitempty"`
Channel string `json:"channel,omitempty"`
}
func NotifyReboot(hookURL, username, nodeID string) error {
func notify(hookURL, username, channel, message string) error {
msg := body{
Text: fmt.Sprintf("Rebooting node %s", nodeID),
Text: message,
Username: username,
Channel: channel,
}
var buf bytes.Buffer
@@ -40,3 +42,11 @@ func NotifyReboot(hookURL, username, nodeID string) error {
return nil
}
func NotifyDrain(hookURL, username, channel, nodeID string) error {
return notify(hookURL, username, channel, fmt.Sprintf("Draining node %s", nodeID))
}
func NotifyReboot(hookURL, username, channel, nodeID string) error {
return notify(hookURL, username, channel, fmt.Sprintf("Rebooting node %s", nodeID))
}

91
pkg/timewindow/days.go Normal file
View File

@@ -0,0 +1,91 @@
package timewindow
import (
"fmt"
"strconv"
"strings"
"time"
)
var EveryDay = []string{"su", "mo", "tu", "we", "th", "fr", "sa"}
// dayStrings maps day strings to time.Weekdays
var dayStrings = map[string]time.Weekday{
"su": time.Sunday,
"sun": time.Sunday,
"sunday": time.Sunday,
"mo": time.Monday,
"mon": time.Monday,
"monday": time.Monday,
"tu": time.Tuesday,
"tue": time.Tuesday,
"tuesday": time.Tuesday,
"we": time.Wednesday,
"wed": time.Wednesday,
"wednesday": time.Wednesday,
"th": time.Thursday,
"thu": time.Thursday,
"thursday": time.Thursday,
"fr": time.Friday,
"fri": time.Friday,
"friday": time.Friday,
"sa": time.Saturday,
"sat": time.Saturday,
"saturday": time.Saturday,
}
type weekdays uint32
// parseWeekdays creates a set of weekdays from a string slice
func parseWeekdays(days []string) (weekdays, error) {
var result uint32
for _, day := range days {
if len(day) == 0 {
continue
}
weekday, err := parseWeekday(day)
if err != nil {
return weekdays(0), err
}
result |= 1 << uint32(weekday)
}
return weekdays(result), nil
}
// Contains returns true if the specified weekday is a member of this set.
func (w weekdays) Contains(day time.Weekday) bool {
return uint32(w)&(1<<uint32(day)) != 0
}
// String returns a string representation of the set of weekdays.
func (w weekdays) String() string {
var b strings.Builder
for i := uint32(0); i < 7; i++ {
if uint32(w)&(1<<i) != 0 {
b.WriteString(time.Weekday(i).String()[0:3])
} else {
b.WriteString("---")
}
}
return b.String()
}
func parseWeekday(day string) (time.Weekday, error) {
if n, err := strconv.Atoi(day); err == nil {
if n >= 0 && n < 7 {
return time.Weekday(n), nil
} else {
return time.Sunday, fmt.Errorf("Invalid weekday, number out of range: %s", day)
}
}
if weekday, ok := dayStrings[strings.ToLower(day)]; ok {
return weekday, nil
} else {
return time.Sunday, fmt.Errorf("Invalid weekday: %s", day)
}
}

View File

@@ -0,0 +1,46 @@
package timewindow
import (
"strings"
"testing"
)
func TestParseWeekdays(t *testing.T) {
tests := []struct {
input string
result string
}{
{"0,4", "Sun---------Thu------"},
{"su,mo,tu", "SunMonTue------------"},
{"sunday,tu,thu", "Sun---Tue---Thu------"},
{"THURSDAY", "------------Thu------"},
{"we,WED,WeDnEsDaY", "---------Wed---------"},
{"", "---------------------"},
{",,,", "---------------------"},
}
for _, tst := range tests {
res, err := parseWeekdays(strings.Split(tst.input, ","))
if err != nil {
t.Errorf("Received error for input %s: %v", tst.input, err)
} else if res.String() != tst.result {
t.Errorf("Test %s: Expected %s got %s", tst.input, tst.result, res.String())
}
}
}
func TestParseWeekdaysErrors(t *testing.T) {
tests := []string{
"15",
"-8",
"8",
"mon,tue,wed,fridayyyy",
}
for _, tst := range tests {
_, err := parseWeekdays(strings.Split(tst, ","))
if err == nil {
t.Errorf("Expected to receive error for input %s", tst)
}
}
}

View File

@@ -0,0 +1,68 @@
package timewindow
import (
"fmt"
"time"
)
// TimeWindow specifies a schedule of days and times.
type TimeWindow struct {
days weekdays
location *time.Location
startTime time.Time
endTime time.Time
}
// New creates a TimeWindow instance based on string inputs specifying a schedule.
func New(days []string, startTime, endTime, location string) (*TimeWindow, error) {
tw := &TimeWindow{}
var err error
if tw.days, err = parseWeekdays(days); err != nil {
return nil, err
}
if tw.location, err = time.LoadLocation(location); err != nil {
return nil, err
}
if tw.startTime, err = parseTime(startTime, tw.location); err != nil {
return nil, err
}
if tw.endTime, err = parseTime(endTime, tw.location); err != nil {
return nil, err
}
return tw, nil
}
// Contains determines whether the specified time is within this time window.
func (tw *TimeWindow) Contains(t time.Time) bool {
loctime := t.In(tw.location)
if !tw.days.Contains(loctime.Weekday()) {
return false
}
start := time.Date(loctime.Year(), loctime.Month(), loctime.Day(), tw.startTime.Hour(), tw.startTime.Minute(), tw.startTime.Second(), 0, tw.location)
end := time.Date(loctime.Year(), loctime.Month(), loctime.Day(), tw.endTime.Hour(), tw.endTime.Minute(), tw.endTime.Second(), 1e9-1, tw.location)
return (loctime.After(start) || loctime.Equal(start)) && (loctime.Before(end) || loctime.Equal(end))
}
// String returns a string representation of this time window.
func (tw *TimeWindow) String() string {
return fmt.Sprintf("%s between %02d:%02d and %02d:%02d %s", tw.days.String(), tw.startTime.Hour(), tw.startTime.Minute(), tw.endTime.Hour(), tw.endTime.Minute(), tw.location.String())
}
// parseTime tries to parse a time with several formats.
func parseTime(s string, loc *time.Location) (time.Time, error) {
fmts := []string{"15:04", "15:04:05", "03:04pm", "15", "03pm", "3pm"}
for _, f := range fmts {
if t, err := time.ParseInLocation(f, s, loc); err == nil {
return t, nil
}
}
return time.Now(), fmt.Errorf("Invalid time format: %s", s)
}

View File

@@ -0,0 +1,60 @@
package timewindow
import (
"strings"
"testing"
"time"
)
func TestTimeWindows(t *testing.T) {
type testcase struct {
time string
result bool
}
tests := []struct {
days string
start string
end string
loc string
cases []testcase
}{
{"mon,tue,wed,thu,fri", "9am", "5pm", "America/Los_Angeles", []testcase{
{"2019/04/04 00:49 PDT", false},
{"2019/04/05 08:59 PDT", false},
{"2019/04/05 9:01 PDT", true},
{"2019/03/31 10:00 PDT", false},
{"2019/04/04 12:00 PDT", true},
{"2019/04/04 11:59 UTC", false},
}},
{"mon,we,fri", "10:01", "11:30am", "America/Los_Angeles", []testcase{
{"2019/04/05 10:30 PDT", true},
{"2019/04/06 10:30 PDT", false},
{"2019/04/07 10:30 PDT", false},
{"2019/04/08 10:30 PDT", true},
{"2019/04/09 10:30 PDT", false},
{"2019/04/10 10:30 PDT", true},
{"2019/04/11 10:30 PDT", false},
}},
{"mo,tu,we,th,fr", "00:00", "23:59:59", "UTC", []testcase{
{"2019/04/18 00:00 UTC", true},
{"2019/04/18 23:59 UTC", true},
}},
}
for i, tst := range tests {
tw, err := New(strings.Split(tst.days, ","), tst.start, tst.end, tst.loc)
if err != nil {
t.Errorf("Test [%d] failed to create TimeWindow: %v", i, err)
}
for _, cas := range tst.cases {
tm, err := time.ParseInLocation("2006/01/02 15:04 MST", cas.time, tw.location)
if err != nil {
t.Errorf("Failed to parse time \"%s\": %v", cas.time, err)
} else if cas.result != tw.Contains(tm) {
t.Errorf("(%s) contains (%s) didn't match expected result of %v", tw.String(), cas.time, cas.result)
}
}
}
}