command := exec.Command("umount", target) output, err := command.CombinedOutput() if err != nil { <ins> if err.Error() == errNoChildProcesses { if command.ProcessState.Success() { // We don't consider errNoChildProcesses an error if the process itself succeeded (see - k/k issue #103753). return nil } // Rewrite err with the actual exit error of the process. err = &exec.ExitError{ProcessState: command.ProcessState} } </ins> return fmt.Errorf("unmount failed: %vnUnmounting arguments: %snOutput: %s", err, target, string(output)) } return nil


Subsystem:         KubeletSubsystem, Name:              AssignedConfigKey, Help:              "The node's understanding of intended config. The count is always 1.", <del> DeprecatedVersion: "1.23.0", </del> <ins> DeprecatedVersion: "1.22.0", </ins> StabilityLevel:    metrics.ALPHA, }, []string{ConfigSourceLabelKey, ConfigUIDLabelKey, ConfigResourceVersionLabelKey, KubeletConfigKeyLabelKey},


Subsystem:         KubeletSubsystem, Name:              ActiveConfigKey, Help:              "The config source the node is actively using. The count is always 1.", <del> DeprecatedVersion: "1.23.0", </del> <ins> DeprecatedVersion: "1.22.0", </ins> StabilityLevel:    metrics.ALPHA, }, []string{ConfigSourceLabelKey, ConfigUIDLabelKey, ConfigResourceVersionLabelKey, KubeletConfigKeyLabelKey},


Subsystem:         KubeletSubsystem, Name:              LastKnownGoodConfigKey, Help:              "The config source the node will fall back to when it encounters certain errors. The count is always 1.", <del> DeprecatedVersion: "1.23.0", </del> <ins> DeprecatedVersion: "1.22.0", </ins> StabilityLevel:    metrics.ALPHA, }, []string{ConfigSourceLabelKey, ConfigUIDLabelKey, ConfigResourceVersionLabelKey, KubeletConfigKeyLabelKey},


Subsystem:         KubeletSubsystem, Name:              ConfigErrorKey, Help:              "This metric is true (1) if the node is experiencing a configuration-related error, false (0) otherwise.", <del> DeprecatedVersion: "1.23.0", </del> <ins> DeprecatedVersion: "1.22.0", </ins> StabilityLevel:    metrics.ALPHA, }, )


framework.ExpectNoError(err) beforeKC = kc } <ins> // show hidden metrics for release 1.22 beforeKC = updateShowHiddenMetricsForVersion(beforeKC, "1.22") </ins> // reset the node's assigned/active/last-known-good config by setting the source to nil, // so each test starts from a clean-slate (&nodeConfigTestCase{


framework.ExpectNoError(err) localKC = kc } <ins> // show hidden metrics for release 1.22 localKC = updateShowHiddenMetricsForVersion(localKC, "1.22") </ins> }) ginkgo.AfterEach(func() {


return nil }, timeout, interval).Should(gomega.BeNil()) } <ins> func updateShowHiddenMetricsForVersion(cfg *kubeletconfig.KubeletConfiguration, version string) *kubeletconfig.KubeletConfiguration { if cfg == nil { return &kubeletconfig.KubeletConfiguration{ ShowHiddenMetricsForVersion: version, } } cfg.ShowHiddenMetricsForVersion = version return cfg } </ins>


return false } <del> // GetAllocatableDevices returns information about all the devices known to the manager </del> <ins> // GetAllocatableDevices returns information about all the healthy devices known to the manager </ins> func (m *ManagerImpl) GetAllocatableDevices() ResourceDeviceInstances { m.mutex.Lock() <del> resp := m.allDevices.Clone() m.mutex.Unlock() klog.V(4).InfoS("Known devices", "numDevices", len(resp)) </del> <ins> defer m.mutex.Unlock() resp := m.allDevices.Filter(m.healthyDevices) klog.V(4).InfoS("GetAllocatableDevices", "known", len(m.allDevices), "allocatable", len(resp)) </ins> return resp }


as.True(testManager.isDevicePluginResource(resourceName2)) } <ins> func TestGetAllocatableDevicesMultipleResources(t *testing.T) { socketDir, socketName, _, err := tmpSocketDir() topologyStore := topologymanager.NewFakeManager() require.NoError(t, err) defer os.RemoveAll(socketDir) testManager, err := newManagerImpl(socketName, nil, topologyStore) as := assert.New(t) as.NotNil(testManager) as.Nil(err) resource1Devs := []pluginapi.Device{ {ID: "R1Device1", Health: pluginapi.Healthy}, {ID: "R1Device2", Health: pluginapi.Healthy}, {ID: "R1Device3", Health: pluginapi.Unhealthy}, } resourceName1 := "domain1.com/resource1" e1 := &endpointImpl{} testManager.endpoints[resourceName1] = endpointInfo{e: e1, opts: nil} testManager.genericDeviceUpdateCallback(resourceName1, resource1Devs) resource2Devs := []pluginapi.Device{ {ID: "R2Device1", Health: pluginapi.Healthy}, } resourceName2 := "other.domain2.org/resource2" e2 := &endpointImpl{} testManager.endpoints[resourceName2] = endpointInfo{e: e2, opts: nil} testManager.genericDeviceUpdateCallback(resourceName2, resource2Devs) allocatableDevs := testManager.GetAllocatableDevices() as.Equal(2, len(allocatableDevs)) devInstances1, ok := allocatableDevs[resourceName1] as.True(ok) checkAllocatableDevicesConsistsOf(as, devInstances1, []string{"R1Device1", "R1Device2"}) devInstances2, ok := allocatableDevs[resourceName2] as.True(ok) checkAllocatableDevicesConsistsOf(as, devInstances2, []string{"R2Device1"}) } func TestGetAllocatableDevicesHealthTransition(t *testing.T) { socketDir, socketName, _, err := tmpSocketDir() topologyStore := topologymanager.NewFakeManager() require.NoError(t, err) defer os.RemoveAll(socketDir) testManager, err := newManagerImpl(socketName, nil, topologyStore) as := assert.New(t) as.NotNil(testManager) as.Nil(err) resource1Devs := []pluginapi.Device{ {ID: "R1Device1", Health: pluginapi.Healthy}, {ID: "R1Device2", Health: pluginapi.Healthy}, {ID: "R1Device3", Health: pluginapi.Unhealthy}, } // Adds three devices for resource1, two healthy and one unhealthy. // Expects allocatable devices for resource1 to be 2. resourceName1 := "domain1.com/resource1" e1 := &endpointImpl{} testManager.endpoints[resourceName1] = endpointInfo{e: e1, opts: nil} testManager.genericDeviceUpdateCallback(resourceName1, resource1Devs) allocatableDevs := testManager.GetAllocatableDevices() as.Equal(1, len(allocatableDevs)) devInstances, ok := allocatableDevs[resourceName1] as.True(ok) checkAllocatableDevicesConsistsOf(as, devInstances, []string{"R1Device1", "R1Device2"}) // Unhealthy device becomes healthy resource1Devs = []pluginapi.Device{ {ID: "R1Device1", Health: pluginapi.Healthy}, {ID: "R1Device2", Health: pluginapi.Healthy}, {ID: "R1Device3", Health: pluginapi.Healthy}, } testManager.genericDeviceUpdateCallback(resourceName1, resource1Devs) allocatableDevs = testManager.GetAllocatableDevices() as.Equal(1, len(allocatableDevs)) devInstances, ok = allocatableDevs[resourceName1] as.True(ok) checkAllocatableDevicesConsistsOf(as, devInstances, []string{"R1Device1", "R1Device2", "R1Device3"}) } func checkAllocatableDevicesConsistsOf(as *assert.Assertions, devInstances DeviceInstances, expectedDevs []string) { as.Equal(len(expectedDevs), len(devInstances)) for _, deviceID := range expectedDevs { _, ok := devInstances[deviceID] as.True(ok) } } </ins> func constructDevices(devices []string) checkpoint.DevicesPerNUMA { ret := checkpoint.DevicesPerNUMA{} for _, dev := range devices {


} return clone } <ins> // Filter takes a condition set expressed as map[string]sets.String and returns a new // ResourceDeviceInstances with only the devices matching the condition set. func (rdev ResourceDeviceInstances) Filter(cond map[string]sets.String) ResourceDeviceInstances { filtered := NewResourceDeviceInstances() for resourceName, filterIDs := range cond { if _, exists := rdev[resourceName]; !exists { continue } filtered[resourceName] = DeviceInstances{} for instanceID, instance := range rdev[resourceName] { if filterIDs.Has(instanceID) { filtered[resourceName][instanceID] = instance } } } return filtered } </ins>


package devicemanager import ( <ins> "encoding/json" </ins> "testing" "github.com/stretchr/testify/require" <ins> "k8s.io/apimachinery/pkg/util/sets" pluginapi "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1" </ins> "k8s.io/kubernetes/pkg/kubelet/cm/devicemanager/checkpoint" )


} } } <ins> func TestResourceDeviceInstanceFilter(t *testing.T) { var expected string var cond map[string]sets.String var resp ResourceDeviceInstances devs := ResourceDeviceInstances{ "foo": DeviceInstances{ "dev-foo1": pluginapi.Device{ ID: "foo1", }, "dev-foo2": pluginapi.Device{ ID: "foo2", }, "dev-foo3": pluginapi.Device{ ID: "foo3", }, }, "bar": DeviceInstances{ "dev-bar1": pluginapi.Device{ ID: "bar1", }, "dev-bar2": pluginapi.Device{ ID: "bar2", }, "dev-bar3": pluginapi.Device{ ID: "bar3", }, }, "baz": DeviceInstances{ "dev-baz1": pluginapi.Device{ ID: "baz1", }, "dev-baz2": pluginapi.Device{ ID: "baz2", }, "dev-baz3": pluginapi.Device{ ID: "baz3", }, }, } resp = devs.Filter(map[string]sets.String{}) expected = `{}` expectResourceDeviceInstances(t, resp, expected) cond = map[string]sets.String{ "foo": sets.NewString("dev-foo1", "dev-foo2"), "bar": sets.NewString("dev-bar1"), } resp = devs.Filter(cond) expected = `{"bar":{"dev-bar1":{"ID":"bar1"}},"foo":{"dev-foo1":{"ID":"foo1"},"dev-foo2":{"ID":"foo2"}}}` expectResourceDeviceInstances(t, resp, expected) cond = map[string]sets.String{ "foo": sets.NewString("dev-foo1", "dev-foo2", "dev-foo3"), "bar": sets.NewString("dev-bar1", "dev-bar2", "dev-bar3"), "baz": sets.NewString("dev-baz1", "dev-baz2", "dev-baz3"), } resp = devs.Filter(cond) expected = `{"bar":{"dev-bar1":{"ID":"bar1"},"dev-bar2":{"ID":"bar2"},"dev-bar3":{"ID":"bar3"}},"baz":{"dev-baz1":{"ID":"baz1"},"dev-baz2":{"ID":"baz2"},"dev-baz3":{"ID":"baz3"}},"foo":{"dev-foo1":{"ID":"foo1"},"dev-foo2":{"ID":"foo2"},"dev-foo3":{"ID":"foo3"}}}` expectResourceDeviceInstances(t, resp, expected) cond = map[string]sets.String{ "foo": sets.NewString("dev-foo1", "dev-foo2", "dev-foo3", "dev-foo4"), "bar": sets.NewString("dev-bar1", "dev-bar2", "dev-bar3", "dev-bar4"), "baz": sets.NewString("dev-baz1", "dev-baz2", "dev-baz3", "dev-bar4"), } resp = devs.Filter(cond) expected = `{"bar":{"dev-bar1":{"ID":"bar1"},"dev-bar2":{"ID":"bar2"},"dev-bar3":{"ID":"bar3"}},"baz":{"dev-baz1":{"ID":"baz1"},"dev-baz2":{"ID":"baz2"},"dev-baz3":{"ID":"baz3"}},"foo":{"dev-foo1":{"ID":"foo1"},"dev-foo2":{"ID":"foo2"},"dev-foo3":{"ID":"foo3"}}}` expectResourceDeviceInstances(t, resp, expected) cond = map[string]sets.String{ "foo": sets.NewString("dev-foo1", "dev-foo4", "dev-foo7"), "bar": sets.NewString("dev-bar1", "dev-bar4", "dev-bar7"), "baz": sets.NewString("dev-baz1", "dev-baz4", "dev-baz7"), } resp = devs.Filter(cond) expected = `{"bar":{"dev-bar1":{"ID":"bar1"}},"baz":{"dev-baz1":{"ID":"baz1"}},"foo":{"dev-foo1":{"ID":"foo1"}}}` expectResourceDeviceInstances(t, resp, expected) } func expectResourceDeviceInstances(t *testing.T, resp ResourceDeviceInstances, expected string) { // per docs in https://pkg.go.dev/encoding/json#Marshal // "Map values encode as JSON objects. The map's key type must either be a string, an integer type, or // implement encoding.TextMarshaler. The map keys are sorted [...]" // so this check is expected to be stable and not flaky data, err := json.Marshal(resp) if err != nil { t.Fatalf("unexpected JSON marshalling error: %v", err) } got := string(data) if got != expected { t.Errorf("expected %q got %q", expected, got) } } </ins>


}, { "ImportPath": "github.com/google/cadvisor/api", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/container", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/events", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/fs", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/healthz", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/http", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/info/v1", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/info/v2", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/manager", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/metrics", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/pages", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/storage", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/summary", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/utils", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/validate", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/cadvisor/version", <del> "Comment": "0.10.1-92-g41a0c30", "Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4" </del> <ins> "Comment": "0.10.1-103-gbfaf70b", "Rev": "bfaf70b2555fcaba212130da04a21302344e38f5" </ins> }, { "ImportPath": "github.com/google/gofuzz",


// TODO(jnagal): Infer schema through reflection. (See bigquery/client/example) func (self *bigqueryStorage) GetSchema() *bigquery.TableSchema { <del> fields := make([]*bigquery.TableFieldSchema, 18) </del> <ins> fields := make([]*bigquery.TableFieldSchema, 19) </ins> i := 0 fields[i] = &bigquery.TableFieldSchema{ Type: typeTimestamp,


"flag" "fmt" "io/ioutil" <del> "net/http" </del> "strings" <del> "code.google.com/p/goauth2/oauth" "code.google.com/p/goauth2/oauth/jwt" </del> bigquery "code.google.com/p/google-api-go-client/bigquery/v2" <ins> "golang.org/x/oauth2" "golang.org/x/oauth2/jwt" </ins> ) var (


type Client struct { service   *bigquery.Service <del> token     *oauth.Token </del> <ins> token     *oauth2.Token </ins> datasetId string tableId   string } // Helper method to create an authenticated connection. <del> func connect() (*oauth.Token, *bigquery.Service, error) { </del> <ins> func connect() (*oauth2.Token, *bigquery.Service, error) { </ins> if *clientId == "" { return nil, nil, fmt.Errorf("no client id specified") }


return nil, nil, fmt.Errorf("could not access credential file %v - %v", pemFile, err) } <del> t := jwt.NewToken(*serviceAccount, authScope, pemBytes) token, err := t.Assert(&http.Client{}) </del> <ins> jwtConfig := &jwt.Config{ Email:      *serviceAccount, Scopes:     []string{authScope}, PrivateKey: pemBytes, TokenURL:   "https://accounts.google.com/o/oauth2/token", } token, err := jwtConfig.TokenSource(oauth2.NoContext).Token() </ins> if err != nil { <del> fmt.Printf("Invalid token: %vn", err) </del> return nil, nil, err } <del> config := &oauth.Config{ ClientId:     *clientId, ClientSecret: *clientSecret, Scope:        authScope, AuthURL:      "https://accounts.google.com/o/oauth2/auth", TokenURL:     "https://accounts.google.com/o/oauth2/token", </del> <ins> if !token.Valid() { return nil, nil, fmt.Errorf("invalid token for BigQuery oauth") </ins> } <del> transport := &oauth.Transport{ Token:  token, Config: config, </del> <ins> config := &oauth2.Config{ ClientID:     *clientId, ClientSecret: *clientSecret, Scopes:       []string{authScope}, Endpoint: oauth2.Endpoint{ AuthURL:  "https://accounts.google.com/o/oauth2/auth", TokenURL: "https://accounts.google.com/o/oauth2/token", }, </ins> } <del> client := transport.Client() </del> <ins> client := config.Client(oauth2.NoContext, token) </ins> service, err := bigquery.New(client) if err != nil {


} // Refresh expired token. <del> if c.token.Expired() { </del> <ins> if !c.token.Valid() { </ins> token, service, err := connect() if err != nil { return nil, err


apiVersion: apps/v1 kind: Deployment metadata: <del> name: metrics-server-v0.5.0 </del> <ins> name: metrics-server-v0.5.1 </ins> namespace: kube-system labels: k8s-app: metrics-server addonmanager.kubernetes.io/mode: Reconcile <del> version: v0.5.0 </del> <ins> version: v0.5.1 </ins> spec: selector: matchLabels: k8s-app: metrics-server <del> version: v0.5.0 </del> <ins> version: v0.5.1 </ins> template: metadata: name: metrics-server labels: k8s-app: metrics-server <del> version: v0.5.0 </del> <ins> version: v0.5.1 </ins> spec: securityContext: seccompProfile:


kubernetes.io/os: linux containers: - name: metrics-server <del> image: k8s.gcr.io/metrics-server/metrics-server:v0.5.0 </del> <ins> image: k8s.gcr.io/metrics-server/metrics-server:v0.5.1 </ins> command: - /metrics-server - --metric-resolution=30s


- --memory={{ base_metrics_server_memory }} - --extra-memory={{ metrics_server_memory_per_node }}Mi - --threshold=5 <del> - --deployment=metrics-server-v0.5.0 </del> <ins> - --deployment=metrics-server-v0.5.1 </ins> - --container=metrics-server - --poll-period=30000 - --estimator=exponential


log.Printf("Error parsing response (%#v): %s", response, err) return err } <del> log.Printf("Got initial state from etcd: %+v", manifests) </del> <ins> log.Printf("Got state from etcd: %+v", manifests) </ins> updateChannel <- manifestUpdate{etcdSource, manifests} return nil }


defer util.HandleCrash() for { watchResponse := <-watchChannel <del> log.Printf("Got change: %#v", watchResponse) </del> // This means the channel has been closed. if watchResponse == nil { return } <ins> log.Printf("Got etcd change: %#v", watchResponse) </ins> manifests, err := kl.extractFromEtcd(watchResponse) if err != nil { log.Printf("Error handling response from etcd: %#v", err)


// Sync the configured list of containers (desired state) with the host current state func (kl *Kubelet) SyncManifests(config []api.ContainerManifest) error { <del> log.Printf("Desired:%#v", config) </del> <ins> log.Printf("Desired: %#v", config) </ins> var err error desired := map[string]bool{} for _, manifest := range config {


continue } if !exists { <del> log.Printf("Network container doesn't exit, creating") </del> <ins> log.Printf("Network container doesn't exist, creating") </ins> netName, err = kl.createNetworkContainer(&manifest) if err != nil { log.Printf("Failed to create network container: %#v", err)


} } existingContainers, _ := kl.ListContainers() <del> log.Printf("Existing:n%#v Desired: %#v", existingContainers, desired) </del> <ins> log.Printf("Existing: %#v Desired: %#v", existingContainers, desired) </ins> for _, container := range existingContainers { // Skip containers that we didn't create to allow users to manually // spin up their own containers if they want.


https://storage.googleapis.com/kubernetes-release/release/${version}/kubernetes-src.tar.gz It is based on the Kubernetes source at: <del> https://github.com/kubernetes/kubernetes/tree/${gitref} </del> <ins> https://github.com/kubernetes/kubernetes/tree/${gitref/-gke.*/} </ins> ${devel} For Kubernetes copyright and licensing information, see: /home/kubernetes/LICENSES


} func getMemoryStat(f *framework.Framework, host string) (rss, workingSet float64) { <del> memCmd := "cat /sys/fs/cgroup/memory/system.slice/node-problem-detector.service/memory.usage_in_bytes && cat /sys/fs/cgroup/memory/system.slice/node-problem-detector.service/memory.stat" </del> <ins> var memCmd string isCgroupV2 := isHostRunningCgroupV2(f, host) if isCgroupV2 { memCmd = "cat /sys/fs/cgroup/system.slice/node-problem-detector.service/memory.current && cat /sys/fs/cgroup/system.slice/node-problem-detector.service/memory.stat" } else { memCmd = "cat /sys/fs/cgroup/memory/system.slice/node-problem-detector.service/memory.usage_in_bytes && cat /sys/fs/cgroup/memory/system.slice/node-problem-detector.service/memory.stat" } </ins> result, err := e2essh.SSH(memCmd, host, framework.TestContext.Provider) framework.ExpectNoError(err) framework.ExpectEqual(result.Code, 0)


memoryUsage, err := strconv.ParseFloat(lines[0], 64) framework.ExpectNoError(err) <ins> var rssToken, inactiveFileToken string if isCgroupV2 { // Use Anon memory for RSS as cAdvisor on cgroupv2 // see https://github.com/google/cadvisor/blob/a9858972e75642c2b1914c8d5428e33e6392c08a/container/libcontainer/handler.go#L799 rssToken = "anon" inactiveFileToken = "inactive_file" } else { rssToken = "total_rss" inactiveFileToken = "total_inactive_file" } </ins> var totalInactiveFile float64 for _, line := range lines[1:] { tokens := strings.Split(line, " ") <del> if tokens[0] == "total_rss" { </del> <ins> if tokens[0] == rssToken { </ins> rss, err = strconv.ParseFloat(tokens[1], 64) framework.ExpectNoError(err) } <del> if tokens[0] == "total_inactive_file" { </del> <ins> if tokens[0] == inactiveFileToken { </ins> totalInactiveFile, err = strconv.ParseFloat(tokens[1], 64) framework.ExpectNoError(err) }


} func getCPUStat(f *framework.Framework, host string) (usage, uptime float64) { <del> cpuCmd := "cat /sys/fs/cgroup/cpu/system.slice/node-problem-detector.service/cpuacct.usage && cat /proc/uptime | awk '{print $1}'" </del> <ins> var cpuCmd string if isHostRunningCgroupV2(f, host) { cpuCmd = " cat /sys/fs/cgroup/cpu.stat | grep 'usage_usec' | sed 's/[^0-9]*//g' && cat /proc/uptime | awk '{print $1}'" } else { cpuCmd = "cat /sys/fs/cgroup/cpu/system.slice/node-problem-detector.service/cpuacct.usage && cat /proc/uptime | awk '{print $1}'" } </ins> result, err := e2essh.SSH(cpuCmd, host, framework.TestContext.Provider) framework.ExpectNoError(err) framework.ExpectEqual(result.Code, 0)


return } <ins> func isHostRunningCgroupV2(f *framework.Framework, host string) bool { result, err := e2essh.SSH("stat -fc %T /sys/fs/cgroup/", host, framework.TestContext.Provider) framework.ExpectNoError(err) framework.ExpectEqual(result.Code, 0) // 0x63677270 == CGROUP2_SUPER_MAGIC // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html return strings.Contains(result.Stdout, "cgroup2") || strings.Contains(result.Stdout, "0x63677270") } </ins> func getNpdPodStat(f *framework.Framework, nodeName string) (cpuUsage, rss, workingSet float64) { summary, err := e2ekubelet.GetStatsSummary(f.ClientSet, nodeName) framework.ExpectNoError(err)


"UserDefinedMetrics": gomega.BeEmpty(), }) } <ins> expectedPageFaultsUpperBound := 1000000 </ins> expectedMajorPageFaultsUpperBound := 10 if IsCgroup2UnifiedMode() { <del> expectedMajorPageFaultsUpperBound = 1000 </del> <ins> // On cgroupv2 these stats are recursive, so make sure they are at least like the value set // above for the container. expectedPageFaultsUpperBound = 1e9 expectedMajorPageFaultsUpperBound = 100000 </ins> } podsContExpectations := sysContExpectations().(*gstruct.FieldsMatcher)


"UsageBytes":      bounded(10*e2evolume.Kb, memoryLimit), "WorkingSetBytes": bounded(10*e2evolume.Kb, memoryLimit), "RSSBytes":        bounded(1*e2evolume.Kb, memoryLimit), <del> "PageFaults":      bounded(0, 1000000), </del> <ins> "PageFaults":      bounded(0, expectedPageFaultsUpperBound), </ins> "MajorPageFaults": bounded(0, expectedMajorPageFaultsUpperBound), }) runtimeContExpectations := sysContExpectations().(*gstruct.FieldsMatcher)


func TestUpdatePodWithTerminatedPod(t *testing.T) { podWorkers, _ := createPodWorkers() terminatedPod := newPodWithPhase("0000-0000-0000", "done-pod", v1.PodSucceeded) <del> runningPod := &kubecontainer.Pod{ID: "0000-0000-0001", Name: "done-pod"} </del> <ins> orphanedPod := &kubecontainer.Pod{ID: "0000-0000-0001", Name: "orphaned-pod"} </ins> pod := newPod("0000-0000-0002", "running-pod") podWorkers.UpdatePod(UpdatePodOptions{


}) podWorkers.UpdatePod(UpdatePodOptions{ UpdateType: kubetypes.SyncPodKill, <del> RunningPod: runningPod, </del> <ins> RunningPod: orphanedPod, </ins> }) <ins> drainAllWorkers(podWorkers) </ins> if podWorkers.IsPodKnownTerminated(pod.UID) == true { t.Errorf("podWorker state should not be terminated") } if podWorkers.IsPodKnownTerminated(terminatedPod.UID) == false { t.Errorf("podWorker state should be terminated") } <del> if podWorkers.IsPodKnownTerminated(runningPod.ID) == true { t.Errorf("podWorker state should not be marked terminated for a running pod") </del> <ins> if podWorkers.IsPodKnownTerminated(orphanedPod.ID) == false { t.Errorf("podWorker state should be terminated for orphaned pod") </ins> } }


"uniqueItems": true }, { <del> "description": "Redirect the standard error stream of the pod for this call. Defaults to true.", </del> <ins> "description": "Redirect the standard error stream of the pod for this call.", </ins> "in": "query", "name": "stderr", "type": "boolean",


"uniqueItems": true }, { <del> "description": "Redirect the standard output stream of the pod for this call. Defaults to true.", </del> <ins> "description": "Redirect the standard output stream of the pod for this call.", </ins> "in": "query", "name": "stdout", "type": "boolean",


optional bool stdin = 1; // Redirect the standard output stream of the pod for this call. <del> // Defaults to true. </del> // +optional optional bool stdout = 2; // Redirect the standard error stream of the pod for this call. <del> // Defaults to true. </del> // +optional optional bool stderr = 3;


Stdin bool `json:"stdin,omitempty" protobuf:"varint,1,opt,name=stdin"` // Redirect the standard output stream of the pod for this call. <del> // Defaults to true. </del> // +optional Stdout bool `json:"stdout,omitempty" protobuf:"varint,2,opt,name=stdout"` // Redirect the standard error stream of the pod for this call. <del> // Defaults to true. </del> // +optional Stderr bool `json:"stderr,omitempty" protobuf:"varint,3,opt,name=stderr"`


var map_PodExecOptions = map[string]string{ "":          "PodExecOptions is the query options to a Pod's remote exec call.", "stdin":     "Redirect the standard input stream of the pod for this call. Defaults to false.", <del> "stdout":    "Redirect the standard output stream of the pod for this call. Defaults to true.", "stderr":    "Redirect the standard error stream of the pod for this call. Defaults to true.", </del> <ins> "stdout":    "Redirect the standard output stream of the pod for this call.", "stderr":    "Redirect the standard error stream of the pod for this call.", </ins> "tty":       "TTY if true indicates that a tty will be allocated for the exec call. Defaults to false.", "container": "Container in which to execute the command. Defaults to only container if there is only one container in the pod.", "command":   "Command is the remote command to execute. argv array. Not executed within a shell.",


RuntimeCgroupsName:    s.RuntimeCgroups, SystemCgroupsName:     s.SystemCgroups, KubeletCgroupsName:    s.KubeletCgroups, <ins> KubeletOOMScoreAdj:    s.OOMScoreAdj, </ins> CgroupsPerQOS:         s.CgroupsPerQOS, CgroupRoot:            s.CgroupRoot, CgroupDriver:          s.CgroupDriver,


RuntimeCgroupsName    string SystemCgroupsName     string KubeletCgroupsName    string <ins> KubeletOOMScoreAdj    int32 </ins> ContainerRuntime      string CgroupsPerQOS         bool CgroupRoot            string


kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" "k8s.io/kubernetes/pkg/kubelet/lifecycle" "k8s.io/kubernetes/pkg/kubelet/pluginmanager/cache" <del> "k8s.io/kubernetes/pkg/kubelet/qos" </del> "k8s.io/kubernetes/pkg/kubelet/stats/pidlimit" "k8s.io/kubernetes/pkg/kubelet/status" schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework"


} cont.ensureStateFunc = func(_ cgroups.Manager) error { <del> return ensureProcessInContainerWithOOMScore(os.Getpid(), qos.KubeletOOMScoreAdj, cont.manager) </del> <ins> return ensureProcessInContainerWithOOMScore(os.Getpid(), int(cm.KubeletOOMScoreAdj), cont.manager) </ins> } systemContainers = append(systemContainers, cont) } else { cm.periodicTasks = append(cm.periodicTasks, func() { <del> if err := ensureProcessInContainerWithOOMScore(os.Getpid(), qos.KubeletOOMScoreAdj, nil); err != nil { </del> <ins> if err := ensureProcessInContainerWithOOMScore(os.Getpid(), int(cm.KubeletOOMScoreAdj), nil); err != nil { </ins> klog.ErrorS(err, "Failed to ensure process in container with oom score") return }


echo "minion-$((${BASH_REMATCH[1]} - 1))" } <del> # Find the vagrant machien name based on the host name of the minion </del> <ins> # Find the vagrant machine name based on the host name of the minion </ins> function find-vagrant-name-by-minion-name { local ip="$1" if [[ "$ip" == "${INSTANCE_PREFIX}-master" ]]; then


} func (eic *execInContainer) SetDir(dir string) { <del> //unimplemented </del> <ins> // unimplemented </ins> } func (eic *execInContainer) SetStdin(in io.Reader) { <del> //unimplemented </del> <ins> // unimplemented </ins> } func (eic *execInContainer) SetStdout(out io.Writer) {


} func (eic *execInContainer) SetEnv(env []string) { <del> //unimplemented </del> <ins> // unimplemented </ins> } func (eic *execInContainer) Stop() { <del> //unimplemented </del> <ins> // unimplemented </ins> } func (eic *execInContainer) Start() error {


timeoutErr, ok := err.(*TimeoutError) if ok { if utilfeature.DefaultFeatureGate.Enabled(features.ExecProbeTimeout) { <del> return probe.Failure, string(data), nil </del> <ins> // When exec probe timeout, data is empty, so we should return timeoutErr.Error() as the stdout. return probe.Failure, timeoutErr.Error(), nil </ins> } klog.Warningf("Exec probe timed out after %s but ExecProbeTimeout feature gate was disabled", timeoutErr.Timeout())


"io" "strings" "testing" <ins> "time" </ins> "k8s.io/kubernetes/pkg/probe" )


{probe.Unknown, true, "", "", fmt.Errorf("test error")}, // Unhealthy {probe.Failure, false, "Fail", "", &fakeExitError{true, 1}}, <ins> // Timeout {probe.Failure, false, "", "command testcmd timed out", NewTimeoutError(fmt.Errorf("command testcmd timed out"), time.Second)}, </ins> } for i, test := range tests { fake := FakeCmd{


// TODO: This k8s-generic, well-known constant should be fetchable from another source, not be in this package KubeProxyClusterRoleName = "system:node-proxier" <ins> // KubeProxyClusterRoleBindingName sets the name for the kube-proxy CluterRoleBinding KubeProxyClusterRoleBindingName = "kubeadm:node-proxier" </ins> // KubeProxyServiceAccountName describes the name of the ServiceAccount for the kube-proxy addon KubeProxyServiceAccountName = "kube-proxy" <del> // KubeProxyClusterRoleBindingName sets the name for the kube-proxy CluterRoleBinding KubeProxyClusterRoleBindingName = "kubeam:node-proxier" </del> // KubeProxyConfigMapRoleName sets the name of ClusterRole for ConfigMap KubeProxyConfigMapRoleName = "kube-proxy" )


// https://github.com/kubernetes/kubeadm/issues/1582 var UnversionedKubeletConfigMap bool if _, ok := m["featureGates"]; ok { <del> if featureGates, ok := m["featureGates"].(map[string]bool); ok { </del> <ins> if featureGates, ok := m["featureGates"].(map[interface{}]interface{}); ok { </ins> // TODO: update the default to true once this graduates to Beta. UnversionedKubeletConfigMap = false if val, ok := featureGates["UnversionedKubeletConfigMap"]; ok { <del> UnversionedKubeletConfigMap = val </del> <ins> if valBool, ok := val.(bool); ok { UnversionedKubeletConfigMap = valBool } else { framework.Failf("unable to cast the value of feature gate UnversionedKubeletConfigMap to bool") } </ins> } } else { framework.Failf("unable to cast the featureGates field in the %s ConfigMap", kubeadmConfigName)


import ( "context" <ins> "encoding/json" </ins> "fmt" "strconv" "time" <ins> kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1" kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" kubeletconfigscheme "k8s.io/kubernetes/pkg/kubelet/apis/config/scheme" </ins> v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/kubernetes/test/e2e/framework" <del> e2ekubelet "k8s.io/kubernetes/test/e2e/framework/kubelet" </del> e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" imageutils "k8s.io/kubernetes/test/utils/image"


framework.ExpectNotEqual(nodeList.Size(), 0) ginkgo.By("Getting memory details from node status and kubelet config") status := nodeList.Items[0].Status nodeName := nodeList.Items[0].ObjectMeta.Name <del> kubeletConfig, err := e2ekubelet.GetCurrentKubeletConfig(nodeName, f.Namespace.Name, true) </del> <ins> framework.Logf("Getting configuration details for node %s", nodeName) request := f.ClientSet.CoreV1().RESTClient().Get().Resource("nodes").Name(nodeName).SubResource("proxy").Suffix("configz") rawbytes, err := request.DoRaw(context.Background()) framework.ExpectNoError(err) kubeletConfig, err := decodeConfigz(rawbytes) </ins> framework.ExpectNoError(err) systemReserve, err := resource.ParseQuantity(kubeletConfig.SystemReserved["memory"])


return totalAllocatable } <ins> // modified from https://github.com/kubernetes/kubernetes/blob/master/test/e2e/framework/kubelet/config.go#L110 // the proxy version was causing and non proxy used a value that isn't set by e2e func decodeConfigz(contentsBytes []byte) (*kubeletconfig.KubeletConfiguration, error) { // This hack because /configz reports the following structure: // {"kubeletconfig": {the JSON representation of kubeletconfigv1beta1.KubeletConfiguration}} type configzWrapper struct { ComponentConfig kubeletconfigv1beta1.KubeletConfiguration `json:"kubeletconfig"` } configz := configzWrapper{} kubeCfg := kubeletconfig.KubeletConfiguration{} err := json.Unmarshal(contentsBytes, &configz) if err != nil { return nil, err } scheme, _, err := kubeletconfigscheme.NewSchemeAndCodecs() if err != nil { return nil, err } err = scheme.Convert(&configz.ComponentConfig, &kubeCfg, nil) if err != nil { return nil, err } return &kubeCfg, nil } </ins>


} patchedJS, retErr = jsonpatch.MergePatch(versionedJS, p.patchBytes) <ins> if retErr == jsonpatch.ErrBadJSONPatch { return nil, nil, errors.NewBadRequest(retErr.Error()) } </ins> return patchedJS, strictErrors, retErr default: // only here as a safety net - go-restful filters content-type


import ( "context" "path/filepath" <ins> "regexp" </ins> "time" <ins> "github.com/onsi/ginkgo" "github.com/onsi/gomega" </ins> appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" <del> e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" </del> <ins> kubeletdevicepluginv1beta1 "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1" </ins> e2etestfiles "k8s.io/kubernetes/test/e2e/framework/testfiles" admissionapi "k8s.io/pod-security-admission/api" <del> "regexp" </del> "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/uuid"


"k8s.io/kubernetes/test/e2e/framework" e2enode "k8s.io/kubernetes/test/e2e/framework/node" e2epod "k8s.io/kubernetes/test/e2e/framework/pod" <del> "github.com/onsi/ginkgo" "github.com/onsi/gomega" </del> ) const (


var _ = SIGDescribe("Device Plugin [Feature:DevicePluginProbe][NodeFeature:DevicePluginProbe][Serial]", func() { f := framework.NewDefaultFramework("device-plugin-errors") f.NamespacePodSecurityEnforceLevel = admissionapi.LevelPrivileged <del> testDevicePlugin(f, "/var/lib/kubelet/plugins_registry") </del> <ins> testDevicePlugin(f, kubeletdevicepluginv1beta1.DevicePluginPath) </ins> }) // numberOfSampleResources returns the number of resources advertised by a node.


var devicePluginPod, dptemplate *v1.Pod ginkgo.BeforeEach(func() { <del> e2eskipper.Skipf("Device Plugin tests are currently broken and being investigated") </del> ginkgo.By("Wait for node to be ready") gomega.Eventually(func() bool { nodes, err := e2enode.TotalReady(f.ClientSet)


dp.Spec.Containers[0].Env[i].Value = pluginSockDir } } <del> dptemplate = dp </del> <ins> dptemplate = dp.DeepCopy() </ins> devicePluginPod = f.PodClient().CreateSync(dp) ginkgo.By("Waiting for devices to become available on the local node") gomega.Eventually(func() bool { <del> return numberOfSampleResources(getLocalNode(f)) > 0 </del> <ins> node, ready := getLocalTestNode(f) return ready && numberOfSampleResources(node) > 0 </ins> }, 5*time.Minute, framework.Poll).Should(gomega.BeTrue()) framework.Logf("Successfully created device plugin pod") ginkgo.By("Waiting for the resource exported by the sample device plugin to become available on the local node") gomega.Eventually(func() bool { <del> node := getLocalNode(f) return numberOfDevicesCapacity(node, resourceName) == devsLen && </del> <ins> node, ready := getLocalTestNode(f) return ready && numberOfDevicesCapacity(node, resourceName) == devsLen && </ins> numberOfDevicesAllocatable(node, resourceName) == devsLen }, 30*time.Second, framework.Poll).Should(gomega.BeTrue()) })


ginkgo.By("Waiting for devices to become unavailable on the local node") gomega.Eventually(func() bool { <del> return numberOfSampleResources(getLocalNode(f)) <= 0 </del> <ins> node, ready := getLocalTestNode(f) return ready && numberOfSampleResources(node) <= 0 </ins> }, 5*time.Minute, framework.Poll).Should(gomega.BeTrue()) <ins> ginkgo.By("devices now unavailable on the local node") </ins> }) ginkgo.It("Can schedule a pod that requires a device", func() {


ginkgo.By("Waiting for resource to become available on the local node after re-registration") gomega.Eventually(func() bool { <del> node := getLocalNode(f) return numberOfDevicesCapacity(node, resourceName) == devsLen && </del> <ins> node, ready := getLocalTestNode(f) return ready && numberOfDevicesCapacity(node, resourceName) == devsLen && </ins> numberOfDevicesAllocatable(node, resourceName) == devsLen }, 30*time.Second, framework.Poll).Should(gomega.BeTrue())


return &nodeList.Items[0] } <ins> // getLocalTestNode fetches the node object describing the local worker node set up by the e2e_node infra, alongside with its ready state. // getLocalTestNode is a variant of `getLocalNode` which reports but does not set any requirement about the node readiness state, letting // the caller decide. The check is intentionally done like `getLocalNode` does. // Note `getLocalNode` aborts (as in ginkgo.Expect) the test implicitly if the worker node is not ready. func getLocalTestNode(f *framework.Framework) (*v1.Node, bool) { node, err := f.ClientSet.CoreV1().Nodes().Get(context.TODO(), framework.TestContext.NodeName, metav1.GetOptions{}) framework.ExpectNoError(err) ready := e2enode.IsNodeReady(node) schedulable := e2enode.IsNodeSchedulable(node) framework.Logf("node %q ready=%v schedulable=%v", node.Name, ready, schedulable) return node, ready && schedulable } </ins> // logKubeletLatencyMetrics logs KubeletLatencyMetrics computed from the Prometheus // metrics exposed on the current node and identified by the metricNames. // The Kubelet subsystem prefix is automatically prepended to these metric names.


"strconv" "time" <ins> apierrors "k8s.io/apimachinery/pkg/api/errors" </ins> "k8s.io/apimachinery/pkg/fields" "github.com/onsi/ginkgo"


ginkgo.Context("when gracefully shutting down with Pod priority", func() { const ( <del> pollInterval           = 1 * time.Second podStatusUpdateTimeout = 10 * time.Second </del> <ins> pollInterval                 = 1 * time.Second podStatusUpdateTimeout       = 10 * time.Second priorityClassesCreateTimeout = 10 * time.Second </ins> ) var (


ginkgo.By("Wait for the node to be ready") waitForNodeReady() <del> for _, customClass := range []*schedulingv1.PriorityClass{customClassA, customClassB, customClassC} { </del> <ins> customClasses := []*schedulingv1.PriorityClass{customClassA, customClassB, customClassC} for _, customClass := range customClasses { </ins> _, err := f.ClientSet.SchedulingV1().PriorityClasses().Create(context.Background(), customClass, metav1.CreateOptions{}) <del> framework.ExpectNoError(err) </del> <ins> if err != nil && !apierrors.IsAlreadyExists(err) { framework.ExpectNoError(err) } </ins> } <ins> gomega.Eventually(func() error { for _, customClass := range customClasses { _, err := f.ClientSet.SchedulingV1().PriorityClasses().Get(context.Background(), customClass.Name, metav1.GetOptions{}) if err != nil { return err } } return nil }, priorityClassesCreateTimeout, pollInterval).Should(gomega.BeNil()) </ins> }) ginkgo.AfterEach(func() {


It("should lookup the Schema by its GroupVersionKind", func() { schema = resources.LookupResource(gvk) Expect(schema).ToNot(BeNil()) <del> }) var deployment *proto.Kind It("should be a Kind", func() { deployment = schema.(*proto.Kind) Expect(deployment).ToNot(BeNil()) </del> <ins> Expect(schema.(*proto.Kind)).ToNot(BeNil()) </ins> }) })


It("should lookup the Schema by its GroupVersionKind", func() { schema = resources.LookupResource(gvk) Expect(schema).ToNot(BeNil()) <del> }) var sarspec *proto.Kind It("should be a Kind and have a spec", func() { </del> sar := schema.(*proto.Kind) Expect(sar).ToNot(BeNil()) Expect(sar.Fields).To(HaveKey("spec")) specRef := sar.Fields["spec"].(proto.Reference) Expect(specRef).ToNot(BeNil()) Expect(specRef.Reference()).To(Equal("io.k8s.api.authorization.v1.SubjectAccessReviewSpec")) <del> sarspec = specRef.SubSchema().(*proto.Kind) Expect(sarspec).ToNot(BeNil()) </del> <ins> Expect(specRef.SubSchema().(*proto.Kind)).ToNot(BeNil()) </ins> }) })


config.DeleteNodePortService() ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (nodeIP) and getting ZERO host endpoints", config.NodeIP, config.NodeIP, config.NodeHTTPPort)) <del> err = config.DialFromNode("http", config.NodeIP, config.NodeHTTPPort, config.MaxTries, config.MaxTries, sets.NewString()) </del> <ins> // #106770 MaxTries can be very large on large clusters, with the risk that a new NodePort is created by another test and start to answer traffic. // Since we only want to assert that traffic is not being forwarded anymore and the retry timeout is 2 seconds, consider the test is correct // if the service doesn't answer after 10 tries. err = config.DialFromNode("http", config.NodeIP, config.NodeHTTPPort, 10, 10, sets.NewString()) </ins> if err != nil { <del> framework.Failf("Error dialing http from node: %v", err) </del> <ins> framework.Failf("Failure validating that node port service STOPPED removed properly: %v", err) </ins> } })


config.DeleteNodePortService() ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (nodeIP) and getting ZERO host endpoints", config.NodeIP, config.NodeIP, config.NodeUDPPort)) <del> err = config.DialFromNode("udp", config.NodeIP, config.NodeUDPPort, config.MaxTries, config.MaxTries, sets.NewString()) </del> <ins> // #106770 MaxTries can be very large on large clusters, with the risk that a new NodePort is created by another test and start to answer traffic. // Since we only want to assert that traffic is not being forwarded anymore and the retry timeout is 2 seconds, consider the test is correct // if the service doesn't answer after 10 tries. err = config.DialFromNode("udp", config.NodeIP, config.NodeUDPPort, 10, 10, sets.NewString()) </ins> if err != nil { framework.Failf("Failure validating that node port service STOPPED removed properly: %v", err) }


if svcInfo.preserveDIP || svcInfo.localTrafficDSR { nodePortEndpoints = hnsLocalEndpoints } <del> hnsLoadBalancer, err := hns.getLoadBalancer( nodePortEndpoints, loadBalancerFlags{isDSR: svcInfo.localTrafficDSR, localRoutedVIP: true, sessionAffinity: sessionAffinityClientIP, isIPv6: proxier.isIPv6Mode}, sourceVip, "", Enum(svcInfo.Protocol()), uint16(svcInfo.targetPort), uint16(svcInfo.NodePort()), ) if err != nil { klog.ErrorS(err, "Policy creation failed") continue } svcInfo.nodePorthnsID = hnsLoadBalancer.hnsID klog.V(3).InfoS("Hns LoadBalancer resource created for nodePort resources", "clusterIP", svcInfo.ClusterIP(), "hnsID", hnsLoadBalancer.hnsID) </del> <ins> if len(nodePortEndpoints) > 0 { hnsLoadBalancer, err := hns.getLoadBalancer( nodePortEndpoints, loadBalancerFlags{isDSR: svcInfo.localTrafficDSR, localRoutedVIP: true, sessionAffinity: sessionAffinityClientIP, isIPv6: proxier.isIPv6Mode}, sourceVip, "", Enum(svcInfo.Protocol()), uint16(svcInfo.targetPort), uint16(svcInfo.NodePort()), ) if err != nil { klog.ErrorS(err, "Policy creation failed") continue } svcInfo.nodePorthnsID = hnsLoadBalancer.hnsID klog.V(3).InfoS("Hns LoadBalancer resource created for nodePort resources", "clusterIP", svcInfo.ClusterIP(), "nodeport", svcInfo.NodePort(), "hnsID", hnsLoadBalancer.hnsID) } else { klog.V(3).InfoS("Skipped creating Hns LoadBalancer for nodePort resources", "clusterIP", svcInfo.ClusterIP(), "nodeport", svcInfo.NodePort(), "hnsID", hnsLoadBalancer.hnsID) } </ins> } // Create a Load Balancer Policy for each external IP


if svcInfo.localTrafficDSR { externalIPEndpoints = hnsLocalEndpoints } <del> // Try loading existing policies, if already available hnsLoadBalancer, err = hns.getLoadBalancer( externalIPEndpoints, loadBalancerFlags{isDSR: svcInfo.localTrafficDSR, sessionAffinity: sessionAffinityClientIP, isIPv6: proxier.isIPv6Mode}, sourceVip, externalIP.ip, Enum(svcInfo.Protocol()), uint16(svcInfo.targetPort), uint16(svcInfo.Port()), ) if err != nil { klog.ErrorS(err, "Policy creation failed") continue </del> <ins> if len(externalIPEndpoints) > 0 { // Try loading existing policies, if already available hnsLoadBalancer, err = hns.getLoadBalancer( externalIPEndpoints, loadBalancerFlags{isDSR: svcInfo.localTrafficDSR, sessionAffinity: sessionAffinityClientIP, isIPv6: proxier.isIPv6Mode}, sourceVip, externalIP.ip, Enum(svcInfo.Protocol()), uint16(svcInfo.targetPort), uint16(svcInfo.Port()), ) if err != nil { klog.ErrorS(err, "Policy creation failed") continue } externalIP.hnsID = hnsLoadBalancer.hnsID klog.V(3).InfoS("Hns LoadBalancer resource created for externalIP resources", "externalIP", externalIP, "hnsID", hnsLoadBalancer.hnsID) } else { klog.V(3).InfoS("Skipped creating Hns LoadBalancer for externalIP resources", "externalIP", externalIP, "hnsID", hnsLoadBalancer.hnsID) </ins> } <del> externalIP.hnsID = hnsLoadBalancer.hnsID klog.V(3).InfoS("Hns LoadBalancer resource created for externalIP resources", "externalIP", externalIP, "hnsID", hnsLoadBalancer.hnsID) </del> } // Create a Load Balancer Policy for each loadbalancer ingress for _, lbIngressIP := range svcInfo.loadBalancerIngressIPs {


if svcInfo.preserveDIP || svcInfo.localTrafficDSR { lbIngressEndpoints = hnsLocalEndpoints } <del> hnsLoadBalancer, err := hns.getLoadBalancer( lbIngressEndpoints, loadBalancerFlags{isDSR: svcInfo.preserveDIP || svcInfo.localTrafficDSR, useMUX: svcInfo.preserveDIP, preserveDIP: svcInfo.preserveDIP, sessionAffinity: sessionAffinityClientIP, isIPv6: proxier.isIPv6Mode}, sourceVip, lbIngressIP.ip, Enum(svcInfo.Protocol()), uint16(svcInfo.targetPort), uint16(svcInfo.Port()), ) if err != nil { klog.ErrorS(err, "Policy creation failed") continue </del> <ins> if len(lbIngressEndpoints) > 0 { hnsLoadBalancer, err := hns.getLoadBalancer( lbIngressEndpoints, loadBalancerFlags{isDSR: svcInfo.preserveDIP || svcInfo.localTrafficDSR, useMUX: svcInfo.preserveDIP, preserveDIP: svcInfo.preserveDIP, sessionAffinity: sessionAffinityClientIP, isIPv6: proxier.isIPv6Mode}, sourceVip, lbIngressIP.ip, Enum(svcInfo.Protocol()), uint16(svcInfo.targetPort), uint16(svcInfo.Port()), ) if err != nil { klog.ErrorS(err, "Policy creation failed") continue } lbIngressIP.hnsID = hnsLoadBalancer.hnsID klog.V(3).InfoS("Hns LoadBalancer resource created for loadBalancer Ingress resources", "lbIngressIP", lbIngressIP) } else { klog.V(3).InfoS("Skipped creating Hns LoadBalancer for loadBalancer Ingress resources", "lbIngressIP", lbIngressIP) </ins> } <del> lbIngressIP.hnsID = hnsLoadBalancer.hnsID klog.V(3).InfoS("Hns LoadBalancer resource created for loadBalancer Ingress resources", "lbIngressIP", lbIngressIP) </del> } svcInfo.policyApplied = true klog.V(2).InfoS("Policy successfully applied for service", "serviceInfo", svcInfo)


"description": "EndpointPort is a tuple that describes a single port.", "properties": { "appProtocol": { <del> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </del> <ins> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </ins> "type": "string" }, "name": {


"description": "ServicePort contains information on service's port.", "properties": { "appProtocol": { <del> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </del> <ins> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </ins> "type": "string" }, "name": {


"name":        "The name of this port.  This must match the 'name' field in the corresponding ServicePort. Must be a DNS_LABEL. Optional only if one port is defined.", "port":        "The port number of the endpoint.", "protocol":    "The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP.", <del> "appProtocol": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </del> <ins> "appProtocol": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </ins> } func (EndpointPort) SwaggerDoc() map[string]string {


"":            "ServicePort contains information on service's port.", "name":        "The name of this port within the service. This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. When considering the endpoints for a Service, this must match the 'name' field in the EndpointPort. Optional if only one ServicePort is defined on this service.", "protocol":    "The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". Default is TCP.", <del> "appProtocol": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </del> <ins> "appProtocol": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </ins> "port":        "The port that will be exposed by this service.", "targetPort":  "Number or name of the port to access on the pods targeted by the service. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If this is a string, it will be looked up as a named port in the target Pod's container ports. If this is not specified, the value of the 'port' field is used (an identity map). This field is ignored for services with clusterIP=None, and should be omitted or set equal to the 'port' field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service", "nodePort":    "The port on each node on which this service is exposed when type is NodePort or LoadBalancer.  Usually assigned by the system. If a value is specified, in-range, and not in use it will be used, otherwise the operation will fail.  If not specified, a port will be allocated if this Service requires one.  If this field is specified when creating a Service which does not need it, creation will fail. This field will be wiped when updating a Service to no longer need it (e.g. changing type from NodePort to ClusterIP). More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport",


// The application protocol for this port. // This field follows standard Kubernetes label syntax. // Un-prefixed names are reserved for IANA standard service names (as per <del> // RFC-6335 and http://www.iana.org/assignments/service-names). </del> <ins> // RFC-6335 and https://www.iana.org/assignments/service-names). </ins> // Non-standard protocols should use prefixed names such as // mycompany.com/my-custom-protocol. // +optional


"name":        "The name of this port. All ports in an EndpointSlice must have a unique name. If the EndpointSlice is dervied from a Kubernetes service, this corresponds to the Service.ports[].name. Name must either be an empty string or pass DNS_LABEL validation: * must be no more than 63 characters long. * must consist of lower case alphanumeric characters or '-'. * must start and end with an alphanumeric character. Default is empty string.", "protocol":    "The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP.", "port":        "The port number of the endpoint. If this is not specified, ports are not restricted and must be interpreted in the context of the specific consumer.", <del> "appProtocol": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </del> <ins> "appProtocol": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </ins> } func (EndpointPort) SwaggerDoc() map[string]string {


"description": "EndpointPort is a tuple that describes a single port.", "properties": { "appProtocol": { <del> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. This is a beta field that is guarded by the ServiceAppProtocol feature gate and enabled by default.", </del> <ins> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. This is a beta field that is guarded by the ServiceAppProtocol feature gate and enabled by default.", </ins> "type": "string" }, "name": {


"description": "ServicePort contains information on service's port.", "properties": { "appProtocol": { <del> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. This is a beta field that is guarded by the ServiceAppProtocol feature gate and enabled by default.", </del> <ins> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol. This is a beta field that is guarded by the ServiceAppProtocol feature gate and enabled by default.", </ins> "type": "string" }, "name": {


"description": "EndpointPort represents a Port used by an EndpointSlice", "properties": { "appProtocol": { <del> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and http://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </del> <ins> "description": "The application protocol for this port. This field follows standard Kubernetes label syntax. Un-prefixed names are reserved for IANA standard service names (as per RFC-6335 and https://www.iana.org/assignments/service-names). Non-standard protocols should use prefixed names such as mycompany.com/my-custom-protocol.", </ins> "type": "string" }, "name": {


package pidlimit import ( <ins> "fmt" </ins> "io/ioutil" "strconv" <ins> "strings" </ins> "syscall" "time" <del> "k8s.io/apimachinery/pkg/apis/meta/v1" </del> <ins> v1 "k8s.io/apimachinery/pkg/apis/meta/v1" </ins> statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" )


} } <del> var info syscall.Sysinfo_t syscall.Sysinfo(&info) procs := int64(info.Procs) rlimit.NumOfRunningProcesses = &procs </del> <ins> // Prefer to read "/proc/loadavg" when possible because sysinfo(2) // returns truncated number when greater than 65538. See // https://github.com/kubernetes/kubernetes/issues/107107 if procs, err := runningTaskCount(); err == nil { rlimit.NumOfRunningProcesses = &procs } else { var info syscall.Sysinfo_t syscall.Sysinfo(&info) procs := int64(info.Procs) rlimit.NumOfRunningProcesses = &procs } </ins> rlimit.Time = v1.NewTime(time.Now()) return rlimit, nil } <ins> func runningTaskCount() (int64, error) { // Example: 1.36 3.49 4.53 2/3518 3715089 bytes, err := ioutil.ReadFile("/proc/loadavg") if err != nil { return 0, err } fields := strings.Fields(string(bytes)) if len(fields) < 5 { return 0, fmt.Errorf("not enough fields in /proc/loadavg") } subfields := strings.Split(fields[3], "/") if len(subfields) != 2 { return 0, fmt.Errorf("error parsing fourth field of /proc/loadavg") } return strconv.ParseInt(subfields[1], 10, 64) } </ins>


pluginName := fmt.Sprintf("example-plugin") p := pluginwatcher.NewTestExamplePlugin(pluginName, registerapi.DevicePlugin, socketPath, supportedVersions...) require.NoError(t, p.Serve("v1beta1", "v1beta2")) <ins> defer func() { require.NoError(t, p.Stop()) }() </ins> timestampBeforeRegistration := time.Now() dsw.AddOrUpdatePlugin(socketPath) waitForRegistration(t, socketPath, timestampBeforeRegistration, asw)


// validation with resource counting, but we did this before QoS was even defined. // let's not make that mistake again with other resources now that QoS is defined. requiredSet := quota.ToSet(required).Intersection(validationSet) <del> missingSet := sets.NewString() </del> <ins> missingSetResourceToContainerNames := make(map[string]sets.String) </ins> for i := range pod.Spec.Containers { <del> enforcePodContainerConstraints(&pod.Spec.Containers[i], requiredSet, missingSet) </del> <ins> enforcePodContainerConstraints(&pod.Spec.Containers[i], requiredSet, missingSetResourceToContainerNames) </ins> } for i := range pod.Spec.InitContainers { <del> enforcePodContainerConstraints(&pod.Spec.InitContainers[i], requiredSet, missingSet) </del> <ins> enforcePodContainerConstraints(&pod.Spec.InitContainers[i], requiredSet, missingSetResourceToContainerNames) </ins> } <del> if len(missingSet) == 0 { </del> <ins> if len(missingSetResourceToContainerNames) == 0 { </ins> return nil } <del> return fmt.Errorf("must specify %s", strings.Join(missingSet.List(), ",")) </del> <ins> var resources = sets.NewString() for resource := range missingSetResourceToContainerNames { resources.Insert(resource) } var errorMessages = make([]string, 0, len(missingSetResourceToContainerNames)) for _, resource := range resources.List() { errorMessages = append(errorMessages, fmt.Sprintf("%s for: %s", resource, strings.Join(missingSetResourceToContainerNames[resource].List(), ","))) } return fmt.Errorf("must specify %s", strings.Join(errorMessages, "; ")) </ins> } // GroupResource that this evaluator tracks


// enforcePodContainerConstraints checks for required resources that are not set on this container and // adds them to missingSet. <del> func enforcePodContainerConstraints(container *corev1.Container, requiredSet, missingSet sets.String) { </del> <ins> func enforcePodContainerConstraints(container *corev1.Container, requiredSet sets.String, missingSetResourceToContainerNames map[string]sets.String) { </ins> requests := container.Resources.Requests limits := container.Resources.Limits containerUsage := podComputeUsageHelper(requests, limits) containerSet := quota.ToSet(quota.ResourceNames(containerUsage)) if !containerSet.Equal(requiredSet) { <del> difference := requiredSet.Difference(containerSet) missingSet.Insert(difference.List()...) </del> <ins> if difference := requiredSet.Difference(containerSet); difference.Len() != 0 { for _, diff := range difference.List() { if _, ok := missingSetResourceToContainerNames[diff]; !ok { missingSetResourceToContainerNames[diff] = sets.NewString(container.Name) } else { missingSetResourceToContainerNames[diff].Insert(container.Name) } } } </ins> } }


"time" "github.com/google/go-cmp/cmp" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"


pod: &api.Pod{ Spec: api.PodSpec{ InitContainers: []api.Container{{ <ins> Name: "dummy", Resources: api.ResourceRequirements{ Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("1m")}, Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("2m")}, }, }}, }, }, required: []corev1.ResourceName{corev1.ResourceMemory}, err:      `must specify memory for: dummy`, }, "multiple init container resource missing": { pod: &api.Pod{ Spec: api.PodSpec{ InitContainers: []api.Container{{ Name: "foo", Resources: api.ResourceRequirements{ Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("1m")}, Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("2m")}, }, }, { Name: "bar", </ins> Resources: api.ResourceRequirements{ Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("1m")}, Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("2m")},


}, }, required: []corev1.ResourceName{corev1.ResourceMemory}, <del> err:      `must specify memory`, </del> <ins> err:      `must specify memory for: bar,foo`, </ins> }, "container resource missing": { pod: &api.Pod{ Spec: api.PodSpec{ Containers: []api.Container{{ <ins> Name: "dummy", Resources: api.ResourceRequirements{ Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("1m")}, Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("2m")}, }, }}, }, }, required: []corev1.ResourceName{corev1.ResourceMemory}, err:      `must specify memory for: dummy`, }, "multiple container resource missing": { pod: &api.Pod{ Spec: api.PodSpec{ Containers: []api.Container{{ Name: "foo", Resources: api.ResourceRequirements{ Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("1m")}, Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("2m")}, }, }, { Name: "bar", </ins> Resources: api.ResourceRequirements{ Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("1m")}, Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("2m")},


}, }, required: []corev1.ResourceName{corev1.ResourceMemory}, <del> err:      `must specify memory`, </del> <ins> err:      `must specify memory for: bar,foo`, }, "container resource missing multiple": { pod: &api.Pod{ Spec: api.PodSpec{ Containers: []api.Container{{ Name:      "foo", Resources: api.ResourceRequirements{}, }, { Name:      "bar", Resources: api.ResourceRequirements{}, }}, }, }, required: []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceCPU}, err:      `must specify cpu for: bar,foo; memory for: bar,foo`, </ins> }, } evaluator := NewPodEvaluator(nil, clock.RealClock{})


case err != nil && len(test.err) == 0, err == nil && len(test.err) != 0, err != nil && test.err != err.Error(): <del> t.Errorf("%s unexpected error: %v", testName, err) </del> <ins> t.Errorf("%s want: %v,got: %v", testName, test.err, err) </ins> } } }


id, err := getDiskID(pdName, exec) if err != nil { klog.Errorf("WaitForAttach (windows) failed with error %s", err) <ins> return "", err </ins> } <del> return id, err </del> <ins> return id, nil </ins> } partition := ""


clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" v1 "k8s.io/client-go/tools/clientcmd/api/v1" <ins> resttransport "k8s.io/client-go/transport" </ins> kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing" "k8s.io/kubernetes/pkg/apis/autoscaling" api "k8s.io/kubernetes/pkg/apis/core"


controlPlaneConfig.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysDenyAuthorizer() _, s, closeFn := framework.RunAnAPIServer(controlPlaneConfig) defer closeFn() ns := framework.CreateTestingNamespace("auth-always-deny", s, t) defer framework.DeleteTestingNamespace(ns, s, t) <del> transport := http.DefaultTransport </del> <ins> transport := resttransport.NewBearerAuthRoundTripper(framework.UnprivilegedUserToken, http.DefaultTransport) </ins> for _, r := range getTestRequests(ns.Name) { bodyBytes := bytes.NewReader([]byte(r.body))


apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" <ins> authauthenticator "k8s.io/apiserver/pkg/authentication/authenticator" </ins> "k8s.io/apiserver/pkg/authentication/group" "k8s.io/apiserver/pkg/authentication/request/bearertoken" <ins> authenticatorunion "k8s.io/apiserver/pkg/authentication/request/union" </ins> "k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizerfactory"


func initStatusForbiddenControlPlaneConfig() *controlplane.Config { controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig() <ins> controlPlaneConfig.GenericConfig.Authentication.Authenticator = authenticatorunion.New( authauthenticator.RequestFunc(func(req *http.Request) (*authauthenticator.Response, bool, error) { return &authauthenticator.Response{ User: &user.DefaultInfo{ Name:   "unprivileged", Groups: []string{user.AllAuthenticated}, }, }, true, nil })) </ins> controlPlaneConfig.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysDenyAuthorizer() return controlPlaneConfig }


statusCode:         http.StatusForbidden, reqPath:            "/apis", reason:             "Forbidden", <del> message:            `forbidden: User "" cannot get path "/apis": Everything is forbidden.`, </del> <ins> message:            `forbidden: User "unprivileged" cannot get path "/apis": Everything is forbidden.`, </ins> }, { name:               "401",


netutils "k8s.io/utils/net" ) <ins> const ( UnprivilegedUserToken = "unprivileged-user" ) </ins> // Config is a struct of configuration directives for NewControlPlaneComponents. type Config struct { // If nil, a default is used, partially filled configs will not get populated.


return authorizer.DecisionAllow, "always allow", nil } <del> // alwaysEmpty simulates "no authentication" for old tests func alwaysEmpty(req *http.Request) (*authauthenticator.Response, bool, error) { </del> <ins> // unsecuredUser simulates requests to the unsecured endpoint for old tests func unsecuredUser(req *http.Request) (*authauthenticator.Response, bool, error) { auth := req.Header.Get("Authorization") if len(auth) != 0 { return nil, false, nil } </ins> return &authauthenticator.Response{ User: &user.DefaultInfo{ <del> Name: "", </del> <ins> Name:   "system:unsecured", Groups: []string{user.SystemPrivilegedGroup, user.AllAuthenticated}, </ins> }, }, true, nil }


tokens[privilegedLoopbackToken] = &user.DefaultInfo{ Name:   user.APIServerUser, UID:    uuid.New().String(), <del> Groups: []string{user.SystemPrivilegedGroup}, </del> <ins> Groups: []string{user.SystemPrivilegedGroup, user.AllAuthenticated}, } tokens[UnprivilegedUserToken] = &user.DefaultInfo{ Name:   "unprivileged", UID:    uuid.New().String(), Groups: []string{user.AllAuthenticated}, </ins> } tokenAuthenticator := authenticatorfactory.NewFromTokens(tokens, controlPlaneConfig.GenericConfig.Authentication.APIAudiences) if controlPlaneConfig.GenericConfig.Authentication.Authenticator == nil { <del> controlPlaneConfig.GenericConfig.Authentication.Authenticator = authenticatorunion.New(tokenAuthenticator, authauthenticator.RequestFunc(alwaysEmpty)) </del> <ins> controlPlaneConfig.GenericConfig.Authentication.Authenticator = authenticatorunion.New(tokenAuthenticator, authauthenticator.RequestFunc(unsecuredUser)) </ins> } else { controlPlaneConfig.GenericConfig.Authentication.Authenticator = authenticatorunion.New(tokenAuthenticator, controlPlaneConfig.GenericConfig.Authentication.Authenticator) }


VolumeAttributes: attributes, }, } <ins> if pattern.FsType != "" { r.VolSource.CSI.FSType = &pattern.FsType } </ins> } default: framework.Failf("VolumeResource doesn't support: %s", pattern.VolType)


"context" "crypto/sha256" "encoding/binary" <del> "encoding/json" </del> "errors" "fmt" "math"


apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" <del> apitypes "k8s.io/apimachinery/pkg/types" </del> utilerrors "k8s.io/apimachinery/pkg/util/errors" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets"


"k8s.io/utils/clock" flowcontrol "k8s.io/api/flowcontrol/v1beta3" <ins> flowcontrolapplyconfiguration "k8s.io/client-go/applyconfigurations/flowcontrol/v1beta3" </ins> flowcontrolclient "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3" flowcontrollister "k8s.io/client-go/listers/flowcontrol/v1beta3" )


// if we are going to issue an update, be sure we track every name we update so we know if we update it too often. currResult.updatedItems.Insert(fsu.flowSchema.Name) <del> patchBytes, err := makeFlowSchemaConditionPatch(fsu.condition) if err != nil { // should never happen because these conditions are created here and well formed panic(fmt.Sprintf("Failed to json.Marshall(%#+v): %s", fsu.condition, err.Error())) } </del> if klogV := klog.V(4); klogV.Enabled() { klogV.Infof("%s writing Condition %s to FlowSchema %s, which had ResourceVersion=%s, because its previous value was %s, diff: %s", cfgCtlr.name, fsu.condition, fsu.flowSchema.Name, fsu.flowSchema.ResourceVersion, fcfmt.Fmt(fsu.oldValue), cmp.Diff(fsu.oldValue, fsu.condition)) } <del> fsIfc := cfgCtlr.flowcontrolClient.FlowSchemas() patchOptions := metav1.PatchOptions{FieldManager: cfgCtlr.asFieldManager} _, err = fsIfc.Patch(context.TODO(), fsu.flowSchema.Name, apitypes.StrategicMergePatchType, patchBytes, patchOptions, "status") if err != nil { </del> <ins> if err := apply(cfgCtlr.flowcontrolClient.FlowSchemas(), fsu, cfgCtlr.asFieldManager); err != nil { </ins> if apierrors.IsNotFound(err) { // This object has been deleted.  A notification is coming // and nothing more needs to be done here.


return suggestedDelay, utilerrors.NewAggregate(errs) } <del> // makeFlowSchemaConditionPatch takes in a condition and returns the patch status as a json. func makeFlowSchemaConditionPatch(condition flowcontrol.FlowSchemaCondition) ([]byte, error) { o := struct { Status flowcontrol.FlowSchemaStatus `json:"status"` }{ Status: flowcontrol.FlowSchemaStatus{ Conditions: []flowcontrol.FlowSchemaCondition{ condition, }, }, } return json.Marshal(o) </del> <ins> func apply(client flowcontrolclient.FlowSchemaInterface, fsu fsStatusUpdate, asFieldManager string) error { applyOptions := metav1.ApplyOptions{FieldManager: asFieldManager, Force: true} // the condition field in fsStatusUpdate holds the new condition we want to update. // TODO: this will break when we have multiple conditions for a flowschema _, err := client.ApplyStatus(context.TODO(), toFlowSchemaApplyConfiguration(fsu), applyOptions) return err } func toFlowSchemaApplyConfiguration(fsUpdate fsStatusUpdate) *flowcontrolapplyconfiguration.FlowSchemaApplyConfiguration { condition := flowcontrolapplyconfiguration.FlowSchemaCondition(). WithType(fsUpdate.condition.Type). WithStatus(fsUpdate.condition.Status). WithReason(fsUpdate.condition.Reason). WithLastTransitionTime(fsUpdate.condition.LastTransitionTime). WithMessage(fsUpdate.condition.Message) return flowcontrolapplyconfiguration.FlowSchema(fsUpdate.flowSchema.Name). WithStatus(flowcontrolapplyconfiguration.FlowSchemaStatus(). WithConditions(condition), ) </ins> } // shouldDelayUpdate checks to see if a flowschema has been updated too often and returns true if a delay is needed.


<del> /* Copyright 2021 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package flowcontrol import ( "fmt" "reflect" "testing" "time" "github.com/google/go-cmp/cmp" flowcontrol "k8s.io/api/flowcontrol/v1beta3" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func Test_configController_generatePatchBytes(t *testing.T) { now := time.Now().UTC() tests := []struct { name      string condition flowcontrol.FlowSchemaCondition want      []byte }{ { name: "check if only condition is parsed", condition: flowcontrol.FlowSchemaCondition{ Type:               flowcontrol.FlowSchemaConditionDangling, Status:             flowcontrol.ConditionTrue, Reason:             "test reason", Message:            "test none", LastTransitionTime: metav1.NewTime(now), }, want: []byte(fmt.Sprintf(`{"status":{"conditions":[{"type":"Dangling","status":"True","lastTransitionTime":"%s","reason":"test reason","message":"test none"}]}}`, now.Format(time.RFC3339))), }, { name: "check when message has double quotes", condition: flowcontrol.FlowSchemaCondition{ Type:               flowcontrol.FlowSchemaConditionDangling, Status:             flowcontrol.ConditionTrue, Reason:             "test reason", Message:            `test ""none`, LastTransitionTime: metav1.NewTime(now), }, want: []byte(fmt.Sprintf(`{"status":{"conditions":[{"type":"Dangling","status":"True","lastTransitionTime":"%s","reason":"test reason","message":"test ""none"}]}}`, now.Format(time.RFC3339))), }, { name: "check when message has a whitespace character that can be escaped", condition: flowcontrol.FlowSchemaCondition{ Type:               flowcontrol.FlowSchemaConditionDangling, Status:             flowcontrol.ConditionTrue, Reason:             "test reason", Message:            "test u0009u0009none", LastTransitionTime: metav1.NewTime(now), }, want: []byte(fmt.Sprintf(`{"status":{"conditions":[{"type":"Dangling","status":"True","lastTransitionTime":"%s","reason":"test reason","message":"test ttnone"}]}}`, now.Format(time.RFC3339))), }, { name: "check when a few fields (message & lastTransitionTime) are missing", condition: flowcontrol.FlowSchemaCondition{ Type:   flowcontrol.FlowSchemaConditionDangling, Status: flowcontrol.ConditionTrue, Reason: "test reason", }, want: []byte(`{"status":{"conditions":[{"type":"Dangling","status":"True","lastTransitionTime":null,"reason":"test reason"}]}}`), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, _ := makeFlowSchemaConditionPatch(tt.condition) if !reflect.DeepEqual(got, tt.want) { t.Errorf("makeFlowSchemaConditionPatch() got = %s, want %s; diff is %s", got, tt.want, cmp.Diff(tt.want, got)) } }) } } </del>


}() }() <del> postTimeoutFn() </del> <ins> defer postTimeoutFn() </ins> tw.timeout(err) } }


}) } <ins> postTimeoutCh := make(chan struct{}) </ins> ts := httptest.NewServer( withDeadline( WithTimeout(


h := w.Header() // trigger the timeout cancel() <del> // mutate response Headers for j := 0; j < 1000; j++ { h.Set("Test", "post") </del> <ins> // keep mutating response Headers until the request times out for { select { case <-postTimeoutCh: return default: h.Set("Test", "post") } </ins> } }), func(req *http.Request) (*http.Request, bool, func(), *apierrors.StatusError) { <del> return req, false, func() {}, apierrors.NewServerTimeout(schema.GroupResource{Group: "foo", Resource: "bar"}, "get", 0) </del> <ins> return req, false, func() { close(postTimeoutCh) }, apierrors.NewServerTimeout(schema.GroupResource{Group: "foo", Resource: "bar"}, "get", 0) </ins> }, ), ),


FailureThreshold:    1, } pod := livenessPodSpec(f.Namespace.Name, nil, livenessProbe) <del> RunLivenessTest(f, pod, 5, time.Minute*5) </del> <ins> // ~2 minutes backoff timeouts + 4 minutes defaultObservationTimeout + 2 minutes for each pod restart RunLivenessTest(f, pod, 5, 2*time.Minute+defaultObservationTimeout+4*2*time.Minute) </ins> }) /*


framework.PodNominator parallelizer parallelize.Parallelizer <del> // Indicates that RunFilterPlugins should accumulate all failed statuses and not return // after the first failure. runAllFilters bool </del> } // extensionPoint encapsulates desired and applied set of plugins at a specific extension


metricsRecorder        *metricsRecorder podNominator           framework.PodNominator extenders              []framework.Extender <del> runAllFilters          bool </del> captureProfile         CaptureProfile clusterEventMap        map[framework.ClusterEvent]sets.String parallelizer           parallelize.Parallelizer


} } <del> // WithRunAllFilters sets the runAllFilters flag, which means RunFilterPlugins accumulates // all failure Statuses. func WithRunAllFilters(runAllFilters bool) Option { return func(o *frameworkOptions) { o.runAllFilters = runAllFilters } } </del> // WithPodNominator sets podNominator for the scheduling frameworkImpl. func WithPodNominator(nominator framework.PodNominator) Option { return func(o *frameworkOptions) {


eventRecorder:        options.eventRecorder, informerFactory:      options.informerFactory, metricsRecorder:      options.metricsRecorder, <del> runAllFilters:        options.runAllFilters, </del> extenders:            options.extenders, PodNominator:         options.podNominator, parallelizer:         options.parallelizer,


} pluginStatus.SetFailedPlugin(pl.Name()) statuses[pl.Name()] = pluginStatus <del> if !f.runAllFilters { // Exit early if we don't need to run all filters. return statuses } </del> } }


plugins       []*TestPlugin wantStatus    *framework.Status wantStatusMap framework.PluginToStatus <del> runAllFilters bool </del> }{ { name: "SuccessFilter",


"TestPlugin2": framework.NewStatus(framework.Unschedulable, "injected filter status").WithFailedPlugin("TestPlugin2"), }, }, <del> { name: "SuccessFilterWithRunAllFilters", plugins: []*TestPlugin{ { name: "TestPlugin", inj:  injectedResult{FilterStatus: int(framework.Success)}, }, }, runAllFilters: true, wantStatus:    nil, wantStatusMap: framework.PluginToStatus{}, }, { name: "ErrorAndErrorFilters", plugins: []*TestPlugin{ { name: "TestPlugin1", inj:  injectedResult{FilterStatus: int(framework.Error)}, }, { name: "TestPlugin2", inj:  injectedResult{FilterStatus: int(framework.Error)}, }, }, runAllFilters: true, wantStatus:    framework.AsStatus(fmt.Errorf(`running "TestPlugin1" filter plugin: %w`, errInjectedFilterStatus)).WithFailedPlugin("TestPlugin1"), wantStatusMap: framework.PluginToStatus{ "TestPlugin1": framework.AsStatus(fmt.Errorf(`running "TestPlugin1" filter plugin: %w`, errInjectedFilterStatus)).WithFailedPlugin("TestPlugin1"), }, }, { name: "ErrorAndErrorFilters", plugins: []*TestPlugin{ { name: "TestPlugin1", inj:  injectedResult{FilterStatus: int(framework.UnschedulableAndUnresolvable)}, }, { name: "TestPlugin2", inj:  injectedResult{FilterStatus: int(framework.Unschedulable)}, }, }, runAllFilters: true, wantStatus:    framework.NewStatus(framework.UnschedulableAndUnresolvable, "injected filter status", "injected filter status").WithFailedPlugin("TestPlugin1"), wantStatusMap: framework.PluginToStatus{ "TestPlugin1": framework.NewStatus(framework.UnschedulableAndUnresolvable, "injected filter status").WithFailedPlugin("TestPlugin1"), "TestPlugin2": framework.NewStatus(framework.Unschedulable, "injected filter status").WithFailedPlugin("TestPlugin2"), }, }, </del> } for _, tt := range tests {


config.Plugin{Name: pl.name}) } profile := config.KubeSchedulerProfile{Plugins: cfgPls} <del> f, err := newFrameworkWithQueueSortAndBind(registry, profile, WithRunAllFilters(tt.runAllFilters)) </del> <ins> f, err := newFrameworkWithQueueSortAndBind(registry, profile) </ins> if err != nil { t.Fatalf("fail to create framework: %s", err) }


- endpoint: replaceNetworkingV1NamespacedNetworkPolicyStatus reason: endpoints is currently feature gated and and will only receive e2e & conformance test in 1.25 link: https://github.com/kubernetes/kubernetes/pull/107963 <ins> - endpoint: readCoreV1NodeStatus reason: Kubernetes distribution would reasonably not allow this action via the API link: https://github.com/kubernetes/kubernetes/issues/109379 - endpoint: replaceCoreV1NodeStatus reason: Kubernetes distribution would reasonably not allow this action via the API link: https://github.com/kubernetes/kubernetes/issues/109379 - endpoint: deleteCoreV1CollectionNode reason: Kubernetes distribution would reasonably not allow this action via the API link: https://github.com/kubernetes/kubernetes/issues/109379 </ins>


OPENSTACK_IMAGE_NAME=${OPENSTACK_IMAGE_NAME:-CentOS7} # Downloaded image name for Openstack project <del> IMAGE_FILE=${IMAGE_FILE:-CentOS-7-x86_64-GenericCloud-1510.qcow2} </del> <ins> IMAGE_FILE=${IMAGE_FILE:-CentOS-7-x86_64-GenericCloud-1604.qcow2} </ins> # Absolute path where image file is stored. IMAGE_PATH=${IMAGE_PATH:-~/Downloads/openstack}


# Verify prereqs on host machine function verify-prereqs() { # Check the OpenStack command-line clients <del> for client in swift glance nova openstack; </del> <ins> for client in swift glance nova heat openstack; </ins> do if which $client >/dev/null 2>&1; then echo "${client} client installed"


# etcd - name: "etcd" <del> version: 3.5.3 </del> <ins> version: 3.5.4 </ins> refPaths: - path: cluster/gce/manifests/etcd.manifest match: etcd_docker_tag|etcd_version


{ "name": "etcd-container", {{security_context}} <del> "image": "{{ pillar.get('etcd_docker_repository', 'registry.k8s.io/etcd') }}:{{ pillar.get('etcd_docker_tag', '3.5.3-0') }}", </del> <ins> "image": "{{ pillar.get('etcd_docker_repository', 'registry.k8s.io/etcd') }}:{{ pillar.get('etcd_docker_tag', '3.5.4-0') }}", </ins> "resources": { "requests": { "cpu": {{ cpulimit }}


"value": "{{ pillar.get('storage_backend', 'etcd3') }}" }, { "name": "TARGET_VERSION", <del> "value": "{{ pillar.get('etcd_version', '3.5.3') }}" </del> <ins> "value": "{{ pillar.get('etcd_version', '3.5.4') }}" </ins> }, { "name": "DO_NOT_MOVE_BINARIES",


export SECONDARY_RANGE_NAME="pods-default" export STORAGE_BACKEND="etcd3" export STORAGE_MEDIA_TYPE="application/vnd.kubernetes.protobuf" <del> export ETCD_IMAGE=3.5.3-0 export ETCD_VERSION=3.5.3 </del> <ins> export ETCD_IMAGE=3.5.4-0 export ETCD_VERSION=3.5.4 </ins> # Upgrade master with updated kube envs "${KUBE_ROOT}/cluster/gce/upgrade.sh" -M -l


MinExternalEtcdVersion = "3.2.18" // DefaultEtcdVersion indicates the default etcd version that kubeadm uses <del> DefaultEtcdVersion = "3.5.3-0" </del> <ins> DefaultEtcdVersion = "3.5.4-0" </ins> // Etcd defines variable used internally when referring to etcd component Etcd = "etcd"


19: "3.4.13-0", 20: "3.4.13-0", 21: "3.4.13-0", <del> 22: "3.5.3-0", 23: "3.5.3-0", 24: "3.5.3-0", </del> <ins> 22: "3.5.4-0", 23: "3.5.4-0", 24: "3.5.4-0", 25: "3.5.4-0", </ins> } // KubeadmCertsClusterRoleName sets the name for the ClusterRole that allows


# A set of helpers for starting/running etcd for tests <del> ETCD_VERSION=${ETCD_VERSION:-3.5.3} </del> <ins> ETCD_VERSION=${ETCD_VERSION:-3.5.4} </ins> ETCD_HOST=${ETCD_HOST:-127.0.0.1} ETCD_PORT=${ETCD_PORT:-2379} # This is intentionally not called ETCD_LOG_LEVEL:


imagePullPolicy: Never args: [ "--etcd-servers=http://localhost:2379" ] - name: etcd <del> image: gcr.io/etcd-development/etcd:v3.5.3 </del> <ins> image: gcr.io/etcd-development/etcd:v3.5.4 </ins>


e2essh "k8s.io/kubernetes/test/e2e/framework/ssh" ) <del> const etcdImage = "3.5.3-0" </del> <ins> const etcdImage = "3.5.4-0" </ins> // EtcdUpgrade upgrades etcd on GCE. func EtcdUpgrade(targetStorage, targetVersion string) error {


configs[CudaVectorAdd2] = Config{list.PromoterE2eRegistry, "cuda-vector-add", "2.2"} configs[DebianIptables] = Config{list.BuildImageRegistry, "debian-iptables", "bullseye-v1.3.0"} configs[EchoServer] = Config{list.PromoterE2eRegistry, "echoserver", "2.4"} <del> configs[Etcd] = Config{list.GcEtcdRegistry, "etcd", "3.5.3-0"} </del> <ins> configs[Etcd] = Config{list.GcEtcdRegistry, "etcd", "3.5.4-0"} </ins> configs[GlusterDynamicProvisioner] = Config{list.PromoterE2eRegistry, "glusterdynamic-provisioner", "v1.3"} configs[Httpd] = Config{list.PromoterE2eRegistry, "httpd", "2.4.38-2"} configs[HttpdNew] = Config{list.PromoterE2eRegistry, "httpd", "2.4.39-2"}


Pod:        newNamedPod("5-static", "test1", "pod1", true), UpdateType: kubetypes.SyncPodUpdate, }) <ins> // Wait for the previous work to be delivered to the worker drainAllWorkers(podWorkers) </ins> channels.Channel("5-static").Hold() podWorkers.UpdatePod(UpdatePodOptions{ Pod:        newNamedPod("5-static", "test1", "pod1", true),


return true, binding, nil }) controllers := make(map[string]string) <del> stopFn := broadcaster.StartEventWatcher(func(obj runtime.Object) { </del> <ins> stopFn, err := broadcaster.StartEventWatcher(func(obj runtime.Object) { </ins> e, ok := obj.(*eventsv1.Event) if !ok || e.Reason != "Scheduled" { return


controllers[e.Regarding.Name] = e.ReportingController wg.Done() }) <ins> if err != nil { t.Fatal(err) } </ins> defer stopFn() // Run scheduler.


fwk.EventRecorder().Eventf(p.Pod, nil, v1.EventTypeWarning, "FailedScheduling", "Scheduling", msg) } called := make(chan struct{}) <del> stopFunc := eventBroadcaster.StartEventWatcher(func(obj runtime.Object) { </del> <ins> stopFunc, err := eventBroadcaster.StartEventWatcher(func(obj runtime.Object) { </ins> e, _ := obj.(*eventsv1.Event) if e.Reason != item.eventReason { t.Errorf("got event %v, want %v", e.Reason, item.eventReason) } close(called) }) <ins> if err != nil { t.Fatal(err) } </ins> sched.scheduleOne(ctx) <-called if e, a := item.expectAssumedPod, gotAssumedPod; !reflect.DeepEqual(e, a) {


fakeVolumeBinder := volumebinding.NewFakeVolumeBinder(item.volumeBinderConfig) s, bindingChan, errChan := setupTestSchedulerWithVolumeBinding(ctx, fakeVolumeBinder, eventBroadcaster) eventChan := make(chan struct{}) <del> stopFunc := eventBroadcaster.StartEventWatcher(func(obj runtime.Object) { </del> <ins> stopFunc, err := eventBroadcaster.StartEventWatcher(func(obj runtime.Object) { </ins> e, _ := obj.(*eventsv1.Event) if e, a := item.eventReason, e.Reason; e != a { t.Errorf("expected %v, got %v", e, a) } close(eventChan) }) <ins> if err != nil { t.Fatal(err) } </ins> s.scheduleOne(ctx) // Wait for pod to succeed or fail scheduling select {


// StartStructuredLogging starts sending events received from this EventBroadcaster to the structured logging function. // The return value can be ignored or used to stop recording, if desired. <ins> // TODO: this function should also return an error. </ins> func (e *eventBroadcasterImpl) StartStructuredLogging(verbosity klog.Level) func() { <del> return e.StartEventWatcher( </del> <ins> stopWatcher, err := e.StartEventWatcher( </ins> func(obj runtime.Object) { event, ok := obj.(*eventsv1.Event) if !ok {


} klog.V(verbosity).InfoS("Event occurred", "object", klog.KRef(event.Regarding.Namespace, event.Regarding.Name), "kind", event.Regarding.Kind, "apiVersion", event.Regarding.APIVersion, "type", event.Type, "reason", event.Reason, "action", event.Action, "note", event.Note) }) <ins> if err != nil { klog.Errorf("failed to start event watcher: '%v'", err) return func() {} } return stopWatcher </ins> } // StartEventWatcher starts sending events received from this EventBroadcaster to the given event handler function. // The return value is used to stop recording <del> func (e *eventBroadcasterImpl) StartEventWatcher(eventHandler func(event runtime.Object)) func() { </del> <ins> func (e *eventBroadcasterImpl) StartEventWatcher(eventHandler func(event runtime.Object)) (func(), error) { </ins> watcher, err := e.Watch() if err != nil { klog.Errorf("Unable start event watcher: '%v' (will not retry!)", err) <del> // TODO: Rewrite the function signature to return an error, for // now just return a no-op function return func() { klog.Error("The event watcher failed to start") } </del> <ins> return nil, err </ins> } go func() { defer utilruntime.HandleCrash()


eventHandler(watchEvent.Object) } }() <del> return watcher.Stop </del> <ins> return watcher.Stop, nil </ins> } <del> func (e *eventBroadcasterImpl) startRecordingEvents(stopCh <-chan struct{}) { </del> <ins> func (e *eventBroadcasterImpl) startRecordingEvents(stopCh <-chan struct{}) error { </ins> eventHandler := func(obj runtime.Object) { event, ok := obj.(*eventsv1.Event) if !ok {


} e.recordToSink(event, clock.RealClock{}) } <del> stopWatcher := e.StartEventWatcher(eventHandler) </del> <ins> stopWatcher, err := e.StartEventWatcher(eventHandler) if err != nil { return err } </ins> go func() { <-stopCh stopWatcher() }() <ins> return nil </ins> } // StartRecordingToSink starts sending events received from the specified eventBroadcaster to the given sink. func (e *eventBroadcasterImpl) StartRecordingToSink(stopCh <-chan struct{}) { go wait.Until(e.refreshExistingEventSeries, refreshTime, stopCh) go wait.Until(e.finishSeries, finishTime, stopCh) <del> e.startRecordingEvents(stopCh) </del> <ins> err := e.startRecordingEvents(stopCh) if err != nil { klog.Errorf("unexpected type, expected eventsv1.Event") return } </ins> } type eventBroadcasterAdapterImpl struct {


// Don't call StartRecordingToSink, as we don't need neither refreshing event // series nor finishing them in this tests and additional events updated would // race with our expected ones. <del> broadcaster.startRecordingEvents(stopCh) </del> <ins> err = broadcaster.startRecordingEvents(stopCh) if err != nil { t.Fatal(err) } </ins> recorder.Eventf(regarding, related, isomorphicEvent.Type, isomorphicEvent.Reason, isomorphicEvent.Action, isomorphicEvent.Note, []interface{}{1}) // read from the chan as this was needed only to populate the cache <-createEvent


// of StartRecordingToSink. This lets you also process events in a custom way (e.g. in tests). // NOTE: events received on your eventHandler should be copied before being used. // TODO: figure out if this can be removed. <del> StartEventWatcher(eventHandler func(event runtime.Object)) func() </del> <ins> StartEventWatcher(eventHandler func(event runtime.Object)) (func(), error) </ins> // StartStructuredLogging starts sending events received from this EventBroadcaster to the structured // logging function. The return value can be ignored or used to stop recording, if desired.


"v":                   true, "vmodule":             true, "log-flush-frequency": true, <ins> "provider-id":         true, </ins> } fs.VisitAll(func(f *pflag.Flag) { if notDeprecated[f.Name] {


"api/v1.0", }, "/"), } <del> _, err := c.MachineInfo() if err != nil { return nil, err } </del> return c, nil }


NumStats:               3, NumSamples:             2, CpuUsagePercentiles:    []int{10, 50, 90}, <del> MemoryUsagePercentages: []int{10, 80, 90}, </del> <ins> MemoryUsagePercentiles: []int{10, 80, 90}, </ins> } containerName := "/some/container" cinfo := itest.GenerateRandomContainerInfo(containerName, 4, query, 1*time.Second)


"time" v1 "k8s.io/api/core/v1" <ins> apiequality "k8s.io/apimachinery/pkg/api/equality" </ins> metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" <ins> "k8s.io/apimachinery/pkg/util/diff" </ins> "k8s.io/apimachinery/pkg/util/wait" "k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/instrumentation/common"


} }) <ins> ginkgo.It("should manage the lifecycle of an event", func() { eventTestName := "event-test" ginkgo.By("creating a test event") // create a test event in test namespace _, err := f.ClientSet.CoreV1().Events(f.Namespace.Name).Create(context.TODO(), &v1.Event{ ObjectMeta: metav1.ObjectMeta{ Name: eventTestName, Labels: map[string]string{ "testevent-constant": "true", }, }, Message: "This is a test event", Reason:  "Test", Type:    "Normal", Count:   1, InvolvedObject: v1.ObjectReference{ Namespace: f.Namespace.Name, }, }, metav1.CreateOptions{}) framework.ExpectNoError(err, "failed to create test event") ginkgo.By("listing all events in all namespaces") // get a list of Events in all namespaces to ensure endpoint coverage eventsList, err := f.ClientSet.CoreV1().Events("").List(context.TODO(), metav1.ListOptions{ LabelSelector: "testevent-constant=true", }) framework.ExpectNoError(err, "failed list all events") foundCreatedEvent := false var eventCreatedName string for _, val := range eventsList.Items { if val.ObjectMeta.Name == eventTestName && val.ObjectMeta.Namespace == f.Namespace.Name { foundCreatedEvent = true eventCreatedName = val.ObjectMeta.Name break } } if !foundCreatedEvent { framework.Failf("unable to find test event %s in namespace %s, full list of events is %+v", eventTestName, f.Namespace.Name, eventsList.Items) } ginkgo.By("patching the test event") // patch the event's message eventPatchMessage := "This is a test event - patched" eventPatch, err := json.Marshal(map[string]interface{}{ "message": eventPatchMessage, }) framework.ExpectNoError(err, "failed to marshal the patch JSON payload") _, err = f.ClientSet.CoreV1().Events(f.Namespace.Name).Patch(context.TODO(), eventTestName, types.StrategicMergePatchType, []byte(eventPatch), metav1.PatchOptions{}) framework.ExpectNoError(err, "failed to patch the test event") ginkgo.By("fetching the test event") // get event by name event, err := f.ClientSet.CoreV1().Events(f.Namespace.Name).Get(context.TODO(), eventCreatedName, metav1.GetOptions{}) framework.ExpectNoError(err, "failed to fetch the test event") framework.ExpectEqual(event.Message, eventPatchMessage, "test event message does not match patch message") ginkgo.By("updating the test event") testEvent, err := f.ClientSet.CoreV1().Events(f.Namespace.Name).Get(context.TODO(), event.Name, metav1.GetOptions{}) framework.ExpectNoError(err, "failed to get test event") testEvent.Series = &v1.EventSeries{ Count:            100, LastObservedTime: metav1.MicroTime{Time: time.Unix(1505828956, 0)}, } // clear ResourceVersion and ManagedFields which are set by control-plane testEvent.ObjectMeta.ResourceVersion = "" testEvent.ObjectMeta.ManagedFields = nil _, err = f.ClientSet.CoreV1().Events(f.Namespace.Name).Update(context.TODO(), testEvent, metav1.UpdateOptions{}) framework.ExpectNoError(err, "failed to update the test event") ginkgo.By("getting the test event") event, err = f.ClientSet.CoreV1().Events(f.Namespace.Name).Get(context.TODO(), testEvent.Name, metav1.GetOptions{}) framework.ExpectNoError(err, "failed to get test event") // clear ResourceVersion and ManagedFields which are set by control-plane event.ObjectMeta.ResourceVersion = "" event.ObjectMeta.ManagedFields = nil if !apiequality.Semantic.DeepEqual(testEvent, event) { framework.Failf("test event wasn't properly updated: %v", diff.ObjectReflectDiff(testEvent, event)) } ginkgo.By("deleting the test event") // delete original event err = f.ClientSet.CoreV1().Events(f.Namespace.Name).Delete(context.TODO(), eventCreatedName, metav1.DeleteOptions{}) framework.ExpectNoError(err, "failed to delete the test event") ginkgo.By("listing all events in all namespaces") // get a list of Events list namespace eventsList, err = f.ClientSet.CoreV1().Events("").List(context.TODO(), metav1.ListOptions{ LabelSelector: "testevent-constant=true", }) framework.ExpectNoError(err, "fail to list all events") foundCreatedEvent = false for _, val := range eventsList.Items { if val.ObjectMeta.Name == eventTestName && val.ObjectMeta.Namespace == f.Namespace.Name { foundCreatedEvent = true break } } if foundCreatedEvent { framework.Failf("Should not have found test event %s in namespace %s, full list of events %+v", eventTestName, f.Namespace.Name, eventsList.Items) } }) </ins> /* Release: v1.20 Testname: Event, delete a collection