Files
kubesphere/vendor/github.com/projectcalico/libcalico-go/lib/backend/model/resource.go
2019-08-17 15:34:02 +08:00

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
}