istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/writer/pilot/status_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pilot 16 17 import ( 18 "bytes" 19 "encoding/json" 20 "os" 21 "testing" 22 23 core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" 24 discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" 25 status "github.com/envoyproxy/go-control-plane/envoy/service/status/v3" 26 "google.golang.org/protobuf/types/known/anypb" 27 28 "istio.io/istio/pilot/pkg/model" 29 "istio.io/istio/pilot/pkg/util/protoconv" 30 "istio.io/istio/pilot/pkg/xds" 31 v3 "istio.io/istio/pilot/pkg/xds/v3" 32 "istio.io/istio/pkg/cluster" 33 "istio.io/istio/pkg/test/util/assert" 34 istioversion "istio.io/istio/pkg/version" 35 "istio.io/istio/tests/util" 36 ) 37 38 func TestXdsStatusWriter_PrintAll(t *testing.T) { 39 tests := []struct { 40 name string 41 input map[string]*discovery.DiscoveryResponse 42 want string 43 wantErr bool 44 }{ 45 { 46 name: "prints multiple istiod inputs to buffer in alphabetical order by pod name", 47 input: map[string]*discovery.DiscoveryResponse{ 48 "istiod1": xdsResponseInput("istiod1", []clientConfigInput{ 49 { 50 proxyID: "proxy1", 51 clusterID: "cluster1", 52 version: "1.20", 53 cdsSyncStatus: status.ConfigStatus_STALE, 54 ldsSyncStatus: status.ConfigStatus_SYNCED, 55 rdsSyncStatus: status.ConfigStatus_NOT_SENT, 56 edsSyncStatus: status.ConfigStatus_SYNCED, 57 ecdsSyncStatus: status.ConfigStatus_SYNCED, 58 }, 59 }), 60 "istiod2": xdsResponseInput("istiod2", []clientConfigInput{ 61 { 62 proxyID: "proxy2", 63 clusterID: "cluster2", 64 version: "1.19", 65 cdsSyncStatus: status.ConfigStatus_STALE, 66 ldsSyncStatus: status.ConfigStatus_SYNCED, 67 rdsSyncStatus: status.ConfigStatus_SYNCED, 68 edsSyncStatus: status.ConfigStatus_STALE, 69 ecdsSyncStatus: status.ConfigStatus_STALE, 70 }, 71 }), 72 "istiod3": xdsResponseInput("istiod3", []clientConfigInput{ 73 { 74 proxyID: "proxy3", 75 clusterID: "cluster3", 76 version: "1.20", 77 cdsSyncStatus: status.ConfigStatus_NOT_SENT, 78 ldsSyncStatus: status.ConfigStatus_ERROR, 79 rdsSyncStatus: status.ConfigStatus_NOT_SENT, 80 edsSyncStatus: status.ConfigStatus_STALE, 81 ecdsSyncStatus: status.ConfigStatus_NOT_SENT, 82 }, 83 }), 84 "istiod4": xdsResponseInput("istiod4", []clientConfigInput{ 85 { 86 proxyID: "proxy4", 87 clusterID: "cluster4", 88 version: "1.20", 89 cdsSyncStatus: status.ConfigStatus_UNKNOWN, 90 ldsSyncStatus: status.ConfigStatus_UNKNOWN, 91 rdsSyncStatus: status.ConfigStatus_UNKNOWN, 92 edsSyncStatus: status.ConfigStatus_UNKNOWN, 93 ecdsSyncStatus: status.ConfigStatus_UNKNOWN, 94 }, 95 }), 96 }, 97 want: "testdata/multiXdsStatusMultiPilot.txt", 98 }, 99 { 100 name: "prints single istiod input to buffer in alphabetical order by pod name", 101 input: map[string]*discovery.DiscoveryResponse{ 102 "istiod1": xdsResponseInput("istiod1", []clientConfigInput{ 103 { 104 proxyID: "proxy1", 105 clusterID: "cluster1", 106 version: "1.20", 107 cdsSyncStatus: status.ConfigStatus_STALE, 108 ldsSyncStatus: status.ConfigStatus_SYNCED, 109 rdsSyncStatus: status.ConfigStatus_NOT_SENT, 110 edsSyncStatus: status.ConfigStatus_SYNCED, 111 ecdsSyncStatus: status.ConfigStatus_NOT_SENT, 112 }, 113 { 114 proxyID: "proxy2", 115 clusterID: "cluster2", 116 version: "1.20", 117 cdsSyncStatus: status.ConfigStatus_STALE, 118 ldsSyncStatus: status.ConfigStatus_SYNCED, 119 rdsSyncStatus: status.ConfigStatus_SYNCED, 120 edsSyncStatus: status.ConfigStatus_STALE, 121 ecdsSyncStatus: status.ConfigStatus_NOT_SENT, 122 }, 123 }), 124 }, 125 want: "testdata/multiXdsStatusSinglePilot.txt", 126 }, 127 } 128 for _, tt := range tests { 129 t.Run(tt.name, func(t *testing.T) { 130 got := &bytes.Buffer{} 131 sw := XdsStatusWriter{Writer: got} 132 input := map[string]*discovery.DiscoveryResponse{} 133 for key, ss := range tt.input { 134 input[key] = ss 135 } 136 137 err := sw.PrintAll(input) 138 if tt.wantErr { 139 assert.Error(t, err) 140 } else { 141 assert.NoError(t, err) 142 } 143 want, _ := os.ReadFile(tt.want) 144 if err := util.Compare(got.Bytes(), want); err != nil { 145 t.Errorf(err.Error()) 146 } 147 }) 148 } 149 } 150 151 const clientConfigType = "type.googleapis.com/envoy.service.status.v3.ClientConfig" 152 153 type clientConfigInput struct { 154 proxyID string 155 clusterID string 156 version string 157 158 cdsSyncStatus status.ConfigStatus 159 ldsSyncStatus status.ConfigStatus 160 rdsSyncStatus status.ConfigStatus 161 edsSyncStatus status.ConfigStatus 162 ecdsSyncStatus status.ConfigStatus 163 } 164 165 func newXdsClientConfig(config clientConfigInput) *status.ClientConfig { 166 meta := model.NodeMetadata{ 167 ClusterID: cluster.ID(config.clusterID), 168 IstioVersion: config.version, 169 } 170 return &status.ClientConfig{ 171 Node: &core.Node{ 172 Id: config.proxyID, 173 Metadata: meta.ToStruct(), 174 }, 175 GenericXdsConfigs: []*status.ClientConfig_GenericXdsConfig{ 176 { 177 TypeUrl: v3.ClusterType, 178 ConfigStatus: config.cdsSyncStatus, 179 }, 180 { 181 TypeUrl: v3.ListenerType, 182 ConfigStatus: config.ldsSyncStatus, 183 }, 184 { 185 TypeUrl: v3.RouteType, 186 ConfigStatus: config.rdsSyncStatus, 187 }, 188 { 189 TypeUrl: v3.EndpointType, 190 ConfigStatus: config.edsSyncStatus, 191 }, 192 { 193 TypeUrl: v3.ExtensionConfigurationType, 194 ConfigStatus: config.ecdsSyncStatus, 195 }, 196 }, 197 } 198 } 199 200 func xdsResponseInput(istiodID string, configInputs []clientConfigInput) *discovery.DiscoveryResponse { 201 icp := &xds.IstioControlPlaneInstance{ 202 Component: "istiod", 203 ID: istiodID, 204 Info: istioversion.BuildInfo{ 205 Version: "1.1", 206 }, 207 } 208 identifier, _ := json.Marshal(icp) 209 210 resources := make([]*anypb.Any, 0) 211 for _, input := range configInputs { 212 resources = append(resources, protoconv.MessageToAny(newXdsClientConfig(input))) 213 } 214 215 return &discovery.DiscoveryResponse{ 216 VersionInfo: "1.1", 217 TypeUrl: clientConfigType, 218 Resources: resources, 219 ControlPlane: &core.ControlPlane{ 220 Identifier: string(identifier), 221 }, 222 } 223 }