2020-01-07 10:33:28 -08:00
|
|
|
package generate
|
|
|
|
|
|
|
|
import (
|
2020-02-04 12:13:41 -08:00
|
|
|
"encoding/json"
|
2020-01-07 10:33:28 -08:00
|
|
|
"fmt"
|
2020-03-04 13:11:48 +05:30
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/nirmata/kyverno/pkg/policyStatus"
|
2020-01-07 10:33:28 -08:00
|
|
|
|
|
|
|
"github.com/golang/glog"
|
|
|
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
|
|
|
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
|
|
|
"github.com/nirmata/kyverno/pkg/engine"
|
|
|
|
"github.com/nirmata/kyverno/pkg/engine/context"
|
|
|
|
"github.com/nirmata/kyverno/pkg/engine/validate"
|
|
|
|
"github.com/nirmata/kyverno/pkg/engine/variables"
|
2020-01-09 17:53:27 -08:00
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
2020-01-07 10:33:28 -08:00
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
|
2020-01-07 15:13:57 -08:00
|
|
|
var err error
|
|
|
|
var resource *unstructured.Unstructured
|
|
|
|
var genResources []kyverno.ResourceSpec
|
2020-01-07 10:33:28 -08:00
|
|
|
// 1 - Check if the resource exists
|
2020-01-07 15:13:57 -08:00
|
|
|
resource, err = getResource(c.client, gr.Spec.Resource)
|
2020-01-07 10:33:28 -08:00
|
|
|
if err != nil {
|
|
|
|
// Dont update status
|
|
|
|
glog.V(4).Infof("resource does not exist or is yet to be created, requeuing: %v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// 2 - Apply the generate policy on the resource
|
2020-01-07 15:13:57 -08:00
|
|
|
genResources, err = c.applyGenerate(*resource, *gr)
|
2020-01-07 10:33:28 -08:00
|
|
|
// 3 - Report Events
|
|
|
|
reportEvents(err, c.eventGen, *gr, *resource)
|
|
|
|
// 4 - Update Status
|
2020-01-07 15:13:57 -08:00
|
|
|
return updateStatus(c.statusControl, *gr, err, genResources)
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-01-07 15:13:57 -08:00
|
|
|
func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
|
2020-01-07 10:33:28 -08:00
|
|
|
// Get the list of rules to be applied
|
|
|
|
// get policy
|
|
|
|
policy, err := c.pLister.Get(gr.Spec.Policy)
|
|
|
|
if err != nil {
|
|
|
|
glog.V(4).Infof("policy %s not found: %v", gr.Spec.Policy, err)
|
2020-01-07 15:13:57 -08:00
|
|
|
return nil, nil
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
// build context
|
|
|
|
ctx := context.NewContext()
|
|
|
|
resourceRaw, err := resource.MarshalJSON()
|
|
|
|
if err != nil {
|
|
|
|
glog.V(4).Infof("failed to marshal resource: %v", err)
|
2020-01-07 15:13:57 -08:00
|
|
|
return nil, err
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-01-24 09:37:12 -08:00
|
|
|
err = ctx.AddResource(resourceRaw)
|
|
|
|
if err != nil {
|
|
|
|
glog.Infof("Failed to load resource in context: %v", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo)
|
|
|
|
if err != nil {
|
|
|
|
glog.Infof("Failed to load userInfo in context: %v", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
|
|
|
|
if err != nil {
|
|
|
|
glog.Infof("Failed to load serviceAccount in context: %v", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-01-07 10:33:28 -08:00
|
|
|
|
|
|
|
policyContext := engine.PolicyContext{
|
|
|
|
NewResource: resource,
|
|
|
|
Policy: *policy,
|
|
|
|
Context: ctx,
|
|
|
|
AdmissionInfo: gr.Spec.Context.UserRequestInfo,
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if the policy still applies to the resource
|
2020-01-24 12:05:53 -08:00
|
|
|
engineResponse := engine.Generate(policyContext)
|
2020-01-07 10:33:28 -08:00
|
|
|
if len(engineResponse.PolicyResponse.Rules) == 0 {
|
|
|
|
glog.V(4).Infof("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
|
2020-01-07 15:13:57 -08:00
|
|
|
return nil, fmt.Errorf("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-01-07 15:13:57 -08:00
|
|
|
|
2020-01-07 10:33:28 -08:00
|
|
|
// Apply the generate rule on resource
|
2020-03-04 13:11:48 +05:30
|
|
|
return c.applyGeneratePolicy(policyContext, gr)
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-01-07 15:13:57 -08:00
|
|
|
func updateStatus(statusControl StatusControlInterface, gr kyverno.GenerateRequest, err error, genResources []kyverno.ResourceSpec) error {
|
2020-01-07 10:33:28 -08:00
|
|
|
if err != nil {
|
2020-01-07 15:13:57 -08:00
|
|
|
return statusControl.Failed(gr, err.Error(), genResources)
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generate request successfully processed
|
2020-01-07 15:13:57 -08:00
|
|
|
return statusControl.Success(gr, genResources)
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-03-04 13:11:48 +05:30
|
|
|
func (c *Controller) applyGeneratePolicy(policyContext engine.PolicyContext, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
|
2020-01-07 15:13:57 -08:00
|
|
|
// List of generatedResources
|
|
|
|
var genResources []kyverno.ResourceSpec
|
2020-01-07 10:33:28 -08:00
|
|
|
// Get the response as the actions to be performed on the resource
|
|
|
|
// - - substitute values
|
|
|
|
policy := policyContext.Policy
|
|
|
|
resource := policyContext.NewResource
|
|
|
|
ctx := policyContext.Context
|
|
|
|
// To manage existing resources, we compare the creation time for the default resiruce to be generated and policy creation time
|
|
|
|
processExisting := func() bool {
|
|
|
|
rcreationTime := resource.GetCreationTimestamp()
|
|
|
|
pcreationTime := policy.GetCreationTimestamp()
|
|
|
|
return rcreationTime.Before(&pcreationTime)
|
|
|
|
}()
|
|
|
|
|
2020-03-04 13:11:48 +05:30
|
|
|
ruleNameToProcessingTime := make(map[string]time.Duration)
|
2020-01-07 10:33:28 -08:00
|
|
|
for _, rule := range policy.Spec.Rules {
|
|
|
|
if !rule.HasGenerate() {
|
|
|
|
continue
|
|
|
|
}
|
2020-03-04 13:11:48 +05:30
|
|
|
|
|
|
|
startTime := time.Now()
|
|
|
|
genResource, err := applyRule(c.client, rule, resource, ctx, processExisting)
|
2020-01-07 15:13:57 -08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-03-04 13:11:48 +05:30
|
|
|
|
|
|
|
ruleNameToProcessingTime[rule.Name] = time.Since(startTime)
|
2020-01-07 15:13:57 -08:00
|
|
|
genResources = append(genResources, genResource)
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-03-04 13:11:48 +05:30
|
|
|
if gr.Status.State == "" {
|
2020-03-04 13:35:49 +05:30
|
|
|
c.policyStatus.Listener <- &generateSyncStats{
|
|
|
|
policyName: policy.Name,
|
|
|
|
ruleNameToProcessingTime: ruleNameToProcessingTime,
|
|
|
|
}
|
2020-03-04 13:11:48 +05:30
|
|
|
}
|
|
|
|
|
2020-01-07 15:13:57 -08:00
|
|
|
return genResources, nil
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-03-04 13:11:48 +05:30
|
|
|
type generateSyncStats struct {
|
|
|
|
policyName string
|
|
|
|
ruleNameToProcessingTime map[string]time.Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
func (vc *generateSyncStats) UpdateStatus(s *policyStatus.Sync) {
|
|
|
|
s.Cache.Mutex.Lock()
|
|
|
|
status, exist := s.Cache.Data[vc.policyName]
|
|
|
|
if !exist {
|
|
|
|
policy, _ := s.PolicyStore.Get(vc.policyName)
|
|
|
|
if policy != nil {
|
|
|
|
status = policy.Status
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range status.Rules {
|
|
|
|
if executionTime, exist := vc.ruleNameToProcessingTime[status.Rules[i].Name]; exist {
|
|
|
|
status.ResourcesGeneratedCount += 1
|
|
|
|
status.Rules[i].ResourcesGeneratedCount += 1
|
|
|
|
averageOver := int64(status.Rules[i].AppliedCount + status.Rules[i].FailedCount)
|
|
|
|
status.Rules[i].ExecutionTime = updateGenerateExecutionTime(
|
|
|
|
executionTime,
|
|
|
|
status.Rules[i].ExecutionTime,
|
|
|
|
averageOver,
|
|
|
|
).String()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s.Cache.Data[vc.policyName] = status
|
|
|
|
s.Cache.Mutex.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateGenerateExecutionTime(newTime time.Duration, oldAverageTimeString string, averageOver int64) time.Duration {
|
|
|
|
if averageOver == 0 {
|
|
|
|
return newTime
|
|
|
|
}
|
|
|
|
oldAverageExecutionTime, _ := time.ParseDuration(oldAverageTimeString)
|
|
|
|
numerator := (oldAverageExecutionTime.Nanoseconds() * averageOver) + newTime.Nanoseconds()
|
|
|
|
denominator := averageOver
|
|
|
|
newAverageTimeInNanoSeconds := numerator / denominator
|
|
|
|
return time.Duration(newAverageTimeInNanoSeconds) * time.Nanosecond
|
|
|
|
}
|
|
|
|
|
2020-02-04 12:13:41 -08:00
|
|
|
func applyRule(client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, processExisting bool) (kyverno.ResourceSpec, error) {
|
2020-01-07 10:33:28 -08:00
|
|
|
var rdata map[string]interface{}
|
|
|
|
var err error
|
2020-02-04 12:13:41 -08:00
|
|
|
var mode ResourceMode
|
2020-01-07 15:13:57 -08:00
|
|
|
var noGenResource kyverno.ResourceSpec
|
2020-02-13 13:57:48 -08:00
|
|
|
// convert to unstructured Resource
|
|
|
|
genUnst, err := getUnstrRule(rule.Generation.DeepCopy())
|
|
|
|
if err != nil {
|
|
|
|
return noGenResource, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Variable substitutions
|
|
|
|
// format : {{<variable_name}}
|
|
|
|
// - if there is variables that are not defined the context -> results in error and rule is not applied
|
|
|
|
// - valid variables are replaced with the values
|
2020-02-14 11:59:28 -08:00
|
|
|
if _, err := variables.SubstituteVars(ctx, genUnst.Object); err != nil {
|
2020-02-13 13:57:48 -08:00
|
|
|
return noGenResource, err
|
|
|
|
}
|
|
|
|
genKind, _, err := unstructured.NestedString(genUnst.Object, "kind")
|
|
|
|
if err != nil {
|
|
|
|
return noGenResource, err
|
|
|
|
}
|
|
|
|
genName, _, err := unstructured.NestedString(genUnst.Object, "name")
|
|
|
|
if err != nil {
|
|
|
|
return noGenResource, err
|
|
|
|
}
|
|
|
|
genNamespace, _, err := unstructured.NestedString(genUnst.Object, "namespace")
|
|
|
|
if err != nil {
|
|
|
|
return noGenResource, err
|
2020-01-10 11:59:05 -08:00
|
|
|
}
|
|
|
|
|
2020-01-07 15:13:57 -08:00
|
|
|
// Resource to be generated
|
|
|
|
newGenResource := kyverno.ResourceSpec{
|
2020-02-13 13:57:48 -08:00
|
|
|
Kind: genKind,
|
|
|
|
Namespace: genNamespace,
|
|
|
|
Name: genName,
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-02-13 13:57:48 -08:00
|
|
|
genData, _, err := unstructured.NestedMap(genUnst.Object, "data")
|
|
|
|
if err != nil {
|
|
|
|
return noGenResource, err
|
|
|
|
}
|
|
|
|
genCopy, _, err := unstructured.NestedMap(genUnst.Object, "clone")
|
|
|
|
if err != nil {
|
|
|
|
return noGenResource, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if genData != nil {
|
|
|
|
rdata, mode, err = manageData(genKind, genNamespace, genName, genData, client, resource)
|
|
|
|
} else {
|
|
|
|
rdata, mode, err = manageClone(genKind, genNamespace, genName, genCopy, client, resource)
|
|
|
|
}
|
2020-02-14 11:59:28 -08:00
|
|
|
if err != nil {
|
|
|
|
return noGenResource, err
|
|
|
|
}
|
|
|
|
|
2020-02-13 13:57:48 -08:00
|
|
|
if rdata == nil {
|
|
|
|
// existing resource contains the configuration
|
|
|
|
return newGenResource, nil
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
if processExisting {
|
|
|
|
// handle existing resources
|
|
|
|
// policy was generated after the resource
|
|
|
|
// we do not create new resource
|
2020-01-07 15:13:57 -08:00
|
|
|
return noGenResource, err
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-02-04 12:13:41 -08:00
|
|
|
|
|
|
|
// build the resource template
|
2020-01-07 10:33:28 -08:00
|
|
|
newResource := &unstructured.Unstructured{}
|
|
|
|
newResource.SetUnstructuredContent(rdata)
|
2020-02-13 13:57:48 -08:00
|
|
|
newResource.SetName(genName)
|
|
|
|
newResource.SetNamespace(genNamespace)
|
2020-01-07 10:33:28 -08:00
|
|
|
|
2020-02-10 12:44:20 -08:00
|
|
|
// manage labels
|
|
|
|
// - app.kubernetes.io/managed-by: kyverno
|
|
|
|
// - kyverno.io/generated-by: kind/namespace/name (trigger resource)
|
|
|
|
manageLabels(newResource, resource)
|
|
|
|
|
2020-02-04 12:13:41 -08:00
|
|
|
if mode == Create {
|
|
|
|
// Reset resource version
|
|
|
|
newResource.SetResourceVersion("")
|
|
|
|
// Create the resource
|
2020-02-13 13:57:48 -08:00
|
|
|
glog.V(4).Infof("Creating new resource %s/%s/%s", genKind, genNamespace, genName)
|
|
|
|
_, err = client.CreateResource(genKind, genNamespace, newResource, false)
|
2020-02-04 12:13:41 -08:00
|
|
|
if err != nil {
|
|
|
|
// Failed to create resource
|
|
|
|
return noGenResource, err
|
|
|
|
}
|
2020-02-13 13:57:48 -08:00
|
|
|
glog.V(4).Infof("Created new resource %s/%s/%s", genKind, genNamespace, genName)
|
2020-02-04 12:13:41 -08:00
|
|
|
|
|
|
|
} else if mode == Update {
|
2020-02-13 13:57:48 -08:00
|
|
|
glog.V(4).Infof("Updating existing resource %s/%s/%s", genKind, genNamespace, genName)
|
2020-02-04 12:13:41 -08:00
|
|
|
// Update the resource
|
2020-02-13 13:57:48 -08:00
|
|
|
_, err := client.UpdateResource(genKind, genNamespace, newResource, false)
|
2020-02-04 12:13:41 -08:00
|
|
|
if err != nil {
|
|
|
|
// Failed to update resource
|
|
|
|
return noGenResource, err
|
|
|
|
}
|
2020-02-13 13:57:48 -08:00
|
|
|
glog.V(4).Infof("Updated existing resource %s/%s/%s", genKind, genNamespace, genName)
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-02-04 12:13:41 -08:00
|
|
|
|
2020-01-07 15:13:57 -08:00
|
|
|
return newGenResource, nil
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-02-13 13:57:48 -08:00
|
|
|
func manageData(kind, namespace, name string, data map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
|
|
|
|
// check if resource to be generated exists
|
|
|
|
obj, err := client.GetResource(kind, namespace, name)
|
2020-01-09 17:53:27 -08:00
|
|
|
if apierrors.IsNotFound(err) {
|
2020-02-13 13:57:48 -08:00
|
|
|
glog.V(4).Infof("Resource %s/%s/%s does not exists, will try to create", kind, namespace, name)
|
|
|
|
return data, Create, nil
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
//something wrong while fetching resource
|
2020-02-13 13:57:48 -08:00
|
|
|
// client-errors
|
2020-02-04 12:13:41 -08:00
|
|
|
return nil, Skip, err
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
// Resource exists; verfiy the content of the resource
|
2020-02-13 13:57:48 -08:00
|
|
|
err = checkResource(data, obj)
|
|
|
|
if err == nil {
|
|
|
|
// Existing resource does contain the mentioned configuration in spec, skip processing the resource as it is already in expected state
|
|
|
|
return nil, Skip, nil
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-02-04 12:13:41 -08:00
|
|
|
|
2020-02-13 13:57:48 -08:00
|
|
|
glog.V(4).Infof("Resource %s/%s/%s exists but missing required configuration, will try to update", kind, namespace, name)
|
|
|
|
return data, Update, nil
|
2020-02-04 12:13:41 -08:00
|
|
|
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-02-13 13:57:48 -08:00
|
|
|
func manageClone(kind, namespace, name string, clone map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
|
2020-02-04 12:13:41 -08:00
|
|
|
// check if resource to be generated exists
|
2020-02-13 13:57:48 -08:00
|
|
|
_, err := client.GetResource(kind, namespace, name)
|
2020-01-07 10:33:28 -08:00
|
|
|
if err == nil {
|
2020-02-04 12:13:41 -08:00
|
|
|
// resource does exists, not need to process further as it is already in expected state
|
|
|
|
return nil, Skip, nil
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-02-13 13:57:48 -08:00
|
|
|
//TODO: check this
|
2020-01-09 17:53:27 -08:00
|
|
|
if !apierrors.IsNotFound(err) {
|
2020-01-07 10:33:28 -08:00
|
|
|
//something wrong while fetching resource
|
2020-02-04 12:13:41 -08:00
|
|
|
return nil, Skip, err
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-02-13 13:57:48 -08:00
|
|
|
newRNs, _, err := unstructured.NestedString(clone, "namespace")
|
|
|
|
if err != nil {
|
|
|
|
return nil, Skip, err
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-02-13 13:57:48 -08:00
|
|
|
newRName, _, err := unstructured.NestedString(clone, "name")
|
|
|
|
if err != nil {
|
|
|
|
return nil, Skip, err
|
|
|
|
}
|
|
|
|
// Short-circuit if the resource to be generated and the clone is the same
|
|
|
|
if newRNs == namespace && newRName == name {
|
|
|
|
// attempting to clone it self, this will fail -> short-ciruit it
|
|
|
|
return nil, Skip, nil
|
|
|
|
}
|
|
|
|
|
2020-02-14 11:59:28 -08:00
|
|
|
glog.V(4).Infof("check if resource %s/%s/%s exists", kind, newRNs, newRName)
|
2020-02-13 13:57:48 -08:00
|
|
|
// check if the resource as reference in clone exists?
|
|
|
|
obj, err := client.GetResource(kind, newRNs, newRName)
|
2020-01-07 10:33:28 -08:00
|
|
|
if err != nil {
|
2020-02-14 11:59:28 -08:00
|
|
|
return nil, Skip, fmt.Errorf("reference clone resource %s/%s/%s not found. %v", kind, newRNs, newRName, err)
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-02-04 12:13:41 -08:00
|
|
|
// create the resource based on the reference clone
|
|
|
|
return obj.UnstructuredContent(), Create, nil
|
2020-02-13 13:57:48 -08:00
|
|
|
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-02-13 13:57:48 -08:00
|
|
|
// ResourceMode defines the mode for generated resource
|
|
|
|
type ResourceMode string
|
|
|
|
|
|
|
|
const (
|
|
|
|
//Skip : failed to process rule, will not update the resource
|
|
|
|
Skip ResourceMode = "SKIP"
|
|
|
|
//Create : create a new resource
|
|
|
|
Create = "CREATE"
|
|
|
|
//Update : update/overwrite the new resource
|
|
|
|
Update = "UPDATE"
|
|
|
|
)
|
|
|
|
|
|
|
|
func checkResource(newResourceSpec interface{}, resource *unstructured.Unstructured) error {
|
2020-01-07 10:33:28 -08:00
|
|
|
// check if the resource spec if a subset of the resource
|
2020-02-14 12:05:13 -08:00
|
|
|
if path, err := validate.ValidateResourceWithPattern(resource.Object, newResourceSpec); err != nil {
|
2020-02-14 11:59:28 -08:00
|
|
|
glog.V(4).Infof("Failed to match the resource at path %s: err %v", path, err)
|
2020-02-13 13:57:48 -08:00
|
|
|
return err
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-02-13 13:57:48 -08:00
|
|
|
return nil
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
|
|
|
|
2020-02-13 13:57:48 -08:00
|
|
|
func getUnstrRule(rule *kyverno.Generation) (*unstructured.Unstructured, error) {
|
|
|
|
ruleData, err := json.Marshal(rule)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return ConvertToUnstructured(ruleData)
|
|
|
|
}
|
2020-01-07 10:33:28 -08:00
|
|
|
|
2020-02-13 13:57:48 -08:00
|
|
|
//ConvertToUnstructured converts the resource to unstructured format
|
|
|
|
func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
|
|
|
|
resource := &unstructured.Unstructured{}
|
|
|
|
err := resource.UnmarshalJSON(data)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|
2020-02-13 13:57:48 -08:00
|
|
|
return resource, nil
|
2020-01-07 10:33:28 -08:00
|
|
|
}
|