#!/usr/bin/env 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.

# Call this to dump all control_plane and node logs into the folder specified in $1
# (defaults to _artifacts). Only works if the provider supports SSH.

set -o errexit
set -o nounset
set -o pipefail

readonly local_report_dir="${1:-_artifacts}"
report_dir=""
readonly gcs_artifacts_dir="${2:-}"
readonly logexporter_namespace="${3:-logexporter}"

# In order to more trivially extend log-dump for custom deployments,
# check for a function named log_dump_custom_get_instances. If it's
# defined, we assume the function can me called with one argument, the
# role, which is either "control_plane" or "node".
echo 'Checking for custom logdump instances, if any'
if [[ $(type -t log_dump_custom_get_instances) == "function" ]]; then
  readonly use_custom_instance_list=yes
else
  readonly use_custom_instance_list=
fi

readonly control_plane_ssh_supported_providers="gce aws"
readonly node_ssh_supported_providers="gce gke aws"
readonly gcloud_supported_providers="gce gke"

readonly control_plane_logfiles="kube-apiserver.log kube-apiserver-audit.log kube-scheduler.log kube-controller-manager.log etcd.log etcd-events.log glbc.log cluster-autoscaler.log kube-addon-manager.log konnectivity-server.log fluentd.log kubelet.cov"
readonly node_logfiles="kube-proxy.log fluentd.log node-problem-detector.log kubelet.cov"
readonly node_systemd_services="node-problem-detector"
readonly hollow_node_logfiles="kubelet-hollow-node-*.log kubeproxy-hollow-node-*.log npd-hollow-node-*.log"
readonly aws_logfiles="cloud-init-output.log"
readonly gce_logfiles="startupscript.log"
readonly kern_logfile="kern.log"
readonly initd_logfiles="docker/log"
readonly supervisord_logfiles="kubelet.log supervisor/supervisord.log supervisor/kubelet-stdout.log supervisor/kubelet-stderr.log supervisor/docker-stdout.log supervisor/docker-stderr.log"
readonly systemd_services="kubelet kubelet-monitor kube-container-runtime-monitor ${LOG_DUMP_SYSTEMD_SERVICES:-docker}"
readonly extra_log_files="${LOG_DUMP_EXTRA_FILES:-}"
readonly extra_systemd_services="${LOG_DUMP_SAVE_SERVICES:-}"
readonly dump_systemd_journal="${LOG_DUMP_SYSTEMD_JOURNAL:-false}"

# Root directory for Kubernetes files on Windows nodes.
WINDOWS_K8S_DIR="C:\\etc\\kubernetes"
# Directory where Kubernetes log files will be stored on Windows nodes.
export WINDOWS_LOGS_DIR="${WINDOWS_K8S_DIR}\\logs"
# Log files found in WINDOWS_LOGS_DIR on Windows nodes:
readonly windows_node_logfiles="kubelet.log kube-proxy.log docker.log docker_images.log csi-proxy.log"
# Log files found in other directories on Windows nodes:
readonly windows_node_otherfiles="C:\\Windows\\MEMORY.dmp"

# Limit the number of concurrent node connections so that we don't run out of
# file descriptors for large clusters.
readonly max_dump_processes=25

# Indicator variable whether we experienced a significant failure during
# logexporter creation or execution.
logexporter_failed=0

# Percentage of nodes that must be logexported successfully (otherwise the
# process will exit with a non-zero exit code).
readonly log_dump_expected_success_percentage="${LOG_DUMP_EXPECTED_SUCCESS_PERCENTAGE:-0}"

# Example:  kube::util::trap_add 'echo "in trap DEBUG"' DEBUG
# See: http://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal
kube::util::trap_add() {
  local trap_add_cmd
  trap_add_cmd=$1
  shift

  for trap_add_name in "$@"; do
    local existing_cmd
    local new_cmd

    # Grab the currently defined trap commands for this trap
    existing_cmd=$(trap -p "${trap_add_name}" |  awk -F"'" '{print $2}')

    if [[ -z "${existing_cmd}" ]]; then
      new_cmd="${trap_add_cmd}"
    else
      new_cmd="${trap_add_cmd};${existing_cmd}"
    fi

    # Assign the test. Disable the shellcheck warning telling that trap
    # commands should be single quoted to avoid evaluating them at this
    # point instead evaluating them at run time. The logic of adding new
    # commands to a single trap requires them to be evaluated right away.
    # shellcheck disable=SC2064
    trap "${new_cmd}" "${trap_add_name}"
  done
}

# Opposite of kube::util::ensure-temp-dir()
kube::util::cleanup-temp-dir() {
  rm -rf "${KUBE_TEMP}"
}

# Create a temp dir that'll be deleted at the end of this bash session.
#
# Vars set:
#   KUBE_TEMP
kube::util::ensure-temp-dir() {
  if [[ -z ${KUBE_TEMP-} ]]; then
    KUBE_TEMP=$(mktemp -d 2>/dev/null || mktemp -d -t kubernetes.XXXXXX)
    kube::util::trap_add kube::util::cleanup-temp-dir EXIT
  fi
}

# Use the gcloud defaults to find the project.  If it is already set in the
# environment then go with that.
#
# Vars set:
#   PROJECT
#   NETWORK_PROJECT
#   PROJECT_REPORTED
function detect-project() {
  if [[ -z "${PROJECT-}" ]]; then
    PROJECT=$(gcloud config list project --format 'value(core.project)')
  fi

  NETWORK_PROJECT=${NETWORK_PROJECT:-${PROJECT}}

  if [[ -z "${PROJECT-}" ]]; then
    echo "Could not detect Google Cloud Platform project.  Set the default project using " >&2
    echo "'gcloud config set project <PROJECT>'" >&2
    exit 1
  fi
  if [[ -z "${PROJECT_REPORTED-}" ]]; then
    echo "Project: ${PROJECT}" >&2
    echo "Network Project: ${NETWORK_PROJECT}" >&2
    echo "Zone: ${ZONE}" >&2
    PROJECT_REPORTED=true
  fi
}

# Detect Linux and Windows nodes created in the instance group.
#
# Vars set:
#   NODE_NAMES
#   INSTANCE_GROUPS
#   WINDOWS_NODE_NAMES
#   WINDOWS_INSTANCE_GROUPS
function detect-node-names() {
  # These prefixes must not be prefixes of each other, so that they can be used to
  # detect mutually exclusive sets of nodes.
  local -r NODE_INSTANCE_PREFIX=${NODE_INSTANCE_PREFIX:-"${INSTANCE_PREFIX}-minion"}
  local -r WINDOWS_NODE_INSTANCE_PREFIX=${WINDOWS_NODE_INSTANCE_PREFIX:-"${INSTANCE_PREFIX}-windows-node"}
  detect-project
  INSTANCE_GROUPS=()
  INSTANCE_GROUPS+=($(gcloud compute instance-groups managed list \
    --project "${PROJECT}" \
    --filter "name ~ '${NODE_INSTANCE_PREFIX}-.+' AND zone:(${ZONE})" \
    --format='value(name)' || true))
  WINDOWS_INSTANCE_GROUPS=()
  WINDOWS_INSTANCE_GROUPS+=($(gcloud compute instance-groups managed list \
    --project "${PROJECT}" \
    --filter "name ~ '${WINDOWS_NODE_INSTANCE_PREFIX}-.+' AND zone:(${ZONE})" \
    --format='value(name)' || true))

  NODE_NAMES=()
  if [[ -n "${INSTANCE_GROUPS[@]:-}" ]]; then
    for group in "${INSTANCE_GROUPS[@]}"; do
      NODE_NAMES+=($(gcloud compute instance-groups managed list-instances \
        "${group}" --zone "${ZONE}" --project "${PROJECT}" \
        --format='value(instance)'))
    done
  fi
  # Add heapster node name to the list too (if it exists).
  if [[ -n "${HEAPSTER_MACHINE_TYPE:-}" ]]; then
    NODE_NAMES+=("${NODE_INSTANCE_PREFIX}-heapster")
  fi
  WINDOWS_NODE_NAMES=()
  if [[ -n "${WINDOWS_INSTANCE_GROUPS[@]:-}" ]]; then
    for group in "${WINDOWS_INSTANCE_GROUPS[@]}"; do
      WINDOWS_NODE_NAMES+=($(gcloud compute instance-groups managed \
        list-instances "${group}" --zone "${ZONE}" --project "${PROJECT}" \
        --format='value(instance)'))
    done
  fi

  echo "INSTANCE_GROUPS=${INSTANCE_GROUPS[*]:-}" >&2
  echo "NODE_NAMES=${NODE_NAMES[*]:-}" >&2
}

# Detect the IP for the control_plane
#
# Assumed vars:
#   CONTROL_PLANE_NAME
#   ZONE
#   REGION
# Vars set:
#   KUBE_CONTROL_PLANE
#   KUBE_CONTROL_PLANE_IP
function detect-control_plane() {
  detect-project
  KUBE_CONTROL_PLANE=${CONTROL_PLANE_NAME}
  echo "Trying to find control_plane named '${CONTROL_PLANE_NAME}'" >&2
  if [[ -z "${KUBE_CONTROL_PLANE_IP-}" ]]; then
    local control_plane_address_name="${CONTROL_PLANE_NAME}-ip"
    echo "Looking for address '${control_plane_address_name}'" >&2
    if ! KUBE_CONTROL_PLANE_IP=$(gcloud compute addresses describe "${control_plane_address_name}" \
      --project "${PROJECT}" --region "${REGION}" -q --format='value(address)') || \
      [[ -z "${KUBE_CONTROL_PLANE_IP-}" ]]; then
      echo "Could not detect Kubernetes control_plane node.  Make sure you've launched a cluster with 'kube-up.sh'" >&2
      exit 1
    fi
  fi
  if [[ -z "${KUBE_CONTROL_PLANE_INTERNAL_IP-}" ]] && [[ ${GCE_PRIVATE_CLUSTER:-} == "true" ]]; then
      local control_plane_address_name="${CONTROL_PLANE_NAME}-internal-ip"
      echo "Looking for address '${control_plane_address_name}'" >&2
      if ! KUBE_CONTROL_PLANE_INTERNAL_IP=$(gcloud compute addresses describe "${control_plane_address_name}" \
        --project "${PROJECT}" --region "${REGION}" -q --format='value(address)') || \
        [[ -z "${KUBE_CONTROL_PLANE_INTERNAL_IP-}" ]]; then
        echo "Could not detect Kubernetes control_plane node.  Make sure you've launched a cluster with 'kube-up.sh'" >&2
        exit 1
      fi
  fi
  echo "Using control_plane: $KUBE_CONTROL_PLANE (external IP: $KUBE_CONTROL_PLANE_IP; internal IP: ${KUBE_CONTROL_PLANE_INTERNAL_IP:-(not set)})" >&2
}

# SSH to a node by name ($1) and run a command ($2).
function setup() {
  if [[ -z "${use_custom_instance_list}" ]]; then
    echo "Using gce provider, skipping check for LOG_DUMP_SSH_KEY and LOG_DUMP_SSH_USER"
    ZONE="${KUBE_GCE_ZONE:-us-central1-b}"
    REGION="${ZONE%-*}"
    INSTANCE_PREFIX="${KUBE_GCE_INSTANCE_PREFIX:-kubernetes}"
    CLUSTER_NAME="${CLUSTER_NAME:-${INSTANCE_PREFIX}}"
    CONTROL_PLANE_NAME="${INSTANCE_PREFIX}-control_plane"
    GCE_PRIVATE_CLUSTER="${KUBE_GCE_PRIVATE_CLUSTER:-false}"
    detect-project 2>&1
  elif [[ "${KUBERNETES_PROVIDER}" == "gke" ]]; then
    NUM_NODES=${NUM_NODES:-3}
    echo "Using 'use_custom_instance_list' with gke, skipping check for LOG_DUMP_SSH_KEY and LOG_DUMP_SSH_USER"
  elif [[ -z "${LOG_DUMP_SSH_KEY:-}" ]]; then
    echo 'LOG_DUMP_SSH_KEY not set, but required when using log_dump_custom_get_instances'
    exit 1
  elif [[ -z "${LOG_DUMP_SSH_USER:-}" ]]; then
    echo 'LOG_DUMP_SSH_USER not set, but required when using log_dump_custom_get_instances'
    exit 1
  fi
}

function log-dump-ssh() {
  local host="$1"
  local cmd="$2"

  if [[ "${gcloud_supported_providers}" =~ ${KUBERNETES_PROVIDER} ]]; then
    for (( i=0; i<5; i++)); do
      if gcloud compute ssh --ssh-flag="-o LogLevel=quiet" --ssh-flag="-o ConnectTimeout=30" --project "${PROJECT}" --zone="${ZONE}" "${host}" --command "echo test > /dev/null"; then
        break
      fi
      sleep 5
    done
    # Then actually try the command.
    gcloud compute ssh --ssh-flag="-o LogLevel=quiet" --ssh-flag="-o ConnectTimeout=30" --project "${PROJECT}" --zone="${ZONE}" "${host}" --command "${cmd}"
    return
  fi

  ssh -oLogLevel=quiet -oConnectTimeout=30 -oStrictHostKeyChecking=no -i "${LOG_DUMP_SSH_KEY}" "${LOG_DUMP_SSH_USER}@${host}" "${cmd}"
}

# Copy all files /var/log/{$3}.log on node $1 into local dir $2.
# $3 should be a string array of file names.
# This function shouldn't ever trigger errexit, but doesn't block stderr.
function copy-logs-from-node() {
    local -r node="${1}"
    local -r dir="${2}"
    shift
    shift
    local files=("$@")
    # Append "*"
    # The * at the end is needed to also copy rotated logs (which happens
    # in large clusters and long runs).
    files=( "${files[@]/%/*}" )
    # Prepend "/var/log/"
    files=( "${files[@]/#/\/var\/log\/}" )
    # Comma delimit (even the singleton, or scp does the wrong thing), surround by braces.
    local -r scp_files="{$(printf "%s," "${files[@]}")}"

    if [[ "${gcloud_supported_providers}" =~ ${KUBERNETES_PROVIDER} ]]; then
      # get-serial-port-output lets you ask for ports 1-4, but currently (11/21/2016) only port 1 contains useful information
      gcloud compute instances get-serial-port-output --project "${PROJECT}" --zone "${ZONE}" --port 1 "${node}" > "${dir}/serial-1.log" || true
      gcloud compute scp --recurse --project "${PROJECT}" --zone "${ZONE}" "${node}:${scp_files}" "${dir}" > /dev/null || true
    elif  [[ "${KUBERNETES_PROVIDER}" == "aws" ]]; then
      local ip
      ip=$(get_ssh_hostname "${node}")
      scp -oLogLevel=quiet -oConnectTimeout=30 -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" "${SSH_USER}@${ip}:${scp_files}" "${dir}" > /dev/null || true
    elif  [[ -n "${use_custom_instance_list}" ]]; then
      scp -oLogLevel=quiet -oConnectTimeout=30 -oStrictHostKeyChecking=no -i "${LOG_DUMP_SSH_KEY}" "${LOG_DUMP_SSH_USER}@${node}:${scp_files}" "${dir}" > /dev/null || true
    else
      echo "Unknown cloud-provider '${KUBERNETES_PROVIDER}' and use_custom_instance_list is unset too - skipping logdump for '${node}'"
    fi
}

# Save logs for node $1 into directory $2. Pass in any non-common files in $3.
# Pass in any non-common systemd services in $4.
# $3 and $4 should be a space-separated list of files.
# Set $5 to true to indicate it is on control_plane. Default to false.
# This function shouldn't ever trigger errexit
function save-logs() {
    local -r node_name="${1}"
    local -r dir="${2}"
    local files=()
    IFS=' ' read -r -a files <<< "$3"
    local opt_systemd_services="${4:-""}"
    local on_control_plane="${5:-"false"}"

    local extra=()
    IFS=' ' read -r -a extra <<< "$extra_log_files"
    files+=("${extra[@]}")
    if [[ -n "${use_custom_instance_list}" ]]; then
      if [[ -n "${LOG_DUMP_SAVE_LOGS:-}" ]]; then
        local dump=()
        IFS=' ' read -r -a dump <<< "${LOG_DUMP_SAVE_LOGS:-}"
        files+=("${dump[@]}")
      fi
    else
      local providerlogs=()
      case "${KUBERNETES_PROVIDER}" in
        gce|gke)
          IFS=' ' read -r -a providerlogs <<< "${gce_logfiles}"
          ;;
        aws)
          IFS=' ' read -r -a providerlogs <<< "${aws_logfiles}"
          ;;
      esac
      files+=("${providerlogs[@]}")
    fi
    local services
    read -r -a services <<< "${systemd_services} ${opt_systemd_services} ${extra_systemd_services}"

    if log-dump-ssh "${node_name}" "command -v journalctl" &> /dev/null; then
        if [[ "${on_control_plane}" == "true" ]]; then
          log-dump-ssh "${node_name}" "sudo journalctl --output=short-precise -u kube-control_plane-installation.service" > "${dir}/kube-control_plane-installation.log" || true
          log-dump-ssh "${node_name}" "sudo journalctl --output=short-precise -u kube-control_plane-configuration.service" > "${dir}/kube-control_plane-configuration.log" || true
        else
          log-dump-ssh "${node_name}" "sudo journalctl --output=short-precise -u kube-node-installation.service" > "${dir}/kube-node-installation.log" || true
          log-dump-ssh "${node_name}" "sudo journalctl --output=short-precise -u kube-node-configuration.service" > "${dir}/kube-node-configuration.log" || true
        fi
        log-dump-ssh "${node_name}" "sudo journalctl --output=short-precise -k" > "${dir}/kern.log" || true

        for svc in "${services[@]}"; do
            log-dump-ssh "${node_name}" "sudo journalctl --output=cat -u ${svc}.service" > "${dir}/${svc}.log" || true
        done

        if [[ "$dump_systemd_journal" == "true" ]]; then
          log-dump-ssh "${node_name}" "sudo journalctl --output=short-precise" > "${dir}/systemd.log" || true
        fi
    else
        local tmpfiles=()
        for f in "${kern_logfile}" "${initd_logfiles}" "${supervisord_logfiles}"; do
            IFS=' ' read -r -a tmpfiles <<< "$f"
            files+=("${tmpfiles[@]}")
        done
    fi

    # Try dumping coverage profiles, if it looks like coverage is enabled in the first place.
    if log-dump-ssh "${node_name}" "stat /var/log/kubelet.cov" &> /dev/null; then
      if log-dump-ssh "${node_name}" "command -v docker" &> /dev/null; then
        if [[ "${on_control_plane}" == "true" ]]; then
          run-in-docker-container "${node_name}" "kube-apiserver" "cat /tmp/k8s-kube-apiserver.cov" > "${dir}/kube-apiserver.cov" || true
          run-in-docker-container "${node_name}" "kube-scheduler" "cat /tmp/k8s-kube-scheduler.cov" > "${dir}/kube-scheduler.cov" || true
          run-in-docker-container "${node_name}" "kube-controller-manager" "cat /tmp/k8s-kube-controller-manager.cov" > "${dir}/kube-controller-manager.cov" || true
        else
          run-in-docker-container "${node_name}" "kube-proxy" "cat /tmp/k8s-kube-proxy.cov" > "${dir}/kube-proxy.cov" || true
        fi
      else
        echo 'Coverage profiles seem to exist, but cannot be retrieved from inside containers.'
      fi
    fi

    echo 'Changing logfiles to be world-readable for download'
    log-dump-ssh "${node_name}" "sudo chmod -R a+r /var/log" || true

    echo "Copying '${files[*]}' from ${node_name}"
    copy-logs-from-node "${node_name}" "${dir}" "${files[@]}"
}

# Saves a copy of the Windows Docker event log to ${WINDOWS_LOGS_DIR}\docker.log
# on node $1.
function export-windows-docker-event-log() {
    local -r node="${1}"

    local -r powershell_cmd="powershell.exe -Command \"\$logs=\$(Get-EventLog -LogName Application -Source Docker | Format-Table -Property TimeGenerated, EntryType, Message -Wrap); \$logs | Out-File -FilePath '${WINDOWS_LOGS_DIR}\\docker.log'\""

    # Retry up to 3 times to allow ssh keys to be properly propagated and
    # stored.
    for retry in {1..3}; do
      if gcloud compute ssh --project "${PROJECT}" --zone "${ZONE}" "${node}" \
        --command "$powershell_cmd"; then
        break
      else
        sleep 10
      fi
    done
}

# Saves prepulled Windows Docker images list to ${WINDOWS_LOGS_DIR}\docker_images.log
# on node $1.
function export-windows-docker-images-list() {
    local -r node="${1}"

    local -r powershell_cmd="powershell.exe -Command \"\$logs=\$(docker image list); \$logs | Out-File -FilePath '${WINDOWS_LOGS_DIR}\\docker_images.log'\""

    # Retry up to 3 times to allow ssh keys to be properly propagated and
    # stored.
    for retry in {1..3}; do
      if gcloud compute ssh --project "${PROJECT}" --zone "${ZONE}" "${node}" \
        --command "$powershell_cmd"; then
        break
      else
        sleep 10
      fi
    done
}

# Saves log files from diagnostics tool.(https://github.com/GoogleCloudPlatform/compute-image-tools/tree/control_plane/cli_tools/diagnostics)
function save-windows-logs-via-diagnostics-tool() {
    local node="${1}"
    local dest_dir="${2}"

    gcloud compute instances add-metadata "${node}" --metadata enable-diagnostics=true --project="${PROJECT}" --zone="${ZONE}"
    local logs_archive_in_gcs
    logs_archive_in_gcs=$(gcloud alpha compute diagnose export-logs "${node}" "--zone=${ZONE}" "--project=${PROJECT}" | tail -n 1)
    local temp_local_path="${node}.zip"
    for retry in {1..20}; do
      if gsutil mv "${logs_archive_in_gcs}" "${temp_local_path}"  > /dev/null 2>&1; then
        echo "Downloaded diagnostics log from ${logs_archive_in_gcs}"
        break
      else
        sleep 10
      fi
    done

    if [[ -f "${temp_local_path}" ]]; then
      unzip "${temp_local_path}" -d "${dest_dir}" > /dev/null
      rm -f "${temp_local_path}"
    fi
}

# Saves log files from SSH
function save-windows-logs-via-ssh() {
    local node="${1}"
    local dest_dir="${2}"

    export-windows-docker-event-log "${node}"
    export-windows-docker-images-list "${node}"

    local remote_files=()
    for file in "${windows_node_logfiles[@]}"; do
      remote_files+=( "${WINDOWS_LOGS_DIR}\\${file}" )
    done
    remote_files+=( "${windows_node_otherfiles[@]}" )

    # TODO(pjh, yujuhong): handle rotated logs and copying multiple files at the
    # same time.
    for remote_file in "${remote_files[@]}"; do
      # Retry up to 3 times to allow ssh keys to be properly propagated and
      # stored.
      for retry in {1..3}; do
        if gcloud compute scp --recurse --project "${PROJECT}" \
          --zone "${ZONE}" "${node}:${remote_file}" "${dest_dir}" \
          > /dev/null; then
          break
        else
          sleep 10
        fi
      done
    done
}

# Save log files and serial console output from Windows node $1 into local
# directory $2.
# This function shouldn't ever trigger errexit.
function save-logs-windows() {
    local -r node="${1}"
    local -r dest_dir="${2}"

    if [[ ! "${gcloud_supported_providers}" =~ ${KUBERNETES_PROVIDER} ]]; then
      echo "Not saving logs for ${node}, Windows log dumping requires gcloud support"
      return
    fi

    if [[ "${KUBERNETES_PROVIDER}" == "gke" ]]; then
      save-windows-logs-via-diagnostics-tool "${node}" "${dest_dir}"
    else
      save-windows-logs-via-ssh "${node}" "${dest_dir}"
    fi

    # Serial port 1 contains the Windows console output.
    gcloud compute instances get-serial-port-output --project "${PROJECT}" \
      --zone "${ZONE}" --port 1 "${node}" > "${dest_dir}/serial-1.log" || true
}

# Execute a command in container $2 on node $1.
# Uses docker because the container may not ordinarily permit direct execution.
function run-in-docker-container() {
  local node_name="$1"
  local container="$2"
  shift 2
  log-dump-ssh "${node_name}" "docker exec \"\$(docker ps -f label=io.kubernetes.container.name=${container} --format \"{{.ID}}\")\" $*"
}

function dump_control_planes() {
  local control_plane_names=()
  if [[ -n "${use_custom_instance_list}" ]]; then
    while IFS='' read -r line; do control_plane_names+=("$line"); done < <(log_dump_custom_get_instances control_plane)
  elif [[ ! "${control_plane_ssh_supported_providers}" =~ ${KUBERNETES_PROVIDER} ]]; then
    echo "Control_Plane SSH not supported for ${KUBERNETES_PROVIDER}"
    return
  elif [[ -n "${KUBEMARK_CONTROL_PLANE_NAME:-}" ]]; then
    control_plane_names=( "${KUBEMARK_CONTROL_PLANE_NAME}" )
  else
    if ! (detect-control_plane); then
      echo 'Control_Plane not detected. Is the cluster up?'
      return
    fi
    control_plane_names=( "${CONTROL_PLANE_NAME}" )
  fi

  if [[ "${#control_plane_names[@]}" == 0 ]]; then
    echo 'No control_planes found?'
    return
  fi

  proc=${max_dump_processes}
  for control_plane_name in "${control_plane_names[@]}"; do
    control_plane_dir="${report_dir}/${control_plane_name}"
    mkdir -p "${control_plane_dir}"
    save-logs "${control_plane_name}" "${control_plane_dir}" "${control_plane_logfiles}" "" "true" &

    # We don't want to run more than ${max_dump_processes} at a time, so
    # wait once we hit that many nodes. This isn't ideal, since one might
    # take much longer than the others, but it should help.
    proc=$((proc - 1))
    if [[ proc -eq 0 ]]; then
      proc=${max_dump_processes}
      wait
    fi
  done
  # Wait for any remaining processes.
  if [[ proc -gt 0 && proc -lt ${max_dump_processes} ]]; then
    wait
  fi
}

# Dumps logs from nodes in the cluster. Linux nodes to dump logs from can be
# specified via $1 or $use_custom_instance_list. If not specified then the nodes
# to dump logs for will be detected using detect-node-names(); if Windows nodes
# are present then they will be detected and their logs will be dumped too.
function dump_nodes() {
  local node_names=()
  local windows_node_names=()
  if [[ -n "${1:-}" ]]; then
    echo 'Dumping logs for nodes provided as args to dump_nodes() function'
    node_names=( "$@" )
  elif [[ -n "${use_custom_instance_list}" ]]; then
    echo 'Dumping logs for nodes provided by log_dump_custom_get_instances() function'
    while IFS='' read -r line; do node_names+=("$line"); done < <(log_dump_custom_get_instances node)
  elif [[ ! "${node_ssh_supported_providers}" =~ ${KUBERNETES_PROVIDER} ]]; then
    echo "Node SSH not supported for ${KUBERNETES_PROVIDER}"
    return
  else
    echo 'Detecting nodes in the cluster'
    detect-node-names &> /dev/null
    if [[ -n "${NODE_NAMES:-}" ]]; then
      node_names=( "${NODE_NAMES[@]}" )
    fi
    if [[ -n "${WINDOWS_NODE_NAMES:-}" ]]; then
      windows_node_names=( "${WINDOWS_NODE_NAMES[@]}" )
    fi
  fi

  if [[ "${#node_names[@]}" == 0 && "${#windows_node_names[@]}" == 0 ]]; then
    echo 'No nodes found!'
    return
  fi

  node_logfiles_all="${node_logfiles}"
  if [[ "${ENABLE_HOLLOW_NODE_LOGS:-}" == "true" ]]; then
    node_logfiles_all="${node_logfiles_all} ${hollow_node_logfiles}"
  fi

  linux_nodes_selected_for_logs=()
  if [[ -n "${LOGDUMP_ONLY_N_RANDOM_NODES:-}" ]]; then
    # We randomly choose 'LOGDUMP_ONLY_N_RANDOM_NODES' many nodes for fetching logs.
    for index in $(shuf -i 0-$(( ${#node_names[*]} - 1 )) -n "${LOGDUMP_ONLY_N_RANDOM_NODES}")
    do
      linux_nodes_selected_for_logs+=("${node_names[$index]}")
    done
  else
    linux_nodes_selected_for_logs=( "${node_names[@]}" )
  fi
  all_selected_nodes=( "${linux_nodes_selected_for_logs[@]}" )

  proc=${max_dump_processes}
  start="$(date +%s)"
  # log_dump_ssh_timeout is the maximal number of seconds the log dumping over
  # SSH operation can take. Please note that the logic enforcing the timeout
  # is only a best effort. The actual time of the operation may be longer
  # due to waiting for all the child processes below.
  log_dump_ssh_timeout_seconds="${LOG_DUMP_SSH_TIMEOUT_SECONDS:-}"
  for i in "${!all_selected_nodes[@]}"; do
    node_name="${all_selected_nodes[$i]}"
    node_dir="${report_dir}/${node_name}"
    mkdir -p "${node_dir}"
    if [[ "${i}" -lt "${#linux_nodes_selected_for_logs[@]}" ]]; then
      # Save logs in the background. This speeds up things when there are
      # many nodes.
      save-logs "${node_name}" "${node_dir}" "${node_logfiles_all}" "${node_systemd_services}" &
    else
      save-logs-windows "${node_name}" "${node_dir}" &
    fi

    # We don't want to run more than ${max_dump_processes} at a time, so
    # wait once we hit that many nodes. This isn't ideal, since one might
    # take much longer than the others, but it should help.
    proc=$((proc - 1))
    if [[ proc -eq 0 ]]; then
      proc=${max_dump_processes}
      wait
      now="$(date +%s)"
      if [[ -n "${log_dump_ssh_timeout_seconds}" && $((now - start)) -gt ${log_dump_ssh_timeout_seconds} ]]; then
        echo "WARNING: Hit timeout after ${log_dump_ssh_timeout_seconds} seconds, finishing log dumping over SSH shortly"
        break
      fi
    fi
  done
  # Wait for any remaining processes.
  if [[ proc -gt 0 && proc -lt ${max_dump_processes} ]]; then
    wait
  fi
}

# Collect names of nodes which didn't run logexporter successfully.
# This function examines NODE_NAMES but not WINDOWS_NODE_NAMES since logexporter
# does not run on Windows nodes.
#
# Note: This step is O(#nodes^2) as we check if each node is present in the list of succeeded nodes.
# Making it linear would add code complexity without much benefit (as it just takes ~1s for 5k nodes).
# Assumes:
#   NODE_NAMES
# Sets:
#   NON_LOGEXPORTED_NODES
function find_non_logexported_nodes() {
  local file="${gcs_artifacts_dir}/logexported-nodes-registry"
  echo "Listing marker files ($file) for successful nodes..."
  succeeded_nodes=$(gsutil ls "${file}") || return 1
  echo 'Successfully listed marker files for successful nodes'
  NON_LOGEXPORTED_NODES=()
  for node in "${NODE_NAMES[@]}"; do
    if [[ ! "${succeeded_nodes}" =~ ${node} ]]; then
      NON_LOGEXPORTED_NODES+=("${node}")
    fi
  done
}

# This function examines NODE_NAMES but not WINDOWS_NODE_NAMES since logexporter
# does not run on Windows nodes.
function dump_nodes_with_logexporter() {
  if [[ -n "${use_custom_instance_list}" ]]; then
    echo 'Dumping logs for nodes provided by log_dump_custom_get_instances() function'
    NODE_NAMES=()
    while IFS='' read -r line; do NODE_NAMES+=("$line"); done < <(log_dump_custom_get_instances node)
  else
    echo 'Detecting nodes in the cluster'
    detect-node-names &> /dev/null
  fi

  if [[ -z "${NODE_NAMES:-}" ]]; then
    echo 'No nodes found!'
    return
  fi

  # Obtain parameters required by logexporter.
  local -r service_account_credentials="$(base64 "${GOOGLE_APPLICATION_CREDENTIALS}" | tr -d '\n')"
  local -r cloud_provider="${KUBERNETES_PROVIDER}"
  local -r enable_hollow_node_logs="${ENABLE_HOLLOW_NODE_LOGS:-false}"
  local -r logexport_sleep_seconds="$(( 90 + NUM_NODES / 3 ))"
  if [[ -z "${ZONE_NODE_SELECTOR_DISABLED:-}" ]]; then
    local -r node_selector="${ZONE_NODE_SELECTOR_LABEL:-topology.kubernetes.io/zone}: ${ZONE}"
  fi

  # Fill in the parameters in the logexporter daemonset template.
  local -r tmp="${KUBE_TEMP}/logexporter"
  local -r manifest_yaml="${tmp}/logexporter-daemonset.yaml"
  mkdir -p "${tmp}"
  local -r cwd=$(dirname "${BASH_SOURCE[0]}")
  cp "${cwd}/logexporter-daemonset.yaml" "${manifest_yaml}"

  sed -i'' -e "s@{{.NodeSelector}}@${node_selector:-}@g" "${manifest_yaml}"
  sed -i'' -e "s@{{.LogexporterNamespace}}@${logexporter_namespace}@g" "${manifest_yaml}"
  sed -i'' -e "s@{{.ServiceAccountCredentials}}@${service_account_credentials}@g" "${manifest_yaml}"
  sed -i'' -e "s@{{.CloudProvider}}@${cloud_provider}@g" "${manifest_yaml}"
  sed -i'' -e "s@{{.GCSPath}}@${gcs_artifacts_dir}@g" "${manifest_yaml}"
  sed -i'' -e "s@{{.EnableHollowNodeLogs}}@${enable_hollow_node_logs}@g" "${manifest_yaml}"
  sed -i'' -e "s@{{.DumpSystemdJournal}}@${dump_systemd_journal}@g" "${manifest_yaml}"
  sed -i'' -e "s@{{.ExtraLogFiles}}@${extra_log_files}@g" "${manifest_yaml}"
  sed -i'' -e "s@{{.ExtraSystemdServices}}@${extra_systemd_services}@g" "${manifest_yaml}"

  # Create the logexporter namespace, service-account secret and the logexporter daemonset within that namespace.
  if ! kubectl create -f "${manifest_yaml}"; then
    echo 'Failed to create logexporter daemonset.. falling back to logdump through SSH'
    kubectl delete namespace "${logexporter_namespace}" || true
    dump_nodes "${NODE_NAMES[@]}"
    logexporter_failed=1
    return
  fi

  # Periodically fetch list of already logexported nodes to verify
  # if we aren't already done.
  start="$(date +%s)"
  while true; do
    now="$(date +%s)"
    if [[ $((now - start)) -gt ${logexport_sleep_seconds} ]]; then
      echo 'Waiting for all nodes to be logexported timed out.'
      break
    fi
    if find_non_logexported_nodes; then
      if [[ -z "${NON_LOGEXPORTED_NODES:-}" ]]; then
        break
      fi
    fi
    sleep 15
  done

  # Store logs from logexporter pods to allow debugging log exporting process
  # itself.
  proc=${max_dump_processes}
  kubectl get pods -n "${logexporter_namespace}" -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.nodeName}{"\n"}{end}' | (while read -r pod node; do
    echo "Fetching logs from ${pod} running on ${node}"
    mkdir -p "${report_dir}/${node}"
    kubectl logs -n "${logexporter_namespace}" "${pod}" > "${report_dir}/${node}/${pod}.log" &

    # We don't want to run more than ${max_dump_processes} at a time, so
    # wait once we hit that many nodes. This isn't ideal, since one might
    # take much longer than the others, but it should help.
    proc=$((proc - 1))
    if [[ proc -eq 0 ]]; then
      proc=${max_dump_processes}
      wait
    fi
  # Wait for any remaining processes.
  done; wait)

  # List registry of marker files (of nodes whose logexporter succeeded) from GCS.
  for retry in {1..10}; do
    if find_non_logexported_nodes; then
      break
    else
      echo "Attempt ${retry} failed to list marker files for successful nodes"
      if [[ "${retry}" == 10 ]]; then
        echo 'Final attempt to list marker files failed.. falling back to logdump through SSH'
        kubectl delete namespace "${logexporter_namespace}" || true
        dump_nodes "${NODE_NAMES[@]}"
        logexporter_failed=1
        return
      fi
      sleep 2
    fi
  done

  failed_nodes=()
  # The following if is needed, because defaulting for empty arrays
  # seems to treat them as non-empty with single empty string.
  if [[ -n "${NON_LOGEXPORTED_NODES:-}" ]]; then
    for node in "${NON_LOGEXPORTED_NODES[@]:-}"; do
      echo "Logexporter didn't succeed on node ${node}. Queuing it for logdump through SSH."
      failed_nodes+=("${node}")
    done
  fi

  # If less than a certain ratio of the nodes got logexported, report an error.
  if [[ $(((${#NODE_NAMES[@]} - ${#failed_nodes[@]}) * 100)) -lt $((${#NODE_NAMES[@]} * log_dump_expected_success_percentage )) ]]; then
    logexporter_failed=1
  fi

  # Delete the logexporter resources and dump logs for the failed nodes (if any) through SSH.
  kubectl get pods --namespace "${logexporter_namespace}" || true
  kubectl delete namespace "${logexporter_namespace}" || true
  if [[ "${#failed_nodes[@]}" != 0 ]]; then
    echo -e "Dumping logs through SSH for the following nodes:\n${failed_nodes[*]}"
    dump_nodes "${failed_nodes[@]}"
  fi
}

function detect_node_failures() {
  if ! [[ "${gcloud_supported_providers}" =~ ${KUBERNETES_PROVIDER} ]]; then
    return
  fi

  detect-node-names
  if [[ "${KUBERNETES_PROVIDER}" == "gce" ]]; then
    local all_instance_groups=("${INSTANCE_GROUPS[@]}" "${WINDOWS_INSTANCE_GROUPS[@]}")
  else
    local all_instance_groups=("${INSTANCE_GROUPS[@]}")
  fi

  if [ -z "${all_instance_groups:-}" ]; then
    return
  fi
  for group in "${all_instance_groups[@]}"; do
    local creation_timestamp
    creation_timestamp=$(gcloud compute instance-groups managed describe \
                         "${group}" \
                         --project "${PROJECT}" \
                         --zone "${ZONE}" \
                         --format='value(creationTimestamp)')
    echo "Failures for ${group} (if any):"
    gcloud logging read --order=asc \
          --format='table(timestamp,jsonPayload.resource.name,jsonPayload.event_subtype)' \
          --project "${PROJECT}" \
          "resource.type=\"gce_instance\"
           logName=\"projects/${PROJECT}/logs/compute.googleapis.com%2Factivity_log\"
           (jsonPayload.event_subtype=\"compute.instances.hostError\" OR jsonPayload.event_subtype=\"compute.instances.automaticRestart\")
           jsonPayload.resource.name:\"${group}\"
           timestamp >= \"${creation_timestamp}\""
  done
}

function dump_logs() {
  # Copy control_plane logs to artifacts dir locally (through SSH).
  echo "Dumping logs from control_plane locally to '${report_dir}'"
  dump_control_planes
  if [[ "${DUMP_ONLY_CONTROL_PLANE_LOGS:-}" == "true" ]]; then
    echo 'Skipping dumping of node logs'
    return
  fi

  # Copy logs from nodes to GCS directly or to artifacts dir locally (through SSH).
  if [[ -n "${gcs_artifacts_dir}" ]]; then
    echo "Dumping logs from nodes to GCS directly at '${gcs_artifacts_dir}' using logexporter"
    dump_nodes_with_logexporter
  else
    echo "Dumping logs from nodes locally to '${report_dir}'"
    dump_nodes
  fi
}

# Without ${DUMP_TO_GCS_ONLY} == true:
# * only logs exported by logexporter will be uploaded to
#   ${gcs_artifacts_dir}
# * other logs (control_plane logs, nodes where logexporter failed) will be
#   fetched locally to ${report_dir}.
# If $DUMP_TO_GCS_ONLY == 'true', all logs will be uploaded directly to
# ${gcs_artifacts_dir}.
function main() {
  setup
  kube::util::ensure-temp-dir
  if [[ "${DUMP_TO_GCS_ONLY:-}" == "true" ]] && [[ -n "${gcs_artifacts_dir}" ]]; then
    report_dir="${KUBE_TEMP}/logs"
    mkdir -p "${report_dir}"
    echo "${gcs_artifacts_dir}" > "${local_report_dir}/control_plane-and-node-logs.link.txt"
    echo "Dumping logs temporarily to '${report_dir}'. Will upload to '${gcs_artifacts_dir}' later."
  else
    report_dir="${local_report_dir}"
  fi

  dump_logs

  if [[ "${DUMP_TO_GCS_ONLY:-}" == "true" ]] && [[ -n "${gcs_artifacts_dir}" ]]; then
    if [[ "$(ls -A ${report_dir})" ]]; then
      echo "Uploading '${report_dir}' to '${gcs_artifacts_dir}'"

      if gsutil ls "${gcs_artifacts_dir}" > /dev/null; then
        # If "${gcs_artifacts_dir}" exists, the simple call:
        # `gsutil cp -r /tmp/dir/logs ${gcs_artifacts_dir}` will
        #  create subdirectory 'logs' in ${gcs_artifacts_dir}
        #
        # If "${gcs_artifacts_dir}" exists, we want to merge its content
        # with local logs. To do that we do the following trick:
        # * Let's say that ${gcs_artifacts_dir} == 'gs://a/b/c'.
        # * We rename 'logs' to 'c'
        # * Call `gsutil cp -r /tmp/dir/c gs://a/b/`
        #
        # Similar pattern is used in bootstrap.py#L409-L416.
        # It is a known issue that gsutil cp behavior is that complex.
        # For more information on this, see:
        # https://cloud.google.com/storage/docs/gsutil/commands/cp#how-names-are-constructed
        remote_dir=$(dirname ${gcs_artifacts_dir})
        remote_basename=$(basename ${gcs_artifacts_dir})
        mv ${report_dir} "${KUBE_TEMP}/${remote_basename}"
        gsutil -m cp -r -c -z log,txt,xml "${KUBE_TEMP}/${remote_basename}" "${remote_dir}"
        rm -rf "${KUBE_TEMP}/${remote_basename}"
      else  # ${gcs_artifacts_dir} doesn't exist.
        gsutil -m cp -r -c -z log,txt,xml "${report_dir}" "${gcs_artifacts_dir}"
        rm -rf "${report_dir}"
      fi
    else
      echo "Skipping upload of '${report_dir}' as it's empty."
    fi
  fi

  detect_node_failures
  if [[ ${logexporter_failed} -ne 0 && ${log_dump_expected_success_percentage} -gt 0 ]]; then
    return 1
  fi
}

main


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

if [ "$AWS_ROLE_ARN" == "" ]; then
    echo "Empty AWS_ROLE_ARN, this script must be run in a postsubmit pod with IAM Roles for Service Accounts"
    exit 1
fi

cat << EOF > config
[default]
output = json
region = us-west-2
role_arn=$AWS_ROLE_ARN
web_identity_token_file=/var/run/secrets/eks.amazonaws.com/serviceaccount/token

[profile release-prod]
role_arn = arn:aws:iam::379412251201:role/DocsDeploymentRole
region = us-east-1
source_profile=default
EOF

BUCKET_NAME=artifactsstack-379412251201-docsbucketecea003f-bhslmuf2xe3m
DISTRIBUTION_ID=${DISTRIBUTION_ID:-"E1G9R70424D2RN"}

export AWS_CONFIG_FILE=$(pwd)/config
export AWS_DEFAULT_PROFILE=release-prod

aws s3 sync --acl public-read ./site s3://${BUCKET_NAME}
aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID --paths "/404.html" "/assets/" "/community/" "/index.html" "/search/" "/sitemap.xml" "/sitemap.xml.gz" "/users/"


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -x
set -o errexit
set -o nounset
set -o pipefail

TAG="$1"
BIN_PATH="$2"
OS="$3"
ARCH="$4"

CGO_ENABLED=0 GOOS=$OS GOARCH=$ARCH \
	sh build_linux.sh -trimpath \
	-ldflags "-s -w -buildid='' -extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=${TAG}"

 mv bin/* $BIN_PATH
 rm -rf gopath


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -x
set -o errexit
set -o nounset
set -o pipefail

REPO="$1"
OUTPUT_FILE="$2"

function build::plugins::patterns(){
  cd $REPO
  # Pull licenses for the plugins we are building, similiar logic exist in build_linux.sh called above
  # https://github.com/containernetworking/plugins/blob/master/build_linux.sh#L14
  PLUGINS="plugins/meta/* plugins/main/* plugins/ipam/*"
  ALL_PLUGINS=""
  FILES=""
  for d in $PLUGINS; do
    if [ -d "$d" ]; then
      plugin="$(basename "$d")"
      if [ "${plugin}" != "windows" ]; then
        ALL_PLUGINS+="./$d "
        FILES+="$plugin "
      fi
    fi
  done
  mkdir -p $(dirname $OUTPUT_FILE)
  echo "SOURCE_PATTERNS=$ALL_PLUGINS" > $OUTPUT_FILE
  echo "BINARY_TARGET_FILES=$FILES" >> $OUTPUT_FILE
}

build::plugins::patterns


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -x
set -o errexit
set -o nounset
set -o pipefail

MAKE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"

REPO="$1"
GOLANG_VERSION="$2"
GIT_TAG="$3"
RELEASE_BRANCH="$4"

source "${MAKE_ROOT}/build/lib/init.sh"
source "${MAKE_ROOT}/../../../build/lib/common.sh"

OUTPUT_DIR=${MAKE_ROOT}/_output/${RELEASE_BRANCH}
KUBE_GIT_VERSION_FILE=${MAKE_ROOT}/${RELEASE_BRANCH}/KUBE_GIT_VERSION_FILE

build::common::use_go_version $GOLANG_VERSION
build::common::set_go_cache kubernetes $GIT_TAG
build::binaries::kube_bins "$SOURCE_DIR" $RELEASE_BRANCH $GIT_TAG $KUBE_GIT_VERSION_FILE

mkdir -p ${OUTPUT_DIR}/bin
rsync --remove-source-files -a --include '*/' --include 'kube-*' --include 'kubelet*' \
	--include 'kubeadm*' --include 'kubectl*' --exclude '*' ${SOURCE_DIR}/_output/local/bin ${OUTPUT_DIR}

# In presubmit builds space is very limited
rm -rf ${SOURCE_DIR}/_output


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -x
set -o errexit
set -o nounset
set -o pipefail

REPO="$1"
GIT_TAG="$2"
RELEASE_BRANCH="$3"

MAKE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
GIT_TAG="$(cat ${MAKE_ROOT}/${RELEASE_BRANCH}/GIT_TAG)"

source "${MAKE_ROOT}/../../../build/lib/common.sh"
source "${MAKE_ROOT}/build/lib/init.sh"
source "${MAKE_ROOT}/build/lib/tarballs.sh"

if [ ! -d ${OUTPUT_DIR}/${RELEASE_BRANCH} ]; then
    echo "${OUTPUT_DIR}/${RELEASE_BRANCH} not present!"
    exit 1
fi

OUTPUT_RELEASE_DIR="${OUTPUT_DIR}/${RELEASE_BRANCH}"
BIN="${OUTPUT_RELEASE_DIR}/bin"
TAR_OUTPUT_DIR=${OUTPUT_DIR}/tar/${RELEASE_BRANCH}

mkdir -p $TAR_OUTPUT_DIR
build::common::ensure_tar
build::tarballs::create_tarballs $BIN $OUTPUT_RELEASE_DIR $TAR_OUTPUT_DIR

# exclude helper files used for make targets
echo "eks-distro-checkout-$GIT_TAG export-ignore" >> $SOURCE_DIR/.git/info/attributes
echo "eks-distro-patched export-ignore" >> $SOURCE_DIR/.git/info/attributes

# Tag current HEAD of repo which includes the patches so that when the archive is created
# the proper tag will be written into the hack/lib/version.sh file for anyone building from
# this source tarball. Load version file to avoid recreating git version
source "${MAKE_ROOT}/${RELEASE_BRANCH}/KUBE_GIT_VERSION_FILE"
git -C $SOURCE_DIR tag -f $KUBE_GIT_VERSION

git \
    -C $SOURCE_DIR \
    archive \
    --format=tar.gz \
    --output=${TAR_OUTPUT_DIR}/kubernetes-src.tar.gz \
    HEAD


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -o errexit
set -o nounset
set -o pipefail

TAG=$1
RELEASE_BRANCH=$2

BASE_DIRECTORY=$(git rev-parse --show-toplevel)
MAKE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
source "${MAKE_ROOT}/build/lib/init.sh"

VERSION_FILE="${MAKE_ROOT}/${RELEASE_BRANCH}/KUBE_GIT_VERSION_FILE"
rm -f $VERSION_FILE
touch $VERSION_FILE
build::version::create_env_file "$TAG" "$VERSION_FILE" "kubernetes"


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.
set -x
set -o errexit
set -o nounset
set -o pipefail

REPO="$1"
OUTPUT_DIR="$2"
RELEASE_BRANCH="$3"

# The heketi/heketi dependency is dual licensed between Apache 2.0 or LGPLv3+
# this was done at the request of the kubernetes project since the original license
# was not one that allowed redistro.  The pieces used by the kubernetes project follow under
# the apache2 license.
# https://github.com/heketi/heketi/pull/1419
# https://github.com/kubernetes/kubernetes/pull/70828
# Copy the apache2 license into place in the vendor directory
#
# For Kubernetes 1.26+, heketi was removed https://github.com/kubernetes/kubernetes/pull/112015
# This block should be removed once 1-25 is no longer supported.
MINOR_VERSION=${RELEASE_BRANCH: -2}
if [[ $MINOR_VERSION -le 25 ]]; then
  cp $REPO/vendor/github.com/heketi/heketi/LICENSE-APACHE2 $REPO/vendor/github.com/heketi/heketi/LICENSE
  rm -f $REPO/vendor/github.com/heketi/heketi/COPYING-*
fi

# a number of k8s.io dependencies which come from the main repo show
# up in the list and since they are in the repo they have no version
# set the rootmodule name to k8s.io to force all projects with that
# prefix and no version to use the k8s git_tag version
mkdir -p ${OUTPUT_DIR}/attribution
echo "k8s.io" > ${OUTPUT_DIR}/attribution/root-module.txt


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -o errexit
set -o nounset
set -o pipefail

MAKE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
source "${MAKE_ROOT}/build/lib/init.sh"
source "${MAKE_ROOT}/../../../build/lib/common.sh"

RELEASE_BRANCH="$1"
GOLANG_VERSION="$2"

export ARTIFACTS=${ARTIFACTS:-"./_artifacts"}
export KUBE_JUNIT_REPORT_DIR="${ARTIFACTS}"
export KUBE_KEEP_VERBOSE_TEST_OUTPUT=y
export LOG_LEVEL=4
export KUBE_TIMEOUT=${KUBE_TIMEOUT:-"--timeout=600s"}

build::common::use_go_version $GOLANG_VERSION

# Beginning with Go 1.17, using `go get` to install executables was deprecated
# in favor of `go install`. See https://go.dev/doc/go-get-install-deprecation
awk -v short_golang_version="${GOLANG_VERSION:0:4}" \
    -v go_install_min_version="1.17" \
  'BEGIN {
    if (short_golang_version<go_install_min_version)
      system("go get gotest.tools/gotestsum")
    else
      system("go install gotest.tools/gotestsum")
    fi
  };'

cd $MAKE_ROOT/kubernetes

# Install etcd for tests
./hack/install-etcd.sh

export PATH="${GOPATH}/bin:${MAKE_ROOT}/kubernetes/third_party/etcd:${PATH}"

# kube build scripts set GOCACHE and GOMODCACHE to be in the ./_output/local/go/cache directory
# relative to the kubernetes source folder instead
# unsetting these two which we set in our common script to allow kube to fully manage these locations
# and keep the directories we need to clean consistent through versions
unset GOCACHE GOMODCACHE

MAX_RETRIES=5
# There are flakes in upstream tests, the process also caches passing results
# so on rerun it only runs the tests which failed
for i in $(seq 1 $MAX_RETRIES);
do
  [ $i -gt 1 ] && sleep 5
  make test && ret=0 && break || ret=$?;
done

if [ $ret -ne 0 ]; then
  echo "Tests failed after $MAX_RETRIES runs, checking if failures are known flakes"

  latest_log=$(ls -td $ARTIFACTS/junit*.stdout | head -1)
  gotestsum --jsonfile $ARTIFACTS/out.json --raw-command cat "$latest_log"
  jq -r 'select(.Action=="fail" and .Test) | [.Package, .Test]  | join("/")' $ARTIFACTS/out.json > $ARTIFACTS/failed_tests
  non_flakes=$(grep -Fxv -f $MAKE_ROOT/top_flakes $ARTIFACTS/failed_tests || true)

  if [ ! "$non_flakes" ]
  then
        echo "Failures are confirmed flakes.  Tests considered passing"
        ret=0
  else
    echo "
The following tests failed after $MAX_RETRIES runs and are not listed in top_flakes
Check upstream if failing test is a common flake and add it to the top_flakes file:
  https://github.com/kubernetes/community/blob/master/contributors/devel/sig-testing/flaky-tests.md

$non_flakes
"
  fi
fi

exit $ret


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

function build::binaries::kube_bins() {
  local -r repository="$1"
  local -r release_branch="$2"
  local -r git_tag="$3"
  local -r kube_git_version_file="$4"

  export KUBE_GIT_VERSION_FILE=$kube_git_version_file

  cd $repository

  # kube build scripts set GOCACHE and GOMODCACHE to be in the ./_output/local/go/cache directory
  # relative to the kubernetes source folder instead
  # unsetting these two which we set in our common script to allow kube to fully manage these locations
  # and keep the directories we need to clean consistent through versions
  unset GOCACHE GOMODCACHE

  # Ideally, to avoid checksum differences due to modules being downloaded by go mod download vs
  # vendored in the vendor directly, which really only comes into play when build locally vs in a clean
  # builder-base, we would run `./hack/update-vendor.sh` to redownload all the modules avoiding this difference
  # We do this for all projects, however, with kubernetes we actually patch some files in vendor
  # so if we ran this it would overwrite our patched changes
  # TODO: potentially look at ways to run this but reset back to patches after downloads?
  # or once we are using go 1.15, using the seperate cache dirs like we do could help?
  # ./hack/update-vendor.sh

  # Build all core components for linux arm64 and amd64
  # GOLDFLASGS
  # * strip symbol, debug, and DWARF tables
  # * set an empty build id for reproducibility
  # * build static binaries
  # Run in two steps to support passing -trimpath
  export CGO_ENABLED=0
  export GOLDFLAGS='-s -w -buildid=""'
  export KUBE_STATIC_OVERRIDES="cmd/kubelet \
      cmd/kube-proxy \
      cmd/kubeadm \
      cmd/kubectl \
      cmd/kube-apiserver \
      cmd/kube-controller-manager \
      cmd/kube-scheduler"

  # For Kubernetes 1.23 and older, removing `make generated_files` results in this error:
  # cmd/kube-apiserver/app/server.go:401:80: undefined: "k8s.io/kubernetes/pkg/generated/openapi".GetOpenAPIDefinitions
  #
  # This block should be removes when 1.23 is no longer supported.
  local -r minor_version=${release_branch: -2}
  if [[ $minor_version -le 23 ]]; then
    make generated_files
  fi

  # Linux
  for arch in linux/amd64 linux/arm64; do
    export KUBE_BUILD_PLATFORMS="$arch"
    hack/make-rules/build.sh -trimpath cmd/kubelet \
          cmd/kube-proxy \
          cmd/kubeadm \
          cmd/kubectl \
          cmd/kube-apiserver \
          cmd/kube-controller-manager \
          cmd/kube-scheduler

    # In presubmit builds space is very limited
    rm -rf ./_output/local/go/cache
  done

  # Windows
  export KUBE_BUILD_PLATFORMS="windows/amd64"
  hack/make-rules/build.sh -trimpath cmd/kubelet \
    cmd/kube-proxy \
      cmd/kubeadm \
      cmd/kubectl

  # Darwin
  export KUBE_BUILD_PLATFORMS="darwin/amd64"
  hack/make-rules/build.sh -trimpath cmd/kubectl

  # In presubmit builds space is very limited
  rm -rf ./_output/local/go/cache

  cd ..
}


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

MAKE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)"

REPOSITORY="kubernetes"
SOURCE_DIR=${MAKE_ROOT}/${REPOSITORY}

OUTPUT_DIR="${MAKE_ROOT}/_output"

source "${MAKE_ROOT}/build/lib/binaries.sh"
source "${MAKE_ROOT}/build/lib/version.sh"


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

source "${MAKE_ROOT}/../../../build/lib/common.sh"

readonly KUBE_SUPPORTED_SERVER_PLATFORMS=(
  linux/amd64
  linux/arm64
)

readonly KUBE_SUPPORTED_NODE_PLATFORMS=(
  linux/amd64
  linux/arm64
  windows/amd64
)

readonly KUBE_SUPPORTED_CLIENT_PLATFORMS=(
  linux/amd64
  linux/arm64
  darwin/amd64
  windows/amd64
)

### server binaries
function build::tarballs::server_targets() {
  local targets=(
    cmd/kube-proxy
    cmd/kube-apiserver
    cmd/kube-controller-manager
    cmd/kubelet
    cmd/kubeadm
    cmd/kube-scheduler
  )
  echo "${targets[@]}"
}

IFS=" " read -ra KUBE_SERVER_TARGETS <<< "$(build::tarballs::server_targets)"
readonly KUBE_SERVER_TARGETS
readonly KUBE_SERVER_BINARIES=("${KUBE_SERVER_TARGETS[@]##*/}")

### node binaries
function build::tarballs::node_targets() {
  local targets=(
    cmd/kube-proxy
    cmd/kubeadm
    cmd/kubelet
  )
  echo "${targets[@]}"
}

IFS=" " read -ra KUBE_NODE_TARGETS <<< "$(build::tarballs::node_targets)"
readonly KUBE_NODE_TARGETS
readonly KUBE_NODE_BINARIES=("${KUBE_NODE_TARGETS[@]##*/}")
readonly KUBE_NODE_BINARIES_WIN=("${KUBE_NODE_BINARIES[@]/%/.exe}")

### client binaries
readonly KUBE_CLIENT_TARGETS=(
  cmd/kubectl
)
readonly KUBE_CLIENT_BINARIES=("${KUBE_CLIENT_TARGETS[@]##*/}")
readonly KUBE_CLIENT_BINARIES_WIN=("${KUBE_CLIENT_BINARIES[@]/%/.exe}")

function build::tarballs::create_tarballs(){
    local -r bin_root="$1"
    local -r output_dir="$2"
    local -r tar_output_dir="$3"

    for platform in "${KUBE_SUPPORTED_SERVER_PLATFORMS[@]}"; do
        # The substitution on platform_src below will replace all slashes with
        # dashes.  It'll transform darwin/amd64 -> darwin-amd64.
        local platform_src="${platform//\//-}"

        tarball=$tar_output_dir/kubernetes-server-$platform_src.tar.gz
        local ch_dir="${output_dir}/${platform}"
        local bin_dir="${output_dir}/${platform}/kubernetes/server/bin"
        mkdir -p $bin_dir
        for bin in ${KUBE_SERVER_BINARIES[@]}; do
            cp ${bin_root}/${platform}/${bin} $bin_dir
        done
        cp -rf $output_dir/LICENSES $ch_dir/kubernetes
        cp $output_dir/ATTRIBUTION.txt $ch_dir/kubernetes
        build::common::create_tarball $tarball $ch_dir kubernetes
        rm -rf $ch_dir
        rmdir $(dirname $ch_dir)
    done

    for platform in "${KUBE_SUPPORTED_NODE_PLATFORMS[@]}"; do
        # The substitution on platform_src below will replace all slashes with
        # dashes.  It'll transform darwin/amd64 -> darwin-amd64.
        local platform_src="${platform//\//-}"
        tarball=$tar_output_dir/kubernetes-node-$platform_src.tar.gz
        local ch_dir="${output_dir}/${platform}"
        local bin_dir="${output_dir}/${platform}/kubernetes/node/bin"
        mkdir -p $bin_dir
        if [ "$platform" == "windows/amd64" ]; then
            for bin in ${KUBE_NODE_BINARIES_WIN[@]}; do
                cp ${bin_root}/${platform}/${bin} $bin_dir
            done
        else
            for bin in ${KUBE_NODE_BINARIES[@]}; do
                cp ${bin_root}/${platform}/${bin} $bin_dir
            done
        fi
        cp -rf $output_dir/LICENSES $ch_dir/kubernetes
        cp $output_dir/ATTRIBUTION.txt $ch_dir/kubernetes
        build::common::create_tarball $tarball $ch_dir kubernetes
        rm -rf $ch_dir
        rmdir $(dirname $ch_dir)
    done

    for platform in "${KUBE_SUPPORTED_CLIENT_PLATFORMS[@]}"; do
        # The substitution on platform_src below will replace all slashes with
        # dashes.  It'll transform darwin/amd64 -> darwin-amd64.
        local platform_src="${platform//\//-}"
        tarball=$tar_output_dir/kubernetes-client-$platform_src.tar.gz
        local ch_dir="${output_dir}/${platform}"
        local bin_dir="${output_dir}/${platform}/kubernetes/client/bin"
        mkdir -p $bin_dir
        if [ "$platform" == "windows/amd64" ]; then
            for bin in ${KUBE_CLIENT_BINARIES_WIN[@]}; do
                cp ${bin_root}/${platform}/${bin} $bin_dir
            done
        else
            for bin in ${KUBE_CLIENT_BINARIES[@]}; do
                cp ${bin_root}/${platform}/${bin} $bin_dir
            done
        fi
        cp -rf $output_dir/LICENSES $ch_dir/kubernetes
        cp $output_dir/ATTRIBUTION.txt $ch_dir/kubernetes
        build::common::create_tarball $tarball $ch_dir kubernetes
        rm -rf $ch_dir
        rmdir $(dirname $ch_dir)
    done
}


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

function build::version::create_env_file() {
    local -r tag="$1"
    local -r version_file="$2"
    local -r repository="$3"

    local -r source_date_epoch=$(git -C $repository show -s --format=format:%ct $tag^{commit})
    local -r kube_git_version=$tag-eks-$(git -C $repository rev-parse --short=7 HEAD)

    export KUBE_GIT_VERSION=$tag
    export KUBE_GIT_TREE_STATE=clean

    cd $repository

    source "${MAKE_ROOT}/$repository/hack/lib/init.sh"
    source "${MAKE_ROOT}/$repository/hack/lib/version.sh"
    kube::version::get_version_vars
    kube::version::save_version_vars $version_file
    cd -

    local -r version_file_cleaned=$version_file.tmp

    cat $version_file | sed -e "s/${tag}/${kube_git_version}/g"| grep -v "KUBE_GIT_TREE_STATE" > $version_file_cleaned

    cat << EOF >> $version_file_cleaned
SOURCE_DATE_EPOCH='${source_date_epoch}'
KUBE_GIT_TREE_STATE='archive'
EOF
    mv $version_file_cleaned $version_file
}


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -o errexit
set -o nounset
set -o pipefail

OUTPUT_DIR="$1"

MAKE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
ATTRIBUTION_DIR="${OUTPUT_DIR}/attribution"
source "${MAKE_ROOT}/../../../build/lib/common.sh"

# go-licenses calls the main module command-line-arguments in the csv output
MODULE_NAME=$(cat "${ATTRIBUTION_DIR}/root-module.txt")
SEARCH='command-line-arguments'
REPLACE=$(build::common::re_quote $MODULE_NAME)
sed -i.bak "s/^$SEARCH/$REPLACE/" "${ATTRIBUTION_DIR}/go-license.csv"


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.
set -x
set -o errexit
set -o nounset
set -o pipefail

RELEASE_BRANCH="$1"

MAKE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
OUTPUT_DIR="${MAKE_ROOT}/_output/${RELEASE_BRANCH}"
ATTRIBUTION_DIR="${OUTPUT_DIR}/attribution"
source "${MAKE_ROOT}/../../../build/lib/common.sh"

# go-licenses calls adds an additional cmd/livenessprobe
# to the main module name in the csv output
MODULE_NAME=$(cat "${ATTRIBUTION_DIR}/root-module.txt")
SEARCH=$(build::common::re_quote "$MODULE_NAME/cmd/livenessprobe")
REPLACE=$(build::common::re_quote $MODULE_NAME)
sed -i.bak "s/^$SEARCH/$REPLACE/" "${ATTRIBUTION_DIR}/go-license.csv"


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -o errexit
set -o nounset
set -o pipefail

RELEASE_BRANCH="$1"

MAKE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
OUTPUT_DIR="${MAKE_ROOT}/_output/${RELEASE_BRANCH}"
ATTRIBUTION_DIR="${OUTPUT_DIR}/attribution"
source "${MAKE_ROOT}/../../../build/lib/common.sh"

# go-licenses calls adds an additonal cmd/csi-node-driver-registrar
# to the main module name in the csv output
MODULE_NAME=$(cat "${ATTRIBUTION_DIR}/root-module.txt")
SEARCH=$(build::common::re_quote "$MODULE_NAME/cmd/csi-node-driver-registrar")
REPLACE=$(build::common::re_quote $MODULE_NAME)
sed -i.bak "s/^$SEARCH/$REPLACE/" "${ATTRIBUTION_DIR}/go-license.csv"


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -o errexit
set -o nounset
set -o pipefail

SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
BASE_DIRECTORY="$(cd "${SCRIPT_ROOT}/.." && pwd -P)"
source ${BASE_DIRECTORY}/build/lib/common.sh

PROJECT="${1?First required argument is project}"
SOURCE_ARTIFACT_DIR="${2?Second required argument is source artifact directory}"
RELEASE_BRANCH="${3?Third required argument is release branch for example 1-18}"
RELEASE="${4?Fourth required argument is release for example 1}"
GIT_TAG="${5:-}"

DEST_DIR=${BASE_DIRECTORY}/kubernetes-${RELEASE_BRANCH}/releases/${RELEASE}/artifacts

# For when calling from projects other than kubernetes
if [ $PROJECT = "kubernetes" ]; then
  GIT_TAG=$(cat ${BASE_DIRECTORY}/projects/kubernetes/kubernetes/${RELEASE_BRANCH}/GIT_TAG)
fi

ARTIFACT_DIR=${DEST_DIR}/${PROJECT}/${GIT_TAG}
mkdir -p $ARTIFACT_DIR
build::common::echo_and_run cp -r $SOURCE_ARTIFACT_DIR/* $ARTIFACT_DIR

# create checksums in source output since we validate artifacts from that folder
build::common::echo_and_run $SCRIPT_ROOT/create_release_checksums.sh $SOURCE_ARTIFACT_DIR
build::common::echo_and_run $SCRIPT_ROOT/create_release_checksums.sh $ARTIFACT_DIR


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -o errexit
set -o nounset
set -o pipefail

SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
BASE_DIRECTORY="$(cd "${SCRIPT_ROOT}/.." && pwd -P)"
source ${BASE_DIRECTORY}/build/lib/common.sh

ASSET_ROOT="$1"

FIND=find
if which gfind &>/dev/null; then
    FIND=gfind
elif which gnudate &>/dev/null; then
    FIND=gnufind
fi

SHA256SUM=$(dirname ${ASSET_ROOT})/SHA256SUM
SHA512SUM=$(dirname ${ASSET_ROOT})/SHA512SUM
rm -f $SHA256SUM
rm -f $SHA512SUM
echo "Writing artifact hashes to SHA256SUM/SHA512SUM files in folder: $ASSET_ROOT"
cd $ASSET_ROOT
for file in $(find ${ASSET_ROOT} -type f -not -path '*\.sha[25][51][62]' -not -path '*\.docker_*' \( -path '*bin/linux*' -o -path '*bin/windows*' -o -path '*bin/darwin*' -o -name '*tar\.gz' \) ); do
    filepath=$(realpath --relative-base=${ASSET_ROOT} $file )
    sha256sum "$filepath" | tee -a $SHA256SUM > "$file.sha256" || return 1
    sha512sum "$filepath" | tee -a $SHA512SUM > "$file.sha512" || return 1
done

mv $SHA256SUM $SHA512SUM "$ASSET_ROOT"
sha256sum SHA256SUM > "SHA256SUM.sha256" || return 1
sha512sum SHA256SUM > "SHA256SUM.sha512" || return 1
sha256sum SHA512SUM > "SHA512SUM.sha256" || return 1
sha512sum SHA512SUM > "SHA512SUM.sha512" || return 1

cat SHA256SUM
cd -


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -euxo pipefail

ARTIFACT_BUCKET="${1?First required argument should be bucket to create}"

# Create the bucket if it doesn't exist
_bucket_name=$(aws s3api list-buckets  --query "Buckets[?Name=='$ARTIFACT_BUCKET'].Name | [0]" --out text)
if [ $_bucket_name == "None" ]; then
    echo "Creating artifact bucket: s3://$ARTIFACT_BUCKET"
    if [ "$AWS_DEFAULT_REGION" == "us-east-1" ]; then
        aws s3api create-bucket --bucket $ARTIFACT_BUCKET
    else
        aws s3api create-bucket --bucket $ARTIFACT_BUCKET --create-bucket-configuration LocationConstraint=$AWS_DEFAULT_REGION
    fi
else
    echo "Using existing artifact bucket: s3://$ARTIFACT_BUCKET"
fi


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -euxo pipefail

RELEASE_BRANCH="${1?First required argument is release branch for example 1-18}"
RELEASE="${2?Second required argument is release for example 1}"
IMAGE_REPO="${3?Third required argument is image repository}"
REPO_OWNER=${REPO_OWNER:-aws}

BASE_DIRECTORY=$(git rev-parse --show-toplevel)
cd ${BASE_DIRECTORY}

DEV_RELEASE=true
if [[ "$JOB_NAME" =~ "prod-release" ]]; then
    DEV_RELEASE=false
fi

REPOSITORY="https://github.com/${REPO_OWNER}/eks-distro-build-tooling.git"
rm -rf ./eks-distro-build-tooling
git clone ${REPOSITORY}
make -C eks-distro-build-tooling/release
DESTINATION="./kubernetes-${RELEASE_BRANCH}/kubernetes-${RELEASE_BRANCH}-eks-${RELEASE}.yaml"
./eks-distro-build-tooling/release/bin/eks-distro-release release \
    --image-repository ${IMAGE_REPO} \
    --release-branch ${RELEASE_BRANCH} \
    --release-number ${RELEASE} \
    --dev-release=${DEV_RELEASE} | tee ${DESTINATION}
mkdir -p releasechannels
grep -v '^#.*' eks-distro-build-tooling/release/config/${RELEASE_BRANCH}/${RELEASE_BRANCH}.yaml \
    | sed "s/latestRelease: .*/latestRelease: ${RELEASE}/" >releasechannels/${RELEASE_BRANCH}.yaml
mkdir -p crds
grep -v '^#.*' eks-distro-build-tooling/release/config/crds/releasechannels.distro.eks.amazonaws.com-v1alpha1.yaml \
    >crds/releasechannels.distro.eks.amazonaws.com-v1alpha1.yaml
grep -v '^#.*' eks-distro-build-tooling/release/config/crds/releases.distro.eks.amazonaws.com-v1alpha1.yaml \
    >crds/releases.distro.eks.amazonaws.com-v1alpha1.yaml


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

AWS_ROLE_ARN="${AWS_ROLE_ARN?The AWS_ROLE_ARN must be set}"
ARTIFACT_DEPLOYMENT_ROLE_ARN="${ARTIFACT_DEPLOYMENT_ROLE_ARN?The ARTIFACT_DEPLOYMENT_ROLE_ARN must be set}"
SNS_TOPIC_ARN="${SNS_TOPIC_ARN?The SNS_TOPIC_ARN must be set}"

BASE_DIRECTORY=$(git rev-parse --show-toplevel)
cd ${BASE_DIRECTORY}

cat << EOF > awscliconfig
[default]
output=json
region=${AWS_REGION:-${AWS_DEFAULT_REGION:-us-west-2}}
role_arn=$AWS_ROLE_ARN
web_identity_token_file=/var/run/secrets/eks.amazonaws.com/serviceaccount/token

[profile release-account]
role_arn=$ARTIFACT_DEPLOYMENT_ROLE_ARN
region=${AWS_REGION:-${AWS_DEFAULT_REGION:-us-east-1}}
source_profile=default
EOF
export AWS_CONFIG_FILE=$(pwd)/awscliconfig
export AWS_PROFILE=release-account
unset AWS_ROLE_ARN AWS_WEB_IDENTITY_TOKEN_FILE

git -C . diff --name-only HEAD^ HEAD |
grep '^docs/contents/releases' |
grep release-announcement.txt |
while read ANNOUNCEMENT
do
    ${BASE_DIRECTORY}/release/sns_notification.sh ${ANNOUNCEMENT} ${SNS_TOPIC_ARN}
done


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

if [ "$AWS_ROLE_ARN" == "" ]; then
    echo "Empty AWS_ROLE_ARN"
    exit 1
fi

if [ "$ARTIFACT_DEPLOYMENT_ROLE_ARN" == "" ]; then
    echo "Empty ARTIFACT_DEPLOYMENT_ROLE_ARN"
    exit 1
fi

BASE_DIRECTORY=$(git rev-parse --show-toplevel)
cd ${BASE_DIRECTORY}
RELEASE_ENVIRONMENT=${RELEASE_ENVIRONMENT:-development}

export RELEASE=$(cat ${BASE_DIRECTORY}/release/${RELEASE_BRANCH}/${RELEASE_ENVIRONMENT}/RELEASE)

if [ "${RELEASE}" == "0" ]
then
    echo "No production release zero"
    exit 0
fi

cat << EOF > awscliconfig
[default]
output=json
region=${AWS_REGION:-${AWS_DEFAULT_REGION:-us-west-2}}
role_arn=$AWS_ROLE_ARN
web_identity_token_file=/var/run/secrets/eks.amazonaws.com/serviceaccount/token

[profile release-account]
role_arn=$ARTIFACT_DEPLOYMENT_ROLE_ARN
region=${AWS_REGION:-${AWS_DEFAULT_REGION:-us-east-1}}
source_profile=default
EOF
export AWS_CONFIG_FILE=$(pwd)/awscliconfig
export AWS_PROFILE=release-account
unset AWS_ROLE_ARN AWS_WEB_IDENTITY_TOKEN_FILE

cp -r /$HOME/.docker ${BASE_DIRECTORY}
export DOCKER_CONFIG=${BASE_DIRECTORY}/.docker
${BASE_DIRECTORY}/development/ecr/ecr-command.sh install-ecr-public
${BASE_DIRECTORY}/development/ecr/ecr-command.sh login-ecr-public
make release ${*}


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

if [ "$AWS_ROLE_ARN" == "" ]; then
    echo "Empty AWS_ROLE_ARN"
    exit 1
fi
BASE_DIRECTORY=$(git rev-parse --show-toplevel)
cd ${BASE_DIRECTORY}
RELEASE_ENVIRONMENT=${RELEASE_ENVIRONMENT:-development}

export RELEASE=$(cat ${BASE_DIRECTORY}/release/${RELEASE_BRANCH}/${RELEASE_ENVIRONMENT}/RELEASE)

if [ "${RELEASE}" == "0" ]
then
    echo "No dev release zero"
    exit 0
fi

cp -r /$HOME/.docker ${BASE_DIRECTORY}
export DOCKER_CONFIG=${BASE_DIRECTORY}/.docker
${BASE_DIRECTORY}/development/ecr/ecr-command.sh install-ecr-public
${BASE_DIRECTORY}/development/ecr/ecr-command.sh login-ecr-public
make release ${*}


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -euxo pipefail

RELEASE_BRANCH="${1?First required argument is release branch for example 1-18}"
RELEASE="${2?Second required argument is release for example 1}"
ARTIFACT_BUCKET="${3?Third required argument is artifact bucket name}"
CRDS="${4:-false}"
DRY_RUN="${5:-false}"

BASE_DIRECTORY=$(git rev-parse --show-toplevel)

PUBLIC_READ='--acl public-read'

cd ${BASE_DIRECTORY}
PREFIX_DIR=kubernetes-${RELEASE_BRANCH}
DEST_DIR=${PREFIX_DIR}/releases/${RELEASE}/artifacts

if [ "$DRY_RUN" = "true" ]; then
  aws s3 cp $DEST_DIR s3://${ARTIFACT_BUCKET}/${DEST_DIR} ${PUBLIC_READ} --recursive --dryrun
else
  aws s3 sync $DEST_DIR s3://${ARTIFACT_BUCKET}/${DEST_DIR} ${PUBLIC_READ}
fi

if [ "$CRDS" != "true" ]
then
  exit 0
fi
if [ "$DRY_RUN" = "true" ]; then
  echo "dry run not supported for crd uploads!"
  exit 1
fi

cd ${PREFIX_DIR}

for CRD
in *yaml
do
  aws s3 ls s3://${ARTIFACT_BUCKET}/${PREFIX_DIR}/${CRD} || aws s3 cp ${CRD} s3://${ARTIFACT_BUCKET}/${PREFIX_DIR}/${CRD} ${PUBLIC_READ}
done
cd ${BASE_DIRECTORY}
if [ -d crds ]
then
  for CRD
  in crds/*yaml
  do
    aws s3 ls s3://${ARTIFACT_BUCKET}/${CRD} || aws s3 cp ${CRD} s3://${ARTIFACT_BUCKET}/${CRD} ${PUBLIC_READ}
  done
fi
if [ -d releasechannels ]
then
  for CHANNEL
  in releasechannels/*yaml
  do
    aws s3 cp ${CHANNEL} s3://${ARTIFACT_BUCKET}/${CHANNEL} ${PUBLIC_READ}
  done
fi


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

ANNOUNCEMENT_FILE="${1?First required argument is file path (from base directory) for announcement message}"
SNS_TOPIC_ARN="${2?Second required argument is SNS topic ARN}"

# Get release notification subject
RELEASE_NUMBER=$(echo "${ANNOUNCEMENT_FILE}" | grep -o -E "[[:digit:]]{1}\-[[:digit:]]{2}") # e.g. 1-19
if [ -z "$RELEASE_NUMBER" ]; then
  echo "Failed to publish release notification: Unable to generate release number for notification subject"
  exit 1
fi
NOTIFICATION_SUBJECT="New Release of EKS-D v$RELEASE_NUMBER"

# Get release notification body
if ! [ -s "$ANNOUNCEMENT_FILE" ]; then
  echo "Failed to publish release notification: Non-empty text for notification body expected at ${ANNOUNCEMENT_FILE}"
  exit 1
fi
NOTIFICATION_BODY=$(<"${ANNOUNCEMENT_FILE}")

# Publish release notification
echo "
Sending SNS message with the following details:
    - Topic ARN: $SNS_TOPIC_ARN
    - Subject: $NOTIFICATION_SUBJECT
    - Body: $NOTIFICATION_BODY"

SNS_MESSAGE_ID=$(
  aws sns publish \
    --topic-arn "$SNS_TOPIC_ARN" \
    --subject "$NOTIFICATION_SUBJECT" \
    --message "$NOTIFICATION_BODY" \
    --query "MessageId" --output text
)

if [ "$SNS_MESSAGE_ID" ]; then
  echo -e "\nRelease notification published with SNS MessageId $SNS_MESSAGE_ID"
else
  echo "Received unexpected response while publishing to release SNS topic. An error may have occurred, and the \
notification may not have not have been published"
  exit 1
fi


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -e
set -o pipefail
set -x

NEW_TAG="$1"

SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"

${SCRIPT_ROOT}/../pr-scripts/update_local_branch.sh eks-distro-prow-jobs
${SCRIPT_ROOT}/../pr-scripts/update_image_tag.sh eks-distro-prow-jobs 'builder-base:(.+)-.*' 'builder-base:'"\1-$NEW_TAG" '*.yaml'
${SCRIPT_ROOT}/../pr-scripts/update_image_tag.sh eks-distro-prow-jobs '(.+)-.*' "\1-$NEW_TAG" BUILDER_BASE_TAG_FILE
${SCRIPT_ROOT}/../pr-scripts/create_pr.sh eks-distro-prow-jobs '*.yaml'

${SCRIPT_ROOT}/../pr-scripts/update_local_branch.sh eks-anywhere-prow-jobs
${SCRIPT_ROOT}/../pr-scripts/update_image_tag.sh eks-anywhere-prow-jobs 'builder-base:(.+)-.*' 'builder-base:'"\1-$NEW_TAG" '*.yaml'
${SCRIPT_ROOT}/../pr-scripts/update_image_tag.sh eks-anywhere-prow-jobs '(.+)-.*' "\1-$NEW_TAG" BUILDER_BASE_TAG_FILE
${SCRIPT_ROOT}/../pr-scripts/create_pr.sh eks-anywhere-prow-jobs '*.yaml'


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

# Script to perform buildkit builds in daemonless mode

set -e
set -o pipefail
set -x

tmp=$(mktemp -d /tmp/buildctl-daemonless.XXXXXX)
trap "kill \$(cat $tmp/pid); rm -rf $tmp" EXIT

start::buildkitd() {
    buildkitd --addr=unix:///run/buildkit/buildkitd.sock --oci-worker-platform=linux/amd64 --oci-worker-platform=linux/arm64 >$tmp/log 2>&1 &
    pid=$!
    echo $pid >$tmp/pid
}

wait::for::buildkitd() {
    try=0
    max_retries=10
    until buildctl --addr=unix:///run/buildkit/buildkitd.sock debug workers >/dev/null 2>&1; do
        if [ $try -gt $max_retries ]; then
            echo >&2 "could not connect to Buildkit socket after $max_retries trials"
            echo >&2 "========== log =========="
            cat >&2 $tmp/log
            exit 1
        fi
        sleep $(awk "BEGIN{print (100 + $try * 20) * 0.001}")
        try=$(expr $try + 1)
    done
}

start::buildkitd
wait::for::buildkitd

buildctl --addr=unix:///run/buildkit/buildkitd.sock "$@"


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -e
set -o pipefail

TARGETARCH=${TARGETARCH:-amd64}
USR=${USR:-${NEWROOT}/usr}
USR_LOCAL=${USR_LOCAL:-${USR}/local}
USR_BIN=${USR}/bin
USR_LOCAL_BIN=${USR_LOCAL}/bin

BASE_DIR=""

IS_AL23=false
if [ -f /etc/yum.repos.d/amazonlinux.repo ] && grep -q "2023" /etc/yum.repos.d/amazonlinux.repo; then
    IS_AL23=true
fi

[ ${SKIP_INSTALL:-false} != false ] || mkdir -p $USR_BIN $USR_LOCAL_BIN


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

# Script to perform docker builds in daemonless mode

set -e
set -o pipefail
set -x

start::dockerd() {
    dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 &>/var/log/docker.log &
}

wait::for::dockerd() {
    try=0
    max_retries=10
    until docker info >/dev/null 2>&1; do
        if [ $try -gt $max_retries ]; then
            echo >&2 "could not connect to Docker socket after $max_retries trials"
            echo >&2 "========== log =========="
            cat /var/log/docker.log
            exit 1
        fi
        sleep $(awk "BEGIN{print (100 + $try * 20) * 0.001}")
        try=$(expr $try + 1)
    done
}


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -x
set -e
set -o pipefail

SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"

VERSION="$1"
OUTPUT_DIR="$2"

RELEASE_NUMBER="$(echo $VERSION | cut -d'-' -f 2)"

source $SCRIPT_ROOT/common_vars.sh

function build::go::download(){
    # Set up specific go version by using go get, additional versions apart from default can be installed by calling
    # the function again with the specific parameter.
    local version=${1%-*}
    local outputDir=${2}
    local arch=${3}

    for artifact in golang golang-bin; do
        local filename="$outputDir/$arch/$artifact-$version-$RELEASE_NUMBER.amzn2.eks.$arch.rpm"
        if [ ! -f $filename ]; then
            curl -sSL --retry 5 https://distro.eks.amazonaws.com/golang-go$version/releases/$RELEASE_NUMBER/$arch/RPMS/$arch/$artifact-$version-$RELEASE_NUMBER.amzn2.eks.$arch.rpm -o $filename --create-dirs
            curl -sSL --retry 5 https://distro.eks.amazonaws.com/golang-go$version/releases/$RELEASE_NUMBER/$arch/RPMS/$arch/$artifact-$version-$RELEASE_NUMBER.amzn2.eks.$arch.rpm.sha256 -o $filename.sha256

            if [[ $(sha256sum ${filename} | cut -d' ' -f1) != $(cut -d' ' -f1 "${filename}.sha256") ]] ; then
                echo "Checksum doesn't match!"
                exit 1
            fi
        fi
    done

    for artifact in golang-docs golang-misc golang-tests golang-src; do
        local filename="$outputDir/$arch/$artifact-$version-$RELEASE_NUMBER.amzn2.eks.noarch.rpm"
        if [ ! -f $filename ]; then
            curl -sSL --retry 5 https://distro.eks.amazonaws.com/golang-go$version/releases/$RELEASE_NUMBER/$arch/RPMS/noarch/$artifact-$version-$RELEASE_NUMBER.amzn2.eks.noarch.rpm -o $filename --create-dirs
            curl -sSL --retry 5 https://distro.eks.amazonaws.com/golang-go$version/releases/$RELEASE_NUMBER/$arch/RPMS/noarch/$artifact-$version-$RELEASE_NUMBER.amzn2.eks.noarch.rpm.sha256 -o $filename.sha256

            if [[ $(sha256sum ${filename} | cut -d' ' -f1) != $(cut -d' ' -f1 "${filename}.sha256") ]] ; then
                echo "Checksum doesn't match!"
                exit 1
            fi
        fi
    done
}

build::go::download "${VERSION}" "$OUTPUT_DIR" "x86_64"
build::go::download "${VERSION}" "$OUTPUT_DIR" "aarch64"


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -e
set -o pipefail

SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"

NEWROOT=/ansible

source $SCRIPT_ROOT/common_vars.sh

function instal_ansible() {
    local -r deps="python3-pip"
    yum install -y $deps

    #################### IMAGE BUILDER ####################
    # Install image-builder build dependencies - pip, Ansible, Packer
    # Post upgrade, pip3 got renamed to pip and moved locations. It works completely with python3
    # Symlinking pip3 to pip, to have pip3 commands work successfully
    if [ "$IS_AL23" = "false" ]; then
        pip3 install --no-cache-dir -U pip setuptools
        ln -sf $USR_LOCAL_BIN/pip $USR_BIN/pip3
    fi

    ANSIBLE_VERSION="$ANSIBLE_VERSION"
    pip3 install --user --no-cache-dir "ansible-core==$ANSIBLE_VERSION"

    PYWINRM_VERSION="$PYWINRM_VERSION"
    pip3 install --user --no-cache-dir "pywinrm==$PYWINRM_VERSION"

    rm -rf ${NEWROOT}/usr/*
    mv /root/.local/* ${NEWROOT}/usr

    rm -rf /root/.cache
}

[ ${SKIP_INSTALL:-false} != false ] || instal_ansible


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -e
set -o pipefail

SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"

NEWROOT=/aws-cli

source $SCRIPT_ROOT/common_vars.sh

function install_aws_cli() {
    if [ $TARGETARCH == 'amd64' ]; then
        ARCH='x86_64'
    else
        ARCH='aarch64'
    fi

    wget \
        --progress dot:giga \
        https://awscli.amazonaws.com/awscli-exe-linux-$ARCH.zip
    unzip -qq awscli-exe-linux-$ARCH.zip
    ./aws/install
    aws --version

    # install symlinks so we cant install directly to our overridden usr/local
    if [ "$USR_LOCAL" != "/usr/local" ]; then
        mv /usr/local/aws-cli $USR_LOCAL
        mv /usr/local/bin/{aws,aws_completer} $USR_LOCAL_BIN
    fi

    rm awscli-exe-linux-$ARCH.zip
    rm -rf aws
}

[ ${SKIP_INSTALL:-false} != false ] || install_aws_cli


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

set -e
set -o pipefail

SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
source $SCRIPT_ROOT/common_vars.sh

# since we are using the minimal-base-builder
# policycoreutils is only half installed and the rpm db
# is technically in an invalid state
# removing it to avoid issues in future rpm transactions
yum remove -y policycoreutils > /dev/null 2>&1

# keep rpms around since we use them in every stage
if [ "$IS_AL23" = "true" ]; then
    echo "keepcache=1" >> /etc/dnf/dnf.conf
    rm -rf /var/cache/dnf
    ln -s yum /var/cache/dnf
    rm -f /var/lib/dnf/history.*
else
    sed -i 's/keepcache=0/keepcache=1/g' /etc/yum.conf
    yum history new
fi

yum install --setopt=install_weak_deps=False -y \
    gzip \
    tar \
    unzip \
    wget

chmod -R 777 /newroot
rm -rf /newroot


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

# This script is used to install the necessary dependencies on the pod
# building the builder-base as well as into the builder-base itself
# Note: since we run the build in fargate we do not have access to an overlayfs
# so we use a single script from the dockerfile instead of layers to avoid
# layer duplicate and running out of disk space
# This does make local builds painful.  Its recommended to add new additions
# in their own script/layer while testing and then when you are done add
# to here

set -e
set -o pipefail

SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"

NEWROOT=/bash

source $SCRIPT_ROOT/common_vars.sh

BASH_DOWNLOAD_URL="http://ftp.gnu.org/gnu/bash/bash-$OVERRIDE_BASH_VERSION.tar.gz"

function install_bash() {
    # al23 already ships with 5.1
    if [ "$IS_AL23" != "false" ]; then
        return
    fi

    # Bash 4.3 is required to run kubernetes make test
    wget --progress dot:giga $BASH_DOWNLOAD_URL
    tar -xf bash-$OVERRIDE_BASH_VERSION.tar.gz
    sha256sum -c $BASE_DIR/bash-checksum
    cd bash-$OVERRIDE_BASH_VERSION
    ./configure --prefix=${NEWROOT}/usr --without-bash-malloc
    make
    make install

    cd ..
    rm -rf bash-$OVERRIDE_BASH_VERSION.tar.gz bash-$OVERRIDE_BASH_VERSION
}

[ ${SKIP_INSTALL:-false} != false ] || install_bash


#!/usr/bin/env bash
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# 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.

# This script is used to install the necessary dependencies on the pod
# building the builder-base as well as into the builder-base itself
# Note: since we run the build in fargate we do not have access to an overlayfs
# so we use a single script from the dockerfile instead of layers to avoid
# layer duplicate and running out of disk space
# This does make local builds painful.  Its recommended to add new additions
# in their own script/layer while testing and then when you are done add
# to here

set -e
set -o pipefail

SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"

NEWROOT=/buildkit

source $SCRIPT_ROOT/common_vars.sh

BUILDKIT_DOWNLOAD_URL="https://github.com/moby/buildkit/releases/download/$BUILDKIT_VERSION/buildkit-$BUILDKIT_VERSION.linux-$TARGETARCH.tar.gz"

function install_buildkit() {
    wget \
        --progress dot:giga \
        $BUILDKIT_DOWNLOAD_URL
    sha256sum -c $BASE_DIR/buildkit-$TARGETARCH-checksum
    tar -C $USR -xzf buildkit-$BUILDKIT_VERSION.linux-$TARGETARCH.tar.gz
    rm -rf buildkit-$BUILDKIT_VERSION.linux-$TARGETARCH.tar.gz
}

[ ${SKIP_INSTALL:-false} != false ] || install_buildkit