Commit 93fa5167 authored by Adam Reese's avatar Adam Reese

Merge pull request #635 from adamreese/ref/kube

ref(kube): refactor kubeclient to a struct
parents fc9171f8 0b6309be
...@@ -43,7 +43,7 @@ func (i *Installer) Install() error { ...@@ -43,7 +43,7 @@ func (i *Installer) Install() error {
return err return err
} }
return kube.Create("helm", &b, nil) return kube.New(nil).Create("helm", &b)
} }
// InstallYAML is the installation YAML for DM. // InstallYAML is the installation YAML for DM.
......
...@@ -9,7 +9,17 @@ import ( ...@@ -9,7 +9,17 @@ import (
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
) )
const includeThirdPartyAPIs = false // Client represents a client capable of communicating with the Kubernetes API.
type Client struct {
config clientcmd.ClientConfig
}
// New create a new Client
func New(config clientcmd.ClientConfig) *Client {
return &Client{
config: config,
}
}
// ResourceActorFunc performs an action on a signle resource. // ResourceActorFunc performs an action on a signle resource.
type ResourceActorFunc func(*resource.Info) error type ResourceActorFunc func(*resource.Info) error
...@@ -17,12 +27,13 @@ type ResourceActorFunc func(*resource.Info) error ...@@ -17,12 +27,13 @@ type ResourceActorFunc func(*resource.Info) error
// Create creates kubernetes resources from an io.reader // Create creates kubernetes resources from an io.reader
// //
// Namespace will set the namespace // Namespace will set the namespace
// Config allows for overiding values from kubectl func (c *Client) Create(namespace string, reader io.Reader) error {
func Create(namespace string, reader io.Reader, config clientcmd.ClientConfig) error { f := cmdutil.NewFactory(c.config)
f := cmdutil.NewFactory(config)
return perform(f, namespace, reader, createResource) return perform(f, namespace, reader, createResource)
} }
const includeThirdPartyAPIs = false
func perform(f *cmdutil.Factory, namespace string, reader io.Reader, fn ResourceActorFunc) error { func perform(f *cmdutil.Factory, namespace string, reader io.Reader, fn ResourceActorFunc) error {
r := f.NewBuilder(includeThirdPartyAPIs). r := f.NewBuilder(includeThirdPartyAPIs).
ContinueOnError(). ContinueOnError().
......
package kube package kube
import ( import (
"os" "io"
"strings"
"testing" "testing"
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
...@@ -11,21 +12,37 @@ import ( ...@@ -11,21 +12,37 @@ import (
) )
func TestPerform(t *testing.T) { func TestPerform(t *testing.T) {
input, err := os.Open("./testdata/guestbook-all-in-one.yaml") tests := []struct {
if err != nil { name string
t.Fatal(err) namespace string
reader io.Reader
count int
err bool
errMessage string
}{
{
name: "Valid input",
namespace: "test",
reader: strings.NewReader(guestbookManifest),
count: 6,
}, {
name: "Empty manifests",
namespace: "test",
reader: strings.NewReader(""),
err: true,
errMessage: "no objects passed to create",
},
} }
defer input.Close()
for _, tt := range tests {
results := []*resource.Info{} results := []*resource.Info{}
fn := func(info *resource.Info) error { fn := func(info *resource.Info) error {
results = append(results, info) results = append(results, info)
if info.Namespace != "test" { if info.Namespace != tt.namespace {
t.Errorf("expected namespace to be 'test', got %s", info.Namespace) t.Errorf("%q. expected namespace to be '%s', got %s", tt.name, tt.namespace, info.Namespace)
} }
return nil return nil
} }
...@@ -34,11 +51,140 @@ func TestPerform(t *testing.T) { ...@@ -34,11 +51,140 @@ func TestPerform(t *testing.T) {
return &fake.RESTClient{}, nil return &fake.RESTClient{}, nil
} }
if err := perform(f, "test", input, fn); err != nil { err := perform(f, tt.namespace, tt.reader, fn)
t.Fatalf("Unexpected error: %s", err) if (err != nil) != tt.err {
t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err)
}
if err != nil && err.Error() != tt.errMessage {
t.Errorf("%q. expected error message: %v, got %v", tt.name, tt.errMessage, err)
} }
if len(results) != 6 { if len(results) != tt.count {
t.Errorf("expected 6 result objects, got %d", len(results)) t.Errorf("%q. expected %d result objects, got %d", tt.name, tt.count, len(results))
}
} }
} }
const guestbookManifest = `
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
app: redis
tier: backend
role: master
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis
tier: backend
role: master
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-master
spec:
replicas: 1
template:
metadata:
labels:
app: redis
role: master
tier: backend
spec:
containers:
- name: master
image: gcr.io/google_containers/redis:e2e # or just image: redis
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-slave
labels:
app: redis
tier: backend
role: slave
spec:
ports:
# the port that this service should serve on
- port: 6379
selector:
app: redis
tier: backend
role: slave
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-slave
spec:
replicas: 2
template:
metadata:
labels:
app: redis
role: slave
tier: backend
spec:
containers:
- name: slave
image: gcr.io/google_samples/gb-redisslave:v1
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
ports:
- port: 80
selector:
app: guestbook
tier: frontend
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 3
template:
metadata:
labels:
app: guestbook
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google-samples/gb-frontend:v4
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 80
`
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
app: redis
tier: backend
role: master
spec:
ports:
# the port that this service should serve on
- port: 6379
targetPort: 6379
selector:
app: redis
tier: backend
role: master
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-master
# these labels can be applied automatically
# from the labels in the pod template if not set
# labels:
# app: redis
# role: master
# tier: backend
spec:
# this replicas value is default
# modify it according to your case
replicas: 1
# selector can be applied automatically
# from the labels in the pod template if not set
# selector:
# matchLabels:
# app: guestbook
# role: master
# tier: backend
template:
metadata:
labels:
app: redis
role: master
tier: backend
spec:
containers:
- name: master
image: gcr.io/google_containers/redis:e2e # or just image: redis
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-slave
labels:
app: redis
tier: backend
role: slave
spec:
ports:
# the port that this service should serve on
- port: 6379
selector:
app: redis
tier: backend
role: slave
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-slave
# these labels can be applied automatically
# from the labels in the pod template if not set
# labels:
# app: redis
# role: slave
# tier: backend
spec:
# this replicas value is default
# modify it according to your case
replicas: 2
# selector can be applied automatically
# from the labels in the pod template if not set
# selector:
# matchLabels:
# app: guestbook
# role: slave
# tier: backend
template:
metadata:
labels:
app: redis
role: slave
tier: backend
spec:
containers:
- name: slave
image: gcr.io/google_samples/gb-redisslave:v1
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
# If your cluster config does not include a dns service, then to
# instead access an environment variable to find the master
# service's host, comment out the 'value: dns' line above, and
# uncomment the line below.
# value: env
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# if your cluster supports it, uncomment the following to automatically create
# an external load-balanced IP for the frontend service.
# type: LoadBalancer
ports:
# the port that this service should serve on
- port: 80
selector:
app: guestbook
tier: frontend
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend
# these labels can be applied automatically
# from the labels in the pod template if not set
# labels:
# app: guestbook
# tier: frontend
spec:
# this replicas value is default
# modify it according to your case
replicas: 3
# selector can be applied automatically
# from the labels in the pod template if not set
# selector:
# matchLabels:
# app: guestbook
# tier: frontend
template:
metadata:
labels:
app: guestbook
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google-samples/gb-frontend:v4
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
# If your cluster config does not include a dns service, then to
# instead access environment variables to find service host
# info, comment out the 'value: dns' line above, and uncomment the
# line below.
# value: env
ports:
- containerPort: 80
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment