get(t, "valid TLS cert again", false) } <ins> func TestConcurrentUpdateTransportConfig(t *testing.T) { n := time.Now() now := func() time.Time { return n } env := []string{""} environ := func() []string { s := make([]string, len(env)) copy(s, env) return s } c := api.ExecConfig{ Command:    "./testdata/test-plugin.sh", APIVersion: "client.authentication.k8s.io/v1alpha1", } a, err := newAuthenticator(newCache(), &c) if err != nil { t.Fatal(err) } a.environ = environ a.now = now a.stderr = ioutil.Discard stopCh := make(chan struct{}) defer close(stopCh) numConcurrent := 2 for i := 0; i < numConcurrent; i++ { go func() { for { tc := &transport.Config{} a.UpdateTransportConfig(tc) select { case <-stopCh: return default: continue } } }() } time.Sleep(2 * time.Second) } </ins> // genClientCert generates an x509 certificate for testing. Certificate and key // are returned in PEM encoding. func genClientCert(t *testing.T) ([]byte, []byte) {


"k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" <ins> "k8s.io/apimachinery/pkg/util/sets" </ins> cloudprovider "k8s.io/cloud-provider" cloudproviderapi "k8s.io/cloud-provider/api" "k8s.io/klog"


requiresUpdate := kl.reconcileCMADAnnotationWithExistingNode(node, existingNode) requiresUpdate = kl.updateDefaultLabels(node, existingNode) || requiresUpdate requiresUpdate = kl.reconcileExtendedResource(node, existingNode) || requiresUpdate <ins> requiresUpdate = kl.reconcileHugePageResource(node, existingNode) || requiresUpdate </ins> if requiresUpdate { if _, _, err := nodeutil.PatchNodeStatus(kl.kubeClient.CoreV1(), types.NodeName(kl.nodeName), originalNode, existingNode); err != nil { klog.Errorf("Unable to reconcile node %q with API server: error updating node: %v", kl.nodeName, err)


return true } <ins> // reconcileHugePageResource will update huge page capacity for each page size and remove huge page sizes no longer supported func (kl *Kubelet) reconcileHugePageResource(initialNode, existingNode *v1.Node) bool { requiresUpdate := false supportedHugePageResources := sets.String{} for resourceName := range initialNode.Status.Capacity { if !v1helper.IsHugePageResourceName(resourceName) { continue } supportedHugePageResources.Insert(string(resourceName)) initialCapacity := initialNode.Status.Capacity[resourceName] initialAllocatable := initialNode.Status.Allocatable[resourceName] capacity, resourceIsSupported := existingNode.Status.Capacity[resourceName] allocatable := existingNode.Status.Allocatable[resourceName] // Add or update capacity if it the size was previously unsupported or has changed if !resourceIsSupported || capacity.Cmp(initialCapacity) != 0 { existingNode.Status.Capacity[resourceName] = initialCapacity.DeepCopy() requiresUpdate = true } // Add or update allocatable if it the size was previously unsupported or has changed if !resourceIsSupported || allocatable.Cmp(initialAllocatable) != 0 { existingNode.Status.Allocatable[resourceName] = initialAllocatable.DeepCopy() requiresUpdate = true } } for resourceName := range existingNode.Status.Capacity { if !v1helper.IsHugePageResourceName(resourceName) { continue } // If huge page size no longer is supported, we remove it from the node if !supportedHugePageResources.Has(string(resourceName)) { delete(existingNode.Status.Capacity, resourceName) delete(existingNode.Status.Allocatable, resourceName) klog.Infof("Removing now unsupported huge page resource named: %s", resourceName) requiresUpdate = true } } return requiresUpdate } </ins> // Zeros out extended resource capacity during reconciliation. func (kl *Kubelet) reconcileExtendedResource(initialNode, node *v1.Node) bool { requiresUpdate := false


} } <ins> func TestReconcileHugePageResource(t *testing.T) { testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */) hugePageResourceName64Ki := v1.ResourceName("hugepages-64Ki") hugePageResourceName2Mi := v1.ResourceName("hugepages-2Mi") hugePageResourceName1Gi := v1.ResourceName("hugepages-1Gi") cases := []struct { name         string testKubelet  *TestKubelet initialNode  *v1.Node existingNode *v1.Node expectedNode *v1.Node needsUpdate  bool }{ { name:        "no update needed when all huge page resources are similar", testKubelet: testKubelet, needsUpdate: false, initialNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     resource.MustParse("100Mi"), hugePageResourceName64Ki:    *resource.NewQuantity(0, resource.BinarySI), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     resource.MustParse("100Mi"), hugePageResourceName64Ki:    *resource.NewQuantity(0, resource.BinarySI), }, }, }, existingNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     resource.MustParse("100Mi"), hugePageResourceName64Ki:    *resource.NewQuantity(0, resource.BinarySI), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     resource.MustParse("100Mi"), hugePageResourceName64Ki:    *resource.NewQuantity(0, resource.BinarySI), }, }, }, expectedNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     resource.MustParse("100Mi"), hugePageResourceName64Ki:    *resource.NewQuantity(0, resource.BinarySI), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     resource.MustParse("100Mi"), hugePageResourceName64Ki:    *resource.NewQuantity(0, resource.BinarySI), }, }, }, }, { name:        "update needed when new huge page resources is supported", testKubelet: testKubelet, needsUpdate: true, initialNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     *resource.NewQuantity(0, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     *resource.NewQuantity(0, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, }, }, existingNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     resource.MustParse("100Mi"), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     resource.MustParse("100Mi"), }, }, }, expectedNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     *resource.NewQuantity(0, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     *resource.NewQuantity(0, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, }, }, }, { name:        "update needed when huge page resource quantity has changed", testKubelet: testKubelet, needsUpdate: true, initialNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("4Gi"), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("4Gi"), }, }, }, existingNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, }, }, expectedNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("4Gi"), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("4Gi"), }, }, }, }, { name:        "update needed when a huge page resources is no longer supported", testKubelet: testKubelet, needsUpdate: true, initialNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, }, }, existingNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     *resource.NewQuantity(0, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName2Mi:     *resource.NewQuantity(0, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, }, }, expectedNode: &v1.Node{ Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, Allocatable: v1.ResourceList{ v1.ResourceCPU:              *resource.NewMilliQuantity(2000, resource.DecimalSI), v1.ResourceMemory:           *resource.NewQuantity(10e9, resource.BinarySI), v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI), hugePageResourceName1Gi:     resource.MustParse("2Gi"), }, }, }, }, } for _, tc := range cases { t.Run(tc.name, func(T *testing.T) { defer testKubelet.Cleanup() kubelet := testKubelet.kubelet needsUpdate := kubelet.reconcileHugePageResource(tc.initialNode, tc.existingNode) assert.Equal(t, tc.needsUpdate, needsUpdate, tc.name) assert.Equal(t, tc.expectedNode, tc.existingNode, tc.name) }) } } </ins> func TestReconcileExtendedResource(t *testing.T) { testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */) testKubelet.kubelet.kubeClient = nil // ensure only the heartbeat client is used


v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" <ins> "k8s.io/apimachinery/pkg/types" </ins> "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/kubernetes/pkg/kubelet/cm" "k8s.io/kubernetes/test/e2e/framework"


err := e2epod.WaitForPodSuccessInNamespace(f.ClientSet, verifyPod.Name, f.Namespace.Name) framework.ExpectNoError(err) }) <ins> ginkgo.It("should add resources for new huge page sizes on kubelet restart", func() { ginkgo.By("Stopping kubelet") startKubelet := stopKubelet() ginkgo.By(`Patching away support for hugepage resource "hugepages-2Mi"`) patch := []byte(`[{"op": "remove", "path": "/status/capacity/hugepages-2Mi"}, {"op": "remove", "path": "/status/allocatable/hugepages-2Mi"}]`) result := f.ClientSet.CoreV1().RESTClient().Patch(types.JSONPatchType).Resource("nodes").Name(framework.TestContext.NodeName).SubResource("status").Body(patch).Do(context.TODO()) framework.ExpectNoError(result.Error(), "while patching") ginkgo.By("Starting kubelet again") startKubelet() ginkgo.By("verifying that the hugepages-2Mi resource is present") gomega.Eventually(func() bool { node, err := f.ClientSet.CoreV1().Nodes().Get(context.TODO(), framework.TestContext.NodeName, metav1.GetOptions{}) framework.ExpectNoError(err, "while getting node status") _, isPresent := node.Status.Capacity["hugepages-2Mi"] return isPresent }, 30*time.Second, framework.Poll).Should(gomega.Equal(true)) }) </ins> } // Serial because the test updates kubelet configuration. var _ = SIGDescribe("HugePages [Serial] [Feature:HugePages][NodeFeature:HugePages]", func() { f := framework.NewDefaultFramework("hugepages-test") <ins> ginkgo.It("should remove resources for huge page sizes no longer supported", func() { ginkgo.By("mimicking support for 9Mi of 3Mi huge page memory by patching the node status") patch := []byte(`[{"op": "add", "path": "/status/capacity/hugepages-3Mi", "value": "9Mi"}, {"op": "add", "path": "/status/allocatable/hugepages-3Mi", "value": "9Mi"}]`) result := f.ClientSet.CoreV1().RESTClient().Patch(types.JSONPatchType).Resource("nodes").Name(framework.TestContext.NodeName).SubResource("status").Body(patch).Do(context.TODO()) framework.ExpectNoError(result.Error(), "while patching") node, err := f.ClientSet.CoreV1().Nodes().Get(context.TODO(), framework.TestContext.NodeName, metav1.GetOptions{}) framework.ExpectNoError(err, "while getting node status") ginkgo.By("Verifying that the node now supports huge pages with size 3Mi") value, ok := node.Status.Capacity["hugepages-3Mi"] framework.ExpectEqual(ok, true, "capacity should contain resouce hugepages-3Mi") framework.ExpectEqual(value.String(), "9Mi", "huge pages with size 3Mi should be supported") ginkgo.By("restarting the node and verifying that huge pages with size 3Mi are not supported") restartKubelet() ginkgo.By("verifying that the hugepages-3Mi resource no longer is present") gomega.Eventually(func() bool { node, err = f.ClientSet.CoreV1().Nodes().Get(context.TODO(), framework.TestContext.NodeName, metav1.GetOptions{}) framework.ExpectNoError(err, "while getting node status") _, isPresent := node.Status.Capacity["hugepages-3Mi"] return isPresent }, 30*time.Second, framework.Poll).Should(gomega.Equal(false)) }) </ins> ginkgo.Context("With config updated with hugepages feature enabled", func() { ginkgo.BeforeEach(func() { ginkgo.By("verifying hugepages are supported")


} // TODO: Find a uniform way to deal with systemctl/initctl/service operations. #34494 <del> func restartKubelet() { </del> <ins> func findRunningKubletServiceName() string { </ins> stdout, err := exec.Command("sudo", "systemctl", "list-units", "kubelet*", "--state=running").CombinedOutput() framework.ExpectNoError(err) regex := regexp.MustCompile("(kubelet-w+)") matches := regex.FindStringSubmatch(string(stdout)) <del> framework.ExpectNotEqual(len(matches), 0) kube := matches[0] framework.Logf("Get running kubelet with systemctl: %v, %v", string(stdout), kube) stdout, err = exec.Command("sudo", "systemctl", "restart", kube).CombinedOutput() </del> <ins> framework.ExpectNotEqual(len(matches), 0, "Found more than one kubelet service running: %q", stdout) kubeletServiceName := matches[0] framework.Logf("Get running kubelet with systemctl: %v, %v", string(stdout), kubeletServiceName) return kubeletServiceName } func restartKubelet() { kubeletServiceName := findRunningKubletServiceName() stdout, err := exec.Command("sudo", "systemctl", "restart", kubeletServiceName).CombinedOutput() </ins> framework.ExpectNoError(err, "Failed to restart kubelet with systemctl: %v, %v", err, stdout) } <ins> // stopKubelet will kill the running kubelet, and returns a func that will restart the process again func stopKubelet() func() { kubeletServiceName := findRunningKubletServiceName() stdout, err := exec.Command("sudo", "systemctl", "kill", kubeletServiceName).CombinedOutput() framework.ExpectNoError(err, "Failed to stop kubelet with systemctl: %v, %v", err, stdout) return func() { stdout, err := exec.Command("sudo", "systemctl", "start", kubeletServiceName).CombinedOutput() framework.ExpectNoError(err, "Failed to restart kubelet with systemctl: %v, %v", err, stdout) } } </ins> func toCgroupFsName(cgroupName cm.CgroupName) string { if framework.TestContext.KubeletConfig.CgroupDriver == "systemd" { return cgroupName.ToSystemd()


"//:all-srcs", ], outs = ["stable-metrics-list.yaml"], <del> cmd = "./$(locations :instrumentation) $(locations //:all-srcs) > $@", </del> <ins> cmd = "for loc in $(locations //:all-srcs); do echo $$loc; done | ./$(locations :instrumentation) - > $@", </ins> message = "Listing all stable metrics.", tools = [":instrumentation"], )


package main import ( <ins> "bufio" </ins> "flag" "fmt" "go/ast"


func main() { flag.Parse() if len(flag.Args()) < 1 { <del> fmt.Fprintf(os.Stderr, "USAGE: %s <DIR or FILE> [...]n", os.Args[0]) </del> <ins> fmt.Fprintf(os.Stderr, "USAGE: %s <DIR or FILE or '-'> [...]n", os.Args[0]) </ins> os.Exit(64) } stableMetrics := []metric{} errors := []error{} <ins> addStdin := false </ins> for _, arg := range flag.Args() { <ins> if arg == "-" { addStdin = true continue } </ins> ms, es := searchPathForStableMetrics(arg) stableMetrics = append(stableMetrics, ms...) errors = append(errors, es...) } <ins> if addStdin { scanner := bufio.NewScanner(os.Stdin) scanner.Split(bufio.ScanLines) for scanner.Scan() { arg := scanner.Text() ms, es := searchPathForStableMetrics(arg) stableMetrics = append(stableMetrics, ms...) errors = append(errors, es...) } } </ins> for _, err := range errors { fmt.Fprintf(os.Stderr, "%sn", err) }


Creates a replication controller to manage the created container(s). ``` <del> kubectl run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] </del> <ins> kubectl run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...] </ins> ``` ### Examples


* [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager <del> ###### Auto generated by spf13/cobra on 6-Nov-2015 </del> <ins> ###### Auto generated by spf13/cobra on 10-Nov-2015 </ins> <!-- BEGIN MUNGE: GENERATED_ANALYTICS --> [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_run.md?pixel)]()


func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command { cmd := &cobra.Command{ <del> Use: "run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json]", </del> <ins> Use: "run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...]", </ins> // run-container is deprecated Aliases: []string{"run-container"}, Short:   "Run a particular image on the cluster.", Long:    run_long, Example: run_example, Run: func(cmd *cobra.Command, args []string) { <del> err := Run(f, cmdIn, cmdOut, cmdErr, cmd, args) </del> <ins> argsLenAtDash := cmd.ArgsLenAtDash() err := Run(f, cmdIn, cmdOut, cmdErr, cmd, args, argsLenAtDash) </ins> cmdutil.CheckErr(err) }, }


cmd.Flags().String("service-overrides", "", "An inline JSON override for the generated service object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.  Only used if --expose is true.") } <del> func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string) error { </del> <ins> func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string, argsLenAtDash int) error { </ins> if len(os.Args) > 1 && os.Args[1] == "run-container" { printDeprecationWarning("run", "run-container") } <del> if len(args) == 0 { </del> <ins> // Let kubectl run follow rules for `--`, see #13004 issue if len(args) == 0 || argsLenAtDash == 0 { </ins> return cmdutil.UsageError(cmd, "NAME is required for run") }


"fmt" "io/ioutil" "net/http" <ins> "os" </ins> "reflect" "testing"


} } <ins> func TestRunArgsFollowDashRules(t *testing.T) { _, _, rc := testData() tests := []struct { args          []string argsLenAtDash int expectError   bool name          string }{ { args:          []string{}, argsLenAtDash: -1, expectError:   true, name:          "empty", }, { args:          []string{"foo"}, argsLenAtDash: -1, expectError:   false, name:          "no cmd", }, { args:          []string{"foo", "sleep"}, argsLenAtDash: -1, expectError:   false, name:          "cmd no dash", }, { args:          []string{"foo", "sleep"}, argsLenAtDash: 1, expectError:   false, name:          "cmd has dash", }, { args:          []string{"foo", "sleep"}, argsLenAtDash: 0, expectError:   true, name:          "no name", }, } for _, test := range tests { f, tf, codec := NewAPIFactory() tf.Client = &fake.RESTClient{ Codec: codec, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return &http.Response{StatusCode: 201, Body: objBody(codec, &rc.Items[0])}, nil }), } tf.Namespace = "test" tf.ClientConfig = &client.Config{} cmd := NewCmdRun(f, os.Stdin, os.Stdout, os.Stderr) cmd.Flags().Set("image", "nginx") err := Run(f, os.Stdin, os.Stdout, os.Stderr, cmd, test.args, test.argsLenAtDash) if test.expectError && err == nil { t.Errorf("unexpected non-error (%s)", test.name) } if !test.expectError && err != nil { t.Errorf("unexpected error: %v (%s)", err, test.name) } } } </ins> func TestGenerateService(t *testing.T) { tests := []struct {


} e2elog.Logf("Got an error creating template %d: %v", i, err) } <del> ginkgo.Fail("Unable to create template %d, exiting", i) </del> <ins> e2elog.Fail("Unable to create template %d, exiting", i) </ins> }) })


} e2elog.Logf("Got an error creating template %d: %v", i, err) } <del> ginkgo.Fail("Unable to create template %d, exiting", i) </del> <ins> e2elog.Fail("Unable to create template %d, exiting", i) </ins> }) pagedTable := &metav1beta1.Table{}


srcs = ["testfiles.go"], importpath = "k8s.io/kubernetes/test/e2e/framework/testfiles", visibility = ["//visibility:public"], <del> deps = ["//vendor/github.com/onsi/ginkgo:go_default_library"], </del> <ins> deps = ["//test/e2e/framework/log:go_default_library"], </ins> ) filegroup(


"sort" "strings" <del> "github.com/onsi/ginkgo" </del> <ins> e2elog "k8s.io/kubernetes/test/e2e/framework/log" </ins> ) var filesources []FileSource


func ReadOrDie(filePath string) []byte { data, err := Read(filePath) if err != nil { <del> ginkgo.Fail(err.Error(), 1) </del> <ins> e2elog.Fail(err.Error(), 1) </ins> } return data }


for _, filesource := range filesources { data, err := filesource.ReadTestFile(filePath) if err != nil { <del> ginkgo.Fail(fmt.Sprintf("fatal error looking for test file %s: %s", filePath, err), 1) </del> <ins> e2elog.Fail(fmt.Sprintf("fatal error looking for test file %s: %s", filePath, err), 1) </ins> } if data != nil { return true


}) ginkgo.AfterEach(func() { <ins> defer func() { if expectedNodeCondition == v1.NodeDiskPressure && framework.TestContext.PrepullImages { // The disk eviction test may cause the prepulled images to be evicted, // prepull those images again to ensure this test not affect following tests. PrePullAllImages() } }() </ins> ginkgo.By("deleting pods") for _, spec := range testSpecs { ginkgo.By(fmt.Sprintf("deleting pod: %s", spec.pod.Name)) f.PodClient().DeleteSync(spec.pod.Name, &metav1.DeleteOptions{}, 10*time.Minute) } reduceAllocatableMemoryUsage() <del> if expectedNodeCondition == v1.NodeDiskPressure && framework.TestContext.PrepullImages { // The disk eviction test may cause the prepulled images to be evicted, // prepull those images again to ensure this test not affect following tests. PrePullAllImages() } </del> ginkgo.By("making sure we can start a new pod after the test") podName := "test-admit-pod" f.PodClient().CreateSync(&v1.Pod{


}, time.Minute*8, time.Second*4).ShouldNot(gomega.HaveOccurred()) }) ginkgo.AfterEach(func() { <ins> defer func() { if framework.TestContext.PrepullImages { // The test may cause the prepulled images to be evicted, // prepull those images again to ensure this test not affect following tests. PrePullAllImages() } }() </ins> ginkgo.By("delete the static pod") err := deleteStaticPod(podPath, staticPodName, ns) gomega.Expect(err).ShouldNot(gomega.HaveOccurred())


gomega.Eventually(func() error { return checkMirrorPodDisappear(f.ClientSet, mirrorPodName, ns) }, time.Minute, time.Second*2).Should(gomega.BeNil()) }) }) })


return nil, false, nil } if ctx.ComponentConfig.CSRSigningController.ClusterSigningCertFile == "" || ctx.ComponentConfig.CSRSigningController.ClusterSigningKeyFile == "" { <ins> klog.V(2).Info("skipping CSR signer controller because no csr cert/key was specified") </ins> return nil, false, nil }


// setting up the signing controller. This isn't // actually a problem since the signer is not a // required controller. <ins> klog.V(2).Info("skipping CSR signer controller because no csr cert/key was specified and the default files are missing") </ins> return nil, false, nil default: // Note that '!filesExist && !usesDefaults' is obviously


recognizers: recognizers(), } return certificates.NewCertificateController( <ins> "csrapproving", </ins> client, csrInformer, approver.handle,


) type CertificateController struct { <ins> // name is an identifier for this particular controller instance. name string </ins> kubeClient clientset.Interface csrLister  certificateslisters.CertificateSigningRequestLister


} func NewCertificateController( <ins> name string, </ins> kubeClient clientset.Interface, csrInformer certificatesinformers.CertificateSigningRequestInformer, handler func(*certificates.CertificateSigningRequest) error,


eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")}) cc := &CertificateController{ <ins> name:       name, </ins> kubeClient: kubeClient, queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewMaxOfRateLimiter( workqueue.NewItemExponentialFailureRateLimiter(200*time.Millisecond, 1000*time.Second),


defer utilruntime.HandleCrash() defer cc.queue.ShutDown() <del> klog.Infof("Starting certificate controller") defer klog.Infof("Shutting down certificate controller") </del> <ins> klog.Infof("Starting certificate controller %q", cc.name) defer klog.Infof("Shutting down certificate controller %q", cc.name) </ins> <del> if !cache.WaitForNamedCacheSync("certificate", stopCh, cc.csrsSynced) { </del> <ins> if !cache.WaitForNamedCacheSync(fmt.Sprintf("certificate-%s", cc.name), stopCh, cc.csrsSynced) { </ins> return }


} controller := NewCertificateController( <ins> "test", </ins> client, informerFactory.Certificates().V1beta1().CertificateSigningRequests(), handler,


return nil, err } return certificates.NewCertificateController( <ins> "csrsigning", </ins> client, csrInformer, signer.handle,


) const ( <del> // MaxUint defines the max unsigned int value. MaxUint = ^uint(0) // MaxInt defines the max signed int value. MaxInt = int(MaxUint >> 1) </del> // MaxTotalPriority defines the max total priority value. MaxTotalPriority = int64(math.MaxInt64) // MaxPriority defines the max priority value. MaxPriority = 10 // MaxWeight defines the max weight value. <del> MaxWeight = int64(math.MaxInt64 / MaxPriority) </del> <ins> MaxWeight = MaxTotalPriority / MaxPriority </ins> // DefaultPercentageOfNodesToScore defines the percentage of nodes of all nodes // that once found feasible, the scheduler stops looking for more nodes. DefaultPercentageOfNodesToScore = 50


package factory import ( <del> "math" </del> "testing" "github.com/stretchr/testify/assert"


expected    bool }{ { <del> description: "one of the weights is MaxInt64", configs:     []priorities.PriorityConfig{{Weight: math.MaxInt64}, {Weight: 5}}, </del> <ins> description: "one of the weights is MaxTotalPriority(MaxInt64)", configs:     []priorities.PriorityConfig{{Weight: api.MaxTotalPriority}, {Weight: 5}}, </ins> expected:    true, }, { description: "after multiplication with MaxPriority the weight is larger than MaxWeight", <del> configs:     []priorities.PriorityConfig{{Weight: math.MaxInt64/api.MaxPriority + api.MaxPriority}, {Weight: 5}}, </del> <ins> configs:     []priorities.PriorityConfig{{Weight: api.MaxWeight + api.MaxPriority}, {Weight: 5}}, </ins> expected:    true, }, {


flags.StringVar(&TestContext.KubernetesAnywherePath, "kubernetes-anywhere-path", "/workspace/k8s.io/kubernetes-anywhere", "Which directory kubernetes-anywhere is installed to.") flags.BoolVar(&TestContext.ListImages, "list-images", false, "If true, will show list of images used for runnning tests.") <ins> flags.StringVar(&TestContext.KubectlPath, "kubectl-path", "kubectl", "The kubectl binary to use. For development, you might use 'cluster/kubectl.sh' here.") </ins> } // RegisterClusterFlags registers flags specific to the cluster e2e test suite.


flags.StringVar(&TestContext.RepoRoot, "repo-root", "../../", "Root directory of kubernetes repository, for finding test files.") flags.StringVar(&TestContext.Provider, "provider", "", "The name of the Kubernetes provider (gce, gke, local, skeleton (the fallback if not set), etc.)") flags.StringVar(&TestContext.Tooling, "tooling", "", "The tooling in use (kops, gke, etc.)") <del> flags.StringVar(&TestContext.KubectlPath, "kubectl-path", "kubectl", "The kubectl binary to use. For development, you might use 'cluster/kubectl.sh' here.") </del> flags.StringVar(&TestContext.OutputDir, "e2e-output-dir", "/tmp", "Output directory for interesting/useful test data, like performance data, benchmarks, and other metrics.") flags.StringVar(&TestContext.Prefix, "prefix", "e2e", "A prefix to be added to cloud resources created during testing.") flags.StringVar(&TestContext.MasterOSDistro, "master-os-distro", "debian", "The OS distribution of cluster master (debian, ubuntu, gci, coreos, or custom).")


import ( "errors" "fmt" <ins> "io/ioutil" </ins> "os" "path/filepath" "strings"


// attachFileDevice takes a path to a regular file and makes it available as an // attached block device. func attachFileDevice(path string, exec utilexec.Interface) (string, error) { <del> blockDevicePath, err := getLoopDevice(path, exec) </del> <ins> blockDevicePath, err := getLoopDevice(path) </ins> if err != nil && err.Error() != ErrDeviceNotFound { return "", err }


} // Returns the full path to the loop device associated with the given path. <del> func getLoopDevice(path string, exec utilexec.Interface) (string, error) { </del> <ins> func getLoopDevice(path string) (string, error) { </ins> _, err := os.Stat(path) if os.IsNotExist(err) { return "", errors.New(ErrNotAvailable)


return "", fmt.Errorf("not attachable: %v", err) } <del> args := []string{"-j", path} out, err := exec.Command(losetupPath, args...).CombinedOutput() if err != nil { klog.V(2).Infof("Failed device discover command for path %s: %v", path, err) return "", err } return parseLosetupOutputForDevice(out) </del> <ins> return getLoopDeviceFromSysfs(path) </ins> } func makeLoopDevice(path string, exec utilexec.Interface) (string, error) { <del> args := []string{"-f", "-P", "--show", path} </del> <ins> args := []string{"-f", "-P", path} </ins> out, err := exec.Command(losetupPath, args...).CombinedOutput() if err != nil { <del> klog.V(2).Infof("Failed device create command for path %s: %v", path, err) </del> <ins> klog.V(2).Infof("Failed device create command for path %s: %v %s", path, err, out) </ins> return "", err } <del> return parseLosetupOutputForDevice(out) </del> <ins> return getLoopDeviceFromSysfs(path) </ins> } func removeLoopDevice(device string, exec utilexec.Interface) error {


return strings.HasPrefix(device, "/dev/loop") } <del> func parseLosetupOutputForDevice(output []byte) (string, error) { if len(output) == 0 { </del> <ins> // getLoopDeviceFromSysfs finds the backing file for a loop // device from sysfs via "/sys/block/loop*/loop/backing_file". func getLoopDeviceFromSysfs(path string) (string, error) { // If the file is a symlink. realPath, err := filepath.EvalSymlinks(path) if err != nil { </ins> return "", errors.New(ErrDeviceNotFound) } <del> // losetup returns device in the format: // /dev/loop1: [0073]:148662 (/var/lib/storageos/volumes/308f14af-cf0a-08ff-c9c3-b48104318e05) device := strings.TrimSpace(strings.SplitN(string(output), ":", 2)[0]) if len(device) == 0 { </del> <ins> devices, err := filepath.Glob("/sys/block/loop*") if err != nil { </ins> return "", errors.New(ErrDeviceNotFound) } <del> return device, nil </del> <ins> for _, device := range devices { backingFile := fmt.Sprintf("%s/loop/backing_file", device) // The contents of this file is the absolute path of "path". data, err := ioutil.ReadFile(backingFile) if err != nil { continue } // Return the first match. backingFilePath := strings.TrimSpace(string(data)) if backingFilePath == path || backingFilePath == realPath { return fmt.Sprintf("/dev/%s", filepath.Base(device)), nil } } return "", errors.New(ErrDeviceNotFound) </ins> }


package volumepathhandler import ( <del> "bufio" </del> "errors" "fmt" <ins> "io/ioutil" </ins> "os" "os/exec" "path/filepath"


return "", fmt.Errorf("not attachable: %v", err) } <del> args := []string{"-j", path} cmd := exec.Command(losetupPath, args...) out, err := cmd.CombinedOutput() if err != nil { klog.V(2).Infof("Failed device discover command for path %s: %v %s", path, err, out) return "", fmt.Errorf("losetup -j %s failed: %v", path, err) } return parseLosetupOutputForDevice(out, path) </del> <ins> return getLoopDeviceFromSysfs(path) </ins> } func makeLoopDevice(path string) (string, error) { <del> args := []string{"-f", "--show", path} </del> <ins> args := []string{"-f", path} </ins> cmd := exec.Command(losetupPath, args...) out, err := cmd.CombinedOutput() if err != nil { <del> klog.V(2).Infof("Failed device create command for path: %s %v %s ", path, err, out) return "", fmt.Errorf("losetup -f --show %s failed: %v", path, err) </del> <ins> klog.V(2).Infof("Failed device create command for path: %s %v %s", path, err, out) return "", fmt.Errorf("losetup %s failed: %v", strings.Join(args, " "), err) </ins> } <del> // losetup -f --show {path} returns device in the format: // /dev/loop1 if len(out) == 0 { return "", errors.New(ErrDeviceNotFound) } return strings.TrimSpace(string(out)), nil </del> <ins> return getLoopDeviceFromSysfs(path) </ins> } // removeLoopDevice removes specified loopback device


return nil } <del> func parseLosetupOutputForDevice(output []byte, path string) (string, error) { if len(output) == 0 { return "", errors.New(ErrDeviceNotFound) } </del> <ins> // getLoopDeviceFromSysfs finds the backing file for a loop // device from sysfs via "/sys/block/loop*/loop/backing_file". func getLoopDeviceFromSysfs(path string) (string, error) { // If the file is a symlink. </ins> realPath, err := filepath.EvalSymlinks(path) if err != nil { return "", fmt.Errorf("failed to evaluate path %s: %s", path, err) } <del> // losetup -j {path} returns device in the format: // /dev/loop1: [0073]:148662 ({path}) // /dev/loop2: [0073]:148662 (/dev/sdX) // // losetup -j shows all the loop device for the same device that has the same // major/minor number, by resolving symlink and matching major/minor number. // Therefore, there will be other path than {path} in output, as shown in above output. s := string(output) // Find the line that exact matches to the path, or "({path})" var matched string scanner := bufio.NewScanner(strings.NewReader(s)) for scanner.Scan() { // losetup output has symlinks expanded if strings.HasSuffix(scanner.Text(), "("+realPath+")") { matched = scanner.Text() break </del> <ins> devices, err := filepath.Glob("/sys/block/loop*") if err != nil { return "", fmt.Errorf("failed to list loop devices in sysfs: %s", err) } for _, device := range devices { backingFile := fmt.Sprintf("%s/loop/backing_file", device) // The contents of this file is the absolute path of "path". data, err := ioutil.ReadFile(backingFile) if err != nil { continue </ins> } <del> // Just in case losetup changes, check for the original path too if strings.HasSuffix(scanner.Text(), "("+path+")") { matched = scanner.Text() break </del> <ins> // Return the first match. backingFilePath := strings.TrimSpace(string(data)) if backingFilePath == path || backingFilePath == realPath { return fmt.Sprintf("/dev/%s", filepath.Base(device)), nil </ins> } } <del> if len(matched) == 0 { return "", errors.New(ErrDeviceNotFound) } s = matched // Get device name, or the 0th field of the output separated with ":". // We don't need 1st field or later to be splitted, so passing 2 to SplitN. device := strings.TrimSpace(strings.SplitN(s, ":", 2)[0]) if len(device) == 0 { return "", errors.New(ErrDeviceNotFound) } return device, nil </del> <ins> return "", errors.New(ErrDeviceNotFound) </ins> } // FindGlobalMapPathUUIDFromPod finds {pod uuid} bind mount under globalMapPath


import ( "context" <del> "k8s.io/api/core/v1" </del> <ins> v1 "k8s.io/api/core/v1" </ins> clientset "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/test/e2e/framework" e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"


ginkgo.Describe("NFSv4", func() { ginkgo.It("should be mountable for NFSv4", func() { config, _, serverIP := volume.NewNFSServer(c, namespace.Name, []string{}) <del> defer volume.TestCleanup(f, config) </del> <ins> defer volume.TestServerCleanup(f, config) </ins> tests := []volume.Test{ {


ginkgo.Describe("NFSv3", func() { ginkgo.It("should be mountable for NFSv3", func() { config, _, serverIP := volume.NewNFSServer(c, namespace.Name, []string{}) <del> defer volume.TestCleanup(f, config) </del> <ins> defer volume.TestServerCleanup(f, config) </ins> tests := []volume.Test{ {


config, _, _ := volume.NewGlusterfsServer(c, namespace.Name) name := config.Prefix + "-server" defer func() { <del> volume.TestCleanup(f, config) </del> <ins> volume.TestServerCleanup(f, config) </ins> err := c.CoreV1().Endpoints(namespace.Name).Delete(context.TODO(), name, nil) framework.ExpectNoError(err, "defer: Gluster delete endpoints failed") }()


return pod } <del> // TestCleanup cleans both server and client pods. func TestCleanup(f *framework.Framework, config TestConfig) { </del> <ins> // TestServerCleanup cleans server pod. func TestServerCleanup(f *framework.Framework, config TestConfig) { </ins> ginkgo.By(fmt.Sprint("cleaning the environment after ", config.Prefix)) defer ginkgo.GinkgoRecover() <del> cs := f.ClientSet err := e2epod.DeletePodWithWaitByName(cs, config.Prefix+"-client", config.Namespace) gomega.Expect(err).To(gomega.BeNil(), "Failed to delete pod %v in namespace %v", config.Prefix+"-client", config.Namespace) if config.ServerImage != "" { err := e2epod.DeletePodWithWaitByName(cs, config.Prefix+"-server", config.Namespace) gomega.Expect(err).To(gomega.BeNil(), "Failed to delete pod %v in namespace %v", config.Prefix+"-server", config.Namespace) </del> <ins> if config.ServerImage == "" { return </ins> } <ins> err := e2epod.DeletePodWithWaitByName(f.ClientSet, config.Prefix+"-server", config.Namespace) gomega.Expect(err).To(gomega.BeNil(), "Failed to delete pod %v in namespace %v", config.Prefix+"-server", config.Namespace) </ins> } func runVolumeTesterPod(client clientset.Interface, config TestConfig, podSuffix string, privileged bool, fsGroup *int64, tests []Test) (*v1.Pod, error) {


clientPod, err := runVolumeTesterPod(f.ClientSet, config, "client", false, fsGroup, tests) if err != nil { framework.Failf("Failed to create client pod: %v", err) } <ins> defer func() { e2epod.DeletePodOrFail(f.ClientSet, clientPod.Namespace, clientPod.Name) e2epod.WaitForPodToDisappear(f.ClientSet, clientPod.Namespace, clientPod.Name, labels.Everything(), framework.Poll, framework.PodDeleteTimeout) }() </ins> framework.ExpectNoError(e2epod.WaitForPodRunningInNamespace(f.ClientSet, clientPod)) testVolumeContent(f, clientPod, fsGroup, fsType, tests) }


}, } volume.TestVolumeClient(f, config, nil, "" /* fsType */, tests) <del> volume.TestCleanup(f, config) </del> } // installFlex installs the driver found at filePath on the node, and restarts


init() defer func() { <del> volume.TestCleanup(f, convertTestConfig(l.config)) </del> <ins> volume.TestServerCleanup(f, convertTestConfig(l.config)) </ins> cleanup() }()


import ( "context" "github.com/onsi/ginkgo" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"


Namespace: namespace.Name, Prefix:    "configmap", } <del> defer volume.TestCleanup(f, config) </del> configMap := &v1.ConfigMap{ TypeMeta: metav1.TypeMeta{ Kind:       "ConfigMap",


imagePullTest(image, false, v1.PodPending, true, false) }) <del> ginkgo.It("should not be able to pull non-existing image from gcr.io [NodeConformance]", func() { image := imageutils.GetE2EImage(imageutils.Invalid) imagePullTest(image, false, v1.PodPending, true, false) }) ginkgo.It("should be able to pull image from gcr.io [NodeConformance]", func() { image := imageutils.GetE2EImage(imageutils.DebianBase) isWindows := false if framework.NodeOSDistroIs("windows") { image = imageutils.GetE2EImage(imageutils.WindowsNanoServer) isWindows = true } imagePullTest(image, false, v1.PodRunning, false, isWindows) }) ginkgo.It("should be able to pull image from docker hub [NodeConformance]", func() { image := imageutils.GetE2EImage(imageutils.Alpine) isWindows := false if framework.NodeOSDistroIs("windows") { // TODO(claudiub): Switch to nanoserver image manifest list. image = "e2eteam/busybox:1.29" isWindows = true } imagePullTest(image, false, v1.PodRunning, false, isWindows) </del> <ins> ginkgo.It("should be able to pull image [NodeConformance]", func() { // NOTE(claudiub): The agnhost image is supposed to work on both Linux and Windows. image := imageutils.GetE2EImage(imageutils.Agnhost) imagePullTest(image, false, v1.PodRunning, false, false) </ins> }) ginkgo.It("should not be able to pull from private registry without secret [NodeConformance]", func() {


const ( // Agnhost image Agnhost = iota <del> // Alpine image Alpine </del> // APIServer image APIServer // AppArmorLoader image


CudaVectorAdd2 // Dnsutils image Dnsutils <del> // DebianBase image DebianBase </del> // EchoServer image EchoServer // Etcd image


Httpd // HttpdNew image HttpdNew <del> // Invalid image Invalid </del> // InvalidRegistryImage image InvalidRegistryImage // IpcUtils image


VolumeGlusterServer // VolumeRBDServer image VolumeRBDServer <del> // WindowsNanoServer image WindowsNanoServer </del> ) func initImageConfigs() map[int]Config { configs := map[int]Config{} configs[Agnhost] = Config{e2eRegistry, "agnhost", "2.6"} <del> configs[Alpine] = Config{dockerLibraryRegistry, "alpine", "3.7"} </del> configs[AuthenticatedAlpine] = Config{gcAuthenticatedRegistry, "alpine", "3.7"} configs[AuthenticatedWindowsNanoServer] = Config{gcAuthenticatedRegistry, "windows-nanoserver", "v1"} configs[APIServer] = Config{e2eRegistry, "sample-apiserver", "1.10"}


configs[CudaVectorAdd] = Config{e2eRegistry, "cuda-vector-add", "1.0"} configs[CudaVectorAdd2] = Config{e2eRegistry, "cuda-vector-add", "2.0"} configs[Dnsutils] = Config{e2eRegistry, "dnsutils", "1.1"} <del> configs[DebianBase] = Config{googleContainerRegistry, "debian-base", "0.4.1"} </del> configs[EchoServer] = Config{e2eRegistry, "echoserver", "2.2"} configs[Etcd] = Config{gcRegistry, "etcd", "3.3.15"} configs[GBFrontend] = Config{sampleRegistry, "gb-frontend", "v6"} configs[GlusterDynamicProvisioner] = Config{dockerGluster, "glusterdynamic-provisioner", "v1.0"} configs[Httpd] = Config{dockerLibraryRegistry, "httpd", "2.4.38-alpine"} configs[HttpdNew] = Config{dockerLibraryRegistry, "httpd", "2.4.39-alpine"} <del> configs[Invalid] = Config{gcRegistry, "invalid-image", "invalid-tag"} </del> configs[InvalidRegistryImage] = Config{invalidRegistry, "alpine", "3.1"} configs[IpcUtils] = Config{e2eRegistry, "ipc-utils", "1.0"} configs[JessieDnsutils] = Config{e2eRegistry, "jessie-dnsutils", "1.0"}


configs[VolumeISCSIServer] = Config{e2eRegistry, "volume/iscsi", "2.0"} configs[VolumeGlusterServer] = Config{e2eRegistry, "volume/gluster", "1.0"} configs[VolumeRBDServer] = Config{e2eRegistry, "volume/rbd", "1.0.1"} <del> configs[WindowsNanoServer] = Config{e2eRegistry, "windows-nanoserver", "v1"} </del> return configs }


if priorityConfigs[i].Function != nil { wg.Add(1) go func(index int) { <del> defer wg.Done() </del> <ins> metrics.SchedulerGoroutines.WithLabelValues("prioritizing_legacy").Inc() defer func() { metrics.SchedulerGoroutines.WithLabelValues("prioritizing_legacy").Dec() wg.Done() }() </ins> var err error results[index], err = priorityConfigs[index].Function(pod, nodeNameToInfo, nodes) if err != nil {


} wg.Add(1) go func(index int) { <del> defer wg.Done() </del> <ins> metrics.SchedulerGoroutines.WithLabelValues("prioritizing_mapreduce").Inc() defer func() { metrics.SchedulerGoroutines.WithLabelValues("prioritizing_mapreduce").Dec() wg.Done() }() </ins> if err := priorityConfigs[index].Reduce(pod, meta, nodeNameToInfo, results[index]); err != nil { appendError(err) }


} wg.Add(1) go func(extIndex int) { <del> defer wg.Done() </del> <ins> metrics.SchedulerGoroutines.WithLabelValues("prioritizing_extender").Inc() defer func() { metrics.SchedulerGoroutines.WithLabelValues("prioritizing_extender").Dec() wg.Done() }() </ins> prioritizedList, weight, err := extenders[extIndex].Prioritize(pod, nodes) if err != nil { // Prioritization errors from extender can be ignored, let k8s/other extenders determine the priorities


Help:           "Total preemption attempts in the cluster till now", StabilityLevel: metrics.ALPHA, }) pendingPods = metrics.NewGaugeVec( &metrics.GaugeOpts{ Subsystem:      SchedulerSubsystem,


Help:           "Number of pending pods, by the queue type. 'active' means number of pods in activeQ; 'backoff' means number of pods in backoffQ; 'unschedulable' means number of pods in unschedulableQ.", StabilityLevel: metrics.ALPHA, }, []string{"queue"}) <ins> SchedulerGoroutines = metrics.NewGaugeVec( &metrics.GaugeOpts{ Subsystem:      SchedulerSubsystem, Name:           "scheduler_goroutines", Help:           "Number of running goroutines split by the work they do such as binding.", StabilityLevel: metrics.ALPHA, }, []string{"work"}) </ins> PodSchedulingDuration = metrics.NewHistogram( &metrics.HistogramOpts{


PodSchedulingAttempts, FrameworkExtensionPointDuration, SchedulerQueueIncomingPods, <ins> SchedulerGoroutines, </ins> } )


} // bind the pod to its host asynchronously (we can do this b/c of the assumption step above). go func() { <ins> metrics.SchedulerGoroutines.WithLabelValues("binding").Inc() defer metrics.SchedulerGoroutines.WithLabelValues("binding").Dec() </ins> // Bind volumes first before Pod if !allBound { err := sched.bindVolumes(assumedPod)


} } <ins> func (e *eventBroadcasterImpl) Shutdown() { e.Broadcaster.Shutdown() } </ins> // refreshExistingEventSeries refresh events TTL func (e *eventBroadcasterImpl) refreshExistingEventSeries() { // TODO: Investigate whether lock contention won't be a problem


// NOTE: events received on your eventHandler should be copied before being used. // TODO: figure out if this can be removed. StartEventWatcher(eventHandler func(event runtime.Object)) func() <ins> // Shutdown shuts down the broadcaster Shutdown() </ins> } // EventSink knows how to store events (client-go implements it.)


// NewRecorder returns an EventRecorder that can be used to send events to this EventBroadcaster // with the event source set to the given event source. NewRecorder(scheme *runtime.Scheme, source v1.EventSource) EventRecorder <ins> // Shutdown shuts down the broadcaster Shutdown() </ins> } // Creates a new event broadcaster.


}) } <ins> func (e *eventBroadcasterImpl) Shutdown() { e.Broadcaster.Shutdown() } </ins> func recordToSink(sink EventSink, event *v1.Event, eventCorrelator *EventCorrelator, sleepDuration time.Duration) { // Make a copy before modification, because there could be multiple listeners. // Events are safe to copy like this.


cs := context.clientSet podLabel := map[string]string{"service": "securityscan"} <del> // podLabel2 := map[string]string{"security": "S1"} </del> <ins> podLabel2 := map[string]string{"security": "S1"} </ins> tests := []struct { pod       *v1.Pod


errorType string test      string }{ <del> /*{ </del> <ins> { </ins> pod: &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:   "fakename",


{ Key:      "security", Operator: metav1.LabelSelectorOpDoesNotExist, <del> Values:   []string{"securityscan"}, </del> }, }, },


node: nodes[0], fits: false, test: "satisfies the PodAffinity but doesn't satisfies the PodAntiAffinity with the existing pod", <del> },*/ </del> <ins> }, </ins> { pod: &v1.Pod{ ObjectMeta: metav1.ObjectMeta{


} // sanityCheckService performs sanity checks on the given service; in particular, ensuring <del> // that creating/updating a service allocates IPs, ports, etc, as needed. </del> <ins> // that creating/updating a service allocates IPs, ports, etc, as needed. It does not // check for ingress assignment as that happens asynchronously after the Service is created. </ins> func (j *TestJig) sanityCheckService(svc *v1.Service, svcType v1.ServiceType) (*v1.Service, error) { if svcType == "" { svcType = v1.ServiceTypeClusterIP


} } } <del> expectIngress := false if svcType == v1.ServiceTypeLoadBalancer { expectIngress = true } hasIngress := len(svc.Status.LoadBalancer.Ingress) != 0 if hasIngress != expectIngress { return nil, fmt.Errorf("unexpected number of Status.LoadBalancer.Ingress (%d) for service", len(svc.Status.LoadBalancer.Ingress)) } if hasIngress { for i, ing := range svc.Status.LoadBalancer.Ingress { if ing.IP == "" && ing.Hostname == "" { return nil, fmt.Errorf("unexpected Status.LoadBalancer.Ingress[%d] for service: %#v", i, ing) } </del> <ins> if svcType != v1.ServiceTypeLoadBalancer { if len(svc.Status.LoadBalancer.Ingress) != 0 { return nil, fmt.Errorf("unexpected Status.LoadBalancer.Ingress on non-LoadBalancer service") </ins> } }


if err != nil { return nil, err } <ins> for i, ing := range service.Status.LoadBalancer.Ingress { if ing.IP == "" && ing.Hostname == "" { return nil, fmt.Errorf("unexpected Status.LoadBalancer.Ingress[%d] for service: %#v", i, ing) } } </ins> return j.sanityCheckService(service, v1.ServiceTypeLoadBalancer) }


flags.DurationVar(&nodeKiller.SimulatedDowntime, "node-killer-simulated-downtime", 10*time.Minute, "A delay between node death and recreation") } <del> // RegisterNodeFlags registers flags specific to the node e2e test suite. func RegisterNodeFlags(flags *flag.FlagSet) { // Mark the test as node e2e when node flags are api.Registry. TestContext.NodeE2E = true flags.StringVar(&TestContext.NodeName, "node-name", "", "Name of the node to run tests on.") // TODO(random-liu): Move kubelet start logic out of the test. // TODO(random-liu): Move log fetch logic out of the test. // There are different ways to start kubelet (systemd, initd, docker, manually started etc.) // and manage logs (journald, upstart etc.). // For different situation we need to mount different things into the container, run different commands. // It is hard and unnecessary to deal with the complexity inside the test suite. flags.BoolVar(&TestContext.NodeConformance, "conformance", false, "If true, the test suite will not start kubelet, and fetch system log (kernel, docker, kubelet log etc.) to the report directory.") flags.BoolVar(&TestContext.PrepullImages, "prepull-images", true, "If true, prepull images so image pull failures do not cause test failures.") flags.StringVar(&TestContext.ImageDescription, "image-description", "", "The description of the image which the test will be running on.") flags.StringVar(&TestContext.SystemSpecName, "system-spec-name", "", "The name of the system spec (e.g., gke) that's used in the node e2e test. The system specs are in test/e2e_node/system/specs/. This is used by the test framework to determine which tests to run for validating the system requirements.") flags.Var(cliflag.NewMapStringString(&TestContext.ExtraEnvs), "extra-envs", "The extra environment variables needed for node e2e tests. Format: a list of key=value pairs, e.g., env1=val1,env2=val2") } </del> func createKubeConfig(clientCfg *restclient.Config) *clientcmdapi.Config { clusterNick := "cluster" userNick := "user"


"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library", <ins> "//staging/src/k8s.io/component-base/cli/flag:go_default_library", </ins> "//test/e2e/framework/config:go_default_library", "//test/e2e/framework/kubelet:go_default_library", "//test/e2e/framework/perf:go_default_library",


metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilyaml "k8s.io/apimachinery/pkg/util/yaml" clientset "k8s.io/client-go/kubernetes" <ins> cliflag "k8s.io/component-base/cli/flag" </ins> commontest "k8s.io/kubernetes/test/e2e/common" "k8s.io/kubernetes/test/e2e/framework" e2econfig "k8s.io/kubernetes/test/e2e/framework/config"


var systemValidateMode = flag.Bool("system-validate-mode", false, "If true, only run system validation in current process, and not run test.") var systemSpecFile = flag.String("system-spec-file", "", "The name of the system spec file that will be used for node conformance test. If it's unspecified or empty, the default system spec (system.DefaultSysSpec) will be used.") <ins> // registerNodeFlags registers flags specific to the node e2e test suite. func registerNodeFlags(flags *flag.FlagSet) { // Mark the test as node e2e when node flags are api.Registry. framework.TestContext.NodeE2E = true flags.StringVar(&framework.TestContext.NodeName, "node-name", "", "Name of the node to run tests on.") // TODO(random-liu): Move kubelet start logic out of the test. // TODO(random-liu): Move log fetch logic out of the test. // There are different ways to start kubelet (systemd, initd, docker, manually started etc.) // and manage logs (journald, upstart etc.). // For different situation we need to mount different things into the container, run different commands. // It is hard and unnecessary to deal with the complexity inside the test suite. flags.BoolVar(&framework.TestContext.NodeConformance, "conformance", false, "If true, the test suite will not start kubelet, and fetch system log (kernel, docker, kubelet log etc.) to the report directory.") flags.BoolVar(&framework.TestContext.PrepullImages, "prepull-images", true, "If true, prepull images so image pull failures do not cause test failures.") flags.StringVar(&framework.TestContext.ImageDescription, "image-description", "", "The description of the image which the test will be running on.") flags.StringVar(&framework.TestContext.SystemSpecName, "system-spec-name", "", "The name of the system spec (e.g., gke) that's used in the node e2e test. The system specs are in test/e2e_node/system/specs/. This is used by the test framework to determine which tests to run for validating the system requirements.") flags.Var(cliflag.NewMapStringString(&framework.TestContext.ExtraEnvs), "extra-envs", "The extra environment variables needed for node e2e tests. Format: a list of key=value pairs, e.g., env1=val1,env2=val2") } </ins> func init() { // Enable bindata file lookup as fallback. testfiles.AddFileSource(testfiles.BindataFileSource{


// Copy go flags in TestMain, to ensure go test flags are registered (no longer available in init() as of go1.13) e2econfig.CopyFlags(e2econfig.Flags, flag.CommandLine) framework.RegisterCommonFlags(flag.CommandLine) <del> framework.RegisterNodeFlags(flag.CommandLine) </del> <ins> registerNodeFlags(flag.CommandLine) </ins> pflag.CommandLine.AddGoFlagSet(flag.CommandLine) // Mark the run-services-mode flag as hidden to prevent user from using it. pflag.CommandLine.MarkHidden("run-services-mode")


deps = [ "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", <ins> "//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library", </ins> "//staging/src/k8s.io/csi-translation-lib/plugins:go_default_library", ], )


github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= <ins> github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= </ins> github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=


} pv := &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ <del> // A.K.A InnerVolumeSpecName required to match for Unmount Name: volume.Name, </del> <ins> // Must be unique per disk as it is used as the unique part of the // staging path Name: fmt.Sprintf("%s-%s", AWSEBSDriverName, ebsSource.VolumeID), </ins> }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{


azureSource := volume.AzureDisk pv := &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ <del> // A.K.A InnerVolumeSpecName required to match for Unmount Name: volume.Name, </del> <ins> // Must be unique per disk as it is used as the unique part of the // staging path Name: fmt.Sprintf("%s-%s", AzureDiskDriverName, azureSource.DiskName), </ins> }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{


pv := &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ <del> // A.K.A InnerVolumeSpecName required to match for Unmount Name: volume.Name, </del> <ins> // Must be unique per disk as it is used as the unique part of the // staging path Name: fmt.Sprintf("%s-%s", AzureFileDriverName, azureSource.ShareName), </ins> }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{


return &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ <del> // A.K.A InnerVolumeSpecName required to match for Unmount Name: volume.Name, </del> <ins> // Must be unique per disk as it is used as the unique part of the // staging path Name: fmt.Sprintf("%s-%s", GCEPDDriverName, pdSource.PDName), </ins> }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{


cinderSource := volume.Cinder pv := &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ <del> // A.K.A InnerVolumeSpecName required to match for Unmount Name: volume.Name, </del> <ins> // Must be unique per disk as it is used as the unique part of the // staging path Name: fmt.Sprintf("%s-%s", CinderDriverName, cinderSource.VolumeID), </ins> }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{


package csitranslation import ( <ins> "fmt" </ins> "reflect" "testing" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" <ins> "k8s.io/apimachinery/pkg/util/uuid" </ins> "k8s.io/csi-translation-lib/plugins" )


} } <ins> func TestTranslateInTreeInlineVolumeToCSINameUniqueness(t *testing.T) { for driverName := range inTreePlugins { t.Run(driverName, func(t *testing.T) { ctl := New() vs1, err := generateUniqueVolumeSource(driverName) if err != nil { t.Fatalf("Couldn't generate random source: %v", err) } pv1, err := ctl.TranslateInTreeInlineVolumeToCSI(&v1.Volume{ VolumeSource: vs1, }) if err != nil { t.Fatalf("Error when translating to CSI: %v", err) } vs2, err := generateUniqueVolumeSource(driverName) if err != nil { t.Fatalf("Couldn't generate random source: %v", err) } pv2, err := ctl.TranslateInTreeInlineVolumeToCSI(&v1.Volume{ VolumeSource: vs2, }) if err != nil { t.Fatalf("Error when translating to CSI: %v", err) } if pv1 == nil || pv2 == nil { t.Fatalf("Did not expect either pv1: %v or pv2: %v to be nil", pv1, pv2) } if pv1.Name == pv2.Name { t.Errorf("PV name %s not sufficiently unique for different volumes", pv1.Name) } }) } } func generateUniqueVolumeSource(driverName string) (v1.VolumeSource, error) { switch driverName { case plugins.GCEPDDriverName: return v1.VolumeSource{ GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ PDName: string(uuid.NewUUID()), }, }, nil case plugins.AWSEBSDriverName: return v1.VolumeSource{ AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{ VolumeID: string(uuid.NewUUID()), }, }, nil case plugins.CinderDriverName: return v1.VolumeSource{ Cinder: &v1.CinderVolumeSource{ VolumeID: string(uuid.NewUUID()), }, }, nil case plugins.AzureDiskDriverName: return v1.VolumeSource{ AzureDisk: &v1.AzureDiskVolumeSource{ DiskName:    string(uuid.NewUUID()), DataDiskURI: string(uuid.NewUUID()), }, }, nil case plugins.AzureFileDriverName: return v1.VolumeSource{ AzureFile: &v1.AzureFileVolumeSource{ SecretName: string(uuid.NewUUID()), ShareName:  string(uuid.NewUUID()), }, }, nil default: return v1.VolumeSource{}, fmt.Errorf("couldn't find logic for driver: %v", driverName) } } </ins> func TestPluginNameMappings(t *testing.T) { testCases := []struct { name             string


return sgList, setupSg, nil } <ins> // sortELBSecurityGroupList returns a list of sorted securityGroupIDs based on the original order // from buildELBSecurityGroupList. The logic is: //  * securityGroups specified by ServiceAnnotationLoadBalancerSecurityGroups appears first in order //  * securityGroups specified by ServiceAnnotationLoadBalancerExtraSecurityGroups appears last in order func (c *Cloud) sortELBSecurityGroupList(securityGroupIDs []string, annotations map[string]string) { annotatedSGList := getSGListFromAnnotation(annotations[ServiceAnnotationLoadBalancerSecurityGroups]) annotatedExtraSGList := getSGListFromAnnotation(annotations[ServiceAnnotationLoadBalancerExtraSecurityGroups]) annotatedSGIndex := make(map[string]int, len(annotatedSGList)) annotatedExtraSGIndex := make(map[string]int, len(annotatedExtraSGList)) for i, sgID := range annotatedSGList { annotatedSGIndex[sgID] = i } for i, sgID := range annotatedExtraSGList { annotatedExtraSGIndex[sgID] = i } sgOrderMapping := make(map[string]int, len(securityGroupIDs)) for _, sgID := range securityGroupIDs { if i, ok := annotatedSGIndex[sgID]; ok { sgOrderMapping[sgID] = i } else if j, ok := annotatedExtraSGIndex[sgID]; ok { sgOrderMapping[sgID] = len(annotatedSGIndex) + 1 + j } else { sgOrderMapping[sgID] = len(annotatedSGIndex) } } sort.Slice(securityGroupIDs, func(i, j int) bool { return sgOrderMapping[securityGroupIDs[i]] < sgOrderMapping[securityGroupIDs[j]] }) } </ins> // buildListener creates a new listener from the given port, adding an SSL certificate // if indicated by the appropriate annotations. func buildListener(port v1.ServicePort, annotations map[string]string, sslPorts *portSets) (*elb.Listener, error) {


} } <del> err = c.updateInstanceSecurityGroupsForLoadBalancer(loadBalancer, instances) </del> <ins> err = c.updateInstanceSecurityGroupsForLoadBalancer(loadBalancer, instances, annotations) </ins> if err != nil { klog.Warningf("Error opening ingress rules for the load balancer to the instances: %q", err) return nil, err


// Open security group ingress rules on the instances so that the load balancer can talk to them // Will also remove any security groups ingress rules for the load balancer that are _not_ needed for allInstances <del> func (c *Cloud) updateInstanceSecurityGroupsForLoadBalancer(lb *elb.LoadBalancerDescription, instances map[InstanceID]*ec2.Instance) error { </del> <ins> func (c *Cloud) updateInstanceSecurityGroupsForLoadBalancer(lb *elb.LoadBalancerDescription, instances map[InstanceID]*ec2.Instance, annotations map[string]string) error { </ins> if c.cfg.Global.DisableSecurityGroupIngress { return nil } // Determine the load balancer security group id <del> loadBalancerSecurityGroupID := "" for _, securityGroup := range lb.SecurityGroups { if aws.StringValue(securityGroup) == "" { continue } if loadBalancerSecurityGroupID != "" { // We create LBs with one SG klog.Warningf("Multiple security groups for load balancer: %q", aws.StringValue(lb.LoadBalancerName)) } loadBalancerSecurityGroupID = *securityGroup } if loadBalancerSecurityGroupID == "" { </del> <ins> lbSecurityGroupIDs := aws.StringValueSlice(lb.SecurityGroups) if len(lbSecurityGroupIDs) == 0 { </ins> return fmt.Errorf("could not determine security group for load balancer: %s", aws.StringValue(lb.LoadBalancerName)) } <ins> c.sortELBSecurityGroupList(lbSecurityGroupIDs, annotations) loadBalancerSecurityGroupID := lbSecurityGroupIDs[0] </ins> // Get the actual list of groups that allow ingress from the load-balancer var actualGroups []*ec2.SecurityGroup


{ // De-authorize the load balancer security group from the instances security group <del> err = c.updateInstanceSecurityGroupsForLoadBalancer(lb, nil) </del> <ins> err = c.updateInstanceSecurityGroupsForLoadBalancer(lb, nil, service.Annotations) </ins> if err != nil { klog.Errorf("Error deregistering load balancer from instance security groups: %q", err) return err


return nil } <del> err = c.updateInstanceSecurityGroupsForLoadBalancer(lb, instances) </del> <ins> err = c.updateInstanceSecurityGroupsForLoadBalancer(lb, instances, service.Annotations) </ins> if err != nil { return err }


assert.Equal(t, testCase.region, result) } } <ins> func TestCloud_sortELBSecurityGroupList(t *testing.T) { type args struct { securityGroupIDs []string annotations      map[string]string } tests := []struct { name                 string args                 args wantSecurityGroupIDs []string }{ { name: "with no annotation", args: args{ securityGroupIDs: []string{"sg-1"}, annotations:      map[string]string{}, }, wantSecurityGroupIDs: []string{"sg-1"}, }, { name: "with service.beta.kubernetes.io/aws-load-balancer-security-groups", args: args{ securityGroupIDs: []string{"sg-2", "sg-1", "sg-3"}, annotations: map[string]string{ "service.beta.kubernetes.io/aws-load-balancer-security-groups": "sg-3,sg-2,sg-1", }, }, wantSecurityGroupIDs: []string{"sg-3", "sg-2", "sg-1"}, }, { name: "with service.beta.kubernetes.io/aws-load-balancer-extra-security-groups", args: args{ securityGroupIDs: []string{"sg-2", "sg-1", "sg-3", "sg-4"}, annotations: map[string]string{ "service.beta.kubernetes.io/aws-load-balancer-extra-security-groups": "sg-3,sg-2,sg-1", }, }, wantSecurityGroupIDs: []string{"sg-4", "sg-3", "sg-2", "sg-1"}, }, { name: "with both annotation", args: args{ securityGroupIDs: []string{"sg-2", "sg-1", "sg-3", "sg-4", "sg-5", "sg-6"}, annotations: map[string]string{ "service.beta.kubernetes.io/aws-load-balancer-security-groups":       "sg-3,sg-2,sg-1", "service.beta.kubernetes.io/aws-load-balancer-extra-security-groups": "sg-6,sg-5", }, }, wantSecurityGroupIDs: []string{"sg-3", "sg-2", "sg-1", "sg-4", "sg-6", "sg-5"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Cloud{} c.sortELBSecurityGroupList(tt.args.securityGroupIDs, tt.args.annotations) assert.Equal(t, tt.wantSecurityGroupIDs, tt.args.securityGroupIDs) }) } } </ins>


return } if shouldHide(&version, selfVersion) { <del> klog.Warningf("This metric(%s) has been deprecated for more than one release, hiding.", d.fqName) </del> <ins> // TODO(RainbowMango): Remove this log temporarily. https://github.com/kubernetes/kubernetes/issues/85369 // klog.Warningf("This metric(%s) has been deprecated for more than one release, hiding.", d.fqName) </ins> d.isHidden = true } })


return } if shouldHide(&version, selfVersion) { <del> klog.Warningf("This metric has been deprecated for more than one release, hiding.") </del> <ins> // TODO(RainbowMango): Remove this log temporarily. https://github.com/kubernetes/kubernetes/issues/85369 // klog.Warningf("This metric has been deprecated for more than one release, hiding.") </ins> r.isHidden = true } })


// TODO: remove the check, because we support no-op updates now. if graceful || pendingFinalizers || shouldUpdateFinalizers { err, ignoreNotFound, deleteImmediately, out, lastExisting = e.updateForGracefulDeletionAndFinalizers(ctx, name, key, options, preconditions, deleteValidation, obj) <ins> // Update the preconditions.ResourceVersion if set since we updated the object. if err == nil && deleteImmediately && preconditions.ResourceVersion != nil { accessor, err = meta.Accessor(out) if err != nil { return out, false, kubeerr.NewInternalError(err) } resourceVersion := accessor.GetResourceVersion() preconditions.ResourceVersion = &resourceVersion } </ins> } // !deleteImmediately covers all cases where err != nil. We keep both to be future-proof.


} } <ins> func TestStoreGracefulDeleteWithResourceVersion(t *testing.T) { podA := &example.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec:       example.PodSpec{NodeName: "machine"}, } testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") destroyFunc, registry := NewTestGenericStoreRegistry(t) defer destroyFunc() defaultDeleteStrategy := testRESTStrategy{scheme, names.SimpleNameGenerator, true, false, true} registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy} // test failure condition _, _, err := registry.Delete(testContext, podA.Name, rest.ValidateAllObjectFunc, nil) if !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } // create pod _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Errorf("Unexpected error: %v", err) } // try to get a item which should be deleted obj, err := registry.Get(testContext, podA.Name, &metav1.GetOptions{}) if errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } accessor, err := meta.Accessor(obj) if err != nil { t.Errorf("Unexpected error: %v", err) } resourceVersion := accessor.GetResourceVersion() options := metav1.NewDeleteOptions(0) options.Preconditions = &metav1.Preconditions{ResourceVersion: &resourceVersion} // delete object _, wasDeleted, err := registry.Delete(testContext, podA.Name, rest.ValidateAllObjectFunc, options) if err != nil { t.Errorf("Unexpected error: %v", err) } if !wasDeleted { t.Errorf("unexpected, pod %s should have been deleted immediately", podA.Name) } // try to get a item which should be deleted _, err = registry.Get(testContext, podA.Name, &metav1.GetOptions{}) if !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } } </ins> // TestGracefulStoreCanDeleteIfExistingGracePeriodZero tests recovery from // race condition where the graceful delete is unable to complete // in prior operation, but the pod remains with deletion timestamp


if err != nil { return nil, fmt.Errorf("failed to get region from zones: %v", err) } <del> volID = fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, region, pv.Spec.GCEPersistentDisk.PDName) </del> <ins> volID = fmt.Sprintf(volIDRegionalFmt, UnspecifiedValue, region, pv.Spec.GCEPersistentDisk.PDName) </ins> } else { // Unspecified volID = fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, UnspecifiedValue, pv.Spec.GCEPersistentDisk.PDName)


v1 "k8s.io/api/core/v1" storage "k8s.io/api/storage/v1" <ins> metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" </ins> ) func NewStorageClass(params map[string]string, allowedTopologies []v1.TopologySelectorTerm) *storage.StorageClass {


t.Errorf("got am %v, expected access mode of ReadOnlyMany", ams[0]) } } <ins> func TestTranslateInTreePVToCSIVolIDFmt(t *testing.T) { g := NewGCEPersistentDiskCSITranslator() pdName := "pd-name" tests := []struct { desc               string topologyLabelKey   string topologyLabelValue string wantVolId          string }{ { desc:               "beta topology key zonal", topologyLabelKey:   v1.LabelFailureDomainBetaZone, topologyLabelValue: "us-east1-a", wantVolId:          "projects/UNSPECIFIED/zones/us-east1-a/disks/pd-name", }, { desc:               "v1 topology key zonal", topologyLabelKey:   v1.LabelTopologyZone, topologyLabelValue: "us-east1-a", wantVolId:          "projects/UNSPECIFIED/zones/us-east1-a/disks/pd-name", }, { desc:               "beta topology key regional", topologyLabelKey:   v1.LabelFailureDomainBetaZone, topologyLabelValue: "us-central1-a__us-central1-c", wantVolId:          "projects/UNSPECIFIED/regions/us-central1/disks/pd-name", }, { desc:               "v1 topology key regional", topologyLabelKey:   v1.LabelTopologyZone, topologyLabelValue: "us-central1-a__us-central1-c", wantVolId:          "projects/UNSPECIFIED/regions/us-central1/disks/pd-name", }, } for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { translatedPV, err := g.TranslateInTreePVToCSI(&v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{tc.topologyLabelKey: tc.topologyLabelValue}, }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{ GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ PDName: pdName, }, }, }, }) if err != nil { t.Errorf("got error translating in-tree PV to CSI: %v", err) } if got := translatedPV.Spec.PersistentVolumeSource.CSI.VolumeHandle; got != tc.wantVolId { t.Errorf("got translated volume handle: %q, want %q", got, tc.wantVolId) } }) } } </ins>


"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/rest:go_default_library", <ins> "//staging/src/k8s.io/component-base/metrics/legacyregistry:go_default_library", </ins> "//test/integration/util:go_default_library", <ins> "//vendor/github.com/prometheus/client_model/go:go_default_library", "//vendor/k8s.io/klog:go_default_library", </ins> ], )


configFile = "config/performance-config.yaml" ) <ins> var ( defaultMetrics = []string{ "scheduler_scheduling_algorithm_predicate_evaluation_seconds", "scheduler_scheduling_algorithm_priority_evaluation_seconds", "scheduler_binding_duration_seconds", "scheduler_e2e_scheduling_duration_seconds", } ) </ins> // testCase configures a test case to run the scheduler performance test. Users should be able to // provide this via a YAML file. //


} func BenchmarkPerfScheduling(b *testing.B) { <ins> dataItems := DataItems{Version: "v1"} </ins> tests := getSimpleTestCases(configFile) for _, test := range tests {


for feature, flag := range test.FeatureGates { defer featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, feature, flag)() } <del> perfScheduling(test, b) </del> <ins> dataItems.DataItems = append(dataItems.DataItems, perfScheduling(test, b)...) </ins> }) } <ins> if err := dataItems2JSONFile(dataItems, b.Name()); err != nil { klog.Fatalf("%v: unable to write measured data: %v", b.Name(), err) } </ins> } <del> func perfScheduling(test testCase, b *testing.B) { </del> <ins> func perfScheduling(test testCase, b *testing.B) []DataItem { </ins> var nodeStrategy testutils.PrepareNodeStrategy = &testutils.TrivialNodePrepareStrategy{} if test.Nodes.NodeAllocatableStrategy != nil { nodeStrategy = test.Nodes.NodeAllocatableStrategy


// start benchmark b.ResetTimer() <ins> // Start measuring throughput stopCh := make(chan struct{}) throughputCollector := newThroughputCollector(podInformer) go throughputCollector.run(stopCh) // Scheduling the main workload </ins> config = testutils.NewTestPodCreatorConfig() config.AddStrategy(testNamespace, test.PodsToSchedule.Num, testPodStrategy) podCreator = testutils.NewTestPodCreator(clientset, config) podCreator.CreatePods() <-completedCh <ins> close(stopCh) </ins> // Note: without this line we're taking the overhead of defer() into account. b.StopTimer() <ins> setNameLabel := func(dataItem *DataItem) DataItem { if dataItem.Labels == nil { dataItem.Labels = map[string]string{} } dataItem.Labels["Name"] = b.Name() return *dataItem } dataItems := []DataItem{ setNameLabel(throughputCollector.collect()), } for _, metric := range defaultMetrics { dataItem := newPrometheusCollector(metric).collect() if dataItem == nil { continue } dataItems = append(dataItems, setNameLabel(dataItem)) } return dataItems </ins> } func getPodStrategy(pc podCase) testutils.TestPodCreateStrategy {


package benchmark import ( <ins> "encoding/json" "flag" "fmt" "io/ioutil" "math" "path" "sort" "time" dto "github.com/prometheus/client_model/go" </ins> v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" coreinformers "k8s.io/client-go/informers/core/v1" clientset "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" <ins> "k8s.io/component-base/metrics/legacyregistry" "k8s.io/klog" </ins> "k8s.io/kubernetes/test/integration/util" ) <ins> const ( dateFormat                = "2006-01-02T15:04:05Z" throughputSampleFrequency = time.Second ) var dataItemsDir = flag.String("data-items-dir", "", "destination directory for storing generated data items for perf dashboard") </ins> // mustSetupScheduler starts the following components: // - k8s api server (a.k.a. master) // - scheduler


} return scheduled, nil } <ins> // DataItem is the data point. type DataItem struct { // Data is a map from bucket to real data point (e.g. "Perc90" -> 23.5). Notice // that all data items with the same label combination should have the same buckets. Data map[string]float64 `json:"data"` // Unit is the data unit. Notice that all data items with the same label combination // should have the same unit. Unit string `json:"unit"` // Labels is the labels of the data item. Labels map[string]string `json:"labels,omitempty"` } // DataItems is the data point set. It is the struct that perf dashboard expects. type DataItems struct { Version   string     `json:"version"` DataItems []DataItem `json:"dataItems"` } func dataItems2JSONFile(dataItems DataItems, namePrefix string) error { b, err := json.Marshal(dataItems) if err != nil { return err } destFile := fmt.Sprintf("%v_%v.json", namePrefix, time.Now().Format(dateFormat)) if *dataItemsDir != "" { destFile = path.Join(*dataItemsDir, destFile) } return ioutil.WriteFile(destFile, b, 0644) } // prometheusCollector collects metrics from legacyregistry.DefaultGatherer.Gather() endpoint. // Currently only Histrogram metrics are supported. type prometheusCollector struct { metric string cache  *dto.MetricFamily } func newPrometheusCollector(metric string) *prometheusCollector { return &prometheusCollector{ metric: metric, } } func (pc *prometheusCollector) collect() *DataItem { var metricFamily *dto.MetricFamily m, err := legacyregistry.DefaultGatherer.Gather() if err != nil { klog.Error(err) return nil } for _, mFamily := range m { if mFamily.Name != nil && *mFamily.Name == pc.metric { metricFamily = mFamily break } } if metricFamily == nil { klog.Infof("Metric %q not found", pc.metric) return nil } if metricFamily.GetMetric() == nil { klog.Infof("Metric %q is empty", pc.metric) return nil } if len(metricFamily.GetMetric()) == 0 { klog.Infof("Metric %q is empty", pc.metric) return nil } // Histograms are stored under the first index (based on observation). // Given there's only one histogram registered per each metric name, accessaing // the first index is sufficient. dataItem := pc.promHist2Summary(metricFamily.GetMetric()[0].GetHistogram()) if dataItem.Data == nil { return nil } // clear the metrics so that next test always starts with empty prometheus // metrics (since the metrics are shared among all tests run inside the same binary) clearPromHistogram(metricFamily.GetMetric()[0].GetHistogram()) return dataItem } // Bucket of a histogram type bucket struct { upperBound float64 count      float64 } func bucketQuantile(q float64, buckets []bucket) float64 { if q < 0 { return math.Inf(-1) } if q > 1 { return math.Inf(+1) } if len(buckets) < 2 { return math.NaN() } rank := q * buckets[len(buckets)-1].count b := sort.Search(len(buckets)-1, func(i int) bool { return buckets[i].count >= rank }) if b == 0 { return buckets[0].upperBound * (rank / buckets[0].count) } // linear approximation of b-th bucket brank := rank - buckets[b-1].count bSize := buckets[b].upperBound - buckets[b-1].upperBound bCount := buckets[b].count - buckets[b-1].count return buckets[b-1].upperBound + bSize*(brank/bCount) } func (pc *prometheusCollector) promHist2Summary(hist *dto.Histogram) *DataItem { buckets := []bucket{} if hist.SampleCount == nil || *hist.SampleCount == 0 { return &DataItem{} } if hist.SampleSum == nil || *hist.SampleSum == 0 { return &DataItem{} } for _, bckt := range hist.Bucket { if bckt == nil { return &DataItem{} } if bckt.UpperBound == nil || *bckt.UpperBound < 0 { return &DataItem{} } buckets = append(buckets, bucket{ count:      float64(*bckt.CumulativeCount), upperBound: *bckt.UpperBound, }) } // bucketQuantile expects the upper bound of the last bucket to be +inf buckets[len(buckets)-1].upperBound = math.Inf(+1) q50 := bucketQuantile(0.50, buckets) q90 := bucketQuantile(0.90, buckets) q99 := bucketQuantile(0.95, buckets) msFactor := float64(time.Second) / float64(time.Millisecond) return &DataItem{ Labels: map[string]string{ "Metric": pc.metric, }, Data: map[string]float64{ "Perc50":  q50 * msFactor, "Perc90":  q90 * msFactor, "Perc99":  q99 * msFactor, "Average": (*hist.SampleSum / float64(*hist.SampleCount)) * msFactor, }, Unit: "ms", } } func clearPromHistogram(hist *dto.Histogram) { if hist.SampleCount != nil { *hist.SampleCount = 0 } if hist.SampleSum != nil { *hist.SampleSum = 0 } for _, b := range hist.Bucket { if b.CumulativeCount != nil { *b.CumulativeCount = 0 } if b.UpperBound != nil { *b.UpperBound = 0 } } } type throughputCollector struct { podInformer           coreinformers.PodInformer schedulingThroughputs []float64 } func newThroughputCollector(podInformer coreinformers.PodInformer) *throughputCollector { return &throughputCollector{ podInformer: podInformer, } } func (tc *throughputCollector) run(stopCh chan struct{}) { podsScheduled, err := getScheduledPods(tc.podInformer) if err != nil { klog.Fatalf("%v", err) } lastScheduledCount := len(podsScheduled) for { select { case <-stopCh: return case <-time.After(throughputSampleFrequency): podsScheduled, err := getScheduledPods(tc.podInformer) if err != nil { klog.Fatalf("%v", err) } scheduled := len(podsScheduled) samplingRatioSeconds := float64(throughputSampleFrequency) / float64(time.Second) throughput := float64(scheduled-lastScheduledCount) / samplingRatioSeconds tc.schedulingThroughputs = append(tc.schedulingThroughputs, throughput) lastScheduledCount = scheduled klog.Infof("%d pods scheduled", lastScheduledCount) } } } func (tc *throughputCollector) collect() *DataItem { throughputSummary := &DataItem{} if length := len(tc.schedulingThroughputs); length > 0 { sort.Float64s(tc.schedulingThroughputs) sum := 0.0 for i := range tc.schedulingThroughputs { sum += tc.schedulingThroughputs[i] } throughputSummary.Labels = map[string]string{ "Metric": "SchedulingThroughput", } throughputSummary.Data = map[string]float64{ "Average": sum / float64(length), "Perc50":  tc.schedulingThroughputs[int(math.Ceil(float64(length*50)/100))-1], "Perc90":  tc.schedulingThroughputs[int(math.Ceil(float64(length*90)/100))-1], "Perc99":  tc.schedulingThroughputs[int(math.Ceil(float64(length*99)/100))-1], } throughputSummary.Unit = "pods/s" } return throughputSummary } </ins>


/* Release : v1.15 Testname: Pods, delete grace period <del> Description: Create a pod, make sure it is running. Using the http client send a 'delete' with gracePeriodSeconds=30. Pod SHOULD get deleted within 30 seconds. </del> <ins> Description: Create a pod, make sure it is running. Using the http client send a 'delete' with gracePeriodSeconds=30. Pod SHOULD get terminated within gracePeriodSeconds and removed from API server within a window. </ins> */ <del> ginkgo.It("should be submitted and removed [Flaky]", func() { </del> <ins> ginkgo.It("should be submitted and removed", func() { </ins> ginkgo.By("creating the pod") name := "pod-submit-remove-" + string(uuid.NewUUID()) value := strconv.Itoa(time.Now().Nanosecond())


ginkgo.By("verifying the kubelet observed the termination notice") <ins> // allow up to 3x grace period (which allows process termination) // for the kubelet to remove from api.  need to follow-up on if this // latency between termination and reportal can be isolated further. </ins> start := time.Now() <del> err = wait.Poll(time.Second*5, time.Second*30, func() (bool, error) { </del> <ins> err = wait.Poll(time.Second*5, time.Second*30*3, func() (bool, error) { </ins> podList, err := e2ekubelet.GetKubeletPods(f.ClientSet, pod.Spec.NodeName) if err != nil { framework.Logf("Unable to retrieve kubelet pods for node %v: %v", pod.Spec.NodeName, err)


<ins> # See the OWNERS docs at https://go.k8s.io/owners approvers: - lavalamp - smarterclayton - deads2k - sttts - liggitt - caesarxuchao reviewers: - thockin - lavalamp - smarterclayton - wojtek-t - deads2k - derekwaynecarr - caesarxuchao - cheftako - mikedanese - liggitt - gmarek - sttts - ncdc - logicalhan - tallclair labels: - sig/api-machinery </ins>  No newline at end of file


package apimachinery import ( <ins> "encoding/json" </ins> "fmt" "strings" "sync"


apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" <ins> "k8s.io/apimachinery/pkg/util/uuid" </ins> "k8s.io/apimachinery/pkg/util/wait" "k8s.io/kubernetes/test/e2e/framework" e2epod "k8s.io/kubernetes/test/e2e/framework/pod" imageutils "k8s.io/kubernetes/test/utils/image" "github.com/onsi/ginkgo" <ins> "k8s.io/apimachinery/pkg/types" </ins> ) func extinguish(f *framework.Framework, totalNS int, maxAllowedAfterDel int, maxSeconds int) {


ginkgo.It("should always delete fast (ALL of 100 namespaces in 150 seconds) [Feature:ComprehensiveNamespaceDraining]", func() { extinguish(f, 100, 0, 150) }) <ins> ginkgo.It("should patch a Namespace", func() { ginkgo.By("creating a Namespace") namespaceName := "nspatchtest-" + string(uuid.NewUUID()) ns, err := f.CreateNamespace(namespaceName, nil) framework.ExpectNoError(err, "failed creating Namespace") namespaceName = ns.ObjectMeta.Name ginkgo.By("patching the Namespace") nspatch, err := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ "labels": map[string]string{"testLabel": "testValue"}, }, }) framework.ExpectNoError(err, "failed to marshal JSON patch data") _, err = f.ClientSet.CoreV1().Namespaces().Patch(namespaceName, types.StrategicMergePatchType, []byte(nspatch)) framework.ExpectNoError(err, "failed to patch Namespace") ginkgo.By("get the Namespace and ensuring it has the label") namespace, err := f.ClientSet.CoreV1().Namespaces().Get(namespaceName, metav1.GetOptions{}) framework.ExpectNoError(err, "failed to get Namespace") framework.ExpectEqual(namespace.ObjectMeta.Labels["testLabel"], "testValue", "namespace not patched") }) </ins> })


## Known Issues - volumeDevices mapping ignored when container is privileged - The `Should recreate evicted statefulset` conformance [test]( https://github.com/kubernetes/kubernetes/blob/master/test/e2e/apps/statefulset.go) fails because `Pod ss-0 expected to be re-created at least once`. This was caused by the `Predicate PodFitsHostPorts failed` scheduling error. The root cause was a host port conflict for port `21017`. This port was in-use as an ephemeral port by another application running on the node. This will be looked at for the 1.18 release. <ins> - client-go discovery clients constructed using `NewDiscoveryClientForConfig` or `NewDiscoveryClientForConfigOrDie` default to rate limits that cause normal discovery request patterns to take several seconds. This is fixed in https://issue.k8s.io/86168 and will be resolved in v1.17.1. As a workaround, the `Burst` value can be adjusted higher in the rest.Config passed into `NewDiscoveryClientForConfig` or `NewDiscoveryClientForConfigOrDie`. </ins> ## Urgent Upgrade Notes ### (No, really, you MUST read this before you upgrade)


if config.Timeout == 0 { config.Timeout = defaultTimeout } <ins> if config.Burst == 0 && config.QPS < 100 { // discovery is expected to be bursty, increase the default burst // to accommodate looking up resource info for many API groups. // matches burst set by ConfigFlags#ToDiscoveryClient(). // see https://issue.k8s.io/86149 config.Burst = 100 } </ins> codec := runtime.NoopEncoder{Decoder: scheme.Codecs.UniversalDecoder()} config.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec}) if len(config.UserAgent) == 0 {


"net/http/httptest" "reflect" "testing" <ins> "time" </ins> "github.com/gogo/protobuf/proto" "github.com/googleapis/gnostic/OpenAPIv2"


{Name: "jobs", Namespaced: true, Kind: "Job"}, }, } <ins> extensionsbeta3 := metav1.APIResourceList{GroupVersion: "extensions/v1beta3", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} extensionsbeta4 := metav1.APIResourceList{GroupVersion: "extensions/v1beta4", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} extensionsbeta5 := metav1.APIResourceList{GroupVersion: "extensions/v1beta5", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} extensionsbeta6 := metav1.APIResourceList{GroupVersion: "extensions/v1beta6", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} extensionsbeta7 := metav1.APIResourceList{GroupVersion: "extensions/v1beta7", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} extensionsbeta8 := metav1.APIResourceList{GroupVersion: "extensions/v1beta8", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} extensionsbeta9 := metav1.APIResourceList{GroupVersion: "extensions/v1beta9", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} extensionsbeta10 := metav1.APIResourceList{GroupVersion: "extensions/v1beta10", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta1 := metav1.APIResourceList{GroupVersion: "apps/v1beta1", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta2 := metav1.APIResourceList{GroupVersion: "apps/v1beta2", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta3 := metav1.APIResourceList{GroupVersion: "apps/v1beta3", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta4 := metav1.APIResourceList{GroupVersion: "apps/v1beta4", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta5 := metav1.APIResourceList{GroupVersion: "apps/v1beta5", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta6 := metav1.APIResourceList{GroupVersion: "apps/v1beta6", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta7 := metav1.APIResourceList{GroupVersion: "apps/v1beta7", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta8 := metav1.APIResourceList{GroupVersion: "apps/v1beta8", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta9 := metav1.APIResourceList{GroupVersion: "apps/v1beta9", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} appsbeta10 := metav1.APIResourceList{GroupVersion: "apps/v1beta10", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}} </ins> tests := []struct { resourcesList *metav1.APIResourceList path          string


list = &beta case "/apis/extensions/v1beta2": list = &beta2 <ins> case "/apis/extensions/v1beta3": list = &extensionsbeta3 case "/apis/extensions/v1beta4": list = &extensionsbeta4 case "/apis/extensions/v1beta5": list = &extensionsbeta5 case "/apis/extensions/v1beta6": list = &extensionsbeta6 case "/apis/extensions/v1beta7": list = &extensionsbeta7 case "/apis/extensions/v1beta8": list = &extensionsbeta8 case "/apis/extensions/v1beta9": list = &extensionsbeta9 case "/apis/extensions/v1beta10": list = &extensionsbeta10 case "/apis/apps/v1beta1": list = &appsbeta1 case "/apis/apps/v1beta2": list = &appsbeta2 case "/apis/apps/v1beta3": list = &appsbeta3 case "/apis/apps/v1beta4": list = &appsbeta4 case "/apis/apps/v1beta5": list = &appsbeta5 case "/apis/apps/v1beta6": list = &appsbeta6 case "/apis/apps/v1beta7": list = &appsbeta7 case "/apis/apps/v1beta8": list = &appsbeta8 case "/apis/apps/v1beta9": list = &appsbeta9 case "/apis/apps/v1beta10": list = &appsbeta10 </ins> case "/api": list = &metav1.APIVersions{ Versions: []string{


list = &metav1.APIGroupList{ Groups: []metav1.APIGroup{ { <ins> Name: "apps", Versions: []metav1.GroupVersionForDiscovery{ {GroupVersion: "apps/v1beta1", Version: "v1beta1"}, {GroupVersion: "apps/v1beta2", Version: "v1beta2"}, {GroupVersion: "apps/v1beta3", Version: "v1beta3"}, {GroupVersion: "apps/v1beta4", Version: "v1beta4"}, {GroupVersion: "apps/v1beta5", Version: "v1beta5"}, {GroupVersion: "apps/v1beta6", Version: "v1beta6"}, {GroupVersion: "apps/v1beta7", Version: "v1beta7"}, {GroupVersion: "apps/v1beta8", Version: "v1beta8"}, {GroupVersion: "apps/v1beta9", Version: "v1beta9"}, {GroupVersion: "apps/v1beta10", Version: "v1beta10"}, }, }, { </ins> Name: "extensions", Versions: []metav1.GroupVersionForDiscovery{ {GroupVersion: "extensions/v1beta1", Version: "v1beta1"}, {GroupVersion: "extensions/v1beta2", Version: "v1beta2"}, <ins> {GroupVersion: "extensions/v1beta3", Version: "v1beta3"}, {GroupVersion: "extensions/v1beta4", Version: "v1beta4"}, {GroupVersion: "extensions/v1beta5", Version: "v1beta5"}, {GroupVersion: "extensions/v1beta6", Version: "v1beta6"}, {GroupVersion: "extensions/v1beta7", Version: "v1beta7"}, {GroupVersion: "extensions/v1beta8", Version: "v1beta8"}, {GroupVersion: "extensions/v1beta9", Version: "v1beta9"}, {GroupVersion: "extensions/v1beta10", Version: "v1beta10"}, </ins> }, }, },


w.Write(output) })) defer server.Close() <del> client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) </del> for _, test := range tests { <ins> client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) </ins> got, err := client.ServerResourcesForGroupVersion(test.request) if test.expectErr { if err == nil {


} } <ins> client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) start := time.Now() </ins> serverResources, err := client.ServerResources() if err != nil { t.Errorf("unexpected error: %v", err) } <ins> end := time.Now() if d := end.Sub(start); d > time.Second { t.Errorf("took too long to perform discovery: %s", d) } </ins> serverGroupVersions := groupVersions(serverResources) <del> expectedGroupVersions := []string{"v1", "extensions/v1beta1", "extensions/v1beta2"} </del> <ins> expectedGroupVersions := []string{ "v1", "apps/v1beta1", "apps/v1beta2", "apps/v1beta3", "apps/v1beta4", "apps/v1beta5", "apps/v1beta6", "apps/v1beta7", "apps/v1beta8", "apps/v1beta9", "apps/v1beta10", "extensions/v1beta1", "extensions/v1beta2", "extensions/v1beta3", "extensions/v1beta4", "extensions/v1beta5", "extensions/v1beta6", "extensions/v1beta7", "extensions/v1beta8", "extensions/v1beta9", "extensions/v1beta10", } </ins> if !reflect.DeepEqual(expectedGroupVersions, serverGroupVersions) { t.Errorf("unexpected group versions: %v", diff.ObjectReflectDiff(expectedGroupVersions, serverGroupVersions)) }


CMD_TARGETS="${CMD_TARGETS} ${KUBE_CONFORMANCE_IMAGE_TARGETS[*]}" fi <ins> # TODO(dims): Remove this when we get rid of hyperkube image CMD_TARGETS="${CMD_TARGETS} cmd/kubelet cmd/kubectl" </ins> kube::build::verify_prereqs kube::build::build_image kube::build::run_build_command make all WHAT="${CMD_TARGETS}" KUBE_BUILD_PLATFORMS="${KUBE_SERVER_PLATFORMS[*]}"