mirror of
https://github.com/danielgormly/drone-plugin-kube.git
synced 2026-06-04 18:23:48 +08:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 438081953b | |||
| f9f8d9aa49 | |||
| cd888d5ff8 | |||
| ddac2b3969 | |||
| 5afd783cc1 | |||
| cdf38eea63 | |||
| 988c199078 | |||
| 184aa03d35 | |||
| b48fbdf379 | |||
| 18eb9355f6 | |||
| 905e7fb4dd | |||
| 3b7fbfd838 | |||
| 5ca8575d87 | |||
| 3035df5f71 | |||
| fd8b5db452 | |||
| 0984bb35d0 | |||
| bf86fd6da1 | |||
| b734a70f81 | |||
| bffcd56139 | |||
| 52c2cfd645 | |||
| 96a6a70009 | |||
| 5e5f7599d4 |
@@ -0,0 +1,3 @@
|
||||
**
|
||||
|
||||
!/built/*
|
||||
@@ -2,43 +2,23 @@
|
||||
|
||||
[](https://microbadger.com/images/danielgormly/drone-plugin-kube "Get your own version badge on microbadger.com")
|
||||
|
||||
A simple Drone plugin for updating Kubernetes deployments from templates & configMaps from files. Follows from [vallard/drone-kube](https://github.com/vallard/drone-kube) but with dependency management, up-to-date client-go, docs updated to Drone 1.0.0 syntax, examples and a different structure. This plugin will create a deployment if it doesn't currently exist.
|
||||
A simple Drone plugin for updating Kubernetes resources from yaml templates. Follows from [vallard/drone-kube](https://github.com/vallard/drone-kube). The plugin will create a resource if it doesn't already exist i.e. behaves similar to `kubectl apply`. This plugin supports deployments, configmaps, ingresses, and services.
|
||||
|
||||
## Usage
|
||||
Usage: See [drone.md](./drone.md)
|
||||
|
||||
Add the following [build step](https://docs.drone.io/user-guide/pipeline/steps/) to your drone pipeline definition. Currently this plugin only updates deployments, it does not create them. I can add this behaviour or I will accept pull requests to introduce it.
|
||||
|
||||
#### drone.yaml deployment example
|
||||
```yml
|
||||
- name: Deploy app
|
||||
image: danielgormly/drone-plugin-kube
|
||||
settings:
|
||||
template: path/to/deployment.yaml # within repo
|
||||
ca: LS0tLS1... # BASE64 encoded string of the K8s CA cert
|
||||
server: https://10.0.0.20:6443 # K8s master node address
|
||||
token:
|
||||
from_secret: kubernetes_token # Service account token to a service account that can manage deployments
|
||||
namespace: custom # [Optional] Kubernetes namespace to use (defaults to `default`)
|
||||
[example_custom_key]: string # [Optional, example] Any additional values you label here will be available for template interpolation (lower case key names only!)
|
||||
```
|
||||
|
||||
## Deployment templates
|
||||
|
||||
Deployment config files are first interpreted by **aymerick/raymond** ([handlebarsjs](http://handlebarsjs.com/) equivalent). You can use all available raymond expressions and anything you put in settings will be made available in your deployment template e.g. `{{namespace}}`. See [example/deployment.template.yaml](/example/deployment.template.yaml) for a complete example.
|
||||
|
||||
## Config maps from files
|
||||
|
||||
In this case, you can create a template just like deployment.yaml but you can provide a file path (relative to the repo's root) in the plugin setting `configmap_file`. (Currently only accepts utf-8 encoded data). Like deployments, this will both create new or update existing configmaps (based on the configmap name).
|
||||
|
||||
#### Adding a service account to Kubernetes that can manage deployments
|
||||
#### Creating a Kubernetes service account for Drone
|
||||
See [example/Role.yaml](example/Role.yaml), [example/ServiceAccount.yaml](example/ServiceAccount.yaml), [example/RoleBinding.yaml](example/RoleBinding.yaml).
|
||||
|
||||
## Usage notes:
|
||||
|
||||
- The watching process is not currently reliable i.e. it doesn't properly wait for new deployments to become live. Not entirely sure how this should behave but I think behind a flag would make sense. PRs welcome.
|
||||
|
||||
## Development notes
|
||||
- No tagged releases or support for older go libraries yet, happy to take feedback in Github issues or PRs.
|
||||
- Kubernetes client not yet supported by dep, so we are using
|
||||
[`brew install glide`](https://github.com/Masterminds/glide).
|
||||
- Update dependencies with brew `glide update --strip-vendor`
|
||||
- [Installing kubernetes/client-go](https://github.com/kubernetes/client-go/blob/master/INSTALL.md)
|
||||
- [Creating a Drone plugin in Go](https://docs.drone.io/plugins/examples/golang/)
|
||||
- [kubernetes/client-go installation notes](https://github.com/kubernetes/client-go/blob/master/INSTALL.md)
|
||||
- [Creating a Drone plugin in Go](https://docs.drone.io/plugins/golang/)
|
||||
- [Client-go API Docs @ godoc.org](https://pkg.go.dev/k8s.io/client-go/kubernetes?tab=doc)
|
||||
- Testing with minikube (OSX: `brew cask install minikube`)
|
||||
- [Client-go API Docs @ godoc.org](https://godoc.org/k8s.io/client-go/kubernetes)
|
||||
|
||||
## Acknowledgements
|
||||
- [@vallard](https://github.com/vallard) for the original plugin
|
||||
- [@jbonzo](https://github.com/jbonzo) for ingress, service support, improved error handling etc
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eou pipefail
|
||||
|
||||
rm -rf build/kubano
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o build/kubano
|
||||
|
||||
docker build -t danielgormly/drone-plugin-kube:0.0.1 build
|
||||
docker push danielgormly/drone-plugin-kube
|
||||
docker build -t danielgormly/drone-plugin-kube:0.2.0 -t danielgormly/drone-plugin-kube:latest build
|
||||
docker push danielgormly/drone-plugin-kube:0.2.0
|
||||
docker push danielgormly/drone-plugin-kube:latest
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// ApplyConfigMapFromFile -- Updates given deployment in Kubernetes
|
||||
func ApplyConfigMapFromFile(clientset *kubernetes.Clientset, namespace string, configmap *corev1.ConfigMap, path string) error {
|
||||
log.Printf("📦 Reading contents of %s", path)
|
||||
_, filename := filepath.Split(path)
|
||||
fileContents, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configMapData := make(map[string]string)
|
||||
configMapData[filename] = string(fileContents)
|
||||
configmap.Data = configMapData
|
||||
// Check if deployment exists
|
||||
deploymentExists, err := configMapExists(clientset, namespace, configmap.Name)
|
||||
if deploymentExists {
|
||||
log.Printf("📦 Found existing deployment. Updating %s.", configmap.Name)
|
||||
_, err = clientset.CoreV1().ConfigMaps(namespace).Update(configmap)
|
||||
return err
|
||||
}
|
||||
_, err = clientset.CoreV1().ConfigMaps(namespace).Create(configmap)
|
||||
return err
|
||||
}
|
||||
|
||||
// configMapExists -- Updates given deployment in Kubernetes
|
||||
func configMapExists(clientset *kubernetes.Clientset, namespace string, name string) (bool, error) {
|
||||
_, err := clientset.CoreV1().ConfigMaps(namespace).Get(name, meta.GetOptions{})
|
||||
if err != nil {
|
||||
// TODO: Only conver to StatusError if the error is in fact a status error
|
||||
statusError, ok := err.(*errors.StatusError)
|
||||
if ok == true && statusError.Status().Code == 404 {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
appv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// CreateOrUpdateDeployment -- Checks if deployment already exists, updates if it does, creates if it doesn't
|
||||
func CreateOrUpdateDeployment(clientset *kubernetes.Clientset, namespace string, deployment *appv1.Deployment) error {
|
||||
deploymentExists, err := deploymentExists(clientset, namespace, deployment.Name)
|
||||
if deploymentExists {
|
||||
log.Printf("📦 Found existing deployment '%s'. Updating.", deployment.Name)
|
||||
_, err = clientset.AppsV1().Deployments(namespace).Update(deployment)
|
||||
return err
|
||||
}
|
||||
log.Printf("📦 Creating new deployment '%s'. Updating.", deployment.Name)
|
||||
_, err = clientset.AppsV1().Deployments(namespace).Create(deployment)
|
||||
return err
|
||||
}
|
||||
|
||||
// deploymentExists -- Updates given deployment in Kubernetes
|
||||
func deploymentExists(clientset *kubernetes.Clientset, namespace string, name string) (bool, error) {
|
||||
_, err := clientset.AppsV1().Deployments(namespace).Get(name, meta.GetOptions{})
|
||||
if err != nil {
|
||||
// TODO: Only conver to StatusError if the error is in fact a status error
|
||||
statusError, ok := err.(*errors.StatusError)
|
||||
if ok == true && statusError.Status().Code == 404 {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// waitUntilDeploymentSettled -- Waits until ready, failure or timeout
|
||||
func waitUntilDeploymentSettled(clientset *kubernetes.Clientset, namespace string, name string, timeout int64) (state string, err error) {
|
||||
fieldSelector := strings.Join([]string{"metadata.name", name}, "=")
|
||||
watchOptions := meta.ListOptions{
|
||||
FieldSelector: fieldSelector,
|
||||
Watch: true,
|
||||
}
|
||||
watcher, error := clientset.AppsV1().Deployments(namespace).Watch(watchOptions)
|
||||
liveDeployment, error := clientset.AppsV1().Deployments(namespace).Get(name, meta.GetOptions{})
|
||||
log.Printf("📦 Unavailable replicas: %d", liveDeployment.Status.UnavailableReplicas)
|
||||
log.Printf("📦 %s", liveDeployment)
|
||||
if liveDeployment.Status.UnavailableReplicas == 0 {
|
||||
return "📦 Updated", error
|
||||
}
|
||||
i := 0
|
||||
for {
|
||||
event := <-watcher.ResultChan()
|
||||
deployment := event.Object.(*appv1.Deployment)
|
||||
if liveDeployment.Status.UnavailableReplicas == 0 {
|
||||
return "📦 Updated", error
|
||||
}
|
||||
log.Printf("📦 Unavailable replicas: %d", deployment.Status.UnavailableReplicas)
|
||||
i++
|
||||
}
|
||||
return "failed", error
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
date: 2019-09-26T00:00:00+00:00
|
||||
date: 2019-09-27T00:00:00+00:00
|
||||
title: Kubernetes
|
||||
author: danielgormly
|
||||
tags: [ kubernetes, deployment, configmap ]
|
||||
@@ -8,14 +8,14 @@ logo: kubernetes.svg
|
||||
image: danielgormly/drone-plugin-kube
|
||||
---
|
||||
|
||||
Updates Kubernetes deployments from templates & configMaps from files. This plugin will either create or update existing resources dependent on their presence. It will wait for deployments before it progresses.
|
||||
Updates Kubernetes resources (deployments, ingresses, services, configmap - with binary data). This plugin will either create or update existing resources dependent on their presence. It will wait for deployments before it progresses.
|
||||
|
||||
Create or update deployment
|
||||
|
||||
```yaml
|
||||
pipeline:
|
||||
- name: Deploy app
|
||||
image: danielgormly/drone-plugin-kube:0.0.1
|
||||
image: danielgormly/drone-plugin-kube:0.2.0
|
||||
settings:
|
||||
template: path/to/deployment.yaml # relative to repo root
|
||||
ca: LS0tLS1... # BASE64 encoded string of the K8s CA cert
|
||||
@@ -29,7 +29,7 @@ Create or update config-map from a single file
|
||||
```diff
|
||||
pipeline:
|
||||
- name: Deploy app
|
||||
image: danielgormly/drone-plugin-kube:0.0.1
|
||||
image: danielgormly/drone-plugin-kube:0.2.0
|
||||
settings:
|
||||
- template: path/to/deployment.yaml
|
||||
+ template: path/to/config-map.yaml
|
||||
@@ -40,15 +40,77 @@ pipeline:
|
||||
from_secret: kubernetes_token
|
||||
```
|
||||
|
||||
# Secret Reference
|
||||
|
||||
kubernetes_token
|
||||
: Kubernetes service account token (Not base64 encoded)
|
||||
|
||||
# Parameter Reference
|
||||
|
||||
ca
|
||||
: Base-64 encoded string of the K8s CA cert
|
||||
| Value | Key |
|
||||
|------------------|------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ca | Base-64 encoded string of the K8s CA cert |
|
||||
| server | https://10.0.0.20:6443 |
|
||||
| namespace | Namespace to deploy to |
|
||||
| kubernetes_token | Kubernetes service account token (Not base64 encoded) |
|
||||
| template | Path to Kubernetes yaml based definition file (Configmap or Deployment). Relative to Git basedir. |
|
||||
| configmap_file | Path to file containing data to inject in configmap (They configmap key that contains the data will be the filename) |
|
||||
| * | Other parameters will be made available for interpolation within yaml templates (upper-case will be converted to lower-case) |
|
||||
|
||||
server
|
||||
: https://10.0.0.20:6443
|
||||
## Template Substitution
|
||||
|
||||
You can substitute values in the deployment template files. But first you have to define the variables.
|
||||
|
||||
```yaml {4-5}
|
||||
- name: Deploy K8s - Workload
|
||||
image: danielgormly/drone-plugin-kube:0.0.2
|
||||
settings:
|
||||
build_number: ${DRONE_BUILD_NUMBER}
|
||||
template: deployment.yaml
|
||||
ca:
|
||||
from_secret: k8s_cert
|
||||
server:
|
||||
from_secret: k8s_server
|
||||
token:
|
||||
from_secret: k8s_token
|
||||
```
|
||||
|
||||
You can substitute the following values between ```{{ }}``` in your deployment template.
|
||||
Example `deployment.yaml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: wiki
|
||||
labels:
|
||||
app: wiki
|
||||
name: wiki
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: wiki
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: wiki
|
||||
spec:
|
||||
containers:
|
||||
- image: registry.example.com/wiki:{{ build_number }}
|
||||
imagePullPolicy: Always
|
||||
name: wiki
|
||||
```
|
||||
|
||||
### Template Reference
|
||||
|
||||
| Key | Value |
|
||||
|---------------|----------------------------------------------------------------------------------|
|
||||
| repo.owner | repository owner |
|
||||
| repo.name | repository name |
|
||||
| build.status | build status type enumeration, either `success` or `failure` |
|
||||
| build.event | build event type enumeration, one of `push`, `pull_request`, `tag`, `deployment` |
|
||||
| build.number | build number |
|
||||
| build.commit | git sha for current commit |
|
||||
| build.branch | git branch for current commit |
|
||||
| build.tag | git tag for current commit |
|
||||
| build.ref | git ref for current commit |
|
||||
| build.author | git author for current commit |
|
||||
| build.link | link the the build results in drone |
|
||||
| build.created | unix timestamp for build creation |
|
||||
| build.started | unix timestamp for build started |
|
||||
|
||||
Generated
-243
@@ -1,243 +0,0 @@
|
||||
hash: 0a6476e347f6e80ed358c4dadb03f9a46c1acac36f211864199ff09a4325ec94
|
||||
updated: 2019-08-27T11:44:06.143731+10:00
|
||||
imports:
|
||||
- name: github.com/aymerick/raymond
|
||||
version: b565731e1464263de0bda75f2e45d97b54b60110
|
||||
subpackages:
|
||||
- ast
|
||||
- lexer
|
||||
- parser
|
||||
- name: github.com/davecgh/go-spew
|
||||
version: 8991bc29aa16c548c550c7ff78260e27b9ab7c73
|
||||
subpackages:
|
||||
- spew
|
||||
- name: github.com/gogo/protobuf
|
||||
version: 4c00d2f19fb91be5fecd8681fa83450a2a979e69
|
||||
subpackages:
|
||||
- proto
|
||||
- sortkeys
|
||||
- name: github.com/golang/protobuf
|
||||
version: aa810b61a9c79d51363740d207bb46cf8e620ed5
|
||||
subpackages:
|
||||
- proto
|
||||
- ptypes
|
||||
- ptypes/any
|
||||
- ptypes/duration
|
||||
- ptypes/timestamp
|
||||
- name: github.com/google/gofuzz
|
||||
version: f140a6486e521aad38f5917de355cbf147cc0496
|
||||
- name: github.com/googleapis/gnostic
|
||||
version: 0c5108395e2debce0d731cf0287ddf7242066aba
|
||||
subpackages:
|
||||
- OpenAPIv2
|
||||
- compiler
|
||||
- extensions
|
||||
- name: github.com/imdario/mergo
|
||||
version: 9316a62528ac99aaecb4e47eadd6dc8aa6533d58
|
||||
- name: github.com/json-iterator/go
|
||||
version: 27518f6661eba504be5a7a9a9f6d9460d892ade3
|
||||
- name: github.com/modern-go/concurrent
|
||||
version: bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94
|
||||
- name: github.com/modern-go/reflect2
|
||||
version: 94122c33edd36123c84d5368cfb2b69df93a0ec8
|
||||
- name: github.com/spf13/pflag
|
||||
version: 298182f68c66c05229eb03ac171abe6e309ee79a
|
||||
- name: golang.org/x/crypto
|
||||
version: de0752318171da717af4ce24d0a2e8626afaeb11
|
||||
subpackages:
|
||||
- ssh/terminal
|
||||
- name: golang.org/x/net
|
||||
version: cdfb69ac37fc6fa907650654115ebebb3aae2087
|
||||
subpackages:
|
||||
- context
|
||||
- http/httpguts
|
||||
- http2
|
||||
- http2/hpack
|
||||
- idna
|
||||
- name: golang.org/x/oauth2
|
||||
version: a6bd8cefa1811bd24b86f8902872e4e8225f74c4
|
||||
subpackages:
|
||||
- google
|
||||
- internal
|
||||
- jws
|
||||
- jwt
|
||||
- name: golang.org/x/sys
|
||||
version: 3b5209105503162ded1863c307ac66fec31120dd
|
||||
subpackages:
|
||||
- unix
|
||||
- windows
|
||||
- name: golang.org/x/text
|
||||
version: e6919f6577db79269a6443b9dc46d18f2238fb5d
|
||||
subpackages:
|
||||
- secure/bidirule
|
||||
- transform
|
||||
- unicode/bidi
|
||||
- unicode/norm
|
||||
- name: golang.org/x/time
|
||||
version: f51c12702a4d776e4c1fa9b0fabab841babae631
|
||||
subpackages:
|
||||
- rate
|
||||
- name: google.golang.org/appengine
|
||||
version: fb139bde60fa77cede04f226b4d5a3cf68dcce27
|
||||
subpackages:
|
||||
- internal
|
||||
- internal/base
|
||||
- internal/datastore
|
||||
- internal/log
|
||||
- internal/remote_api
|
||||
- internal/urlfetch
|
||||
- urlfetch
|
||||
- name: gopkg.in/inf.v0
|
||||
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
|
||||
- name: gopkg.in/yaml.v2
|
||||
version: 51d6538a90f86fe93ac480b35f37b2be17fef232
|
||||
- name: k8s.io/api
|
||||
version: 40a48860b5abbba9aa891b02b32da429b08d96a0
|
||||
subpackages:
|
||||
- admissionregistration/v1beta1
|
||||
- apps/v1
|
||||
- apps/v1beta1
|
||||
- apps/v1beta2
|
||||
- auditregistration/v1alpha1
|
||||
- authentication/v1
|
||||
- authentication/v1beta1
|
||||
- authorization/v1
|
||||
- authorization/v1beta1
|
||||
- autoscaling/v1
|
||||
- autoscaling/v2beta1
|
||||
- autoscaling/v2beta2
|
||||
- batch/v1
|
||||
- batch/v1beta1
|
||||
- batch/v2alpha1
|
||||
- certificates/v1beta1
|
||||
- coordination/v1
|
||||
- coordination/v1beta1
|
||||
- core/v1
|
||||
- events/v1beta1
|
||||
- extensions/v1beta1
|
||||
- networking/v1
|
||||
- networking/v1beta1
|
||||
- node/v1alpha1
|
||||
- node/v1beta1
|
||||
- policy/v1beta1
|
||||
- rbac/v1
|
||||
- rbac/v1alpha1
|
||||
- rbac/v1beta1
|
||||
- scheduling/v1
|
||||
- scheduling/v1alpha1
|
||||
- scheduling/v1beta1
|
||||
- settings/v1alpha1
|
||||
- storage/v1
|
||||
- storage/v1alpha1
|
||||
- storage/v1beta1
|
||||
- name: k8s.io/apimachinery
|
||||
version: d7deff9243b165ee192f5551710ea4285dcfd615
|
||||
subpackages:
|
||||
- pkg/api/errors
|
||||
- pkg/api/meta
|
||||
- pkg/api/resource
|
||||
- pkg/apis/meta/v1
|
||||
- pkg/apis/meta/v1/unstructured
|
||||
- pkg/apis/meta/v1beta1
|
||||
- pkg/conversion
|
||||
- pkg/conversion/queryparams
|
||||
- pkg/fields
|
||||
- pkg/labels
|
||||
- pkg/runtime
|
||||
- pkg/runtime/schema
|
||||
- pkg/runtime/serializer
|
||||
- pkg/runtime/serializer/json
|
||||
- pkg/runtime/serializer/protobuf
|
||||
- pkg/runtime/serializer/recognizer
|
||||
- pkg/runtime/serializer/streaming
|
||||
- pkg/runtime/serializer/versioning
|
||||
- pkg/selection
|
||||
- pkg/types
|
||||
- pkg/util/clock
|
||||
- pkg/util/errors
|
||||
- pkg/util/framer
|
||||
- pkg/util/intstr
|
||||
- pkg/util/json
|
||||
- pkg/util/naming
|
||||
- pkg/util/net
|
||||
- pkg/util/runtime
|
||||
- pkg/util/sets
|
||||
- pkg/util/validation
|
||||
- pkg/util/validation/field
|
||||
- pkg/util/yaml
|
||||
- pkg/version
|
||||
- pkg/watch
|
||||
- third_party/forked/golang/reflect
|
||||
- name: k8s.io/client-go
|
||||
version: 6ee68ca5fd8355d024d02f9db0b3b667e8357a0f
|
||||
subpackages:
|
||||
- discovery
|
||||
- kubernetes
|
||||
- kubernetes/scheme
|
||||
- kubernetes/typed/admissionregistration/v1beta1
|
||||
- kubernetes/typed/apps/v1
|
||||
- kubernetes/typed/apps/v1beta1
|
||||
- kubernetes/typed/apps/v1beta2
|
||||
- kubernetes/typed/auditregistration/v1alpha1
|
||||
- kubernetes/typed/authentication/v1
|
||||
- kubernetes/typed/authentication/v1beta1
|
||||
- kubernetes/typed/authorization/v1
|
||||
- kubernetes/typed/authorization/v1beta1
|
||||
- kubernetes/typed/autoscaling/v1
|
||||
- kubernetes/typed/autoscaling/v2beta1
|
||||
- kubernetes/typed/autoscaling/v2beta2
|
||||
- kubernetes/typed/batch/v1
|
||||
- kubernetes/typed/batch/v1beta1
|
||||
- kubernetes/typed/batch/v2alpha1
|
||||
- kubernetes/typed/certificates/v1beta1
|
||||
- kubernetes/typed/coordination/v1
|
||||
- kubernetes/typed/coordination/v1beta1
|
||||
- kubernetes/typed/core/v1
|
||||
- kubernetes/typed/events/v1beta1
|
||||
- kubernetes/typed/extensions/v1beta1
|
||||
- kubernetes/typed/networking/v1
|
||||
- kubernetes/typed/networking/v1beta1
|
||||
- kubernetes/typed/node/v1alpha1
|
||||
- kubernetes/typed/node/v1beta1
|
||||
- kubernetes/typed/policy/v1beta1
|
||||
- kubernetes/typed/rbac/v1
|
||||
- kubernetes/typed/rbac/v1alpha1
|
||||
- kubernetes/typed/rbac/v1beta1
|
||||
- kubernetes/typed/scheduling/v1
|
||||
- kubernetes/typed/scheduling/v1alpha1
|
||||
- kubernetes/typed/scheduling/v1beta1
|
||||
- kubernetes/typed/settings/v1alpha1
|
||||
- kubernetes/typed/storage/v1
|
||||
- kubernetes/typed/storage/v1alpha1
|
||||
- kubernetes/typed/storage/v1beta1
|
||||
- pkg/apis/clientauthentication
|
||||
- pkg/apis/clientauthentication/v1alpha1
|
||||
- pkg/apis/clientauthentication/v1beta1
|
||||
- pkg/version
|
||||
- plugin/pkg/client/auth/exec
|
||||
- rest
|
||||
- rest/watch
|
||||
- tools/auth
|
||||
- tools/clientcmd
|
||||
- tools/clientcmd/api
|
||||
- tools/clientcmd/api/latest
|
||||
- tools/clientcmd/api/v1
|
||||
- tools/metrics
|
||||
- tools/reference
|
||||
- transport
|
||||
- util/cert
|
||||
- util/connrotation
|
||||
- util/flowcontrol
|
||||
- util/homedir
|
||||
- util/keyutil
|
||||
- name: k8s.io/klog
|
||||
version: 3ca30a56d8a775276f9cdae009ba326fdc05af7f
|
||||
- name: k8s.io/utils
|
||||
version: c2654d5206da6b7b6ace12841e8f359bb89b443c
|
||||
subpackages:
|
||||
- buffer
|
||||
- integer
|
||||
- trace
|
||||
- name: sigs.k8s.io/yaml
|
||||
version: fd68e9863619f6ec2fdd8625fe1f02e7c877e480
|
||||
testImports: []
|
||||
@@ -1,5 +0,0 @@
|
||||
package: github.com/danielgormly/kubano
|
||||
import:
|
||||
- package: k8s.io/client-go
|
||||
version: v11.0.0
|
||||
- package: github.com/aymerick/raymond
|
||||
@@ -0,0 +1,16 @@
|
||||
module github.com/polygon-io/drone-plugin-kube
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible
|
||||
github.com/gogo/protobuf v1.2.2-0.20190818160850-4c00d2f19fb9 // indirect
|
||||
github.com/json-iterator/go v1.1.7 // indirect
|
||||
github.com/spf13/pflag v1.0.3 // indirect
|
||||
google.golang.org/appengine v1.6.2-0.20190801181406-fb139bde60fa // indirect
|
||||
gopkg.in/yaml.v2 v2.2.2 // indirect
|
||||
k8s.io/api v0.0.0-20190819141258-3544db3b9e44
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d
|
||||
k8s.io/client-go v0.0.0-20190819141724-e14f31a72a77
|
||||
k8s.io/klog v0.4.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,118 @@
|
||||
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/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns=
|
||||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||
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/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190818160850-4c00d2f19fb9 h1:ACDM6sadFsshhlBc2RXIEFJqVY3uChLkeWBZhlcc1pA=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190818160850-4c00d2f19fb9/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/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/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/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 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
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 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
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/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/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-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68=
|
||||
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c h1:+EXw7AwNOKzPFXMZ1yNjO40aWCh3PIquJB2fYlv9wcs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g=
|
||||
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.2-0.20190801181406-fb139bde60fa h1:MnE5UP0nRrHc2tdEcOM2SIf8s1GWYfVetU/nVFDQf/U=
|
||||
google.golang.org/appengine v1.6.2-0.20190801181406-fb139bde60fa/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
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 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
|
||||
gopkg.in/inf.v0 v0.9.0/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-20190819141258-3544db3b9e44 h1:7Gz7/nQ7X2qmPXMyN0bNq7Zm9Uip+UnFuMZTd2l3vms=
|
||||
k8s.io/api v0.0.0-20190819141258-3544db3b9e44/go.mod h1:AOxZTnaXR/xiarlQL0JUfwQPxjmKDvVYoRp58cA7lUo=
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d h1:7Kns6qqhMAQWvGkxYOLSLRZ5hJO0/5pcE5lPGP2fxUw=
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d/go.mod h1:3jediapYqJ2w1BFw7lAZPCx7scubsTfosqHkhXCWJKw=
|
||||
k8s.io/client-go v0.0.0-20190819141724-e14f31a72a77 h1:w1BoabVnPpPqQCY3sHK4qVwa12Lk8ip1pKMR1C+qbdo=
|
||||
k8s.io/client-go v0.0.0-20190819141724-e14f31a72a77/go.mod h1:DmkJD5UDP87MVqUQ5VJ6Tj9Oen8WzXPhk3la4qpyG4g=
|
||||
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.4.0 h1:lCJCxf/LIowc2IGS9TPjWDyXY4nOmdGdfcwwDQCOURQ=
|
||||
k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
||||
k8s.io/utils v0.0.0-20190221042446-c2654d5206da h1:ElyM7RPonbKnQqOcw7dG2IK5uvQQn3b/WPHqD5mBvP4=
|
||||
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
@@ -22,7 +22,7 @@ func (p Plugin) CreateKubeClient() (*kubernetes.Clientset, error) {
|
||||
} else {
|
||||
ca, err := base64.StdEncoding.DecodeString(p.KubeConfig.Ca)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Printf("possible corrupted CA, or not base64 encoded: %s\n", err)
|
||||
}
|
||||
clusterConfig.CertificateAuthorityData = ca
|
||||
}
|
||||
@@ -39,10 +39,7 @@ func (p Plugin) CreateKubeClient() (*kubernetes.Clientset, error) {
|
||||
clientBuilder := clientcmd.NewNonInteractiveClientConfig(*config, "default", &clientcmd.ConfigOverrides{}, nil)
|
||||
actualCfg, err := clientBuilder.ClientConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Printf("Unexpected error: %v", err)
|
||||
return nil, fmt.Errorf("client builder client config; %w", err)
|
||||
}
|
||||
return kubernetes.NewForConfig(actualCfg)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func main() {
|
||||
},
|
||||
}
|
||||
fmt.Printf(os.Getenv("PLUGIN_SKIP_TLS"))
|
||||
fmt.Println("kubano v0.0.1 https://github.com/danielgormly/drone-plugin-kube")
|
||||
fmt.Println("danielgormly/drone-plugin-kube@0.2.0 https://github.com/danielgormly/drone-plugin-kube")
|
||||
err := plugin.Exec()
|
||||
if err != nil {
|
||||
log.Fatalf("⛔️ Fatal error: \n%s", err)
|
||||
|
||||
@@ -9,8 +9,9 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/aymerick/raymond"
|
||||
appv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
appV1 "k8s.io/api/apps/v1"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
v1BetaV1 "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
@@ -42,9 +43,6 @@ func (p Plugin) Exec() error {
|
||||
if p.KubeConfig.Ca == "" {
|
||||
return errors.New("PLUGIN_CA is not defined")
|
||||
}
|
||||
if p.KubeConfig.Namespace == "" {
|
||||
p.KubeConfig.Namespace = "default"
|
||||
}
|
||||
if p.Template == "" {
|
||||
return errors.New("PLUGIN_TEMPLATE, or template must be defined")
|
||||
}
|
||||
@@ -58,47 +56,81 @@ func (p Plugin) Exec() error {
|
||||
key := strings.ToLower(matches[1])
|
||||
ctx[key] = matches[2]
|
||||
}
|
||||
|
||||
re = regexp.MustCompile(`^DRONE_(.*)=(.*)`)
|
||||
if re.MatchString(value) {
|
||||
matches := re.FindStringSubmatch(value)
|
||||
key := strings.ToLower(matches[1])
|
||||
ctx[key] = matches[2]
|
||||
}
|
||||
}
|
||||
|
||||
// Grab template from filesystem
|
||||
raw, err := ioutil.ReadFile(p.Template)
|
||||
if err != nil {
|
||||
log.Print("⛔️ Error reading template file:")
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse template
|
||||
templateYaml, err := raymond.Render(string(raw), ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Connect to Kubernetes
|
||||
clientset, err := p.CreateKubeClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Decode
|
||||
kubernetesObject, _, err := scheme.Codecs.UniversalDeserializer().Decode([]byte(templateYaml), nil, nil)
|
||||
if err != nil {
|
||||
log.Print("⛔️ Error decoding template into valid Kubernetes object:")
|
||||
return err
|
||||
}
|
||||
|
||||
switch o := kubernetesObject.(type) {
|
||||
case *appv1.Deployment:
|
||||
case *appV1.Deployment:
|
||||
log.Print("📦 Resource type: Deployment")
|
||||
if p.KubeConfig.Namespace == "" {
|
||||
p.KubeConfig.Namespace = o.Namespace
|
||||
}
|
||||
|
||||
err = CreateOrUpdateDeployment(clientset, p.KubeConfig.Namespace, o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for successful update
|
||||
log.Print("📦 Watching deployment until no unavailable replicas.")
|
||||
state, watchErr := waitUntilDeploymentSettled(clientset, p.KubeConfig.Namespace, o.ObjectMeta.Name, 120)
|
||||
log.Printf("%s", state)
|
||||
return watchErr
|
||||
case *corev1.ConfigMap:
|
||||
case *coreV1.ConfigMap:
|
||||
if p.KubeConfig.Namespace == "" {
|
||||
p.KubeConfig.Namespace = o.Namespace
|
||||
}
|
||||
|
||||
log.Print("📦 Resource type: ConfigMap")
|
||||
err = ApplyConfigMapFromFile(clientset, p.KubeConfig.Namespace, o, p.ConfigMapFile)
|
||||
case *coreV1.Service:
|
||||
if p.KubeConfig.Namespace == "" {
|
||||
p.KubeConfig.Namespace = o.Namespace
|
||||
}
|
||||
|
||||
log.Print("Resource type: Service")
|
||||
err = ApplyService(clientset, p.KubeConfig.Namespace, o)
|
||||
case *v1BetaV1.Ingress:
|
||||
if p.KubeConfig.Namespace == "" {
|
||||
p.KubeConfig.Namespace = o.Namespace
|
||||
}
|
||||
|
||||
log.Print("Resource type: Ingress")
|
||||
err = ApplyIngress(clientset, p.KubeConfig.Namespace, o)
|
||||
default:
|
||||
err = errors.New("⛔️ This plugin doesn't support that resource type")
|
||||
return err
|
||||
return errors.New("⛔️ This plugin doesn't support that resource type")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
appV1 "k8s.io/api/apps/v1"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
v1BetaV1 "k8s.io/api/extensions/v1beta1"
|
||||
kubeErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// CreateOrUpdateDeployment -- Checks if deployment already exists, updates if it does, creates if it doesn't
|
||||
func CreateOrUpdateDeployment(clientset *kubernetes.Clientset, namespace string, deployment *appV1.Deployment) error {
|
||||
deploymentExists, err := deploymentExists(clientset, namespace, deployment.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if deploymentExists {
|
||||
log.Printf("📦 Found existing deployment '%s'. Updating.", deployment.Name)
|
||||
_, err = clientset.AppsV1().Deployments(namespace).Update(deployment)
|
||||
return err
|
||||
}
|
||||
log.Printf("📦 Creating new deployment '%s'. Updating.", deployment.Name)
|
||||
_, err = clientset.AppsV1().Deployments(namespace).Create(deployment)
|
||||
return err
|
||||
}
|
||||
|
||||
// deploymentExists -- Updates given deployment in Kubernetes
|
||||
func deploymentExists(clientset *kubernetes.Clientset, namespace string, name string) (bool, error) {
|
||||
_, err := clientset.AppsV1().Deployments(namespace).Get(name, metaV1.GetOptions{})
|
||||
if err != nil {
|
||||
// TODO: Only conver to StatusError if the error is in fact a status error
|
||||
statusError, ok := err.(*kubeErrors.StatusError)
|
||||
if ok && statusError.Status().Code == http.StatusNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
const (
|
||||
stateUpdated = "📦 Updated"
|
||||
stateFailed = "⛔️ Failed"
|
||||
)
|
||||
|
||||
// waitUntilDeploymentSettled -- Waits until ready, failure or timeout
|
||||
func waitUntilDeploymentSettled(clientset *kubernetes.Clientset, namespace string, name string, timeoutInSeconds int64) (string, error) {
|
||||
fieldSelector := strings.Join([]string{"metadata.name", name}, "=")
|
||||
watchOptions := metaV1.ListOptions{
|
||||
FieldSelector: fieldSelector,
|
||||
Watch: true,
|
||||
}
|
||||
|
||||
watcher, err := clientset.AppsV1().Deployments(namespace).Watch(watchOptions)
|
||||
if err != nil {
|
||||
return stateFailed, fmt.Errorf("watch deployment; %w", err)
|
||||
}
|
||||
|
||||
liveDeployment, err := clientset.AppsV1().Deployments(namespace).Get(name, metaV1.GetOptions{})
|
||||
if err != nil {
|
||||
return stateFailed, fmt.Errorf("get deployment; %w", err)
|
||||
}
|
||||
|
||||
log.Printf("📦 Unavailable replicas: %d", liveDeployment.Status.UnavailableReplicas)
|
||||
if liveDeployment.Status.UnavailableReplicas == 0 {
|
||||
return "📦 Updated", nil
|
||||
}
|
||||
|
||||
timer := time.NewTimer(time.Duration(timeoutInSeconds) * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-timer.C:
|
||||
return stateFailed, errors.New("deployment watcher timed out. Something is wrong")
|
||||
case event := <-watcher.ResultChan():
|
||||
deployment := event.Object.(*appV1.Deployment)
|
||||
if deployment.Status.UnavailableReplicas == 0 {
|
||||
return stateUpdated, nil
|
||||
}
|
||||
log.Printf("📦 Unavailable replicas: %d", deployment.Status.UnavailableReplicas)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyService creates a service if it doesn't exists, updates it if it does
|
||||
func ApplyService(clientset *kubernetes.Clientset, namespace string, service *coreV1.Service) error {
|
||||
existingService, exists, err := getService(clientset, namespace, service.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists {
|
||||
_, err = clientset.CoreV1().Services(namespace).Update(existingService)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = clientset.CoreV1().Services(namespace).Create(service)
|
||||
return err
|
||||
}
|
||||
|
||||
// getService returns a service object, or false if it doesn't exist
|
||||
func getService(clientset *kubernetes.Clientset, namespace string, name string) (*coreV1.Service, bool, error) {
|
||||
service, err := clientset.CoreV1().Services(namespace).Get(name, metaV1.GetOptions{})
|
||||
if err != nil {
|
||||
statusError, ok := err.(*kubeErrors.StatusError)
|
||||
if ok && statusError.Status().Code == http.StatusNotFound {
|
||||
return nil, false, nil
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return service, true, nil
|
||||
}
|
||||
|
||||
// ApplyConfigMapFromFile -- Updates given deployment in Kubernetes
|
||||
func ApplyConfigMapFromFile(clientset *kubernetes.Clientset, namespace string, configMap *coreV1.ConfigMap, path string) error {
|
||||
log.Printf("📦 Reading contents of %s", path)
|
||||
_, filename := filepath.Split(path)
|
||||
fileContents, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configMapData := make(map[string]string)
|
||||
configMapData[filename] = string(fileContents)
|
||||
configMap.Data = configMapData
|
||||
|
||||
// Check if deployment exists
|
||||
exists, err := configMapExists(clientset, namespace, configMap.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists {
|
||||
log.Printf("📦 Found existing deployment. Updating %s.", configMap.Name)
|
||||
_, err = clientset.CoreV1().ConfigMaps(namespace).Update(configMap)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = clientset.CoreV1().ConfigMaps(namespace).Create(configMap)
|
||||
return err
|
||||
}
|
||||
|
||||
// configMapExists -- Updates given deployment in Kubernetes
|
||||
func configMapExists(clientset *kubernetes.Clientset, namespace string, name string) (bool, error) {
|
||||
_, err := clientset.CoreV1().ConfigMaps(namespace).Get(name, metaV1.GetOptions{})
|
||||
if err != nil {
|
||||
statusError, ok := err.(*kubeErrors.StatusError)
|
||||
if ok && statusError.Status().Code == http.StatusNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func ApplyIngress(clientset *kubernetes.Clientset, namespace string, ingress *v1BetaV1.Ingress) error {
|
||||
_, exists, err := getIngress(clientset, namespace, ingress.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
_, err = clientset.ExtensionsV1beta1().Ingresses(namespace).Create(ingress)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = clientset.ExtensionsV1beta1().Ingresses(namespace).Update(ingress)
|
||||
return err
|
||||
}
|
||||
|
||||
func getIngress(clientset *kubernetes.Clientset, namespace string, name string) (*v1BetaV1.Ingress, bool, error) {
|
||||
ingress, err := clientset.ExtensionsV1beta1().Ingresses(namespace).Get(name, metaV1.GetOptions{})
|
||||
if err != nil {
|
||||
statusError, ok := err.(*kubeErrors.StatusError)
|
||||
if ok && statusError.Status().Code == http.StatusNotFound {
|
||||
return nil, false, nil
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return ingress, true, nil
|
||||
}
|
||||
@@ -4,6 +4,7 @@ export PLUGIN_TEMPLATE=test/configmap.template.yaml
|
||||
export PLUGIN_CONFIGMAP_FILE=test/sample-config-data
|
||||
export PLUGIN_NAME=drone-kube-test
|
||||
export PLUGIN_COMMIT=a5b81d0f
|
||||
export PLUGIN_NAMESPACE=default
|
||||
|
||||
go build -o build/kubano
|
||||
export $(cat .env | xargs) && ./build/kubano
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
export PLUGIN_TEMPLATE=test/deployment.template.yaml
|
||||
export PLUGIN_NAME=drone-kube-test
|
||||
export PLUGIN_NAMESPACE=default
|
||||
|
||||
go build -o build/kubano
|
||||
export $(cat .env | xargs) && ./build/kubano
|
||||
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PLUGIN_TEMPLATE=test/service.template.yaml
|
||||
export PLUGIN_NAME=drone-kube-test
|
||||
export PLUGIN_NAMESPACE=default
|
||||
|
||||
go build -o build/kubano
|
||||
export $(cat .env | xargs) && ./build/kubano
|
||||
|
||||
# docker run --env-file=.env drone-kubano
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: wiki-http
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: wiki
|
||||
type: ClusterIP
|
||||
Reference in New Issue
Block a user