blob: e4f3964a1215258a69d0a777377cc9e3f5bee2c3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 xds
import (
"sort"
)
import (
envoy_sd "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
envoy_types "github.com/envoyproxy/go-control-plane/pkg/cache/types"
protov1 "github.com/golang/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"
)
// ResourcePayload is a convenience type alias.
type ResourcePayload = envoy_types.Resource
// Resource represents a generic xDS resource with name and version.
type Resource struct {
Name string
Origin string
Resource ResourcePayload
}
// ResourceList represents a list of generic xDS resources.
type ResourceList []*Resource
func (rs ResourceList) ToDeltaDiscoveryResponse() (*envoy_sd.DeltaDiscoveryResponse, error) {
resp := &envoy_sd.DeltaDiscoveryResponse{}
for _, r := range rs {
pbany, err := anypb.New(protov1.MessageV2(r.Resource))
if err != nil {
return nil, err
}
resp.Resources = append(resp.Resources, &envoy_sd.Resource{
Name: r.Name,
Resource: pbany,
})
}
return resp, nil
}
func (rs ResourceList) ToIndex() map[string]ResourcePayload {
if len(rs) == 0 {
return nil
}
index := make(map[string]ResourcePayload)
for _, resource := range rs {
index[resource.Name] = resource.Resource
}
return index
}
func (rs ResourceList) Payloads() []ResourcePayload {
var payloads []ResourcePayload
for _, res := range rs {
payloads = append(payloads, res.Resource)
}
return payloads
}
func (rs ResourceList) Len() int { return len(rs) }
func (rs ResourceList) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] }
func (rs ResourceList) Less(i, j int) bool {
return rs[i].Name < rs[j].Name
}
// ResourceSet represents a set of generic xDS resources.
type ResourceSet struct {
// we want to prevent duplicates
typeToNamesIndex map[string]map[string]*Resource
}
func NewResourceSet() *ResourceSet {
set := &ResourceSet{}
set.typeToNamesIndex = map[string]map[string]*Resource{}
return set
}
// ResourceTypes returns names of all the distinct resource types in the set.
func (s *ResourceSet) ResourceTypes() []string {
var typeNames []string
for typeName := range s.typeToNamesIndex {
typeNames = append(typeNames, typeName)
}
return typeNames
}
func (s *ResourceSet) ListOf(typ string) ResourceList {
list := ResourceList{}
for _, resource := range s.typeToNamesIndex[typ] {
list = append(list, resource)
}
sort.Stable(list)
return list
}
func (s *ResourceSet) Contains(name string, resource ResourcePayload) bool {
names, ok := s.typeToNamesIndex[s.typeName(resource)]
if !ok {
return false
}
_, ok = names[name]
return ok
}
func (s *ResourceSet) Empty() bool {
for _, resourceMap := range s.typeToNamesIndex {
if len(resourceMap) != 0 {
return false
}
}
return true
}
func (s *ResourceSet) Add(resources ...*Resource) *ResourceSet {
for _, resource := range resources {
if s.typeToNamesIndex[s.typeName(resource.Resource)] == nil {
s.typeToNamesIndex[s.typeName(resource.Resource)] = map[string]*Resource{}
}
s.typeToNamesIndex[s.typeName(resource.Resource)][resource.Name] = resource
}
return s
}
func (s *ResourceSet) Remove(typ string, name string) {
if s.typeToNamesIndex[typ] != nil {
delete(s.typeToNamesIndex[typ], name)
}
}
func (s *ResourceSet) Resources(typ string) map[string]*Resource {
return s.typeToNamesIndex[typ]
}
func (s *ResourceSet) AddSet(set *ResourceSet) *ResourceSet {
if set == nil {
return s
}
for typ, resources := range set.typeToNamesIndex {
if s.typeToNamesIndex[typ] == nil {
s.typeToNamesIndex[typ] = map[string]*Resource{}
}
for name, resource := range resources {
s.typeToNamesIndex[typ][name] = resource
}
}
return s
}
func (s *ResourceSet) typeName(resource ResourcePayload) string {
return "type.googleapis.com/" + string(protov1.MessageV2(resource).ProtoReflect().Descriptor().FullName())
}
func (s *ResourceSet) List() ResourceList {
if s == nil {
return nil
}
types := s.ResourceTypes()
list := ResourceList{}
sort.Strings(types) // Deterministic for test output.
for _, name := range types {
list = append(list, s.ListOf(name)...)
}
return list
}