diff --git a/.gitignore b/.gitignore index 026134d26a..9a64c44b2a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.dll *.so *.dylib +*__debug* # Avoid checking in keys *.pem diff --git a/hack/tools/kapinger/go.mod b/hack/tools/kapinger/go.mod index 1d3e1c7422..a2461a784b 100644 --- a/hack/tools/kapinger/go.mod +++ b/hack/tools/kapinger/go.mod @@ -3,23 +3,24 @@ module github.com/microsoft/retina/hack/tools/kapinger go 1.22.5 require ( + github.com/microsoft/retina v0.10.0 k8s.io/api v0.30.2 k8s.io/apimachinery v0.30.2 k8s.io/client-go v0.30.2 ) require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.2 // indirect github.com/go-logr/logr v1.4.1 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/jsonpointer v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/swag v0.22.10 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -32,16 +33,16 @@ require ( golang.org/x/sys v0.18.0 // indirect golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.33.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/protobuf v1.34.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/hack/tools/kapinger/go.sum b/hack/tools/kapinger/go.sum index d5d665ee17..f6c65c2715 100644 --- a/hack/tools/kapinger/go.sum +++ b/hack/tools/kapinger/go.sum @@ -2,16 +2,26 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU= +github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.10 h1:4y86NVn7Z2yYd6pfS4Z+Nyh3aAUL3Nul+LMbhFKy0gA= +github.com/go-openapi/swag v0.22.10/go.mod h1:Cnn8BYtRlx6BNE3DPN86f/xkapGIcLWzh3CLEb4C1jI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -21,6 +31,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU= +github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -31,6 +43,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -46,6 +60,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/microsoft/retina v0.10.0 h1:LBFqEidd3oJZ0cKnn16wj0gLwYUcZEwEXoWVNrsWOJ0= +github.com/microsoft/retina v0.10.0/go.mod h1:rfXc+UqWj1qSRE5hZw8JuFGl3ILxO6/CIyhQoAmwd0s= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -86,8 +102,12 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -98,8 +118,12 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -107,6 +131,8 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -119,8 +145,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= +google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -144,9 +174,13 @@ k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7F k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/tools/kapinger/servers/http.go b/hack/tools/kapinger/servers/http.go index 5810c5e4d5..ce8d029442 100644 --- a/hack/tools/kapinger/servers/http.go +++ b/hack/tools/kapinger/servers/http.go @@ -22,7 +22,7 @@ func (k *KapingerHTTPServer) Start(ctx context.Context) error { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err := w.Write(getResponse(r.RemoteAddr, "http")) if err != nil { - fmt.Println(err) + fmt.Printf("http server: error writing response: %v\n", err) } }) diff --git a/hack/tools/kapinger/servers/util.go b/hack/tools/kapinger/servers/util.go index 497c90071e..d81662b5a0 100644 --- a/hack/tools/kapinger/servers/util.go +++ b/hack/tools/kapinger/servers/util.go @@ -7,5 +7,5 @@ import ( func getResponse(addressString, protocol string) []byte { podname := os.Getenv("POD_NAME") - return []byte(fmt.Sprintf("connected to: %s via %s, connected from: %v", podname, protocol, addressString)) + return []byte(fmt.Sprintf("connected to: %s via %s, connected from: %v\n", podname, protocol, addressString)) } diff --git a/test/e2e/Makefile b/test/e2e/Makefile new file mode 100644 index 0000000000..9bc1e8ee2d --- /dev/null +++ b/test/e2e/Makefile @@ -0,0 +1,16 @@ + +.PHONY: longrunning +longrunning: + @echo "Running long running tests" + @echo "Be sure to set CLUSTER_NAME, TAG, AZURE_LOCATION, AZURE_SUBSCRIPTION_ID" + @if [ -z "$$CLUSTER_NAME" ]; then echo "CLUSTER_NAME is not set"; exit 1; fi + @if [ -z "$$AZURE_LOCATION" ]; then echo "AZURE_LOCATION is not set"; exit 1; fi + @if [ -z "$$AZURE_SUBSCRIPTION_ID" ]; then echo "AZURE_SUBSCRIPTION_ID is not set"; exit 1; fi + @if [ -z "$$TAG" ]; then echo "TAG is not set"; exit 1; fi + go test -v ./*.go -timeout 0 -tags=e2e -count=1 \ + -run=TestLongRunningRetina \ + -args \ + -create-infra=false \ + -delete-infra=false \ + -image-namespace=microsoft/retina \ + -image-registry=acnpublic.azurecr.io diff --git a/test/e2e/framework/kubernetes/check-pod-status.go b/test/e2e/framework/kubernetes/check-pod-status.go index 27405031bb..c360400b81 100644 --- a/test/e2e/framework/kubernetes/check-pod-status.go +++ b/test/e2e/framework/kubernetes/check-pod-status.go @@ -37,7 +37,6 @@ func (w *WaitPodsReady) Prevalidate() error { // Primary step where test logic is executed // Returning an error will cause the test to fail func (w *WaitPodsReady) Run() error { - config, err := clientcmd.BuildConfigFromFlags("", w.KubeConfigFilePath) if err != nil { return fmt.Errorf("error building kubeconfig: %w", err) @@ -95,7 +94,8 @@ func WaitForPodReady(ctx context.Context, clientset *kubernetes.Clientset, names } // Check all container status. - for _, containerStatus := range pod.Status.ContainerStatuses { + for i := range pod.Status.ContainerStatuses { + containerStatus := &pod.Status.ContainerStatuses[i] if !containerStatus.Ready { log.Printf("container \"%s\" in pod \"%s\" is not ready yet. Waiting...\n", containerStatus.Name, pod.Name) return false, nil diff --git a/test/e2e/framework/kubernetes/create-agnhost-statefulset.go b/test/e2e/framework/kubernetes/create-agnhost-statefulset.go index 6783d7aa66..8f071ee333 100644 --- a/test/e2e/framework/kubernetes/create-agnhost-statefulset.go +++ b/test/e2e/framework/kubernetes/create-agnhost-statefulset.go @@ -90,7 +90,6 @@ func (c *CreateAgnhostStatefulSet) getAgnhostDeployment() *appsv1.StatefulSet { }, }, } - } else { affinity = &v1.Affinity{ PodAntiAffinity: &v1.PodAntiAffinity{ diff --git a/test/e2e/framework/kubernetes/create-kapinger-deployment.go b/test/e2e/framework/kubernetes/create-kapinger-deployment.go index 06862e1c09..248b29c5ca 100644 --- a/test/e2e/framework/kubernetes/create-kapinger-deployment.go +++ b/test/e2e/framework/kubernetes/create-kapinger-deployment.go @@ -27,6 +27,8 @@ type CreateKapingerDeployment struct { KapingerNamespace string KapingerReplicas string KubeConfigFilePath string + BurstIntervalMs string + BurstVolume string } func (c *CreateKapingerDeployment) Run() error { @@ -63,6 +65,11 @@ func (c *CreateKapingerDeployment) Run() error { } } + err = WaitForPodReady(ctx, clientset, c.KapingerNamespace, "app=kapinger") + if err != nil { + return fmt.Errorf("error waiting for agnhost pod to be ready: %w", err) + } + return nil } @@ -92,6 +99,13 @@ func (c *CreateKapingerDeployment) GetKapingerDeployment() *appsv1.Deployment { Namespace: c.KapingerNamespace, }, Spec: appsv1.DeploymentSpec{ + Strategy: appsv1.DeploymentStrategy{ + Type: appsv1.RollingUpdateDeploymentStrategyType, + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{IntVal: 20}, + MaxSurge: &intstr.IntOrString{IntVal: 20}, + }, + }, Replicas: &reps, Selector: &metaV1.LabelSelector{ MatchLabels: map[string]string{ @@ -148,8 +162,28 @@ func (c *CreateKapingerDeployment) GetKapingerDeployment() *appsv1.Deployment { }, Env: []v1.EnvVar{ { - Name: "GODEBUG", - Value: "netdns=go", + Name: "POD_NAME", + ValueFrom: &v1.EnvVarSource{ + FieldRef: &v1.ObjectFieldSelector{ + FieldPath: "metadata.name", + }, + }, + }, + { + Name: "POD_IP", + ValueFrom: &v1.EnvVarSource{ + FieldRef: &v1.ObjectFieldSelector{ + FieldPath: "status.podIP", + }, + }, + }, + { + Name: "GOMEMLIMIT", + ValueFrom: &v1.EnvVarSource{ + ResourceFieldRef: &v1.ResourceFieldSelector{ + Resource: "limits.memory", + }, + }, }, { Name: "TARGET_TYPE", @@ -167,6 +201,14 @@ func (c *CreateKapingerDeployment) GetKapingerDeployment() *appsv1.Deployment { Name: "UDP_PORT", Value: strconv.Itoa(KapingerUDPPort), }, + { + Name: "BURST_INTERVAL_MS", + Value: c.BurstIntervalMs, + }, + { + Name: "BURST_VOLUME", + Value: c.BurstVolume, + }, }, }, }, diff --git a/test/e2e/framework/kubernetes/get-external-crd.go b/test/e2e/framework/kubernetes/get-external-crd.go index 1564691362..6e80e226ab 100644 --- a/test/e2e/framework/kubernetes/get-external-crd.go +++ b/test/e2e/framework/kubernetes/get-external-crd.go @@ -55,7 +55,7 @@ func extractFileName(rawURL string) (string, error) { } func saveToFile(filename string, data []byte) error { - err := os.WriteFile(filename, data, 0644) + err := os.WriteFile(filename, data, 0o644) if err != nil { return fmt.Errorf("failed to write crd.yaml to /crds dir : %w", err) } diff --git a/test/e2e/framework/kubernetes/install-retina-helm.go b/test/e2e/framework/kubernetes/install-retina-helm.go index 7f1828f17c..deb211fd31 100644 --- a/test/e2e/framework/kubernetes/install-retina-helm.go +++ b/test/e2e/framework/kubernetes/install-retina-helm.go @@ -67,7 +67,7 @@ func (i *InstallHelmChart) Run() error { return fmt.Errorf("image namespace is not set: %w", errEmpty) } - //Download necessary CRD's + // Download necessary CRD's err = downloadExternalCRDs(i.ChartPath) if err != nil { return fmt.Errorf("failed to load external crd's: %w", err) diff --git a/test/e2e/framework/kubernetes/port-forward.go b/test/e2e/framework/kubernetes/port-forward.go index db04368372..60180e7ff5 100644 --- a/test/e2e/framework/kubernetes/port-forward.go +++ b/test/e2e/framework/kubernetes/port-forward.go @@ -110,6 +110,8 @@ func (p *PortForward) Run() error { log.Printf("port forward validation HTTP request to \"%s\" succeeded, response: %s\n", p.pf.Address(), resp.Status) + log.Printf("starting keepalive for port forward...\n") + go p.pf.KeepAlive(pctx) return nil } @@ -117,6 +119,8 @@ func (p *PortForward) Run() error { return fmt.Errorf("could not start port forward within %ds: %w", defaultTimeoutSeconds, err) } log.Printf("successfully port forwarded to \"%s\"\n", p.pf.Address()) + log.Printf("starting port forward keepalive...\n") + go p.pf.KeepAlive(pctx) return nil } diff --git a/test/e2e/framework/kubernetes/portforward.go b/test/e2e/framework/kubernetes/portforward.go index a62728d2c3..d5376d6f8b 100644 --- a/test/e2e/framework/kubernetes/portforward.go +++ b/test/e2e/framework/kubernetes/portforward.go @@ -171,6 +171,9 @@ func (p *PortForwarder) KeepAlive(ctx context.Context) { case <-ctx.Done(): p.logger.Logf("port forwarder: keep alive cancelled: %v", ctx.Err()) return + case <-p.stopChan: + p.logger.Logf("port forwarder: keep alive stopped via stop channel") + return case pfErr := <-p.errChan: // as of client-go v0.26.1, if the connection is successful at first but then fails, // an error is logged but only a nil error is sent to this channel. this will be fixed diff --git a/test/e2e/framework/kubernetes/pprof.go b/test/e2e/framework/kubernetes/pprof.go new file mode 100644 index 0000000000..a85226fbfc --- /dev/null +++ b/test/e2e/framework/kubernetes/pprof.go @@ -0,0 +1,204 @@ +package kubernetes + +import ( + "context" + "fmt" + "io" + "log" + "net/http" + "net/url" + "os" + "strconv" + "time" +) + +const ( + defaultTimeout = 3200 * time.Second + defaultRetinaPort = 10093 + defaultSpanTime = 10 * time.Second +) + +var ( + + // key:profile name, value: pprof endpoint + simpleProfiles = map[string]string{ + "heap": "/heap", + "block": "/block", + "mutex": "/mutex", + "cmdline": "/cmdline", + "symbol": "/symbol", + } + + durationProfiles = map[string]string{ + "cpu": "/profile", + "trace": "/trace", + "goroutine": "/goroutine", + } +) + +type PullPProf struct { + LocalPort string + DurationSeconds string // full duration which includes as many intervals as possible + ScrapeIntervalSeconds string // will pull all profiles at this interval + + scraper *PprofScraper +} + +func (p *PullPProf) Run() error { + host := "localhost" + var err error + p.scraper, err = NewPprofScraper(host, defaultRetinaPort) + if err != nil { + return err + } + + duration, err := strconv.Atoi(p.DurationSeconds) + if err != nil { + return fmt.Errorf("error converting pprof duration to int: %w", err) + } + interval, err := strconv.Atoi(p.ScrapeIntervalSeconds) + if err != nil { + return fmt.Errorf("error converting pprof interval to int: %w", err) + } + + log.Printf("starting pprof scraping for %s seconds at %s second intervals\n", p.DurationSeconds, p.ScrapeIntervalSeconds) + + ticker := time.NewTicker(time.Duration(interval) * time.Second) + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(duration)*time.Second) + defer cancel() + + log.Printf("--pprof viewing commands:--\n") + log.Printf("profile: \tgo tool pprof -http=:8081 %s\n", "profile.out") + log.Printf("heap: \tgo tool pprof -http=:8081 %s\n", "heap.out") + log.Printf("cpu: \tgo tool pprof -http=:8082 %s\n", "cpu.out") + log.Printf("block: \tgo tool pprof -http=:8083 %s\n", "block.out") + log.Printf("mutex: \tgo tool pprof -http=:8084 %s\n", "mutex.out") + log.Printf("cmdline: \tgo tool pprof -http=:8085 %s\n", "cmdline.out") + log.Printf("symbol: \tgo tool pprof -http=:8086 %s\n", "symbol.out") + log.Printf("trace: \tgo tool trace -http=:8087 %s\n", "trace.out") + + scrape := func() error { + log.Printf("-- starting scrape pprof profiles --\n") + folder := "./pprof/" + time.Now().Format("2006.01.02-15:04:05") + "/" + err = os.MkdirAll(folder, os.ModePerm) + if err != nil { + return fmt.Errorf("error creating pprof folder: %w", err) + } + + for name, path := range simpleProfiles { + file := folder + name + ".out" + err = p.scraper.GetProfile(name, path, file) + if err != nil { + // don't return here because some data is better than no data, + // and other profiles might be functional + log.Printf("error getting %s profile: %v\n", name, err) + } + } + + for name, path := range durationProfiles { + file := folder + name + ".out" + err = p.scraper.GetProfileWithDuration(name, path, file, defaultSpanTime) + if err != nil { + // don't return here because some data is better than no data, + // and other profiles might be functional + log.Printf("error getting %s profile: %v\n", name, err) + } + } + + log.Printf("-- finished scraping profiles, saved to to %s --\n", folder) + log.Printf("waiting %s seconds for next scrape\n", p.ScrapeIntervalSeconds) + return err + } + + // pull initial scrape + err = scrape() + if err != nil { + return fmt.Errorf("error pulling pprof profiles: %w", err) + } + + // start scraping on intervals + for { + select { + case <-ctx.Done(): + if err != nil { + return fmt.Errorf("error pulling pprof profiles: %w", err) + } + return nil + case <-ticker.C: + err = scrape() + } + } +} + +func (p *PullPProf) Prevalidate() error { + return nil +} + +func (p *PullPProf) Stop() error { + return nil +} + +type PprofScraper struct { + baseURL *url.URL +} + +func NewPprofScraper(host string, port int) (*PprofScraper, error) { + scraper := &PprofScraper{} + var err error + baseURL := fmt.Sprintf("http://%s:%d/debug/pprof", host, port) + scraper.baseURL, err = url.Parse(baseURL) + if err != nil { + return nil, fmt.Errorf("error parsing URL: %w", err) + } + return scraper, nil +} + +func (p *PprofScraper) GetProfileWithDuration(name, path, outfile string, duration time.Duration) error { + seconds := int(duration.Seconds()) + log.Printf("getting %s profile for %d seconds...\n", name, seconds) + profileURL := p.formatURLWithSeconds(seconds) + profileURL.Path += path + return p.scrape(profileURL.String(), outfile) +} + +func (p *PprofScraper) GetProfile(name, path, outfile string) error { + log.Printf("getting %s profile...\n", name) + return p.scrape(p.baseURL.String()+path, outfile) +} + +func (p *PprofScraper) formatURLWithSeconds(seconds int) url.URL { + // Add query parameters + queryURL := *p.baseURL + q := queryURL.Query() + q.Set("seconds", strconv.Itoa(seconds)) + queryURL.RawQuery = q.Encode() + return queryURL +} + +func (p *PprofScraper) scrape(scrapingURL, outfile string) error { + client := http.Client{} + + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, scrapingURL, http.NoBody) + if err != nil { + return fmt.Errorf("error creating request: %w", err) + } + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("error scraping: %w", err) + } + defer resp.Body.Close() + + file, err := os.Create(outfile) + if err != nil { + return fmt.Errorf("error creating file: %w", err) + } + defer file.Close() + + _, err = io.Copy(file, resp.Body) + if err != nil { + return fmt.Errorf("error copying scrape response to file: %w", err) + } + + return nil +} diff --git a/test/e2e/framework/kubernetes/validateHttp.go b/test/e2e/framework/kubernetes/validateHttp.go index 39e2e400b2..45fa3624f7 100644 --- a/test/e2e/framework/kubernetes/validateHttp.go +++ b/test/e2e/framework/kubernetes/validateHttp.go @@ -21,7 +21,7 @@ func (v *ValidateHTTPResponse) Run() error { ctx, cancel := context.WithTimeout(context.Background(), RequestTimeout) defer cancel() - req, err := http.NewRequestWithContext(ctx, http.MethodGet, v.URL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, v.URL, http.NoBody) if err != nil { return fmt.Errorf("error creating HTTP request: %w", err) } @@ -34,7 +34,7 @@ func (v *ValidateHTTPResponse) Run() error { defer resp.Body.Close() if resp.StatusCode != v.ExpectedStatus { - return fmt.Errorf("unexpected status code: got %d, want %d", resp.StatusCode, v.ExpectedStatus) + return fmt.Errorf("unexpected status code: got %d, want %d", resp.StatusCode, v.ExpectedStatus) //nolint:goerr113 no formatting needed } log.Printf("HTTP validation succeeded for URL: %s with status code %d\n", v.URL, resp.StatusCode) diff --git a/test/e2e/framework/scaletest/add-shared-labels.go b/test/e2e/framework/scaletest/add-shared-labels.go index d76139c0be..086f196696 100644 --- a/test/e2e/framework/scaletest/add-shared-labels.go +++ b/test/e2e/framework/scaletest/add-shared-labels.go @@ -35,7 +35,6 @@ func (a *AddSharedLabelsToAllPods) Prevalidate() error { // Primary step where test logic is executed // Returning an error will cause the test to fail func (a *AddSharedLabelsToAllPods) Run() error { - if a.NumSharedLabelsPerPod < 1 { return nil } diff --git a/test/e2e/framework/scaletest/add-unique-labels.go b/test/e2e/framework/scaletest/add-unique-labels.go index cfdd458c82..c4d9a3eff7 100644 --- a/test/e2e/framework/scaletest/add-unique-labels.go +++ b/test/e2e/framework/scaletest/add-unique-labels.go @@ -29,7 +29,6 @@ func (a *AddUniqueLabelsToAllPods) Prevalidate() error { // Primary step where test logic is executed // Returning an error will cause the test to fail func (a *AddUniqueLabelsToAllPods) Run() error { - if a.NumUniqueLabelsPerPod < 1 { return nil } diff --git a/test/e2e/framework/scaletest/create-network-policies.go b/test/e2e/framework/scaletest/create-network-policies.go index c38f9597cc..ebf0f08e83 100644 --- a/test/e2e/framework/scaletest/create-network-policies.go +++ b/test/e2e/framework/scaletest/create-network-policies.go @@ -34,7 +34,6 @@ func (c *CreateNetworkPolicies) Prevalidate() error { // Primary step where test logic is executed // Returning an error will cause the test to fail func (c *CreateNetworkPolicies) Run() error { - config, err := clientcmd.BuildConfigFromFlags("", c.KubeConfigFilePath) if err != nil { return fmt.Errorf("error building kubeconfig: %w", err) diff --git a/test/e2e/framework/scaletest/delete-and-re-add-labels.go b/test/e2e/framework/scaletest/delete-and-re-add-labels.go index 5897b4d766..68a78b1cad 100644 --- a/test/e2e/framework/scaletest/delete-and-re-add-labels.go +++ b/test/e2e/framework/scaletest/delete-and-re-add-labels.go @@ -33,7 +33,6 @@ func (d *DeleteAndReAddLabels) Prevalidate() error { // Primary step where test logic is executed // Returning an error will cause the test to fail func (d *DeleteAndReAddLabels) Run() error { - if d.NumSharedLabelsPerPod <= 2 || !d.DeleteLabels { return nil } @@ -89,7 +88,6 @@ func (d *DeleteAndReAddLabels) Run() error { } func (d *DeleteAndReAddLabels) addLabels(ctx context.Context, clientset *kubernetes.Clientset, pods *corev1.PodList, patch string) error { - for _, pod := range pods.Items { _, err := clientset.CoreV1().Pods(d.Namespace).Patch(ctx, pod.Name, types.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{}) if err != nil { @@ -101,7 +99,6 @@ func (d *DeleteAndReAddLabels) addLabels(ctx context.Context, clientset *kuberne } func (d *DeleteAndReAddLabels) deleteLabels(ctx context.Context, clientset *kubernetes.Clientset, pods *corev1.PodList, patch string) error { - for _, pod := range pods.Items { _, err := clientset.CoreV1().Pods(d.Namespace).Patch(ctx, pod.Name, types.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{}) if err != nil { diff --git a/test/e2e/framework/scaletest/get-publish-metrics.go b/test/e2e/framework/scaletest/get-publish-metrics.go index 3495addf33..c576dc2959 100644 --- a/test/e2e/framework/scaletest/get-publish-metrics.go +++ b/test/e2e/framework/scaletest/get-publish-metrics.go @@ -47,7 +47,6 @@ func (g *GetAndPublishMetrics) Run() error { g.wg.Add(1) go func() { - t := time.NewTicker(5 * time.Minute) for { @@ -66,7 +65,6 @@ func (g *GetAndPublishMetrics) Run() error { } } - }() return nil @@ -92,7 +90,6 @@ func (g *GetAndPublishMetrics) Prevalidate() error { } func (g *GetAndPublishMetrics) getAndPublishMetrics() error { - config, err := clientcmd.BuildConfigFromFlags("", g.KubeConfigFilePath) if err != nil { return fmt.Errorf("error building kubeconfig: %w", err) @@ -121,14 +118,13 @@ func (g *GetAndPublishMetrics) getAndPublishMetrics() error { log.Println("Publishing metrics to AppInsights") for _, metric := range metrics { g.telemetryClient.TrackEvent("scale-test", metric) - } } // Write metrics to file if g.OutputFilePath != "" { log.Println("Writing metrics to file ", g.OutputFilePath) - file, err := os.OpenFile(g.OutputFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + file, err := os.OpenFile(g.OutputFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { return fmt.Errorf("error writing to csv file: %w", err) } @@ -151,7 +147,6 @@ func (g *GetAndPublishMetrics) getAndPublishMetrics() error { type metric map[string]string func (g *GetAndPublishMetrics) getMetrics(ctx context.Context, k8sClient *kubernetes.Clientset, metricsClient *metrics.Clientset) ([]metric, error) { - labelSelector := labels.Set(g.Labels).String() pods, err := k8sClient.CoreV1().Pods(common.KubeSystemNamespace).List(ctx, metav1.ListOptions{LabelSelector: labelSelector}) diff --git a/test/e2e/framework/scaletest/templates/networkpolicy.go b/test/e2e/framework/scaletest/templates/networkpolicy.go index 2eef3e3161..936767b3d7 100644 --- a/test/e2e/framework/scaletest/templates/networkpolicy.go +++ b/test/e2e/framework/scaletest/templates/networkpolicy.go @@ -5,23 +5,21 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -var ( - NetworkPolicy = netv1.NetworkPolicy{ - TypeMeta: metav1.TypeMeta{ - Kind: "NetworkPolicy", - APIVersion: "networking.k8s.io/v1", +var NetworkPolicy = netv1.NetworkPolicy{ + TypeMeta: metav1.TypeMeta{ + Kind: "NetworkPolicy", + APIVersion: "networking.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "template-network-policy", + }, + Spec: netv1.NetworkPolicySpec{ + PolicyTypes: []netv1.PolicyType{ + "Ingress", + "Egress", }, - ObjectMeta: metav1.ObjectMeta{ - Name: "template-network-policy", + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{}, }, - Spec: netv1.NetworkPolicySpec{ - PolicyTypes: []netv1.PolicyType{ - "Ingress", - "Egress", - }, - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{}, - }, - }, - } -) + }, +} diff --git a/test/e2e/framework/scaletest/validate-options.go b/test/e2e/framework/scaletest/validate-options.go index 0dafdd2b06..a091a6f61f 100644 --- a/test/e2e/framework/scaletest/validate-options.go +++ b/test/e2e/framework/scaletest/validate-options.go @@ -37,8 +37,7 @@ func (po *ValidateAndPrintOptions) Prevalidate() error { // Returning an error will cause the test to fail func (po *ValidateAndPrintOptions) Run() error { - - log.Printf("Starting to scale with folowing options: %+v", po.Options) + log.Printf("Starting to scale with following options: %+v", po.Options) return nil } diff --git a/test/e2e/jobs/jobs.go b/test/e2e/jobs/jobs.go index ddc58b5daf..0f1a1978b9 100644 --- a/test/e2e/jobs/jobs.go +++ b/test/e2e/jobs/jobs.go @@ -365,4 +365,3 @@ func RunPerfTest(kubeConfigFilePath string, chartPath string) *types.Job { return job } - diff --git a/test/e2e/jobs/logrunning.go b/test/e2e/jobs/logrunning.go new file mode 100644 index 0000000000..1002cb4fc6 --- /dev/null +++ b/test/e2e/jobs/logrunning.go @@ -0,0 +1,12 @@ +package retina + +import ( + "github.com/microsoft/retina/test/e2e/framework/types" + "github.com/microsoft/retina/test/e2e/scenarios/longrunning" +) + +func CreateLongRunningTest(subID, clusterName, location, kubeConfigFilePath string, createInfra bool) *types.Job { + job := types.NewJob("Run Retina over a long period of time") + job.AddScenario(longrunning.PullPProf(kubeConfigFilePath)) + return job +} diff --git a/test/e2e/jobs/scale.go b/test/e2e/jobs/scale.go index 89215785c1..1be75c8e18 100644 --- a/test/e2e/jobs/scale.go +++ b/test/e2e/jobs/scale.go @@ -66,7 +66,7 @@ func ScaleTest(opt *scaletest.Options) *types.Job { job.AddStep(&scaletest.GetAndPublishMetrics{ Labels: opt.LabelsToGetMetrics, AdditionalTelemetryProperty: opt.AdditionalTelemetryProperty, - OutputFilePath: os.Getenv("OUTPUT_FILEPATH"), + OutputFilePath: os.Getenv("OUTPUT_FILEPATH"), }, &types.StepOptions{ SkipSavingParametersToJob: true, RunInBackgroundWithID: "get-metrics", diff --git a/test/e2e/retina_longrunning_test.go b/test/e2e/retina_longrunning_test.go new file mode 100644 index 0000000000..df51c04e5a --- /dev/null +++ b/test/e2e/retina_longrunning_test.go @@ -0,0 +1,31 @@ +package retina + +import ( + "testing" + + "github.com/microsoft/retina/test/e2e/framework/helpers" + "github.com/microsoft/retina/test/e2e/framework/types" + jobs "github.com/microsoft/retina/test/e2e/jobs" + "github.com/stretchr/testify/require" +) + +// Scrape PProf over a long running datapath tests +func TestLongRunningRetina(t *testing.T) { + ctx, cancel := helpers.Context(t) + defer cancel() + + settings, err := LoadInfraSettings() + require.NoError(t, err) + + // CreateTestInfra + createTestInfra := types.NewRunner(t, jobs.CreateTestInfra(subID, resourceGroup, clusterName, location, settings.KubeConfigFilePath, settings.CreateInfra)) + createTestInfra.Run(ctx) + t.Cleanup(func() { + if settings.DeleteInfra { + _ = jobs.DeleteTestInfra(subID, resourceGroup, clusterName, location).Run() + } + }) + + longrunning := types.NewRunner(t, jobs.CreateLongRunningTest(subID, clusterName, location, settings.KubeConfigFilePath, settings.CreateInfra)) + longrunning.Run(ctx) +} diff --git a/test/e2e/scenarios/longrunning/scenario.go b/test/e2e/scenarios/longrunning/scenario.go new file mode 100644 index 0000000000..938a95649d --- /dev/null +++ b/test/e2e/scenarios/longrunning/scenario.go @@ -0,0 +1,59 @@ +package longrunning + +import ( + "strconv" + "time" + + "github.com/microsoft/retina/test/e2e/framework/kubernetes" + "github.com/microsoft/retina/test/e2e/framework/types" +) + +func PullPProf(kubeConfigFilePath string) *types.Scenario { + Name := "Pull PProf" + Steps := []*types.StepWrapper{ + { + Step: &kubernetes.CreateKapingerDeployment{ + KapingerNamespace: "default", + KapingerReplicas: "500", + KubeConfigFilePath: kubeConfigFilePath, + BurstIntervalMs: "10000", // 10 seconds + BurstVolume: "200", // 500 requests every 10 seconds + }, + }, + { + Step: &kubernetes.PortForward{ + Namespace: "kube-system", + LabelSelector: "k8s-app=retina", + LocalPort: "10093", + RemotePort: "10093", + Endpoint: "metrics", + OptionalLabelAffinity: "app=kapinger", + }, + Opts: &types.StepOptions{ + RunInBackgroundWithID: "retina-port-forward", + }, + }, + { + Step: &kubernetes.PullPProf{ + DurationSeconds: strconv.Itoa(int((8 * time.Hour).Seconds())), //nolint part of the test + ScrapeIntervalSeconds: strconv.Itoa(int((1 * time.Hour).Seconds())), //nolint part of the test + }, + }, + { + Step: &types.Stop{ + BackgroundID: "retina-port-forward", + }, + }, + { + Step: &kubernetes.DeleteKubernetesResource{ + ResourceType: kubernetes.TypeString(kubernetes.Deployment), + ResourceName: "kapinger", + ResourceNamespace: "kube-system", + }, Opts: &types.StepOptions{ + SkipSavingParametersToJob: true, + }, + }, + } + + return types.NewScenario(Name, Steps...) +} diff --git a/test/e2e/scenarios/perf/publish-perf-results.go b/test/e2e/scenarios/perf/publish-perf-results.go index 4f1dd05344..aeb760fb6b 100644 --- a/test/e2e/scenarios/perf/publish-perf-results.go +++ b/test/e2e/scenarios/perf/publish-perf-results.go @@ -28,7 +28,7 @@ func (v *PublishPerfResults) Run() error { return nil } - resultsFile, err := os.OpenFile(v.ResultsFile, os.O_RDONLY, 0644) + resultsFile, err := os.OpenFile(v.ResultsFile, os.O_RDONLY, 0o644) if err != nil { return errors.Wrap(err, "failed to open results file") } diff --git a/test/e2e/scenarios/tcp/scenario.go b/test/e2e/scenarios/tcp/scenario.go index 0afa0c5013..6a8052f5d0 100644 --- a/test/e2e/scenarios/tcp/scenario.go +++ b/test/e2e/scenarios/tcp/scenario.go @@ -23,6 +23,8 @@ func ValidateTCPMetrics(namespace string) *types.Scenario { Step: &kubernetes.CreateKapingerDeployment{ KapingerNamespace: namespace, KapingerReplicas: "1", + BurstIntervalMs: "10000", // 10 seconds + BurstVolume: "10", // 500 requests every 10 seconds }, }, { diff --git a/test/e2e/settings_test.go b/test/e2e/settings_test.go new file mode 100644 index 0000000000..bd563f913f --- /dev/null +++ b/test/e2e/settings_test.go @@ -0,0 +1,92 @@ +package retina + +import ( + "crypto/rand" + "errors" + "flag" + "fmt" + "log" + "math/big" + "os" + "os/user" + "path/filepath" + "strconv" + "time" + + "github.com/microsoft/retina/test/e2e/common" +) + +var ( + clusterName = os.Getenv("CLUSTER_NAME") + subID = os.Getenv("AZURE_SUBSCRIPTION_ID") + location = os.Getenv("AZURE_LOCATION") + resourceGroup = os.Getenv("AZURE_RESOURCE_GROUP") + + errAzureSubscriptionIDNotSet = errors.New("AZURE_SUBSCRIPTION_ID is not set") +) + +var ( + locations = []string{"eastus2", "centralus", "southcentralus", "uksouth", "centralindia", "westus2"} + createInfra = flag.Bool("create-infra", true, "create a Resource group, vNET and AKS cluster for testing") + deleteInfra = flag.Bool("delete-infra", true, "delete a Resource group, vNET and AKS cluster for testing") +) + +type TestInfraSettings struct { + CreateInfra bool + DeleteInfra bool + ChartPath string + ProfilePath string + KubeConfigFilePath string +} + +func LoadInfraSettings() (*TestInfraSettings, error) { + curuser, err := user.Current() + if err != nil { + return nil, fmt.Errorf("Failed to get current user: %w", err) + } + + flag.Parse() + + if clusterName == "" { + clusterName = curuser.Username + common.NetObsRGtag + strconv.FormatInt(time.Now().Unix(), 10) + log.Printf("CLUSTER_NAME is not set, generating a random cluster name: %s", clusterName) + } + + if subID == "" { + return nil, errAzureSubscriptionIDNotSet + } + + if location == "" { + var nBig *big.Int + nBig, err = rand.Int(rand.Reader, big.NewInt(int64(len(locations)))) + if err != nil { + return nil, fmt.Errorf("Failed to generate a secure random index: %w", err) + } + location = locations[nBig.Int64()] + } + + if resourceGroup == "" { + log.Printf("AZURE_RESOURCE_GROUP is not set, using the cluster name as the resource group name by default") + resourceGroup = clusterName + } + + cwd, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("Failed to get current working directory: %w", err) + } + + // Get to root of the repo by going up two directories + rootDir := filepath.Dir(filepath.Dir(cwd)) + + chartPath := filepath.Join(rootDir, "deploy", "legacy", "manifests", "controller", "helm", "retina") + profilePath := filepath.Join(rootDir, "test", "profiles", "advanced", "values.yaml") + kubeConfigFilePath := filepath.Join(rootDir, "test", "e2e", "test.pem") + + return &TestInfraSettings{ + CreateInfra: *createInfra, + DeleteInfra: *deleteInfra, + ChartPath: chartPath, + ProfilePath: profilePath, + KubeConfigFilePath: kubeConfigFilePath, + }, nil +} diff --git a/test/prometheus/create-cm.sh b/test/prometheus/create-cm.sh index eb97c9befe..456e671606 100755 --- a/test/prometheus/create-cm.sh +++ b/test/prometheus/create-cm.sh @@ -2,7 +2,7 @@ kubectl apply -f ./test/prometheus/service.yaml kubectl delete configmap ama-metrics-prometheus-config-node -n kube-system -#kubectl create configmap ama-metrics-prometheus-config-node --from-file=./test/prometheus/ama-metrics-node/prometheus-config -n kube-system +kubectl create configmap ama-metrics-prometheus-config-node --from-file=./test/prometheus/ama-metrics-node/prometheus-config -n kube-system kubectl delete configmap ama-metrics-prometheus-config -n kube-system # kubectl create configmap ama-metrics-prometheus-config --from-file=./test/prometheus/ama-metrics/prometheus-config -n kube-system