feat: initial commit
This commit is contained in:
+148
@@ -0,0 +1,148 @@
|
||||
package kube
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/apex/log"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
appsv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
|
||||
batchv1 "k8s.io/client-go/kubernetes/typed/batch/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
provider ClientProvider
|
||||
}
|
||||
|
||||
type Options func(*Client)
|
||||
|
||||
func WithInClusterProvider() func(c *Client) {
|
||||
return func(c *Client) {
|
||||
c.provider = &DefaultProvider{provider: &InClusterProvider{}}
|
||||
}
|
||||
}
|
||||
|
||||
func WithKubeConfigProvider(kubeconfig string) func(c *Client) {
|
||||
return func(c *Client) {
|
||||
c.provider = &DefaultProvider{provider: &PathConfigProvider{kubecfg: kubeconfig}}
|
||||
}
|
||||
}
|
||||
|
||||
func New(opts ...Options) *Client {
|
||||
c := &Client{}
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) GetImages(ctx context.Context, logger log.Interface, namespaces []string) (map[string][]string, error) {
|
||||
client, err := c.provider.Provide()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
collector := NewImageCollector()
|
||||
for _, ns := range namespaces {
|
||||
deployments, err := client.AppsV1().Deployments(ns).List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, deployment := range deployments.Items {
|
||||
for _, container := range deployment.Spec.Template.Spec.Containers {
|
||||
if strings.HasPrefix(container.Image, "registry.gitlab.com") {
|
||||
logger.Infof("Found image '%s' in deployment %s.%s", container.Image[20:], ns, deployment.Name)
|
||||
collector.Add(container.Image)
|
||||
}
|
||||
}
|
||||
}
|
||||
cronjobs, err := client.BatchV1().CronJobs(ns).List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cronjob := range cronjobs.Items {
|
||||
for _, container := range cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers {
|
||||
if strings.HasPrefix(container.Image, "registry.gitlab.com") {
|
||||
logger.Infof("Found image '%s' in cronjob %s.%s", container.Image[20:], ns, cronjob.Name)
|
||||
collector.Add(container.Image)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return collector.Images(), nil
|
||||
}
|
||||
|
||||
type APIClient interface {
|
||||
AppsV1() appsv1.AppsV1Interface
|
||||
BatchV1() batchv1.BatchV1Interface
|
||||
}
|
||||
|
||||
type ClientProvider interface {
|
||||
Provide() (APIClient, error)
|
||||
}
|
||||
|
||||
type DefaultProvider struct {
|
||||
provider ConfigProvider
|
||||
}
|
||||
|
||||
func (d DefaultProvider) Provide() (APIClient, error) {
|
||||
config, err := d.provider.Provide()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kubernetes.NewForConfig(config)
|
||||
}
|
||||
|
||||
var _ ClientProvider = &DefaultProvider{}
|
||||
|
||||
type ConfigProvider interface {
|
||||
Provide() (*rest.Config, error)
|
||||
}
|
||||
|
||||
type InClusterProvider struct{}
|
||||
|
||||
func (i InClusterProvider) Provide() (*rest.Config, error) {
|
||||
return rest.InClusterConfig()
|
||||
}
|
||||
|
||||
var _ ConfigProvider = &InClusterProvider{}
|
||||
|
||||
type PathConfigProvider struct {
|
||||
kubecfg string
|
||||
}
|
||||
|
||||
func (k PathConfigProvider) Provide() (*rest.Config, error) {
|
||||
return clientcmd.BuildConfigFromFlags("", k.kubecfg)
|
||||
}
|
||||
|
||||
var _ ConfigProvider = &PathConfigProvider{}
|
||||
|
||||
type ImageCollector map[string]map[string]struct{}
|
||||
|
||||
func NewImageCollector() ImageCollector {
|
||||
return make(map[string]map[string]struct{})
|
||||
}
|
||||
|
||||
func (c *ImageCollector) Add(image string) {
|
||||
parts := strings.Split(image[20:], ":")
|
||||
if x, exists := (*c)[parts[0]]; exists {
|
||||
x[parts[1]] = struct{}{}
|
||||
} else {
|
||||
(*c)[parts[0]] = map[string]struct{}{
|
||||
parts[1]: {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ImageCollector) Images() map[string][]string {
|
||||
images := make(map[string][]string)
|
||||
for i, x := range *c {
|
||||
for v := range x {
|
||||
images[i] = append(images[i], v)
|
||||
}
|
||||
}
|
||||
return images
|
||||
}
|
||||
Reference in New Issue
Block a user