{"action":"created","comment":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/76325149","id":76325149,"diff_hunk":"@@ -629,977 +581,117 @@ function kube::build::run_build_command() {\n \n   # Clean up container from any previous run\n   kube::build::destroy_container \"${KUBE_BUILD_CONTAINER_NAME}\"\n-  \"${docker_cmd[@]}\" \"$@\"\n+  \"${docker_cmd[@]}\" \"${cmd[@]}\"\n   kube::build::destroy_container \"${KUBE_BUILD_CONTAINER_NAME}\"\n }\n \n-# Test if the output directory is remote (and can only be accessed through\n-# docker) or if it is \"local\" and we can access the output without going through\n-# docker.\n-function kube::build::is_output_remote() {\n-  rm -f \"${LOCAL_OUTPUT_SUBPATH}/test_for_remote\"\n-  kube::build::run_build_command touch \"${REMOTE_OUTPUT_BINPATH}/test_for_remote\"\n-\n-  [[ ! -e \"${LOCAL_OUTPUT_BINPATH}/test_for_remote\" ]]\n-}\n-\n-# If the Docker server is remote, copy the results back out.\n-function kube::build::copy_output() {\n-  if kube::build::is_output_remote; then\n-    # At time of this code, docker cp does not work when copying from a volume.\n-    # As a workaround, the binaries are first copied to a local filesystem,\n-    # /tmp, then docker cp'd to the local binaries output directory.\n-    # The fix for the volume bug has been accepted and once it's widely\n-    # deployed the code below should be simplified to a simple docker cp\n-    # Bug: https://github.com/docker/docker/pull/8509\n-    local -a docker_run_opts=(\n-      \"--name=${KUBE_BUILD_CONTAINER_NAME}\"\n-      \"--user=$(id -u):$(id -g)\"\n-      \"${DOCKER_MOUNT_ARGS[@]}\"\n-      -d\n-    )\n-\n-    local -ra docker_cmd=(\n-      \"${DOCKER[@]}\" run \"${docker_run_opts[@]}\" \"${KUBE_BUILD_IMAGE}\"\n-    )\n-\n-    kube::log::status \"Syncing back _output/dockerized/bin directory from remote Docker\"\n-    rm -rf \"${LOCAL_OUTPUT_BINPATH}\"\n-    mkdir -p \"${LOCAL_OUTPUT_BINPATH}\"\n-    rm -f \"${THIS_PLATFORM_BIN}\"\n-    ln -s \"${LOCAL_OUTPUT_BINPATH}\" \"${THIS_PLATFORM_BIN}\"\n-\n-    kube::build::destroy_container \"${KUBE_BUILD_CONTAINER_NAME}\"\n-    \"${docker_cmd[@]}\" bash -c \"cp -r ${REMOTE_OUTPUT_BINPATH} /tmp/bin;touch /tmp/finished;rm /tmp/bin/test_for_remote;/bin/sleep 600\" > /dev/null 2>&1\n-\n-    # Wait until binaries have finished coppying\n-    count=0\n-    while true;do\n-      if \"${DOCKER[@]}\" cp \"${KUBE_BUILD_CONTAINER_NAME}:/tmp/finished\" \"${LOCAL_OUTPUT_BINPATH}\" > /dev/null 2>&1;then\n-        \"${DOCKER[@]}\" cp \"${KUBE_BUILD_CONTAINER_NAME}:/tmp/bin\" \"${LOCAL_OUTPUT_SUBPATH}\"\n-        break;\n-      fi\n-\n-      let count=count+1\n-      if [[ $count -eq 60 ]]; then\n-        # break after 5m\n-        kube::log::error \"Timed out waiting for binaries...\"\n-        break\n-      fi\n-      sleep 5\n-    done\n-\n-    \"${DOCKER[@]}\" rm -f -v \"${KUBE_BUILD_CONTAINER_NAME}\" >/dev/null 2>&1 || true\n-  else\n-    kube::log::status \"Output directory is local.  No need to copy results out.\"\n-  fi\n-}\n-\n-# ---------------------------------------------------------------------------\n-# Build final release artifacts\n-function kube::release::clean_cruft() {\n-  # Clean out cruft\n-  find ${RELEASE_STAGE} -name '*~' -exec rm {} \\;\n-  find ${RELEASE_STAGE} -name '#*#' -exec rm {} \\;\n-  find ${RELEASE_STAGE} -name '.DS*' -exec rm {} \\;\n-}\n-\n-function kube::release::package_hyperkube() {\n-  # If we have these variables set then we want to build all docker images.\n-  if [[ -n \"${KUBE_DOCKER_IMAGE_TAG-}\" && -n \"${KUBE_DOCKER_REGISTRY-}\" ]]; then\n-    for arch in \"${KUBE_SERVER_PLATFORMS[@]##*/}\"; do\n-      kube::log::status \"Building hyperkube image for arch: ${arch}\"\n-      REGISTRY=\"${KUBE_DOCKER_REGISTRY}\" VERSION=\"${KUBE_DOCKER_IMAGE_TAG}\" ARCH=\"${arch}\" make -C cluster/images/hyperkube/ build\n-    done\n-  fi\n-}\n-\n-function kube::release::package_tarballs() {\n-  # Clean out any old releases\n-  rm -rf \"${RELEASE_DIR}\"\n-  mkdir -p \"${RELEASE_DIR}\"\n-  kube::release::package_build_image_tarball &\n-  kube::release::package_client_tarballs &\n-  kube::release::package_server_tarballs &\n-  kube::release::package_salt_tarball &\n-  kube::release::package_kube_manifests_tarball &\n-  kube::util::wait-for-jobs || { kube::log::error \"previous tarball phase failed\"; return 1; }\n-\n-  kube::release::package_full_tarball & # _full depends on all the previous phases\n-  kube::release::package_test_tarball & # _test doesn't depend on anything\n-  kube::util::wait-for-jobs || { kube::log::error \"previous tarball phase failed\"; return 1; }\n-}\n-\n-# Package the build image we used from the previous stage, for compliance/licensing/audit/yadda.\n-function kube::release::package_build_image_tarball() {\n-  kube::log::status \"Building tarball: src\"\n-  \"${TAR}\" czf \"${RELEASE_DIR}/kubernetes-src.tar.gz\" -C \"${LOCAL_OUTPUT_BUILD_CONTEXT}\" .\n-}\n-\n-# Package up all of the cross compiled clients. Over time this should grow into\n-# a full SDK\n-function kube::release::package_client_tarballs() {\n-   # Find all of the built client binaries\n-  local platform platforms\n-  platforms=($(cd \"${LOCAL_OUTPUT_BINPATH}\" ; echo */*))\n-  for platform in \"${platforms[@]}\"; do\n-    local platform_tag=${platform/\\//-} # Replace a \"/\" for a \"-\"\n-    kube::log::status \"Starting tarball: client $platform_tag\"\n-\n-    (\n-      local release_stage=\"${RELEASE_STAGE}/client/${platform_tag}/kubernetes\"\n-      rm -rf \"${release_stage}\"\n-      mkdir -p \"${release_stage}/client/bin\"\n-\n-      local client_bins=(\"${KUBE_CLIENT_BINARIES[@]}\")\n-      if [[ \"${platform%/*}\" == \"windows\" ]]; then\n-        client_bins=(\"${KUBE_CLIENT_BINARIES_WIN[@]}\")\n-      fi\n-\n-      # This fancy expression will expand to prepend a path\n-      # (${LOCAL_OUTPUT_BINPATH}/${platform}/) to every item in the\n-      # KUBE_CLIENT_BINARIES array.\n-      cp \"${client_bins[@]/#/${LOCAL_OUTPUT_BINPATH}/${platform}/}\" \\\n-        \"${release_stage}/client/bin/\"\n-\n-      kube::release::clean_cruft\n-\n-      local package_name=\"${RELEASE_DIR}/kubernetes-client-${platform_tag}.tar.gz\"\n-      kube::release::create_tarball \"${package_name}\" \"${release_stage}/..\"\n-    ) &\n-  done\n-\n-  kube::log::status \"Waiting on tarballs\"\n-  kube::util::wait-for-jobs || { kube::log::error \"client tarball creation failed\"; exit 1; }\n-}\n-\n-# Package up all of the server binaries\n-function kube::release::package_server_tarballs() {\n-  local platform\n-  for platform in \"${KUBE_SERVER_PLATFORMS[@]}\"; do\n-    local platform_tag=${platform/\\//-} # Replace a \"/\" for a \"-\"\n-    local arch=$(basename ${platform})\n-    kube::log::status \"Building tarball: server $platform_tag\"\n-\n-    local release_stage=\"${RELEASE_STAGE}/server/${platform_tag}/kubernetes\"\n-    rm -rf \"${release_stage}\"\n-    mkdir -p \"${release_stage}/server/bin\"\n-    mkdir -p \"${release_stage}/addons\"\n-\n-    # This fancy expression will expand to prepend a path\n-    # (${LOCAL_OUTPUT_BINPATH}/${platform}/) to every item in the\n-    # KUBE_SERVER_BINARIES array.\n-    cp \"${KUBE_SERVER_BINARIES[@]/#/${LOCAL_OUTPUT_BINPATH}/${platform}/}\" \\\n-      \"${release_stage}/server/bin/\"\n-\n-    kube::release::create_docker_images_for_server \"${release_stage}/server/bin\" \"${arch}\"\n-\n-    # Include the client binaries here too as they are useful debugging tools.\n-    local client_bins=(\"${KUBE_CLIENT_BINARIES[@]}\")\n-    if [[ \"${platform%/*}\" == \"windows\" ]]; then\n-      client_bins=(\"${KUBE_CLIENT_BINARIES_WIN[@]}\")\n-    fi\n-    cp \"${client_bins[@]/#/${LOCAL_OUTPUT_BINPATH}/${platform}/}\" \\\n-      \"${release_stage}/server/bin/\"\n-\n-    cp \"${KUBE_ROOT}/Godeps/LICENSES\" \"${release_stage}/\"\n-\n-    cp \"${RELEASE_DIR}/kubernetes-src.tar.gz\" \"${release_stage}/\"\n-\n-    kube::release::clean_cruft\n-\n-    local package_name=\"${RELEASE_DIR}/kubernetes-server-${platform_tag}.tar.gz\"\n-    kube::release::create_tarball \"${package_name}\" \"${release_stage}/..\"\n-  done\n-}\n-\n-function kube::release::md5() {\n-  if which md5 >/dev/null 2>&1; then\n-    md5 -q \"$1\"\n-  else\n-    md5sum \"$1\" | awk '{ print $1 }'\n-  fi\n-}\n-\n-function kube::release::sha1() {\n-  if which shasum >/dev/null 2>&1; then\n-    shasum -a1 \"$1\" | awk '{ print $1 }'\n-  else\n-    sha1sum \"$1\" | awk '{ print $1 }'\n-  fi\n-}\n-\n-# This will take binaries that run on master and creates Docker images\n-# that wrap the binary in them. (One docker image per binary)\n-# Args:\n-#  $1 - binary_dir, the directory to save the tared images to.\n-#  $2 - arch, architecture for which we are building docker images.\n-function kube::release::create_docker_images_for_server() {\n-  # Create a sub-shell so that we don't pollute the outer environment\n-  (\n-    local binary_dir=\"$1\"\n-    local arch=\"$2\"\n-    local binary_name\n-    local binaries=($(kube::build::get_docker_wrapped_binaries ${arch}))\n-\n-    for wrappable in \"${binaries[@]}\"; do\n-\n-      local oldifs=$IFS\n-      IFS=\",\"\n-      set $wrappable\n-      IFS=$oldifs\n-\n-      local binary_name=\"$1\"\n-      local base_image=\"$2\"\n-\n-      kube::log::status \"Starting Docker build for image: ${binary_name}\"\n-\n-      (\n-        local md5_sum\n-        md5_sum=$(kube::release::md5 \"${binary_dir}/${binary_name}\")\n-\n-        local docker_build_path=\"${binary_dir}/${binary_name}.dockerbuild\"\n-        local docker_file_path=\"${docker_build_path}/Dockerfile\"\n-        local binary_file_path=\"${binary_dir}/${binary_name}\"\n-\n-        rm -rf ${docker_build_path}\n-        mkdir -p ${docker_build_path}\n-        ln ${binary_dir}/${binary_name} ${docker_build_path}/${binary_name}\n-        printf \" FROM ${base_image} \\n ADD ${binary_name} /usr/local/bin/${binary_name}\\n\" > ${docker_file_path}\n-\n-        if [[ ${arch} == \"amd64\" ]]; then\n-          # If we are building a amd64 docker image, preserve the original image name\n-          local docker_image_tag=gcr.io/google_containers/${binary_name}:${md5_sum}\n-        else\n-          # If we are building a docker image for another architecture, append the arch in the image tag\n-          local docker_image_tag=gcr.io/google_containers/${binary_name}-${arch}:${md5_sum}\n-        fi\n-\n-        \"${DOCKER[@]}\" build -q -t \"${docker_image_tag}\" ${docker_build_path} >/dev/null\n-        \"${DOCKER[@]}\" save ${docker_image_tag} > ${binary_dir}/${binary_name}.tar\n-        echo $md5_sum > ${binary_dir}/${binary_name}.docker_tag\n-\n-        rm -rf ${docker_build_path}\n-\n-        # If we are building an official/alpha/beta release we want to keep docker images\n-        # and tag them appropriately.\n-        if [[ -n \"${KUBE_DOCKER_IMAGE_TAG-}\" && -n \"${KUBE_DOCKER_REGISTRY-}\" ]]; then\n-          local release_docker_image_tag=\"${KUBE_DOCKER_REGISTRY}/${binary_name}-${arch}:${KUBE_DOCKER_IMAGE_TAG}\"\n-          kube::log::status \"Tagging docker image ${docker_image_tag} as ${release_docker_image_tag}\"\n-          \"${DOCKER[@]}\" tag -f \"${docker_image_tag}\" \"${release_docker_image_tag}\" 2>/dev/null\n-        fi\n-\n-        kube::log::status \"Deleting docker image ${docker_image_tag}\"\n-        \"${DOCKER[@]}\" rmi ${docker_image_tag} 2>/dev/null || true\n-      ) &\n-    done\n-\n-    kube::util::wait-for-jobs || { kube::log::error \"previous Docker build failed\"; return 1; }\n-    kube::log::status \"Docker builds done\"\n-  )\n-\n-}\n-\n-# Package up the salt configuration tree.  This is an optional helper to getting\n-# a cluster up and running.\n-function kube::release::package_salt_tarball() {\n-  kube::log::status \"Building tarball: salt\"\n-\n-  local release_stage=\"${RELEASE_STAGE}/salt/kubernetes\"\n-  rm -rf \"${release_stage}\"\n-  mkdir -p \"${release_stage}\"\n-\n-  cp -R \"${KUBE_ROOT}/cluster/saltbase\" \"${release_stage}/\"\n-\n-  # TODO(#3579): This is a temporary hack. It gathers up the yaml,\n-  # yaml.in, json files in cluster/addons (minus any demos) and overlays\n-  # them into kube-addons, where we expect them. (This pipeline is a\n-  # fancy copy, stripping anything but the files we don't want.)\n-  local objects\n-  objects=$(cd \"${KUBE_ROOT}/cluster/addons\" && find . \\( -name \\*.yaml -or -name \\*.yaml.in -or -name \\*.json \\) | grep -v demo)\n-  tar c -C \"${KUBE_ROOT}/cluster/addons\" ${objects} | tar x -C \"${release_stage}/saltbase/salt/kube-addons\"\n-\n-  kube::release::clean_cruft\n-\n-  local package_name=\"${RELEASE_DIR}/kubernetes-salt.tar.gz\"\n-  kube::release::create_tarball \"${package_name}\" \"${release_stage}/..\"\n-}\n-\n-# This will pack kube-system manifests files for distros without using salt\n-# such as GCI and Ubuntu Trusty. We directly copy manifests from\n-# cluster/addons and cluster/saltbase/salt. The script of cluster initialization\n-# will remove the salt configuration and evaluate the variables in the manifests.\n-function kube::release::package_kube_manifests_tarball() {\n-  kube::log::status \"Building tarball: manifests\"\n-\n-  local release_stage=\"${RELEASE_STAGE}/manifests/kubernetes\"\n-  rm -rf \"${release_stage}\"\n-  local dst_dir=\"${release_stage}/gci-trusty\"\n-  mkdir -p \"${dst_dir}\"\n-\n-  local salt_dir=\"${KUBE_ROOT}/cluster/saltbase/salt\"\n-  cp \"${salt_dir}/cluster-autoscaler/cluster-autoscaler.manifest\" \"${dst_dir}/\"\n-  cp \"${salt_dir}/fluentd-es/fluentd-es.yaml\" \"${release_stage}/\"\n-  cp \"${salt_dir}/fluentd-gcp/fluentd-gcp.yaml\" \"${release_stage}/\"\n-  cp \"${salt_dir}/kube-registry-proxy/kube-registry-proxy.yaml\" \"${release_stage}/\"\n-  cp \"${salt_dir}/kube-proxy/kube-proxy.manifest\" \"${release_stage}/\"\n-  cp \"${salt_dir}/etcd/etcd.manifest\" \"${dst_dir}\"\n-  cp \"${salt_dir}/kube-scheduler/kube-scheduler.manifest\" \"${dst_dir}\"\n-  cp \"${salt_dir}/kube-apiserver/kube-apiserver.manifest\" \"${dst_dir}\"\n-  cp \"${salt_dir}/kube-apiserver/abac-authz-policy.jsonl\" \"${dst_dir}\"\n-  cp \"${salt_dir}/kube-controller-manager/kube-controller-manager.manifest\" \"${dst_dir}\"\n-  cp \"${salt_dir}/kube-addons/kube-addon-manager.yaml\" \"${dst_dir}\"\n-  cp \"${salt_dir}/l7-gcp/glbc.manifest\" \"${dst_dir}\"\n-  cp \"${salt_dir}/rescheduler/rescheduler.manifest\" \"${dst_dir}/\"\n-  cp \"${KUBE_ROOT}/cluster/gce/trusty/configure-helper.sh\" \"${dst_dir}/trusty-configure-helper.sh\"\n-  cp \"${KUBE_ROOT}/cluster/gce/gci/configure-helper.sh\" \"${dst_dir}/gci-configure-helper.sh\"\n-  cp \"${KUBE_ROOT}/cluster/gce/gci/health-monitor.sh\" \"${dst_dir}/health-monitor.sh\"\n-  cp -r \"${salt_dir}/kube-admission-controls/limit-range\" \"${dst_dir}\"\n-  local objects\n-  objects=$(cd \"${KUBE_ROOT}/cluster/addons\" && find . \\( -name \\*.yaml -or -name \\*.yaml.in -or -name \\*.json \\) | grep -v demo)\n-  tar c -C \"${KUBE_ROOT}/cluster/addons\" ${objects} | tar x -C \"${dst_dir}\"\n-\n-  # This is for coreos only. ContainerVM, GCI, or Trusty does not use it.\n-  cp -r \"${KUBE_ROOT}/cluster/gce/coreos/kube-manifests\"/* \"${release_stage}/\"\n-\n-  kube::release::clean_cruft\n-\n-  local package_name=\"${RELEASE_DIR}/kubernetes-manifests.tar.gz\"\n-  kube::release::create_tarball \"${package_name}\" \"${release_stage}/..\"\n-}\n-\n-# This is the stuff you need to run tests from the binary distribution.\n-function kube::release::package_test_tarball() {\n-  kube::log::status \"Building tarball: test\"\n-\n-  local release_stage=\"${RELEASE_STAGE}/test/kubernetes\"\n-  rm -rf \"${release_stage}\"\n-  mkdir -p \"${release_stage}\"\n-\n-  local platform\n-  for platform in \"${KUBE_TEST_PLATFORMS[@]}\"; do\n-    local test_bins=(\"${KUBE_TEST_BINARIES[@]}\")\n-    if [[ \"${platform%/*}\" == \"windows\" ]]; then\n-      test_bins=(\"${KUBE_TEST_BINARIES_WIN[@]}\")\n-    fi\n-    mkdir -p \"${release_stage}/platforms/${platform}\"\n-    cp \"${test_bins[@]/#/${LOCAL_OUTPUT_BINPATH}/${platform}/}\" \\\n-      \"${release_stage}/platforms/${platform}\"\n-  done\n-\n-  # Add the test image files\n-  mkdir -p \"${release_stage}/test/images\"\n-  cp -fR \"${KUBE_ROOT}/test/images\" \"${release_stage}/test/\"\n-  tar c ${KUBE_TEST_PORTABLE[@]} | tar x -C ${release_stage}\n-\n-  kube::release::clean_cruft\n-\n-  local package_name=\"${RELEASE_DIR}/kubernetes-test.tar.gz\"\n-  kube::release::create_tarball \"${package_name}\" \"${release_stage}/..\"\n-}\n-\n-# This is all the stuff you need to run/install kubernetes.  This includes:\n-#   - precompiled binaries for client\n-#   - Cluster spin up/down scripts and configs for various cloud providers\n-#   - tarballs for server binary and salt configs that are ready to be uploaded\n-#     to master by whatever means appropriate.\n-function kube::release::package_full_tarball() {\n-  kube::log::status \"Building tarball: full\"\n-\n-  local release_stage=\"${RELEASE_STAGE}/full/kubernetes\"\n-  rm -rf \"${release_stage}\"\n-  mkdir -p \"${release_stage}\"\n-\n-  # Copy all of the client binaries in here, but not test or server binaries.\n-  # The server binaries are included with the server binary tarball.\n-  local platform\n-  for platform in \"${KUBE_CLIENT_PLATFORMS[@]}\"; do\n-    local client_bins=(\"${KUBE_CLIENT_BINARIES[@]}\")\n-    if [[ \"${platform%/*}\" == \"windows\" ]]; then\n-      client_bins=(\"${KUBE_CLIENT_BINARIES_WIN[@]}\")\n-    fi\n-    mkdir -p \"${release_stage}/platforms/${platform}\"\n-    cp \"${client_bins[@]/#/${LOCAL_OUTPUT_BINPATH}/${platform}/}\" \\\n-      \"${release_stage}/platforms/${platform}\"\n-  done\n-\n-  # We want everything in /cluster except saltbase.  That is only needed on the\n-  # server.\n-  cp -R \"${KUBE_ROOT}/cluster\" \"${release_stage}/\"\n-  rm -rf \"${release_stage}/cluster/saltbase\"\n-\n-  mkdir -p \"${release_stage}/server\"\n-  cp \"${RELEASE_DIR}/kubernetes-salt.tar.gz\" \"${release_stage}/server/\"\n-  cp \"${RELEASE_DIR}\"/kubernetes-server-*.tar.gz \"${release_stage}/server/\"\n-  cp \"${RELEASE_DIR}/kubernetes-manifests.tar.gz\" \"${release_stage}/server/\"\n-\n-  mkdir -p \"${release_stage}/third_party\"\n-  cp -R \"${KUBE_ROOT}/third_party/htpasswd\" \"${release_stage}/third_party/htpasswd\"\n-\n-  # Include only federation/cluster and federation/manifests\n-  mkdir \"${release_stage}/federation\"\n-  cp -R \"${KUBE_ROOT}/federation/cluster\" \"${release_stage}/federation/\"\n-  cp -R \"${KUBE_ROOT}/federation/manifests\" \"${release_stage}/federation/\"\n-\n-  cp -R \"${KUBE_ROOT}/examples\" \"${release_stage}/\"\n-  cp -R \"${KUBE_ROOT}/docs\" \"${release_stage}/\"\n-  cp \"${KUBE_ROOT}/README.md\" \"${release_stage}/\"\n-  cp \"${KUBE_ROOT}/Godeps/LICENSES\" \"${release_stage}/\"\n-  cp \"${KUBE_ROOT}/Vagrantfile\" \"${release_stage}/\"\n-\n-  echo \"${KUBE_GIT_VERSION}\" > \"${release_stage}/version\"\n-\n-  kube::release::clean_cruft\n-\n-  local package_name=\"${RELEASE_DIR}/kubernetes.tar.gz\"\n-  kube::release::create_tarball \"${package_name}\" \"${release_stage}/..\"\n-}\n-\n-# Build a release tarball.  $1 is the output tar name.  $2 is the base directory\n-# of the files to be packaged.  This assumes that ${2}/kubernetes is what is\n-# being packaged.\n-function kube::release::create_tarball() {\n-  kube::build::ensure_tar\n-\n-  local tarfile=$1\n-  local stagingdir=$2\n-\n-  \"${TAR}\" czf \"${tarfile}\" -C \"${stagingdir}\" kubernetes --owner=0 --group=0\n-}\n-\n-# ---------------------------------------------------------------------------\n-# GCS Release\n-\n-function kube::release::gcs::release() {\n-  [[ ${KUBE_GCS_UPLOAD_RELEASE} =~ ^[yY]$ ]] || return 0\n-\n-  kube::release::gcs::verify_prereqs || return 1\n-  kube::release::gcs::ensure_release_bucket || return 1\n-  kube::release::gcs::copy_release_artifacts || return 1\n-}\n-\n-# Verify things are set up for uploading to GCS\n-function kube::release::gcs::verify_prereqs() {\n-  if [[ -z \"$(which gsutil)\" || -z \"$(which gcloud)\" ]]; then\n-    echo \"Releasing Kubernetes requires gsutil and gcloud.  Please download,\"\n-    echo \"install and authorize through the Google Cloud SDK: \"\n-    echo\n-    echo \"  https://developers.google.com/cloud/sdk/\"\n-    return 1\n-  fi\n-\n-  if [[ -z \"${GCLOUD_ACCOUNT-}\" ]]; then\n-    GCLOUD_ACCOUNT=$(gcloud config list --format='value(core.account)' 2>/dev/null)\n-  fi\n-  if [[ -z \"${GCLOUD_ACCOUNT-}\" ]]; then\n-    echo \"No account authorized through gcloud.  Please fix with:\"\n-    echo\n-    echo \"  gcloud auth login\"\n-    return 1\n-  fi\n-\n-  if [[ -z \"${GCLOUD_PROJECT-}\" ]]; then\n-    GCLOUD_PROJECT=$(gcloud config list --format='value(core.project)' 2>/dev/null)\n-  fi\n-  if [[ -z \"${GCLOUD_PROJECT-}\" ]]; then\n-    echo \"No account authorized through gcloud.  Please fix with:\"\n-    echo\n-    echo \"  gcloud config set project <project id>\"\n-    return 1\n-  fi\n-}\n-\n-# Create a unique bucket name for releasing Kube and make sure it exists.\n-function kube::release::gcs::ensure_release_bucket() {\n-  local project_hash\n-  project_hash=$(kube::build::short_hash \"$GCLOUD_PROJECT\")\n-  KUBE_GCS_RELEASE_BUCKET=${KUBE_GCS_RELEASE_BUCKET-kubernetes-releases-${project_hash}}\n-\n-  if ! gsutil ls \"gs://${KUBE_GCS_RELEASE_BUCKET}\" >/dev/null 2>&1 ; then\n-    echo \"Creating Google Cloud Storage bucket: $KUBE_GCS_RELEASE_BUCKET\"\n-    gsutil mb -p \"${GCLOUD_PROJECT}\" \"gs://${KUBE_GCS_RELEASE_BUCKET}\" || return 1\n-  fi\n-}\n-\n-function kube::release::gcs::stage_and_hash() {\n-  kube::build::ensure_tar || return 1\n-\n-  # Split the args into srcs... and dst\n-  local -r args=( \"$@\" )\n-  local -r split=$((${#args[@]}-1)) # Split point for src/dst args\n-  local -r srcs=( \"${args[@]::${split}}\" )\n-  local -r dst=\"${args[${split}]}\"\n-\n-  for src in ${srcs[@]}; do\n-    srcdir=$(dirname ${src})\n-    srcthing=$(basename ${src})\n-    mkdir -p ${GCS_STAGE}/${dst} || return 1\n-    \"${TAR}\" c -C ${srcdir} ${srcthing} | \"${TAR}\" x -C ${GCS_STAGE}/${dst} || return 1\n-  done\n-}\n-\n-function kube::release::gcs::copy_release_artifacts() {\n-  # TODO: This isn't atomic.  There will be points in time where there will be\n-  # no active release.  Also, if something fails, the release could be half-\n-  # copied.  The real way to do this would perhaps to have some sort of release\n-  # version so that we are never overwriting a destination.\n-  local -r gcs_destination=\"gs://${KUBE_GCS_RELEASE_BUCKET}/${KUBE_GCS_RELEASE_PREFIX}\"\n-\n-  kube::log::status \"Staging release artifacts to ${GCS_STAGE}\"\n-\n-  rm -rf ${GCS_STAGE} || return 1\n-  mkdir -p ${GCS_STAGE} || return 1\n-\n-  # Stage everything in release directory\n-  kube::release::gcs::stage_and_hash \"${RELEASE_DIR}\"/* . || return 1\n-\n-  # Having the configure-vm.sh script and GCI code from the GCE cluster\n-  # deploy hosted with the release is useful for GKE.\n-  kube::release::gcs::stage_and_hash \"${RELEASE_STAGE}/full/kubernetes/cluster/gce/configure-vm.sh\" extra/gce || return 1\n-  kube::release::gcs::stage_and_hash \"${RELEASE_STAGE}/full/kubernetes/cluster/gce/gci/node.yaml\" extra/gce || return 1\n-  kube::release::gcs::stage_and_hash \"${RELEASE_STAGE}/full/kubernetes/cluster/gce/gci/master.yaml\" extra/gce || return 1\n-  kube::release::gcs::stage_and_hash \"${RELEASE_STAGE}/full/kubernetes/cluster/gce/gci/configure.sh\" extra/gce || return 1\n-\n-  # Upload the \"naked\" binaries to GCS.  This is useful for install scripts that\n-  # download the binaries directly and don't need tars.\n-  local platform platforms\n-  platforms=($(cd \"${RELEASE_STAGE}/client\" ; echo *))\n-  for platform in \"${platforms[@]}\"; do\n-    local src=\"${RELEASE_STAGE}/client/${platform}/kubernetes/client/bin/*\"\n-    local dst=\"bin/${platform/-//}/\"\n-    # We assume here the \"server package\" is a superset of the \"client package\"\n-    if [[ -d \"${RELEASE_STAGE}/server/${platform}\" ]]; then\n-      src=\"${RELEASE_STAGE}/server/${platform}/kubernetes/server/bin/*\"\n-    fi\n-    kube::release::gcs::stage_and_hash \"$src\" \"$dst\" || return 1\n-  done\n-\n-  kube::log::status \"Hashing files in ${GCS_STAGE}\"\n-  find ${GCS_STAGE} -type f | while read path; do\n-    kube::release::md5 ${path} > \"${path}.md5\" || return 1\n-    kube::release::sha1 ${path} > \"${path}.sha1\" || return 1\n-  done\n-\n-  kube::log::status \"Copying release artifacts to ${gcs_destination}\"\n-\n-  # First delete all objects at the destination\n-  if gsutil ls \"${gcs_destination}\" >/dev/null 2>&1; then\n-    kube::log::error \"${gcs_destination} not empty.\"\n-    [[ ${KUBE_GCS_DELETE_EXISTING} =~ ^[yY]$ ]] || {\n-      read -p \"Delete everything under ${gcs_destination}? [y/n] \" -r || {\n-        kube::log::status \"EOF on prompt.  Skipping upload\"\n-        return\n-      }\n-      [[ $REPLY =~ ^[yY]$ ]] || {\n-        kube::log::status \"Skipping upload\"\n-        return\n-      }\n-    }\n-    kube::log::status \"Deleting everything under ${gcs_destination}\"\n-    gsutil -q -m rm -f -R \"${gcs_destination}\" || return 1\n-  fi\n-\n-  local gcs_options=()\n-  if [[ ${KUBE_GCS_NO_CACHING} =~ ^[yY]$ ]]; then\n-    gcs_options=(\"-h\" \"Cache-Control:private, max-age=0\")\n-  fi\n-\n-  gsutil -q -m \"${gcs_options[@]+${gcs_options[@]}}\" cp -r \"${GCS_STAGE}\"/* ${gcs_destination} || return 1\n-\n-  # TODO(jbeda): Generate an HTML page with links for this release so it is easy\n-  # to see it.  For extra credit, generate a dynamic page that builds up the\n-  # release list using the GCS JSON API.  Use Angular and Bootstrap for extra\n-  # extra credit.\n-\n-  if [[ ${KUBE_GCS_MAKE_PUBLIC} =~ ^[yY]$ ]]; then\n-    kube::log::status \"Marking all uploaded objects public\"\n-    gsutil -q -m acl ch -R -g all:R \"${gcs_destination}\" >/dev/null 2>&1 || return 1\n-  fi\n-\n-  gsutil ls -lhr \"${gcs_destination}\" || return 1\n-\n-  if [[ -n \"${KUBE_GCS_RELEASE_BUCKET_MIRROR:-}\" ]] &&\n-     [[ \"${KUBE_GCS_RELEASE_BUCKET_MIRROR}\" != \"${KUBE_GCS_RELEASE_BUCKET}\" ]]; then\n-    local -r gcs_mirror=\"gs://${KUBE_GCS_RELEASE_BUCKET_MIRROR}/${KUBE_GCS_RELEASE_PREFIX}\"\n-    kube::log::status \"Mirroring build to ${gcs_mirror}\"\n-    gsutil -q -m \"${gcs_options[@]+${gcs_options[@]}}\" rsync -d -r \"${gcs_destination}\" \"${gcs_mirror}\" || return 1\n-    if [[ ${KUBE_GCS_MAKE_PUBLIC} =~ ^[yY]$ ]]; then\n-      kube::log::status \"Marking all uploaded mirror objects public\"\n-      gsutil -q -m acl ch -R -g all:R \"${gcs_mirror}\" >/dev/null 2>&1 || return 1\n-    fi\n-  fi\n-}\n-\n-# Publish a new ci version, (latest,) but only if the release files actually\n-# exist on GCS.\n-#\n-# Globals:\n-#   See callees\n-# Arguments:\n-#   None\n-# Returns:\n-#   Success\n-function kube::release::gcs::publish_ci() {\n-  kube::release::gcs::verify_release_files || return 1\n-\n-  kube::release::parse_and_validate_ci_version \"${KUBE_GCS_PUBLISH_VERSION}\" || return 1\n-  local -r version_major=\"${VERSION_MAJOR}\"\n-  local -r version_minor=\"${VERSION_MINOR}\"\n-\n-  local -r publish_files=(ci/latest.txt ci/latest-${version_major}.txt ci/latest-${version_major}.${version_minor}.txt)\n-\n-  for publish_file in ${publish_files[*]}; do\n-    # If there's a version that's above the one we're trying to release, don't\n-    # do anything, and just try the next one.\n-    kube::release::gcs::verify_ci_ge \"${publish_file}\" || continue\n-    kube::release::gcs::publish \"${publish_file}\" || return 1\n-  done\n-}\n+function kube::build::start_rsyncd_container() {\n+  kube::build::stop_rsyncd_container\n+  V=6 kube::log::status \"Starting rsyncd container\"\n+  kube::build::run_build_command_ex \\\n+    \"${KUBE_RSYNC_CONTAINER_NAME}\" -p 127.0.0.1:${KUBE_RSYNC_PORT}:8730 -d \\\n+    -- /rsyncd.sh >/dev/null\n \n-# Publish a new official version, (latest or stable,) but only if the release\n-# files actually exist on GCS and the release we're dealing with is newer than\n-# the contents in GCS.\n-#\n-# Globals:\n-#   KUBE_GCS_PUBLISH_VERSION\n-#   See callees\n-# Arguments:\n-#   release_kind: either 'latest' or 'stable'\n-# Returns:\n-#   Success\n-function kube::release::gcs::publish_official() {\n-  local -r release_kind=\"${1-}\"\n-\n-  kube::release::gcs::verify_release_files || return 1\n-\n-  kube::release::parse_and_validate_release_version \"${KUBE_GCS_PUBLISH_VERSION}\" || return 1\n-  local -r version_major=\"${VERSION_MAJOR}\"\n-  local -r version_minor=\"${VERSION_MINOR}\"\n-\n-  local publish_files\n-  if [[ \"${release_kind}\" == 'latest' ]]; then\n-    publish_files=(release/latest.txt release/latest-${version_major}.txt release/latest-${version_major}.${version_minor}.txt)\n-  elif [[ \"${release_kind}\" == 'stable' ]]; then\n-    publish_files=(release/stable.txt release/stable-${version_major}.txt release/stable-${version_major}.${version_minor}.txt)\n-  else\n-    kube::log::error \"Wrong release_kind: must be 'latest' or 'stable'.\"\n-    return 1\n-  fi\n-\n-  for publish_file in ${publish_files[*]}; do\n-    # If there's a version that's above the one we're trying to release, don't\n-    # do anything, and just try the next one.\n-    kube::release::gcs::verify_release_gt \"${publish_file}\" || continue\n-    kube::release::gcs::publish \"${publish_file}\" || return 1\n-  done\n-}\n-\n-# Verify that the release files we expect actually exist.\n-#\n-# Globals:\n-#   KUBE_GCS_RELEASE_BUCKET\n-#   KUBE_GCS_RELEASE_PREFIX\n-# Arguments:\n-#   None\n-# Returns:\n-#   If release files exist\n-function kube::release::gcs::verify_release_files() {\n-  local -r release_dir=\"gs://${KUBE_GCS_RELEASE_BUCKET}/${KUBE_GCS_RELEASE_PREFIX}\"\n-  if ! gsutil ls \"${release_dir}\" >/dev/null 2>&1 ; then\n-    kube::log::error \"Release files don't exist at '${release_dir}'\"\n+  if ! KUBE_REAL_RSYNC_PORT=$(docker port \"${KUBE_RSYNC_CONTAINER_NAME}\" 8730 2> /dev/null | cut -d: -f 2) ; then\n+    kube:log:error \"Could not get effective rsync port\"\n     return 1\n   fi\n-}\n-\n-# Check if the new version is greater than the version currently published on\n-# GCS.\n-#\n-# Globals:\n-#   KUBE_GCS_PUBLISH_VERSION\n-#   KUBE_GCS_RELEASE_BUCKET\n-# Arguments:\n-#   publish_file: the GCS location to look in\n-# Returns:\n-#   If new version is greater than the GCS version\n-#\n-# TODO(16529): This should all be outside of build an in release, and should be\n-# refactored to reduce code duplication.  Also consider using strictly nested\n-# if and explicit handling of equals case.\n-function kube::release::gcs::verify_release_gt() {\n-  local -r publish_file=\"${1-}\"\n-  local -r new_version=${KUBE_GCS_PUBLISH_VERSION}\n-  local -r publish_file_dst=\"gs://${KUBE_GCS_RELEASE_BUCKET}/${publish_file}\"\n-\n-  kube::release::parse_and_validate_release_version \"${new_version}\" || return 1\n-\n-  local -r version_major=\"${VERSION_MAJOR}\"\n-  local -r version_minor=\"${VERSION_MINOR}\"\n-  local -r version_patch=\"${VERSION_PATCH}\"\n-  local -r version_prerelease=\"${VERSION_PRERELEASE}\"\n-  local -r version_prerelease_rev=\"${VERSION_PRERELEASE_REV}\"\n-\n-  local gcs_version\n-  if gcs_version=\"$(gsutil cat \"${publish_file_dst}\")\"; then\n-    kube::release::parse_and_validate_release_version \"${gcs_version}\" || {\n-      kube::log::error \"${publish_file_dst} contains invalid release version, can't compare: '${gcs_version}'\"\n-      return 1\n-    }\n \n-    local -r gcs_version_major=\"${VERSION_MAJOR}\"\n-    local -r gcs_version_minor=\"${VERSION_MINOR}\"\n-    local -r gcs_version_patch=\"${VERSION_PATCH}\"\n-    local -r gcs_version_prerelease=\"${VERSION_PRERELEASE}\"\n-    local -r gcs_version_prerelease_rev=\"${VERSION_PRERELEASE_REV}\"\n-\n-    local greater=true\n-    if [[ \"${version_major}\" -lt \"${gcs_version_major}\" ]]; then\n-      greater=false\n-    elif [[ \"${version_major}\" -gt \"${gcs_version_major}\" ]]; then\n-      : # fall out\n-    elif [[ \"${version_minor}\" -lt \"${gcs_version_minor}\" ]]; then\n-      greater=false\n-    elif [[ \"${version_minor}\" -gt \"${gcs_version_minor}\" ]]; then\n-      : # fall out\n-    elif [[ \"${version_patch}\" -lt \"${gcs_version_patch}\" ]]; then\n-      greater=false\n-    elif [[ \"${version_patch}\" -gt \"${gcs_version_patch}\" ]]; then\n-      : # fall out\n-    # Use lexicographic (instead of integer) comparison because\n-    # version_prerelease is a string, (\"alpha\" or \"beta\",) but first check if\n-    # either is an official release (i.e. empty prerelease string).\n-    #\n-    # We have to do this because lexicographically \"beta\" > \"alpha\" > \"\", but\n-    # we want official > beta > alpha.\n-    elif [[ -n \"${version_prerelease}\" && -z \"${gcs_version_prerelease}\" ]]; then\n-      greater=false\n-    elif [[ -z \"${version_prerelease}\" && -n \"${gcs_version_prerelease}\" ]]; then\n-      : # fall out\n-    elif [[ \"${version_prerelease}\" < \"${gcs_version_prerelease}\" ]]; then\n-      greater=false\n-    elif [[ \"${version_prerelease}\" > \"${gcs_version_prerelease}\" ]]; then\n-      : # fall out\n-    # Finally resort to -le here, since we want strictly-greater-than.\n-    elif [[ \"${version_prerelease_rev}\" -le \"${gcs_version_prerelease_rev}\" ]]; then\n-      greater=false\n-    fi\n-\n-    if [[ \"${greater}\" != \"true\" ]]; then\n-      kube::log::status \"${new_version} (just uploaded) <= ${gcs_version} (latest on GCS), not updating ${publish_file_dst}\"\n-      return 1\n-    else\n-      kube::log::status \"${new_version} (just uploaded) > ${gcs_version} (latest on GCS), updating ${publish_file_dst}\"\n-    fi\n-  else  # gsutil cat failed; file does not exist\n-    kube::log::error \"Release file '${publish_file_dst}' does not exist.  Continuing.\"\n+  # Wait unil rsync is up and running.\n+  if ! which nc >/dev/null ; then\n+    V=6 kube::log::info \"netcat not installed, waiting for 1s for rsyncd to come up.\"\n+    sleep 1\n     return 0\n   fi\n-}\n-\n-# Check if the new version is greater than or equal to the version currently\n-# published on GCS.  (Ignore the build; if it's different, overwrite anyway.)\n-#\n-# Globals:\n-#   KUBE_GCS_PUBLISH_VERSION\n-#   KUBE_GCS_RELEASE_BUCKET\n-# Arguments:\n-#   publish_file: the GCS location to look in\n-# Returns:\n-#   If new version is greater than the GCS version\n-#\n-# TODO(16529): This should all be outside of build an in release, and should be\n-# refactored to reduce code duplication.  Also consider using strictly nested\n-# if and explicit handling of equals case.\n-function kube::release::gcs::verify_ci_ge() {\n-  local -r publish_file=\"${1-}\"\n-  local -r new_version=${KUBE_GCS_PUBLISH_VERSION}\n-  local -r publish_file_dst=\"gs://${KUBE_GCS_RELEASE_BUCKET}/${publish_file}\"\n-\n-  kube::release::parse_and_validate_ci_version \"${new_version}\" || return 1\n-\n-  local -r version_major=\"${VERSION_MAJOR}\"\n-  local -r version_minor=\"${VERSION_MINOR}\"\n-  local -r version_patch=\"${VERSION_PATCH}\"\n-  local -r version_prerelease=\"${VERSION_PRERELEASE}\"\n-  local -r version_prerelease_rev=\"${VERSION_PRERELEASE_REV}\"\n-  local -r version_commits=\"${VERSION_COMMITS}\"\n-\n-  local gcs_version\n-  if gcs_version=\"$(gsutil cat \"${publish_file_dst}\")\"; then\n-    kube::release::parse_and_validate_ci_version \"${gcs_version}\" || {\n-      kube::log::error \"${publish_file_dst} contains invalid ci version, can't compare: '${gcs_version}'\"\n-      return 1\n-    }\n-\n-    local -r gcs_version_major=\"${VERSION_MAJOR}\"\n-    local -r gcs_version_minor=\"${VERSION_MINOR}\"\n-    local -r gcs_version_patch=\"${VERSION_PATCH}\"\n-    local -r gcs_version_prerelease=\"${VERSION_PRERELEASE}\"\n-    local -r gcs_version_prerelease_rev=\"${VERSION_PRERELEASE_REV}\"\n-    local -r gcs_version_commits=\"${VERSION_COMMITS}\"\n-\n-    local greater=true\n-    if [[ \"${version_major}\" -lt \"${gcs_version_major}\" ]]; then\n-      greater=false\n-    elif [[ \"${version_major}\" -gt \"${gcs_version_major}\" ]]; then\n-      : # fall out\n-    elif [[ \"${version_minor}\" -lt \"${gcs_version_minor}\" ]]; then\n-      greater=false\n-    elif [[ \"${version_minor}\" -gt \"${gcs_version_minor}\" ]]; then\n-      : # fall out\n-    elif [[ \"${version_patch}\" -lt \"${gcs_version_patch}\" ]]; then\n-      greater=false\n-    elif [[ \"${version_patch}\" -gt \"${gcs_version_patch}\" ]]; then\n-      : # fall out\n-    # Use lexicographic (instead of integer) comparison because\n-    # version_prerelease is a string, (\"alpha\" or \"beta\")\n-    elif [[ \"${version_prerelease}\" < \"${gcs_version_prerelease}\" ]]; then\n-      greater=false\n-    elif [[ \"${version_prerelease}\" > \"${gcs_version_prerelease}\" ]]; then\n-      : # fall out\n-    elif [[ \"${version_prerelease_rev}\" -lt \"${gcs_version_prerelease_rev}\" ]]; then\n-      greater=false\n-    elif [[ \"${version_prerelease_rev}\" -gt \"${gcs_version_prerelease_rev}\" ]]; then\n-      : # fall out\n-    # If either version_commits is empty, it will be considered less-than, as\n-    # expected, (e.g. 1.2.3-beta < 1.2.3-beta.1).\n-    elif [[ \"${version_commits}\" -lt \"${gcs_version_commits}\" ]]; then\n-      greater=false\n-    fi\n \n-    if [[ \"${greater}\" != \"true\" ]]; then\n-      kube::log::status \"${new_version} (just uploaded) < ${gcs_version} (latest on GCS), not updating ${publish_file_dst}\"\n-      return 1\n-    else\n-      kube::log::status \"${new_version} (just uploaded) >= ${gcs_version} (latest on GCS), updating ${publish_file_dst}\"\n+  # Apple has an ancient version of netcat with custom timeout flags.  This is\n+  # the best way I (jbeda) could find to test for that.\n+  local nc\n+  if nc 2>&1 | grep -e 'apple' >/dev/null ; then\n+    netcat=\"nc -G 1\"\n+  else\n+    netcat=\"nc -w 1\"\n+  fi\n+\n+  local tries=60\n+  while (( $tries > 0 )) ; do\n+    if $netcat -z 127.0.0.1 ${KUBE_REAL_RSYNC_PORT} 2> /dev/null ; then\n+      sleep 0.5\n+      \"${DOCKER[@]}\" logs ${KUBE_RSYNC_CONTAINER_NAME}\n+      \"${DOCKER[@]}\" port ${KUBE_RSYNC_CONTAINER_NAME}\n+      \"${DOCKER[@]}\" inspect ${KUBE_RSYNC_CONTAINER_NAME}\n+      ip addr\n+      ip route\n+      return 0\n     fi\n-  else  # gsutil cat failed; file does not exist\n-    kube::log::error \"File '${publish_file_dst}' does not exist.  Continuing.\"\n-    return 0\n-  fi\n-}\n+    tries=$(($tries-1))\n+    sleep 0.1\n+  done\n \n-# Publish a release to GCS: upload a version file, if KUBE_GCS_MAKE_PUBLIC,\n-# make it public, and verify the result.\n-#\n-# Globals:\n-#   KUBE_GCS_RELEASE_BUCKET\n-#   RELEASE_STAGE\n-#   KUBE_GCS_PUBLISH_VERSION\n-#   KUBE_GCS_MAKE_PUBLIC\n-# Arguments:\n-#   publish_file: the GCS location to look in\n-# Returns:\n-#   If new version is greater than the GCS version\n-function kube::release::gcs::publish() {\n-  local -r publish_file=\"${1-}\"\n-\n-  kube::release::gcs::publish_to_bucket \"${KUBE_GCS_RELEASE_BUCKET}\" \"${publish_file}\" || return 1\n-\n-  if [[ -n \"${KUBE_GCS_RELEASE_BUCKET_MIRROR:-}\" ]] &&\n-     [[ \"${KUBE_GCS_RELEASE_BUCKET_MIRROR}\" != \"${KUBE_GCS_RELEASE_BUCKET}\" ]]; then\n-    kube::release::gcs::publish_to_bucket \"${KUBE_GCS_RELEASE_BUCKET_MIRROR}\" \"${publish_file}\" || return 1\n-  fi\n+  kube::log::error \"Could not connect to rsync container. See build/README.md for setting up remote Docker engine.\"\n+  \"${DOCKER[@]}\" logs ${KUBE_RSYNC_CONTAINER_NAME}\n+  \"${DOCKER[@]}\" port ${KUBE_RSYNC_CONTAINER_NAME}\n+  \"${DOCKER[@]}\" inspect ${KUBE_RSYNC_CONTAINER_NAME}\n+  ip addr\n+  ip route\n+  return 1\n }\n \n-\n-function kube::release::gcs::publish_to_bucket() {\n-  local -r publish_bucket=\"${1}\"\n-  local -r publish_file=\"${2}\"\n-  local -r publish_file_dst=\"gs://${publish_bucket}/${publish_file}\"\n-\n-  mkdir -p \"${RELEASE_STAGE}/upload\" || return 1\n-  echo \"${KUBE_GCS_PUBLISH_VERSION}\" > \"${RELEASE_STAGE}/upload/latest\" || return 1\n-\n-  gsutil -m cp \"${RELEASE_STAGE}/upload/latest\" \"${publish_file_dst}\" || return 1\n-\n-  local contents\n-  if [[ ${KUBE_GCS_MAKE_PUBLIC} =~ ^[yY]$ ]]; then\n-    kube::log::status \"Making uploaded version file public and non-cacheable.\"\n-    gsutil acl ch -R -g all:R \"${publish_file_dst}\" >/dev/null 2>&1 || return 1\n-    gsutil setmeta -h \"Cache-Control:private, max-age=0\" \"${publish_file_dst}\" >/dev/null 2>&1 || return 1\n-    # If public, validate public link\n-    local -r public_link=\"https://storage.googleapis.com/${publish_bucket}/${publish_file}\"\n-    kube::log::status \"Validating uploaded version file at ${public_link}\"\n-    contents=\"$(curl -s \"${public_link}\")\"\n-  else\n-    # If not public, validate using gsutil\n-    kube::log::status \"Validating uploaded version file at ${publish_file_dst}\"\n-    contents=\"$(gsutil cat \"${publish_file_dst}\")\"\n-  fi\n-  if [[ \"${contents}\" == \"${KUBE_GCS_PUBLISH_VERSION}\" ]]; then\n-    kube::log::status \"Contents as expected: ${contents}\"\n-  else\n-    kube::log::error \"Expected contents of file to be ${KUBE_GCS_PUBLISH_VERSION}, but got ${contents}\"\n-    return 1\n-  fi\n+function kube::build::stop_rsyncd_container() {\n+  V=6 kube::log::status \"Stopping any currently running rsyncd container\"\n+  kube::build::destroy_container \"${KUBE_RSYNC_CONTAINER_NAME}\"\n }\n \n-# ---------------------------------------------------------------------------\n-# Docker Release\n-\n-# Releases all docker images to a docker registry specified by KUBE_DOCKER_REGISTRY\n-# using tag KUBE_DOCKER_IMAGE_TAG.\n-#\n-# Globals:\n-#   KUBE_DOCKER_REGISTRY\n-#   KUBE_DOCKER_IMAGE_TAG\n-#   KUBE_SERVER_PLATFORMS\n-# Returns:\n-#   If new pushing docker images was successful.\n-function kube::release::docker::release() {\n-  local binaries=(\n-    \"kube-apiserver\"\n-    \"kube-controller-manager\"\n-    \"kube-scheduler\"\n-    \"kube-proxy\"\n-    \"hyperkube\"\n-    \"federation-apiserver\"\n-    \"federation-controller-manager\"\n-  )\n+# This will launch rsyncd in a container and then sync the source tree to the\n+# container over the local network.\n+function kube::build::sync_to_container() {\n+  kube::log::status \"Syncing sources to container\"\n \n-  local docker_push_cmd=(\"${DOCKER[@]}\")\n-  if [[ \"${KUBE_DOCKER_REGISTRY}\" == \"gcr.io/\"* ]]; then\n-    docker_push_cmd=(\"gcloud\" \"docker\")\n-  fi\n+  kube::build::start_rsyncd_container\n \n-  if [[ \"${KUBE_DOCKER_REGISTRY}\" == \"gcr.io/google_containers\" ]]; then\n-    # Activate credentials for the k8s.production.user@gmail.com\n-    gcloud config set account k8s.production.user@gmail.com\n+  local rsync_extra=\"\"\n+  if (( $KUBE_VERBOSE >= 6 )); then\n+    rsync_extra=\"-iv\"\n   fi\n \n-  for arch in \"${KUBE_SERVER_PLATFORMS[@]##*/}\"; do\n-    for binary in \"${binaries[@]}\"; do\n-\n-      # TODO(IBM): Enable hyperkube builds for ppc64le again\n-      if [[ ${binary} != \"hyperkube\" || ${arch} != \"ppc64le\" ]]; then\n-\n-        local docker_target=\"${KUBE_DOCKER_REGISTRY}/${binary}-${arch}:${KUBE_DOCKER_IMAGE_TAG}\"\n-        kube::log::status \"Pushing ${binary} to ${docker_target}\"\n-        \"${docker_push_cmd[@]}\" push \"${docker_target}\"\n-\n-        # If we have a amd64 docker image. Tag it without -amd64 also and push it for compatibility with earlier versions\n-        if [[ ${arch} == \"amd64\" ]]; then\n-          local legacy_docker_target=\"${KUBE_DOCKER_REGISTRY}/${binary}:${KUBE_DOCKER_IMAGE_TAG}\"\n-\n-          \"${DOCKER[@]}\" tag -f \"${docker_target}\" \"${legacy_docker_target}\" 2>/dev/null\n+  V=6 kube::log::status \"Running rsync\"\n+  rsync $rsync_extra \\\n+    --password-file=\"${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password\" \\\n+    --filter='- /.git/' \\\n+    --filter='- /.make/' \\\n+    --filter='- /_output/' \\\n+    --filter='- /' \\\n+    --prune-empty-dirs \\\n+    --archive --perms \\\n+    \"${KUBE_ROOT}/\" rsync://k8s@localhost:${KUBE_REAL_RSYNC_PORT}/k8s/\n \n-          kube::log::status \"Pushing ${binary} to ${legacy_docker_target}\"\n-          \"${docker_push_cmd[@]}\" push \"${legacy_docker_target}\"\n-        fi\n-      fi\n-    done\n-  done\n-  if [[ \"${KUBE_DOCKER_REGISTRY}\" == \"gcr.io/google_containers\" ]]; then\n-    # Activate default account\n-    gcloud config set account ${USER}@google.com\n-  fi\n+  kube::build::stop_rsyncd_container\n }\n \n-function kube::release::gcloud_account_is_active() {\n-  local -r account=\"${1-}\"\n-  if [[ \"$(gcloud config list --format='value(core.account)')\" == \"${account}\" ]]; then\n-    return 0\n-  else\n-    return 1\n-  fi\n+# If the Docker server is remote, copy the results back out.\n+function kube::build::copy_output() {\n+  kube::log::status \"Syncing out of container\"\n+\n+  kube::build::start_rsyncd_container\n+\n+  local rsync_extra=\"\"\n+  if (( $KUBE_VERBOSE >= 6 )); then\n+    rsync_extra=\"-iv\"\n+  fi\n+\n+  V=6 kube::log::status \"Running rsync\"\n+  rsync $rsync_extra \\\n+    --password-file=\"${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password\" \\\n+    --prune-empty-dirs \\\n+    --filter='- /vendor/' \\\n+    --filter='+ /_output/dockerized/bin/**' \\\n+    --filter='+ zz_generated.*' \\\n+    --filter='+ generated.proto' \\\n+    --filter='+ *.pb.go' \\\n+    --filter='+ */' \\\n+    --filter='- /**' \\\n+    --archive --perms \\","path":"build/common.sh","position":1628,"original_position":1628,"commit_id":"5057c0ff12e21acf7da93772725af7b1ebfeab47","original_commit_id":"5057c0ff12e21acf7da93772725af7b1ebfeab47","user":{"login":"MHBauer","id":13337345,"avatar_url":"https://avatars.githubusercontent.com/u/13337345?v=3","gravatar_id":"","url":"https://api.github.com/users/MHBauer","html_url":"https://github.com/MHBauer","followers_url":"https://api.github.com/users/MHBauer/followers","following_url":"https://api.github.com/users/MHBauer/following{/other_user}","gists_url":"https://api.github.com/users/MHBauer/gists{/gist_id}","starred_url":"https://api.github.com/users/MHBauer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MHBauer/subscriptions","organizations_url":"https://api.github.com/users/MHBauer/orgs","repos_url":"https://api.github.com/users/MHBauer/repos","events_url":"https://api.github.com/users/MHBauer/events{/privacy}","received_events_url":"https://api.github.com/users/MHBauer/received_events","type":"User","site_admin":false},"body":"doesn't `archive` imply `perms`?","created_at":"2016-08-25T21:09:46Z","updated_at":"2016-08-25T21:09:46Z","html_url":"https://github.com/kubernetes/kubernetes/pull/30787#discussion_r76325149","pull_request_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/30787","_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments/76325149"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/30787#discussion_r76325149"},"pull_request":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/30787"}}},"pull_request":{"url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/30787","id":81687721,"html_url":"https://github.com/kubernetes/kubernetes/pull/30787","diff_url":"https://github.com/kubernetes/kubernetes/pull/30787.diff","patch_url":"https://github.com/kubernetes/kubernetes/pull/30787.patch","issue_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/30787","number":30787,"state":"open","locked":false,"title":"[WIP] Speed up dockerized builds","user":{"login":"jbeda","id":37310,"avatar_url":"https://avatars.githubusercontent.com/u/37310?v=3","gravatar_id":"","url":"https://api.github.com/users/jbeda","html_url":"https://github.com/jbeda","followers_url":"https://api.github.com/users/jbeda/followers","following_url":"https://api.github.com/users/jbeda/following{/other_user}","gists_url":"https://api.github.com/users/jbeda/gists{/gist_id}","starred_url":"https://api.github.com/users/jbeda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbeda/subscriptions","organizations_url":"https://api.github.com/users/jbeda/orgs","repos_url":"https://api.github.com/users/jbeda/repos","events_url":"https://api.github.com/users/jbeda/events{/privacy}","received_events_url":"https://api.github.com/users/jbeda/received_events","type":"User","site_admin":false},"body":"This PR speeds up dockerized builds.  First, we make sure that we are as incremental as possible.  The bigger change is that now we use rsync to move sources into the container and get data back out.\r\n\r\nTo do yet:\r\n* [x] Add a random password to rsync.  This is 128bit MD4, but it is better than nothing.\r\n* [x] Lock down rsync to only come from the host.\r\n* [x] Deal with remote docker engines -- this should be necessary for docker-machine on the mac.\r\n* [x] Allow users to specify the port for the rsync daemon.  Perhaps randomize this or let docker pick an ephemeral port and detect the port?\r\n* [x] Copy back generated files so that users can check them in.  This is done for `zz_generated.*` files generated by `make generated_files` \r\n  * [x] This should include generated proto files so that we can remove the hack-o-rama that is `hack/hack/update-*-dockerized.sh` \r\n* [x] Start \"versioning\" the build container and the data container so that the CI system doesn't have to be manually kicked.\r\n* [x] Get some benchmarks to qualify how much faster.\r\n\r\nThis replaces #28518 and is related to #30600.\r\n\r\ncc @thockin @spxtr @david-mcmahon @MHBauer \r\n\r\nBenchmarks by running `make clean ; time bash -xc 'time build/make-build-image.sh ; time build/run.sh make ; time build/run.sh make'` on a GCE n1-standard-8 with PD-SSD.\r\n\r\n| setup | build image | first build | second build | total |\r\n|-------|-------------|----------|------------|--------|\r\n| baseline | 0m18.419s | 6m46.581s | 6m50.694s | 13m55.696s |\r\n| this pr | 0m13.401s | 6m58.939s | 0m12.740s | 7m25.08s |\r\n\r\n<!-- Reviewable:start -->\r\n---\r\nThis change is [<img src=\"https://reviewable.kubernetes.io/review_button.svg\" height=\"34\" align=\"absmiddle\" alt=\"Reviewable\"/>](https://reviewable.kubernetes.io/reviews/kubernetes/kubernetes/30787)\r\n<!-- Reviewable:end -->\r\n","created_at":"2016-08-17T17:56:39Z","updated_at":"2016-08-25T21:09:46Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8e813a8e8e037cfcf15446ed7a13861e26d492fb","assignee":{"login":"ixdy","id":8061296,"avatar_url":"https://avatars.githubusercontent.com/u/8061296?v=3","gravatar_id":"","url":"https://api.github.com/users/ixdy","html_url":"https://github.com/ixdy","followers_url":"https://api.github.com/users/ixdy/followers","following_url":"https://api.github.com/users/ixdy/following{/other_user}","gists_url":"https://api.github.com/users/ixdy/gists{/gist_id}","starred_url":"https://api.github.com/users/ixdy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ixdy/subscriptions","organizations_url":"https://api.github.com/users/ixdy/orgs","repos_url":"https://api.github.com/users/ixdy/repos","events_url":"https://api.github.com/users/ixdy/events{/privacy}","received_events_url":"https://api.github.com/users/ixdy/received_events","type":"User","site_admin":false},"assignees":[{"login":"ixdy","id":8061296,"avatar_url":"https://avatars.githubusercontent.com/u/8061296?v=3","gravatar_id":"","url":"https://api.github.com/users/ixdy","html_url":"https://github.com/ixdy","followers_url":"https://api.github.com/users/ixdy/followers","following_url":"https://api.github.com/users/ixdy/following{/other_user}","gists_url":"https://api.github.com/users/ixdy/gists{/gist_id}","starred_url":"https://api.github.com/users/ixdy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ixdy/subscriptions","organizations_url":"https://api.github.com/users/ixdy/orgs","repos_url":"https://api.github.com/users/ixdy/repos","events_url":"https://api.github.com/users/ixdy/events{/privacy}","received_events_url":"https://api.github.com/users/ixdy/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/30787/commits","review_comments_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/30787/comments","review_comment_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}","comments_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/30787/comments","statuses_url":"https://api.github.com/repos/kubernetes/kubernetes/statuses/5057c0ff12e21acf7da93772725af7b1ebfeab47","head":{"label":"jbeda:rsync","ref":"rsync","sha":"5057c0ff12e21acf7da93772725af7b1ebfeab47","user":{"login":"jbeda","id":37310,"avatar_url":"https://avatars.githubusercontent.com/u/37310?v=3","gravatar_id":"","url":"https://api.github.com/users/jbeda","html_url":"https://github.com/jbeda","followers_url":"https://api.github.com/users/jbeda/followers","following_url":"https://api.github.com/users/jbeda/following{/other_user}","gists_url":"https://api.github.com/users/jbeda/gists{/gist_id}","starred_url":"https://api.github.com/users/jbeda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbeda/subscriptions","organizations_url":"https://api.github.com/users/jbeda/orgs","repos_url":"https://api.github.com/users/jbeda/repos","events_url":"https://api.github.com/users/jbeda/events{/privacy}","received_events_url":"https://api.github.com/users/jbeda/received_events","type":"User","site_admin":false},"repo":{"id":20701361,"name":"kubernetes","full_name":"jbeda/kubernetes","owner":{"login":"jbeda","id":37310,"avatar_url":"https://avatars.githubusercontent.com/u/37310?v=3","gravatar_id":"","url":"https://api.github.com/users/jbeda","html_url":"https://github.com/jbeda","followers_url":"https://api.github.com/users/jbeda/followers","following_url":"https://api.github.com/users/jbeda/following{/other_user}","gists_url":"https://api.github.com/users/jbeda/gists{/gist_id}","starred_url":"https://api.github.com/users/jbeda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbeda/subscriptions","organizations_url":"https://api.github.com/users/jbeda/orgs","repos_url":"https://api.github.com/users/jbeda/repos","events_url":"https://api.github.com/users/jbeda/events{/privacy}","received_events_url":"https://api.github.com/users/jbeda/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jbeda/kubernetes","description":"Container Cluster Manager","fork":true,"url":"https://api.github.com/repos/jbeda/kubernetes","forks_url":"https://api.github.com/repos/jbeda/kubernetes/forks","keys_url":"https://api.github.com/repos/jbeda/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jbeda/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jbeda/kubernetes/teams","hooks_url":"https://api.github.com/repos/jbeda/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/jbeda/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/jbeda/kubernetes/events","assignees_url":"https://api.github.com/repos/jbeda/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/jbeda/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/jbeda/kubernetes/tags","blobs_url":"https://api.github.com/repos/jbeda/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jbeda/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jbeda/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/jbeda/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jbeda/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/jbeda/kubernetes/languages","stargazers_url":"https://api.github.com/repos/jbeda/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/jbeda/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/jbeda/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/jbeda/kubernetes/subscription","commits_url":"https://api.github.com/repos/jbeda/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/jbeda/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/jbeda/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/jbeda/kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/jbeda/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/jbeda/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jbeda/kubernetes/merges","archive_url":"https://api.github.com/repos/jbeda/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jbeda/kubernetes/downloads","issues_url":"https://api.github.com/repos/jbeda/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/jbeda/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/jbeda/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/jbeda/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jbeda/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/jbeda/kubernetes/releases{/id}","deployments_url":"https://api.github.com/repos/jbeda/kubernetes/deployments","created_at":"2014-06-10T20:55:43Z","updated_at":"2016-07-05T20:56:31Z","pushed_at":"2016-08-25T00:12:15Z","git_url":"git://github.com/jbeda/kubernetes.git","ssh_url":"git@github.com:jbeda/kubernetes.git","clone_url":"https://github.com/jbeda/kubernetes.git","svn_url":"https://github.com/jbeda/kubernetes","homepage":null,"size":304089,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"kubernetes:master","ref":"master","sha":"1952986a345b2106fc165530592eb9c689decc10","user":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"repo":{"id":20580498,"name":"kubernetes","full_name":"kubernetes/kubernetes","owner":{"login":"kubernetes","id":13629408,"avatar_url":"https://avatars.githubusercontent.com/u/13629408?v=3","gravatar_id":"","url":"https://api.github.com/users/kubernetes","html_url":"https://github.com/kubernetes","followers_url":"https://api.github.com/users/kubernetes/followers","following_url":"https://api.github.com/users/kubernetes/following{/other_user}","gists_url":"https://api.github.com/users/kubernetes/gists{/gist_id}","starred_url":"https://api.github.com/users/kubernetes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kubernetes/subscriptions","organizations_url":"https://api.github.com/users/kubernetes/orgs","repos_url":"https://api.github.com/users/kubernetes/repos","events_url":"https://api.github.com/users/kubernetes/events{/privacy}","received_events_url":"https://api.github.com/users/kubernetes/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/kubernetes/kubernetes","description":"Production-Grade Container Scheduling and Management","fork":false,"url":"https://api.github.com/repos/kubernetes/kubernetes","forks_url":"https://api.github.com/repos/kubernetes/kubernetes/forks","keys_url":"https://api.github.com/repos/kubernetes/kubernetes/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kubernetes/kubernetes/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kubernetes/kubernetes/teams","hooks_url":"https://api.github.com/repos/kubernetes/kubernetes/hooks","issue_events_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/events{/number}","events_url":"https://api.github.com/repos/kubernetes/kubernetes/events","assignees_url":"https://api.github.com/repos/kubernetes/kubernetes/assignees{/user}","branches_url":"https://api.github.com/repos/kubernetes/kubernetes/branches{/branch}","tags_url":"https://api.github.com/repos/kubernetes/kubernetes/tags","blobs_url":"https://api.github.com/repos/kubernetes/kubernetes/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kubernetes/kubernetes/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kubernetes/kubernetes/git/refs{/sha}","trees_url":"https://api.github.com/repos/kubernetes/kubernetes/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kubernetes/kubernetes/statuses/{sha}","languages_url":"https://api.github.com/repos/kubernetes/kubernetes/languages","stargazers_url":"https://api.github.com/repos/kubernetes/kubernetes/stargazers","contributors_url":"https://api.github.com/repos/kubernetes/kubernetes/contributors","subscribers_url":"https://api.github.com/repos/kubernetes/kubernetes/subscribers","subscription_url":"https://api.github.com/repos/kubernetes/kubernetes/subscription","commits_url":"https://api.github.com/repos/kubernetes/kubernetes/commits{/sha}","git_commits_url":"https://api.github.com/repos/kubernetes/kubernetes/git/commits{/sha}","comments_url":"https://api.github.com/repos/kubernetes/kubernetes/comments{/number}","issue_comment_url":"https://api.github.com/repos/kubernetes/kubernetes/issues/comments{/number}","contents_url":"https://api.github.com/repos/kubernetes/kubernetes/contents/{+path}","compare_url":"https://api.github.com/repos/kubernetes/kubernetes/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kubernetes/kubernetes/merges","archive_url":"https://api.github.com/repos/kubernetes/kubernetes/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kubernetes/kubernetes/downloads","issues_url":"https://api.github.com/repos/kubernetes/kubernetes/issues{/number}","pulls_url":"https://api.github.com/repos/kubernetes/kubernetes/pulls{/number}","milestones_url":"https://api.github.com/repos/kubernetes/kubernetes/milestones{/number}","notifications_url":"https://api.github.com/repos/kubernetes/kubernetes/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kubernetes/kubernetes/labels{/name}","releases_url":"https://api.github.com/repos/kubernetes/kubernetes/releases{/id}","deployments_url":"https://api.github.com/repos/kubernetes/kubernetes/deployments","created_at":"2014-06-06T22:56:04Z","updated_at":"2016-08-25T20:22:26Z","pushed_at":"2016-08-25T21:07:08Z","git_url":"git://github.com/kubernetes/kubernetes.git","ssh_url":"git@github.com:kubernetes/kubernetes.git","clone_url":"https://github.com/kubernetes/kubernetes.git","svn_url":"https://github.com/kubernetes/kubernetes","homepage":"http://kubernetes.io","size":542247,"stargazers_count":16310,"watchers_count":16310,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":5261,"mirror_url":null,"open_issues_count":4311,"forks":5261,"open_issues":4311,"watchers":16310,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/30787"},"html":{"href":"https://github.com/kubernetes/kubernetes/pull/30787"},"issue":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/30787"},"comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/issues/30787/comments"},"review_comments":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/30787/comments"},"review_comment":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/kubernetes/kubernetes/pulls/30787/commits"},"statuses":{"href":"https://api.github.com/repos/kubernetes/kubernetes/statuses/5057c0ff12e21acf7da93772725af7b1ebfeab47"}}}}
{"actor":{"display_login":"MHBauer"}}