go.ligato.io/vpp-agent/v3@v3.5.0/tests/e2e/e2etest/options.go (about) 1 // Copyright (c) 2020 Pantheon.tech 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 e2etest 16 17 import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 "strings" 22 23 docker "github.com/fsouza/go-dockerclient" 24 "github.com/onsi/gomega" 25 "go.ligato.io/cn-infra/v2/logging" 26 ) 27 28 // SetupOpt is options data holder for customizing setup of tests 29 type SetupOpt struct { 30 AgentOptMods []AgentOptModifier 31 EtcdOptMods []EtcdOptModifier 32 DNSOptMods []DNSOptModifier 33 SetupAgent bool 34 SetupEtcd bool 35 SetupDNSServer bool 36 37 ctx *TestCtx 38 } 39 40 // AgentOpt is options data holder for customizing setup of agent 41 type AgentOpt struct { 42 Runtime ComponentRuntime 43 RuntimeStartOptions RuntimeStartOptionsFunc 44 Name string 45 Image string 46 Env []string 47 UseEtcd bool 48 InitialResync bool 49 ContainerOptsHook func(*docker.CreateContainerOptions) 50 } 51 52 // MicroserviceOpt is options data holder for customizing setup of microservice 53 type MicroserviceOpt struct { 54 Runtime ComponentRuntime 55 RuntimeStartOptions RuntimeStartOptionsFunc 56 Name string 57 ContainerOptsHook func(*docker.CreateContainerOptions) 58 } 59 60 // EtcdOpt is options data holder for customizing setup of ETCD 61 type EtcdOpt struct { 62 Runtime ComponentRuntime 63 RuntimeStartOptions RuntimeStartOptionsFunc 64 UseHTTPS bool 65 UseTestContainerForNetworking bool 66 } 67 68 // DNSOpt is options data holder for customizing setup of DNS server 69 type DNSOpt struct { 70 Runtime ComponentRuntime 71 RuntimeStartOptions RuntimeStartOptionsFunc 72 73 // DomainNameSuffix is common suffix of all static dns entries configured in hostsConfig 74 DomainNameSuffix string 75 // HostsConfig is content of configuration of static DNS entries in hosts file format 76 HostsConfig string 77 } 78 79 // RuntimeStartOptionsFunc is function that provides component runtime start options 80 type RuntimeStartOptionsFunc func(ctx *TestCtx, options interface{}) (interface{}, error) 81 82 // PingOpt are options for pinging command. 83 type PingOpt struct { 84 AllowedLoss int // percentage of allowed loss for success 85 SourceIface string // outgoing interface name 86 MaxTimeout int // timeout in seconds before ping exits 87 Count int // number of pings 88 } 89 90 // SetupOptModifier is function customizing general setup options 91 type SetupOptModifier func(*SetupOpt) 92 93 // AgentOptModifier is function customizing Agent setup options 94 type AgentOptModifier func(*AgentOpt) 95 96 // MicroserviceOptModifier is function customizing Microservice setup options 97 type MicroserviceOptModifier func(*MicroserviceOpt) 98 99 // EtcdOptModifier is function customizing ETCD setup options 100 type EtcdOptModifier func(*EtcdOpt) 101 102 // DNSOptModifier is function customizing DNS server setup options 103 type DNSOptModifier func(*DNSOpt) 104 105 // PingOptModifier is modifiers of pinging options 106 type PingOptModifier func(*PingOpt) 107 108 // DefaultSetupOpt creates default values for SetupOpt 109 func DefaultSetupOpt(testCtx *TestCtx) *SetupOpt { 110 opt := &SetupOpt{ 111 AgentOptMods: nil, 112 EtcdOptMods: nil, 113 DNSOptMods: nil, 114 SetupAgent: true, 115 SetupEtcd: false, 116 SetupDNSServer: false, 117 ctx: testCtx, 118 } 119 return opt 120 } 121 122 // DefaultEtcdOpt creates default values for EtcdOpt 123 func DefaultEtcdOpt(ctx *TestCtx) *EtcdOpt { 124 return &EtcdOpt{ 125 Runtime: &ContainerRuntime{ 126 ctx: ctx, 127 logIdentity: "ETCD", 128 stopTimeout: etcdStopTimeout, 129 }, 130 RuntimeStartOptions: ETCDStartOptionsForContainerRuntime, 131 UseHTTPS: false, 132 UseTestContainerForNetworking: false, 133 } 134 } 135 136 // DefaultDNSOpt creates default values for DNSOpt 137 func DefaultDNSOpt(testCtx *TestCtx) *DNSOpt { 138 return &DNSOpt{ 139 Runtime: &ContainerRuntime{ 140 ctx: testCtx, 141 logIdentity: "DNS server", 142 stopTimeout: dnsStopTimeout, 143 }, 144 RuntimeStartOptions: DNSServerStartOptionsForContainerRuntime, 145 DomainNameSuffix: "", // no DNS entries => no common domain name suffix 146 HostsConfig: "", // no DNS entries 147 } 148 } 149 150 // DefaultMicroserviceiOpt creates default values for MicroserviceOpt 151 func DefaultMicroserviceOpt(testCtx *TestCtx, msName string) *MicroserviceOpt { 152 return &MicroserviceOpt{ 153 Runtime: &ContainerRuntime{ 154 ctx: testCtx, 155 logIdentity: "Microservice " + msName, 156 stopTimeout: msStopTimeout, 157 }, 158 RuntimeStartOptions: MicroserviceStartOptionsForContainerRuntime, 159 Name: msName, 160 } 161 } 162 163 // DefaultAgentOpt creates default values for AgentOpt 164 func DefaultAgentOpt(testCtx *TestCtx, agentName string) *AgentOpt { 165 agentImg := agentImage 166 if img := os.Getenv("VPP_AGENT"); img != "" { 167 agentImg = img 168 } 169 grpcConfig := "grpc.conf" 170 if val := os.Getenv("GRPC_CONFIG"); val != "" { 171 grpcConfig = val 172 } 173 etcdConfig := "DISABLED" 174 if val := os.Getenv("ETCD_CONFIG"); val != "" { 175 etcdConfig = val 176 } 177 opt := &AgentOpt{ 178 Runtime: &ContainerRuntime{ 179 ctx: testCtx, 180 logIdentity: "Agent " + agentName, 181 stopTimeout: agentStopTimeout, 182 }, 183 RuntimeStartOptions: AgentStartOptionsForContainerRuntime, 184 Name: agentName, 185 Image: agentImg, 186 UseEtcd: false, 187 InitialResync: true, 188 Env: []string{ 189 "INITIAL_LOGLVL=" + logging.DefaultLogger.GetLevel().String(), 190 "ETCD_CONFIG=" + etcdConfig, 191 "GRPC_CONFIG=" + grpcConfig, 192 "DEBUG=" + os.Getenv("DEBUG"), 193 "MICROSERVICE_LABEL=" + agentName, 194 }, 195 } 196 return opt 197 } 198 199 // DefaultPingOpts creates default values for PingOpt 200 func DefaultPingOpts() *PingOpt { 201 return &PingOpt{ 202 AllowedLoss: 49, // by default at least half of the packets should get through 203 MaxTimeout: 4, 204 } 205 } 206 207 // WithoutVPPAgent is test setup option disabling vpp-agent setup 208 func WithoutVPPAgent() SetupOptModifier { 209 return func(o *SetupOpt) { 210 o.SetupAgent = false 211 } 212 } 213 214 // WithCustomVPPAgent is test setup option using alternative vpp-agent image (customized original vpp-agent) 215 func WithCustomVPPAgent() SetupOptModifier { 216 return func(o *SetupOpt) { 217 o.AgentOptMods = append(o.AgentOptMods, func(ao *AgentOpt) { 218 ao.Image = "vppagent.test.ligato.io:custom" 219 }) 220 } 221 } 222 223 // WithEtcd is test setup option enabling etcd setup 224 func WithEtcd(etcdOptMods ...EtcdOptModifier) SetupOptModifier { 225 return func(o *SetupOpt) { 226 o.SetupEtcd = true 227 o.EtcdOptMods = append(o.EtcdOptMods, etcdOptMods...) 228 } 229 } 230 231 // WithDNSServer is test setup option enabling setup of container serving as dns server 232 func WithDNSServer(dnsOpts ...DNSOptModifier) SetupOptModifier { 233 return func(o *SetupOpt) { 234 o.SetupDNSServer = true 235 } 236 } 237 238 // WithoutManualInitialAgentResync is test setup option disabling manual agent resync just after agent setup 239 func WithoutManualInitialAgentResync() AgentOptModifier { 240 return func(o *AgentOpt) { 241 o.InitialResync = false 242 } 243 } 244 245 // WithAdditionalAgentCmdParams is test setup option adding additional command line parameters to executing vpp-agent 246 func WithAdditionalAgentCmdParams(params ...string) AgentOptModifier { 247 return func(o *AgentOpt) { 248 o.Env = append(o.Env, params...) 249 } 250 } 251 252 // WithZonedStaticEntries is test setup option configuring group of static dns cache entries that belong 253 // to the same zone (have the same domain name suffix). The static dns cache entries are lines of config file 254 // in linux /etc/hosts file format. 255 // Currently supporting only one domain name suffix with static entries (even when DNS server solution supports 256 // multiple "zones" that each of them can be configured by one file in hosts file format) 257 func WithZonedStaticEntries(zoneDomainNameSuffix string, staticEntries ...string) DNSOptModifier { 258 return func(o *DNSOpt) { 259 o.DomainNameSuffix = zoneDomainNameSuffix 260 o.HostsConfig = strings.Join(staticEntries, "\n") 261 } 262 } 263 264 // WithPluginConfigArg persists configContent for give VPP-Agent plugin (expecting generic plugin config name) 265 // and returns argument for VPP-Agent executable to use this plugin configuration file. 266 func WithPluginConfigArg(ctx *TestCtx, pluginName string, configContent string) string { 267 configFilePath := CreateFileOnSharedVolume(ctx, fmt.Sprintf("%v.config", pluginName), configContent) 268 return fmt.Sprintf("%v_CONFIG=%v", strings.ToUpper(pluginName), configFilePath) 269 } 270 271 // FIXME container that will use it can have it mounted in different location as seen by the container where 272 // it is created (this works now due to the same mountpoint of shared volume in every container) 273 274 // CreateFileOnSharedVolume persists fileContent to file in mounted shared volume used for sharing file 275 // between containers. It returns the absolute path to the newly created file as seen by the container 276 // that creates it. 277 func CreateFileOnSharedVolume(ctx *TestCtx, simpleFileName string, fileContent string) string { 278 // subtest test names can container filepath.Separator 279 testName := strings.ReplaceAll(ctx.t.Name(), string(filepath.Separator), "-") 280 filePath, err := filepath.Abs(filepath.Join(ctx.ShareDir, 281 fmt.Sprintf("e2e-test-%v-%v", testName, simpleFileName))) 282 ctx.Expect(err).To(gomega.Not(gomega.HaveOccurred())) 283 ctx.Expect(os.WriteFile(filePath, []byte(fileContent), 0777)).To(gomega.Succeed()) 284 285 // TODO register in context and delete in teardown? this doesn't matter 286 // that much because file names contain unique test names so no file collision can happen 287 return filePath 288 } 289 290 // WithMSContainerStartHook is microservice test setup option that will set the microservice container start 291 // hook that will modify the microservice start options. 292 func WithMSContainerStartHook(hook func(*docker.CreateContainerOptions)) MicroserviceOptModifier { 293 return func(opt *MicroserviceOpt) { 294 opt.ContainerOptsHook = hook 295 } 296 } 297 298 // WithEtcdHTTPsConnection is ETCD test setup option that will use HTTPS connection to ETCD (by default it is used 299 // unsecure HTTP connection) 300 func WithEtcdHTTPsConnection() EtcdOptModifier { 301 return func(o *EtcdOpt) { 302 o.UseHTTPS = true 303 } 304 } 305 306 // WithEtcdTestContainerNetworking is ETCD test setup option that will use main Test container for 307 // networking (by default the ETCD has separate networking) 308 func WithEtcdTestContainerNetworking() EtcdOptModifier { 309 return func(o *EtcdOpt) { 310 o.UseTestContainerForNetworking = true 311 } 312 } 313 314 // NewPingOpts create new PingOpt 315 func NewPingOpts(opts ...PingOptModifier) *PingOpt { 316 options := DefaultPingOpts() 317 for _, o := range opts { 318 o(options) 319 } 320 return options 321 } 322 323 func (ping *PingOpt) args() []string { 324 var args []string 325 if ping.MaxTimeout > 0 { 326 args = append(args, "-w", fmt.Sprint(ping.MaxTimeout)) 327 } 328 if ping.Count > 0 { 329 args = append(args, "-c", fmt.Sprint(ping.Count)) 330 } 331 if ping.SourceIface != "" { 332 args = append(args, "-I", ping.SourceIface) 333 } 334 return args 335 } 336 337 // PingWithAllowedLoss sets max allowed packet loss for pinging to be considered successful. 338 func PingWithAllowedLoss(maxLoss int) PingOptModifier { 339 return func(opts *PingOpt) { 340 opts.AllowedLoss = maxLoss 341 } 342 } 343 344 // PingWithSourceInterface set source interface for ping packets. 345 func PingWithSourceInterface(iface string) PingOptModifier { 346 return func(opts *PingOpt) { 347 opts.SourceIface = iface 348 } 349 }