271 lines
7.3 KiB
Go
271 lines
7.3 KiB
Go
// Copyright (c) 2016-2019 Tigera, Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package model
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
apiv3 "github.com/projectcalico/libcalico-go/lib/apis/v3"
|
|
"github.com/projectcalico/libcalico-go/lib/namespace"
|
|
)
|
|
|
|
// Name/type information about a single resource.
|
|
type resourceInfo struct {
|
|
typeOf reflect.Type
|
|
plural string
|
|
kind string
|
|
}
|
|
|
|
var (
|
|
matchGlobalResource = regexp.MustCompile("^/calico/resources/v3/projectcalico[.]org/([^/]+)/([^/]+)$")
|
|
matchNamespacedResource = regexp.MustCompile("^/calico/resources/v3/projectcalico[.]org/([^/]+)/([^/]+)/([^/]+)$")
|
|
resourceInfoByKind = make(map[string]resourceInfo)
|
|
resourceInfoByPlural = make(map[string]resourceInfo)
|
|
)
|
|
|
|
func registerResourceInfo(kind string, plural string, typeOf reflect.Type) {
|
|
kind = strings.ToLower(kind)
|
|
plural = strings.ToLower(plural)
|
|
ri := resourceInfo{
|
|
typeOf: typeOf,
|
|
kind: kind,
|
|
plural: plural,
|
|
}
|
|
resourceInfoByKind[kind] = ri
|
|
resourceInfoByPlural[plural] = ri
|
|
}
|
|
|
|
func init() {
|
|
registerResourceInfo(
|
|
apiv3.KindBGPPeer,
|
|
"bgppeers",
|
|
reflect.TypeOf(apiv3.BGPPeer{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindBGPConfiguration,
|
|
"bgpconfigurations",
|
|
reflect.TypeOf(apiv3.BGPConfiguration{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindClusterInformation,
|
|
"clusterinformations",
|
|
reflect.TypeOf(apiv3.ClusterInformation{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindFelixConfiguration,
|
|
"felixconfigurations",
|
|
reflect.TypeOf(apiv3.FelixConfiguration{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindGlobalNetworkPolicy,
|
|
"globalnetworkpolicies",
|
|
reflect.TypeOf(apiv3.GlobalNetworkPolicy{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindHostEndpoint,
|
|
"hostendpoints",
|
|
reflect.TypeOf(apiv3.HostEndpoint{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindGlobalNetworkSet,
|
|
"globalnetworksets",
|
|
reflect.TypeOf(apiv3.GlobalNetworkSet{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindIPPool,
|
|
"ippools",
|
|
reflect.TypeOf(apiv3.IPPool{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindNetworkPolicy,
|
|
"networkpolicies",
|
|
reflect.TypeOf(apiv3.NetworkPolicy{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindNetworkSet,
|
|
"networksets",
|
|
reflect.TypeOf(apiv3.NetworkSet{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindNode,
|
|
"nodes",
|
|
reflect.TypeOf(apiv3.Node{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindProfile,
|
|
"profiles",
|
|
reflect.TypeOf(apiv3.Profile{}),
|
|
)
|
|
registerResourceInfo(
|
|
apiv3.KindWorkloadEndpoint,
|
|
"workloadendpoints",
|
|
reflect.TypeOf(apiv3.WorkloadEndpoint{}),
|
|
)
|
|
}
|
|
|
|
type ResourceKey struct {
|
|
// The name of the resource.
|
|
Name string
|
|
// The namespace of the resource. Not required if the resource is not namespaced.
|
|
Namespace string
|
|
// The resource kind.
|
|
Kind string
|
|
}
|
|
|
|
func (key ResourceKey) defaultPath() (string, error) {
|
|
return key.defaultDeletePath()
|
|
}
|
|
|
|
func (key ResourceKey) defaultDeletePath() (string, error) {
|
|
ri, ok := resourceInfoByKind[strings.ToLower(key.Kind)]
|
|
if !ok {
|
|
return "", fmt.Errorf("couldn't convert key: %+v", key)
|
|
}
|
|
if namespace.IsNamespaced(key.Kind) {
|
|
return fmt.Sprintf("/calico/resources/v3/projectcalico.org/%s/%s/%s", ri.plural, key.Namespace, key.Name), nil
|
|
}
|
|
return fmt.Sprintf("/calico/resources/v3/projectcalico.org/%s/%s", ri.plural, key.Name), nil
|
|
}
|
|
|
|
func (key ResourceKey) defaultDeleteParentPaths() ([]string, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (key ResourceKey) valueType() (reflect.Type, error) {
|
|
ri, ok := resourceInfoByKind[strings.ToLower(key.Kind)]
|
|
if !ok {
|
|
return nil, fmt.Errorf("Unexpected resource kind: " + key.Kind)
|
|
}
|
|
return ri.typeOf, nil
|
|
}
|
|
|
|
func (key ResourceKey) String() string {
|
|
if namespace.IsNamespaced(key.Kind) {
|
|
return fmt.Sprintf("%s(%s/%s)", key.Kind, key.Namespace, key.Name)
|
|
}
|
|
return fmt.Sprintf("%s(%s)", key.Kind, key.Name)
|
|
}
|
|
|
|
type ResourceListOptions struct {
|
|
// The name of the resource.
|
|
Name string
|
|
// The namespace of the resource. Not required if the resource is not namespaced.
|
|
Namespace string
|
|
// The resource kind.
|
|
Kind string
|
|
// Whether the name is prefix rather than the full name.
|
|
Prefix bool
|
|
}
|
|
|
|
// If the Kind, Namespace and Name are specified, but the Name is a prefix then the
|
|
// last segment of this path is a prefix.
|
|
func (options ResourceListOptions) IsLastSegmentIsPrefix() bool {
|
|
return len(options.Kind) != 0 &&
|
|
(len(options.Namespace) != 0 || !namespace.IsNamespaced(options.Kind)) &&
|
|
len(options.Name) != 0 &&
|
|
options.Prefix
|
|
}
|
|
|
|
func (options ResourceListOptions) KeyFromDefaultPath(path string) Key {
|
|
ri, ok := resourceInfoByKind[strings.ToLower(options.Kind)]
|
|
if !ok {
|
|
log.Panic("Unexpected resource kind: " + options.Kind)
|
|
}
|
|
|
|
if namespace.IsNamespaced(options.Kind) {
|
|
log.Debugf("Get Namespaced Resource key from %s", path)
|
|
r := matchNamespacedResource.FindAllStringSubmatch(path, -1)
|
|
if len(r) != 1 {
|
|
log.Debugf("Didn't match regex")
|
|
return nil
|
|
}
|
|
kindPlural := r[0][1]
|
|
namespace := r[0][2]
|
|
name := r[0][3]
|
|
if len(options.Kind) == 0 {
|
|
panic("Kind must be specified in List option but is not")
|
|
}
|
|
if kindPlural != ri.plural {
|
|
log.Debugf("Didn't match kind %s != %s", kindPlural, kindPlural)
|
|
return nil
|
|
}
|
|
if len(options.Namespace) != 0 && namespace != options.Namespace {
|
|
log.Debugf("Didn't match namespace %s != %s", options.Namespace, namespace)
|
|
return nil
|
|
}
|
|
if len(options.Name) != 0 {
|
|
if options.Prefix && !strings.HasPrefix(name, options.Name) {
|
|
log.Debugf("Didn't match name prefix %s != prefix(%s)", options.Name, name)
|
|
return nil
|
|
} else if !options.Prefix && name != options.Name {
|
|
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
|
return nil
|
|
}
|
|
}
|
|
return ResourceKey{Kind: options.Kind, Namespace: namespace, Name: name}
|
|
}
|
|
|
|
log.Debugf("Get Global Resource key from %s", path)
|
|
r := matchGlobalResource.FindAllStringSubmatch(path, -1)
|
|
if len(r) != 1 {
|
|
log.Debugf("Didn't match regex")
|
|
return nil
|
|
}
|
|
kindPlural := r[0][1]
|
|
name := r[0][2]
|
|
if kindPlural != ri.plural {
|
|
log.Debugf("Didn't match kind %s != %s", kindPlural, kindPlural)
|
|
return nil
|
|
}
|
|
if len(options.Name) != 0 {
|
|
if options.Prefix && !strings.HasPrefix(name, options.Name) {
|
|
log.Debugf("Didn't match name prefix %s != prefix(%s)", options.Name, name)
|
|
return nil
|
|
} else if !options.Prefix && name != options.Name {
|
|
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
|
return nil
|
|
}
|
|
}
|
|
return ResourceKey{Kind: options.Kind, Name: name}
|
|
}
|
|
|
|
func (options ResourceListOptions) defaultPathRoot() string {
|
|
ri, ok := resourceInfoByKind[strings.ToLower(options.Kind)]
|
|
if !ok {
|
|
log.Panic("Unexpected resource kind: " + options.Kind)
|
|
}
|
|
|
|
k := "/calico/resources/v3/projectcalico.org/" + ri.plural
|
|
if namespace.IsNamespaced(options.Kind) {
|
|
if options.Namespace == "" {
|
|
return k
|
|
}
|
|
k = k + "/" + options.Namespace
|
|
}
|
|
if options.Name == "" {
|
|
return k
|
|
}
|
|
return k + "/" + options.Name
|
|
}
|
|
|
|
func (options ResourceListOptions) String() string {
|
|
return options.Kind
|
|
}
|