Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for more controller versions #245

Merged
merged 11 commits into from
Feb 26, 2020
4 changes: 3 additions & 1 deletion cmd/polaris/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ var webhookCmd = &cobra.Command{
for innerIndex, supportedAPIType := range controllerToScan.ListSupportedAPIVersions() {
webhookName := strings.ToLower(fmt.Sprintf("%s-%d-%d", controllerToScan, index, innerIndex))
hook := fwebhook.NewWebhook(webhookName, mgr, fwebhook.Validator{Config: config}, supportedAPIType)
webhooks = append(webhooks, hook)
if hook != nil {
webhooks = append(webhooks, hook)
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions pkg/config/supportedcontrollers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import (
"strings"

appsv1 "k8s.io/api/apps/v1"
appsv1beta1 "k8s.io/api/apps/v1beta1"
appsv1beta2 "k8s.io/api/apps/v1beta2"
batchv1 "k8s.io/api/batch/v1"
batchv1beta1 "k8s.io/api/batch/v1beta1"
batchv2alpha1 "k8s.io/api/batch/v2alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
)
Expand Down Expand Up @@ -103,14 +106,19 @@ func (s SupportedController) ListSupportedAPIVersions() []runtime.Object {
case Deployments:
supportedVersions = []runtime.Object{
&appsv1.Deployment{},
&appsv1beta1.Deployment{},
&appsv1beta2.Deployment{},
}
case StatefulSets:
supportedVersions = []runtime.Object{
&appsv1.StatefulSet{},
&appsv1beta1.StatefulSet{},
&appsv1beta2.StatefulSet{},
}
case DaemonSets:
supportedVersions = []runtime.Object{
&appsv1.DaemonSet{},
&appsv1beta2.DaemonSet{},
}
case Jobs:
supportedVersions = []runtime.Object{
Expand All @@ -119,6 +127,7 @@ func (s SupportedController) ListSupportedAPIVersions() []runtime.Object {
case CronJobs:
supportedVersions = []runtime.Object{
&batchv1beta1.CronJob{},
&batchv2alpha1.CronJob{},
}
case ReplicationControllers:
supportedVersions = []runtime.Object{
Expand Down
192 changes: 171 additions & 21 deletions pkg/kube/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package kube

import (
"bytes"
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
Expand Down Expand Up @@ -77,7 +78,7 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
}
contents, err := ioutil.ReadFile(path)
if err != nil {
logrus.Errorf("Error reading file %v", path)
logrus.Errorf("Error reading file: %v", path)
return err
}
specs := regexp.MustCompile("\n-+\n").Split(string(contents), -1)
Expand Down Expand Up @@ -105,12 +106,12 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
func CreateResourceProviderFromCluster() (*ResourceProvider, error) {
kubeConf, configError := config.GetConfig()
if configError != nil {
logrus.Errorf("Error fetching KubeConfig %v", configError)
logrus.Errorf("Error fetching KubeConfig: %v", configError)
return nil, configError
}
api, err := kubernetes.NewForConfig(kubeConf)
if err != nil {
logrus.Errorf("Error creating Kubernetes client %v", err)
logrus.Errorf("Error creating Kubernetes client: %v", err)
return nil, err
}
return CreateResourceProviderFromAPI(api, kubeConf.Host)
Expand All @@ -121,52 +122,49 @@ func CreateResourceProviderFromAPI(kube kubernetes.Interface, clusterName string
listOpts := metav1.ListOptions{}
serverVersion, err := kube.Discovery().ServerVersion()
if err != nil {
logrus.Errorf("Error fetching Cluster API version %v", err)
logrus.Errorf("Error fetching Cluster API version: %v", err)
return nil, err
}
deploys, err := kube.AppsV1().Deployments("").List(listOpts)
deploys, err := getDeployments(kube)
if err != nil {
logrus.Errorf("Error fetching Deployments %v", err)
return nil, err
}
statefulSets, err := kube.AppsV1().StatefulSets("").List(listOpts)
statefulSets, err := getStatefulSets(kube)
if err != nil {
logrus.Errorf("Error fetching StatefulSets%v", err)
return nil, err
}
daemonSets, err := kube.AppsV1().DaemonSets("").List(listOpts)
cronJobs, err := getCronJobs(kube)
if err != nil {
logrus.Errorf("Error fetching DaemonSets %v", err)
return nil, err
}
jobs, err := kube.BatchV1().Jobs("").List(listOpts)
daemonSets, err := kube.AppsV1().DaemonSets("").List(listOpts)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this use getDaemonSets too? I think you will still miss appsv1beta2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I added some tests to make sure we don't miss these.

if err != nil {
logrus.Errorf("Error fetching Jobs %v", err)
logrus.Errorf("Error fetching DaemonSets: %v", err)
return nil, err
}
cronJobs, err := kube.BatchV1beta1().CronJobs("").List(listOpts)
jobs, err := kube.BatchV1().Jobs("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching CronJobs %v", err)
logrus.Errorf("Error fetching Jobs: %v", err)
return nil, err
}
replicationControllers, err := kube.CoreV1().ReplicationControllers("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching ReplicationControllers %v", err)
logrus.Errorf("Error fetching ReplicationControllers: %v", err)
return nil, err
}
nodes, err := kube.CoreV1().Nodes().List(listOpts)
if err != nil {
logrus.Errorf("Error fetching Nodes %v", err)
logrus.Errorf("Error fetching Nodes: %v", err)
return nil, err
}
namespaces, err := kube.CoreV1().Namespaces().List(listOpts)
if err != nil {
logrus.Errorf("Error fetching Namespaces %v", err)
logrus.Errorf("Error fetching Namespaces: %v", err)
return nil, err
}
pods, err := kube.CoreV1().Pods("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching Pods %v", err)
logrus.Errorf("Error fetching Pods: %v", err)
return nil, err
}

Expand All @@ -175,11 +173,11 @@ func CreateResourceProviderFromAPI(kube kubernetes.Interface, clusterName string
SourceType: "Cluster",
SourceName: clusterName,
CreationTime: time.Now(),
Deployments: deploys.Items,
StatefulSets: statefulSets.Items,
Deployments: deploys,
StatefulSets: statefulSets,
DaemonSets: daemonSets.Items,
Jobs: jobs.Items,
CronJobs: cronJobs.Items,
CronJobs: cronJobs,
ReplicationControllers: replicationControllers.Items,
Nodes: nodes.Items,
Namespaces: namespaces.Items,
Expand Down Expand Up @@ -237,3 +235,155 @@ func addResourceFromString(contents string, resources *ResourceProvider) error {
}
return nil
}

func getDeployments(kube kubernetes.Interface) ([]appsv1.Deployment, error) {
listOpts := metav1.ListOptions{}
deployList, err := kube.AppsV1().Deployments("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching Deployments: %v", err)
return nil, err
}
deploys := deployList.Items

oldDeploys := make([]interface{}, 0)
deploysV1B1, err := kube.AppsV1beta1().Deployments("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching Deployments v1beta1: %v", err)
return nil, err
}
for _, oldDeploy := range deploysV1B1.Items {
oldDeploys = append(oldDeploys, oldDeploy)
}
deploysV1B2, err := kube.AppsV1beta2().Deployments("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching Deployments v1beta2: %v", err)
return nil, err
}
for _, oldDeploy := range deploysV1B2.Items {
oldDeploys = append(oldDeploys, oldDeploy)
}

for _, oldDeploy := range oldDeploys {
str, err := json.Marshal(oldDeploy)
if err != nil {
logrus.Errorf("Error marshaling old deployment version: %v", err)
return nil, err
}
deploy := appsv1.Deployment{}
err = json.Unmarshal(str, &deploy)
if err != nil {
logrus.Errorf("Error unmarshaling old deployment version: %v", err)
return nil, err
}
deploys = append(deploys, deploy)
}
return deploys, nil
}

func getStatefulSets(kube kubernetes.Interface) ([]appsv1.StatefulSet, error) {
listOpts := metav1.ListOptions{}
controllerList, err := kube.AppsV1().StatefulSets("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching StatefulSets: %v", err)
return nil, err
}
controllers := controllerList.Items

oldControllers := make([]interface{}, 0)
controllersV1B1, err := kube.AppsV1beta1().StatefulSets("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching StatefulSets v1beta1: %v", err)
return nil, err
}
for _, oldController := range controllersV1B1.Items {
oldControllers = append(oldControllers, oldController)
}
controllersV1B2, err := kube.AppsV1beta2().StatefulSets("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching StatefulSets v1beta2: %v", err)
return nil, err
}
for _, oldController := range controllersV1B2.Items {
oldControllers = append(oldControllers, oldController)
}

for _, oldController := range oldControllers {
str, err := json.Marshal(oldController)
if err != nil {
logrus.Errorf("Error marshaling old StatefulSet version: %v", err)
return nil, err
}
controller := appsv1.StatefulSet{}
err = json.Unmarshal(str, &controller)
if err != nil {
logrus.Errorf("Error unmarshaling old StatefulSet version: %v", err)
return nil, err
}
controllers = append(controllers, controller)
}
return controllers, nil
}

func getDaemonSets(kube kubernetes.Interface) ([]appsv1.DaemonSet, error) {
listOpts := metav1.ListOptions{}
controllerList, err := kube.AppsV1().DaemonSets("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching DaemonSets: %v", err)
return nil, err
}
controllers := controllerList.Items

controllersV1B2, err := kube.AppsV1beta2().DaemonSets("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching DaemonSets v1beta2: %v", err)
return nil, err
}

for _, oldController := range controllersV1B2.Items {
str, err := json.Marshal(oldController)
if err != nil {
logrus.Errorf("Error marshaling old DaemonSet version: %v", err)
return nil, err
}
controller := appsv1.DaemonSet{}
err = json.Unmarshal(str, &controller)
if err != nil {
logrus.Errorf("Error unmarshaling old DaemonSet version: %v", err)
return nil, err
}
controllers = append(controllers, controller)
}
return controllers, nil
}

func getCronJobs(kube kubernetes.Interface) ([]batchv1beta1.CronJob, error) {
listOpts := metav1.ListOptions{}
controllerList, err := kube.BatchV1beta1().CronJobs("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching CronJobs: %v", err)
return nil, err
}
controllers := controllerList.Items

controllersV2A1, err := kube.BatchV2alpha1().CronJobs("").List(listOpts)
if err != nil {
logrus.Errorf("Error fetching CronJobs v2alpha1: %v", err)
return nil, err
}

for _, oldController := range controllersV2A1.Items {
str, err := json.Marshal(oldController)
if err != nil {
logrus.Errorf("Error marshaling old CronJob version: %v", err)
return nil, err
}
controller := batchv1beta1.CronJob{}
err = json.Unmarshal(str, &controller)
if err != nil {
logrus.Errorf("Error unmarshaling old CronJob version: %v", err)
return nil, err
}
controllers = append(controllers, controller)
}
return controllers, nil
}
6 changes: 2 additions & 4 deletions pkg/webhook/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"context"
"fmt"
"net/http"
"os"

"github.com/fairwindsops/polaris/pkg/config"
validator "github.com/fairwindsops/polaris/pkg/validator"
Expand Down Expand Up @@ -80,10 +79,9 @@ func NewWebhook(name string, mgr manager.Manager, validator Validator, apiType r
Build()
if err != nil {
logrus.Errorf("Error building webhook: %v", err)
os.Exit(1)
} else {
logrus.Info(name + " webhook started")
return nil
}
logrus.Info(name + " webhook started")
return webhook
}

Expand Down
48 changes: 48 additions & 0 deletions test/webhook_cases/failing_test.daemonset.v1beta2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
apiVersion: apps/v1beta2
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect:
containers:
- name: fluentd-elasticsearch
image: gcr.io/fluentd-elasticsearch/fluentd:v2.5.1
resources:
requests:
cpu: 100m
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
securityContext:
allowPrivilegeEscalation: true
privileged: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers

Loading