diff --git a/apiserver/cmd/apiserver/server/run_server.go b/apiserver/cmd/apiserver/server/run_server.go index f91a567f22b..ab0d5311cbf 100644 --- a/apiserver/cmd/apiserver/server/run_server.go +++ b/apiserver/cmd/apiserver/server/run_server.go @@ -90,6 +90,11 @@ func RunServer(opts *CalicoServerOptions, server *apiserver.ProjectCalicoServer) server.CalicoResourceLister.WaitForCacheSync(ctx.Done()) server.SharedInformerFactory.WaitForCacheSync(ctx.Done()) + err := migratePolicyNames() + if err != nil { + klog.Infof("Error updating tier names: %v", err) + } + if opts.PrintSwagger { if err := server.GenericAPIServer.AddPostStartHook("swagger-printer", func(context genericapiserver.PostStartHookContext) error { diff --git a/apiserver/cmd/apiserver/server/tier_upgrade.go b/apiserver/cmd/apiserver/server/tier_upgrade.go new file mode 100644 index 00000000000..b0a0ea06e94 --- /dev/null +++ b/apiserver/cmd/apiserver/server/tier_upgrade.go @@ -0,0 +1,56 @@ +package server + +import ( + "context" + "strings" + + "k8s.io/klog/v2" + + client "github.com/projectcalico/calico/libcalico-go/lib/clientv3" + "github.com/projectcalico/calico/libcalico-go/lib/options" +) + +func migratePolicyNames() error { + klog.Infof("Migrating policy names") + calicoClient, err := client.NewFromEnv() + if err != nil { + return err + } + + networkPolicies, err := calicoClient.NetworkPolicies().List(context.Background(), options.ListOptions{}) + if err != nil { + return err + } + for _, policy := range networkPolicies.Items { + policy.Name = updateName(policy.Name) + _, err = calicoClient.NetworkPolicies().Update(context.Background(), &policy, options.SetOptions{}) + if err != nil { + return err + } + } + + globalNetworkPolicies, err := calicoClient.GlobalNetworkPolicies().List(context.Background(), options.ListOptions{}) + if err != nil { + return err + } + for _, policy := range globalNetworkPolicies.Items { + policy.Name = updateName(policy.Name) + _, err = calicoClient.GlobalNetworkPolicies().Update(context.Background(), &policy, options.SetOptions{}) + if err != nil { + return err + } + } + + return nil +} + +func updateName(name string) string { + if strings.HasPrefix(name, "default.") { + name = strings.TrimPrefix(name, "default.") + } + return name +} + +func updateNeeded() bool { + return true +} diff --git a/apiserver/pkg/registry/projectcalico/networkpolicy/storage.go b/apiserver/pkg/registry/projectcalico/networkpolicy/storage.go index e1f00c7ab3e..c982a6a3164 100644 --- a/apiserver/pkg/registry/projectcalico/networkpolicy/storage.go +++ b/apiserver/pkg/registry/projectcalico/networkpolicy/storage.go @@ -17,7 +17,6 @@ package networkpolicy import ( "context" - calico "github.com/projectcalico/api/pkg/apis/projectcalico/v3" "k8s.io/apimachinery/pkg/api/meta" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -28,6 +27,8 @@ import ( genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" + calico "github.com/projectcalico/api/pkg/apis/projectcalico/v3" + "github.com/projectcalico/calico/apiserver/pkg/rbac" "github.com/projectcalico/calico/apiserver/pkg/registry/projectcalico/authorizer" "github.com/projectcalico/calico/apiserver/pkg/registry/projectcalico/server" diff --git a/apiserver/pkg/registry/projectcalico/networkpolicy/strategy.go b/apiserver/pkg/registry/projectcalico/networkpolicy/strategy.go index a7ea92d6edd..1a7e3d39fce 100644 --- a/apiserver/pkg/registry/projectcalico/networkpolicy/strategy.go +++ b/apiserver/pkg/registry/projectcalico/networkpolicy/strategy.go @@ -17,7 +17,6 @@ package networkpolicy import ( "context" "fmt" - "strings" calico "github.com/projectcalico/api/pkg/apis/projectcalico/v3" "k8s.io/apimachinery/pkg/fields" @@ -43,34 +42,9 @@ func (policyStrategy) NamespaceScoped() bool { } func (policyStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { - obj.(*calico.NetworkPolicy).Name = canonicalizePolicyName(obj) } func (policyStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { - obj.(*calico.NetworkPolicy).Name = canonicalizePolicyName(old) -} - -func canonicalizePolicyName(obj runtime.Object) string { - // Policies without a tier prepended to their name should have the tier prepended. - // It's possible for a user to send a policy with one of two name formats: - // - // - "tier.policy" - // - "policy" - // - // The logic below handles canonicalizing the name to the former. - tier := "default" - if oldPolicy, ok := obj.(*calico.NetworkPolicy); ok && oldPolicy.Spec.Tier != "" { - tier = oldPolicy.Spec.Tier - } - - policy := obj.(*calico.NetworkPolicy) - if len(strings.Split(policy.Name, ".")) == 1 { - // Tier is not included in the name - add it. - return tier + "." + policy.Name - } - - // Name already includes the tier. - return policy.Name } func (policyStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { diff --git a/libcalico-go/lib/backend/k8s/resources/resources.go b/libcalico-go/lib/backend/k8s/resources/resources.go index b2ae40eba97..307bc9b139c 100644 --- a/libcalico-go/lib/backend/k8s/resources/resources.go +++ b/libcalico-go/lib/backend/k8s/resources/resources.go @@ -143,6 +143,15 @@ func ConvertCalicoResourceToK8sResource(resIn Resource) (Resource, error) { romCopy.ResourceVersion = "" romCopy.UID = "" + labels := rom.GetLabels() + if labels != nil { + if _, ok := labels["projectcalico.org/metadata-name"]; ok { + romCopy.Name = labels["projectcalico.org/metadata-name"] + delete(labels, "projectcalico.org/metadata-name") + romCopy.SetLabels(labels) + } + } + // Any projectcalico.org/v3 owners need to be translated to their equivalent crd.projectcalico.org/v1 representations. // They will be converted back on read. var err error @@ -293,7 +302,9 @@ func ConvertK8sResourceToCalicoResource(res Resource) error { // Manually write in the data not stored in the annotations: Name, Namespace, ResourceVersion, // so that they do not get overwritten. - meta.Name = rom.GetName() + if meta.Name == "" { + meta.Name = rom.GetName() + } meta.Namespace = rom.GetNamespace() meta.ResourceVersion = rom.GetResourceVersion() meta.UID = rom.GetUID() diff --git a/libcalico-go/lib/clientv3/networkpolicy.go b/libcalico-go/lib/clientv3/networkpolicy.go index cecd00d72cf..7b615ac5d2c 100644 --- a/libcalico-go/lib/clientv3/networkpolicy.go +++ b/libcalico-go/lib/clientv3/networkpolicy.go @@ -17,9 +17,11 @@ package clientv3 import ( "context" - apiv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3" + errors2 "github.com/juju/errors" log "github.com/sirupsen/logrus" + apiv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3" + "github.com/projectcalico/calico/libcalico-go/lib/names" "github.com/projectcalico/calico/libcalico-go/lib/options" validator "github.com/projectcalico/calico/libcalico-go/lib/validator/v3" @@ -44,6 +46,8 @@ type networkPolicies struct { // Create takes the representation of a NetworkPolicy and creates it. Returns the stored // representation of the NetworkPolicy, and an error, if there is any. func (r networkPolicies) Create(ctx context.Context, res *apiv3.NetworkPolicy, opts options.SetOptions) (*apiv3.NetworkPolicy, error) { + storeOriginalName(res) + // Before creating the policy, check that the tier exists. tier := names.TierOrDefault(res.Spec.Tier) if _, err := r.client.resources.Get(ctx, options.GetOptions{}, apiv3.KindTier, noNamespace, tier); err != nil { @@ -91,6 +95,8 @@ func (r networkPolicies) Create(ctx context.Context, res *apiv3.NetworkPolicy, o // Update takes the representation of a NetworkPolicy and updates it. Returns the stored // representation of the NetworkPolicy, and an error, if there is any. func (r networkPolicies) Update(ctx context.Context, res *apiv3.NetworkPolicy, opts options.SetOptions) (*apiv3.NetworkPolicy, error) { + storeOriginalName(res) + if res != nil { // Since we're about to default some fields, take a (shallow) copy of the input data // before we do so. @@ -147,6 +153,10 @@ func (r networkPolicies) Get(ctx context.Context, namespace, name string, opts o backendPolicyName := names.TieredPolicyName(name) out, err := r.client.resources.Get(ctx, opts, apiv3.KindNetworkPolicy, namespace, backendPolicyName) if out != nil { + if name != out.GetObjectMeta().GetName() { + // If the name is different, we need to return a not found error. + return nil, errors2.NotFoundf("%s \"%s\" not found", apiv3.KindNetworkPolicy, name) + } // Add the tier labels if necessary out.GetObjectMeta().SetLabels(defaultTierLabelIfMissing(out.GetObjectMeta().GetLabels())) // Fill in the tier information from the policy name if we find it missing. @@ -205,3 +215,13 @@ func (r networkPolicies) Watch(ctx context.Context, opts options.ListOptions) (w return r.client.resources.Watch(ctx, opts, apiv3.KindNetworkPolicy, &policyConverter{}) } + +func storeOriginalName(res *apiv3.NetworkPolicy) { + originalName := res.GetObjectMeta().GetName() + labels := res.GetObjectMeta().GetLabels() + if labels == nil { + labels = map[string]string{} + } + labels["projectcalico.org/metadata-name"] = originalName + res.GetObjectMeta().SetLabels(labels) +}