From 064b6698ca3db39190a0eeb91073aa194ae63b1c Mon Sep 17 00:00:00 2001 From: Qiyue Yao Date: Tue, 8 Aug 2023 18:46:24 -0700 Subject: [PATCH] Namespaced Group membership API Currently Antrea supports ClusterGroup and namespaced Group CRD, but only provides API for ClusterGroup membership. This solution adds membership API for namespaced Group at namespacedgroupmembers.controlplane.antrea.io. The group association API is still available for both ClusterGroup and namespaced Group. Fixes #5269 Signed-off-by: Qiyue Yao --- hack/update-codegen-dockerized.sh | 1 + pkg/apis/controlplane/register.go | 1 + pkg/apis/controlplane/types.go | 15 +- pkg/apis/controlplane/v1beta2/generated.pb.go | 772 +++++++++++++----- pkg/apis/controlplane/v1beta2/generated.proto | 17 +- pkg/apis/controlplane/v1beta2/register.go | 1 + pkg/apis/controlplane/v1beta2/types.go | 17 +- .../v1beta2/zz_generated.conversion.go | 60 ++ .../v1beta2/zz_generated.deepcopy.go | 40 + .../controlplane/zz_generated.deepcopy.go | 40 + pkg/apiserver/apiserver.go | 3 + pkg/apiserver/openapi/zz_generated.openapi.go | 86 +- .../networkpolicy/clustergroupmember/rest.go | 104 +-- .../clustergroupmember/rest_test.go | 55 +- .../networkpolicy/groupmember/rest.go | 73 ++ .../networkpolicy/groupmember/rest_test.go | 211 +++++ .../v1beta2/controlplane_client.go | 5 + .../v1beta2/fake/fake_controlplane_client.go | 4 + .../v1beta2/fake/fake_groupmembers.go | 47 ++ .../v1beta2/generated_expansion.go | 2 + .../controlplane/v1beta2/groupmembers.go | 65 ++ pkg/controller/networkpolicy/clustergroup.go | 10 +- .../networkpolicy/clustergroup_test.go | 2 +- pkg/controller/networkpolicy/group.go | 3 +- pkg/controller/networkpolicy/group_test.go | 52 ++ 25 files changed, 1414 insertions(+), 272 deletions(-) create mode 100644 pkg/apiserver/registry/networkpolicy/groupmember/rest.go create mode 100644 pkg/apiserver/registry/networkpolicy/groupmember/rest_test.go create mode 100644 pkg/client/clientset/versioned/typed/controlplane/v1beta2/fake/fake_groupmembers.go create mode 100644 pkg/client/clientset/versioned/typed/controlplane/v1beta2/groupmembers.go diff --git a/hack/update-codegen-dockerized.sh b/hack/update-codegen-dockerized.sh index 091693f3ca7..6c4fa2d6fd4 100755 --- a/hack/update-codegen-dockerized.sh +++ b/hack/update-codegen-dockerized.sh @@ -102,6 +102,7 @@ function generate_antrea_client_code { --plural-exceptions "AntreaNetworkPolicyStats:AntreaNetworkPolicyStats" \ --plural-exceptions "AntreaClusterNetworkPolicyStats:AntreaClusterNetworkPolicyStats" \ --plural-exceptions "ClusterGroupMembers:ClusterGroupMembers" \ + --plural-exceptions "GroupMembers:GroupMembers" \ --go-header-file hack/boilerplate/license_header.go.txt # Generate listers with K8s codegen tools. diff --git a/pkg/apis/controlplane/register.go b/pkg/apis/controlplane/register.go index 6e79ee22d18..42a27ddeab8 100644 --- a/pkg/apis/controlplane/register.go +++ b/pkg/apis/controlplane/register.go @@ -56,6 +56,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { &NetworkPolicyStatus{}, &NodeStatsSummary{}, &ClusterGroupMembers{}, + &GroupMembers{}, &PaginationGetOptions{}, &GroupAssociation{}, &IPGroupAssociation{}, diff --git a/pkg/apis/controlplane/types.go b/pkg/apis/controlplane/types.go index 2e81bdd1381..6f576d4f9e1 100644 --- a/pkg/apis/controlplane/types.go +++ b/pkg/apis/controlplane/types.go @@ -95,7 +95,7 @@ type GroupMember struct { // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// ClusterGroupMembers is a list of GroupMember objects or ipBlocks that are currently selected by a ClusterGroup. +// ClusterGroupMembers is a list of GroupMember objects or IPBlocks that are currently selected by a ClusterGroup. type ClusterGroupMembers struct { metav1.TypeMeta metav1.ObjectMeta @@ -106,6 +106,19 @@ type ClusterGroupMembers struct { CurrentPage int64 } +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// GroupMembers is a list of GroupMember objects or IPBlocks that are currently selected by a Group. +type GroupMembers struct { + metav1.TypeMeta + metav1.ObjectMeta + EffectiveMembers []GroupMember + EffectiveIPBlocks []IPNet + TotalMembers int64 + TotalPages int64 + CurrentPage int64 +} + // +k8s:conversion-gen:explicit-from=net/url.Values // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/controlplane/v1beta2/generated.pb.go b/pkg/apis/controlplane/v1beta2/generated.pb.go index 5f0ea38ce5a..3247f1e1ff7 100644 --- a/pkg/apis/controlplane/v1beta2/generated.pb.go +++ b/pkg/apis/controlplane/v1beta2/generated.pb.go @@ -495,10 +495,38 @@ func (m *GroupMember) XXX_DiscardUnknown() { var xxx_messageInfo_GroupMember proto.InternalMessageInfo +func (m *GroupMembers) Reset() { *m = GroupMembers{} } +func (*GroupMembers) ProtoMessage() {} +func (*GroupMembers) Descriptor() ([]byte, []int) { + return fileDescriptor_fbaa7d016762fa1d, []int{16} +} +func (m *GroupMembers) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GroupMembers) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *GroupMembers) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupMembers.Merge(m, src) +} +func (m *GroupMembers) XXX_Size() int { + return m.Size() +} +func (m *GroupMembers) XXX_DiscardUnknown() { + xxx_messageInfo_GroupMembers.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupMembers proto.InternalMessageInfo + func (m *GroupReference) Reset() { *m = GroupReference{} } func (*GroupReference) ProtoMessage() {} func (*GroupReference) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{16} + return fileDescriptor_fbaa7d016762fa1d, []int{17} } func (m *GroupReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -526,7 +554,7 @@ var xxx_messageInfo_GroupReference proto.InternalMessageInfo func (m *HTTPProtocol) Reset() { *m = HTTPProtocol{} } func (*HTTPProtocol) ProtoMessage() {} func (*HTTPProtocol) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{17} + return fileDescriptor_fbaa7d016762fa1d, []int{18} } func (m *HTTPProtocol) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -554,7 +582,7 @@ var xxx_messageInfo_HTTPProtocol proto.InternalMessageInfo func (m *IPBlock) Reset() { *m = IPBlock{} } func (*IPBlock) ProtoMessage() {} func (*IPBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{18} + return fileDescriptor_fbaa7d016762fa1d, []int{19} } func (m *IPBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -582,7 +610,7 @@ var xxx_messageInfo_IPBlock proto.InternalMessageInfo func (m *IPGroupAssociation) Reset() { *m = IPGroupAssociation{} } func (*IPGroupAssociation) ProtoMessage() {} func (*IPGroupAssociation) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{19} + return fileDescriptor_fbaa7d016762fa1d, []int{20} } func (m *IPGroupAssociation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -610,7 +638,7 @@ var xxx_messageInfo_IPGroupAssociation proto.InternalMessageInfo func (m *IPNet) Reset() { *m = IPNet{} } func (*IPNet) ProtoMessage() {} func (*IPNet) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{20} + return fileDescriptor_fbaa7d016762fa1d, []int{21} } func (m *IPNet) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -638,7 +666,7 @@ var xxx_messageInfo_IPNet proto.InternalMessageInfo func (m *L7Protocol) Reset() { *m = L7Protocol{} } func (*L7Protocol) ProtoMessage() {} func (*L7Protocol) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{21} + return fileDescriptor_fbaa7d016762fa1d, []int{22} } func (m *L7Protocol) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -666,7 +694,7 @@ var xxx_messageInfo_L7Protocol proto.InternalMessageInfo func (m *MulticastGroupInfo) Reset() { *m = MulticastGroupInfo{} } func (*MulticastGroupInfo) ProtoMessage() {} func (*MulticastGroupInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{22} + return fileDescriptor_fbaa7d016762fa1d, []int{23} } func (m *MulticastGroupInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -694,7 +722,7 @@ var xxx_messageInfo_MulticastGroupInfo proto.InternalMessageInfo func (m *NamedPort) Reset() { *m = NamedPort{} } func (*NamedPort) ProtoMessage() {} func (*NamedPort) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{23} + return fileDescriptor_fbaa7d016762fa1d, []int{24} } func (m *NamedPort) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -722,7 +750,7 @@ var xxx_messageInfo_NamedPort proto.InternalMessageInfo func (m *NetworkPolicy) Reset() { *m = NetworkPolicy{} } func (*NetworkPolicy) ProtoMessage() {} func (*NetworkPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{24} + return fileDescriptor_fbaa7d016762fa1d, []int{25} } func (m *NetworkPolicy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -750,7 +778,7 @@ var xxx_messageInfo_NetworkPolicy proto.InternalMessageInfo func (m *NetworkPolicyList) Reset() { *m = NetworkPolicyList{} } func (*NetworkPolicyList) ProtoMessage() {} func (*NetworkPolicyList) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{25} + return fileDescriptor_fbaa7d016762fa1d, []int{26} } func (m *NetworkPolicyList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -778,7 +806,7 @@ var xxx_messageInfo_NetworkPolicyList proto.InternalMessageInfo func (m *NetworkPolicyNodeStatus) Reset() { *m = NetworkPolicyNodeStatus{} } func (*NetworkPolicyNodeStatus) ProtoMessage() {} func (*NetworkPolicyNodeStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{26} + return fileDescriptor_fbaa7d016762fa1d, []int{27} } func (m *NetworkPolicyNodeStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -806,7 +834,7 @@ var xxx_messageInfo_NetworkPolicyNodeStatus proto.InternalMessageInfo func (m *NetworkPolicyPeer) Reset() { *m = NetworkPolicyPeer{} } func (*NetworkPolicyPeer) ProtoMessage() {} func (*NetworkPolicyPeer) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{27} + return fileDescriptor_fbaa7d016762fa1d, []int{28} } func (m *NetworkPolicyPeer) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -834,7 +862,7 @@ var xxx_messageInfo_NetworkPolicyPeer proto.InternalMessageInfo func (m *NetworkPolicyReference) Reset() { *m = NetworkPolicyReference{} } func (*NetworkPolicyReference) ProtoMessage() {} func (*NetworkPolicyReference) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{28} + return fileDescriptor_fbaa7d016762fa1d, []int{29} } func (m *NetworkPolicyReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -862,7 +890,7 @@ var xxx_messageInfo_NetworkPolicyReference proto.InternalMessageInfo func (m *NetworkPolicyRule) Reset() { *m = NetworkPolicyRule{} } func (*NetworkPolicyRule) ProtoMessage() {} func (*NetworkPolicyRule) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{29} + return fileDescriptor_fbaa7d016762fa1d, []int{30} } func (m *NetworkPolicyRule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -890,7 +918,7 @@ var xxx_messageInfo_NetworkPolicyRule proto.InternalMessageInfo func (m *NetworkPolicyStats) Reset() { *m = NetworkPolicyStats{} } func (*NetworkPolicyStats) ProtoMessage() {} func (*NetworkPolicyStats) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{30} + return fileDescriptor_fbaa7d016762fa1d, []int{31} } func (m *NetworkPolicyStats) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -918,7 +946,7 @@ var xxx_messageInfo_NetworkPolicyStats proto.InternalMessageInfo func (m *NetworkPolicyStatus) Reset() { *m = NetworkPolicyStatus{} } func (*NetworkPolicyStatus) ProtoMessage() {} func (*NetworkPolicyStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{31} + return fileDescriptor_fbaa7d016762fa1d, []int{32} } func (m *NetworkPolicyStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -946,7 +974,7 @@ var xxx_messageInfo_NetworkPolicyStatus proto.InternalMessageInfo func (m *NodeReference) Reset() { *m = NodeReference{} } func (*NodeReference) ProtoMessage() {} func (*NodeReference) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{32} + return fileDescriptor_fbaa7d016762fa1d, []int{33} } func (m *NodeReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -974,7 +1002,7 @@ var xxx_messageInfo_NodeReference proto.InternalMessageInfo func (m *NodeStatsSummary) Reset() { *m = NodeStatsSummary{} } func (*NodeStatsSummary) ProtoMessage() {} func (*NodeStatsSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{33} + return fileDescriptor_fbaa7d016762fa1d, []int{34} } func (m *NodeStatsSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1002,7 +1030,7 @@ var xxx_messageInfo_NodeStatsSummary proto.InternalMessageInfo func (m *PaginationGetOptions) Reset() { *m = PaginationGetOptions{} } func (*PaginationGetOptions) ProtoMessage() {} func (*PaginationGetOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{34} + return fileDescriptor_fbaa7d016762fa1d, []int{35} } func (m *PaginationGetOptions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1030,7 +1058,7 @@ var xxx_messageInfo_PaginationGetOptions proto.InternalMessageInfo func (m *PodReference) Reset() { *m = PodReference{} } func (*PodReference) ProtoMessage() {} func (*PodReference) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{35} + return fileDescriptor_fbaa7d016762fa1d, []int{36} } func (m *PodReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1058,7 +1086,7 @@ var xxx_messageInfo_PodReference proto.InternalMessageInfo func (m *Service) Reset() { *m = Service{} } func (*Service) ProtoMessage() {} func (*Service) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{36} + return fileDescriptor_fbaa7d016762fa1d, []int{37} } func (m *Service) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1086,7 +1114,7 @@ var xxx_messageInfo_Service proto.InternalMessageInfo func (m *ServiceReference) Reset() { *m = ServiceReference{} } func (*ServiceReference) ProtoMessage() {} func (*ServiceReference) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{37} + return fileDescriptor_fbaa7d016762fa1d, []int{38} } func (m *ServiceReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1114,7 +1142,7 @@ var xxx_messageInfo_ServiceReference proto.InternalMessageInfo func (m *SupportBundleCollection) Reset() { *m = SupportBundleCollection{} } func (*SupportBundleCollection) ProtoMessage() {} func (*SupportBundleCollection) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{38} + return fileDescriptor_fbaa7d016762fa1d, []int{39} } func (m *SupportBundleCollection) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1142,7 +1170,7 @@ var xxx_messageInfo_SupportBundleCollection proto.InternalMessageInfo func (m *SupportBundleCollectionList) Reset() { *m = SupportBundleCollectionList{} } func (*SupportBundleCollectionList) ProtoMessage() {} func (*SupportBundleCollectionList) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{39} + return fileDescriptor_fbaa7d016762fa1d, []int{40} } func (m *SupportBundleCollectionList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1170,7 +1198,7 @@ var xxx_messageInfo_SupportBundleCollectionList proto.InternalMessageInfo func (m *SupportBundleCollectionNodeStatus) Reset() { *m = SupportBundleCollectionNodeStatus{} } func (*SupportBundleCollectionNodeStatus) ProtoMessage() {} func (*SupportBundleCollectionNodeStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{40} + return fileDescriptor_fbaa7d016762fa1d, []int{41} } func (m *SupportBundleCollectionNodeStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1198,7 +1226,7 @@ var xxx_messageInfo_SupportBundleCollectionNodeStatus proto.InternalMessageInfo func (m *SupportBundleCollectionStatus) Reset() { *m = SupportBundleCollectionStatus{} } func (*SupportBundleCollectionStatus) ProtoMessage() {} func (*SupportBundleCollectionStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{41} + return fileDescriptor_fbaa7d016762fa1d, []int{42} } func (m *SupportBundleCollectionStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1226,7 +1254,7 @@ var xxx_messageInfo_SupportBundleCollectionStatus proto.InternalMessageInfo func (m *TLSProtocol) Reset() { *m = TLSProtocol{} } func (*TLSProtocol) ProtoMessage() {} func (*TLSProtocol) Descriptor() ([]byte, []int) { - return fileDescriptor_fbaa7d016762fa1d, []int{42} + return fileDescriptor_fbaa7d016762fa1d, []int{43} } func (m *TLSProtocol) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1268,6 +1296,7 @@ func init() { proto.RegisterType((*ExternalEntityReference)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.ExternalEntityReference") proto.RegisterType((*GroupAssociation)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.GroupAssociation") proto.RegisterType((*GroupMember)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.GroupMember") + proto.RegisterType((*GroupMembers)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.GroupMembers") proto.RegisterType((*GroupReference)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.GroupReference") proto.RegisterType((*HTTPProtocol)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.HTTPProtocol") proto.RegisterType((*IPBlock)(nil), "antrea_io.antrea.pkg.apis.controlplane.v1beta2.IPBlock") @@ -1302,186 +1331,186 @@ func init() { } var fileDescriptor_fbaa7d016762fa1d = []byte{ - // 2852 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3a, 0xcd, 0x6f, 0x24, 0xc5, - 0xf5, 0xdb, 0x9e, 0x19, 0xdb, 0xf3, 0xc6, 0xf6, 0x7a, 0xcb, 0xc0, 0xfa, 0x07, 0xac, 0xbd, 0x34, - 0xbf, 0xa0, 0x4d, 0x44, 0x66, 0xb0, 0x03, 0xec, 0x86, 0x2f, 0xc5, 0xe3, 0xf5, 0x9a, 0x09, 0xb6, - 0x19, 0x6a, 0x06, 0x90, 0x20, 0x10, 0xda, 0xdd, 0x35, 0xe3, 0x8e, 0x7b, 0xba, 0x9a, 0xea, 0x1a, - 0xb3, 0xe6, 0x10, 0x11, 0x91, 0x1c, 0xc8, 0x17, 0x51, 0x2e, 0x51, 0x6e, 0xb9, 0xe5, 0x92, 0xbf, - 0x80, 0x53, 0x38, 0x44, 0xe2, 0x48, 0x14, 0x45, 0xe1, 0x64, 0x65, 0x1d, 0x85, 0x88, 0x43, 0x2e, - 0xb9, 0x65, 0xa3, 0x48, 0x51, 0x55, 0x57, 0x77, 0x57, 0xcf, 0x78, 0xd6, 0x3b, 0xb6, 0xd7, 0x91, - 0x02, 0xa7, 0x99, 0x7e, 0xdf, 0x55, 0xf5, 0x5e, 0xbd, 0x8f, 0x6e, 0x78, 0xc6, 0xf2, 0x39, 0x23, - 0x56, 0xd9, 0xa5, 0x95, 0xe8, 0x5f, 0x25, 0xd8, 0x6e, 0x57, 0xac, 0xc0, 0x0d, 0x2b, 0x36, 0xf5, - 0x39, 0xa3, 0x5e, 0xe0, 0x59, 0x3e, 0xa9, 0xec, 0x2c, 0x6c, 0x12, 0x6e, 0x2d, 0x56, 0xda, 0xc4, - 0x27, 0xcc, 0xe2, 0xc4, 0x29, 0x07, 0x8c, 0x72, 0x8a, 0xca, 0x11, 0xd7, 0xb7, 0x5d, 0xaa, 0xfe, - 0x95, 0x83, 0xed, 0x76, 0x59, 0xf0, 0x97, 0x75, 0xfe, 0xb2, 0xe2, 0xbf, 0xf7, 0xca, 0x60, 0x7d, - 0x21, 0xb7, 0x78, 0x58, 0xd9, 0x59, 0xb0, 0xbc, 0x60, 0xcb, 0x5a, 0xe8, 0xd5, 0x74, 0xef, 0x57, - 0xdb, 0x2e, 0xdf, 0xea, 0x6e, 0x96, 0x6d, 0xda, 0xa9, 0xb4, 0x69, 0x9b, 0x56, 0x24, 0x78, 0xb3, - 0xdb, 0x92, 0x4f, 0xf2, 0x41, 0xfe, 0x53, 0xe4, 0x8f, 0x6e, 0x5f, 0x09, 0xa5, 0x96, 0xc0, 0xed, - 0x58, 0xf6, 0x96, 0xeb, 0x13, 0xb6, 0x9b, 0xea, 0xea, 0x10, 0x6e, 0x55, 0x76, 0xfa, 0x95, 0x54, - 0x06, 0x71, 0xb1, 0xae, 0xcf, 0xdd, 0x0e, 0xe9, 0x63, 0x78, 0xfc, 0x30, 0x86, 0xd0, 0xde, 0x22, - 0x1d, 0xab, 0x8f, 0xef, 0x6b, 0x83, 0xf8, 0xba, 0xdc, 0xf5, 0x2a, 0xae, 0xcf, 0x43, 0xce, 0x7a, - 0x99, 0xcc, 0xbf, 0x19, 0x30, 0xb1, 0xe4, 0x38, 0x8c, 0x84, 0xe1, 0x2a, 0xa3, 0xdd, 0x00, 0xbd, - 0x01, 0xe3, 0x62, 0x25, 0x8e, 0xc5, 0xad, 0x59, 0xe3, 0xa2, 0x71, 0xa9, 0xb4, 0xf8, 0x48, 0x39, - 0x12, 0x5c, 0xd6, 0x05, 0xa7, 0x67, 0x22, 0xa8, 0xcb, 0x3b, 0x0b, 0xe5, 0xe7, 0x37, 0xbf, 0x43, - 0x6c, 0xbe, 0x4e, 0xb8, 0x55, 0x45, 0x1f, 0xed, 0xcd, 0x9f, 0xd9, 0xdf, 0x9b, 0x87, 0x14, 0x86, - 0x13, 0xa9, 0xa8, 0x0b, 0x13, 0x6d, 0xa1, 0x6a, 0x9d, 0x74, 0x36, 0x09, 0x0b, 0x67, 0x47, 0x2e, - 0xe6, 0x2e, 0x95, 0x16, 0x9f, 0x1c, 0xf2, 0xd8, 0xcb, 0xab, 0xa9, 0x8c, 0xea, 0x5d, 0x4a, 0xe1, - 0x84, 0x06, 0x0c, 0x71, 0x46, 0x8d, 0xf9, 0x07, 0x03, 0xa6, 0xf5, 0x95, 0xae, 0xb9, 0x21, 0x47, - 0xdf, 0xea, 0x5b, 0x6d, 0xf9, 0xf6, 0x56, 0x2b, 0xb8, 0xe5, 0x5a, 0xa7, 0x95, 0xea, 0xf1, 0x18, - 0xa2, 0xad, 0xd4, 0x82, 0x82, 0xcb, 0x49, 0x27, 0x5e, 0xe2, 0x53, 0xc3, 0x2e, 0x51, 0x37, 0xb7, - 0x3a, 0xa9, 0x14, 0x15, 0x6a, 0x42, 0x24, 0x8e, 0x24, 0x9b, 0xef, 0xe5, 0xe0, 0x9c, 0x4e, 0x56, - 0xb7, 0xb8, 0xbd, 0x75, 0x0a, 0x87, 0xf8, 0x7d, 0x03, 0xce, 0x59, 0x8e, 0x43, 0x9c, 0xd5, 0x13, - 0x3e, 0xca, 0xff, 0x53, 0x6a, 0xc5, 0xaa, 0xb2, 0xd2, 0x71, 0xbf, 0x42, 0xf4, 0x43, 0x03, 0x66, - 0x18, 0xe9, 0xd0, 0x9d, 0x1e, 0x43, 0x72, 0xc7, 0x37, 0xe4, 0x3e, 0x65, 0xc8, 0x0c, 0xee, 0x97, - 0x8f, 0x0f, 0x52, 0x6a, 0x7e, 0x66, 0xc0, 0xd4, 0x52, 0x10, 0x78, 0x2e, 0x71, 0x9a, 0xf4, 0x7f, - 0x3c, 0x9a, 0xfe, 0x64, 0x00, 0xca, 0xae, 0xf5, 0x14, 0xe2, 0xc9, 0xce, 0xc6, 0xd3, 0x33, 0x43, - 0xc7, 0x53, 0xc6, 0xe0, 0x01, 0x11, 0xf5, 0xa3, 0x1c, 0xcc, 0x64, 0x09, 0xbf, 0x88, 0xa9, 0xff, - 0x5e, 0x4c, 0xbd, 0x09, 0x33, 0x55, 0x2b, 0x74, 0xed, 0xa5, 0x2e, 0xdf, 0x22, 0x3e, 0x77, 0x6d, - 0x8b, 0xbb, 0xd4, 0x47, 0x0f, 0xc3, 0x78, 0x37, 0x24, 0xcc, 0xb7, 0x3a, 0x44, 0x1e, 0x46, 0x31, - 0xf5, 0x9b, 0x17, 0x15, 0x1c, 0x27, 0x14, 0x82, 0x3a, 0xb0, 0xc2, 0xf0, 0x2d, 0xca, 0x9c, 0xd9, - 0x91, 0x2c, 0x75, 0x5d, 0xc1, 0x71, 0x42, 0x61, 0x2e, 0xc0, 0x74, 0xb5, 0xeb, 0x3b, 0x1e, 0xb9, - 0xe6, 0x7a, 0xa4, 0x41, 0xd8, 0x0e, 0x61, 0xe8, 0x02, 0xe4, 0xba, 0xcc, 0x53, 0xaa, 0x4a, 0x8a, - 0x39, 0xf7, 0x22, 0x5e, 0xc3, 0x02, 0x6e, 0xbe, 0x3f, 0x02, 0x17, 0x22, 0x9e, 0x88, 0x5e, 0x58, - 0xbb, 0x4c, 0xfd, 0x96, 0xdb, 0xee, 0xb2, 0xc8, 0xe0, 0xc7, 0xa0, 0xb4, 0x49, 0x2c, 0x46, 0x58, - 0x93, 0x6e, 0x13, 0x5f, 0x09, 0x9a, 0x51, 0x82, 0x4a, 0xd5, 0x14, 0x85, 0x75, 0x3a, 0xf4, 0x10, - 0x8c, 0x5a, 0x81, 0xfb, 0x1c, 0xd9, 0x55, 0x76, 0x4f, 0x29, 0x8e, 0xd1, 0xa5, 0x7a, 0xed, 0x39, - 0xb2, 0x8b, 0x15, 0x16, 0xfd, 0xd4, 0x80, 0x99, 0xcd, 0xfe, 0x7d, 0x9a, 0xcd, 0x49, 0x47, 0x5d, - 0x1e, 0xf6, 0xcc, 0x0e, 0xd8, 0xf2, 0xea, 0x79, 0x71, 0x6e, 0x07, 0x20, 0xf0, 0x41, 0x8a, 0xcd, - 0x5f, 0xe5, 0x61, 0x66, 0xd9, 0xeb, 0x86, 0x9c, 0xb0, 0x8c, 0x73, 0xdd, 0xf9, 0x28, 0xfa, 0x9e, - 0x01, 0xd3, 0xa4, 0xd5, 0x22, 0x36, 0x77, 0x77, 0xc8, 0x09, 0x06, 0xd1, 0xac, 0xd2, 0x3a, 0xbd, - 0xd2, 0x23, 0x1c, 0xf7, 0xa9, 0x43, 0xdf, 0x85, 0x73, 0x09, 0xac, 0x56, 0xaf, 0x7a, 0xd4, 0xde, - 0x8e, 0xe3, 0xe7, 0xb1, 0x61, 0x6d, 0xa8, 0xd5, 0x37, 0x08, 0x4f, 0x43, 0x78, 0xa5, 0x57, 0x2e, - 0xee, 0x57, 0x85, 0xae, 0xc0, 0x04, 0xa7, 0xdc, 0xf2, 0xe2, 0xe5, 0xe7, 0x2f, 0x1a, 0x97, 0x72, - 0xe9, 0xbd, 0xde, 0xd4, 0x70, 0x38, 0x43, 0x89, 0x16, 0x01, 0xe4, 0x73, 0xdd, 0x6a, 0x93, 0x70, - 0xb6, 0x20, 0xf9, 0x92, 0xfd, 0x6e, 0x26, 0x18, 0xac, 0x51, 0x09, 0xdf, 0xb6, 0xbb, 0x8c, 0x11, - 0x9f, 0x8b, 0xe7, 0xd9, 0x51, 0xc9, 0x94, 0xf8, 0xf6, 0x72, 0x8a, 0xc2, 0x3a, 0x9d, 0xf9, 0xa9, - 0x01, 0xa5, 0x95, 0xf6, 0xe7, 0xa0, 0xf2, 0xfc, 0xbd, 0x01, 0x67, 0xb5, 0x85, 0x9e, 0x42, 0xa2, - 0x7c, 0x23, 0x9b, 0x28, 0x87, 0x5e, 0xa1, 0x66, 0xed, 0x80, 0x2c, 0xf9, 0xe3, 0x1c, 0x4c, 0x6b, - 0x54, 0x51, 0x8a, 0x74, 0x00, 0x68, 0xb2, 0xef, 0x27, 0x7a, 0x86, 0x9a, 0xdc, 0x2f, 0xd2, 0xe4, - 0x01, 0x69, 0xd2, 0x83, 0xf3, 0x2b, 0xd7, 0xb9, 0x48, 0x77, 0xde, 0x8a, 0xcf, 0x5d, 0xbe, 0x8b, - 0x49, 0x8b, 0x30, 0xe2, 0xdb, 0x04, 0x5d, 0x84, 0xbc, 0x96, 0x26, 0x27, 0x94, 0xe8, 0xfc, 0x86, - 0x48, 0x91, 0x12, 0x83, 0x2a, 0x50, 0x14, 0xbf, 0x61, 0x60, 0xd9, 0x44, 0xe5, 0x99, 0x73, 0x8a, - 0xac, 0xb8, 0x11, 0x23, 0x70, 0x4a, 0x63, 0xfe, 0xcb, 0x80, 0x69, 0xa9, 0x7e, 0x29, 0x0c, 0xa9, - 0xed, 0x46, 0x19, 0xee, 0x54, 0xea, 0xa3, 0x69, 0x4b, 0x69, 0x54, 0xeb, 0x3f, 0x72, 0x29, 0x28, - 0xb9, 0x93, 0x4d, 0x4a, 0x2f, 0xf7, 0xa5, 0x1e, 0xf9, 0xb8, 0x4f, 0xa3, 0xf9, 0x41, 0x1e, 0x4a, - 0xda, 0xe6, 0xa3, 0x97, 0x21, 0x17, 0x50, 0x47, 0xad, 0x79, 0xe8, 0x1e, 0xaf, 0x4e, 0x9d, 0xd4, - 0x8c, 0x31, 0x51, 0x55, 0x08, 0x88, 0x90, 0x88, 0xde, 0x35, 0x60, 0x8a, 0x64, 0x4e, 0x55, 0x9e, - 0x4e, 0x69, 0x71, 0x75, 0xe8, 0x78, 0x3e, 0xd8, 0x37, 0xaa, 0x68, 0x7f, 0x6f, 0x7e, 0xaa, 0x07, - 0xd9, 0xa3, 0x12, 0x3d, 0x04, 0x39, 0x37, 0x88, 0xdc, 0x7a, 0xa2, 0x7a, 0x97, 0x30, 0xb0, 0x56, - 0x0f, 0x6f, 0xee, 0xcd, 0x17, 0x6b, 0x75, 0xd5, 0x78, 0x62, 0x41, 0x80, 0x5e, 0x87, 0x42, 0x40, - 0x19, 0x17, 0xc9, 0x46, 0x9c, 0xc8, 0xd7, 0x87, 0xb5, 0x51, 0x78, 0x9a, 0x53, 0xa7, 0x8c, 0xa7, - 0x37, 0x8e, 0x78, 0x0a, 0x71, 0x24, 0x16, 0xbd, 0x0a, 0x79, 0x9f, 0x3a, 0x44, 0xe6, 0xa4, 0xd2, - 0xe2, 0xd3, 0x43, 0x8b, 0xa7, 0x0e, 0x49, 0x17, 0x3e, 0x2e, 0x43, 0x40, 0x80, 0xa4, 0x50, 0xd4, - 0x86, 0xb1, 0x90, 0xb0, 0x1d, 0xd7, 0x8e, 0xd2, 0x57, 0x69, 0xf1, 0x1b, 0xc3, 0xca, 0x6f, 0x44, - 0xec, 0xa9, 0x8a, 0xd2, 0xfe, 0xde, 0xfc, 0x58, 0x0c, 0x8d, 0xa5, 0x9b, 0xbf, 0x36, 0x60, 0x2a, - 0xeb, 0x7b, 0xd9, 0xf0, 0x33, 0x0e, 0x0f, 0xbf, 0x24, 0xa2, 0x47, 0x06, 0x46, 0x74, 0x15, 0x72, - 0x5d, 0xd7, 0x91, 0xd5, 0x5f, 0xb1, 0xfa, 0x48, 0x52, 0xae, 0xd6, 0xae, 0xde, 0xdc, 0x9b, 0x7f, - 0x60, 0xd0, 0x98, 0x88, 0xef, 0x06, 0x24, 0x2c, 0xbf, 0x58, 0xbb, 0x8a, 0x05, 0xb3, 0xf9, 0x36, - 0x4c, 0x3c, 0xdb, 0x6c, 0xd6, 0xeb, 0x8c, 0x72, 0x6a, 0x53, 0x4f, 0x68, 0xdd, 0xa2, 0x21, 0xef, - 0xbd, 0x47, 0x9e, 0xa5, 0x21, 0xc7, 0x12, 0x23, 0x8a, 0xd5, 0x0e, 0xe1, 0x5b, 0xd4, 0xe9, 0x2d, - 0x56, 0xd7, 0x25, 0x14, 0x2b, 0xac, 0x90, 0x14, 0x58, 0x7c, 0x4b, 0x99, 0x97, 0x48, 0xaa, 0x5b, - 0x7c, 0x0b, 0x4b, 0x8c, 0xf9, 0xa1, 0x01, 0x63, 0xaa, 0x98, 0x41, 0x2f, 0x43, 0xde, 0x76, 0x1d, - 0xa6, 0xe2, 0xeb, 0x88, 0xe5, 0x53, 0xa2, 0x64, 0xb9, 0x76, 0x15, 0x63, 0x29, 0x10, 0xbd, 0x06, - 0xa3, 0xe4, 0xba, 0x4d, 0x02, 0xae, 0xee, 0x90, 0x23, 0x8a, 0x4e, 0x56, 0xb9, 0x22, 0x85, 0x61, - 0x25, 0xd4, 0xfc, 0xb7, 0x01, 0xa8, 0x56, 0xff, 0xfc, 0x5e, 0x93, 0x2d, 0x28, 0xc8, 0x0d, 0x42, - 0x0f, 0xc2, 0x88, 0x1b, 0xc8, 0xb5, 0x4e, 0x54, 0x67, 0xf6, 0xf7, 0xe6, 0x47, 0x6a, 0xf5, 0xec, - 0xf5, 0x31, 0xe2, 0x06, 0xa2, 0x62, 0x0d, 0x18, 0x69, 0xb9, 0xd7, 0xd7, 0x88, 0xdf, 0xe6, 0x5b, - 0xd2, 0x83, 0x0a, 0x69, 0x75, 0x55, 0xd7, 0x70, 0x38, 0x43, 0x69, 0xfe, 0xd6, 0x00, 0x58, 0xbb, - 0x9c, 0xb8, 0xe9, 0x2b, 0x90, 0xdf, 0xe2, 0x3c, 0x38, 0xea, 0x75, 0xac, 0xbb, 0x7c, 0x74, 0x4b, - 0x08, 0x08, 0x96, 0x32, 0xd1, 0x4b, 0x90, 0xe3, 0x5e, 0xa8, 0x2e, 0xe1, 0xa1, 0x33, 0x7c, 0x73, - 0xad, 0x91, 0x48, 0x96, 0x17, 0x7d, 0x73, 0xad, 0x81, 0x85, 0x40, 0xf3, 0x97, 0x06, 0xa0, 0xf5, - 0xae, 0x27, 0x9a, 0xa7, 0x90, 0xcb, 0xed, 0xab, 0xf9, 0x2d, 0x8a, 0x1e, 0x84, 0x82, 0xac, 0x23, - 0x55, 0xc8, 0x25, 0xd7, 0x62, 0x74, 0x28, 0x11, 0x0e, 0xbd, 0x0e, 0xf9, 0x80, 0x3a, 0x47, 0x1e, - 0x31, 0x66, 0xd2, 0x4f, 0x1a, 0x8a, 0xd4, 0x09, 0xb1, 0x94, 0x6b, 0xbe, 0x67, 0x40, 0x31, 0xb9, - 0x9a, 0x65, 0xe8, 0x52, 0x16, 0x5d, 0x02, 0x05, 0x9d, 0x9e, 0x71, 0x2c, 0x31, 0xb7, 0x71, 0x39, - 0x5d, 0x81, 0xf1, 0x40, 0xed, 0x83, 0xba, 0x02, 0xee, 0x4f, 0xba, 0x71, 0x05, 0xbf, 0xa9, 0xfd, - 0xc7, 0x09, 0xb5, 0xf9, 0xf7, 0x1c, 0x4c, 0x6e, 0x10, 0xfe, 0x16, 0x65, 0xdb, 0x75, 0xea, 0xb9, - 0xf6, 0xee, 0x29, 0x44, 0x53, 0x0b, 0x0a, 0xac, 0xeb, 0x91, 0x78, 0x83, 0x97, 0x86, 0xce, 0x3b, - 0xba, 0xbd, 0xb8, 0xeb, 0x91, 0xf4, 0x1c, 0xc5, 0x53, 0x88, 0x23, 0xf1, 0xe8, 0x69, 0x38, 0x6b, - 0x65, 0xa6, 0x4e, 0x51, 0xca, 0x2d, 0xca, 0x90, 0x39, 0x9b, 0x1d, 0x48, 0x85, 0xb8, 0x97, 0x16, - 0x5d, 0x12, 0x9b, 0xea, 0x52, 0x26, 0x8a, 0x04, 0xd1, 0xed, 0x19, 0xd5, 0x89, 0x68, 0x43, 0x23, - 0x18, 0x4e, 0xb0, 0xe8, 0x51, 0x98, 0xe0, 0x2e, 0x61, 0x31, 0x46, 0xe6, 0xd3, 0x42, 0x75, 0x5a, - 0xf6, 0x85, 0x1a, 0x1c, 0x67, 0xa8, 0x50, 0x08, 0xc5, 0x90, 0x76, 0x99, 0x4c, 0x70, 0x2a, 0x45, - 0x5e, 0x3b, 0xde, 0x56, 0x24, 0x5e, 0x37, 0x29, 0x12, 0x5d, 0x23, 0x16, 0x8e, 0x53, 0x3d, 0xe6, - 0x1f, 0x0d, 0x38, 0x97, 0x61, 0x3a, 0x85, 0xd6, 0x69, 0x33, 0xdb, 0x3a, 0x3d, 0x7d, 0xac, 0x45, - 0x0e, 0x68, 0x9e, 0xfe, 0x61, 0xc0, 0xf9, 0x0c, 0x9d, 0xa8, 0x44, 0x1a, 0xdc, 0xe2, 0xdd, 0x10, - 0x3d, 0x0c, 0xe3, 0xa2, 0x22, 0xd9, 0x38, 0x60, 0xb2, 0xb5, 0xa1, 0xe0, 0x38, 0xa1, 0x10, 0xed, - 0xba, 0x7a, 0xa3, 0xe3, 0x52, 0x5f, 0xc6, 0x9c, 0xd6, 0xae, 0xaf, 0x26, 0x18, 0xac, 0x51, 0xa1, - 0x6f, 0x02, 0x62, 0xc4, 0xf2, 0xdc, 0xb7, 0xe5, 0xe3, 0x35, 0xcb, 0xf5, 0xba, 0x8c, 0xc8, 0x48, - 0x1c, 0xaf, 0xde, 0xab, 0x78, 0x11, 0xee, 0xa3, 0xc0, 0x07, 0x70, 0xa1, 0x2f, 0xc3, 0x58, 0x87, - 0x84, 0xa1, 0x68, 0xfb, 0xf3, 0xd2, 0xd8, 0xb3, 0x4a, 0xc0, 0xd8, 0x7a, 0x04, 0xc6, 0x31, 0x5e, - 0xbe, 0xa9, 0xc8, 0x2c, 0xba, 0x4e, 0x08, 0x43, 0x97, 0x61, 0xd2, 0xd2, 0x5e, 0x5f, 0x84, 0xb3, - 0x86, 0x74, 0xfa, 0x73, 0xfb, 0x7b, 0xf3, 0x93, 0xfa, 0x7b, 0x8d, 0x10, 0x67, 0xe9, 0x10, 0x81, - 0x71, 0x37, 0x50, 0x93, 0x95, 0xe8, 0xa8, 0x2e, 0x0f, 0x9f, 0xbf, 0x25, 0x7f, 0xba, 0xc1, 0xc9, - 0x48, 0x25, 0x11, 0x8d, 0xe6, 0xa1, 0xd0, 0x7a, 0xd3, 0xf1, 0xe3, 0x60, 0x2c, 0x8a, 0xb3, 0xbc, - 0xf6, 0xc2, 0xd5, 0x8d, 0x10, 0x47, 0x70, 0xc4, 0x01, 0x38, 0x55, 0x65, 0x5e, 0x5c, 0xfb, 0x1e, - 0xbf, 0x78, 0xd4, 0x46, 0x2e, 0xb1, 0x6c, 0xac, 0xe9, 0x11, 0xb7, 0x85, 0x67, 0x6d, 0x12, 0xaf, - 0xe6, 0x10, 0x51, 0xa5, 0xbb, 0x72, 0x56, 0x93, 0xbb, 0x34, 0x19, 0xdd, 0x16, 0x6b, 0x59, 0x14, - 0xee, 0xa5, 0x35, 0x3f, 0x35, 0xe0, 0x9e, 0x83, 0xa3, 0x11, 0x3d, 0x06, 0x79, 0x51, 0x08, 0x2a, - 0xdf, 0x7b, 0x20, 0xbe, 0xbf, 0x9b, 0xbb, 0x01, 0xb9, 0xb9, 0x37, 0x9f, 0x3d, 0x41, 0x01, 0xc4, - 0x92, 0x7c, 0xe8, 0x1e, 0x32, 0xc9, 0x13, 0xb9, 0xc3, 0x8a, 0xd8, 0xfc, 0x71, 0x8a, 0xd8, 0x0f, - 0x47, 0x7b, 0x9c, 0x4e, 0xdc, 0xb9, 0xe8, 0x29, 0x28, 0x3a, 0x2e, 0x23, 0xb6, 0x0c, 0x9a, 0x68, - 0xa1, 0x73, 0xb1, 0xb1, 0x57, 0x63, 0xc4, 0x4d, 0xfd, 0x01, 0xa7, 0x0c, 0xc8, 0x86, 0x7c, 0x8b, - 0xd1, 0x8e, 0x2a, 0x03, 0x8e, 0x97, 0x10, 0x44, 0x0c, 0xa4, 0x8b, 0xbf, 0xc6, 0x68, 0x07, 0x4b, - 0xe1, 0xe8, 0x35, 0x18, 0xe1, 0x54, 0x8d, 0x6f, 0x4f, 0x40, 0x05, 0x28, 0x15, 0x23, 0x4d, 0x8a, - 0x47, 0x38, 0x15, 0xd1, 0x13, 0x66, 0x7d, 0xf6, 0xf2, 0x11, 0x7d, 0x36, 0x8d, 0x9e, 0xc4, 0x51, - 0x13, 0xd1, 0x72, 0xf0, 0xde, 0x93, 0x67, 0xd2, 0x54, 0xdf, 0x97, 0x99, 0x5e, 0x82, 0x51, 0x2b, - 0x3a, 0x93, 0x51, 0x79, 0x26, 0xcf, 0xc8, 0x41, 0x77, 0x7c, 0x18, 0x8f, 0xdc, 0xe2, 0xb3, 0x02, - 0xe6, 0xa8, 0xaf, 0x09, 0x16, 0xca, 0xe2, 0x80, 0x23, 0x1e, 0xac, 0xa4, 0xa1, 0x27, 0x61, 0x92, - 0xf8, 0xd6, 0xa6, 0x47, 0xd6, 0x68, 0xbb, 0xed, 0xfa, 0xed, 0xd9, 0x31, 0x79, 0xd7, 0xdd, 0xad, - 0x4c, 0x99, 0x5c, 0xd1, 0x91, 0x38, 0x4b, 0x7b, 0x50, 0x5e, 0x1e, 0x1f, 0x22, 0x2f, 0xc7, 0x6e, - 0x5e, 0x1c, 0xe8, 0xe6, 0x6f, 0x42, 0xc9, 0x4b, 0xca, 0xd7, 0x70, 0x16, 0xe4, 0x69, 0x3c, 0x31, - 0xec, 0x69, 0xa4, 0x15, 0x70, 0x3a, 0x79, 0x4d, 0x61, 0x21, 0xd6, 0x75, 0x88, 0x63, 0xf1, 0x68, - 0x5b, 0xde, 0x12, 0xb3, 0xa5, 0x6c, 0x8e, 0x59, 0x53, 0x70, 0x9c, 0x50, 0x98, 0xef, 0xe7, 0x00, - 0x65, 0x3c, 0x4a, 0x64, 0xaa, 0x10, 0xbd, 0x6b, 0xc0, 0xa4, 0xaf, 0x83, 0x55, 0x32, 0x3e, 0xa9, - 0xb2, 0x20, 0x39, 0x9e, 0x2c, 0x3e, 0xab, 0x13, 0x05, 0x30, 0xc1, 0x99, 0xd5, 0x6a, 0xb9, 0xb6, - 0xb4, 0x4a, 0x05, 0xe5, 0xe3, 0xb7, 0xb0, 0x41, 0x7e, 0x13, 0x52, 0x8e, 0xbf, 0x09, 0x29, 0x37, - 0x35, 0x6e, 0x6d, 0x42, 0xae, 0x41, 0x71, 0x46, 0x03, 0x7a, 0xc7, 0x80, 0x69, 0x51, 0xb2, 0xe9, - 0x24, 0x6a, 0xe8, 0xf7, 0xc4, 0xed, 0xab, 0xc5, 0x3d, 0x12, 0xd2, 0xd6, 0xaa, 0x17, 0x83, 0xfb, - 0xb4, 0x99, 0x7f, 0x35, 0x60, 0xa6, 0xef, 0x44, 0xba, 0xa7, 0xf1, 0x72, 0xc5, 0x83, 0x82, 0xa8, - 0x3d, 0xe2, 0x94, 0xbb, 0x7a, 0xac, 0xb3, 0x4e, 0xab, 0x9e, 0xb4, 0x4e, 0x12, 0xb0, 0x10, 0x47, - 0x4a, 0xcc, 0x05, 0x98, 0xcc, 0x8c, 0x6d, 0x0e, 0x9f, 0x65, 0x9a, 0x1f, 0x14, 0x60, 0x3a, 0x96, - 0x1b, 0x36, 0xba, 0x9d, 0x8e, 0xc5, 0x4e, 0xa3, 0x4b, 0xf8, 0x81, 0x01, 0x67, 0x75, 0xc7, 0x74, - 0x93, 0x2d, 0xaa, 0x1e, 0x6b, 0x8b, 0x22, 0xdf, 0x38, 0xaf, 0x74, 0x9f, 0xdd, 0xc8, 0xaa, 0xc0, - 0xbd, 0x3a, 0xd1, 0x6f, 0x0c, 0xb8, 0x3f, 0xd2, 0xa2, 0x5e, 0xbe, 0xf5, 0x70, 0x28, 0x47, 0x3d, - 0x09, 0xa3, 0xfe, 0x5f, 0x19, 0x75, 0xff, 0xd2, 0x2d, 0xf4, 0xe1, 0x5b, 0x5a, 0x83, 0x7e, 0x61, - 0xc0, 0xdd, 0x11, 0x41, 0xaf, 0x9d, 0xf9, 0x13, 0xb3, 0xf3, 0x82, 0xb2, 0xf3, 0xee, 0xa5, 0x83, - 0x14, 0xe1, 0x83, 0xf5, 0x8b, 0x7e, 0xa7, 0x13, 0x77, 0xe4, 0xb2, 0xb4, 0x3a, 0x82, 0x31, 0xfd, - 0x2d, 0x7d, 0x5a, 0x13, 0x25, 0x38, 0x9c, 0xea, 0x31, 0x5f, 0x83, 0xbb, 0xea, 0x56, 0xdb, 0xf5, - 0x65, 0x89, 0xbd, 0x4a, 0xf8, 0xf3, 0x81, 0xf8, 0x13, 0x46, 0x03, 0xb3, 0x76, 0xe4, 0xf6, 0x39, - 0x7d, 0x60, 0xd6, 0x26, 0x58, 0x62, 0xd0, 0x83, 0x50, 0xf0, 0xdc, 0x8e, 0xcb, 0x55, 0x0b, 0x90, - 0x84, 0xd3, 0x9a, 0x00, 0xe2, 0x08, 0x67, 0x5a, 0x30, 0xa1, 0xb7, 0xfb, 0x77, 0xe2, 0xcd, 0xc0, - 0xef, 0x72, 0x10, 0xcf, 0x3c, 0xd1, 0xa3, 0x5a, 0x9f, 0x1f, 0xa9, 0x98, 0x3d, 0xbc, 0xc7, 0x47, - 0x1b, 0x6a, 0xc2, 0x30, 0x72, 0x48, 0x9c, 0x76, 0xb9, 0xeb, 0x95, 0xa3, 0x8f, 0xda, 0xca, 0x35, - 0x9f, 0x3f, 0xcf, 0x1a, 0x9c, 0xb9, 0x7e, 0x3b, 0x9a, 0xd9, 0x68, 0xf3, 0x88, 0x2f, 0xc1, 0x18, - 0xf1, 0xe5, 0xf0, 0x42, 0x56, 0x53, 0x85, 0x68, 0x2e, 0xbb, 0x12, 0x81, 0x70, 0x8c, 0x13, 0xfd, - 0xb3, 0x6b, 0x77, 0x02, 0x51, 0xd1, 0xca, 0x8a, 0xb3, 0x10, 0xf5, 0xcf, 0xb5, 0xe5, 0xf5, 0xba, - 0xac, 0x72, 0x13, 0x6c, 0x4c, 0xb9, 0x1c, 0xcf, 0xa2, 0x35, 0x4a, 0x01, 0xc3, 0x09, 0x56, 0x52, - 0xb6, 0x95, 0xcc, 0x51, 0x8d, 0x72, 0x35, 0x91, 0xa9, 0xb0, 0xe8, 0x8a, 0x7a, 0x31, 0xa9, 0x3a, - 0x1e, 0x59, 0xa0, 0x14, 0x7b, 0xde, 0x2d, 0xc6, 0xd3, 0xb2, 0x0c, 0xa5, 0x58, 0x5e, 0xc8, 0x6c, - 0xb9, 0xbc, 0xf1, 0x74, 0x79, 0x8d, 0x08, 0x84, 0x63, 0x1c, 0x2a, 0x03, 0x84, 0xcc, 0x56, 0xab, - 0x96, 0xc5, 0x48, 0xa1, 0x3a, 0x25, 0x6e, 0xb3, 0x46, 0x02, 0xc5, 0x1a, 0x85, 0x49, 0x60, 0xba, - 0xb7, 0x27, 0xb9, 0x13, 0xee, 0xf2, 0x7e, 0x1e, 0xce, 0x37, 0xba, 0x81, 0x38, 0xa8, 0xe8, 0xf3, - 0x89, 0x65, 0xea, 0x79, 0xaa, 0xcc, 0xbe, 0xf3, 0x97, 0xf6, 0xab, 0x50, 0x24, 0xd7, 0x03, 0x97, - 0x11, 0x67, 0x29, 0xf6, 0xb7, 0xaf, 0xdc, 0x9e, 0x8a, 0xa6, 0xdb, 0x21, 0xe9, 0xd2, 0x56, 0x62, - 0x21, 0x38, 0x95, 0x27, 0xf6, 0x22, 0x74, 0x7d, 0x9b, 0x08, 0x52, 0xd5, 0xe4, 0x24, 0x0c, 0x8d, - 0x18, 0x81, 0x53, 0x1a, 0xd1, 0x48, 0xb6, 0x92, 0x0f, 0x4e, 0xa4, 0x0f, 0x1e, 0xa1, 0x91, 0xec, - 0xfd, 0x70, 0x25, 0xdd, 0x81, 0x14, 0x86, 0x35, 0x3d, 0xe8, 0x27, 0x06, 0x4c, 0x59, 0xd9, 0x6f, - 0x46, 0xa2, 0x17, 0x2c, 0xeb, 0x47, 0x53, 0x3d, 0xe0, 0xfb, 0x97, 0xea, 0x3d, 0xca, 0x8e, 0xa9, - 0x9e, 0x8f, 0x47, 0x7a, 0x94, 0x9b, 0x9f, 0x19, 0x70, 0xdf, 0x00, 0x8f, 0x38, 0x85, 0xe1, 0x8f, - 0x97, 0x1d, 0xfe, 0x0c, 0x5d, 0xde, 0x0c, 0xb0, 0x7c, 0xc0, 0x18, 0xe8, 0xe7, 0x23, 0xf0, 0xc0, - 0x00, 0x8e, 0x23, 0x0f, 0x84, 0x9e, 0x84, 0xc9, 0xf8, 0xbf, 0x1e, 0x86, 0x69, 0x31, 0xad, 0x23, - 0x71, 0x96, 0x36, 0x56, 0x25, 0x2f, 0xac, 0x5c, 0xbf, 0xaa, 0xe8, 0xd2, 0x8a, 0x29, 0x84, 0x87, - 0xdb, 0xb4, 0x13, 0x78, 0x84, 0x93, 0xa8, 0x4b, 0x1f, 0x4f, 0x3d, 0x7c, 0x39, 0x46, 0xe0, 0x94, - 0x46, 0x24, 0x29, 0xc2, 0x18, 0x65, 0xd2, 0xc3, 0xb4, 0x79, 0xf6, 0x8a, 0x00, 0xe2, 0x08, 0x67, - 0xfe, 0xd3, 0x80, 0x0b, 0x03, 0x36, 0xe5, 0xd4, 0xaa, 0xdc, 0x9d, 0x6c, 0x95, 0xfb, 0xc2, 0x09, - 0xb9, 0xc1, 0xa1, 0xf5, 0xee, 0xc3, 0x50, 0xd2, 0x5e, 0x12, 0xa0, 0x0b, 0x90, 0x0b, 0x7d, 0xb7, - 0xf7, 0xa3, 0xb3, 0xc6, 0x46, 0x0d, 0x0b, 0x78, 0xb5, 0xf9, 0xd1, 0x8d, 0xb9, 0x33, 0x1f, 0xdf, - 0x98, 0x3b, 0xf3, 0xc9, 0x8d, 0xb9, 0x33, 0xef, 0xec, 0xcf, 0x19, 0x1f, 0xed, 0xcf, 0x19, 0x1f, - 0xef, 0xcf, 0x19, 0x9f, 0xec, 0xcf, 0x19, 0x7f, 0xde, 0x9f, 0x33, 0x7e, 0xf6, 0x97, 0xb9, 0x33, - 0xaf, 0x94, 0x87, 0xfb, 0x1a, 0xff, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xdf, 0x8d, 0x27, 0x1b, - 0xbe, 0x2f, 0x00, 0x00, + // 2862 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x1b, 0x4b, 0x6f, 0x24, 0xc5, + 0x79, 0xdb, 0x33, 0x63, 0x7b, 0xbe, 0x19, 0x7b, 0xbd, 0x65, 0x60, 0x1d, 0x60, 0xed, 0xa5, 0x49, + 0xd0, 0x26, 0x22, 0x33, 0xd8, 0x01, 0x76, 0xc3, 0x4b, 0xf1, 0x78, 0xbd, 0x66, 0x82, 0x6d, 0x86, + 0x9a, 0x01, 0x24, 0x08, 0x84, 0x76, 0x77, 0xcd, 0xb8, 0xb3, 0x3d, 0x5d, 0x4d, 0x75, 0x8d, 0x59, + 0x73, 0x88, 0x88, 0x48, 0x0e, 0xe4, 0x45, 0x94, 0x4b, 0xc4, 0x2d, 0xb7, 0x5c, 0xf2, 0x0b, 0x38, + 0x85, 0x43, 0x24, 0x8e, 0x44, 0x51, 0x14, 0x4e, 0x56, 0xd6, 0x51, 0x88, 0x38, 0xe4, 0x92, 0x5b, + 0x36, 0x8a, 0x14, 0x55, 0x75, 0xf5, 0x73, 0x66, 0xd6, 0x3b, 0xb6, 0xd7, 0x91, 0xc2, 0x9e, 0x3c, + 0xfd, 0xbd, 0xab, 0xea, 0xfb, 0xea, 0x7b, 0x74, 0x1b, 0x9e, 0x31, 0x5c, 0xce, 0x88, 0x51, 0xb1, + 0x69, 0x35, 0xf8, 0x55, 0xf5, 0xae, 0x76, 0xaa, 0x86, 0x67, 0xfb, 0x55, 0x93, 0xba, 0x9c, 0x51, + 0xc7, 0x73, 0x0c, 0x97, 0x54, 0x77, 0x16, 0xb7, 0x08, 0x37, 0x96, 0xaa, 0x1d, 0xe2, 0x12, 0x66, + 0x70, 0x62, 0x55, 0x3c, 0x46, 0x39, 0x45, 0x95, 0x80, 0xeb, 0xbb, 0x36, 0x55, 0xbf, 0x2a, 0xde, + 0xd5, 0x4e, 0x45, 0xf0, 0x57, 0x92, 0xfc, 0x15, 0xc5, 0x7f, 0xef, 0xa5, 0xe1, 0xfa, 0x7c, 0x6e, + 0x70, 0xbf, 0xba, 0xb3, 0x68, 0x38, 0xde, 0xb6, 0xb1, 0x98, 0xd5, 0x74, 0xef, 0xd7, 0x3b, 0x36, + 0xdf, 0xee, 0x6d, 0x55, 0x4c, 0xda, 0xad, 0x76, 0x68, 0x87, 0x56, 0x25, 0x78, 0xab, 0xd7, 0x96, + 0x4f, 0xf2, 0x41, 0xfe, 0x52, 0xe4, 0x8f, 0x5e, 0xbd, 0xe4, 0x4b, 0x2d, 0x9e, 0xdd, 0x35, 0xcc, + 0x6d, 0xdb, 0x25, 0x6c, 0x37, 0xd6, 0xd5, 0x25, 0xdc, 0xa8, 0xee, 0xf4, 0x2b, 0xa9, 0x0e, 0xe3, + 0x62, 0x3d, 0x97, 0xdb, 0x5d, 0xd2, 0xc7, 0xf0, 0xf8, 0x41, 0x0c, 0xbe, 0xb9, 0x4d, 0xba, 0x46, + 0x1f, 0xdf, 0x37, 0x86, 0xf1, 0xf5, 0xb8, 0xed, 0x54, 0x6d, 0x97, 0xfb, 0x9c, 0x65, 0x99, 0xf4, + 0xbf, 0x6b, 0x50, 0x5e, 0xb6, 0x2c, 0x46, 0x7c, 0x7f, 0x8d, 0xd1, 0x9e, 0x87, 0xde, 0x80, 0x49, + 0xb1, 0x12, 0xcb, 0xe0, 0xc6, 0x9c, 0x76, 0x5e, 0xbb, 0x50, 0x5a, 0x7a, 0xa4, 0x12, 0x08, 0xae, + 0x24, 0x05, 0xc7, 0x67, 0x22, 0xa8, 0x2b, 0x3b, 0x8b, 0x95, 0xe7, 0xb7, 0xbe, 0x47, 0x4c, 0xbe, + 0x41, 0xb8, 0x51, 0x43, 0x1f, 0xef, 0x2d, 0x9c, 0xda, 0xdf, 0x5b, 0x80, 0x18, 0x86, 0x23, 0xa9, + 0xa8, 0x07, 0xe5, 0x8e, 0x50, 0xb5, 0x41, 0xba, 0x5b, 0x84, 0xf9, 0x73, 0x63, 0xe7, 0x73, 0x17, + 0x4a, 0x4b, 0x4f, 0x8e, 0x78, 0xec, 0x95, 0xb5, 0x58, 0x46, 0xed, 0x2e, 0xa5, 0xb0, 0x9c, 0x00, + 0xfa, 0x38, 0xa5, 0x46, 0xff, 0xa3, 0x06, 0x33, 0xc9, 0x95, 0xae, 0xdb, 0x3e, 0x47, 0xdf, 0xe9, + 0x5b, 0x6d, 0xe5, 0xd6, 0x56, 0x2b, 0xb8, 0xe5, 0x5a, 0x67, 0x94, 0xea, 0xc9, 0x10, 0x92, 0x58, + 0xa9, 0x01, 0x05, 0x9b, 0x93, 0x6e, 0xb8, 0xc4, 0xa7, 0x46, 0x5d, 0x62, 0xd2, 0xdc, 0xda, 0x94, + 0x52, 0x54, 0xa8, 0x0b, 0x91, 0x38, 0x90, 0xac, 0xbf, 0x97, 0x83, 0x33, 0x49, 0xb2, 0x86, 0xc1, + 0xcd, 0xed, 0x13, 0x38, 0xc4, 0x1f, 0x6a, 0x70, 0xc6, 0xb0, 0x2c, 0x62, 0xad, 0x1d, 0xf3, 0x51, + 0x7e, 0x49, 0xa9, 0x15, 0xab, 0x4a, 0x4b, 0xc7, 0xfd, 0x0a, 0xd1, 0x8f, 0x35, 0x98, 0x65, 0xa4, + 0x4b, 0x77, 0x32, 0x86, 0xe4, 0x8e, 0x6e, 0xc8, 0x7d, 0xca, 0x90, 0x59, 0xdc, 0x2f, 0x1f, 0x0f, + 0x52, 0xaa, 0x7f, 0xae, 0xc1, 0xf4, 0xb2, 0xe7, 0x39, 0x36, 0xb1, 0x5a, 0xf4, 0xff, 0x3c, 0x9a, + 0xfe, 0xac, 0x01, 0x4a, 0xaf, 0xf5, 0x04, 0xe2, 0xc9, 0x4c, 0xc7, 0xd3, 0x33, 0x23, 0xc7, 0x53, + 0xca, 0xe0, 0x21, 0x11, 0xf5, 0x93, 0x1c, 0xcc, 0xa6, 0x09, 0xef, 0xc4, 0xd4, 0xff, 0x2e, 0xa6, + 0xde, 0x84, 0xd9, 0x9a, 0xe1, 0xdb, 0xe6, 0x72, 0x8f, 0x6f, 0x13, 0x97, 0xdb, 0xa6, 0xc1, 0x6d, + 0xea, 0xa2, 0x87, 0x61, 0xb2, 0xe7, 0x13, 0xe6, 0x1a, 0x5d, 0x22, 0x0f, 0xa3, 0x18, 0xfb, 0xcd, + 0x8b, 0x0a, 0x8e, 0x23, 0x0a, 0x41, 0xed, 0x19, 0xbe, 0xff, 0x16, 0x65, 0xd6, 0xdc, 0x58, 0x9a, + 0xba, 0xa1, 0xe0, 0x38, 0xa2, 0xd0, 0x17, 0x61, 0xa6, 0xd6, 0x73, 0x2d, 0x87, 0x5c, 0xb1, 0x1d, + 0xd2, 0x24, 0x6c, 0x87, 0x30, 0x74, 0x0e, 0x72, 0x3d, 0xe6, 0x28, 0x55, 0x25, 0xc5, 0x9c, 0x7b, + 0x11, 0xaf, 0x63, 0x01, 0xd7, 0xdf, 0x1f, 0x83, 0x73, 0x01, 0x4f, 0x40, 0x2f, 0xac, 0x5d, 0xa1, + 0x6e, 0xdb, 0xee, 0xf4, 0x58, 0x60, 0xf0, 0x63, 0x50, 0xda, 0x22, 0x06, 0x23, 0xac, 0x45, 0xaf, + 0x12, 0x57, 0x09, 0x9a, 0x55, 0x82, 0x4a, 0xb5, 0x18, 0x85, 0x93, 0x74, 0xe8, 0x21, 0x18, 0x37, + 0x3c, 0xfb, 0x39, 0xb2, 0xab, 0xec, 0x9e, 0x56, 0x1c, 0xe3, 0xcb, 0x8d, 0xfa, 0x73, 0x64, 0x17, + 0x2b, 0x2c, 0xfa, 0xb9, 0x06, 0xb3, 0x5b, 0xfd, 0xfb, 0x34, 0x97, 0x93, 0x8e, 0xba, 0x32, 0xea, + 0x99, 0x0d, 0xd8, 0xf2, 0xda, 0x59, 0x71, 0x6e, 0x03, 0x10, 0x78, 0x90, 0x62, 0xfd, 0xd7, 0x79, + 0x98, 0x5d, 0x71, 0x7a, 0x3e, 0x27, 0x2c, 0xe5, 0x5c, 0xb7, 0x3f, 0x8a, 0x7e, 0xa0, 0xc1, 0x0c, + 0x69, 0xb7, 0x89, 0xc9, 0xed, 0x1d, 0x72, 0x8c, 0x41, 0x34, 0xa7, 0xb4, 0xce, 0xac, 0x66, 0x84, + 0xe3, 0x3e, 0x75, 0xe8, 0xfb, 0x70, 0x26, 0x82, 0xd5, 0x1b, 0x35, 0x87, 0x9a, 0x57, 0xc3, 0xf8, + 0x79, 0x6c, 0x54, 0x1b, 0xea, 0x8d, 0x4d, 0xc2, 0xe3, 0x10, 0x5e, 0xcd, 0xca, 0xc5, 0xfd, 0xaa, + 0xd0, 0x25, 0x28, 0x73, 0xca, 0x0d, 0x27, 0x5c, 0x7e, 0xfe, 0xbc, 0x76, 0x21, 0x17, 0xdf, 0xeb, + 0xad, 0x04, 0x0e, 0xa7, 0x28, 0xd1, 0x12, 0x80, 0x7c, 0x6e, 0x18, 0x1d, 0xe2, 0xcf, 0x15, 0x24, + 0x5f, 0xb4, 0xdf, 0xad, 0x08, 0x83, 0x13, 0x54, 0xc2, 0xb7, 0xcd, 0x1e, 0x63, 0xc4, 0xe5, 0xe2, + 0x79, 0x6e, 0x5c, 0x32, 0x45, 0xbe, 0xbd, 0x12, 0xa3, 0x70, 0x92, 0x4e, 0xff, 0x4c, 0x83, 0xd2, + 0x6a, 0xe7, 0x0b, 0x50, 0x79, 0xfe, 0x41, 0x83, 0xd3, 0x89, 0x85, 0x9e, 0x40, 0xa2, 0x7c, 0x23, + 0x9d, 0x28, 0x47, 0x5e, 0x61, 0xc2, 0xda, 0x21, 0x59, 0xf2, 0xa7, 0x39, 0x98, 0x49, 0x50, 0x05, + 0x29, 0xd2, 0x02, 0xa0, 0xd1, 0xbe, 0x1f, 0xeb, 0x19, 0x26, 0xe4, 0xde, 0x49, 0x93, 0x03, 0xd2, + 0xa4, 0x03, 0x67, 0x57, 0xaf, 0x71, 0x91, 0xee, 0x9c, 0x55, 0x97, 0xdb, 0x7c, 0x17, 0x93, 0x36, + 0x61, 0xc4, 0x35, 0x09, 0x3a, 0x0f, 0xf9, 0x44, 0x9a, 0x2c, 0x2b, 0xd1, 0xf9, 0x4d, 0x91, 0x22, + 0x25, 0x06, 0x55, 0xa1, 0x28, 0xfe, 0xfa, 0x9e, 0x61, 0x12, 0x95, 0x67, 0xce, 0x28, 0xb2, 0xe2, + 0x66, 0x88, 0xc0, 0x31, 0x8d, 0xfe, 0x6f, 0x0d, 0x66, 0xa4, 0xfa, 0x65, 0xdf, 0xa7, 0xa6, 0x1d, + 0x64, 0xb8, 0x13, 0xa9, 0x8f, 0x66, 0x0c, 0xa5, 0x51, 0xad, 0xff, 0xd0, 0xa5, 0xa0, 0xe4, 0x8e, + 0x36, 0x29, 0xbe, 0xdc, 0x97, 0x33, 0xf2, 0x71, 0x9f, 0x46, 0xfd, 0xc3, 0x3c, 0x94, 0x12, 0x9b, + 0x8f, 0x5e, 0x86, 0x9c, 0x47, 0x2d, 0xb5, 0xe6, 0x91, 0x7b, 0xbc, 0x06, 0xb5, 0x62, 0x33, 0x26, + 0x44, 0x55, 0x21, 0x20, 0x42, 0x22, 0x7a, 0x57, 0x83, 0x69, 0x92, 0x3a, 0x55, 0x79, 0x3a, 0xa5, + 0xa5, 0xb5, 0x91, 0xe3, 0x79, 0xb0, 0x6f, 0xd4, 0xd0, 0xfe, 0xde, 0xc2, 0x74, 0x06, 0x99, 0x51, + 0x89, 0x1e, 0x82, 0x9c, 0xed, 0x05, 0x6e, 0x5d, 0xae, 0xdd, 0x25, 0x0c, 0xac, 0x37, 0xfc, 0x1b, + 0x7b, 0x0b, 0xc5, 0x7a, 0x43, 0x35, 0x9e, 0x58, 0x10, 0xa0, 0xd7, 0xa1, 0xe0, 0x51, 0xc6, 0x45, + 0xb2, 0x11, 0x27, 0xf2, 0xcd, 0x51, 0x6d, 0x14, 0x9e, 0x66, 0x35, 0x28, 0xe3, 0xf1, 0x8d, 0x23, + 0x9e, 0x7c, 0x1c, 0x88, 0x45, 0xaf, 0x42, 0xde, 0xa5, 0x16, 0x91, 0x39, 0xa9, 0xb4, 0xf4, 0xf4, + 0xc8, 0xe2, 0xa9, 0x45, 0xe2, 0x85, 0x4f, 0xca, 0x10, 0x10, 0x20, 0x29, 0x14, 0x75, 0x60, 0xc2, + 0x27, 0x6c, 0xc7, 0x36, 0x83, 0xf4, 0x55, 0x5a, 0xfa, 0xd6, 0xa8, 0xf2, 0x9b, 0x01, 0x7b, 0xac, + 0xa2, 0xb4, 0xbf, 0xb7, 0x30, 0x11, 0x42, 0x43, 0xe9, 0xfa, 0x07, 0x79, 0x28, 0xdf, 0x29, 0x88, + 0xee, 0x14, 0x44, 0x83, 0x0a, 0xa2, 0xdf, 0x68, 0x30, 0x9d, 0xbe, 0x97, 0xd2, 0x57, 0xb3, 0x76, + 0xf0, 0xd5, 0x1c, 0xdd, 0xf6, 0x63, 0x43, 0x6f, 0xfb, 0x1a, 0xe4, 0x7a, 0xb6, 0x25, 0x3b, 0x83, + 0x62, 0xed, 0x91, 0xa8, 0x95, 0xa9, 0x5f, 0xbe, 0xb1, 0xb7, 0xf0, 0xc0, 0xb0, 0x11, 0x22, 0xdf, + 0xf5, 0x88, 0x5f, 0x79, 0xb1, 0x7e, 0x19, 0x0b, 0x66, 0xfd, 0x6d, 0x28, 0x3f, 0xdb, 0x6a, 0x35, + 0x1a, 0x8c, 0x72, 0x6a, 0x52, 0x47, 0x68, 0xdd, 0xa6, 0x3e, 0xcf, 0xe6, 0x98, 0x67, 0xa9, 0xcf, + 0xb1, 0xc4, 0x88, 0x46, 0xa6, 0x4b, 0xf8, 0x36, 0xb5, 0xb2, 0x8d, 0xcc, 0x86, 0x84, 0x62, 0x85, + 0x15, 0x92, 0x3c, 0x83, 0x6f, 0x2b, 0xf3, 0x22, 0x49, 0x0d, 0x83, 0x6f, 0x63, 0x89, 0xd1, 0x3f, + 0xd2, 0x60, 0x42, 0x9d, 0x2b, 0x7a, 0x19, 0xf2, 0xa6, 0x6d, 0x31, 0x15, 0x38, 0x87, 0xf4, 0xa4, + 0x48, 0xc9, 0x4a, 0xfd, 0x32, 0xc6, 0x52, 0x20, 0x7a, 0x0d, 0xc6, 0xc9, 0x35, 0x93, 0x78, 0x5c, + 0x05, 0xca, 0x21, 0x45, 0x47, 0xab, 0x5c, 0x95, 0xc2, 0xb0, 0x12, 0xaa, 0xff, 0x47, 0x03, 0x54, + 0x6f, 0x7c, 0x71, 0x53, 0x68, 0x1b, 0x0a, 0x72, 0x83, 0xd0, 0x83, 0x30, 0x66, 0x7b, 0x72, 0xad, + 0xe5, 0xda, 0xec, 0xfe, 0xde, 0xc2, 0x58, 0xbd, 0x91, 0x4e, 0x2d, 0x63, 0xb6, 0x27, 0x82, 0xd7, + 0x63, 0xa4, 0x6d, 0x5f, 0x5b, 0x27, 0x6e, 0x87, 0x6f, 0x4b, 0x0f, 0x2a, 0xc4, 0xc1, 0xdb, 0x48, + 0xe0, 0x70, 0x8a, 0x52, 0xff, 0x9d, 0x06, 0xb0, 0x7e, 0x31, 0x72, 0xd3, 0x57, 0x20, 0xbf, 0xcd, + 0xb9, 0x77, 0xd8, 0x54, 0x9d, 0x74, 0xf9, 0x20, 0x83, 0x08, 0x08, 0x96, 0x32, 0xd1, 0x4b, 0x90, + 0xe3, 0x8e, 0xaf, 0x12, 0xf4, 0xc8, 0xf7, 0x6a, 0x6b, 0xbd, 0x19, 0x49, 0x96, 0x45, 0x40, 0x6b, + 0xbd, 0x89, 0x85, 0x40, 0xfd, 0x03, 0x0d, 0xd0, 0x46, 0xcf, 0x11, 0x8d, 0xb5, 0xcf, 0xe5, 0xf6, + 0xd5, 0xdd, 0x36, 0x45, 0x0f, 0x42, 0x41, 0xf6, 0x18, 0x2a, 0xe4, 0xa2, 0x94, 0x19, 0x1c, 0x4a, + 0x80, 0x43, 0xaf, 0x43, 0xde, 0xa3, 0xd6, 0xa1, 0xc7, 0xcf, 0xa9, 0xd2, 0x24, 0x0e, 0x45, 0x6a, + 0xf9, 0x58, 0xca, 0xd5, 0xdf, 0xd3, 0xa0, 0x18, 0xa5, 0x6d, 0x19, 0xba, 0x94, 0x05, 0x97, 0x40, + 0x21, 0x49, 0xcf, 0x38, 0x96, 0x98, 0x5b, 0xb8, 0x9c, 0x2e, 0xc1, 0xa4, 0xa7, 0xf6, 0x41, 0x5d, + 0x01, 0xf7, 0x47, 0x93, 0x1a, 0x05, 0xbf, 0x91, 0xf8, 0x8d, 0x23, 0x6a, 0xfd, 0x1f, 0x39, 0x98, + 0xda, 0x24, 0xfc, 0x2d, 0xca, 0xae, 0x36, 0xa8, 0x63, 0x9b, 0xbb, 0x27, 0x10, 0x4d, 0x6d, 0x28, + 0xb0, 0x9e, 0x43, 0xc2, 0x0d, 0x5e, 0x1e, 0xb9, 0x26, 0x49, 0xda, 0x8b, 0x7b, 0x0e, 0x89, 0xcf, + 0x51, 0x3c, 0xf9, 0x38, 0x10, 0x8f, 0x9e, 0x86, 0xd3, 0x46, 0x6a, 0x22, 0x19, 0xe4, 0xce, 0xa2, + 0x0c, 0x99, 0xd3, 0xe9, 0x61, 0xa5, 0x8f, 0xb3, 0xb4, 0xe8, 0x82, 0xd8, 0x54, 0x9b, 0x32, 0x51, + 0x40, 0x8a, 0xc4, 0xa7, 0xd5, 0xca, 0xc1, 0x86, 0x06, 0x30, 0x1c, 0x61, 0xd1, 0xa3, 0x50, 0xe6, + 0x36, 0x61, 0x21, 0x46, 0xa6, 0xbb, 0x42, 0x6d, 0x46, 0xa6, 0xc8, 0x04, 0x1c, 0xa7, 0xa8, 0x90, + 0x0f, 0x45, 0x9f, 0xf6, 0x98, 0x2c, 0x7e, 0x54, 0xf9, 0x74, 0xe5, 0x68, 0x5b, 0x11, 0x79, 0xdd, + 0x94, 0x48, 0x74, 0xcd, 0x50, 0x38, 0x8e, 0xf5, 0xe8, 0x7f, 0xd2, 0xe0, 0x4c, 0x8a, 0xe9, 0x04, + 0xda, 0xea, 0xad, 0x74, 0x5b, 0xfd, 0xf4, 0x91, 0x16, 0x39, 0xa4, 0xb1, 0xfe, 0xa7, 0x06, 0x67, + 0x53, 0x74, 0xa2, 0x4a, 0x6d, 0x72, 0x83, 0xf7, 0x7c, 0xf4, 0x30, 0x4c, 0x8a, 0x6a, 0x75, 0x73, + 0xc0, 0xd4, 0x73, 0x53, 0xc1, 0x71, 0x44, 0x21, 0x2a, 0x17, 0xf5, 0xb6, 0xcf, 0xa6, 0xae, 0x8c, + 0xb9, 0x44, 0xe5, 0xb2, 0x16, 0x61, 0x70, 0x82, 0x0a, 0x7d, 0x1b, 0x10, 0x23, 0x86, 0x63, 0xbf, + 0x2d, 0x1f, 0xaf, 0x18, 0xb6, 0xd3, 0x63, 0x44, 0x46, 0xe2, 0x64, 0xed, 0x5e, 0xc5, 0x8b, 0x70, + 0x1f, 0x05, 0x1e, 0xc0, 0x85, 0xbe, 0x0a, 0x13, 0x5d, 0xe2, 0xfb, 0xa2, 0x02, 0xca, 0x4b, 0x63, + 0x4f, 0x2b, 0x01, 0x13, 0x1b, 0x01, 0x18, 0x87, 0x78, 0xf9, 0x16, 0x2b, 0xb5, 0xe8, 0x06, 0x21, + 0x0c, 0x5d, 0x84, 0x29, 0x23, 0xf1, 0x6a, 0xcb, 0x9f, 0xd3, 0xa4, 0xd3, 0x9f, 0xd9, 0xdf, 0x5b, + 0x98, 0x4a, 0xbe, 0xf3, 0xf2, 0x71, 0x9a, 0x0e, 0x11, 0x98, 0xb4, 0x3d, 0x55, 0x64, 0x06, 0x47, + 0x75, 0x71, 0xf4, 0xfc, 0x2d, 0xf9, 0xe3, 0x0d, 0x8e, 0xaa, 0xcb, 0x48, 0x34, 0x5a, 0x80, 0x42, + 0xfb, 0x4d, 0xcb, 0x0d, 0x83, 0xb1, 0x28, 0xce, 0xf2, 0xca, 0x0b, 0x97, 0x37, 0x7d, 0x1c, 0xc0, + 0x11, 0x17, 0xb5, 0xa3, 0x6a, 0x01, 0xc2, 0xbe, 0xe8, 0xe8, 0x8d, 0x45, 0xa2, 0xfa, 0x0c, 0x65, + 0xe3, 0x84, 0x1e, 0x71, 0x5b, 0x38, 0xc6, 0x16, 0x71, 0xea, 0x16, 0x11, 0x1d, 0x9c, 0x2d, 0xcb, + 0xd6, 0xdc, 0x85, 0xa9, 0xe0, 0xb6, 0x58, 0x4f, 0xa3, 0x70, 0x96, 0x56, 0xff, 0x4c, 0x83, 0x7b, + 0x06, 0x47, 0x23, 0x7a, 0x0c, 0xf2, 0xa2, 0x10, 0x54, 0xbe, 0xf7, 0x40, 0x78, 0x7f, 0xb7, 0x76, + 0x3d, 0x72, 0x63, 0x6f, 0x21, 0x7d, 0x82, 0x02, 0x88, 0x25, 0xf9, 0xc8, 0xf3, 0x85, 0x28, 0x4f, + 0xe4, 0x0e, 0x2a, 0x62, 0xf3, 0x47, 0x29, 0x62, 0x3f, 0x1a, 0xcf, 0x38, 0x9d, 0xb8, 0x73, 0xd1, + 0x53, 0x50, 0xb4, 0x6c, 0x26, 0xda, 0x07, 0x1a, 0x8e, 0xe9, 0xe7, 0x43, 0x63, 0x2f, 0x87, 0x88, + 0x1b, 0xc9, 0x07, 0x1c, 0x33, 0x20, 0x13, 0xf2, 0x6d, 0x46, 0xbb, 0xaa, 0x0c, 0x38, 0x5a, 0x42, + 0x10, 0x31, 0x10, 0x2f, 0xfe, 0x0a, 0xa3, 0x5d, 0x2c, 0x85, 0xa3, 0xd7, 0x60, 0x8c, 0x53, 0x35, + 0xda, 0x3f, 0x06, 0x15, 0xa0, 0x54, 0x8c, 0xb5, 0x28, 0x1e, 0xe3, 0x54, 0x44, 0x8f, 0x9f, 0xf6, + 0xd9, 0x8b, 0x87, 0xf4, 0xd9, 0x38, 0x7a, 0x22, 0x47, 0x8d, 0x44, 0xcb, 0x97, 0x32, 0x99, 0x3c, + 0x13, 0xa7, 0xfa, 0xbe, 0xcc, 0xf4, 0x12, 0x8c, 0x1b, 0xc1, 0x99, 0x8c, 0xcb, 0x33, 0x79, 0x46, + 0xbe, 0x04, 0x09, 0x0f, 0xe3, 0x91, 0x9b, 0x7c, 0x72, 0xc2, 0x2c, 0xf5, 0xa5, 0xc9, 0x62, 0x45, + 0x1c, 0x70, 0xc0, 0x83, 0x95, 0x34, 0xf4, 0x24, 0x4c, 0x11, 0xd7, 0xd8, 0x72, 0xc8, 0x3a, 0xed, + 0x74, 0x6c, 0xb7, 0x33, 0x37, 0x21, 0xef, 0xba, 0xbb, 0x95, 0x29, 0x53, 0xab, 0x49, 0x24, 0x4e, + 0xd3, 0x0e, 0xca, 0xcb, 0x93, 0x23, 0xe4, 0xe5, 0xd0, 0xcd, 0x8b, 0x43, 0xdd, 0xfc, 0x4d, 0x28, + 0x39, 0x51, 0xf9, 0xea, 0xcf, 0x81, 0x3c, 0x8d, 0x27, 0x46, 0x3d, 0x8d, 0xb8, 0x02, 0x8e, 0x9b, + 0xd0, 0x18, 0xe6, 0xe3, 0xa4, 0x0e, 0x71, 0x2c, 0x0e, 0xed, 0xc8, 0x5b, 0x62, 0xae, 0x94, 0xce, + 0x31, 0xeb, 0x0a, 0x8e, 0x23, 0x0a, 0xfd, 0xfd, 0x1c, 0xa0, 0x94, 0x47, 0x89, 0x4c, 0xe5, 0xa3, + 0x77, 0x35, 0x98, 0x72, 0x93, 0x60, 0x95, 0x8c, 0x8f, 0xab, 0x2c, 0x88, 0x8e, 0x27, 0x8d, 0x4f, + 0xeb, 0x44, 0x1e, 0x94, 0x39, 0x33, 0xda, 0x6d, 0xdb, 0x94, 0x56, 0xa9, 0xa0, 0x7c, 0xfc, 0x26, + 0x36, 0xc8, 0xef, 0x85, 0x2a, 0xe1, 0xf7, 0x42, 0x95, 0x56, 0x82, 0x3b, 0x31, 0x2c, 0x48, 0x40, + 0x71, 0x4a, 0x03, 0x7a, 0x47, 0x83, 0x19, 0x51, 0xb2, 0x25, 0x49, 0xd4, 0x98, 0xe3, 0x89, 0x5b, + 0x57, 0x8b, 0x33, 0x12, 0xe2, 0xd6, 0x2a, 0x8b, 0xc1, 0x7d, 0xda, 0xf4, 0xbf, 0x69, 0x30, 0xdb, + 0x77, 0x22, 0xbd, 0x93, 0x98, 0x33, 0x39, 0x50, 0x10, 0xb5, 0x47, 0x98, 0x72, 0xd7, 0x8e, 0x74, + 0xd6, 0x71, 0xd5, 0x13, 0xd7, 0x49, 0x02, 0xe6, 0xe3, 0x40, 0x89, 0xbe, 0x08, 0x53, 0xa9, 0x91, + 0xde, 0xc1, 0x73, 0x6e, 0xfd, 0xc3, 0x02, 0xcc, 0x84, 0x72, 0xfd, 0x66, 0xaf, 0xdb, 0x35, 0xd8, + 0x49, 0x74, 0x09, 0x3f, 0xd2, 0xe0, 0x74, 0xd2, 0x31, 0xed, 0x68, 0x8b, 0x6a, 0x47, 0xda, 0xa2, + 0xc0, 0x37, 0xce, 0x2a, 0xdd, 0xa7, 0x37, 0xd3, 0x2a, 0x70, 0x56, 0x27, 0xfa, 0xad, 0x06, 0xf7, + 0x07, 0x5a, 0xd4, 0x8b, 0xd9, 0x0c, 0x87, 0x72, 0xd4, 0xe3, 0x30, 0xea, 0xcb, 0xca, 0xa8, 0xfb, + 0x97, 0x6f, 0xa2, 0x0f, 0xdf, 0xd4, 0x1a, 0xf4, 0x2b, 0x0d, 0xee, 0x0e, 0x08, 0xb2, 0x76, 0xe6, + 0x8f, 0xcd, 0xce, 0x73, 0xca, 0xce, 0xbb, 0x97, 0x07, 0x29, 0xc2, 0x83, 0xf5, 0x8b, 0x7e, 0xa7, + 0x1b, 0x76, 0xe4, 0xb2, 0xb4, 0x3a, 0x84, 0x31, 0xfd, 0x2d, 0x7d, 0x5c, 0x13, 0x45, 0x38, 0x1c, + 0xeb, 0xd1, 0x5f, 0x83, 0xbb, 0x1a, 0x46, 0xc7, 0x76, 0x65, 0x89, 0xbd, 0x46, 0xf8, 0xf3, 0x9e, + 0xf8, 0xe1, 0x07, 0x03, 0xb3, 0x4e, 0xe0, 0xf6, 0xb9, 0xe4, 0xc0, 0xac, 0x43, 0xb0, 0xc4, 0xa0, + 0x07, 0xa1, 0xe0, 0xd8, 0x5d, 0x9b, 0xab, 0x16, 0x20, 0x0a, 0xa7, 0x75, 0x01, 0xc4, 0x01, 0x4e, + 0x37, 0xa0, 0x9c, 0x6c, 0xf7, 0x6f, 0xc7, 0x5b, 0xa3, 0xdf, 0xe7, 0x20, 0x9c, 0x87, 0xa3, 0x47, + 0x13, 0x7d, 0x7e, 0xa0, 0x62, 0xee, 0xe0, 0x1e, 0x1f, 0x6d, 0xaa, 0x09, 0xc3, 0xd8, 0x01, 0x71, + 0xda, 0xe3, 0xb6, 0x53, 0x09, 0x3e, 0x78, 0xac, 0xd4, 0x5d, 0xfe, 0x3c, 0x6b, 0x72, 0x66, 0xbb, + 0x9d, 0x60, 0x66, 0x93, 0x98, 0x47, 0x7c, 0x05, 0x26, 0x88, 0x2b, 0x87, 0x17, 0xb2, 0x9a, 0x2a, + 0x04, 0x33, 0xfb, 0xd5, 0x00, 0x84, 0x43, 0x9c, 0xe8, 0x9f, 0x6d, 0xb3, 0xeb, 0x89, 0x8a, 0x56, + 0x56, 0x9c, 0x85, 0xa0, 0x7f, 0xae, 0xaf, 0x6c, 0x34, 0x64, 0x95, 0x1b, 0x61, 0x43, 0xca, 0x95, + 0xf0, 0x3d, 0x45, 0x82, 0x52, 0xc0, 0x70, 0x84, 0x95, 0x94, 0x1d, 0x25, 0x73, 0x3c, 0x41, 0xb9, + 0x16, 0xc9, 0x54, 0x58, 0x74, 0x49, 0xbd, 0xb4, 0x56, 0x1d, 0x8f, 0x2c, 0x50, 0x8a, 0x99, 0xf7, + 0xce, 0xe1, 0xb4, 0x2c, 0x45, 0x29, 0x96, 0xe7, 0x33, 0x53, 0x2e, 0x6f, 0x32, 0x5e, 0x5e, 0x33, + 0x00, 0xe1, 0x10, 0x87, 0x2a, 0x00, 0x3e, 0x33, 0xd5, 0xaa, 0x65, 0x31, 0x52, 0xa8, 0x4d, 0x8b, + 0xdb, 0xac, 0x19, 0x41, 0x71, 0x82, 0x42, 0x27, 0x30, 0x93, 0xed, 0x49, 0x6e, 0x87, 0xbb, 0xbc, + 0x9f, 0x87, 0xb3, 0xcd, 0x9e, 0x27, 0x0e, 0x2a, 0xf8, 0xb4, 0x66, 0x85, 0x3a, 0x8e, 0x2a, 0xb3, + 0x6f, 0xff, 0xa5, 0xfd, 0x2a, 0x14, 0xc9, 0x35, 0xcf, 0x66, 0xc4, 0x5a, 0x0e, 0xfd, 0xed, 0x6b, + 0xb7, 0xa6, 0xa2, 0x65, 0x77, 0x49, 0xbc, 0xb4, 0xd5, 0x50, 0x08, 0x8e, 0xe5, 0x89, 0xbd, 0xf0, + 0x6d, 0xd7, 0x24, 0x82, 0x54, 0x35, 0x39, 0x11, 0x43, 0x33, 0x44, 0xe0, 0x98, 0x46, 0x34, 0x92, + 0xed, 0xe8, 0x63, 0x24, 0xe9, 0x83, 0x87, 0x68, 0x24, 0xb3, 0x1f, 0x35, 0xc5, 0x3b, 0x10, 0xc3, + 0x70, 0x42, 0x0f, 0xfa, 0x99, 0x06, 0xd3, 0x46, 0xfa, 0x7b, 0xa2, 0xe0, 0xe5, 0xdb, 0xc6, 0xe1, + 0x54, 0x0f, 0xf9, 0x36, 0xaa, 0x76, 0x8f, 0xb2, 0x63, 0x3a, 0xf3, 0x61, 0x51, 0x46, 0xb9, 0xfe, + 0xb9, 0x06, 0xf7, 0x0d, 0xf1, 0x88, 0x13, 0x18, 0xfe, 0x38, 0xe9, 0xe1, 0xcf, 0xc8, 0xe5, 0xcd, + 0x10, 0xcb, 0x87, 0x8c, 0x81, 0x7e, 0x39, 0x06, 0x0f, 0x0c, 0xe1, 0x38, 0xf4, 0x40, 0xe8, 0x49, + 0x98, 0x0a, 0x7f, 0x27, 0xc3, 0x30, 0x2e, 0xa6, 0x93, 0x48, 0x9c, 0xa6, 0x0d, 0x55, 0xc9, 0x0b, + 0x2b, 0xd7, 0xaf, 0x2a, 0xb8, 0xb4, 0x42, 0x0a, 0xe1, 0xe1, 0x26, 0xed, 0x7a, 0x0e, 0xe1, 0x24, + 0xe8, 0xd2, 0x27, 0x63, 0x0f, 0x5f, 0x09, 0x11, 0x38, 0xa6, 0x11, 0x49, 0x8a, 0x30, 0x46, 0x99, + 0xf4, 0xb0, 0xc4, 0x3c, 0x7b, 0x55, 0x00, 0x71, 0x80, 0xd3, 0xff, 0xa5, 0xc1, 0xb9, 0x21, 0x9b, + 0x72, 0x62, 0x55, 0xee, 0x4e, 0xba, 0xca, 0x7d, 0xe1, 0x98, 0xdc, 0xe0, 0xc0, 0x7a, 0xf7, 0x61, + 0x28, 0x25, 0x5e, 0x12, 0xa0, 0x73, 0x90, 0xf3, 0x5d, 0x3b, 0xfb, 0x41, 0x62, 0x73, 0xb3, 0x8e, + 0x05, 0xbc, 0xd6, 0xfa, 0xf8, 0xfa, 0xfc, 0xa9, 0x4f, 0xae, 0xcf, 0x9f, 0xfa, 0xf4, 0xfa, 0xfc, + 0xa9, 0x77, 0xf6, 0xe7, 0xb5, 0x8f, 0xf7, 0xe7, 0xb5, 0x4f, 0xf6, 0xe7, 0xb5, 0x4f, 0xf7, 0xe7, + 0xb5, 0xbf, 0xec, 0xcf, 0x6b, 0xbf, 0xf8, 0xeb, 0xfc, 0xa9, 0x57, 0x2a, 0xa3, 0xfd, 0xa7, 0xc6, + 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x02, 0x8d, 0x03, 0xda, 0x31, 0x00, 0x00, } func (m *AddressGroup) Marshal() (dAtA []byte, err error) { @@ -2299,6 +2328,76 @@ func (m *GroupMember) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *GroupMembers) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GroupMembers) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GroupMembers) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i = encodeVarintGenerated(dAtA, i, uint64(m.CurrentPage)) + i-- + dAtA[i] = 0x30 + i = encodeVarintGenerated(dAtA, i, uint64(m.TotalPages)) + i-- + dAtA[i] = 0x28 + i = encodeVarintGenerated(dAtA, i, uint64(m.TotalMembers)) + i-- + dAtA[i] = 0x20 + if len(m.EffectiveIPBlocks) > 0 { + for iNdEx := len(m.EffectiveIPBlocks) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.EffectiveIPBlocks[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.EffectiveMembers) > 0 { + for iNdEx := len(m.EffectiveMembers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.EffectiveMembers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *GroupReference) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -3979,6 +4078,32 @@ func (m *GroupMember) Size() (n int) { return n } +func (m *GroupMembers) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ObjectMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + if len(m.EffectiveMembers) > 0 { + for _, e := range m.EffectiveMembers { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + if len(m.EffectiveIPBlocks) > 0 { + for _, e := range m.EffectiveIPBlocks { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + n += 1 + sovGenerated(uint64(m.TotalMembers)) + n += 1 + sovGenerated(uint64(m.TotalPages)) + n += 1 + sovGenerated(uint64(m.CurrentPage)) + return n +} + func (m *GroupReference) Size() (n int) { if m == nil { return 0 @@ -4779,6 +4904,31 @@ func (this *GroupMember) String() string { }, "") return s } +func (this *GroupMembers) String() string { + if this == nil { + return "nil" + } + repeatedStringForEffectiveMembers := "[]GroupMember{" + for _, f := range this.EffectiveMembers { + repeatedStringForEffectiveMembers += strings.Replace(strings.Replace(f.String(), "GroupMember", "GroupMember", 1), `&`, ``, 1) + "," + } + repeatedStringForEffectiveMembers += "}" + repeatedStringForEffectiveIPBlocks := "[]IPNet{" + for _, f := range this.EffectiveIPBlocks { + repeatedStringForEffectiveIPBlocks += strings.Replace(strings.Replace(f.String(), "IPNet", "IPNet", 1), `&`, ``, 1) + "," + } + repeatedStringForEffectiveIPBlocks += "}" + s := strings.Join([]string{`&GroupMembers{`, + `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `EffectiveMembers:` + repeatedStringForEffectiveMembers + `,`, + `EffectiveIPBlocks:` + repeatedStringForEffectiveIPBlocks + `,`, + `TotalMembers:` + fmt.Sprintf("%v", this.TotalMembers) + `,`, + `TotalPages:` + fmt.Sprintf("%v", this.TotalPages) + `,`, + `CurrentPage:` + fmt.Sprintf("%v", this.CurrentPage) + `,`, + `}`, + }, "") + return s +} func (this *GroupReference) String() string { if this == nil { return "nil" @@ -7407,6 +7557,214 @@ func (m *GroupMember) Unmarshal(dAtA []byte) error { } return nil } +func (m *GroupMembers) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GroupMembers: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GroupMembers: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ObjectMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ObjectMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EffectiveMembers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EffectiveMembers = append(m.EffectiveMembers, GroupMember{}) + if err := m.EffectiveMembers[len(m.EffectiveMembers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EffectiveIPBlocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EffectiveIPBlocks = append(m.EffectiveIPBlocks, IPNet{}) + if err := m.EffectiveIPBlocks[len(m.EffectiveIPBlocks)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalMembers", wireType) + } + m.TotalMembers = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalMembers |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalPages", wireType) + } + m.TotalPages = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalPages |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentPage", wireType) + } + m.CurrentPage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentPage |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *GroupReference) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apis/controlplane/v1beta2/generated.proto b/pkg/apis/controlplane/v1beta2/generated.proto index 017eba18c9d..e6e89d96d24 100644 --- a/pkg/apis/controlplane/v1beta2/generated.proto +++ b/pkg/apis/controlplane/v1beta2/generated.proto @@ -92,7 +92,7 @@ message BundleServerAuthConfiguration { optional BasicAuthentication basicAuthentication = 3; } -// ClusterGroupMembers is a list of GroupMember objects or ipBlocks that are currently selected by a ClusterGroup. +// ClusterGroupMembers is a list of GroupMember objects or IPBlocks that are currently selected by a ClusterGroup. message ClusterGroupMembers { optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; @@ -170,6 +170,21 @@ message GroupMember { optional ServiceReference service = 6; } +// GroupMembers is a list of GroupMember objects or IPBlocks that are currently selected by a Group. +message GroupMembers { + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + repeated GroupMember effectiveMembers = 2; + + repeated IPNet effectiveIPBlocks = 3; + + optional int64 totalMembers = 4; + + optional int64 totalPages = 5; + + optional int64 currentPage = 6; +} + message GroupReference { // Namespace of the Group. Empty for ClusterGroup. optional string namespace = 1; diff --git a/pkg/apis/controlplane/v1beta2/register.go b/pkg/apis/controlplane/v1beta2/register.go index bc1998f5ada..e90252dfa8f 100644 --- a/pkg/apis/controlplane/v1beta2/register.go +++ b/pkg/apis/controlplane/v1beta2/register.go @@ -71,6 +71,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { &NetworkPolicyStatus{}, &NodeStatsSummary{}, &ClusterGroupMembers{}, + &GroupMembers{}, &PaginationGetOptions{}, &GroupAssociation{}, &IPGroupAssociation{}, diff --git a/pkg/apis/controlplane/v1beta2/types.go b/pkg/apis/controlplane/v1beta2/types.go index 6e9a7372867..8eae3c3cc4e 100644 --- a/pkg/apis/controlplane/v1beta2/types.go +++ b/pkg/apis/controlplane/v1beta2/types.go @@ -98,7 +98,7 @@ type GroupMember struct { // +genclient:onlyVerbs=get // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// ClusterGroupMembers is a list of GroupMember objects or ipBlocks that are currently selected by a ClusterGroup. +// ClusterGroupMembers is a list of GroupMember objects or IPBlocks that are currently selected by a ClusterGroup. type ClusterGroupMembers struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` @@ -109,6 +109,21 @@ type ClusterGroupMembers struct { CurrentPage int64 `json:"currentPage" protobuf:"varint,6,opt,name=currentPage"` } +// +genclient +// +genclient:onlyVerbs=get +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// GroupMembers is a list of GroupMember objects or IPBlocks that are currently selected by a Group. +type GroupMembers struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + EffectiveMembers []GroupMember `json:"effectiveMembers" protobuf:"bytes,2,rep,name=effectiveMembers"` + EffectiveIPBlocks []IPNet `json:"effectiveIPBlocks" protobuf:"bytes,3,rep,name=effectiveIPBlocks"` + TotalMembers int64 `json:"totalMembers" protobuf:"varint,4,opt,name=totalMembers"` + TotalPages int64 `json:"totalPages" protobuf:"varint,5,opt,name=totalPages"` + CurrentPage int64 `json:"currentPage" protobuf:"varint,6,opt,name=currentPage"` +} + // +k8s:conversion-gen:explicit-from=net/url.Values // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go b/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go index 77f7128878a..fe025322eb6 100644 --- a/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go +++ b/pkg/apis/controlplane/v1beta2/zz_generated.conversion.go @@ -199,6 +199,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*GroupMembers)(nil), (*controlplane.GroupMembers)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_GroupMembers_To_controlplane_GroupMembers(a.(*GroupMembers), b.(*controlplane.GroupMembers), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*controlplane.GroupMembers)(nil), (*GroupMembers)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_controlplane_GroupMembers_To_v1beta2_GroupMembers(a.(*controlplane.GroupMembers), b.(*GroupMembers), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*GroupReference)(nil), (*controlplane.GroupReference)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_GroupReference_To_controlplane_GroupReference(a.(*GroupReference), b.(*controlplane.GroupReference), scope) }); err != nil { @@ -1111,6 +1121,56 @@ func Convert_controlplane_GroupMember_To_v1beta2_GroupMember(in *controlplane.Gr return autoConvert_controlplane_GroupMember_To_v1beta2_GroupMember(in, out, s) } +func autoConvert_v1beta2_GroupMembers_To_controlplane_GroupMembers(in *GroupMembers, out *controlplane.GroupMembers, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if in.EffectiveMembers != nil { + in, out := &in.EffectiveMembers, &out.EffectiveMembers + *out = make([]controlplane.GroupMember, len(*in)) + for i := range *in { + if err := Convert_v1beta2_GroupMember_To_controlplane_GroupMember(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.EffectiveMembers = nil + } + out.EffectiveIPBlocks = *(*[]controlplane.IPNet)(unsafe.Pointer(&in.EffectiveIPBlocks)) + out.TotalMembers = in.TotalMembers + out.TotalPages = in.TotalPages + out.CurrentPage = in.CurrentPage + return nil +} + +// Convert_v1beta2_GroupMembers_To_controlplane_GroupMembers is an autogenerated conversion function. +func Convert_v1beta2_GroupMembers_To_controlplane_GroupMembers(in *GroupMembers, out *controlplane.GroupMembers, s conversion.Scope) error { + return autoConvert_v1beta2_GroupMembers_To_controlplane_GroupMembers(in, out, s) +} + +func autoConvert_controlplane_GroupMembers_To_v1beta2_GroupMembers(in *controlplane.GroupMembers, out *GroupMembers, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if in.EffectiveMembers != nil { + in, out := &in.EffectiveMembers, &out.EffectiveMembers + *out = make([]GroupMember, len(*in)) + for i := range *in { + if err := Convert_controlplane_GroupMember_To_v1beta2_GroupMember(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.EffectiveMembers = nil + } + out.EffectiveIPBlocks = *(*[]IPNet)(unsafe.Pointer(&in.EffectiveIPBlocks)) + out.TotalMembers = in.TotalMembers + out.TotalPages = in.TotalPages + out.CurrentPage = in.CurrentPage + return nil +} + +// Convert_controlplane_GroupMembers_To_v1beta2_GroupMembers is an autogenerated conversion function. +func Convert_controlplane_GroupMembers_To_v1beta2_GroupMembers(in *controlplane.GroupMembers, out *GroupMembers, s conversion.Scope) error { + return autoConvert_controlplane_GroupMembers_To_v1beta2_GroupMembers(in, out, s) +} + func autoConvert_v1beta2_GroupReference_To_controlplane_GroupReference(in *GroupReference, out *controlplane.GroupReference, s conversion.Scope) error { out.Namespace = in.Namespace out.Name = in.Name diff --git a/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go b/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go index 672b6e0d825..86e63a1a0db 100644 --- a/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go +++ b/pkg/apis/controlplane/v1beta2/zz_generated.deepcopy.go @@ -536,6 +536,46 @@ func (in *GroupMember) DeepCopy() *GroupMember { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GroupMembers) DeepCopyInto(out *GroupMembers) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.EffectiveMembers != nil { + in, out := &in.EffectiveMembers, &out.EffectiveMembers + *out = make([]GroupMember, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.EffectiveIPBlocks != nil { + in, out := &in.EffectiveIPBlocks, &out.EffectiveIPBlocks + *out = make([]IPNet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupMembers. +func (in *GroupMembers) DeepCopy() *GroupMembers { + if in == nil { + return nil + } + out := new(GroupMembers) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GroupMembers) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupReference) DeepCopyInto(out *GroupReference) { *out = *in diff --git a/pkg/apis/controlplane/zz_generated.deepcopy.go b/pkg/apis/controlplane/zz_generated.deepcopy.go index 08e0944de99..4b8b67218a2 100644 --- a/pkg/apis/controlplane/zz_generated.deepcopy.go +++ b/pkg/apis/controlplane/zz_generated.deepcopy.go @@ -536,6 +536,46 @@ func (in *GroupMember) DeepCopy() *GroupMember { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GroupMembers) DeepCopyInto(out *GroupMembers) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.EffectiveMembers != nil { + in, out := &in.EffectiveMembers, &out.EffectiveMembers + *out = make([]GroupMember, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.EffectiveIPBlocks != nil { + in, out := &in.EffectiveIPBlocks, &out.EffectiveIPBlocks + *out = make([]IPNet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupMembers. +func (in *GroupMembers) DeepCopy() *GroupMembers { + if in == nil { + return nil + } + out := new(GroupMembers) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GroupMembers) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupReference) DeepCopyInto(out *GroupReference) { *out = *in diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 865a8b87b08..697d4a451bf 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -49,6 +49,7 @@ import ( "antrea.io/antrea/pkg/apiserver/registry/networkpolicy/appliedtogroup" "antrea.io/antrea/pkg/apiserver/registry/networkpolicy/clustergroupmember" "antrea.io/antrea/pkg/apiserver/registry/networkpolicy/groupassociation" + "antrea.io/antrea/pkg/apiserver/registry/networkpolicy/groupmember" "antrea.io/antrea/pkg/apiserver/registry/networkpolicy/ipgroupassociation" "antrea.io/antrea/pkg/apiserver/registry/networkpolicy/networkpolicy" "antrea.io/antrea/pkg/apiserver/registry/stats/antreaclusternetworkpolicystats" @@ -192,6 +193,7 @@ func installAPIGroup(s *APIServer, c completedConfig) error { networkPolicyStorage := networkpolicy.NewREST(c.extraConfig.networkPolicyStore) networkPolicyStatusStorage := networkpolicy.NewStatusREST(c.extraConfig.networkPolicyStatusController) clusterGroupMembershipStorage := clustergroupmember.NewREST(c.extraConfig.networkPolicyController) + groupMembershipStorage := groupmember.NewREST(c.extraConfig.networkPolicyController) groupAssociationStorage := groupassociation.NewREST(c.extraConfig.networkPolicyController) ipGroupAssociationStorage := ipgroupassociation.NewREST(c.extraConfig.podInformer, c.extraConfig.eeInformer, c.extraConfig.networkPolicyController, c.extraConfig.networkPolicyController) nodeStatsSummaryStorage := nodestatssummary.NewREST(c.extraConfig.statsAggregator) @@ -208,6 +210,7 @@ func installAPIGroup(s *APIServer, c completedConfig) error { cpv1beta2Storage["groupassociations"] = groupAssociationStorage cpv1beta2Storage["ipgroupassociations"] = ipGroupAssociationStorage cpv1beta2Storage["clustergroupmembers"] = clusterGroupMembershipStorage + cpv1beta2Storage["groupmembers"] = groupMembershipStorage cpv1beta2Storage["egressgroups"] = egressGroupStorage cpv1beta2Storage["supportbundlecollections"] = bundleCollectionStorage cpv1beta2Storage["supportbundlecollections/status"] = bundleCollectionStatusStorage diff --git a/pkg/apiserver/openapi/zz_generated.openapi.go b/pkg/apiserver/openapi/zz_generated.openapi.go index 5a2eb174d2e..34f4fce09d1 100644 --- a/pkg/apiserver/openapi/zz_generated.openapi.go +++ b/pkg/apiserver/openapi/zz_generated.openapi.go @@ -46,6 +46,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "antrea.io/antrea/pkg/apis/controlplane/v1beta2.ExternalEntityReference": schema_pkg_apis_controlplane_v1beta2_ExternalEntityReference(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.GroupAssociation": schema_pkg_apis_controlplane_v1beta2_GroupAssociation(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.GroupMember": schema_pkg_apis_controlplane_v1beta2_GroupMember(ref), + "antrea.io/antrea/pkg/apis/controlplane/v1beta2.GroupMembers": schema_pkg_apis_controlplane_v1beta2_GroupMembers(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.GroupReference": schema_pkg_apis_controlplane_v1beta2_GroupReference(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.HTTPProtocol": schema_pkg_apis_controlplane_v1beta2_HTTPProtocol(ref), "antrea.io/antrea/pkg/apis/controlplane/v1beta2.IPBlock": schema_pkg_apis_controlplane_v1beta2_IPBlock(ref), @@ -818,7 +819,7 @@ func schema_pkg_apis_controlplane_v1beta2_ClusterGroupMembers(ref common.Referen return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ClusterGroupMembers is a list of GroupMember objects or ipBlocks that are currently selected by a ClusterGroup.", + Description: "ClusterGroupMembers is a list of GroupMember objects or IPBlocks that are currently selected by a ClusterGroup.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -1192,6 +1193,89 @@ func schema_pkg_apis_controlplane_v1beta2_GroupMember(ref common.ReferenceCallba } } +func schema_pkg_apis_controlplane_v1beta2_GroupMembers(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupMembers is a list of GroupMember objects or IPBlocks that are currently selected by a Group.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "effectiveMembers": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("antrea.io/antrea/pkg/apis/controlplane/v1beta2.GroupMember"), + }, + }, + }, + }, + }, + "effectiveIPBlocks": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("antrea.io/antrea/pkg/apis/controlplane/v1beta2.IPNet"), + }, + }, + }, + }, + }, + "totalMembers": { + SchemaProps: spec.SchemaProps{ + Default: 0, + Type: []string{"integer"}, + Format: "int64", + }, + }, + "totalPages": { + SchemaProps: spec.SchemaProps{ + Default: 0, + Type: []string{"integer"}, + Format: "int64", + }, + }, + "currentPage": { + SchemaProps: spec.SchemaProps{ + Default: 0, + Type: []string{"integer"}, + Format: "int64", + }, + }, + }, + Required: []string{"effectiveMembers", "effectiveIPBlocks", "totalMembers", "totalPages", "currentPage"}, + }, + }, + Dependencies: []string{ + "antrea.io/antrea/pkg/apis/controlplane/v1beta2.GroupMember", "antrea.io/antrea/pkg/apis/controlplane/v1beta2.IPNet", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + func schema_pkg_apis_controlplane_v1beta2_GroupReference(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apiserver/registry/networkpolicy/clustergroupmember/rest.go b/pkg/apiserver/registry/networkpolicy/clustergroupmember/rest.go index d072f0db2c6..566b2a5b407 100644 --- a/pkg/apiserver/registry/networkpolicy/clustergroupmember/rest.go +++ b/pkg/apiserver/registry/networkpolicy/clustergroupmember/rest.go @@ -27,7 +27,7 @@ import ( ) type REST struct { - querier groupMembershipQuerier + querier GroupMembershipQuerier } var ( @@ -37,11 +37,11 @@ var ( ) // NewREST returns a REST object that will work against API services. -func NewREST(querier groupMembershipQuerier) *REST { +func NewREST(querier GroupMembershipQuerier) *REST { return &REST{querier} } -type groupMembershipQuerier interface { +type GroupMembershipQuerier interface { GetGroupMembers(name string) (controlplane.GroupMemberSet, []controlplane.IPBlock, error) } @@ -53,87 +53,87 @@ func (r *REST) Destroy() { } func (r *REST) Get(ctx context.Context, name string, options runtime.Object) (runtime.Object, error) { - groupMembers, ipBlocks, err := r.querier.GetGroupMembers(name) + var err error + memberList := &controlplane.ClusterGroupMembers{} + memberList.Name = name + memberList.EffectiveMembers, memberList.EffectiveIPBlocks, memberList.TotalMembers, memberList.TotalPages, memberList.CurrentPage, err = GetPaginatedMembers(r.querier, name, options) + return memberList, err +} + +// NewGetOptions returns the default options for Get, so options object is never nil. +func (r *REST) NewGetOptions() (runtime.Object, bool, string) { + return &controlplane.PaginationGetOptions{}, false, "" +} + +func (r *REST) NamespaceScoped() bool { + return false +} + +func GetPaginatedMembers(querier GroupMembershipQuerier, name string, options runtime.Object) (members []controlplane.GroupMember, ipNets []controlplane.IPNet, totalMembers, totalPages, currentPage int64, err error) { + groupMembers, ipBlocks, err := querier.GetGroupMembers(name) if err != nil { - return nil, errors.NewInternalError(err) + return nil, nil, 0, 0, 0, errors.NewInternalError(err) } // Retrieve options used for pagination. getOptions, ok := options.(*controlplane.PaginationGetOptions) if !ok || getOptions == nil { - return nil, errors.NewInternalError(fmt.Errorf("received error while retrieving options for pagination")) + return nil, nil, 0, 0, 0, errors.NewInternalError(fmt.Errorf("received error while retrieving options for pagination")) } - memberList := &controlplane.ClusterGroupMembers{} if len(ipBlocks) > 0 { - effectiveIPBlocks := make([]controlplane.IPNet, 0, len(ipBlocks)) + ipNets = make([]controlplane.IPNet, 0, len(ipBlocks)) for _, ipb := range ipBlocks { // ClusterGroup ipBlock does not support Except slices, so no need to generate an effective // list of IPs by removing Except slices from allowed CIDR. - effectiveIPBlocks = append(effectiveIPBlocks, ipb.CIDR) + ipNets = append(ipNets, ipb.CIDR) } - memberList.EffectiveIPBlocks = effectiveIPBlocks } if len(groupMembers) > 0 { - effectiveMembers := make([]controlplane.GroupMember, 0, len(groupMembers)) + members = make([]controlplane.GroupMember, 0, len(groupMembers)) for _, member := range groupMembers { - effectiveMembers = append(effectiveMembers, *member) + members = append(members, *member) } - memberList.EffectiveMembers = effectiveMembers } - memberList.Name = name - memberList.TotalMembers = int64(len(memberList.EffectiveMembers)) - err = paginateMemberList(memberList, getOptions) - return memberList, err -} - -// NewGetOptions returns the default options for Get, so options object is never nil. -func (r *REST) NewGetOptions() (runtime.Object, bool, string) { - return &controlplane.PaginationGetOptions{}, false, "" -} - -func (r *REST) NamespaceScoped() bool { - return false + totalMembers = int64(len(members)) + totalPages, currentPage, err = PaginateMemberList(&members, getOptions) + return } -// paginateMemberList returns paginated results if meaningful options are provided, options should never be nil. +// PaginateMemberList returns paginated results if meaningful options are provided. Options should never be nil. // Paginated results are continuous only when there is no member change across multiple calls. -// Pagination is not processed if either page number or limit = 0, thus returns full member list. -// Returns an error for invalid options; returns empty list for page number beyond the total pages range. -func paginateMemberList(memberList *controlplane.ClusterGroupMembers, pageInfo *controlplane.PaginationGetOptions) error { +// Pagination is not enabled if either page number or limit = 0, in which the full member list is returned. +// An error is returned for invalid options, and an empty list is returned for a page number out of the pages range. +func PaginateMemberList(effectiveMembers *[]controlplane.GroupMember, pageInfo *controlplane.PaginationGetOptions) (int64, int64, error) { if pageInfo.Limit < 0 { - return errors.NewBadRequest(fmt.Sprintf("received invalid page limit %d for pagination", pageInfo.Limit)) + return 0, 0, errors.NewBadRequest(fmt.Sprintf("received invalid page limit %d for pagination", pageInfo.Limit)) } else if pageInfo.Page < 0 { - return errors.NewBadRequest(fmt.Sprintf("received invalid page number %d for pagination", pageInfo.Page)) + return 0, 0, errors.NewBadRequest(fmt.Sprintf("received invalid page number %d for pagination", pageInfo.Page)) } - if memberList.TotalMembers == 0 { - memberList.TotalPages, memberList.CurrentPage = 0, 0 - return nil + if len(*effectiveMembers) == 0 { + return 0, 0, nil } - // Sort members based on name of ee/pod to realize consistent pagination support. - sort.SliceStable(memberList.EffectiveMembers, func(i, j int) bool { - if memberList.EffectiveMembers[i].Pod != nil && memberList.EffectiveMembers[j].Pod != nil { - return memberList.EffectiveMembers[i].Pod.Name < memberList.EffectiveMembers[j].Pod.Name - } else if memberList.EffectiveMembers[i].ExternalEntity != nil && memberList.EffectiveMembers[j].ExternalEntity != nil { - return memberList.EffectiveMembers[i].ExternalEntity.Name < memberList.EffectiveMembers[j].ExternalEntity.Name + // Sort members based on EE/Pod names to realize consistent pagination results. + sort.SliceStable(*effectiveMembers, func(i, j int) bool { + if (*effectiveMembers)[i].Pod != nil && (*effectiveMembers)[j].Pod != nil { + return (*effectiveMembers)[i].Pod.Name < (*effectiveMembers)[j].Pod.Name + } else if (*effectiveMembers)[i].ExternalEntity != nil && (*effectiveMembers)[j].ExternalEntity != nil { + return (*effectiveMembers)[i].ExternalEntity.Name < (*effectiveMembers)[j].ExternalEntity.Name } else { return true } }) if pageInfo.Limit == 0 { - memberList.TotalPages, memberList.CurrentPage = 1, 1 - return nil + return 1, 1, nil } - totalPages := (int64(len(memberList.EffectiveMembers)) + pageInfo.Limit - 1) / pageInfo.Limit - memberList.TotalPages = totalPages - memberList.CurrentPage = pageInfo.Page + totalPages := (int64(len(*effectiveMembers)) + pageInfo.Limit - 1) / pageInfo.Limit if totalPages >= pageInfo.Page && pageInfo.Page > 0 { beginMember := (pageInfo.Page - 1) * pageInfo.Limit - memberList.EffectiveMembers = memberList.EffectiveMembers[beginMember:] - if pageInfo.Limit < int64(len(memberList.EffectiveMembers)) { - memberList.EffectiveMembers = memberList.EffectiveMembers[:pageInfo.Limit] + *effectiveMembers = (*effectiveMembers)[beginMember:] + if pageInfo.Limit < int64(len(*effectiveMembers)) { + *effectiveMembers = (*effectiveMembers)[:pageInfo.Limit] } } else if totalPages < pageInfo.Page { - // Returns empty memberList if page number exceeds total pages, to indicate end of list. - memberList.EffectiveMembers = memberList.EffectiveMembers[:0] + // Returns an empty member list if the page number exceeds total pages, to indicate end of list. + *effectiveMembers = (*effectiveMembers)[:0] } - return nil + return totalPages, pageInfo.Page, nil } diff --git a/pkg/apiserver/registry/networkpolicy/clustergroupmember/rest_test.go b/pkg/apiserver/registry/networkpolicy/clustergroupmember/rest_test.go index 39358ff4d45..f0edde36804 100644 --- a/pkg/apiserver/registry/networkpolicy/clustergroupmember/rest_test.go +++ b/pkg/apiserver/registry/networkpolicy/clustergroupmember/rest_test.go @@ -69,7 +69,31 @@ func getTestMembersBasic() map[string]controlplane.GroupMemberSet { } } -func getTestMembersPagination() map[string]controlplane.GroupMemberSet { +func getTestMembersPagination(ifExternalEntity bool) map[string]controlplane.GroupMemberSet { + if ifExternalEntity { + return map[string]controlplane.GroupMemberSet{ + "cgB": { + "memberKey1": &controlplane.GroupMember{ + ExternalEntity: &controlplane.ExternalEntityReference{ + Name: "ee2", + Namespace: "ns1", + }, + IPs: []controlplane.IPAddress{ + []byte{127, 10, 0, 1}, + }, + }, + "memberKey2": &controlplane.GroupMember{ + ExternalEntity: &controlplane.ExternalEntityReference{ + Name: "ee1", + Namespace: "ns1", + }, + IPs: []controlplane.IPAddress{ + []byte{127, 10, 0, 1}, + }, + }, + }, + } + } return map[string]controlplane.GroupMemberSet{ "cgA": { "memberKey1": &controlplane.GroupMember{ @@ -224,6 +248,7 @@ func TestRESTGetPagination(t *testing.T) { tests := []struct { name string groupName string + ifExternalEntity bool paginationOptions runtime.Object expectedObj runtime.Object expectedErr bool @@ -287,6 +312,32 @@ func TestRESTGetPagination(t *testing.T) { }, expectedErr: false, }, + { + name: "page1/2-group-member-pagination", + groupName: "cgB", + ifExternalEntity: true, + paginationOptions: &controlplane.PaginationGetOptions{Page: 2, Limit: 1}, + expectedObj: &controlplane.ClusterGroupMembers{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cgB", + }, + EffectiveMembers: []controlplane.GroupMember{ + { + ExternalEntity: &controlplane.ExternalEntityReference{ + Name: "ee2", + Namespace: "ns1", + }, + IPs: []controlplane.IPAddress{ + []byte{127, 10, 0, 1}, + }, + }, + }, + TotalMembers: 2, + TotalPages: 2, + CurrentPage: 2, + }, + expectedErr: false, + }, { name: "exceed-page-group-member-pagination", groupName: "cgA", @@ -358,8 +409,8 @@ func TestRESTGetPagination(t *testing.T) { expectedErr: true, }, } - rest := NewREST(fakeQuerier{members: getTestMembersPagination()}) for _, tt := range tests { + rest := NewREST(fakeQuerier{members: getTestMembersPagination(tt.ifExternalEntity)}) actualGroupList, err := rest.Get(request.NewDefaultContext(), tt.groupName, tt.paginationOptions) if tt.expectedErr { require.Error(t, err) diff --git a/pkg/apiserver/registry/networkpolicy/groupmember/rest.go b/pkg/apiserver/registry/networkpolicy/groupmember/rest.go new file mode 100644 index 00000000000..8e2c3d53447 --- /dev/null +++ b/pkg/apiserver/registry/networkpolicy/groupmember/rest.go @@ -0,0 +1,73 @@ +// Copyright 2023 Antrea Authors +// +// 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 groupmember + +import ( + "context" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + + "antrea.io/antrea/pkg/apis/controlplane" + "antrea.io/antrea/pkg/apiserver/registry/networkpolicy/clustergroupmember" + "antrea.io/antrea/pkg/util/k8s" +) + +type REST struct { + querier clustergroupmember.GroupMembershipQuerier +} + +var ( + _ rest.Storage = &REST{} + _ rest.Scoper = &REST{} + _ rest.GetterWithOptions = &REST{} +) + +// NewREST returns a REST object that will work against API services. +func NewREST(querier clustergroupmember.GroupMembershipQuerier) *REST { + return &REST{querier} +} + +func (r *REST) New() runtime.Object { + return &controlplane.GroupMembers{} +} + +func (r *REST) Destroy() { +} + +func (r *REST) Get(ctx context.Context, name string, options runtime.Object) (runtime.Object, error) { + ns, ok := request.NamespaceFrom(ctx) + if !ok || len(ns) == 0 { + return nil, errors.NewBadRequest("Namespace parameter required.") + } + groupName := k8s.NamespacedName(ns, name) + var err error + memberList := &controlplane.GroupMembers{} + memberList.Namespace = ns + memberList.Name = name + memberList.EffectiveMembers, memberList.EffectiveIPBlocks, memberList.TotalMembers, memberList.TotalPages, memberList.CurrentPage, err = clustergroupmember.GetPaginatedMembers(r.querier, groupName, options) + return memberList, err +} + +// NewGetOptions returns the default options for Get, so options object is never nil. +func (r *REST) NewGetOptions() (runtime.Object, bool, string) { + return &controlplane.PaginationGetOptions{}, false, "" +} + +func (r *REST) NamespaceScoped() bool { + return true +} diff --git a/pkg/apiserver/registry/networkpolicy/groupmember/rest_test.go b/pkg/apiserver/registry/networkpolicy/groupmember/rest_test.go new file mode 100644 index 00000000000..e3a086471aa --- /dev/null +++ b/pkg/apiserver/registry/networkpolicy/groupmember/rest_test.go @@ -0,0 +1,211 @@ +// Copyright 2023 Antrea Authors +// +// 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 groupmember + +import ( + "net" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/endpoints/request" + + "antrea.io/antrea/pkg/apis/controlplane" +) + +type fakeQuerier struct { + members map[string]controlplane.GroupMemberSet + ipMembers map[string][]controlplane.IPBlock +} + +func (q fakeQuerier) GetGroupMembers(uid string) (controlplane.GroupMemberSet, []controlplane.IPBlock, error) { + if ipMemberList, ok := q.ipMembers[uid]; ok { + return nil, ipMemberList, nil + } + if memberList, ok := q.members[uid]; ok { + return memberList, nil, nil + } + return nil, nil, nil +} + +func getTestMembers() map[string]controlplane.GroupMemberSet { + return map[string]controlplane.GroupMemberSet{ + "default/ngA": { + "memberKey1": &controlplane.GroupMember{ + Pod: &controlplane.PodReference{ + Name: "pod1", + Namespace: "ns1", + }, + IPs: []controlplane.IPAddress{ + []byte{127, 10, 0, 1}, + }, + }, + }, + "default/ngB": { + "memberKey2": &controlplane.GroupMember{ + ExternalEntity: &controlplane.ExternalEntityReference{ + Name: "ee2", + Namespace: "ns1", + }, + IPs: []controlplane.IPAddress{ + []byte{127, 10, 0, 2}, + }, + }, + }, + } +} + +func getTestIPMembers() map[string][]controlplane.IPBlock { + testCIDR := controlplane.IPNet{ + IP: controlplane.IPAddress(net.ParseIP("10.0.0.1")), + PrefixLength: int32(24), + } + ipb := []controlplane.IPBlock{{CIDR: testCIDR}} + return map[string][]controlplane.IPBlock{ + "ns2/ngIPBlock": ipb, + } +} + +func TestREST(t *testing.T) { + r := NewREST(nil) + assert.Equal(t, &controlplane.GroupMembers{}, r.New()) + assert.True(t, r.NamespaceScoped()) +} + +func TestRESTGet(t *testing.T) { + tests := []struct { + name string + groupName string + namespace string + expectedObj runtime.Object + expectedErr bool + }{ + { + name: "single-pod-group-member", + groupName: "ngA", + namespace: "default", + expectedObj: &controlplane.GroupMembers{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ngA", + Namespace: "default", + }, + EffectiveMembers: []controlplane.GroupMember{ + { + Pod: &controlplane.PodReference{ + Name: "pod1", + Namespace: "ns1", + }, + IPs: []controlplane.IPAddress{ + []byte{127, 10, 0, 1}, + }, + }, + }, + TotalMembers: 1, + TotalPages: 1, + CurrentPage: 1, + }, + expectedErr: false, + }, + { + name: "single-ee-group-member", + groupName: "ngB", + namespace: "default", + expectedObj: &controlplane.GroupMembers{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ngB", + Namespace: "default", + }, + EffectiveMembers: []controlplane.GroupMember{ + { + ExternalEntity: &controlplane.ExternalEntityReference{ + Name: "ee2", + Namespace: "ns1", + }, + IPs: []controlplane.IPAddress{ + []byte{127, 10, 0, 2}, + }, + }, + }, + TotalMembers: 1, + TotalPages: 1, + CurrentPage: 1, + }, + expectedErr: false, + }, + { + name: "no-group-member", + groupName: "ngC", + namespace: "default", + expectedObj: &controlplane.GroupMembers{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ngC", + Namespace: "default", + }, + TotalMembers: 0, + TotalPages: 0, + CurrentPage: 0, + }, + expectedErr: false, + }, + { + name: "no-group-member-in-namespace", + groupName: "ngA", + namespace: "test", + expectedObj: &controlplane.GroupMembers{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ngA", + Namespace: "test", + }, + TotalMembers: 0, + TotalPages: 0, + CurrentPage: 0, + }, + expectedErr: false, + }, + { + name: "ipBlock-ng", + groupName: "ngIPBlock", + namespace: "ns2", + expectedObj: &controlplane.GroupMembers{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ngIPBlock", + Namespace: "ns2", + }, + EffectiveIPBlocks: []controlplane.IPNet{ + { + IP: controlplane.IPAddress(net.ParseIP("10.0.0.1")), + PrefixLength: int32(24), + }, + }, + TotalMembers: 0, + TotalPages: 0, + CurrentPage: 0, + }, + expectedErr: false, + }, + } + rest := NewREST(fakeQuerier{members: getTestMembers(), ipMembers: getTestIPMembers()}) + for _, tt := range tests { + actualGroupList, err := rest.Get(request.WithNamespace(request.NewContext(), tt.namespace), tt.groupName, &controlplane.PaginationGetOptions{}) + if tt.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + assert.Equal(t, tt.expectedObj, actualGroupList) + } +} diff --git a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/controlplane_client.go b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/controlplane_client.go index 7bada10f68b..98c7b89f758 100644 --- a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/controlplane_client.go +++ b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/controlplane_client.go @@ -31,6 +31,7 @@ type ControlplaneV1beta2Interface interface { ClusterGroupMembersGetter EgressGroupsGetter GroupAssociationsGetter + GroupMembersGetter IPGroupAssociationsGetter NetworkPoliciesGetter NodeStatsSummariesGetter @@ -62,6 +63,10 @@ func (c *ControlplaneV1beta2Client) GroupAssociations(namespace string) GroupAss return newGroupAssociations(c, namespace) } +func (c *ControlplaneV1beta2Client) GroupMembers(namespace string) GroupMembersInterface { + return newGroupMembers(c, namespace) +} + func (c *ControlplaneV1beta2Client) IPGroupAssociations() IPGroupAssociationInterface { return newIPGroupAssociations(c) } diff --git a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/fake/fake_controlplane_client.go b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/fake/fake_controlplane_client.go index cc417cf9170..232d3b75f8a 100644 --- a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/fake/fake_controlplane_client.go +++ b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/fake/fake_controlplane_client.go @@ -46,6 +46,10 @@ func (c *FakeControlplaneV1beta2) GroupAssociations(namespace string) v1beta2.Gr return &FakeGroupAssociations{c, namespace} } +func (c *FakeControlplaneV1beta2) GroupMembers(namespace string) v1beta2.GroupMembersInterface { + return &FakeGroupMembers{c, namespace} +} + func (c *FakeControlplaneV1beta2) IPGroupAssociations() v1beta2.IPGroupAssociationInterface { return &FakeIPGroupAssociations{c} } diff --git a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/fake/fake_groupmembers.go b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/fake/fake_groupmembers.go new file mode 100644 index 00000000000..2805f704965 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/fake/fake_groupmembers.go @@ -0,0 +1,47 @@ +// Copyright 2023 Antrea Authors +// +// 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. + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1beta2 "antrea.io/antrea/pkg/apis/controlplane/v1beta2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" +) + +// FakeGroupMembers implements GroupMembersInterface +type FakeGroupMembers struct { + Fake *FakeControlplaneV1beta2 + ns string +} + +var groupmembersResource = schema.GroupVersionResource{Group: "controlplane.antrea.io", Version: "v1beta2", Resource: "groupmembers"} + +var groupmembersKind = schema.GroupVersionKind{Group: "controlplane.antrea.io", Version: "v1beta2", Kind: "GroupMembers"} + +// Get takes name of the groupMembers, and returns the corresponding groupMembers object, and an error if there is any. +func (c *FakeGroupMembers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta2.GroupMembers, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(groupmembersResource, c.ns, name), &v1beta2.GroupMembers{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta2.GroupMembers), err +} diff --git a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/generated_expansion.go b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/generated_expansion.go index ab56cd87d39..b8bde69a5e5 100644 --- a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/generated_expansion.go @@ -26,6 +26,8 @@ type EgressGroupExpansion interface{} type GroupAssociationExpansion interface{} +type GroupMembersExpansion interface{} + type IPGroupAssociationExpansion interface{} type NodeStatsSummaryExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/controlplane/v1beta2/groupmembers.go b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/groupmembers.go new file mode 100644 index 00000000000..a76e57ec033 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/controlplane/v1beta2/groupmembers.go @@ -0,0 +1,65 @@ +// Copyright 2023 Antrea Authors +// +// 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. + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta2 + +import ( + "context" + + v1beta2 "antrea.io/antrea/pkg/apis/controlplane/v1beta2" + scheme "antrea.io/antrea/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + rest "k8s.io/client-go/rest" +) + +// GroupMembersGetter has a method to return a GroupMembersInterface. +// A group's client should implement this interface. +type GroupMembersGetter interface { + GroupMembers(namespace string) GroupMembersInterface +} + +// GroupMembersInterface has methods to work with GroupMembers resources. +type GroupMembersInterface interface { + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta2.GroupMembers, error) + GroupMembersExpansion +} + +// groupMembers implements GroupMembersInterface +type groupMembers struct { + client rest.Interface + ns string +} + +// newGroupMembers returns a GroupMembers +func newGroupMembers(c *ControlplaneV1beta2Client, namespace string) *groupMembers { + return &groupMembers{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the groupMembers, and returns the corresponding groupMembers object, and an error if there is any. +func (c *groupMembers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta2.GroupMembers, err error) { + result = &v1beta2.GroupMembers{} + err = c.client.Get(). + Namespace(c.ns). + Resource("groupmembers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} diff --git a/pkg/controller/networkpolicy/clustergroup.go b/pkg/controller/networkpolicy/clustergroup.go index 079065114c2..735b365c241 100644 --- a/pkg/controller/networkpolicy/clustergroup.go +++ b/pkg/controller/networkpolicy/clustergroup.go @@ -421,17 +421,17 @@ func (c *NetworkPolicyController) getParentGroups(grpName string) []antreatypes. return groups } -// GetGroupMembers returns the current members of a ClusterGroup. -// If the ClusterGroup is defined with IPBlocks, the returned members will be []controlplane.IPBlock. +// GetGroupMembers returns the current members of a ClusterGroup/Group. +// If the ClusterGroup/Group is defined with IPBlocks, the returned members will be []controlplane.IPBlock. // Otherwise, the returned members will be of type controlplane.GroupMemberSet. -func (c *NetworkPolicyController) GetGroupMembers(cgName string) (controlplane.GroupMemberSet, []controlplane.IPBlock, error) { - groupObj, found, _ := c.internalGroupStore.Get(cgName) +func (c *NetworkPolicyController) GetGroupMembers(name string) (controlplane.GroupMemberSet, []controlplane.IPBlock, error) { + groupObj, found, _ := c.internalGroupStore.Get(name) if found { group := groupObj.(*antreatypes.Group) member, ipb := c.getInternalGroupMembers(group) return member, ipb, nil } - return nil, nil, fmt.Errorf("no internal Group with name %s is found", cgName) + return nil, nil, fmt.Errorf("no internal Group with name %s is found", name) } func (c *NetworkPolicyController) GetAssociatedIPBlockGroups(ip net.IP) []antreatypes.Group { diff --git a/pkg/controller/networkpolicy/clustergroup_test.go b/pkg/controller/networkpolicy/clustergroup_test.go index e273c4adb65..e957d024318 100644 --- a/pkg/controller/networkpolicy/clustergroup_test.go +++ b/pkg/controller/networkpolicy/clustergroup_test.go @@ -879,7 +879,7 @@ func TestGetAssociatedGroups(t *testing.T) { } } -func TestGetGroupMembers(t *testing.T) { +func TestGetClusterGroupMembers(t *testing.T) { pod1MemberSet := controlplane.GroupMemberSet{} pod1MemberSet.Insert(podToGroupMember(testPods[0], true)) pod12MemberSet := controlplane.GroupMemberSet{} diff --git a/pkg/controller/networkpolicy/group.go b/pkg/controller/networkpolicy/group.go index 4fdb1345792..ab2486330a6 100644 --- a/pkg/controller/networkpolicy/group.go +++ b/pkg/controller/networkpolicy/group.go @@ -27,6 +27,7 @@ import ( "antrea.io/antrea/pkg/apis/controlplane" crdv1beta1 "antrea.io/antrea/pkg/apis/crd/v1beta1" antreatypes "antrea.io/antrea/pkg/controller/types" + "antrea.io/antrea/pkg/util/k8s" ) // addGroup is responsible for processing the ADD event of a Group resource. @@ -181,7 +182,7 @@ func (n *NetworkPolicyController) syncInternalNamespacedGroup(grp *antreatypes.G // 2. All its child groups are created and realized. if len(grp.ChildGroups) > 0 { for _, cgName := range grp.ChildGroups { - internalGroup, found, _ := n.internalGroupStore.Get(grp.SourceReference.Namespace + "/" + cgName) + internalGroup, found, _ := n.internalGroupStore.Get(k8s.NamespacedName(grp.SourceReference.Namespace, cgName)) if !found || internalGroup.(*antreatypes.Group).MembersComputed != v1.ConditionTrue { membersComputed = false break diff --git a/pkg/controller/networkpolicy/group_test.go b/pkg/controller/networkpolicy/group_test.go index c743d098d71..153266c48a0 100644 --- a/pkg/controller/networkpolicy/group_test.go +++ b/pkg/controller/networkpolicy/group_test.go @@ -26,6 +26,7 @@ import ( "antrea.io/antrea/pkg/apis/controlplane" crdv1beta1 "antrea.io/antrea/pkg/apis/crd/v1beta1" antreatypes "antrea.io/antrea/pkg/controller/types" + "antrea.io/antrea/pkg/util/k8s" ) func TestProcessGroup(t *testing.T) { @@ -536,3 +537,54 @@ func TestGetGroupSourceRef(t *testing.T) { }) } } + +func TestGetGroupMembers(t *testing.T) { + var namespacedGroups []antreatypes.Group + for _, group := range groups { + group.SourceReference.Namespace = "test-ns" + namespacedGroups = append(namespacedGroups, group) + } + pod1MemberSet := controlplane.GroupMemberSet{} + pod1MemberSet.Insert(podToGroupMember(testPods[0], true)) + pod12MemberSet := controlplane.GroupMemberSet{} + pod12MemberSet.Insert(podToGroupMember(testPods[0], true)) + pod12MemberSet.Insert(podToGroupMember(testPods[1], true)) + tests := []struct { + name string + group antreatypes.Group + expectedMembers controlplane.GroupMemberSet + }{ + { + "multiple-members", + namespacedGroups[1], + pod12MemberSet, + }, + { + "single-member", + namespacedGroups[0], + pod1MemberSet, + }, + { + "no-member", + namespacedGroups[2], + controlplane.GroupMemberSet{}, + }, + } + _, npc := newController(nil, nil) + for i := range testPods { + npc.groupingInterface.AddPod(testPods[i]) + } + for j := range externalEntities { + npc.groupingInterface.AddExternalEntity(externalEntities[j]) + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + npc.internalGroupStore.Create(&tt.group) + groupName := k8s.NamespacedName(tt.group.SourceReference.Namespace, tt.group.SourceReference.Name) + npc.groupingInterface.AddGroup(internalGroupType, groupName, tt.group.Selector) + members, _, err := npc.GetGroupMembers(groupName) + assert.Equal(t, nil, err) + assert.Equal(t, tt.expectedMembers, members) + }) + } +}