Compare commits

...
Author SHA1 Message Date
baderbuddy abca53d9a0 Add to exemptions docs 2020-12-18 08:34:46 -05:00
Robert Brennan edf28c8790 update for 3.0 (#456) 2020-12-17 17:48:25 -05:00
Robert Brennan 7c98598858 Fix test fixtures, add a test for controllers (#455)
* first pass at fixing test fixtures

* tests mostly working

* add controller test

* remove debug stuff

* delint

* revert test file

* remove extra controllers from fixtures

* delint

* fix messages
2020-12-17 17:32:01 -05:00
2393f0bbf9 Install Doc Updates (#451)
* Update admission-controller.md

Corrected name of helm repo for polaris chart and added blurb about requiring TLS certs.

* Update admission-controller.md

Updated to reflect the kubectl and helm install methods both require cert-manager.

* Update admission-controller.md

Adding bullets to the steps required for CA bundle use.

* Update admission-controller.md

Fixed typo in the chart URL

* Update docs-md/admission-controller.md

Co-authored-by: Barnabas Makonda <6409210+makoscafee@users.noreply.github.com>

Co-authored-by: Robert Brennan <accounts@rbren.io>
Co-authored-by: Barnabas Makonda <6409210+makoscafee@users.noreply.github.com>
2020-12-17 17:11:24 -05:00
Robert Brennan 4e044602f4 change how controller checks are handled (#454)
* change how controller checks are handled

* add changelog

* simpler fix
2020-12-17 16:29:49 -05:00
Robert Brennan 6b7ccdadc4 fix push 2020-12-14 15:55:46 +00:00
Robert Brennan b511abab60 set -u 2020-12-14 15:52:37 +00:00
Robert Brennan fab5cb9a21 have action push to a separate branch 2020-12-14 15:51:00 +00:00
Robert Brennan 949eb9e04a fix action 2020-12-14 15:33:16 +00:00
Robert Brennan e4656bcae8 empty commit 2020-12-14 15:32:22 +00:00
17 changed files with 294 additions and 229 deletions
+2 -2
View File
@@ -41,7 +41,7 @@ jobs:
echo "Build created a diff, but the last commit was a build."
exit 1
fi
git add docs/
git add ../docs/
git commit -m "[CI] rebuild website"
git push
git push -u origin +master:website
fi
+1 -1
View File
@@ -3,7 +3,7 @@
<br>
<h3>Best Practices for Kubernetes Workload Configuration</h3>
<a href="https://github.com/FairwindsOps/polaris">
<img src="https://img.shields.io/static/v1.svg?label=Version&message=2.0.0&color=239922">
<img src="https://img.shields.io/static/v1.svg?label=Version&message=3.0.0&color=239922">
</a>
<a href="https://goreportcard.com/report/github.com/FairwindsOps/polaris">
<img src="https://goreportcard.com/badge/github.com/FairwindsOps/polaris">
+7 -12
View File
@@ -8,19 +8,14 @@ controllers:
schema:
'$schema': http://json-schema.org/draft-07/schema
type: object
required:
- Object
required:
- spec
properties:
Object:
spec:
type: object
required:
- spec
- replicas
properties:
spec:
type: object
required:
- replicas
properties:
replicas:
type: integer
minimum: 2
replicas:
type: integer
minimum: 2
+1 -1
View File
@@ -109,7 +109,7 @@ spec:
- command:
- polaris
- dashboard
image: 'quay.io/fairwinds/polaris:2.0'
image: 'quay.io/fairwinds/polaris:3.0'
imagePullPolicy: 'Always'
name: dashboard
ports:
+1 -1
View File
@@ -109,7 +109,7 @@ spec:
command:
- polaris
- webhook
image: 'quay.io/fairwinds/polaris:2.0'
image: 'quay.io/fairwinds/polaris:3.0'
imagePullPolicy: 'Always'
ports:
- containerPort: 9876
+10 -3
View File
@@ -9,6 +9,14 @@ configuration through dashboard visibility, but to actually enforce it with this
Note that Polaris will not alter your workloads, only block workloads that don't conform to the configured policies.
## Installation
A valid TLS certificate is required for the Polaris Validating Webhook. If you have cert-manager installed in your cluster then the install methods below will work.
If you don't use cert-manager, you'll need to:
* Supply a CA Bundle with the `webhook.caBundle`
* Create a TLS secret in your cluster with a valid certificate that uses that CA
* Pass the name of that secret with the webhook.secretName parameter.
### kubectl
```bash
kubectl apply -f https://github.com/fairwindsops/polaris/releases/latest/download/webhook.yaml
@@ -16,8 +24,8 @@ kubectl apply -f https://github.com/fairwindsops/polaris/releases/latest/downloa
### Helm
```bash
helm repo add fairwindsops-stable https://charts.fairwindsops.com/stable
helm upgrade --install polaris fairwindsops-stable/polaris --namespace polaris \
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm upgrade --install polaris fairwinds-stable/polaris --namespace polaris \
--set webhook.enable=true --set dashboard.enable=false
```
@@ -34,4 +42,3 @@ output unless we are rejecting a workload altogether.
This means that any checks with a severity of `warning` will still pass webhook validation,
and the only evidence of that warning will either be in the Polaris dashboard or the
Polaris webhook logs. This will change in a future version of Kubernetes.
+8
View File
@@ -1,6 +1,14 @@
---
sidebarDepth: 0
---
## 3.0.0
* **Breaking** - fixed inconsistency in how controller-level checks are handled
Custom checks with `target: Controller` should remove `Object` from the top-level of the
JSON schema (see changes to `./checks/multipleReplicasForDeployment.yaml`)
## 2.0.1
* Fixed Polaris deployment process
## 2.0.0
* Standardize categories of checks into Security, Reliability, and Efficiency
* Changes to the dashboard UI
+1 -4
View File
@@ -83,10 +83,7 @@ The steps are:
1. Clone the helm charts repo
1. `git clone https://github.com/FairwindsOps/charts`
2. `git checkout -b yourname/update-polaris`
1. Bump the version number in:
1. stable/polaris/README.md
2. stable/polaris/Chart.yaml
3. stable/polaris/values.yaml
1. Bump the version number in `stable/polaris/Chart.yaml`
2. Make any necessary changes to the chart to support the new version of Polaris (e.g. new RBAC permissions)
3. **Don't merge yet!**
2. Create a PR for this repo
+10 -5
View File
@@ -18,19 +18,24 @@ kubectl annotate deployment my-deployment polaris.fairwinds.com/cpuRequestsMissi
## Config
To exempt a controller via the config, you have to specify a namespace (optional), a list of controller names and a list of rules, e.g.
To exempt a controller via the config, you have to specify a namespace (optional), a list of controller names and a list of rules (optional), e.g.
```yaml
exemptions:
# exemption valid for kube-system namespace
- namespace: kube-system
controllerNames:
- dns-controller
- dns-controller
rules:
- hostNetworkSet
- hostNetworkSet
# exemption valid for all rules on all controllers in default namespace
- namespace: default
controllerNames:
- ""
# exemption valid in all namespaces
- controllerNames:
- dns-controller
- dns-controller
rules:
- hostNetworkSet
- hostNetworkSet
```
If no rules are specified then every rule is exempted. Controller names are matched as a prefix, so an empty string will match every controller.
+1 -1
View File
@@ -20,7 +20,7 @@ import (
const (
// Version represents the current release version of Polaris
Version = "2.0.0"
Version = "3.0.0"
)
func main() {
+18 -9
View File
@@ -27,13 +27,13 @@ func TestGetResourcesFromPath(t *testing.T) {
assert.Equal(t, 1, len(resources.Namespaces), "Should have a namespace")
assert.Equal(t, "two", resources.Namespaces[0].ObjectMeta.Name)
assert.Equal(t, 8, len(resources.Controllers), "Should have eight controllers")
assert.Equal(t, 9, len(resources.Controllers), "Should have eight controllers")
namespaceCount := map[string]int{}
for _, controller := range resources.Controllers {
namespaceCount[controller.ObjectMeta.GetNamespace()]++
}
assert.Equal(t, 7, namespaceCount[""], "Should have seven controller in default namespace")
assert.Equal(t, 1, namespaceCount["two"], "Should have one controller in namespace 'two'")
assert.Equal(t, 8, namespaceCount[""])
assert.Equal(t, 1, namespaceCount["two"])
}
func TestGetMultipleResourceFromSingleFile(t *testing.T) {
@@ -87,10 +87,7 @@ func TestAddResourcesFromReader(t *testing.T) {
}
func TestGetResourceFromAPI(t *testing.T) {
k8s, dynamicInterface := test.SetupTestAPI()
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
// TODO find a way to mock out the dynamic client
// and create fake pods in order to find all of the controllers.
k8s, dynamicInterface := test.SetupTestAPI(test.GetMockControllers("test")...)
resources, err := CreateResourceProviderFromAPI(context.Background(), k8s, "test", &dynamicInterface)
assert.Equal(t, nil, err, "Error should be nil")
@@ -99,7 +96,19 @@ func TestGetResourceFromAPI(t *testing.T) {
assert.IsType(t, time.Now(), resources.CreationTime, "Creation time should be set")
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
assert.Equal(t, 1, len(resources.Controllers), "Should have 1 controller")
assert.Equal(t, 5, len(resources.Controllers), "Should have 5 controllers")
assert.Equal(t, "", resources.Controllers[0].ObjectMeta.GetName())
expectedNames := map[string]bool{
"deploy": false,
"job": false,
"cronjob": false,
"statefulset": false,
"daemonset": false,
}
for _, ctrl := range resources.Controllers {
expectedNames[ctrl.ObjectMeta.GetName()] = true
}
for name, val := range expectedNames {
assert.Equal(t, true, val, name)
}
}
@@ -0,0 +1,20 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: test-deployment-2
spec:
replicas: 2
selector:
matchLabels:
app: test-deployment
template:
metadata:
labels:
app: test-deployment
spec:
containers:
- name: ubuntu
image: ubuntu
ports:
- containerPort: 3000
+2 -1
View File
@@ -136,7 +136,8 @@ func newGenericWorkload(ctx context.Context, podResource kubeAPICoreV1.Pod, dyna
}
if lastKey != "" {
bytes, err := json.Marshal(objectCache[lastKey])
unst := objectCache[lastKey]
bytes, err := json.Marshal(&unst)
if err != nil {
return workload, err
}
+49 -30
View File
@@ -16,6 +16,7 @@ package validator
import (
"context"
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
@@ -59,41 +60,59 @@ func TestValidateController(t *testing.T) {
}
func TestControllerLevelChecks(t *testing.T) {
c := conf.Configuration{
Checks: map[string]conf.Severity{
"multipleReplicasForDeployment": conf.SeverityDanger,
},
}
resources, err := kube.CreateResourceProviderFromPath("../kube/test_files/test_1")
testResources := func(res *kube.ResourceProvider) {
c := conf.Configuration{
Checks: map[string]conf.Severity{
"multipleReplicasForDeployment": conf.SeverityDanger,
},
}
expectedResult := ResultMessage{
ID: "multipleReplicasForDeployment",
Severity: "danger",
Category: "Reliability",
}
for _, controller := range res.Controllers {
if controller.Kind == "Deployment" {
actualResult, err := ValidateController(context.Background(), &c, controller)
if err != nil {
panic(err)
}
if controller.ObjectMeta.GetName() == "test-deployment-2" {
expectedResult.Success = true
expectedResult.Message = "Multiple replicas are scheduled"
} else if controller.ObjectMeta.GetName() == "test-deployment" {
expectedResult.Success = false
expectedResult.Message = "Only one replica is scheduled"
}
expectedResults := ResultSet{
"multipleReplicasForDeployment": expectedResult,
}
assert.Equal(t, nil, err, "Error should be nil")
assert.Equal(t, 8, len(resources.Controllers), "Should have eight controllers")
expectedSum := CountSummary{
Successes: uint(0),
Warnings: uint(0),
Dangers: uint(1),
}
expectedResults := ResultSet{
"multipleReplicasForDeployment": {ID: "multipleReplicasForDeployment", Message: "Only one replica is scheduled", Success: false, Severity: "danger", Category: "Reliability"},
}
for _, controller := range resources.Controllers {
if controller.Kind == "Deployment" && controller.ObjectMeta.GetName() == "test-deployment" {
actualResult, err := ValidateController(context.Background(), &c, controller)
if err != nil {
panic(err)
assert.Equal(t, "Deployment", actualResult.Kind)
assert.Equal(t, 1, len(actualResult.Results), "should be equal")
assert.EqualValues(t, expectedResults, actualResult.Results, controller.ObjectMeta.GetName())
}
assert.Equal(t, "Deployment", actualResult.Kind)
assert.Equal(t, 1, len(actualResult.Results), "should be equal")
assert.EqualValues(t, expectedSum, actualResult.GetSummary())
assert.EqualValues(t, expectedResults, actualResult.Results)
}
}
res, err := kube.CreateResourceProviderFromPath("../kube/test_files/test_1")
assert.Equal(t, nil, err, "Error should be nil")
assert.Equal(t, 9, len(res.Controllers), "Should have eight controllers")
testResources(res)
replicaSpec := map[string]interface{}{"replicas": 2}
b, err := json.Marshal(replicaSpec)
assert.NoError(t, err)
err = json.Unmarshal(b, &replicaSpec)
d1, p1 := test.MockDeploy("test", "test-deployment")
d2, p2 := test.MockDeploy("test", "test-deployment-2")
d2.Object["spec"] = replicaSpec
k8s, dynamicClient := test.SetupTestAPI(&d1, &p1, &d2, &p2)
res, err = kube.CreateResourceProviderFromAPI(context.Background(), k8s, "test", &dynamicClient)
assert.Equal(t, err, nil, "error should be nil")
assert.Equal(t, 2, len(res.Controllers), "Should have two controllers")
testResources(res)
}
func TestSkipHealthChecks(t *testing.T) {
+22 -16
View File
@@ -11,13 +11,10 @@ import (
)
func TestGetTemplateData(t *testing.T) {
k8s, dynamicClient := test.SetupTestAPI()
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
k8s = test.SetupAddExtraControllerVersions(context.Background(), k8s, "test-extra")
// TODO figure out how to mock out dynamic client.
// and add in pods for all controllers to fill out tests.
k8s, dynamicClient := test.SetupTestAPI(test.GetMockControllers("test")...)
resources, err := kube.CreateResourceProviderFromAPI(context.Background(), k8s, "test", &dynamicClient)
assert.Equal(t, err, nil, "error should be nil")
assert.Equal(t, 5, len(resources.Controllers))
c := conf.Configuration{
Checks: map[string]conf.Severity{
@@ -28,29 +25,38 @@ func TestGetTemplateData(t *testing.T) {
sum := CountSummary{
Successes: uint(0),
Warnings: uint(1),
Dangers: uint(1),
Warnings: uint(3),
Dangers: uint(3),
}
actualAudit, err := RunAudit(context.Background(), c, resources)
assert.Equal(t, err, nil, "error should be nil")
assert.EqualValues(t, sum, actualAudit.GetSummary())
assert.Equal(t, actualAudit.SourceType, "Cluster", "should be from a cluster")
assert.Equal(t, actualAudit.SourceName, "test", "should be from a cluster")
expected := []struct {
expectedResults := []struct {
kind string
results int
}{
{kind: "Pod", results: 2},
{kind: "StatefulSet", results: 2},
{kind: "DaemonSet", results: 2},
{kind: "Deployment", results: 2},
{kind: "Job", results: 0},
{kind: "CronJob", results: 0},
}
assert.Equal(t, len(expected), len(actualAudit.Results))
for idx, result := range actualAudit.Results {
assert.Equal(t, expected[idx].kind, result.Kind)
assert.Equal(t, 1, len(result.PodResult.ContainerResults))
assert.Equal(t, expected[idx].results, len(result.PodResult.ContainerResults[0].Results))
assert.Equal(t, len(expectedResults), len(actualAudit.Results))
for _, result := range actualAudit.Results {
found := false
for _, expected := range expectedResults {
if expected.kind != result.Kind {
continue
}
found = true
assert.Equal(t, 1, len(result.PodResult.ContainerResults))
assert.Equal(t, expected.results, len(result.PodResult.ContainerResults[0].Results))
}
assert.Equal(t, found, true)
}
}
-10
View File
@@ -36,8 +36,6 @@ func TestValidatePod(t *testing.T) {
},
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
deployment, err := kube.NewGenericWorkloadFromPod(p, nil)
assert.NoError(t, err)
@@ -73,8 +71,6 @@ func TestInvalidIPCPod(t *testing.T) {
},
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
p.Spec.HostIPC = true
workload, err := kube.NewGenericWorkloadFromPod(p, nil)
@@ -110,8 +106,6 @@ func TestInvalidNeworkPod(t *testing.T) {
},
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
p.Spec.HostNetwork = true
workload, err := kube.NewGenericWorkloadFromPod(p, nil)
@@ -148,8 +142,6 @@ func TestInvalidPIDPod(t *testing.T) {
},
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
p.Spec.HostPID = true
workload, err := kube.NewGenericWorkloadFromPod(p, nil)
@@ -192,8 +184,6 @@ func TestExemption(t *testing.T) {
},
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
p.Spec.HostIPC = true
p.ObjectMeta = metav1.ObjectMeta{
+141 -133
View File
@@ -1,7 +1,7 @@
package test
import (
"context"
"encoding/json"
appsv1 "k8s.io/api/apps/v1"
appsv1beta1 "k8s.io/api/apps/v1beta1"
@@ -10,6 +10,7 @@ import (
batchv1beta1 "k8s.io/api/batch/v1beta1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic"
dynamicFake "k8s.io/client-go/dynamic/fake"
@@ -17,6 +18,20 @@ import (
"k8s.io/client-go/kubernetes/fake"
)
func newUnstructured(apiVersion, kind, namespace, name string, spec interface{}) unstructured.Unstructured {
return unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": apiVersion,
"kind": kind,
"metadata": map[string]interface{}{
"namespace": namespace,
"name": name,
},
"spec": spec,
},
}
}
// MockContainer creates a container object
func MockContainer(name string) corev1.Container {
c := corev1.Container{
@@ -45,166 +60,159 @@ func MockNakedPod() corev1.Pod {
}
}
// MockDeploy creates a Deployment object.
func MockDeploy() appsv1.Deployment {
// MockController creates a mock controller and pod
func MockController(apiVersion, kind, namespace, name string, spec interface{}, podSpec corev1.PodSpec) (unstructured.Unstructured, corev1.Pod) {
d := newUnstructured(apiVersion, kind, namespace, name, spec)
pod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: name + "-12345",
Namespace: namespace,
OwnerReferences: []metav1.OwnerReference{{
APIVersion: apiVersion,
Kind: kind,
Name: name,
}},
},
Spec: podSpec,
}
return d, pod
}
// MockControllerWithNormalSpec mocks a controller with podspec at spec.template.spec
func MockControllerWithNormalSpec(apiVersion, kind, namespace, name string) (unstructured.Unstructured, corev1.Pod) {
p := MockPod()
d := appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
b, err := json.Marshal(p.Spec)
if err != nil {
panic(err)
}
pSpec := map[string]interface{}{}
err = json.Unmarshal(b, &pSpec)
if err != nil {
panic(err)
}
spec := map[string]interface{}{
"template": map[string]interface{}{
"spec": pSpec,
},
}
return d
return MockController(apiVersion, kind, namespace, name, spec, p.Spec)
}
// MockDeploy creates a Deployment object.
func MockDeploy(namespace, name string) (unstructured.Unstructured, corev1.Pod) {
return MockControllerWithNormalSpec("apps/v1", "Deployment", namespace, name)
}
// MockStatefulSet creates a StatefulSet object.
func MockStatefulSet() appsv1.StatefulSet {
p := MockPod()
s := appsv1.StatefulSet{
Spec: appsv1.StatefulSetSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
return s
func MockStatefulSet(namespace, name string) (unstructured.Unstructured, corev1.Pod) {
return MockControllerWithNormalSpec("apps/v1", "StatefulSet", namespace, name)
}
// MockDaemonSet creates a DaemonSet object.
func MockDaemonSet() appsv1.DaemonSet {
p := MockPod()
return appsv1.DaemonSet{
Spec: appsv1.DaemonSetSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
func MockDaemonSet(namespace, name string) (unstructured.Unstructured, corev1.Pod) {
return MockControllerWithNormalSpec("apps/v1", "DaemonSet", namespace, name)
}
// MockJob creates a Job object.
func MockJob() batchv1.Job {
p := MockPod()
return batchv1.Job{
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
func MockJob(namespace, name string) (unstructured.Unstructured, corev1.Pod) {
return MockControllerWithNormalSpec("batch/v1", "Job", namespace, name)
}
// MockCronJob creates a CronJob object.
func MockCronJob() batchv1beta1.CronJob {
func MockCronJob(namespace, name string) (unstructured.Unstructured, corev1.Pod) {
p := MockPod()
return batchv1beta1.CronJob{
Spec: batchv1beta1.CronJobSpec{
JobTemplate: batchv1beta1.JobTemplateSpec{
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
b, err := json.Marshal(p.Spec)
if err != nil {
panic(err)
}
pSpec := map[string]interface{}{}
err = json.Unmarshal(b, &pSpec)
if err != nil {
panic(err)
}
spec := map[string]interface{}{
"job_template": map[string]interface{}{
"spec": map[string]interface{}{
"template": map[string]interface{}{
"spec": pSpec,
},
},
},
}
return MockController("batch/v1beta1", "CronJob", namespace, name, spec, p.Spec)
}
// MockReplicationController creates a ReplicationController object.
func MockReplicationController() corev1.ReplicationController {
p := MockPod()
return corev1.ReplicationController{
Spec: corev1.ReplicationControllerSpec{
Template: &corev1.PodTemplateSpec{Spec: p.Spec},
},
}
func MockReplicationController(namespace, name string) (unstructured.Unstructured, corev1.Pod) {
return MockControllerWithNormalSpec("core/v1", "ReplicationController", namespace, name)
}
// SetupTestAPI creates a test kube API struct.
func SetupTestAPI() (kubernetes.Interface, dynamic.Interface) {
func SetupTestAPI(objects ...runtime.Object) (kubernetes.Interface, dynamic.Interface) {
scheme := runtime.NewScheme()
return fake.NewSimpleClientset(), dynamicFake.NewSimpleDynamicClient(scheme)
appsv1.AddToScheme(scheme)
corev1.AddToScheme(scheme)
fake.AddToScheme(scheme)
dynamicClient := dynamicFake.NewSimpleDynamicClient(scheme, objects...)
k := fake.NewSimpleClientset(objects...)
k.Resources = []*metav1.APIResourceList{
{
GroupVersion: corev1.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
{Name: "pods", Namespaced: true, Kind: "Pod"},
{Name: "replicationcontrollers", Namespaced: true, Kind: "ReplicationController"},
},
},
{
GroupVersion: appsv1.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
{Name: "daemonsets", Namespaced: true, Kind: "DaemonSet"},
{Name: "statefulsets", Namespaced: true, Kind: "StatefulSet"},
},
},
{
GroupVersion: batchv1.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
{Name: "jobs", Namespaced: true, Kind: "Job"},
},
},
{
GroupVersion: batchv1beta1.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
{Name: "cronjobs", Namespaced: true, Kind: "CronJob"},
},
},
{
GroupVersion: appsv1beta2.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
{Name: "deployments/scale", Namespaced: true, Kind: "Scale", Group: "apps", Version: "v1beta2"},
},
},
{
GroupVersion: appsv1beta1.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
{Name: "statefulsets", Namespaced: true, Kind: "StatefulSet"},
{Name: "statefulsets/scale", Namespaced: true, Kind: "Scale", Group: "apps", Version: "v1beta1"},
},
},
}
return k, dynamicClient
}
// SetupAddControllers creates mock controllers and adds them to the test clientset.
func SetupAddControllers(ctx context.Context, k kubernetes.Interface, namespace string) kubernetes.Interface {
d1 := MockDeploy()
if _, err := k.AppsV1().Deployments(namespace).Create(ctx, &d1, metav1.CreateOptions{}); err != nil {
panic(err)
// GetMockControllers returns mocked controllers for 5 major controller types
func GetMockControllers(namespace string) []runtime.Object {
deploy, deployPod := MockDeploy(namespace, "deploy")
statefulset, statefulsetPod := MockStatefulSet(namespace, "statefulset")
daemonset, daemonsetPod := MockDaemonSet(namespace, "daemonset")
job, jobPod := MockJob(namespace, "job")
cronjob, cronjobPod := MockCronJob(namespace, "cronjob")
return []runtime.Object{
&deploy, &deployPod,
&daemonset, &daemonsetPod,
&statefulset, &statefulsetPod,
&cronjob, &cronjobPod,
&job, &jobPod,
}
s1 := MockStatefulSet()
if _, err := k.AppsV1().StatefulSets(namespace).Create(ctx, &s1, metav1.CreateOptions{}); err != nil {
panic(err)
}
ds1 := MockDaemonSet()
if _, err := k.AppsV1().DaemonSets(namespace).Create(ctx, &ds1, metav1.CreateOptions{}); err != nil {
panic(err)
}
j1 := MockJob()
if _, err := k.BatchV1().Jobs(namespace).Create(ctx, &j1, metav1.CreateOptions{}); err != nil {
panic(err)
}
cj1 := MockCronJob()
if _, err := k.BatchV1beta1().CronJobs(namespace).Create(ctx, &cj1, metav1.CreateOptions{}); err != nil {
panic(err)
}
rc1 := MockReplicationController()
if _, err := k.CoreV1().ReplicationControllers(namespace).Create(ctx, &rc1, metav1.CreateOptions{}); err != nil {
panic(err)
}
p1 := MockNakedPod()
if _, err := k.CoreV1().Pods(namespace).Create(ctx, &p1, metav1.CreateOptions{}); err != nil {
panic(err)
}
return k
}
// SetupAddExtraControllerVersions creates mock controllers and adds them to the test clientset.
func SetupAddExtraControllerVersions(ctx context.Context, k kubernetes.Interface, namespace string) kubernetes.Interface {
p := MockPod()
dv1b1 := appsv1beta1.Deployment{
Spec: appsv1beta1.DeploymentSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta1().Deployments(namespace).Create(ctx, &dv1b1, metav1.CreateOptions{}); err != nil {
panic(err)
}
dv1b2 := appsv1beta2.Deployment{
Spec: appsv1beta2.DeploymentSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta2().Deployments(namespace).Create(ctx, &dv1b2, metav1.CreateOptions{}); err != nil {
panic(err)
}
ssv1b1 := appsv1beta1.StatefulSet{
Spec: appsv1beta1.StatefulSetSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta1().StatefulSets(namespace).Create(ctx, &ssv1b1, metav1.CreateOptions{}); err != nil {
panic(err)
}
ssv1b2 := appsv1beta2.StatefulSet{
Spec: appsv1beta2.StatefulSetSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta2().StatefulSets(namespace).Create(ctx, &ssv1b2, metav1.CreateOptions{}); err != nil {
panic(err)
}
dsv1b2 := appsv1beta2.DaemonSet{
Spec: appsv1beta2.DaemonSetSpec{
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta2().DaemonSets(namespace).Create(ctx, &dsv1b2, metav1.CreateOptions{}); err != nil {
panic(err)
}
return k
}