<ins> # On Collaborative Development Kubernetes is open source, but many of the people working on it do so as their day job.  In order to avoid forcing people to be "at work" effectively 24/7, we want to establish some semi-formal protocols around development.  Hopefully these rules make things go more smoothly.  If you find that this is not the case, please complain loudly. ## Patches welcome First and foremost: as a potential contributor, your changes and ideas are welcome at any hour of the day or night, weekdays, weekends, and holidays.  Please do not ever hesitate to ask a question or send a PR. ## Timezones and calendars For the time being, most of the people working on this project are in the US and on Pacific time.  Any times mentioned henceforth will refer to this timezone.  Any references to "work days" will refer to the US calendar. ## Code reviews All changes must be code reviewed.  For non-maintainers this is obvious, since you can't commit anyway.  But even for maintainers, we want all changes to get at least one review, preferably from someone who knows the areas the change touches.  For non-trivial changes we may want two reviewers.  The primary reviewer will make this decision and nominate a second reviewer, if needed.  Except for trivial changes, PRs should sit for at least a 2 hours to allow for wider review. Most PRs will find reviewers organically.  If a maintainer intends to be the primary reviewer of a PR they should set themselves as the assignee on GitHub and say so in a reply to the PR.  Only the primary reviewer of a change should actually do the merge, except in rare cases (e.g. they are unavailable in a reasonable timeframe). If a PR has gone 2 work days without an owner emerging, please poke the PR thread and ask for a reviewer to be assigned. Except for rare cases, such as trivial changes (e.g. typos, comments) or emergencies (e.g. broken builds), maintainers should not merge their own changes. Expect reviewers to request that you avoid [common go style mistakes](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) in your PRs. ## Assigned reviews Maintainers can assign reviews to other maintainers, when appropriate. The assignee becomes the shepherd for that PR and is responsible for merging the PR once they are satisfied with it or else closing it.  The assignee might request reviews from non-maintainers. ## Merge hours Maintainers will do merges between the hours of 7:00 am Monday and 7:00 pm (19:00h) Friday.  PRs that arrive over the weekend or on holidays will only be merged if there is a very good reason for it and if the code review requirements have been met. There may be discussion an even approvals granted outside of the above hours, but merges will generally be deferred. ## Holds Any maintainer or core contributor who wants to review a PR but does not have time immediately may put a hold on a PR simply by saying so on the PR discussion and offering an ETA measured in single-digit days at most.  Any PR that has a hold shall not be merged until the person who requested the hold acks the review, withdraws their hold, or is overruled by a preponderance of maintainers. </ins>


pod.Status.ContainerStatuses = test.oldStatuses podStatus.ContainerStatuses = test.statuses apiStatus := kubelet.generateAPIPodStatus(pod, podStatus) <del> verifyStatus(t, i, apiStatus, test.expectedState, test.expectedLastTerminationState) </del> <ins> assert.NoError(t, verifyContainerStatuses(apiStatus.ContainerStatuses, test.expectedState, test.expectedLastTerminationState), "case %d", i) } // Everything should be the same for init containers for i, test := range tests { kubelet.reasonCache = NewReasonCache() for n, e := range test.reasons { kubelet.reasonCache.add(pod.UID, n, e, "") } pod.Spec.InitContainers = test.containers pod.Status.InitContainerStatuses = test.oldStatuses podStatus.ContainerStatuses = test.statuses apiStatus := kubelet.generateAPIPodStatus(pod, podStatus) expectedState := test.expectedState if test.expectedInitState != nil { expectedState = test.expectedInitState } assert.NoError(t, verifyContainerStatuses(apiStatus.InitContainerStatuses, expectedState, test.expectedLastTerminationState), "case %d", i) } } // Test generateAPIPodStatus with different restart policies. func TestGenerateAPIPodStatusWithDifferentRestartPolicies(t *testing.T) { testErrorReason := fmt.Errorf("test-error") emptyContainerID := (&kubecontainer.ContainerID{}).String() testKubelet := newTestKubelet(t) kubelet := testKubelet.kubelet pod := podWithUidNameNs("12345678", "foo", "new") containers := []api.Container{{Name: "succeed"}, {Name: "failed"}} podStatus := &kubecontainer.PodStatus{ ID:        pod.UID, Name:      pod.Name, Namespace: pod.Namespace, ContainerStatuses: []*kubecontainer.ContainerStatus{ { Name:     "succeed", State:    kubecontainer.ContainerStateExited, ExitCode: 0, }, { Name:     "failed", State:    kubecontainer.ContainerStateExited, ExitCode: 1, }, { Name:     "succeed", State:    kubecontainer.ContainerStateExited, ExitCode: 2, }, { Name:     "failed", State:    kubecontainer.ContainerStateExited, ExitCode: 3, }, }, } kubelet.reasonCache.add(pod.UID, "succeed", testErrorReason, "") kubelet.reasonCache.add(pod.UID, "failed", testErrorReason, "") for c, test := range []struct { restartPolicy                api.RestartPolicy expectedState                map[string]api.ContainerState expectedLastTerminationState map[string]api.ContainerState // Only set expectedInitState when it is different from expectedState expectedInitState map[string]api.ContainerState // Only set expectedInitLastTerminationState when it is different from expectedLastTerminationState expectedInitLastTerminationState map[string]api.ContainerState }{ { restartPolicy: api.RestartPolicyNever, expectedState: map[string]api.ContainerState{ "succeed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    0, ContainerID: emptyContainerID, }}, "failed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    1, ContainerID: emptyContainerID, }}, }, expectedLastTerminationState: map[string]api.ContainerState{ "succeed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    2, ContainerID: emptyContainerID, }}, "failed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    3, ContainerID: emptyContainerID, }}, }, }, { restartPolicy: api.RestartPolicyOnFailure, expectedState: map[string]api.ContainerState{ "succeed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    0, ContainerID: emptyContainerID, }}, "failed": {Waiting: &api.ContainerStateWaiting{Reason: testErrorReason.Error()}}, }, expectedLastTerminationState: map[string]api.ContainerState{ "succeed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    2, ContainerID: emptyContainerID, }}, "failed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    1, ContainerID: emptyContainerID, }}, }, }, { restartPolicy: api.RestartPolicyAlways, expectedState: map[string]api.ContainerState{ "succeed": {Waiting: &api.ContainerStateWaiting{Reason: testErrorReason.Error()}}, "failed":  {Waiting: &api.ContainerStateWaiting{Reason: testErrorReason.Error()}}, }, expectedLastTerminationState: map[string]api.ContainerState{ "succeed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    0, ContainerID: emptyContainerID, }}, "failed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    1, ContainerID: emptyContainerID, }}, }, // If the init container is terminated with exit code 0, it won't be restarted even when the // restart policy is RestartAlways. expectedInitState: map[string]api.ContainerState{ "succeed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    0, ContainerID: emptyContainerID, }}, "failed": {Waiting: &api.ContainerStateWaiting{Reason: testErrorReason.Error()}}, }, expectedInitLastTerminationState: map[string]api.ContainerState{ "succeed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    2, ContainerID: emptyContainerID, }}, "failed": {Terminated: &api.ContainerStateTerminated{ ExitCode:    1, ContainerID: emptyContainerID, }}, }, }, } { pod.Spec.RestartPolicy = test.restartPolicy // Test normal containers pod.Spec.Containers = containers apiStatus := kubelet.generateAPIPodStatus(pod, podStatus) expectedState, expectedLastTerminationState := test.expectedState, test.expectedLastTerminationState assert.NoError(t, verifyContainerStatuses(apiStatus.ContainerStatuses, expectedState, expectedLastTerminationState), "case %d", c) pod.Spec.Containers = nil // Test init containers pod.Spec.InitContainers = containers apiStatus = kubelet.generateAPIPodStatus(pod, podStatus) if test.expectedInitState != nil { expectedState = test.expectedInitState } if test.expectedInitLastTerminationState != nil { expectedLastTerminationState = test.expectedInitLastTerminationState } assert.NoError(t, verifyContainerStatuses(apiStatus.InitContainerStatuses, expectedState, expectedLastTerminationState), "case %d", c) pod.Spec.InitContainers = nil </ins> } }


func TestRegisterExistingNodeWithApiserver(t *testing.T) { testKubelet := newTestKubelet(t) kubelet := testKubelet.kubelet <del> kubelet.hostname = "127.0.0.1" </del> kubeClient := testKubelet.fakeKubeClient kubeClient.ReactFn = func(action testclient.FakeAction) (runtime.Object, error) { segments := strings.Split(action.Action, "-")


// Handle the containers failed to be started, which should be in Waiting state. for _, container := range containers { <ins> if isInitContainer { // If the init container is terminated with exit code 0, it won't be restarted. // TODO(random-liu): Handle this in a cleaner way. s := podStatus.FindContainerStatusByName(container.Name) if s != nil && s.State == kubecontainer.ContainerStateExited && s.ExitCode == 0 { continue } } </ins> // If a container should be restarted in next syncpod, it is *Waiting*. if !kubecontainer.ShouldContainerBeRestarted(&container, pod, podStatus) { continue


} /* <del> Release : v1.12 Testname: Security Context: runAsUser (id:65534) Description: Container created with runAsUser option, passing an id (id:65534) uses that given id when running the container. This test is marked LinuxOnly since Windows does not support running as UID / GID. </del> <ins> Release : v1.15 Testname: Security Context, runAsUser=65534 Description: Container is created with runAsUser option by passing uid 65534 to run as unpriviledged user. Pod MUST be in Succeeded phase. [LinuxOnly]: This test is marked as LinuxOnly since Windows does not support running as UID / GID. </ins> */ <del> It("should run the container with uid 65534 [LinuxOnly] [NodeConformance]", func() { </del> <ins> framework.ConformanceIt("should run the container with uid 65534 [LinuxOnly] [NodeConformance]", func() { </ins> createAndWaitUserPod(65534) }) /* <del> Release : v1.12 Testname: Security Context: runAsUser (id:0) Description: Container created with runAsUser option, passing an id (id:0) uses that given id when running the container. This test is marked LinuxOnly since Windows does not support running as UID / GID. </del> <ins> Release : v1.15 Testname: Security Context, runAsUser=0 Description: Container is created with runAsUser option by passing uid 0 to run as root priviledged user. Pod MUST be in Succeeded phase. This e2e can not be promoted to Conformance because a Conformant platform may not allow to run containers with 'uid 0' or running privileged operations. [LinuxOnly]: This test is marked as LinuxOnly since Windows does not support running as UID / GID. </ins> */ It("should run the container with uid 0 [LinuxOnly] [NodeConformance]", func() { createAndWaitUserPod(0)


srcs = [ "alpha.go", "annotate.go", <ins> "apiresources.go", </ins> "apiversions.go", "apply.go", "apply_edit_last_applied.go",


if [[ ${GOOS} == "windows" ]]; then bin="${bin}.exe" fi <del> CGO_ENABLED=0 go build -installsuffix cgo -o "${output_path}/${bin}"  </del> <ins> go build -o "${output_path}/${bin}"  </ins> "${goflags[@]:+${goflags[@]}}"  -ldflags "${version_ldflags}"  "${binary}" done else <del> CGO_ENABLED=0 go install -installsuffix cgo "${goflags[@]:+${goflags[@]}}"  </del> <ins> go install "${goflags[@]:+${goflags[@]}}"  </ins> -ldflags "${version_ldflags}"  "${binaries[@]}" fi


// +k8s:deepcopy-gen=package <del> package testing </del> <ins> package testing // import "k8s.io/apimachinery/pkg/runtime/testing" </ins>


} fn := func() error { <del> if !p.Quiet && stderr != nil { fmt.Fprintln(stderr, "If you don't see a command prompt, try pressing enter.") } </del> restClient, err := restclient.RESTClientFor(p.Config) if err != nil { return err


return v.target.WithKind(src.Kind), true } } <ins> if v.coerce && len(kinds) > 0 { return v.target.WithKind(kinds[0].Kind), true } </ins> return schema.GroupVersionKind{}, false }


framework.ExpectNotEqual(len(list.Groups), 0, "Missing APIGroups") for _, group := range list.Groups { <ins> if strings.HasSuffix(group.Name, ".example.com") { // ignore known example dynamic API groups that are added/removed during the e2e test run continue } </ins> framework.Logf("Checking APIGroup: %v", group.Name) // locate APIGroup endpoint


namespace quota. The creation MUST fail release: v1.15 file: test/e2e/apps/rc.go <ins> - testname: Replication Controller, lifecycle codename: '[sig-apps] ReplicationController should test the lifecycle of a ReplicationController [Conformance]' description: A Replication Controller (RC) is created, read, patched, and deleted with verification. release: v1.20 file: test/e2e/apps/rc.go </ins> - testname: StatefulSet, Burst Scaling codename: '[sig-apps] StatefulSet [k8s.io] Basic StatefulSet functionality [StatefulSetBasic] Burst scaling should run to completion even with unhealthy pods [Slow] [Conformance]'


"k8s.io/kubernetes/test/e2e/framework" ) <del> const minFileSize = 1 * framework.MiB </del> <ins> const ( minFileSize = 1 * framework.MiB fileSizeSmall  = 1 * framework.MiB fileSizeMedium = 100 * framework.MiB fileSizeLarge  = 1 * framework.GiB ) // MD5 hashes of the test file corresponding to each file size. // Test files are generated in testVolumeIO() // If test file generation algorithm changes, these must be recomputed. var md5hashes = map[int64]string{ fileSizeSmall:  "5c34c2813223a7ca05a3c2f38c0d1710", fileSizeMedium: "f2fa202b1ffeedda5f3a58bd1ae81104", fileSizeLarge:  "8d763edc71bd16217664793b5a15e403", } </ins> // Return the plugin's client pod spec. Use an InitContainer to setup the file i/o test env. func makePodSpec(config framework.VolumeTestConfig, dir, initCmd string, volsrc v1.VolumeSource, podSecContext *v1.PodSecurityContext) *v1.Pod {


Command:       getSchedulerCommand(cfg), LivenessProbe: componentProbe(10251, "/healthz"), Resources:     componentResources("100m"), <ins> Env:           getProxyEnvVars(), </ins> }), }


}, } <ins> // deep copy before reconciler runs to avoid data race. pvWithSize := pv.DeepCopy() </ins> volumePluginMgr, fakePlugin := volumetesting.GetTestKubeletVolumePluginMgr(t) dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr)


local -r known_tokens_csv="${auth_dir}/known_tokens.csv" if [[ ! -e "${known_tokens_csv}" ]]; then echo "${KUBE_BEARER_TOKEN},admin,admin" > "${known_tokens_csv}" <del> echo "${KUBELET_TOKEN},kubelet,kubelet" >> "${known_tokens_csv}" echo "${KUBE_PROXY_TOKEN},kube_proxy,kube_proxy" >> "${known_tokens_csv}" </del> <ins> echo "${KUBE_CONTROLLER_MANAGER_TOKEN},system:kube-controller-manager,uid:system:kube-controller-manager" >> "${known_tokens_csv}" echo "${KUBELET_TOKEN},system:node:node-name,uid:kubelet,system:nodes" >> "${known_tokens_csv}" echo "${KUBE_PROXY_TOKEN},system:kube-proxy,uid:kube_proxy" >> "${known_tokens_csv}" </ins> fi local use_cloud_config="false" cat <<EOF >/etc/gce.conf


func (c *FakePods) Evict(eviction *policy.Eviction) error { action := core.CreateActionImpl{} action.Verb = "create" <ins> action.Namespace = c.ns </ins> action.Resource = podsResource action.Subresource = "eviction" action.Object = eviction


fs.BoolVar(&s.EnableLogsHandler, "enable-logs-handler", s.EnableLogsHandler, "If true, install a /logs handler for the apiserver logs.") <ins> fs.MarkDeprecated("enable-logs-handler", "This flag will be removed in v1.19") </ins> // Deprecated in release 1.9 fs.StringVar(&s.SSHUser, "ssh-user", s.SSHUser,


<ins> #!/bin/bash # Copyright 2017 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. # Sets up FlexVolume drivers on GCE COS instances using mounting utilities packaged in a Google # Container Registry image. # The user-provided FlexVolume driver(s) must be under /flexvolume of the image filesystem. # For example, the driver k8s/nfs must be located at /flexvolume/k8s~nfs/nfs . # # This script should be used on a clean instance, with no FlexVolume installed. # Should not be run on instances with an existing full or partial installation. # Upon failure, the script will clean up the partial installation automatically. # # Must be executed under /home/kubernetes/bin with sudo. # Warning: kubelet will be restarted upon successful execution. set -o errexit set -o nounset set -o pipefail MOUNTER_IMAGE=${1:-} MOUNTER_PATH=/home/kubernetes/flexvolume_mounter VOLUME_PLUGIN_DIR=/etc/srv/kubernetes/kubelet-plugins/volume/exec usage() { echo "usage: $0 imagename[:tag]" echo "    imagename  Name of a Container Registry image. By default the latest image is used." echo "    :tag       Container Registry image tag." exit 1 } if [ -z ${MOUNTER_IMAGE} ]; then echo "ERROR: No Container Registry mounter image is specified." echo usage fi # Unmounts a mount point lazily. If a mount point does not exist, continue silently, # and without error. umount_silent() { umount -l $1 &> /dev/null || /bin/true } # Waits for kubelet to restart for 1 minute. kubelet_wait() { timeout=60 kubelet_readonly_port=10255 until [[ $timeout -eq 0 ]]; do printf "." if [[ $( curl -s http://localhost:${kubelet_readonly_port}/healthz ) == "ok" ]]; then return 0 fi sleep 1 timeout=$(( timeout-1 )) done # Timed out waiting for kubelet to become healthy. return 1 } flex_clean() { echo echo "An error has occurred. Cleaning up..." echo umount_silent ${VOLUME_PLUGIN_DIR} rm -rf ${VOLUME_PLUGIN_DIR} umount_silent ${MOUNTER_PATH}/var/lib/kubelet umount_silent ${MOUNTER_PATH} rm -rf ${MOUNTER_PATH} if [ -n ${IMAGE_URL:-} ]; then docker rmi -f ${IMAGE_URL} &> /dev/null || /bin/true fi if [ -n ${MOUNTER_DEFAULT_NAME:-} ]; then docker rm -f ${MOUNTER_DEFAULT_NAME} &> /dev/null || /bin/true fi } trap flex_clean ERR # Generates a bash script that wraps all calls to the actual driver inside mount utilities # in the chroot environment. Kubelet sees this script as the FlexVolume driver. generate_chroot_wrapper() { if [ ! -d ${MOUNTER_PATH}/flexvolume ]; then echo "Failed to set up FlexVolume driver: cannot find directory '/flexvolume' in the mount utility image." exit 1 fi for driver_dir in ${MOUNTER_PATH}/flexvolume/*; do if [ -d "$driver_dir" ]; then filecount=$(ls -1 $driver_dir | wc -l) if [ $filecount -gt 1 ]; then echo "ERROR: Expected 1 file in the FlexVolume directory but found $filecount." exit 1 fi driver_file=$( ls $driver_dir | head -n 1 ) # driver_path points to the actual driver inside the mount utility image, # relative to image root. # wrapper_path is the wrapper script location, which is known to kubelet. driver_path=flexvolume/$( basename $driver_dir )/${driver_file} wrapper_dir=${VOLUME_PLUGIN_DIR}/$( basename $driver_dir ) wrapper_path=${wrapper_dir}/${driver_file} mkdir -p $wrapper_dir cat >$wrapper_path <<EOF #!/bin/bash chroot ${MOUNTER_PATH} ${driver_path} "$@" EOF chmod 755 $wrapper_path echo "FlexVolume driver installed at ${wrapper_path}" fi done } echo echo "Importing mount utility image from Container Registry..." echo METADATA=http://metadata.google.internal/computeMetadata/v1 SVC_ACCT_ENDPOINT=$METADATA/instance/service-accounts/default ACCESS_TOKEN=$(curl -s -H 'Metadata-Flavor: Google' $SVC_ACCT_ENDPOINT/token | cut -d'"' -f 4) PROJECT_ID=$(curl -s -H 'Metadata-Flavor: Google' $METADATA/project/project-id) IMAGE_URL=gcr.io/${PROJECT_ID}/${MOUNTER_IMAGE} MOUNTER_DEFAULT_NAME=flexvolume_mounter sudo -u ${SUDO_USER} docker login -u _token -p $ACCESS_TOKEN https://gcr.io > /dev/null sudo -u ${SUDO_USER} docker run --name=${MOUNTER_DEFAULT_NAME} ${IMAGE_URL} docker export ${MOUNTER_DEFAULT_NAME} > /tmp/${MOUNTER_DEFAULT_NAME}.tar docker rm ${MOUNTER_DEFAULT_NAME} > /dev/null docker rmi ${IMAGE_URL} > /dev/null echo echo "Loading mount utilities onto this instance..." echo mkdir ${MOUNTER_PATH} tar xf /tmp/${MOUNTER_DEFAULT_NAME}.tar -C ${MOUNTER_PATH} # Bind the kubelet directory to one under flexvolume_mounter mkdir ${MOUNTER_PATH}/var/lib/kubelet mount --rbind /var/lib/kubelet/ ${MOUNTER_PATH}/var/lib/kubelet mount --make-rshared ${MOUNTER_PATH}/var/lib/kubelet # Remount the flexvolume_mounter environment with /dev enabled. mount --bind ${MOUNTER_PATH} ${MOUNTER_PATH} mount -o remount,dev,exec ${MOUNTER_PATH} echo echo "Setting up FlexVolume driver..." echo mkdir -p ${VOLUME_PLUGIN_DIR} mount --bind ${VOLUME_PLUGIN_DIR} ${VOLUME_PLUGIN_DIR} mount -o remount,exec ${VOLUME_PLUGIN_DIR} generate_chroot_wrapper echo echo "Restarting Kubelet..." echo systemctl restart kubelet.service kubelet_wait if [ $? -eq 0 ]; then echo echo "FlexVolume is ready." else echo "ERROR: Timed out after 1 minute waiting for kubelet restart." fi </ins>


ContainerID: emptyContainerID, }}, }, <del> map[string]api.ContainerState{ </del> <ins> expectedLastTerminationState: map[string]api.ContainerState{ </ins> "without-reason": {Terminated: &api.ContainerStateTerminated{ ExitCode:    3, ContainerID: emptyContainerID,


return err } <del> err = os.Chmod(f.Name(), 0755) </del> <ins> err = os.Chmod(f.Name(), 0660) </ins> if err != nil { return err }


return "default", false, nil } <del> func (inClusterClientConfig) ConfigAccess() ConfigAccess { </del> <ins> func (config *inClusterClientConfig) ConfigAccess() ConfigAccess { </ins> return NewDefaultClientConfigLoadingRules() } // Possible returns true if loading an inside-kubernetes-cluster is possible. <del> func (inClusterClientConfig) Possible() bool { </del> <ins> func (config *inClusterClientConfig) Possible() bool { </ins> fi, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/token") return os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "" &&


"github.com/GoogleCloudPlatform/kubernetes/pkg/admission" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" <ins> "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" </ins> "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"


function upload-resources() { swift post kubernetes --read-acl '.r:*,.rlistings' <del> echo "[INFO] Upload ${KUBERNETES_RELEASE_TAR}" swift upload kubernetes ${ROOT}/../../_output/release-tars/${KUBERNETES_RELEASE_TAR}  </del> <ins> locations=( "${ROOT}/../../_output/release-tars/${KUBERNETES_RELEASE_TAR}" "${ROOT}/../../server/${KUBERNETES_RELEASE_TAR}" ) RELEASE_TAR_LOCATION=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 ) RELEASE_TAR_PATH=$(dirname ${RELEASE_TAR_LOCATION}) echo "[INFO] Uploading ${KUBERNETES_RELEASE_TAR}" swift upload kubernetes ${RELEASE_TAR_PATH}/${KUBERNETES_RELEASE_TAR}  </ins> --object-name kubernetes-server.tar.gz <del> echo "[INFO] Upload kubernetes-salt.tar.gz" swift upload kubernetes ${ROOT}/../../_output/release-tars/kubernetes-salt.tar.gz  </del> <ins> echo "[INFO] Uploading kubernetes-salt.tar.gz" swift upload kubernetes ${RELEASE_TAR_PATH}/kubernetes-salt.tar.gz  </ins> --object-name kubernetes-salt.tar.gz }


Import-Module -Force C:$Filename } <ins> # Returns true if the ENABLE_STACKDRIVER_WINDOWS or ENABLE_NODE_LOGGING field in kube_env is true. # $KubeEnv is a hash table containing the kube-env metadata keys+values. # ENABLE_NODE_LOGGING is used for legacy Stackdriver Logging, and will be deprecated (always set to False) # soon. ENABLE_STACKDRIVER_WINDOWS is added to indicate whether logging is enabled for windows nodes. function IsLoggingEnabled { param ( [parameter(Mandatory=$true)] [hashtable]$KubeEnv ) if ($KubeEnv.Contains('ENABLE_STACKDRIVER_WINDOWS') -and ` ($KubeEnv['ENABLE_STACKDRIVER_WINDOWS'] -eq 'true')) { return $true } elseif ($KubeEnv.Contains('ENABLE_NODE_LOGGING') -and ` ($KubeEnv['ENABLE_NODE_LOGGING'] -eq 'true')) { return $true } return $false } </ins> try { # Don't use FetchAndImport-ModuleFromMetadata for common.psm1 - the common # module includes variables and functions that any other function may depend


"-A", string(kubeServicesChain), "-m", "comment", "--comment", proxier.ipsetList[kubeClusterIPSet].getComment(), "-m", "set", "--match-set", kubeClusterIPSet, <del> "dst,dst", </del> ) if proxier.masqueradeAll { <del> writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) </del> <ins> writeLine(proxier.natRules, append(args, "dst,dst", "-j", string(KubeMarkMasqChain))...) </ins> } else if len(proxier.clusterCIDR) > 0 { // This masquerades off-cluster traffic to a service VIP.  The idea // is that you can establish a static route for your Service range, // routing to any node, and that node will bridge into the Service // for you.  Since that might bounce off-node, we masquerade here. // If/when we support "Local" policy for VIPs, we should update this. <del> writeLine(proxier.natRules, append(args, "! -s", proxier.clusterCIDR, "-j", string(KubeMarkMasqChain))...) </del> <ins> writeLine(proxier.natRules, append(args, "dst,dst", "! -s", proxier.clusterCIDR, "-j", string(KubeMarkMasqChain))...) } else { // Masquerade all OUTPUT traffic coming from a service ip. // The kube dummy interface has all service VIPs assigned which // results in the service VIP being picked as the source IP to reach // a VIP. This leads to a connection from VIP:<random port> to // VIP:<service port>. // Always masquerading OUTPUT (node-originating) traffic with a VIP // source ip and service port destination fixes the outgoing connections. writeLine(proxier.natRules, append(args, "src,dst", "-j", string(KubeMarkMasqChain))...) </ins> } }


VolumeNFSServer     = ImageConfig{e2eRegistry, "volume/nfs", "1.0"} VolumeISCSIServer   = ImageConfig{e2eRegistry, "volume/iscsi", "1.0"} VolumeGlusterServer = ImageConfig{e2eRegistry, "volume/gluster", "1.0"} <del> VolumeRBDServer     = ImageConfig{e2eRegistry, "volume/rbd", "1.0"} </del> <ins> VolumeRBDServer     = ImageConfig{e2eRegistry, "volume/rbd", "1.0.1"} </ins> ) func GetE2EImage(image ImageConfig) string {


importpath = "k8s.io/component-base/metrics/testutil", visibility = ["//visibility:public"], deps = [ <ins> "//staging/src/k8s.io/apimachinery/pkg/version:go_default_library", </ins> "//staging/src/k8s.io/component-base/metrics:go_default_library", "//vendor/github.com/prometheus/client_golang/prometheus/testutil:go_default_library", "//vendor/github.com/prometheus/common/expfmt:go_default_library",


// GetInstanceTypeByNodeName gets the instance type by node name. func (ss *scaleSet) GetInstanceTypeByNodeName(name string) (string, error) { <del> _, _, vm, err := ss.getVmssVM(name) </del> <ins> managedByAS, err := ss.isNodeManagedByAvailabilitySet(name) </ins> if err != nil { <del> if err == ErrorNotVmssInstance { glog.V(4).Infof("GetInstanceTypeByNodeName: node %q is managed by availability set", name) // Retry with standard type because nodes are not managed by vmss. return ss.availabilitySet.GetInstanceTypeByNodeName(name) } </del> <ins> glog.Errorf("Failed to check isNodeManagedByAvailabilitySet: %v", err) return "", err } if managedByAS { // vm is managed by availability set. return ss.availabilitySet.GetInstanceTypeByNodeName(name) } _, _, vm, err := ss.getVmssVM(name) if err != nil { </ins> return "", err }


# Optional: Enable node logging. ENABLE_NODE_LOGGING=true LOGGING_DESTINATION=elasticsearch # options: elasticsearch, gcp <ins> # Don't require https for registries in our local RFC1918 network EXTRA_DOCKER_OPTS="--insecure-registry 10.0.0.0/8" </ins>


<modelVersion>4.0.0</modelVersion> <groupId>io.k8s.cassandra</groupId> <artifactId>kubernetes-cassandra</artifactId> <del> <version>0.0.4</version> </del> <ins> <version>0.0.5</version> </ins> <build> <sourceDirectory>src</sourceDirectory> <plugins>


# REVISION provides a version number fo this image and all it's bundled # artifacts. It should start at zero for each LATEST_ETCD_VERSION and increment # for each revision of this image at that etcd version. <del> REVISION?=2 </del> <ins> REVISION?=3 </ins> # IMAGE_TAG Uniquely identifies k8s.gcr.io/etcd docker image with a tag of the form "<etcd-version>-<revision>". IMAGE_TAG=$(LATEST_ETCD_VERSION)-$(REVISION)


import ( "context" <ins> "fmt" </ins> "testing" "time"


host_platform=$(kube::golang::host_platform) # Use eval to preserve embedded quoted strings. <del> local goflags goldflags gogcflags build_with_coverage </del> <ins> local goflags goldflags gogcflags </ins> eval "goflags=(${GOFLAGS:-})" goldflags="${GOLDFLAGS:-} $(kube::version::ldflags)" gogcflags="${GOGCFLAGS:-}" <del> build_with_coverage="${KUBE_BUILD_WITH_COVERAGE:-}" </del> local -a targets=() local arg


} } <ins> // This function is used canary updates and phased rolling updates of template modifications for partiton1 and delete pod-0 func deletingPodForRollingUpdatePartitionTest(ctx context.Context, f *framework.Framework, c clientset.Interface, ns string, ss *appsv1.StatefulSet) { setHTTPProbe(ss) ss.Spec.UpdateStrategy = appsv1.StatefulSetUpdateStrategy{ Type: appsv1.RollingUpdateStatefulSetStrategyType, RollingUpdate: func() *appsv1.RollingUpdateStatefulSetStrategy { return &appsv1.RollingUpdateStatefulSetStrategy{ Partition: pointer.Int32(1), } }(), } ss, err := c.AppsV1().StatefulSets(ns).Create(ctx, ss, metav1.CreateOptions{}) framework.ExpectNoError(err) e2estatefulset.WaitForRunningAndReady(ctx, c, *ss.Spec.Replicas, ss) ss = waitForStatus(ctx, c, ss) currentRevision, updateRevision := ss.Status.CurrentRevision, ss.Status.UpdateRevision gomega.Expect(currentRevision).To(gomega.Equal(updateRevision), fmt.Sprintf("StatefulSet %s/%s created with update revision %s not equal to current revision %s", ss.Namespace, ss.Name, updateRevision, currentRevision)) pods := e2estatefulset.GetPodList(ctx, c, ss) for i := range pods.Items { gomega.Expect(pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel]).To(gomega.Equal(currentRevision), fmt.Sprintf("Pod %s/%s revision %s is not equal to currentRevision %s", pods.Items[i].Namespace, pods.Items[i].Name, pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel], currentRevision)) } ginkgo.By("Adding finalizer for pod-0") pod0name := getStatefulSetPodNameAtIndex(0, ss) pod0, err := c.CoreV1().Pods(ns).Get(ctx, pod0name, metav1.GetOptions{}) framework.ExpectNoError(err) pod0.Finalizers = append(pod0.Finalizers, testFinalizer) pod0, err = c.CoreV1().Pods(ss.Namespace).Update(ctx, pod0, metav1.UpdateOptions{}) framework.ExpectNoError(err) pods.Items[0] = *pod0 defer e2epod.NewPodClient(f).RemoveFinalizer(ctx, pod0.Name, testFinalizer) ginkgo.By("Updating image on StatefulSet") newImage := NewWebserverImage oldImage := ss.Spec.Template.Spec.Containers[0].Image ginkgo.By(fmt.Sprintf("Updating stateful set template: update image from %s to %s", oldImage, newImage)) gomega.Expect(oldImage).ToNot(gomega.Equal(newImage), "Incorrect test setup: should update to a different image") ss, err = updateStatefulSetWithRetries(ctx, c, ns, ss.Name, func(update *appsv1.StatefulSet) { update.Spec.Template.Spec.Containers[0].Image = newImage }) framework.ExpectNoError(err) ginkgo.By("Creating a new revision") ss = waitForStatus(ctx, c, ss) currentRevision, updateRevision = ss.Status.CurrentRevision, ss.Status.UpdateRevision gomega.Expect(currentRevision).ToNot(gomega.Equal(updateRevision), "Current revision should not equal update revision during rolling update") ginkgo.By("Await for all replicas running, all are updated but pod-0") e2estatefulset.WaitForState(ctx, c, ss, func(set2 *appsv1.StatefulSet, pods2 *v1.PodList) (bool, error) { ss = set2 pods = pods2 if ss.Status.UpdatedReplicas == *ss.Spec.Replicas-1 && ss.Status.Replicas == *ss.Spec.Replicas && ss.Status.ReadyReplicas == *ss.Spec.Replicas { // rolling updated is not completed, because replica 0 isn't ready return true, nil } return false, nil }) ginkgo.By("Verify pod images before pod-0 deletion and recreation") for i := range pods.Items { if i < int(*ss.Spec.UpdateStrategy.RollingUpdate.Partition) { gomega.Expect(pods.Items[i].Spec.Containers[0].Image).To(gomega.Equal(oldImage), fmt.Sprintf("Pod %s/%s has image %s not equal to oldimage image %s", pods.Items[i].Namespace, pods.Items[i].Name, pods.Items[i].Spec.Containers[0].Image, oldImage)) gomega.Expect(pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel]).To(gomega.Equal(currentRevision), fmt.Sprintf("Pod %s/%s has revision %s not equal to current revision %s", pods.Items[i].Namespace, pods.Items[i].Name, pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel], currentRevision)) } else { gomega.Expect(pods.Items[i].Spec.Containers[0].Image).To(gomega.Equal(newImage), fmt.Sprintf("Pod %s/%s has image %s not equal to new image  %s", pods.Items[i].Namespace, pods.Items[i].Name, pods.Items[i].Spec.Containers[0].Image, newImage)) gomega.Expect(pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel]).To(gomega.Equal(updateRevision), fmt.Sprintf("Pod %s/%s has revision %s not equal to new revision %s", pods.Items[i].Namespace, pods.Items[i].Name, pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel], updateRevision)) } } ginkgo.By("Deleting the pod-0 so that kubelet terminates it and StatefulSet controller recreates it") deleteStatefulPodAtIndex(ctx, c, 0, ss) ginkgo.By("Await for two replicas to be updated, while the pod-0 is not running") e2estatefulset.WaitForState(ctx, c, ss, func(set2 *appsv1.StatefulSet, pods2 *v1.PodList) (bool, error) { ss = set2 pods = pods2 return ss.Status.ReadyReplicas == *ss.Spec.Replicas-1, nil }) ginkgo.By(fmt.Sprintf("Removing finalizer from pod-0 (%v/%v) to allow recreation", pod0.Namespace, pod0.Name)) e2epod.NewPodClient(f).RemoveFinalizer(ctx, pod0.Name, testFinalizer) ginkgo.By("Await for recreation of pod-0, so that all replicas are running") e2estatefulset.WaitForState(ctx, c, ss, func(set2 *appsv1.StatefulSet, pods2 *v1.PodList) (bool, error) { ss = set2 pods = pods2 return ss.Status.ReadyReplicas == *ss.Spec.Replicas, nil }) ginkgo.By("Verify pod images after pod-0 deletion and recreation") pods = e2estatefulset.GetPodList(ctx, c, ss) for i := range pods.Items { if i < int(*ss.Spec.UpdateStrategy.RollingUpdate.Partition) { gomega.Expect(pods.Items[i].Spec.Containers[0].Image).To(gomega.Equal(oldImage), fmt.Sprintf("Pod %s/%s has image %s not equal to current image %s", pods.Items[i].Namespace, pods.Items[i].Name, pods.Items[i].Spec.Containers[0].Image, oldImage)) gomega.Expect(pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel]).To(gomega.Equal(currentRevision), fmt.Sprintf("Pod %s/%s has revision %s not equal to current revision %s", pods.Items[i].Namespace, pods.Items[i].Name, pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel], currentRevision)) } else { gomega.Expect(pods.Items[i].Spec.Containers[0].Image).To(gomega.Equal(newImage), fmt.Sprintf("Pod %s/%s has image %s not equal to new image  %s", pods.Items[i].Namespace, pods.Items[i].Name, pods.Items[i].Spec.Containers[0].Image, newImage)) gomega.Expect(pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel]).To(gomega.Equal(updateRevision), fmt.Sprintf("Pod %s/%s has revision %s not equal to new revision %s", pods.Items[i].Namespace, pods.Items[i].Name, pods.Items[i].Labels[appsv1.StatefulSetRevisionLabel], updateRevision)) } } } </ins> // confirmStatefulPodCount asserts that the current number of Pods in ss is count, waiting up to timeout for ss to // scale to count. func confirmStatefulPodCount(ctx context.Context, c clientset.Interface, count int, ss *appsv1.StatefulSet, timeout time.Duration, hard bool) {


"restartPolicy": "Always" } } <ins> {% endif %} </ins>


basename := filepath.Base(os.Args[0]) if err := commandFor(basename, hyperkubeCommand, allCommandFns).Execute(); err != nil { <del> fmt.Fprintf(os.Stderr, "%vn", err) </del> os.Exit(1) } }


} return true } <ins> // GetWindowsPath get a windows path func GetWindowsPath(path string) string { windowsPath := strings.Replace(path, "/", "", -1) if strings.HasPrefix(windowsPath, "") { windowsPath = "c:" + windowsPath } return windowsPath } </ins>


// CheckEtcdServers will attempt to reach all etcd servers once. If any // can be reached, return true. func (con EtcdConnection) CheckEtcdServers() (done bool, err error) { <del> // Attempt to reach every Etcd server in order for _, serverURI := range con.ServerList { host, err := parseServerURI(serverURI) </del> <ins> // Attempt to reach every Etcd server randomly. serverNumber := len(con.ServerList) serverPerms := rand.Perm(serverNumber) for _, index := range serverPerms { host, err := parseServerURI(con.ServerList[index]) </ins> if err != nil { return false, err }


} response, err := h.Client.Get(key, false, false) <del> if err != nil && !IsEtcdNotFound(err) { </del> <ins> if err != nil { if IsEtcdNotFound(err) { return nil } </ins> return err }


echo "ZONE='${ZONE}'" echo "MASTER_NAME='${MASTER_NAME}'" echo "MINION_IP_RANGE='${MINION_IP_RANGES[$i]}'" <ins> echo "EXTRA_DOCKER_OPTS='${EXTRA_DOCKER_OPTS}'" </ins> echo "ENABLE_DOCKER_REGISTRY_CACHE='${ENABLE_DOCKER_REGISTRY_CACHE:-false}'" grep -v "^#" "${KUBE_ROOT}/cluster/gce/templates/common.sh" grep -v "^#" "${KUBE_ROOT}/cluster/gce/templates/salt-minion.sh"


return framework.NewStatus(framework.Error, "pod cannot be nil") } if pod.Name == "my-test-pod" { <del> state.Lock() </del> state.Write(framework.StateKey(pod.Name), &stateData{data: "never bind"}) <del> state.Unlock() </del> } return nil }


Priorities []PriorityPolicy `json:"priorities"` // Holds the information to communicate with the extender(s) ExtenderConfigs []ExtenderConfig `json:"extenders"` <ins> // RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule // corresponding to every RequiredDuringScheduling affinity rule. // HardPodAffinitySymmetricWeight represents the weight of implicit PreferredDuringScheduling affinity rule, in the range 1-100. HardPodAffinitySymmetricWeight int `json:"hardPodAffinitySymmetricWeight"` </ins> } type PredicatePolicy struct {


} } <ins> // TestClusterIPLBInCreateDsrLoadBalancer tests, if the available endpoints are remote, // syncproxyrules only creates ClusterIP Loadbalancer and no NodePort, External IP or IngressIP // loadbalancers will be created. func TestClusterIPLBInCreateDsrLoadBalancer(t *testing.T) { syncPeriod := 30 * time.Second proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY) if proxier == nil { t.Error() } svcIP := "10.20.30.41" svcPort := 80 svcNodePort := 3001 svcPortName := proxy.ServicePortName{ NamespacedName: makeNSN("ns1", "svc1"), Port:           "p80", Protocol:       v1.ProtocolTCP, } lbIP := "11.21.31.41" makeServiceMap(proxier, makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) { svc.Spec.Type = "NodePort" svc.Spec.ClusterIP = svcIP svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal svc.Spec.Ports = []v1.ServicePort{{ Name:     svcPortName.Port, Port:     int32(svcPort), Protocol: v1.ProtocolTCP, NodePort: int32(svcNodePort), }} svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{ IP: lbIP, }} }), ) tcpProtocol := v1.ProtocolTCP populateEndpointSlices(proxier, makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) { eps.AddressType = discovery.AddressTypeIPv4 eps.Endpoints = []discovery.Endpoint{{ Addresses: []string{epIpAddressRemote}, NodeName:  pointer.StringPtr("testhost2"), // This will make this endpoint as a remote endpoint }} eps.Ports = []discovery.EndpointPort{{ Name:     pointer.StringPtr(svcPortName.Port), Port:     pointer.Int32(int32(svcPort)), Protocol: &tcpProtocol, }} }), ) proxier.setInitialized(true) proxier.syncProxyRules() svc := proxier.svcPortMap[svcPortName] svcInfo, ok := svc.(*serviceInfo) if !ok { t.Errorf("Failed to cast serviceInfo %q", svcPortName.String()) } else { // Checking ClusterIP Loadbalancer is created if svcInfo.hnsID != guid { t.Errorf("%v does not match %v", svcInfo.hnsID, guid) } // Verifying NodePort Loadbalancer is not created if svcInfo.nodePorthnsID != "" { t.Errorf("NodePortHnsID %v is not empty.", svcInfo.nodePorthnsID) } // Verifying ExternalIP Loadbalancer is not created for _, externalIP := range svcInfo.externalIPs { if externalIP.hnsID != "" { t.Errorf("ExternalLBID %v is not empty.", externalIP.hnsID) } } // Verifying IngressIP Loadbalancer is not created for _, ingressIP := range svcInfo.loadBalancerIngressIPs { if ingressIP.hnsID != "" { t.Errorf("IngressLBID %v is not empty.", ingressIP.hnsID) } } } } </ins> func TestEndpointSlice(t *testing.T) { syncPeriod := 30 * time.Second proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)


VolumeMounts:  volumeMounts, LivenessProbe: componentProbe(8080, "/healthz"), Resources:     componentResources("250m"), <ins> Env:           getProxyEnvVars(), </ins> }, volumes...), kubeControllerManager: componentPod(api.Container{ Name:          kubeControllerManager,


) const execInfoEnv = "KUBERNETES_EXEC_INFO" <ins> const onRotateListWarningLength = 1000 </ins> var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme)


flagNames.InsecureSkipTLSVerify.BindBoolFlag(flags, &clusterInfo.InsecureSkipTLSVerify) } <del> // BindOverrideFlags is a convenience method to bind the specified flags to their associated variables func BindOverrideFlags(overrides *ConfigOverrides, flags *pflag.FlagSet, flagNames ConfigOverrideFlags) { BindAuthInfoFlags(&overrides.AuthInfo, flags, flagNames.AuthOverrideFlags) BindClusterFlags(&overrides.ClusterInfo, flags, flagNames.ClusterOverrideFlags) BindContextFlags(&overrides.Context, flags, flagNames.ContextOverrideFlags) flagNames.CurrentContext.BindStringFlag(flags, &overrides.CurrentContext) flagNames.Timeout.BindStringFlag(flags, &overrides.Timeout) } </del> // BindFlags is a convenience method to bind the specified flags to their associated variables func BindContextFlags(contextInfo *clientcmdapi.Context, flags *pflag.FlagSet, flagNames ContextOverrideFlags) { flagNames.ClusterName.BindStringFlag(flags, &contextInfo.Cluster)


"github.com/golang/glog" <del> "k8s.io/api/core/v1" </del> apierrors "k8s.io/apimachinery/pkg/api/errors" <del> "k8s.io/apimachinery/pkg/labels" </del> utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" <del> v1informers "k8s.io/client-go/informers/core/v1" v1listers "k8s.io/client-go/listers/core/v1" </del> "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue"


Endpoints: []discovery.Endpoint{}, }, }, <ins> "bad-port-name-length": { expectedErrors: 1, endpointSlice: &discovery.EndpointSlice{ ObjectMeta:  standardMeta, AddressType: addressTypePtr(discovery.AddressTypeIP), Ports: []discovery.EndpointPort{{ Name:     utilpointer.StringPtr(strings.Repeat("a", 64)), Protocol: protocolPtr(api.ProtocolTCP), }}, Endpoints: []discovery.Endpoint{}, }, }, </ins> "invalid-port-protocol": { expectedErrors: 1, endpointSlice: &discovery.EndpointSlice{


"spec": { "containers": [{ "name": "test-container", <del> "image": "gcr.io/google_containers/pause-amd64:3.0" </del> <ins> "image": "gcr.io/google_containers/pause-amd64:3.1" </ins> }] } }


} # k8s <del> KUBE_VERSION=${KUBE_VERSION:-"1.1.4"} </del> <ins> KUBE_VERSION=${KUBE_VERSION:-"1.1.7"} </ins> echo "Prepare kubernetes ${KUBE_VERSION} release ..." grep -q "^${KUBE_VERSION}$" binaries/.kubernetes 2>/dev/null || { curl -L https://github.com/kubernetes/kubernetes/releases/download/v${KUBE_VERSION}/kubernetes.tar.gz -o kubernetes.tar.gz


const ( csiNodeLimitUpdateTimeout  = 5 * time.Minute <del> csiPodUnschedulableTimeout = 2 * time.Minute </del> <ins> csiPodUnschedulableTimeout = 5 * time.Minute </ins> ) var _ = utils.SIGDescribe("CSI mock volume", func() {


"//staging/src/k8s.io/component-base/metrics:go_default_library", "//vendor/github.com/emicklei/go-restful:go_default_library", "//vendor/github.com/google/cadvisor/info/v1:go_default_library", <ins> "//vendor/github.com/pkg/errors:go_default_library", </ins> "//vendor/k8s.io/klog:go_default_library", ], )


return 0 } <del> func (ds *dockerService) getSecurityOpts(containerName string, sandboxConfig *runtimeapi.PodSandboxConfig, separator rune) ([]string, error) { hasSeccompSetting := false annotations := sandboxConfig.GetAnnotations() if _, ok := annotations[v1.SeccompContainerAnnotationKeyPrefix+containerName]; !ok { _, hasSeccompSetting = annotations[v1.SeccompPodAnnotationKey] } else { hasSeccompSetting = true </del> <ins> func (ds *dockerService) getSecurityOpts(seccompProfile string, separator rune) ([]string, error) { if seccompProfile != "" { glog.Warningf("seccomp annotations are not supported on windows") </ins> } <del> if hasSeccompSetting { glog.Warningf("seccomp annotations found, but it is not supported on windows") } </del> return nil, nil }


setHugepages() ginkgo.By("restarting kubelet to pick up pre-allocated hugepages") <del> restartKubelet() </del> <ins> // stop the kubelet and wait until the server will restart it automatically stopKubelet() // wait until the kubelet health check will fail gomega.Eventually(func() bool { return kubeletHealthCheck(kubeletHealthCheckURL) }, time.Minute, time.Second).Should(gomega.BeFalse()) // wait until the kubelet health check will pass gomega.Eventually(func() bool { return kubeletHealthCheck(kubeletHealthCheckURL) }, 2*time.Minute, 10*time.Second).Should(gomega.BeTrue()) </ins> waitForHugepages()


match: BASEIMAGE?=k8s.gcr.io/build-image/debian-base-s390x:[a-zA-Z]+-v((([0-9]+).([0-9]+).([0-9]+)(?:-([0-9a-zA-Z-]+(?:.[0-9a-zA-Z-]+)*))?)(?:+([0-9a-zA-Z-]+(?:.[0-9a-zA-Z-]+)*))?) - name: "k8s.gcr.io/debian-iptables: dependents" <del> version: buster-v1.4.0 </del> <ins> version: buster-v1.5.0 </ins> refPaths: - path: build/common.sh match: debian_iptables_version=


VolumePlugins:      volumePlugins(), TLSOptions:         nil, OOMAdjuster:        oom.NewFakeOOMAdjuster(), <del> Mounter:            mount.New("" /* default mount path */), </del> <ins> Mounter:            &mount.FakeMounter{}, </ins> Subpather:          &subpath.FakeSubpath{}, HostUtil:           hostutil.NewFakeHostUtil(nil), }


)}, wantErr: "duplicate profile with scheduler name "foo"", }, <ins> { name: "With extenders", opts: []Option{ WithProfiles( schedulerapi.KubeSchedulerProfile{ SchedulerName: "default-scheduler", Plugins: &schedulerapi.Plugins{ QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}}, Bind:      schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}}, }, }, ), WithExtenders( schedulerapi.Extender{ URLPrefix: "http://extender.kube-system/", }, ), }, wantProfiles:  []string{"default-scheduler"}, wantExtenders: []string{"http://extender.kube-system/"}, }, </ins> } for _, tc := range cases {


// Flush is part of Interface.  Currently we delete IPVS services one by one func (runner *runner) Flush() error { <del> vss, err := runner.GetVirtualServers() if err != nil { return err } for _, vs := range vss { err := runner.DeleteVirtualServer(vs) // TODO: aggregate errors? if err != nil { return err } } return nil </del> <ins> return runner.ipvsHandle.Flush() </ins> } // AddRealServer is part of Interface.


"k8s.io/kubernetes/pkg/api/v1" dockertypes "github.com/docker/engine-api/types" <ins> dockercontainer "github.com/docker/engine-api/types/container" </ins> ) <ins> // These two functions are OS specific (for now at least) func updateHostConfig(config *dockercontainer.HostConfig) { // There is no /etc/resolv.conf in Windows, DNS and DNSSearch options would have to be passed to Docker runtime instead hc.DNS = opts.DNS hc.DNSSearch = opts.DNSSearch // MemorySwap == -1 is not currently supported in Docker 1.14 on Windows // https://github.com/docker/docker/blob/master/daemon/daemon_windows.go#L175 hc.Resources.MemorySwap = 0 } func DefaultMemorySwap() int64 { return 0 } </ins> func getContainerIP(container *dockertypes.ContainerJSON) string { if container.NetworkSettings != nil { for _, network := range container.NetworkSettings.Networks {


const ( DefaultEtcdPathPrefix = "/registry" <ins> globalTimeout         = time.Minute </ins> ) // StorageDestinations is a mapping from API group & resource to


w.WriteHeader(http.StatusNotFound) } <del> func startComponents(manifestURL, apiVersion string) (string, string) { </del> <ins> func startComponents(firstManifestURL, secondManifestURL, apiVersion string) (string, string) { </ins> // Setup servers := []string{} glog.Infof("Creating etcd client pointing to %v", servers)


Priorities []PriorityPolicy // Holds the information to communicate with the extender(s) ExtenderConfigs []ExtenderConfig <ins> // RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule // corresponding to every RequiredDuringScheduling affinity rule. // HardPodAffinitySymmetricWeight represents the weight of implicit PreferredDuringScheduling affinity rule, in the range 1-100. HardPodAffinitySymmetricWeight int </ins> } type PredicatePolicy struct {


func addConversionFuncs(scheme *runtime.Scheme) { // Add non-generated conversion functions err := scheme.AddConversionFuncs( <del> v1.Convert_api_ServiceSpec_To_v1_ServiceSpec, </del> <ins> v1.Convert_v1_DeleteOptions_To_api_DeleteOptions, v1.Convert_api_DeleteOptions_To_v1_DeleteOptions, v1.Convert_v1_ExportOptions_To_api_ExportOptions, v1.Convert_api_ExportOptions_To_v1_ExportOptions, v1.Convert_v1_List_To_api_List, v1.Convert_api_List_To_v1_List, v1.Convert_v1_ListOptions_To_api_ListOptions, v1.Convert_api_ListOptions_To_v1_ListOptions, v1.Convert_v1_ObjectFieldSelector_To_api_ObjectFieldSelector, v1.Convert_api_ObjectFieldSelector_To_v1_ObjectFieldSelector, v1.Convert_v1_ObjectMeta_To_api_ObjectMeta, v1.Convert_api_ObjectMeta_To_v1_ObjectMeta, v1.Convert_v1_ObjectReference_To_api_ObjectReference, v1.Convert_api_ObjectReference_To_v1_ObjectReference, v1.Convert_v1_OwnerReference_To_api_OwnerReference, v1.Convert_api_OwnerReference_To_v1_OwnerReference, v1.Convert_v1_Service_To_api_Service, v1.Convert_api_Service_To_v1_Service, v1.Convert_v1_ServiceList_To_api_ServiceList, v1.Convert_api_ServiceList_To_v1_ServiceList, v1.Convert_v1_ServicePort_To_api_ServicePort, v1.Convert_api_ServicePort_To_v1_ServicePort, v1.Convert_v1_ServiceProxyOptions_To_api_ServiceProxyOptions, v1.Convert_api_ServiceProxyOptions_To_v1_ServiceProxyOptions, </ins> v1.Convert_v1_ServiceSpec_To_api_ServiceSpec, <ins> v1.Convert_api_ServiceSpec_To_v1_ServiceSpec, v1.Convert_v1_ServiceStatus_To_api_ServiceStatus, v1.Convert_api_ServiceStatus_To_v1_ServiceStatus, </ins> ) if err != nil { // If one of the conversion functions is malformed, detect it immediately.


"os" "k8s.io/kubernetes/pkg/api" <ins> "k8s.io/kubernetes/pkg/api/meta" </ins> "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apimachinery/registered" "k8s.io/kubernetes/pkg/kubectl"


} // DiskIsAttached returns if disk is attached to the VM using controllers supported by the plugin. <del> func (vs *VSphere) DiskIsAttached(volPath string, nodeName k8stypes.NodeName) (bool, error) { diskIsAttachedInternal := func(volPath string, nodeName k8stypes.NodeName) (bool, error) { </del> <ins> func (vs *VSphere) DiskIsAttached(volPath string, nodeName k8stypes.NodeName) (bool, string, error) { diskIsAttachedInternal := func(volPath string, nodeName k8stypes.NodeName) (bool, string, error) { </ins> var vSphereInstance string if nodeName == "" { vSphereInstance = vs.hostName


terminating := apiextensions.IsCRDConditionTrue(crd, apiextensions.Terminating) <del> crdInfo, err := r.getOrCreateServingInfoFor(crd) </del> <ins> crdInfo, err := r.getOrCreateServingInfoFor(crd.UID, crd.Name) if apierrors.IsNotFound(err) { r.delegate.ServeHTTP(w, req) return } </ins> if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } <ins> if !hasServedCRDVersion(crdInfo.spec, requestInfo.APIVersion) { r.delegate.ServeHTTP(w, req) return } </ins> verb := strings.ToUpper(requestInfo.Verb) resource := requestInfo.Resource


// Check that request <= limit. limitQuantity, exists := requirements.Limits[resourceName] if exists { <del> // For GPUs, not only requests can't exceed limits, they also can't be lower, i.e. must be equal. </del> <ins> // For non overcommitable resources, not only requests can't exceed limits, they also can't be lower, i.e. must be equal. </ins> if quantity.Cmp(limitQuantity) != 0 && !helper.IsOvercommitAllowed(resourceName) { allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be equal to %s limit", resourceName))) } else if quantity.Cmp(limitQuantity) > 0 { allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be less than or equal to %s limit", resourceName))) } <del> } else if resourceName == core.ResourceNvidiaGPU { allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be equal to %s request", core.ResourceNvidiaGPU))) </del> <ins> } else if !helper.IsOvercommitAllowed(resourceName) { allErrs = append(allErrs, field.Required(limPath, "Limit must be set for non overcommitable resources")) </ins> } }


return nil } <ins> func TestUpgradeServicePreferToDualStack(t *testing.T) { // Create an IPv4 only dual stack control-plane serviceCIDR := "192.168.0.0/24" defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IPv6DualStack, true)() cfg := framework.NewIntegrationTestControlPlaneConfig() _, cidr, err := net.ParseCIDR(serviceCIDR) if err != nil { t.Fatalf("bad cidr: %v", err) } cfg.ExtraConfig.ServiceIPRange = *cidr _, s, closeFn := framework.RunAnAPIServer(cfg) client := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL}) // Wait until the default "kubernetes" service is created. if err = wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) { _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(context.TODO(), "kubernetes", metav1.GetOptions{}) if err != nil && !apierrors.IsNotFound(err) { return false, err } return !apierrors.IsNotFound(err), nil }); err != nil { t.Fatalf("creating kubernetes service timed out") } preferDualStack := v1.IPFamilyPolicyPreferDualStack svc := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: "svc-prefer-dual", }, Spec: v1.ServiceSpec{ Type:           v1.ServiceTypeClusterIP, ClusterIPs:     nil, IPFamilies:     nil, IPFamilyPolicy: &preferDualStack, Ports: []v1.ServicePort{ { Name:       "svc-port-1", Port:       443, TargetPort: intstr.IntOrString{IntVal: 443}, Protocol:   "TCP", }, }, }, } // create the service _, err = client.CoreV1().Services(metav1.NamespaceDefault).Create(context.TODO(), svc, metav1.CreateOptions{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } // validate the service was created correctly if it was not expected to fail svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(context.TODO(), svc.Name, metav1.GetOptions{}) if err != nil { t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err) } if err := validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol}); err != nil { t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err) } // reconfigure the apiserver to be dual-stack closeFn() secondaryServiceCIDR := "2001:db8:1::/48" _, secCidr, err := net.ParseCIDR(secondaryServiceCIDR) if err != nil { t.Fatalf("bad cidr: %v", err) } cfg.ExtraConfig.SecondaryServiceIPRange = *secCidr _, s, closeFn = framework.RunAnAPIServer(cfg) defer closeFn() client = clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL}) // Wait until the default "kubernetes" service is created. if err = wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) { _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(context.TODO(), "kubernetes", metav1.GetOptions{}) if err != nil && !apierrors.IsNotFound(err) { return false, err } return !apierrors.IsNotFound(err), nil }); err != nil { t.Fatalf("creating kubernetes service timed out") } // validate the service was created correctly if it was not expected to fail svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(context.TODO(), svc.Name, metav1.GetOptions{}) if err != nil { t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err) } // service should remain single stack if err = validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol}); err != nil { t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err) } } func TestDowngradeServicePreferToDualStack(t *testing.T) { // Create a dual stack control-plane serviceCIDR := "192.168.0.0/24" secondaryServiceCIDR := "2001:db8:1::/48" defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IPv6DualStack, true)() dualStackCfg := framework.NewIntegrationTestControlPlaneConfig() _, cidr, err := net.ParseCIDR(serviceCIDR) if err != nil { t.Fatalf("bad cidr: %v", err) } dualStackCfg.ExtraConfig.ServiceIPRange = *cidr _, secCidr, err := net.ParseCIDR(secondaryServiceCIDR) if err != nil { t.Fatalf("bad cidr: %v", err) } dualStackCfg.ExtraConfig.SecondaryServiceIPRange = *secCidr _, s, closeFn := framework.RunAnAPIServer(dualStackCfg) client := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL}) // Wait until the default "kubernetes" service is created. if err = wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) { _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(context.TODO(), "kubernetes", metav1.GetOptions{}) if err != nil && !apierrors.IsNotFound(err) { return false, err } return !apierrors.IsNotFound(err), nil }); err != nil { t.Fatalf("creating kubernetes service timed out") } preferDualStack := v1.IPFamilyPolicyPreferDualStack svc := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: "svc-prefer-dual01", }, Spec: v1.ServiceSpec{ Type:           v1.ServiceTypeClusterIP, ClusterIPs:     nil, IPFamilies:     nil, IPFamilyPolicy: &preferDualStack, Ports: []v1.ServicePort{ { Name:       "svc-port-1", Port:       443, TargetPort: intstr.IntOrString{IntVal: 443}, Protocol:   "TCP", }, }, }, } // create the service _, err = client.CoreV1().Services(metav1.NamespaceDefault).Create(context.TODO(), svc, metav1.CreateOptions{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } // validate the service was created correctly if it was not expected to fail svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(context.TODO(), svc.Name, metav1.GetOptions{}) if err != nil { t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err) } if err := validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}); err != nil { t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err) } // reconfigure the apiserver to be sinlge stack closeFn() // reset secondary var emptyCidr net.IPNet dualStackCfg.ExtraConfig.SecondaryServiceIPRange = emptyCidr _, s, closeFn = framework.RunAnAPIServer(dualStackCfg) defer closeFn() client = clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL}) // Wait until the default "kubernetes" service is created. if err = wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) { _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(context.TODO(), "kubernetes", metav1.GetOptions{}) if err != nil && !apierrors.IsNotFound(err) { return false, err } return !apierrors.IsNotFound(err), nil }); err != nil { t.Fatalf("creating kubernetes service timed out") } // validate the service is still there. svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(context.TODO(), svc.Name, metav1.GetOptions{}) if err != nil { t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err) } // service should be single stack if err = validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}); err != nil { t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err) } } </ins>


}) }) <ins> ginkgo.It("should ensure an IP overlapping both IPBlock.CIDR and IPBlock.Except is allowed [Feature:NetworkPolicy]", func() { protocolUDP := v1.ProtocolUDP // Getting podServer's status to get podServer's IP, to create the CIDR with except clause podServerStatus, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(context.TODO(), podServer.Name, metav1.GetOptions{}) if err != nil { framework.ExpectNoError(err, "Error occurred while getting pod status.") } podServerAllowCIDR := fmt.Sprintf("%s/24", podServerStatus.Status.PodIP) podServerIP := fmt.Sprintf("%s/32", podServerStatus.Status.PodIP) // Exclude podServer's IP with an Except clause podServerExceptList := []string{podServerIP} // Create NetworkPolicy which blocks access to podServer with except clause. policyAllowCIDRWithExceptServerPod := &networkingv1.NetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ Namespace: f.Namespace.Name, Name:      "deny-client-a-via-except-cidr-egress-rule", }, Spec: networkingv1.NetworkPolicySpec{ // Apply this policy to the client. PodSelector: metav1.LabelSelector{ MatchLabels: map[string]string{ "pod-name": "client-a", }, }, PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress}, // Allow traffic to only one CIDR block except subnet which includes Server. Egress: []networkingv1.NetworkPolicyEgressRule{ { Ports: []networkingv1.NetworkPolicyPort{ // Allow DNS look-ups { Protocol: &protocolUDP, Port:     &intstr.IntOrString{Type: intstr.Int, IntVal: 53}, }, }, }, { To: []networkingv1.NetworkPolicyPeer{ { IPBlock: &networkingv1.IPBlock{ CIDR:   podServerAllowCIDR, Except: podServerExceptList, }, }, }, }, }, }, } policyAllowCIDRWithExceptServerPodObj, err := f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowCIDRWithExceptServerPod, metav1.CreateOptions{}) framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowCIDRWithExceptServerPod.") ginkgo.By("Creating client-a which should not be able to contact the server.", func() { testCannotConnect(f, f.Namespace, "client-a", service, 80) }) // Create NetworkPolicy which allows access to the podServer using podServer's IP in allow CIDR. policyAllowCIDRServerPod := &networkingv1.NetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ Namespace: f.Namespace.Name, Name:      "allow-client-a-via-cidr-egress-rule", }, Spec: networkingv1.NetworkPolicySpec{ // Apply this policy to the client. PodSelector: metav1.LabelSelector{ MatchLabels: map[string]string{ "pod-name": "client-a", }, }, PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress}, // Allow traffic to only one CIDR block which includes Server. Egress: []networkingv1.NetworkPolicyEgressRule{ { Ports: []networkingv1.NetworkPolicyPort{ // Allow DNS look-ups { Protocol: &protocolUDP, Port:     &intstr.IntOrString{Type: intstr.Int, IntVal: 53}, }, }, }, { To: []networkingv1.NetworkPolicyPeer{ { IPBlock: &networkingv1.IPBlock{ CIDR: podServerIP, }, }, }, }, }, }, } policyAllowCIDRServerPod, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowCIDRServerPod, metav1.CreateOptions{}) framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowCIDRServerPod.") defer cleanupNetworkPolicy(f, policyAllowCIDRServerPod) ginkgo.By("Creating client-a which should now be able to contact the server.", func() { testCanConnect(f, f.Namespace, "client-a", service, 80) }) ginkgo.By("Deleting the network policy with except podServer IP which disallows access to podServer.") cleanupNetworkPolicy(f, policyAllowCIDRWithExceptServerPodObj) ginkgo.By("Creating client-a which should still be able to contact the server after deleting the network policy with except clause.", func() { testCanConnect(f, f.Namespace, "client-a", service, 80) }) // Recreate the NetworkPolicy which contains the podServer's IP in the except list. policyAllowCIDRWithExceptServerPod, err = f.ClientSet.NetworkingV1().NetworkPolicies(f.Namespace.Name).Create(context.TODO(), policyAllowCIDRWithExceptServerPod, metav1.CreateOptions{}) framework.ExpectNoError(err, "Error occurred while creating policy: policyAllowCIDRWithExceptServerPod.") defer cleanupNetworkPolicy(f, policyAllowCIDRWithExceptServerPod) ginkgo.By("Creating client-a which should still be able to contact the server after recreating the network policy with except clause.", func() { testCanConnect(f, f.Namespace, "client-a", service, 80) }) }) </ins> ginkgo.It("should enforce policies to check ingress and egress policies can be controlled independently based on PodSelector [Feature:NetworkPolicy]", func() { var serviceA, serviceB *v1.Service var podA, podB *v1.Pod


<ins> /* Copyright 2017 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 util import ( "os" "reflect" "strings" "testing" "time" "github.com/google/go-cmp/cmp" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kubetypes "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/informers" csitrans "k8s.io/csi-translation-lib" fakeframework "k8s.io/kubernetes/pkg/scheduler/framework/fake" "k8s.io/kubernetes/pkg/volume/csimigration" "k8s.io/kubernetes/pkg/volume/fc" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/kubernetes/fake" utiltesting "k8s.io/client-go/util/testing" "k8s.io/kubernetes/pkg/volume" volumetest "k8s.io/kubernetes/pkg/volume/testing" ) const ( testHostName      = "test-hostname" socketPath        = "/var/run/kmsplugin" migratedVolume    = "migrated-volume-name" nonMigratedVolume = "non-migrated-volume-name" testNodeName      = "test-node-name" ) var ( dirOrCreate = v1.HostPathType(v1.HostPathDirectoryOrCreate) nodeName    = kubetypes.NodeName(testNodeName) hostPath    = &v1.HostPathVolumeSource{ Path: socketPath, Type: &dirOrCreate, } migratedObjectReference    = v1.ObjectReference{Namespace: "default", Name: "migrated-pvc"} nonMigratedObjectReference = v1.ObjectReference{Namespace: "default", Name: "non-migrated-pvc"} fsVolumeMode               = new(v1.PersistentVolumeMode) ) type vaTest struct { desc                 string createNodeName       kubetypes.NodeName pod                  *v1.Pod wantVolume           *v1.Volume wantPersistentVolume *v1.PersistentVolume wantErrorMessage     string } func Test_CreateVolumeSpec(t *testing.T) { for _, test := range []vaTest{ { desc:           "inline volume type that does not support csi migration", createNodeName: nodeName, pod: &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:      "kube-apiserver", Namespace: "default", }, Spec: v1.PodSpec{ Volumes: []v1.Volume{ { Name: migratedVolume, VolumeSource: v1.VolumeSource{ HostPath: hostPath, }, }, }, }, }, wantVolume: &v1.Volume{ Name: migratedVolume, VolumeSource: v1.VolumeSource{ HostPath: hostPath, }, }, }, { desc:           "inline volume type that supports csi migration", createNodeName: nodeName, pod: &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:      "kube-apiserver", Namespace: "default", }, Spec: v1.PodSpec{ Volumes: []v1.Volume{ { Name: migratedVolume, VolumeSource: v1.VolumeSource{ GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ PDName:    "test-disk", FSType:    "ext4", Partition: 0, ReadOnly:  false, }, }, }, }, }, }, wantPersistentVolume: &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: "pd.csi.storage.gke.io-test-disk", }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{ CSI: &v1.CSIPersistentVolumeSource{ Driver:           "pd.csi.storage.gke.io", VolumeHandle:     "projects/UNSPECIFIED/zones/UNSPECIFIED/disks/test-disk", FSType:           "ext4", ReadOnly:         false, VolumeAttributes: map[string]string{"partition": ""}, }, }, AccessModes: []v1.PersistentVolumeAccessMode{"ReadWriteOnce"}, VolumeMode:  fsVolumeMode, }, }, }, { desc:           "pv type that does not support csi migration", createNodeName: nodeName, pod: &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:      "kube-apiserver", Namespace: "default", }, Spec: v1.PodSpec{ Volumes: []v1.Volume{ { Name: nonMigratedVolume, VolumeSource: v1.VolumeSource{ PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ ClaimName: "non-migrated-pvc", ReadOnly:  false, }, }, }, }, }, }, wantPersistentVolume: &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: nonMigratedVolume, }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{ ScaleIO: &v1.ScaleIOPersistentVolumeSource{}, }, ClaimRef: &nonMigratedObjectReference, }, }, }, { desc:           "pv type that supports csi migration", createNodeName: nodeName, pod: &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:      "kube-apiserver", Namespace: "default", }, Spec: v1.PodSpec{ Volumes: []v1.Volume{ { Name: migratedVolume, VolumeSource: v1.VolumeSource{ PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ ClaimName: "migrated-pvc", ReadOnly:  false, }, }, }, }, }, }, wantPersistentVolume: &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: migratedVolume, }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{ CSI: &v1.CSIPersistentVolumeSource{ Driver:           "pd.csi.storage.gke.io", VolumeHandle:     "projects/UNSPECIFIED/zones/UNSPECIFIED/disks/test-disk", FSType:           "ext4", ReadOnly:         false, VolumeAttributes: map[string]string{"partition": ""}, }, }, ClaimRef: &migratedObjectReference, }, }, }, { desc:           "CSINode not found for a volume type that supports csi migration", createNodeName: kubetypes.NodeName("another-node"), pod: &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:      "kube-apiserver", Namespace: "default", }, Spec: v1.PodSpec{ Volumes: []v1.Volume{ { Name: migratedVolume, VolumeSource: v1.VolumeSource{ PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ ClaimName: "migrated-pvc", ReadOnly:  false, }, }, }, }, }, }, wantErrorMessage: "csiNode "another-node" not found", }, } { t.Run(test.desc, func(t *testing.T) { plugMgr, intreeToCSITranslator, csiTranslator, pvLister, pvcLister := setup(testNodeName, t) actualSpec, err := CreateVolumeSpec(test.pod.Spec.Volumes[0], test.pod, test.createNodeName, plugMgr, pvcLister, pvLister, intreeToCSITranslator, csiTranslator) if actualSpec == nil && (test.wantPersistentVolume != nil || test.wantVolume != nil) { t.Errorf("got volume spec is nil") } if (len(test.wantErrorMessage) > 0 && err == nil) || (err != nil && !strings.Contains(err.Error(), test.wantErrorMessage)) { t.Errorf("got err %v, want err with message %v", err, test.wantErrorMessage) } if test.wantPersistentVolume != nil { if actualSpec.PersistentVolume == nil { t.Errorf("gotVolumeWithCSIMigration is nil") } gotVolumeWithCSIMigration := *actualSpec.PersistentVolume if gotVolumeWithCSIMigration.Name != test.wantPersistentVolume.Name { t.Errorf("got volume name is %v, want volume name is %v", gotVolumeWithCSIMigration.Name, test.wantPersistentVolume.Name) } if !reflect.DeepEqual(gotVolumeWithCSIMigration.Spec, test.wantPersistentVolume.Spec) { t.Errorf("got volume.Spec and want.Spec diff is %s", cmp.Diff(gotVolumeWithCSIMigration.Spec, test.wantPersistentVolume.Spec)) } } if test.wantVolume != nil { if actualSpec.Volume == nil { t.Errorf("gotVolume is nil") } gotVolume := *actualSpec.Volume if !reflect.DeepEqual(gotVolume, *test.wantVolume) { t.Errorf("got volume and want diff is %s", cmp.Diff(gotVolume, test.wantVolume)) } } }) } } func setup(nodeName string, t *testing.T) (*volume.VolumePluginMgr, csimigration.PluginManager, csitrans.CSITranslator, fakeframework.PersistentVolumeLister, fakeframework.PersistentVolumeClaimLister) { tmpDir, err := utiltesting.MkTmpdir("csi-test") if err != nil { t.Fatalf("can't make a temp dir: %v", err) } defer os.RemoveAll(tmpDir) *fsVolumeMode = v1.PersistentVolumeFilesystem csiTranslator := csitrans.New() intreeToCSITranslator := csimigration.NewPluginManager(csiTranslator, utilfeature.DefaultFeatureGate) kubeClient := fake.NewSimpleClientset() factory := informers.NewSharedInformerFactory(kubeClient, time.Minute) csiDriverInformer := factory.Storage().V1().CSIDrivers() csiDriverLister := csiDriverInformer.Lister() volumeAttachmentInformer := factory.Storage().V1().VolumeAttachments() volumeAttachmentLister := volumeAttachmentInformer.Lister() plugMgr := &volume.VolumePluginMgr{} fakeAttachDetachVolumeHost := volumetest.NewFakeAttachDetachVolumeHostWithCSINodeName(t, tmpDir, kubeClient, fc.ProbeVolumePlugins(), nodeName, csiDriverLister, volumeAttachmentLister, ) plugMgr.Host = fakeAttachDetachVolumeHost pvLister := fakeframework.PersistentVolumeLister{ { ObjectMeta: metav1.ObjectMeta{Name: migratedVolume}, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{ GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ PDName:    "test-disk", FSType:    "ext4", Partition: 0, ReadOnly:  false, }, }, ClaimRef: &migratedObjectReference, }, }, { ObjectMeta: metav1.ObjectMeta{Name: nonMigratedVolume}, Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{ ScaleIO: &v1.ScaleIOPersistentVolumeSource{}, }, ClaimRef: &nonMigratedObjectReference, }, }, } pvcLister := fakeframework.PersistentVolumeClaimLister{ { ObjectMeta: metav1.ObjectMeta{Name: "migrated-pvc", Namespace: "default"}, Spec:       v1.PersistentVolumeClaimSpec{VolumeName: migratedVolume}, Status: v1.PersistentVolumeClaimStatus{ Phase: v1.ClaimBound, }, }, { ObjectMeta: metav1.ObjectMeta{Name: "non-migrated-pvc", Namespace: "default"}, Spec:       v1.PersistentVolumeClaimSpec{VolumeName: nonMigratedVolume}, Status: v1.PersistentVolumeClaimStatus{ Phase: v1.ClaimBound, }, }, } return plugMgr, intreeToCSITranslator, csiTranslator, pvLister, pvcLister } </ins>


} func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) { <del> return IsNotMountPoint(mounter, dir) </del> <ins> return isNotMountPoint(mounter, dir) </ins> } // IsLikelyNotMountPoint determines if a directory is not a mountpoint.


test/e2e/network/service_latency.go: "should not be very high" test/e2e/node/events.go: "should be sent by kubelets and the scheduler about pods scheduling and running" test/e2e/node/pods.go: "should be submitted and removed" <ins> test/e2e/node/pods.go: "should be submitted and removed" </ins> test/e2e/node/pre_stop.go: "should call prestop when killing a pod" test/e2e/scheduling/predicates.go: "validates resource limits of pods that are allowed to run" test/e2e/scheduling/predicates.go: "validates that NodeSelector is respected if not matching"


if [[ "${KUBE_PROXY_DAEMONSET:-}" == "true" && "${master}" != "true" ]]; then # Add kube-proxy daemonset label to node to avoid situation during cluster # upgrade/downgrade when there are two instances of kube-proxy running on a node. <del> # TODO(liggitt): drop beta.kubernetes.io/kube-proxy-ds-ready in 1.16 node_labels="node.kubernetes.io/kube-proxy-ds-ready=true,beta.kubernetes.io/kube-proxy-ds-ready=true" </del> <ins> node_labels="node.kubernetes.io/kube-proxy-ds-ready=true" </ins> fi if [[ -n "${NODE_LABELS:-}" ]]; then node_labels="${node_labels:+${node_labels},}${NODE_LABELS}"


execAffinityTestForLBService(f, cs, svc) }) <del> // TODO: Get rid of [DisabledForLargeClusters] tag when issue #56138 is fixed. </del> // [LinuxOnly]: Windows does not support session affinity. <del> ginkgo.It("should be able to switch session affinity for LoadBalancer service with ESIPP on [Slow] [DisabledForLargeClusters] [LinuxOnly]", func() { </del> <ins> ginkgo.It("should be able to switch session affinity for LoadBalancer service with ESIPP on [Slow] [LinuxOnly]", func() { </ins> // L4 load balancer affinity `ClientIP` is not supported on AWS ELB. e2eskipper.SkipIfProviderIs("aws")


// api.Registry.GroupOrDie(v1.GroupName).GroupVersions[0].String() is changed // to "v1"? <del> runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" </del> _ "k8s.io/kubernetes/pkg/apis/core/install" "k8s.io/kubernetes/pkg/features" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"


github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 github.com/onsi/ginkgo/v2 v2.9.1 github.com/onsi/gomega v1.27.4 <del> github.com/opencontainers/runc v1.1.4 </del> <ins> github.com/opencontainers/runc v1.1.5 </ins> github.com/opencontainers/selinux v1.10.0 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0


return "", err } <ins> // try and get canonical path for disk and if we can't throw error vmDiskPath, err = getcanonicalVolumePath(ctx, vm.Datacenter, vmDiskPath) if err != nil { klog.Errorf("failed to get canonical path for %s on node %s: %v", vmDiskPath, convertToString(nodeName), err) return "", err } </ins> diskUUID, err = vm.AttachDisk(ctx, vmDiskPath, &vclib.VolumeOptions{SCSIControllerType: vclib.PVSCSIControllerType, StoragePolicyName: storagePolicyName}) if err != nil { klog.Errorf("Failed to attach disk: %s for node: %s. err: +%v", vmDiskPath, convertToString(nodeName), err)


} func (sched *Scheduler) updatePodInSchedulingQueue(oldObj, newObj interface{}) { <del> pod := newObj.(*v1.Pod) if sched.skipPodUpdate(pod) { </del> <ins> oldPod, newPod := oldObj.(*v1.Pod), newObj.(*v1.Pod) // Bypass update event that carries identical objects; otherwise, a duplicated // Pod may go through scheduling and cause unexpected behavior (see #96071). if oldPod.ResourceVersion == newPod.ResourceVersion { </ins> return } <del> if err := sched.SchedulingQueue.Update(oldObj.(*v1.Pod), pod); err != nil { </del> <ins> if sched.skipPodUpdate(newPod) { return } if err := sched.SchedulingQueue.Update(oldPod, newPod); err != nil { </ins> utilruntime.HandleError(fmt.Errorf("unable to update %T: %v", newObj, err)) } }


ExitCode: 1, }, }, <del> map[string]error{}, []api.ContainerStatus{}, map[string]api.ContainerState{ </del> <ins> reasons:     map[string]error{}, oldStatuses: []api.ContainerStatus{}, expectedState: map[string]api.ContainerState{ </ins> "running": {Running: &api.ContainerStateRunning{ StartedAt: unversioned.NewTime(testTimestamp), }}, }, <del> map[string]api.ContainerState{ </del> <ins> expectedLastTerminationState: map[string]api.ContainerState{ </ins> "running": {Terminated: &api.ContainerStateTerminated{ ExitCode:    1, ContainerID: emptyContainerID,


procGetNetworkParams = iphlpapidll.MustFindProc("GetNetworkParams") ) <ins> func fileExists(filename string) (bool, error) { stat, err := os.Stat(filename) if os.IsNotExist(err) { return false, nil } if err != nil { return false, err } return stat.Mode().IsRegular(), nil } </ins> func getHostDNSConfig(resolverConfig string) (*runtimeapi.DNSConfig, error) { <del> if resolverConfig != "" && resolverConfig != hostResolvConf { err := fmt.Errorf(`Unexpected resolver config value: "%s". Expected "" or "%s".`, resolverConfig, hostResolvConf) </del> <ins> if resolverConfig == "" { // This handles "" by returning defaults. return getDNSConfig(resolverConfig) } isFile, err := fileExists(resolverConfig) if err != nil { err = fmt.Errorf(`Unexpected error while getting os.Stat for "%s" resolver config. Error: %w`, resolverConfig, err) </ins> klog.ErrorS(err, "Cannot get host DNS Configuration.") return nil, err } <ins> if isFile { // Get the DNS config from a resolv.conf-like file. return getDNSConfig(resolverConfig) } </ins> <del> var ( hostDNS, hostSearch []string err                 error ) </del> <ins> if resolverConfig != hostResolvConf { err := fmt.Errorf(`Unexpected resolver config value: "%s". Expected "", "%s", or a path to an existing resolv.conf file.`, resolverConfig, hostResolvConf) klog.ErrorS(err, "Cannot get host DNS Configuration.") return nil, err } // If we get here, the resolverConfig == hostResolvConf and that is not actually a file, so // it means to use the host settings. </ins> // Get host DNS settings <del> if resolverConfig == hostResolvConf { hostDNS, err = getDNSServerList() if err != nil { err = fmt.Errorf("Could not get the host's DNS Server List. Error: %w", err) klog.ErrorS(err, "Encountered error while getting host's DNS Server List.") return nil, err } hostSearch, err = getDNSSuffixList() if err != nil { err = fmt.Errorf("Could not get the host's DNS Suffix List. Error: %w", err) klog.ErrorS(err, "Encountered error while getting host's DNS Suffix List.") return nil, err } </del> <ins> hostDNS, err := getDNSServerList() if err != nil { err = fmt.Errorf("Could not get the host's DNS Server List. Error: %w", err) klog.ErrorS(err, "Encountered error while getting host's DNS Server List.") return nil, err } hostSearch, err := getDNSSuffixList() if err != nil { err = fmt.Errorf("Could not get the host's DNS Suffix List. Error: %w", err) klog.ErrorS(err, "Encountered error while getting host's DNS Suffix List.") return nil, err </ins> } return &runtimeapi.DNSConfig{ Servers:  hostDNS,


kubeCfg.PodInfraContainerImage, float32(kubeCfg.RegistryPullQPS), int(kubeCfg.RegistryBurst), <del> containerLogsDir, </del> <ins> ContainerLogsDir, </ins> kubeDeps.OSInterface, klet.networkPlugin, klet,


} return nil } <ins> // ClearEntriesForPortNAT uses the conntrack tool to delete the contrack entries // for connections specified by the {dest IP, port} pair. // Known issue: // https://github.com/kubernetes/kubernetes/issues/59368 func ClearEntriesForPortNAT(execer exec.Interface, dest string, port int, protocol v1.Protocol) error { if port <= 0 { return fmt.Errorf("Wrong port number. The port number must be greater then zero") } parameters := parametersWithFamily(utilnet.IsIPv6String(dest), "-D", "-p", protoStr(protocol), "--dport", strconv.Itoa(port), "--dst-nat", dest) err := Exec(execer, parameters...) if err != nil && !strings.Contains(err.Error(), NoConnectionToDelete) { return fmt.Errorf("error deleting conntrack entries for UDP port: %d, error: %v", port, err) } return nil } </ins>


importpath = "k8s.io/kube-aggregator/pkg/apiserver", deps = [ "//vendor/github.com/golang/glog:go_default_library", <del> "//vendor/k8s.io/api/core/v1:go_default_library", </del> "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",


if len(psp.Spec.AllowedFlexVolumes) > 0 { w.Write(LEVEL_1, "Allowed FlexVolume Types:t%sn", flexVolumesToString(psp.Spec.AllowedFlexVolumes)) } <ins> if len(psp.Spec.AllowedUnsafeSysctls) > 0 { w.Write(LEVEL_1, "Allowed Unsafe Sysctls:t%sn", sysctlsToString(psp.Spec.AllowedUnsafeSysctls)) } if len(psp.Spec.ForbiddenSysctls) > 0 { w.Write(LEVEL_1, "Forbidden Sysctls:t%sn", sysctlsToString(psp.Spec.ForbiddenSysctls)) } </ins> w.Write(LEVEL_1, "Allow Host Network:t%tn", psp.Spec.HostNetwork) w.Write(LEVEL_1, "Allow Host Ports:t%sn", hostPortRangeToString(psp.Spec.HostPorts)) w.Write(LEVEL_1, "Allow Host PID:t%tn", psp.Spec.HostPID)


// applyPlatformSpecificDockerConfig applies platform-specific configurations to a dockertypes.ContainerCreateConfig struct. // The containerCleanupInfo struct it returns will be passed as is to performPlatformSpecificContainerCleanup <del> // after either: //   * the container creation has failed //   * the container has been successfully started //   * the container has been removed // whichever happens first. </del> <ins> // after either the container creation has failed or the container has been removed. </ins> func (ds *dockerService) applyPlatformSpecificDockerConfig(*runtimeapi.CreateContainerRequest, *dockertypes.ContainerCreateConfig) (*containerCleanupInfo, error) { return nil, nil } // performPlatformSpecificContainerCleanup is responsible for doing any platform-specific cleanup <del> // after either: //   * the container creation has failed //   * the container has been successfully started //   * the container has been removed // whichever happens first. // Any errors it returns are simply logged, but do not prevent the container from being started or // removed. </del> <ins> // after either the container creation has failed or the container has been removed. </ins> func (ds *dockerService) performPlatformSpecificContainerCleanup(cleanupInfo *containerCleanupInfo) (errors []error) { return }


utilerrors "k8s.io/apimachinery/pkg/util/errors" serviceapi "k8s.io/kubernetes/pkg/api/v1/service" <ins> "github.com/Azure/azure-sdk-for-go/arm/compute" </ins> "github.com/Azure/azure-sdk-for-go/arm/network" "github.com/Azure/go-autorest/autorest/to" "github.com/golang/glog"


fs.IntVar(&s.HardPodAffinitySymmetricWeight, "hard-pod-affinity-symmetric-weight", api.DefaultHardPodAffinitySymmetricWeight, "RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule corresponding "+ "to every RequiredDuringScheduling affinity rule. --hard-pod-affinity-symmetric-weight represents the weight of implicit PreferredDuringScheduling affinity rule.") <ins> fs.MarkDeprecated("hard-pod-affinity-symmetric-weight", "This option was moved to the policy configuration file") </ins> fs.StringVar(&s.FailureDomains, "failure-domains", api.DefaultFailureDomains, "Indicate the "all topologies" set for an empty topologyKey when it's used for PreferredDuringScheduling pod anti-affinity.") fs.MarkDeprecated("failure-domains", "Doesn't have any effect. Will be removed in future version.") leaderelection.BindFlags(&s.LeaderElection, fs)


PLEASE NOTE: This document applies to the HEAD of the source tree
 If you are using a released version of Kubernetes, you should refer to the docs that go with that version. Documentation for other releases can be found at [releases.k8s.io](http://releases.k8s.io).  --   # Generic Configuration Object ## Abstract This proposal proposes a new API resource, `ConfigMap`, that stores data used for the configuration of applications deployed on `Kubernetes`. The main focus points of this proposal are: * Dynamic distribution of configuration data to deployed applications. * Encapsulate configuration information and simplify `Kubernetes` deployments. * Create a flexible configuration model for `Kubernetes`. ## Motivation A `Secret`-like API resource is needed to store configuration data that pods can consume. Goals of this design: 1.  Describe a `ConfigMap` API resource 2.  Describe the semantics of consuming `ConfigMap` as environment variables 3.  Describe the semantics of consuming `ConfigMap` as files in a volume ## Use Cases 1. As a user, I want to be able to consume configuration data as environment variables 2. As a user, I want to be able to consume configuration data as files in a volume 3. As a user, I want my view of configuration data in files to be eventually consistent with changes to the data ### Consuming `ConfigMap` as Environment Variables Many programs read their configuration from environment variables.  `ConfigMap` should be possible to consume in environment variables.  The rough series of events for consuming `ConfigMap` this way is: 1. A `ConfigMap` object is created 2. A pod that consumes the configuration data via environment variables is created 3. The pod is scheduled onto a node 4. The kubelet retrieves the `ConfigMap` resource(s) referenced by the pod and starts the container processes with the appropriate data in environment variables ### Consuming `ConfigMap` in Volumes Many programs read their configuration from configuration files.  `ConfigMap` should be possible to consume in a volume.  The rough series of events for consuming `ConfigMap` this way is: 1. A `ConfigMap` object is created 2. A new pod using the `ConfigMap` via the volume plugin is created 3. The pod is scheduled onto a node 4. The Kubelet creates an instance of the volume plugin and calls its `Setup()` method 5. The volume plugin retrieves the `ConfigMap` resource(s) referenced by the pod and projects the appropriate data into the volume ### Consuming `ConfigMap`  Updates Any long-running system has configuration that is mutated over time.  Changes made to configuration data must be made visible to pods consuming data in volumes so that they can respond to those changes. The `resourceVersion` of the `ConfigMap` object will be updated by the API server every time the object is modified.  After an update, modifications will be made visible to the consumer container: 1. A `ConfigMap` object is created 2. A new pod using the `ConfigMap` via the volume plugin is created 3. The pod is scheduled onto a node 4. During the sync loop, the Kubelet creates an instance of the volume plugin and calls its `Setup()` method 5. The volume plugin retrieves the `ConfigMap` resource(s) referenced by the pod and projects the appropriate data into the volume 6. The `ConfigMap` referenced by the pod is updated 7. During the next iteration of the `syncLoop`, the Kubelet creates an instance of the volume plugin and calls its `Setup()` method 8. The volume plugin projects the updated data into the volume atomically It is the consuming pod's responsibility to make use of the updated data once it is made visible. Because environment variables cannot be updated without restarting a container, configuration data consumed in environment variables will not be updated. ### Advantages * Easy to consume in pods; consumer-agnostic * Configuration data is persistent and versioned * Consumers of configuration data in volumes can respond to changes in the data ## Proposed Design ### API Resource The `ConfigMap` resource will be added to the `extensions` API Group: ```go package api // ConfigMap holds configuration data for pods to consume. type ConfigMap struct { TypeMeta   `json:",inline"` ObjectMeta `json:"metadata,omitempty"` // Data contains the configuration data.  Each key must be a valid DNS_SUBDOMAIN or leading // dot followed by valid DNS_SUBDOMAIN. Data map[string]string `json:"data,omitempty"` } type ConfigMapList struct { TypeMeta `json:",inline"` ListMeta `json:"metadata,omitempty"` Items []ConfigMap `json:"items"` } ``` A `Registry` implementation for `ConfigMap` will be added to `pkg/registry/configmap`. ### Environment Variables The `EnvVarSource` will be extended with a new selector for `ConfigMap`: ```go package api // EnvVarSource represents a source for the value of an EnvVar. type EnvVarSource struct { // other fields omitted // Specifies a ConfigMap key ConfigMap *ConfigMapSelector `json:"configMap,omitempty"` } // ConfigMapSelector selects a key of a ConfigMap. type ConfigMapSelector struct { // The name of the ConfigMap to select a key from. ConfigMapName string `json:"configMapName"` // The key of the ConfigMap to select. Key string `json:"key"` } ``` ### Volume Source A new `ConfigMapVolumeSource` type of volume source containing the `ConfigMap` object will be added to the `VolumeSource` struct in the API: ```go package api type VolumeSource struct { // other fields omitted ConfigMap *ConfigMapVolumeSource `json:"configMap,omitempty"` } // ConfigMapVolumeSource represents a volume that holds configuration data type ConfigMapVolumeSource struct { // A list of configuration data keys to project into the volume in files Files []ConfigMapVolumeFile `json:"files"` } // ConfigMapVolumeFile represents a single file containing configuration data type ConfigMapVolumeFile struct { ConfigMapSelector `json:",inline"` // The relative path name of the file to be created. // Must not be absolute or contain the '..' path. Must be utf-8 encoded. // The first item of the relative path must not start with '..' Path string `json:"path"` } ``` **Note:** The update logic used in the downward API volume plug-in will be extracted and re-used in the volume plug-in for `ConfigMap`. ## Examples #### Consuming `ConfigMap` as Environment Variables ```yaml apiVersion: extensions/v1beta1 kind: ConfigMap metadata: name: etcd-env-config data: number_of_members: 1 initial_cluster_state: new initial_cluster_token: DUMMY_ETCD_INITIAL_CLUSTER_TOKEN discovery_token: DUMMY_ETCD_DISCOVERY_TOKEN discovery_url: http://etcd-discovery:2379 etcdctl_peers: http://etcd:2379 ``` This pod consumes the `ConfigMap` as environment variables: ```yaml apiVersion: v1 kind: Pod metadata: name: config-env-example spec: containers: - name: etcd image: openshift/etcd-20-centos7 ports: - containerPort: 2379 protocol: TCP - containerPort: 2380 protocol: TCP env: - name: ETCD_NUM_MEMBERS valueFrom: configMap: configMapName: etcd-env-config key: number_of_members - name: ETCD_INITIAL_CLUSTER_STATE valueFrom: configMap: configMapName: etcd-env-config key: initial_cluster_state - name: ETCD_DISCOVERY_TOKEN valueFrom: configMap: configMapName: etcd-env-config key: discovery_token - name: ETCD_DISCOVERY_URL valueFrom: configMap: configMapName: etcd-env-config key: discovery_url - name: ETCDCTL_PEERS valueFrom: configMap: configMapName: etcd-env-config key: etcdctl_peers ``` ### Consuming `ConfigMap` as Volumes `redis-volume-config` is intended to be used as a volume containing a config file: ```yaml apiVersion: extensions/v1beta1 kind: ConfigMap metadata: name: redis-volume-config data: redis.conf: "pidfile /var/run/redis.pidnport6379ntcp-backlog 511n databases 1ntimeout 0n" ``` The following pod consumes the `redis-volume-config` in a volume: ```yaml apiVersion: v1 kind: Pod metadata: name: config-volume-example spec: containers: - name: redis image: kubernetes/redis command: "redis-server /mnt/config-map/etc/redis.conf" ports: - containerPort: 6379 volumeMounts: - name: config-map-volume mountPath: /mnt/config-map volumes: - name: config-map-volume configMap: files: - path: "etc/redis.conf" configMapName: redis-volume-config key: redis.conf ``` ### Future Improvements In the future, we may add the ability to specify an init-container that can watch the volume contents for updates and respond to changes when they occur.  [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/proposals/configmap.md?pixel)]()


// Run begins watching and syncing daemon sets. func (dsc *DaemonSetsController) Run(workers int, stopCh <-chan struct{}) { defer util.HandleCrash() <ins> glog.Infof("Starting Daemon Sets controller manager") controller.SyncAllPodsWithStore(dsc.kubeClient, dsc.podStore.Store) </ins> go dsc.dsController.Run(stopCh) go dsc.podController.Run(stopCh) go dsc.nodeController.Run(stopCh)


}) It("should write files of various sizes, verify size, validate content", func() { <del> fileSizes := []int64{1 * framework.MiB, 100 * framework.MiB} </del> <ins> fileSizes := []int64{fileSizeSmall, fileSizeMedium} </ins> fsGroup := int64(1234) podSec := v1.PodSecurityContext{ FSGroup: &fsGroup,


(disk.ManagedDisk != nil && diskURI != "" && strings.EqualFold(*disk.ManagedDisk.ID, diskURI)) { // found the disk klog.V(2).Infof("azureDisk - detach disk: name %q uri %q", diskName, diskURI) <del> disks[i].ToBeDetached = to.BoolPtr(true) </del> <ins> if strings.EqualFold(as.cloud.Environment.Name, "AZURESTACKCLOUD") { disks = append(disks[:i], disks[i+1:]...) } else { disks[i].ToBeDetached = to.BoolPtr(true) } </ins> bFoundDisk = true break }


klog.Errorf("cannot convert to *v1.Node: %v", t) return } <ins> klog.V(3).Infof("delete event for node %q", node.Name) </ins> // NOTE: Updates must be written to scheduler cache before invalidating // equivalence cache, because we could snapshot equivalence cache after the // invalidation and then snapshot the cache itself. If the cache is


package fake <ins> import ( "fmt" "k8s.io/apimachinery/pkg/util/rand" ) </ins> const ( <del> defaultUnixEndpoint = "unix:///tmp/kubelet_remote.sock" </del> <ins> defaultUnixEndpoint = "unix:///tmp/kubelet_remote_%v.sock" </ins> ) // GenerateEndpoint generates a new unix socket server of grpc server. func GenerateEndpoint() (string, error) { <del> return defaultUnixEndpoint, nil </del> <ins> // use random int be a part fo file name return fmt.Sprintf(defaultUnixEndpoint, rand.Int()), nil </ins> }


return true, errors.New("not implemented") } <ins> func (m *execMounter) EvalHostSymlinks(pathname string) (string, error) { return "", errors.New("not implemented") } </ins> func (mounter *execMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) { return subPath.Path, nil, nil }


Description: The command 'kubectl version' MUST return the major, minor versions,  GitCommit, etc of the Client and the Server that the kubectl is configured to connect to. */ framework.ConformanceIt("should check is all data is printed ", func() { <del> version := framework.RunKubectlOrDie(ns, "version") requiredItems := []string{"Client Version:", "Server Version:", "Major:", "Minor:", "GitCommit:"} </del> <ins> versionString := framework.RunKubectlOrDie(ns, "version") // we expect following values for: Major -> digit, Minor -> numeric followed by an optional '+',  GitCommit -> alphanumeric requiredItems := []string{"Client Version: ", "Server Version: "} </ins> for _, item := range requiredItems { <del> if !strings.Contains(version, item) { framework.Failf("Required item %s not found in %s", item, version) </del> <ins> if matched, _ := regexp.MatchString(item+`version.Info{Major:"d", Minor:"d++?", GitVersion:"vd.d+.[dw-.+]+", GitCommit:"[0-9a-f]+"`, versionString); !matched { framework.Failf("Item %s value is not valid in %sn", item, versionString) </ins> } } })