Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions api/v1alpha1/resourcemanager_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,29 @@ type ResourceManagerSpec struct {
// TODO: add validation + enum
Action string `json:"action"`

Condition []ExpiryCondition `json:"condition"`
Condition []Condition `json:"condition"`
}

type Condition struct {
ExpiryCondition `json:",inline,omitempty"`
TimeframeCondition `json:",inline,omitempty"`
BaseCondition `json:",inline"`
}

type BaseCondition struct {
Type string `json:"type"`
}

type ExpiryCondition struct {
Condition `json:",inline"`
After string `json:"after"`
BaseCondition `json:",inline"`
After string `json:"after,omitempty"`
}

// type IntervalCondition struct {
// Condition
// }
type TimeframeCondition struct {
BaseCondition `json:",inline"`
Timeframe string `json:"time, omitempty"`
//Timezone string `json:"timeZone"`
}

// ResourceManagerStatus defines the observed state of ResourceManager
type ResourceManagerStatus struct {
Expand Down
38 changes: 36 additions & 2 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ spec:
properties:
after:
type: string
time:
type: string
type:
type: string
required:
- after
- type
type: object
type: array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,3 @@ spec:
condition:
- type: expiry
after: "1m"
# OR
# - type: time
# interval: daily
# time: "20:59:59"
#status:
17 changes: 17 additions & 0 deletions config/samples/resource-managmr-timeframe.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: resource-management.tikalk.com/v1alpha1
kind: ResourceManager
metadata:
name: resource-manager-sample
spec:
active: true
dry-run: false
resources: "namespace"
selector:
matchLabels:
name: managed-namespace1
action: "delete"
condition:
- type: timeframe
time: "12:20"
# timeZone: "Asia/Jerusalem"

92 changes: 64 additions & 28 deletions controllers/handlers/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,51 @@ package handlers

import (
"fmt"
utils "github.com/tikalk/resource-manager/controllers/utils"
"time"

"github.com/tikalk/resource-manager/controllers/utils"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// keep everything in a struct

// HandleNamespaceObj handle namespace objects that related to the resource-manager controller
func (o Obj) HandleNamespaceObj() {
// get all the namespaces with the desired selector labels
namespaces, err := GetNamespacesByLabel(o)
namespacesToHandle, err := o.GetNamespacesByLabel()
if err != nil {
o.L.Error(err, fmt.Sprintf("%s: cannot list namespaces\n", o.Name))
o.l.Error(err, fmt.Sprintf("%s: cannot list namespaces\n", o.Name))
return
}

if len(namespaces) <= 0 {
fmt.Printf("%s: did not found any namespaces with the requested label\n", o.Name)
if len(namespacesToHandle) <= 0 {
fmt.Printf("%s: did not found any namespace with the requested label\n", o.Name)
time.Sleep(10 * time.Second)
return
}

fmt.Printf("found %d namespaces with the requested label\n", len(namespaces))

for _, namespace := range namespaces {
expired, secondsUntilExpire := utils.IsObjExpired(namespace.CreationTimestamp, o.Spec.Condition[0].After)
if expired {
switch o.Spec.Action {
case "delete":
fmt.Printf("namespace '%s' has been expired and will be deleted \n", namespace.Name)
err := o.C.Delete(o.Ctx, namespace.DeepCopy(), &client.DeleteOptions{})
if err != nil {
o.L.Error(err, fmt.Sprintf("cannot delete namespaces\n"))
}
fmt.Printf("%s: namespace '%s' has been deleted \n", o.Name, namespace.Name)
}
} else {
fmt.Printf("%s: %d seconds has left to namespace '%s' \n", o.Name, secondsUntilExpire, namespace.Name)

for _, ns := range namespacesToHandle {
switch o.rm.Spec.Condition[0].Type {
case "expiry":
o.handleExpiry(ns)
case "timeframe":
o.handleTimeframe(ns)
}

}
time.Sleep(10 * time.Second)
}

// GetNamespacesByLabel get only namespaces that contains a specific label
func GetNamespacesByLabel(o Obj) ([]v1.Namespace, error) {
func (o Obj) GetNamespacesByLabel() ([]v1.Namespace, error) {

var listOfNamespaces []v1.Namespace
nsListObj := &v1.NamespaceList{}

if err := o.C.List(o.Ctx, nsListObj, &client.ListOptions{
LabelSelector: labels.SelectorFromSet(o.Spec.Selector.MatchLabels),
if err := o.c.List(o.ctx, nsListObj, &client.ListOptions{
LabelSelector: labels.SelectorFromSet(o.rm.Spec.Selector.MatchLabels),
}); err != nil {
o.L.Error(err, fmt.Sprintf("%s: unable to fetch namespaces", o.Name))
o.l.Error(err, fmt.Sprintf("%s: unable to fetch namespaces", o.Name))
return nil, err
}

Expand All @@ -62,3 +55,46 @@ func GetNamespacesByLabel(o Obj) ([]v1.Namespace, error) {
}
return listOfNamespaces, nil
}

// deleteNamespace delete namespace obj
func (o Obj) deleteNamespace(namespace v1.Namespace) {
err := o.c.Delete(o.ctx, namespace.DeepCopy(), &client.DeleteOptions{})
if err != nil {
o.l.Error(err, fmt.Sprintf("cannot delete namespaces\n"))
}
time.Sleep(5 * time.Second)
fmt.Printf("%s: namespace '%s' has been deleted \n", o.Name, namespace.Name)

}

// handleTimeframe handle timeframe type
func (o Obj) handleTimeframe(namespace v1.Namespace) {
fmt.Printf("namespace '%s' will be deleted at timeframe: %s \n", namespace.Name, o.rm.Spec.Condition[0].Timeframe)
err, doesIntervalOccurred := utils.IsIntervalOccurred(o.rm.Spec.Condition[0].Timeframe)
if err != nil {
o.l.Error(err, fmt.Sprintf("cannot calculate timeframe\n"))
return
}
if doesIntervalOccurred {
switch o.rm.Spec.Action {
case "delete":
fmt.Printf("namespace '%s' is in timeframe and will be deleted \n", namespace.Name)
o.deleteNamespace(namespace)
}
}
}

// handleExpiry handle expiry type
func (o Obj) handleExpiry(namespace v1.Namespace) {
expired, secondsUntilExpire := utils.IsObjExpired(namespace.CreationTimestamp, o.rm.Spec.Condition[0].After)
if expired {
switch o.rm.Spec.Action {
case "delete":
fmt.Printf("namespace '%s' has been expired and will be deleted \n", namespace.Name)
o.deleteNamespace(namespace)
fmt.Printf("%s: namespace '%s' has been deleted \n", o.Name, namespace.Name)
}
} else {
fmt.Printf("%s: %d seconds has left to namespace '%s' \n", o.Name, secondsUntilExpire, namespace.Name)
}
}
51 changes: 47 additions & 4 deletions controllers/handlers/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package handlers

import (
"context"
"fmt"

"github.com/go-logr/logr"
resourcemanagmentv1alpha1 "github.com/tikalk/resource-manager/api/v1alpha1"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -12,8 +14,49 @@ import (

type Obj struct {
Name types.NamespacedName
C client.Client
Ctx context.Context
L logr.Logger
Spec resourcemanagmentv1alpha1.ResourceManagerSpec
c client.Client
ctx context.Context
l logr.Logger
rm resourcemanagmentv1alpha1.ResourceManager

stop chan bool
}

func InitObj(rm resourcemanagmentv1alpha1.ResourceManager, c client.Client, ctx context.Context, l logr.Logger) Obj {
stop := make(chan bool)

name := types.NamespacedName{
Name: rm.Name,
Namespace: rm.Namespace,
}

o := Obj{
rm: rm,
Name: name,
c: c,
ctx: ctx,
l: l,
stop: stop,
}
return o
}

func (o Obj) Stop() {
o.stop <- true
}

func (o Obj) Run() {
fmt.Printf("Processing object: %s \n", o.Name)
for {
select {
case <-o.stop:
o.l.Info(fmt.Sprintf("%s Got stop signal!\n", o.Name))
return
default:
switch o.rm.Spec.Resources { // here we decide which handler to use
case "namespace":
o.HandleNamespaceObj()
}
}
}
}
Loading