Skip to content

Commit

Permalink
Merge pull request #304 from gianlucam76/main
Browse files Browse the repository at this point in the history
Merge dev to main
  • Loading branch information
gianlucam76 authored May 17, 2024
2 parents 5f0f032 + 0ed657d commit fd98796
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 58 deletions.
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ go 1.22.0

require (
github.com/go-logr/logr v1.4.1
github.com/onsi/ginkgo/v2 v2.17.2
github.com/onsi/ginkgo/v2 v2.17.3
github.com/onsi/gomega v1.33.1
github.com/pkg/errors v0.9.1
golang.org/x/text v0.14.0
golang.org/x/text v0.15.0
k8s.io/api v0.30.0
k8s.io/apiextensions-apiserver v0.30.0
k8s.io/apimachinery v0.30.0
k8s.io/client-go v0.30.0
k8s.io/klog/v2 v2.120.1
k8s.io/kubectl v0.30.0
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0
sigs.k8s.io/cluster-api v1.7.1
sigs.k8s.io/controller-runtime v0.18.1
sigs.k8s.io/cluster-api v1.7.2
sigs.k8s.io/controller-runtime v0.18.2
)

require (
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g=
github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU=
github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down Expand Up @@ -142,8 +142,8 @@ golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down Expand Up @@ -190,10 +190,10 @@ k8s.io/kubectl v0.30.0 h1:xbPvzagbJ6RNYVMVuiHArC1grrV5vSmmIcSZuCdzRyk=
k8s.io/kubectl v0.30.0/go.mod h1:zgolRw2MQXLPwmic2l/+iHs239L49fhSeICuMhQQXTI=
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/cluster-api v1.7.1 h1:JkMAbAMzBM+WBHxXLTJXTiCisv1PAaHRzld/3qrmLYY=
sigs.k8s.io/cluster-api v1.7.1/go.mod h1:V9ZhKLvQtsDODwjXOKgbitjyCmC71yMBwDcMyNNIov0=
sigs.k8s.io/controller-runtime v0.18.1 h1:RpWbigmuiylbxOCLy0tGnq1cU1qWPwNIQzoJk+QeJx4=
sigs.k8s.io/controller-runtime v0.18.1/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw=
sigs.k8s.io/cluster-api v1.7.2 h1:bRE8zoao7ajuLC0HijqfZVcubKQCPlZ04HMgcA53FGE=
sigs.k8s.io/cluster-api v1.7.2/go.mod h1:V9ZhKLvQtsDODwjXOKgbitjyCmC71yMBwDcMyNNIov0=
sigs.k8s.io/controller-runtime v0.18.2 h1:RqVW6Kpeaji67CY5nPEfRz6ZfFMk0lWQlNrLqlNpx+Q=
sigs.k8s.io/controller-runtime v0.18.2/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
Expand Down
7 changes: 3 additions & 4 deletions hack/tools/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ go 1.22.0

require (
github.com/a8m/envsubst v1.4.2
github.com/onsi/ginkgo/v2 v2.17.2
golang.org/x/oauth2 v0.19.0
github.com/onsi/ginkgo/v2 v2.17.3
golang.org/x/oauth2 v0.20.0
k8s.io/client-go v0.30.0
sigs.k8s.io/controller-tools v0.15.0
)

require (
cloud.google.com/go/compute v1.20.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/compute/metadata v0.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
Expand Down
14 changes: 6 additions & 8 deletions hack/tools/go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg=
cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg=
github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
Expand Down Expand Up @@ -72,8 +70,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g=
github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU=
github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down Expand Up @@ -109,8 +107,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
144 changes: 118 additions & 26 deletions lib/deployer/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ package deployer
import (
"context"
"fmt"
"strings"

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand All @@ -29,54 +31,92 @@ import (

const (
// ReferenceLabelKind is added to each policy deployed by a ClusterSummary
// instance to a CAPI Cluster. Indicates the Kind (ConfigMap or Secret)
// instance to a managed Cluster. Indicates the Kind (ConfigMap or Secret)
// containing the policy.
ReferenceKindLabel = "projectsveltos.io/reference-kind"

// ReferenceNameLabel is added to each policy deployed by a ClusterSummary
// instance to a CAPI Cluster. Indicates the name of the ConfigMap/Secret
// instance to a managed Cluster. Indicates the name of the ConfigMap/Secret
// containing the policy.
ReferenceNameLabel = "projectsveltos.io/reference-name"

// ReferenceNamespaceLabel is added to each policy deployed by a ClusterSummary
// instance to a CAPI Cluster. Indicates the namespace of the ConfigMap/Secret
// instance to a managed Cluster. Indicates the namespace of the ConfigMap/Secret
// containing the policy.
ReferenceNamespaceLabel = "projectsveltos.io/reference-namespace"

// PolicyHash is the annotation set on a policy when deployed in a CAPI
// cluster.
PolicyHash = "projectsveltos.io/hash"

// OwnerTier is the annotation set on a policy when deployed in a managed
// cluster. Contains the tier of the profile instance that deployed it.
OwnerTier = "projectsveltos.io/owner-tier"
)

type ConflictError struct {
message string
}

func NewConflictError(msg string) *ConflictError {
return &ConflictError{message: msg}
}

func (e *ConflictError) Error() string {
return e.message
}

type ResourceInfo struct {
// indicates whethere resource currently exists (only
// existing resources have a Version set)
ResourceVersion string

// Resource's OwnerReferences
OwnerReferences []corev1.ObjectReference

// Current profile owner's tier
OwnerTier string

Hash string
}

// validateObjectForUpdate finds if object currently exists. If object exists:
// - verifies this object was created by same ConfigMap/Secret. Returns an error otherwise.
// - verifies this object was created by same referenced object (specified by
// referenceKind, referenceNamespace, referenceName);
// - verifies this object was deployed because of the same profile instance (specified
// by profile instance).
// Returns an error otherwise.
// This is needed to prevent misconfigurations. An example would be when different
// ConfigMaps are referenced by ClusterProfile(s) or RoleRequest(s) and contain same policy
// namespace/name (content might be different) and are about to be deployed in the same cluster;
// Return an error if validation fails. Return also whether the object currently exists or not.
// If object exists, return value of PolicyHash annotation.
func ValidateObjectForUpdate(ctx context.Context, dr dynamic.ResourceInterface,
object *unstructured.Unstructured,
referenceKind, referenceNamespace, referenceName string) (exist bool, hash string, err error) {
object *unstructured.Unstructured, referenceKind, referenceNamespace, referenceName string,
profile client.Object) (*ResourceInfo, error) {

if object == nil {
return false, "", nil
return nil, nil
}

resourceInfo := &ResourceInfo{}
currentObject, err := dr.Get(ctx, object.GetName(), metav1.GetOptions{})
if err != nil {
if apierrors.IsNotFound(err) {
return false, "", nil
resourceInfo.ResourceVersion = ""
return resourceInfo, nil
}
return nil, err
}

resourceInfo.OwnerReferences = getOwnerReferences(currentObject)
resourceInfo.ResourceVersion = currentObject.GetResourceVersion()

// If currently set, get the Tier of current owner
if annotations := currentObject.GetAnnotations(); annotations != nil {
if tierString, ok := annotations[OwnerTier]; ok {
resourceInfo.OwnerTier = tierString
}
return false, "", err
}

if labels := currentObject.GetLabels(); labels != nil {
Expand All @@ -86,33 +126,42 @@ func ValidateObjectForUpdate(ctx context.Context, dr dynamic.ResourceInterface,

if kindOk {
if kind != referenceKind {
return true, "", &ConflictError{
message: fmt.Sprintf("conflict: policy (kind: %s) %s is currently deployed by %s: %s/%s",
object.GetKind(), object.GetName(), kind, namespace, name)}
return resourceInfo, &ConflictError{
message: fmt.Sprintf("conflict: policy (kind: %s) %s/%s is currently deployed by %s: %s/%s.\n%s",
object.GetKind(), object.GetNamespace(), object.GetName(), kind, namespace, name,
addOwnerMessage(currentObject))}
}
}
if namespaceOk {
if namespace != referenceNamespace {
return true, "", &ConflictError{
message: fmt.Sprintf("conflict: policy (kind: %s) %s is currently deployed by %s: %s/%s",
object.GetKind(), object.GetName(), kind, namespace, name)}
return resourceInfo, &ConflictError{
message: fmt.Sprintf("conflict: policy (kind: %s) %s/%s is currently deployed by %s: %s/%s.\n%s",
object.GetKind(), object.GetNamespace(), object.GetName(), kind, namespace, name,
addOwnerMessage(currentObject))}
}
}
if nameOk {
if name != referenceName {
return true, "", &ConflictError{
message: fmt.Sprintf("conflict: policy (kind: %s) %s is currently deployed by %s: %s/%s",
object.GetKind(), object.GetName(), kind, namespace, name)}
return resourceInfo, &ConflictError{
message: fmt.Sprintf("conflict: policy (kind: %s) %s/%s is currently deployed by %s: %s/%s.\n%s",
object.GetKind(), object.GetNamespace(), object.GetName(), kind, namespace, name,
addOwnerMessage(currentObject))}
}
}
if hasSveltosResourcesAsOwnerReference(currentObject) && !IsOwnerReference(currentObject, profile) {
return resourceInfo, &ConflictError{
message: fmt.Sprintf("conflict: policy (kind: %s) %s/%s is currently deployed by %s: %s/%s.\n%s",
object.GetKind(), object.GetNamespace(), object.GetName(), kind, namespace, name,
addOwnerMessage(currentObject))}
}
}

// Only in case object exists and there are no conflicts, return hash
if annotations := currentObject.GetAnnotations(); annotations != nil {
hash = annotations[PolicyHash]
resourceInfo.Hash = annotations[PolicyHash]
}

return true, hash, nil
return resourceInfo, nil
}

// GetOwnerMessage returns a message listing why this object is deployed. The message lists:
Expand All @@ -136,17 +185,28 @@ func GetOwnerMessage(ctx context.Context, dr dynamic.ResourceInterface,
namespace := labels[ReferenceNamespaceLabel]
name := labels[ReferenceNameLabel]

message += fmt.Sprintf("Object currently deployed because of %s %s/%s.", kind, namespace, name)
message += fmt.Sprintf("Object %s:%s/%s currently deployed because of %s %s/%s.\n",
currentObject.GroupVersionKind().Kind, currentObject.GetNamespace(), currentObject.GetName(),
kind, namespace, name)
}

message += "List of Owners:"
ownerRefs := currentObject.GetOwnerReferences()
message += addOwnerMessage(currentObject)

return message, nil
}

func addOwnerMessage(u *unstructured.Unstructured) string {
message := " Sveltos instance currently deploying this resource: "
ownerRefs := u.GetOwnerReferences()
for i := range ownerRefs {
or := &ownerRefs[i]
message += fmt.Sprintf("%s %s;", or.Kind, or.Name)
// Only include Sveltos resources
if strings.Contains(or.APIVersion, "projectsveltos.io") {
message += fmt.Sprintf("%s %s;", or.Kind, or.Name)
}
}

return message, nil
message += "\n"
return message
}

// AddOwnerReference adds Sveltos resource owning a resource as an object's OwnerReference.
Expand Down Expand Up @@ -249,3 +309,35 @@ func IsOwnerReference(object, owner client.Object) bool {

return false
}

// hasSveltosResourcesAsOwnerReference returns true if at least one
// of current OwnerReferences is a Sveltos resource
func hasSveltosResourcesAsOwnerReference(object client.Object) bool {
onwerReferences := object.GetOwnerReferences()
if onwerReferences == nil {
return false
}

for i := range onwerReferences {
ref := &onwerReferences[i]
if strings.Contains(ref.APIVersion, "projectsveltos.io") {
return true
}
}

return false
}

func getOwnerReferences(currentObject client.Object) []corev1.ObjectReference {
references := currentObject.GetOwnerReferences()
result := make([]corev1.ObjectReference, len(references))
for i := range references {
result[i] = corev1.ObjectReference{
Kind: references[i].Kind,
APIVersion: references[i].APIVersion,
Name: references[i].Name,
}
}

return result
}
Loading

0 comments on commit fd98796

Please sign in to comment.