Change:
[x] two weeks soak start date : testgrid-link [x] two weeks soak end date : [ ] test promotion pr : kubernetes/kubernetes#? According to this APIsnoop query, there are still some remaining ProxyWithPath endpoints which are untested. with this query you can filter untested endpoints by their category and eligiblity for conformance. e.g below shows a query to find all conformance eligible untested,stable,core endpoints Create a pod with a static label using the agnhost image Confirm that the pod is in the running phase Iterate through a list of http methods and check the response from the porter app Confirm that each response code is 200 OK If a test with these calls gets merged, test coverage will go up by 4 points This test is also created with the goal of conformance promotion. /sig testing /sig architecture /area conformance Where/How does PATCH/HEAD/OPTIONS requests for the following endpoints line up with the API reference? connectCoreV1PatchNamespacedPodProxyWithPath connectCoreV1HeadNamespacedPodProxyWithPath connectCoreV1OptionsNamespacedPodProxyWithPath Pod v1 core: Proxy Operations the following endpoints are listed as valid endpoints; connectCoreV1HeadNamespacedPodProxyWithPath connectCoreV1OptionsNamespacedPodProxyWithPath These requests are getting logged as a verb. Line : api/openapi-spec Line : api/openapi-spec Looking at there doesn't look to be a mapping for the above methods. According to this APIsnoop query, there are still some remaining ProxyWithPath endpoints which are untested. with this query you can filter untested endpoints by their category and eligiblity for conformance. e.g below shows a query to find all conformance eligible untested,stable,core endpoints Create a pod with a static label using the agnhost image Confirm that the pod is in the running phase Create a service and link it to the pod Iterate through a list of http methods and check the response from the porter app Confirm that each response code is 200 OK If a test with these calls gets merged, test coverage will go up by 4 points This test is also created with the goal of conformance promotion.
This issue is currently awaiting triage. If a SIG or subproject determines this is a relevant issue, they will accept it by applying the label and provide further guidance. The label can be by org members by writing in a comment. <detailsInstructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/re-open
Reopened this issue. <detailsIn response to : /reopen Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details

Discussion:
"//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library", "//staging/src/k8s.io/client-go/tools/watch:go_default_library", <ins> "//staging/src/k8s.io/client-go/transport:go_default_library", </ins> "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", "//staging/src/k8s.io/client-go/util/retry:go_default_library", "//staging/src/k8s.io/client-go/util/workqueue:go_default_library",

package network import ( <ins> "bytes" </ins> "context" <ins> "encoding/json" </ins> "fmt" "math" "net/http"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/net" <ins> "k8s.io/apimachinery/pkg/util/wait" </ins> clientset "k8s.io/client-go/kubernetes" <ins> "k8s.io/client-go/transport" </ins> "k8s.io/kubernetes/test/e2e/framework" e2enode "k8s.io/kubernetes/test/e2e/framework/node" e2erc "k8s.io/kubernetes/test/e2e/framework/rc"

// We have seen one of these calls take just over 15 seconds, so putting this at 30. proxyHTTPCallTimeout = 30 * time.Second <ins> podRetryPeriod       = 1 * time.Second podRetryTimeout      = 1 * time.Minute </ins> ) <ins> type jsonResponse struct { Method string Body   string } </ins> var _ = SIGDescribe("Proxy", func() { version := "v1" ginkgo.Context("version "+version, func() {

framework.Failf(strings.Join(errs, "n")) } }) <ins> ginkgo.It("A set of valid responses are returned for both pod and service ProxyWithPath", func() { ns := f.Namespace.Name msg := "foo" framework.Logf("Creating pod...") _, err := f.ClientSet.CoreV1().Pods(ns).Create(context.TODO(), &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "agnhost", Labels: map[string]string{ "test": "response"}, }, Spec: v1.PodSpec{ Containers: []v1.Container{{ Image:   imageutils.GetE2EImage(imageutils.Agnhost), Name:    "agnhost", Command: []string{"/agnhost", "porter", "--json-response"}, Env: []v1.EnvVar{{ Name:  "SERVE_PORT_80", Value: msg, }}, }}, RestartPolicy: v1.RestartPolicyNever, }}, metav1.CreateOptions{}) framework.ExpectNoError(err, "failed to create pod") err = wait.PollImmediate(podRetryPeriod, podRetryTimeout, checkPodStatus(f, "test=response")) framework.ExpectNoError(err, "Pod didn't start within time out period") framework.Logf("Creating service...") _, err = f.ClientSet.CoreV1().Services(ns).Create(context.TODO(), &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name:      "test-service", Namespace: ns, Labels: map[string]string{ "test": "response", }, }, Spec: v1.ServiceSpec{ Ports: []v1.ServicePort{{ Port:       80, TargetPort: intstr.FromInt(80), Protocol:   v1.ProtocolTCP, }}, Selector: map[string]string{ "test": "response", }, }}, metav1.CreateOptions{}) framework.ExpectNoError(err, "Failed to create the service") transportCfg, err := f.ClientConfig().TransportConfig() framework.ExpectNoError(err, "Error creating transportCfg") restTransport, err := transport.New(transportCfg) framework.ExpectNoError(err, "Error creating restTransport") client := &http.Client{ CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, Transport: restTransport, } // All methods for Pod ProxyWithPath return 200 // For all methods other than HEAD the response body returns 'foo' with the received http method httpVerbs := []string{"DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"} for _, httpVerb := range httpVerbs { urlString := f.ClientConfig().Host + "/api/v1/namespaces/" + ns + "/pods/agnhost/proxy/some/path/with/" + httpVerb framework.Logf("Starting http.Client for %s", urlString) request, err := http.NewRequest(httpVerb, urlString, nil) framework.ExpectNoError(err, "processing request") resp, err := client.Do(request) framework.ExpectNoError(err, "processing response") defer resp.Body.Close() buf := new(bytes.Buffer) buf.ReadFrom(resp.Body) response := buf.String() switch httpVerb { case "HEAD": framework.Logf("http.Client request:%s | StatusCode:%d", httpVerb, resp.StatusCode) framework.ExpectEqual(resp.StatusCode, 200, "The resp.StatusCode returned: %d", resp.StatusCode) default: var jr *jsonResponse err = json.Unmarshal([]byte(response), &jr) framework.ExpectNoError(err, "Failed to process jsonResponse: %v | err: %v ", buf.String(), err) framework.Logf("http.Client request:%s | StatusCode:%d | Response: %s | Method: %s", httpVerb, resp.StatusCode, jr.Body, jr.Method) framework.ExpectEqual(resp.StatusCode, 200, "The resp.StatusCode returned: %d", resp.StatusCode) framework.ExpectEqual(msg, jr.Body, "The resp.Body returned: %v", jr.Body) framework.ExpectEqual(httpVerb, jr.Method, "The resp.Body returned: %v", jr.Body) } } // All methods for Service ProxyWithPath return 200 // For all methods other than HEAD the response body returns 'foo' with the received http method for _, httpVerb := range httpVerbs { urlString := f.ClientConfig().Host + "/api/v1/namespaces/" + ns + "/services/test-service/proxy/some/path/with/" + httpVerb framework.Logf("Starting http.Client for %s", urlString) request, err := http.NewRequest(httpVerb, urlString, nil) framework.ExpectNoError(err, "processing request") resp, err := client.Do(request) framework.ExpectNoError(err, "processing response") defer resp.Body.Close() buf := new(bytes.Buffer) buf.ReadFrom(resp.Body) response := buf.String() switch httpVerb { case "HEAD": framework.Logf("http.Client request:%s | StatusCode:%d", httpVerb, resp.StatusCode) framework.ExpectEqual(resp.StatusCode, 200, "The resp.StatusCode returned: %d", resp.StatusCode) default: var jr *jsonResponse err = json.Unmarshal([]byte(response), &jr) framework.ExpectNoError(err, "Failed to process jsonResponse: %v | err: %v ", buf.String(), err) framework.Logf("http.Client request:%s | StatusCode:%d | Response: %s | Method: %s", httpVerb, resp.StatusCode, jr.Body, jr.Method) framework.ExpectEqual(resp.StatusCode, 200, "The resp.StatusCode returned: %d", resp.StatusCode) framework.ExpectEqual(msg, jr.Body, "The resp.Body returned: %v", jr.Body) framework.ExpectEqual(httpVerb, jr.Method, "The resp.Body returned: %v", jr.Body) } } }) </ins> }) }) <ins> func checkPodStatus(f *framework.Framework, label string) func() (bool, error) { return func() (bool, error) { var err error list, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{ LabelSelector: label}) if err != nil { return false, err } if list.Items[0].Status.Phase != "Running" { framework.Logf("Pod Quantity: %d Status: %s", len(list.Items), list.Items[0].Status.Phase) return false, err } framework.Logf("Pod Status: %v", list.Items[0].Status.Phase) return true, nil } } </ins> func doProxy(f *framework.Framework, path string, i int) (body []byte, statusCode int, d time.Duration, err error) { // About all of the proxy accesses in this file: // * AbsPath is used because it preserves the trailing '/'.