mirror of https://github.com/k3s-io/k3s
Merge remote-tracking branch 'origin/master' into release-1.14. Deleting CHANGELOG-1.12.md
commit
e5777aab95
|
@ -223,6 +223,11 @@
|
|||
"sideEffects": {
|
||||
"description": "SideEffects states whether this webhookk has side effects. Acceptable values are: Unknown, None, Some, NoneOnDryRun Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission change and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some. Defaults to Unknown.",
|
||||
"type": "string"
|
||||
},
|
||||
"timeoutSeconds": {
|
||||
"description": "TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, the webhook call will be ignored or the API call will fail based on the failure policy. The timeout value must be between 1 and 30 seconds. Default to 30 seconds.",
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
|
@ -17,7 +17,7 @@ COPY elasticsearch_logging_discovery.go go.mod go.sum /
|
|||
RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -a -ldflags "-w" -o /elasticsearch_logging_discovery /elasticsearch_logging_discovery.go
|
||||
|
||||
|
||||
FROM docker.elastic.co/elasticsearch/elasticsearch-oss:6.3.2
|
||||
FROM docker.elastic.co/elasticsearch/elasticsearch-oss:6.6.1
|
||||
|
||||
VOLUME ["/data"]
|
||||
EXPOSE 9200 9300
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
PREFIX = gcr.io/fluentd-elasticsearch
|
||||
IMAGE = elasticsearch
|
||||
TAG = v6.3.0
|
||||
TAG = v6.6.1
|
||||
|
||||
build:
|
||||
gcloud builds submit --tag ${PREFIX}/${IMAGE}:${TAG}
|
||||
gcloud builds submit --tag ${PREFIX}/${IMAGE}:${TAG}
|
||||
|
|
|
@ -54,7 +54,7 @@ metadata:
|
|||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: elasticsearch-logging
|
||||
version: v6.3.0
|
||||
version: v6.6.1
|
||||
kubernetes.io/cluster-service: "true"
|
||||
addonmanager.kubernetes.io/mode: Reconcile
|
||||
spec:
|
||||
|
@ -63,17 +63,17 @@ spec:
|
|||
selector:
|
||||
matchLabels:
|
||||
k8s-app: elasticsearch-logging
|
||||
version: v6.3.0
|
||||
version: v6.6.1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: elasticsearch-logging
|
||||
version: v6.3.0
|
||||
version: v6.6.1
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
serviceAccountName: elasticsearch-logging
|
||||
containers:
|
||||
- image: k8s.gcr.io/elasticsearch:v6.3.0
|
||||
- image: gcr.io/fluentd-elasticsearch/elasticsearch:v6.6.1
|
||||
name: elasticsearch-logging
|
||||
resources:
|
||||
# need more cpu upon initialization, therefore burstable class
|
||||
|
|
|
@ -21,7 +21,7 @@ spec:
|
|||
spec:
|
||||
containers:
|
||||
- name: kibana-logging
|
||||
image: docker.elastic.co/kibana/kibana-oss:6.3.2
|
||||
image: docker.elastic.co/kibana/kibana-oss:6.6.1
|
||||
resources:
|
||||
# need more cpu upon initialization, therefore burstable class
|
||||
limits:
|
||||
|
|
|
@ -66,19 +66,19 @@ spec:
|
|||
- '-c'
|
||||
- >
|
||||
LIVENESS_THRESHOLD_SECONDS=${LIVENESS_THRESHOLD_SECONDS:-300};
|
||||
STUCK_THRESHOLD_SECONDS=${LIVENESS_THRESHOLD_SECONDS:-900};
|
||||
STUCK_THRESHOLD_SECONDS=${STUCK_THRESHOLD_SECONDS:-900};
|
||||
if [ ! -e /var/log/fluentd-buffers ];
|
||||
then
|
||||
exit 1;
|
||||
fi;
|
||||
touch -d "${STUCK_THRESHOLD_SECONDS} seconds ago" /tmp/marker-stuck;
|
||||
if [[ -z "$(find /var/log/fluentd-buffers -type f -newer /tmp/marker-stuck -print -quit)" ]];
|
||||
if [ -z "$(find /var/log/fluentd-buffers -type d -newer /tmp/marker-stuck -print -quit)" ];
|
||||
then
|
||||
rm -rf /var/log/fluentd-buffers;
|
||||
exit 1;
|
||||
fi;
|
||||
touch -d "${LIVENESS_THRESHOLD_SECONDS} seconds ago" /tmp/marker-liveness;
|
||||
if [[ -z "$(find /var/log/fluentd-buffers -type f -newer /tmp/marker-liveness -print -quit)" ]];
|
||||
if [ -z "$(find /var/log/fluentd-buffers -type d -newer /tmp/marker-liveness -print -quit)" ];
|
||||
then
|
||||
exit 1;
|
||||
fi;
|
||||
|
|
|
@ -267,7 +267,7 @@ function prepare-node-upgrade() {
|
|||
|
||||
# TODO(zmerlynn): Get configure-vm script from ${version}. (Must plumb this
|
||||
# through all create-linux-node-instance-template implementations).
|
||||
local template_name=$(get-template-name-from-version ${SANITIZED_VERSION})
|
||||
local template_name=$(get-template-name-from-version ${SANITIZED_VERSION} ${NODE_INSTANCE_PREFIX})
|
||||
create-linux-node-instance-template "${template_name}"
|
||||
# The following is echo'd so that callers can get the template name.
|
||||
echo "Instance template name: ${template_name}"
|
||||
|
@ -373,7 +373,7 @@ function do-node-upgrade() {
|
|||
# Do the actual upgrade.
|
||||
# NOTE(zmerlynn): If you are changing this gcloud command, update
|
||||
# test/e2e/cluster_upgrade.go to match this EXACTLY.
|
||||
local template_name=$(get-template-name-from-version ${SANITIZED_VERSION})
|
||||
local template_name=$(get-template-name-from-version ${SANITIZED_VERSION} ${NODE_INSTANCE_PREFIX})
|
||||
local old_templates=()
|
||||
local updates=()
|
||||
for group in ${INSTANCE_GROUPS[@]}; do
|
||||
|
|
|
@ -112,7 +112,10 @@ if [[ "${ENABLE_CLUSTER_AUTOSCALER}" == "true" ]]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# These prefixes must not be prefixes of each other, so that they can be used to
|
||||
# detect mutually exclusive sets of nodes.
|
||||
NODE_INSTANCE_PREFIX=${NODE_INSTANCE_PREFIX:-"${INSTANCE_PREFIX}-minion"}
|
||||
WINDOWS_NODE_INSTANCE_PREFIX=${WINDOWS_NODE_INSTANCE_PREFIX:-"${INSTANCE_PREFIX}-windows-node"}
|
||||
|
||||
NODE_TAGS="${NODE_TAG}"
|
||||
|
||||
|
@ -373,9 +376,12 @@ function upload-tars() {
|
|||
#
|
||||
# Assumed vars:
|
||||
# NODE_INSTANCE_PREFIX
|
||||
# WINDOWS_NODE_INSTANCE_PREFIX
|
||||
# Vars set:
|
||||
# NODE_NAMES
|
||||
# INSTANCE_GROUPS
|
||||
# WINDOWS_NODE_NAMES
|
||||
# WINDOWS_INSTANCE_GROUPS
|
||||
function detect-node-names() {
|
||||
detect-project
|
||||
INSTANCE_GROUPS=()
|
||||
|
@ -383,6 +389,12 @@ function detect-node-names() {
|
|||
--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
|
||||
|
@ -395,6 +407,14 @@ function detect-node-names() {
|
|||
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
|
||||
|
@ -1403,6 +1423,7 @@ function build-windows-kube-env {
|
|||
build-linux-kube-env false $file
|
||||
|
||||
cat >>$file <<EOF
|
||||
WINDOWS_NODE_INSTANCE_PREFIX: $(yaml-quote ${WINDOWS_NODE_INSTANCE_PREFIX})
|
||||
NODE_BINARY_TAR_URL: $(yaml-quote ${NODE_BINARY_TAR_URL})
|
||||
NODE_BINARY_TAR_HASH: $(yaml-quote ${NODE_BINARY_TAR_HASH})
|
||||
K8S_DIR: $(yaml-quote ${WINDOWS_K8S_DIR})
|
||||
|
@ -1852,9 +1873,13 @@ function make-gcloud-network-argument() {
|
|||
}
|
||||
|
||||
# $1: version (required)
|
||||
# $2: Prefix for the template name, i.e. NODE_INSTANCE_PREFIX or
|
||||
# WINDOWS_NODE_INSTANCE_PREFIX.
|
||||
function get-template-name-from-version() {
|
||||
local -r version=${1}
|
||||
local -r template_prefix=${2}
|
||||
# trim template name to pass gce name validation
|
||||
echo "${NODE_INSTANCE_PREFIX}-template-${1}" | cut -c 1-63 | sed 's/[\.\+]/-/g;s/-*$//g'
|
||||
echo "${template_prefix}-template-${version}" | cut -c 1-63 | sed 's/[\.\+]/-/g;s/-*$//g'
|
||||
}
|
||||
|
||||
# validates the NODE_LOCAL_SSDS_EXT variable
|
||||
|
@ -2627,9 +2652,8 @@ function create-nodes-template() {
|
|||
|
||||
# NOTE: these template names and their format must match
|
||||
# create-[linux,windows]-nodes() as well as get-template()!
|
||||
# TODO(pjh): find a better way to manage these (get-template() is annoying).
|
||||
local linux_template_name="${NODE_INSTANCE_PREFIX}-template"
|
||||
local windows_template_name="${NODE_INSTANCE_PREFIX}-template-windows"
|
||||
local windows_template_name="${WINDOWS_NODE_INSTANCE_PREFIX}-template"
|
||||
create-linux-node-instance-template $linux_template_name
|
||||
create-windows-node-instance-template $windows_template_name "${scope_flags[*]}"
|
||||
}
|
||||
|
@ -2700,22 +2724,22 @@ function create-linux-nodes() {
|
|||
|
||||
# Assumes:
|
||||
# - NUM_WINDOWS_MIGS
|
||||
# - NODE_INSTANCE_PREFIX
|
||||
# - WINDOWS_NODE_INSTANCE_PREFIX
|
||||
# - NUM_WINDOWS_NODES
|
||||
# - PROJECT
|
||||
# - ZONE
|
||||
function create-windows-nodes() {
|
||||
local template_name="${NODE_INSTANCE_PREFIX}-template-windows"
|
||||
local template_name="${WINDOWS_NODE_INSTANCE_PREFIX}-template"
|
||||
|
||||
local -r nodes="${NUM_WINDOWS_NODES}"
|
||||
local instances_left=${nodes}
|
||||
|
||||
for ((i=1; i<=${NUM_WINDOWS_MIGS}; i++)); do
|
||||
local group_name="${NODE_INSTANCE_PREFIX}-windows-group-$i"
|
||||
local group_name="${WINDOWS_NODE_INSTANCE_PREFIX}-group-$i"
|
||||
if [[ $i == ${NUM_WINDOWS_MIGS} ]]; then
|
||||
# TODO: We don't add a suffix for the last group to keep backward compatibility when there's only one MIG.
|
||||
# We should change it at some point, but note #18545 when changing this.
|
||||
group_name="${NODE_INSTANCE_PREFIX}-windows-group"
|
||||
group_name="${WINDOWS_NODE_INSTANCE_PREFIX}-group"
|
||||
fi
|
||||
# Spread the remaining number of nodes evenly
|
||||
this_mig_size=$((${instances_left} / (${NUM_WINDOWS_MIGS}-${i}+1)))
|
||||
|
@ -2946,6 +2970,7 @@ function remove-replica-from-etcd() {
|
|||
# Assumed vars:
|
||||
# MASTER_NAME
|
||||
# NODE_INSTANCE_PREFIX
|
||||
# WINDOWS_NODE_INSTANCE_PREFIX
|
||||
# ZONE
|
||||
# This function tears down cluster resources 10 at a time to avoid issuing too many
|
||||
# API calls and exceeding API quota. It is important to bring down the instances before bringing
|
||||
|
@ -2954,7 +2979,7 @@ function kube-down() {
|
|||
local -r batch=200
|
||||
|
||||
detect-project
|
||||
detect-node-names # For INSTANCE_GROUPS
|
||||
detect-node-names # For INSTANCE_GROUPS and WINDOWS_INSTANCE_GROUPS
|
||||
|
||||
echo "Bringing down cluster"
|
||||
set +e # Do not stop on error
|
||||
|
@ -2965,7 +2990,8 @@ function kube-down() {
|
|||
# change during a cluster upgrade.)
|
||||
local templates=$(get-template "${PROJECT}")
|
||||
|
||||
for group in ${INSTANCE_GROUPS[@]:-}; do
|
||||
local all_instance_groups=(${INSTANCE_GROUPS[@]} ${WINDOWS_INSTANCE_GROUPS[@]})
|
||||
for group in ${all_instance_groups[@]:-}; do
|
||||
if gcloud compute instance-groups managed describe "${group}" --project "${PROJECT}" --zone "${ZONE}" &>/dev/null; then
|
||||
gcloud compute instance-groups managed delete \
|
||||
--project "${PROJECT}" \
|
||||
|
@ -3087,7 +3113,7 @@ function kube-down() {
|
|||
local -a minions
|
||||
minions=( $(gcloud compute instances list \
|
||||
--project "${PROJECT}" \
|
||||
--filter="name ~ '${NODE_INSTANCE_PREFIX}-.+' AND zone:(${ZONE})" \
|
||||
--filter="(name ~ '${NODE_INSTANCE_PREFIX}-.+' OR name ~ '${WINDOWS_NODE_INSTANCE_PREFIX}-.+') AND zone:(${ZONE})" \
|
||||
--format='value(name)') )
|
||||
# If any minions are running, delete them in batches.
|
||||
while (( "${#minions[@]}" > 0 )); do
|
||||
|
@ -3242,15 +3268,19 @@ function set-replica-name() {
|
|||
REPLICA_NAME="${MASTER_NAME}-${suffix}"
|
||||
}
|
||||
|
||||
# Gets the instance template for given NODE_INSTANCE_PREFIX. It echos the template name so that the function
|
||||
# output can be used.
|
||||
# Gets the instance templates in use by the cluster. It echos the template names
|
||||
# so that the function output can be used.
|
||||
# Assumed vars:
|
||||
# NODE_INSTANCE_PREFIX
|
||||
# WINDOWS_NODE_INSTANCE_PREFIX
|
||||
#
|
||||
# $1: project
|
||||
function get-template() {
|
||||
local linux_filter="${NODE_INSTANCE_PREFIX}-template(-(${KUBE_RELEASE_VERSION_DASHED_REGEX}|${KUBE_CI_VERSION_DASHED_REGEX}))?"
|
||||
local windows_filter="${WINDOWS_NODE_INSTANCE_PREFIX}-template(-(${KUBE_RELEASE_VERSION_DASHED_REGEX}|${KUBE_CI_VERSION_DASHED_REGEX}))?"
|
||||
|
||||
gcloud compute instance-templates list \
|
||||
--filter="name ~ '${NODE_INSTANCE_PREFIX}-template(-(${KUBE_RELEASE_VERSION_DASHED_REGEX}|${KUBE_CI_VERSION_DASHED_REGEX}))?'" \
|
||||
--filter="name ~ '${linux_filter}' OR name ~ '${windows_filter}'" \
|
||||
--project="${1}" --format='value(name)'
|
||||
}
|
||||
|
||||
|
@ -3259,6 +3289,7 @@ function get-template() {
|
|||
# Assumed vars:
|
||||
# MASTER_NAME
|
||||
# NODE_INSTANCE_PREFIX
|
||||
# WINDOWS_NODE_INSTANCE_PREFIX
|
||||
# ZONE
|
||||
# REGION
|
||||
# Vars set:
|
||||
|
@ -3274,11 +3305,19 @@ function check-resources() {
|
|||
KUBE_RESOURCE_FOUND="Managed instance groups ${INSTANCE_GROUPS[@]}"
|
||||
return 1
|
||||
fi
|
||||
if [[ -n "${WINDOWS_INSTANCE_GROUPS[@]:-}" ]]; then
|
||||
KUBE_RESOURCE_FOUND="Managed instance groups ${WINDOWS_INSTANCE_GROUPS[@]}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if gcloud compute instance-templates describe --project "${PROJECT}" "${NODE_INSTANCE_PREFIX}-template" &>/dev/null; then
|
||||
KUBE_RESOURCE_FOUND="Instance template ${NODE_INSTANCE_PREFIX}-template"
|
||||
return 1
|
||||
fi
|
||||
if gcloud compute instance-templates describe --project "${PROJECT}" "${WINDOWS_NODE_INSTANCE_PREFIX}-template" &>/dev/null; then
|
||||
KUBE_RESOURCE_FOUND="Instance template ${WINDOWS_NODE_INSTANCE_PREFIX}-template"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if gcloud compute instances describe --project "${PROJECT}" "${MASTER_NAME}" --zone "${ZONE}" &>/dev/null; then
|
||||
KUBE_RESOURCE_FOUND="Kubernetes master ${MASTER_NAME}"
|
||||
|
@ -3294,10 +3333,10 @@ function check-resources() {
|
|||
local -a minions
|
||||
minions=( $(gcloud compute instances list \
|
||||
--project "${PROJECT}" \
|
||||
--filter="name ~ '${NODE_INSTANCE_PREFIX}-.+' AND zone:(${ZONE})" \
|
||||
--filter="(name ~ '${NODE_INSTANCE_PREFIX}-.+' OR name ~ '${WINDOWS_NODE_INSTANCE_PREFIX}-.+') AND zone:(${ZONE})" \
|
||||
--format='value(name)') )
|
||||
if (( "${#minions[@]}" > 0 )); then
|
||||
KUBE_RESOURCE_FOUND="${#minions[@]} matching matching ${NODE_INSTANCE_PREFIX}-.+"
|
||||
KUBE_RESOURCE_FOUND="${#minions[@]} matching ${NODE_INSTANCE_PREFIX}-.+ or ${WINDOWS_NODE_INSTANCE_PREFIX}-.+"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
|
|
@ -250,11 +250,12 @@ function Disable-WindowsDefender {
|
|||
|
||||
# Creates directories where other functions in this module will read and write
|
||||
# data.
|
||||
# Note: C:\tmp is required for running certain kubernetes tests.
|
||||
function Create-Directories {
|
||||
Log-Output "Creating ${env:K8S_DIR} and its subdirectories."
|
||||
ForEach ($dir in ("${env:K8S_DIR}", "${env:NODE_DIR}", "${env:LOGS_DIR}",
|
||||
"${env:CNI_DIR}", "${env:CNI_CONFIG_DIR}", "${env:MANIFESTS_DIR}",
|
||||
"${env:PKI_DIR}")) {
|
||||
"${env:PKI_DIR}"), "C:\tmp") {
|
||||
mkdir -Force $dir
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,10 @@ 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 dump_systemd_journal="${LOG_DUMP_SYSTEMD_JOURNAL:-false}"
|
||||
# Log files found in WINDOWS_LOGS_DIR on Windows nodes:
|
||||
readonly windows_node_logfiles="kubelet.log kube-proxy.log docker.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.
|
||||
|
@ -195,6 +199,66 @@ function save-logs() {
|
|||
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 \$log=\$(Get-EventLog -LogName Application -Source Docker); Set-Content '${WINDOWS_LOGS_DIR}\\docker.log' \$log.Message"
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
export-windows-docker-event-log "${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
|
||||
|
||||
# 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() {
|
||||
|
@ -247,8 +311,13 @@ function dump_masters() {
|
|||
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=( "$@" )
|
||||
|
@ -264,9 +333,12 @@ function dump_nodes() {
|
|||
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 ]]; then
|
||||
if [[ "${#node_names[@]}" == 0 && "${#windows_node_names[@]}" == 0 ]]; then
|
||||
echo "No nodes found!"
|
||||
return
|
||||
fi
|
||||
|
@ -276,24 +348,31 @@ function dump_nodes() {
|
|||
node_logfiles_all="${node_logfiles_all} ${hollow_node_logfiles}"
|
||||
fi
|
||||
|
||||
nodes_selected_for_logs=()
|
||||
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
|
||||
nodes_selected_for_logs+=("${node_names[$index]}")
|
||||
linux_nodes_selected_for_logs+=("${node_names[$index]}")
|
||||
done
|
||||
else
|
||||
nodes_selected_for_logs=( "${node_names[@]}" )
|
||||
linux_nodes_selected_for_logs=( "${node_names[@]}" )
|
||||
fi
|
||||
all_selected_nodes=( "${linux_nodes_selected_for_logs[@]}" )
|
||||
all_selected_nodes+=( "${windows_node_names[@]}" )
|
||||
|
||||
proc=${max_dump_processes}
|
||||
for node_name in "${nodes_selected_for_logs[@]}"; do
|
||||
for i in "${!all_selected_nodes[@]}"; do
|
||||
node_name="${all_selected_nodes[$i]}"
|
||||
node_dir="${report_dir}/${node_name}"
|
||||
mkdir -p "${node_dir}"
|
||||
# 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}" &
|
||||
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
|
||||
|
@ -311,6 +390,9 @@ function dump_nodes() {
|
|||
}
|
||||
|
||||
# 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:
|
||||
|
@ -328,6 +410,8 @@ function find_non_logexported_nodes() {
|
|||
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"
|
||||
|
@ -446,10 +530,16 @@ function detect_node_failures() {
|
|||
fi
|
||||
|
||||
detect-node-names
|
||||
if [ -z "${INSTANCE_GROUPS:-}" ]; then
|
||||
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 "${INSTANCE_GROUPS[@]}"; do
|
||||
for group in "${all_instance_groups[@]}"; do
|
||||
local creation_timestamp=$(gcloud compute instance-groups managed describe \
|
||||
"${group}" \
|
||||
--project "${PROJECT}" \
|
||||
|
|
|
@ -56,7 +56,7 @@ if [[ "${KUBERNETES_PROVIDER:-}" == "gce" ]]; then
|
|||
# In multizone mode we need to add instances for all nodes in the region.
|
||||
if [[ "${MULTIZONE:-}" == "true" ]]; then
|
||||
EXPECTED_NUM_NODES=$(gcloud -q compute instances list --project="${PROJECT}" --format=[no-heading] \
|
||||
--filter="name ~ '${NODE_INSTANCE_PREFIX}.*' AND zone:($(gcloud -q compute zones list --project="${PROJECT}" --filter=region=${REGION} --format=csv[no-heading]\(name\) | tr "\n" "," | sed "s/,$//"))" | wc -l)
|
||||
--filter="(name ~ '${NODE_INSTANCE_PREFIX}.*' OR name ~ '${WINDOWS_NODE_INSTANCE_PREFIX}.*') AND zone:($(gcloud -q compute zones list --project="${PROJECT}" --filter=region=${REGION} --format=csv[no-heading]\(name\) | tr "\n" "," | sed "s/,$//"))" | wc -l)
|
||||
echo "Computing number of nodes, NODE_INSTANCE_PREFIX=${NODE_INSTANCE_PREFIX}, REGION=${REGION}, EXPECTED_NUM_NODES=${EXPECTED_NUM_NODES}"
|
||||
fi
|
||||
else
|
||||
|
|
|
@ -41,6 +41,7 @@ filegroup(
|
|||
"//cmd/kubeadm/app/phases/bootstraptoken/node:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/certs:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/controlplane:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/copycerts:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/etcd:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/kubeconfig:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/kubelet:all-srcs",
|
||||
|
@ -48,7 +49,6 @@ filegroup(
|
|||
"//cmd/kubeadm/app/phases/patchnode:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/selfhosting:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/upgrade:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/uploadcerts:all-srcs",
|
||||
"//cmd/kubeadm/app/phases/uploadconfig:all-srcs",
|
||||
"//cmd/kubeadm/app/preflight:all-srcs",
|
||||
"//cmd/kubeadm/app/util:all-srcs",
|
||||
|
|
|
@ -147,7 +147,7 @@ type APIEndpoint struct {
|
|||
// NodeRegistrationOptions holds fields that relate to registering a new control-plane or node to the cluster, either via "kubeadm init" or "kubeadm join"
|
||||
type NodeRegistrationOptions struct {
|
||||
|
||||
// Name is the `.Metadata.Name` field of the Node API object that will be created in this `kubeadm init` or `kubeadm joiń` operation.
|
||||
// Name is the `.Metadata.Name` field of the Node API object that will be created in this `kubeadm init` or `kubeadm join` operation.
|
||||
// This field is also used in the CommonName field of the kubelet's client certificate to the API server.
|
||||
// Defaults to the hostname of the node if not provided.
|
||||
Name string `json:"name,omitempty"`
|
||||
|
|
|
@ -428,6 +428,7 @@ func isAllowedFlag(flagName string) bool {
|
|||
kubeadmcmdoptions.NodeCRISocket,
|
||||
kubeadmcmdoptions.KubeconfigDir,
|
||||
kubeadmcmdoptions.UploadCerts,
|
||||
kubeadmcmdoptions.CertificateKey,
|
||||
"print-join-command", "rootfs", "v")
|
||||
if knownFlags.Has(flagName) {
|
||||
return true
|
||||
|
|
|
@ -84,6 +84,7 @@ go_test(
|
|||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1beta1:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
|
||||
"//cmd/kubeadm/app/cmd/options:go_default_library",
|
||||
|
|
|
@ -127,6 +127,7 @@ type joinOptions struct {
|
|||
controlPlane bool
|
||||
ignorePreflightErrors []string
|
||||
externalcfg *kubeadmapiv1beta1.JoinConfiguration
|
||||
certificateKey string
|
||||
}
|
||||
|
||||
// compile-time assert that the local data object satisfies the phases data interface.
|
||||
|
@ -142,6 +143,7 @@ type joinData struct {
|
|||
clientSets map[string]*clientset.Clientset
|
||||
ignorePreflightErrors sets.String
|
||||
outputWriter io.Writer
|
||||
certificateKey string
|
||||
}
|
||||
|
||||
// NewCmdJoin returns "kubeadm join" command.
|
||||
|
@ -192,7 +194,7 @@ func NewCmdJoin(out io.Writer, joinOptions *joinOptions) *cobra.Command {
|
|||
}
|
||||
|
||||
addJoinConfigFlags(cmd.Flags(), joinOptions.externalcfg)
|
||||
addJoinOtherFlags(cmd.Flags(), &joinOptions.cfgPath, &joinOptions.ignorePreflightErrors, &joinOptions.controlPlane, &joinOptions.token)
|
||||
addJoinOtherFlags(cmd.Flags(), &joinOptions.cfgPath, &joinOptions.ignorePreflightErrors, &joinOptions.controlPlane, &joinOptions.token, &joinOptions.certificateKey)
|
||||
|
||||
joinRunner.AppendPhase(phases.NewPreflightPhase())
|
||||
joinRunner.AppendPhase(phases.NewControlPlanePreparePhase())
|
||||
|
@ -254,7 +256,14 @@ func addJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiv1beta1.JoinConfig
|
|||
}
|
||||
|
||||
// addJoinOtherFlags adds join flags that are not bound to a configuration file to the given flagset
|
||||
func addJoinOtherFlags(flagSet *flag.FlagSet, cfgPath *string, ignorePreflightErrors *[]string, controlPlane *bool, token *string) {
|
||||
func addJoinOtherFlags(
|
||||
flagSet *flag.FlagSet,
|
||||
cfgPath *string,
|
||||
ignorePreflightErrors *[]string,
|
||||
controlPlane *bool,
|
||||
token *string,
|
||||
certificateKey *string,
|
||||
) {
|
||||
flagSet.StringVar(
|
||||
cfgPath, options.CfgPath, *cfgPath,
|
||||
"Path to kubeadm config file.",
|
||||
|
@ -271,6 +280,10 @@ func addJoinOtherFlags(flagSet *flag.FlagSet, cfgPath *string, ignorePreflightEr
|
|||
controlPlane, options.ControlPlane, *controlPlane,
|
||||
"Create a new control plane instance on this node",
|
||||
)
|
||||
flagSet.StringVar(
|
||||
certificateKey, options.CertificateKey, "",
|
||||
"Use this key to decrypt the certificate secrets uploaded by init.",
|
||||
)
|
||||
}
|
||||
|
||||
// newJoinOptions returns a struct ready for being used for creating cmd join flags.
|
||||
|
@ -375,9 +388,15 @@ func newJoinData(cmd *cobra.Command, args []string, options *joinOptions, out io
|
|||
clientSets: map[string]*clientset.Clientset{},
|
||||
ignorePreflightErrors: ignorePreflightErrorsSet,
|
||||
outputWriter: out,
|
||||
certificateKey: options.certificateKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CertificateKey returns the key used to encrypt the certs.
|
||||
func (j *joinData) CertificateKey() string {
|
||||
return j.certificateKey
|
||||
}
|
||||
|
||||
// Cfg returns the JoinConfiguration.
|
||||
func (j *joinData) Cfg() *kubeadmapi.JoinConfiguration {
|
||||
return j.cfg
|
||||
|
|
|
@ -121,4 +121,7 @@ const (
|
|||
|
||||
// UploadCerts flag instruct kubeadm to upload certificates
|
||||
UploadCerts = "experimental-upload-certs"
|
||||
|
||||
// CertificateKey flag sets the key used to encrypt and decrypt certificate secrets
|
||||
CertificateKey = "certificate-key"
|
||||
)
|
||||
|
|
|
@ -33,12 +33,12 @@ go_library(
|
|||
"//cmd/kubeadm/app/phases/bootstraptoken/node:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/controlplane:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/copycerts:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/etcd:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/kubelet:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/markcontrolplane:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/patchnode:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/uploadcerts:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/uploadconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/preflight:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadcerts"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/copycerts"
|
||||
)
|
||||
|
||||
// NewUploadCertsPhase returns the uploadCerts phase
|
||||
|
@ -59,14 +59,14 @@ func runUploadCerts(c workflow.RunData) error {
|
|||
}
|
||||
|
||||
if len(data.CertificateKey()) == 0 {
|
||||
certificateKey, err := uploadcerts.CreateCertificateKey()
|
||||
certificateKey, err := copycerts.CreateCertificateKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data.SetCertificateKey(certificateKey)
|
||||
}
|
||||
|
||||
if err := uploadcerts.UploadCerts(client, data.Cfg(), data.CertificateKey()); err != nil {
|
||||
if err := copycerts.UploadCerts(client, data.Cfg(), data.CertificateKey()); err != nil {
|
||||
return errors.Wrap(err, "error uploading certs")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -20,6 +20,7 @@ go_library(
|
|||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/controlplane:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/copycerts:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/etcd:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/kubelet:go_default_library",
|
||||
|
|
|
@ -21,13 +21,17 @@ import (
|
|||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/copycerts"
|
||||
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
|
||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||
)
|
||||
|
||||
// NewControlPlanePreparePhase creates a kubeadm workflow phase that implements the preparation of the node to serve a control plane
|
||||
|
@ -35,7 +39,6 @@ func NewControlPlanePreparePhase() workflow.Phase {
|
|||
return workflow.Phase{
|
||||
Name: "control-plane-prepare",
|
||||
Short: "Prepares the machine for serving a control plane.",
|
||||
Long: cmdutil.MacroCommandLongDescription,
|
||||
Phases: []workflow.Phase{
|
||||
{
|
||||
Name: "all",
|
||||
|
@ -43,6 +46,7 @@ func NewControlPlanePreparePhase() workflow.Phase {
|
|||
InheritFlags: getControlPlanePreparePhaseFlags(),
|
||||
RunAllSiblings: true,
|
||||
},
|
||||
newControlPlanePrepareDownloadCertsSubphase(),
|
||||
newControlPlanePrepareCertsSubphase(),
|
||||
newControlPlanePrepareKubeconfigSubphase(),
|
||||
newControlPlanePrepareManifestsSubphases(),
|
||||
|
@ -60,6 +64,20 @@ func getControlPlanePreparePhaseFlags() []string {
|
|||
options.TokenDiscovery,
|
||||
options.TokenDiscoveryCAHash,
|
||||
options.TokenDiscoverySkipCAHash,
|
||||
options.CertificateKey,
|
||||
}
|
||||
}
|
||||
|
||||
func newControlPlanePrepareDownloadCertsSubphase() workflow.Phase {
|
||||
return workflow.Phase{
|
||||
Name: "download-certs",
|
||||
Short: fmt.Sprintf("Download certificates from %s", kubeadmconstants.KubeadmCertsSecret),
|
||||
Long: cmdutil.MacroCommandLongDescription,
|
||||
Run: runControlPlanePrepareDownloadCertsPhaseLocal,
|
||||
InheritFlags: []string{
|
||||
options.CfgPath,
|
||||
options.CertificateKey,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,6 +128,33 @@ func runControlPlanePrepareManifestsSubphase(c workflow.RunData) error {
|
|||
return controlplane.CreateInitStaticPodManifestFiles(kubeadmconstants.GetStaticPodDirectory(), cfg)
|
||||
}
|
||||
|
||||
func runControlPlanePrepareDownloadCertsPhaseLocal(c workflow.RunData) error {
|
||||
data, ok := c.(JoinData)
|
||||
if !ok {
|
||||
return errors.New("download-certs phase invoked with an invalid data struct")
|
||||
}
|
||||
|
||||
if data.Cfg().ControlPlane == nil || len(data.CertificateKey()) == 0 {
|
||||
klog.V(1).Infoln("[download-certs] Skipping certs download")
|
||||
return nil
|
||||
}
|
||||
|
||||
cfg, err := data.InitCfg()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := bootstrapClient(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := copycerts.DownloadCerts(client, cfg, data.CertificateKey()); err != nil {
|
||||
return errors.Wrap(err, "error downloading certs")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runControlPlanePrepareCertsPhaseLocal(c workflow.RunData) error {
|
||||
data, ok := c.(JoinData)
|
||||
if !ok {
|
||||
|
@ -157,3 +202,15 @@ func runControlPlanePrepareKubeconfigPhaseLocal(c workflow.RunData) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func bootstrapClient(data JoinData) (clientset.Interface, error) {
|
||||
tlsBootstrapCfg, err := data.TLSBootstrapCfg()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to access the cluster")
|
||||
}
|
||||
client, err := kubeconfigutil.ToClientSet(tlsBootstrapCfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to access the cluster")
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
// JoinData is the interface to use for join phases.
|
||||
// The "joinData" type from "cmd/join.go" must satisfy this interface.
|
||||
type JoinData interface {
|
||||
CertificateKey() string
|
||||
Cfg() *kubeadmapi.JoinConfiguration
|
||||
KubeConfigPath() string
|
||||
TLSBootstrapCfg() (*clientcmdapi.Config, error)
|
||||
|
|
|
@ -31,6 +31,7 @@ type testJoinData struct{}
|
|||
// testJoinData must satisfy JoinData.
|
||||
var _ JoinData = &testJoinData{}
|
||||
|
||||
func (j *testJoinData) CertificateKey() string { return "" }
|
||||
func (j *testJoinData) Cfg() *kubeadmapi.JoinConfiguration { return nil }
|
||||
func (j *testJoinData) KubeConfigPath() string { return "" }
|
||||
func (j *testJoinData) TLSBootstrapCfg() (*clientcmdapi.Config, error) { return nil, nil }
|
||||
|
|
|
@ -39,7 +39,7 @@ var (
|
|||
kubeadm join phase preflight --config kubeadm-config.yml
|
||||
`)
|
||||
|
||||
notReadyToJoinControPlaneTemp = template.Must(template.New("join").Parse(dedent.Dedent(`
|
||||
notReadyToJoinControlPlaneTemp = template.Must(template.New("join").Parse(dedent.Dedent(`
|
||||
One or more conditions for hosting a new control plane instance is not satisfied.
|
||||
|
||||
{{.Error}}
|
||||
|
@ -105,14 +105,15 @@ func runPreflight(c workflow.RunData) error {
|
|||
if j.Cfg().ControlPlane != nil {
|
||||
// Checks if the cluster configuration supports
|
||||
// joining a new control plane instance and if all the necessary certificates are provided
|
||||
if err := checkIfReadyForAdditionalControlPlane(&initCfg.ClusterConfiguration); err != nil {
|
||||
hasCertificateKey := len(j.CertificateKey()) > 0
|
||||
if err := checkIfReadyForAdditionalControlPlane(&initCfg.ClusterConfiguration, hasCertificateKey); err != nil {
|
||||
// outputs the not ready for hosting a new control plane instance message
|
||||
ctx := map[string]string{
|
||||
"Error": err.Error(),
|
||||
}
|
||||
|
||||
var msg bytes.Buffer
|
||||
notReadyToJoinControPlaneTemp.Execute(&msg, ctx)
|
||||
notReadyToJoinControlPlaneTemp.Execute(&msg, ctx)
|
||||
return errors.New(msg.String())
|
||||
}
|
||||
|
||||
|
@ -134,15 +135,17 @@ func runPreflight(c workflow.RunData) error {
|
|||
|
||||
// checkIfReadyForAdditionalControlPlane ensures that the cluster is in a state that supports
|
||||
// joining an additional control plane instance and if the node is ready to preflight
|
||||
func checkIfReadyForAdditionalControlPlane(initConfiguration *kubeadmapi.ClusterConfiguration) error {
|
||||
func checkIfReadyForAdditionalControlPlane(initConfiguration *kubeadmapi.ClusterConfiguration, hasCertificateKey bool) error {
|
||||
// blocks if the cluster was created without a stable control plane endpoint
|
||||
if initConfiguration.ControlPlaneEndpoint == "" {
|
||||
return errors.New("unable to add a new control plane instance a cluster that doesn't have a stable controlPlaneEndpoint address")
|
||||
}
|
||||
|
||||
// checks if the certificates that must be equal across contolplane instances are provided
|
||||
if ret, err := certs.SharedCertificateExists(initConfiguration); !ret {
|
||||
return err
|
||||
if !hasCertificateKey {
|
||||
// checks if the certificates that must be equal across controlplane instances are provided
|
||||
if ret, err := certs.SharedCertificateExists(initConfiguration); !ret {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -31,6 +31,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||
|
@ -68,15 +69,20 @@ func NewCmdReset(in io.Reader, out io.Writer) *cobra.Command {
|
|||
kubeadmutil.CheckErr(err)
|
||||
}
|
||||
|
||||
cfg, err := configutil.FetchInitConfigurationFromCluster(client, os.Stdout, "reset", false)
|
||||
if err != nil {
|
||||
klog.Warningf("[reset] Unable to fetch the kubeadm-config ConfigMap from cluster: %v", err)
|
||||
}
|
||||
|
||||
if criSocketPath == "" {
|
||||
criSocketPath, err = resetDetectCRISocket(client)
|
||||
criSocketPath, err = resetDetectCRISocket(cfg)
|
||||
kubeadmutil.CheckErr(err)
|
||||
klog.V(1).Infof("[reset] detected and using CRI socket: %s", criSocketPath)
|
||||
}
|
||||
|
||||
r, err := NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
|
||||
kubeadmutil.CheckErr(err)
|
||||
kubeadmutil.CheckErr(r.Run(out, client))
|
||||
kubeadmutil.CheckErr(r.Run(out, client, cfg))
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -131,17 +137,19 @@ func NewReset(in io.Reader, ignorePreflightErrors sets.String, forceReset bool,
|
|||
}
|
||||
|
||||
// Run reverts any changes made to this host by "kubeadm init" or "kubeadm join".
|
||||
func (r *Reset) Run(out io.Writer, client clientset.Interface) error {
|
||||
func (r *Reset) Run(out io.Writer, client clientset.Interface, cfg *kubeadmapi.InitConfiguration) error {
|
||||
var dirsToClean []string
|
||||
// Only clear etcd data when using local etcd.
|
||||
etcdManifestPath := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ManifestsSubDirName, "etcd.yaml")
|
||||
|
||||
klog.V(1).Infof("[reset] checking for etcd config")
|
||||
etcdDataDir, err := getEtcdDataDir(etcdManifestPath, client)
|
||||
etcdDataDir, err := getEtcdDataDir(etcdManifestPath, cfg)
|
||||
if err == nil {
|
||||
dirsToClean = append(dirsToClean, etcdDataDir)
|
||||
if err := removeEtcdMember(client); err != nil {
|
||||
klog.Warningf("[reset] failed to remove etcd member: %v\n.Please manually remove this etcd member using etcdctl", err)
|
||||
if cfg != nil {
|
||||
if err := etcdphase.RemoveStackedEtcdMemberFromCluster(client, cfg); err != nil {
|
||||
klog.Warningf("[reset] failed to remove etcd member: %v\n.Please manually remove this etcd member using etcdctl", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Println("[reset] no etcd config found. Assuming external etcd")
|
||||
|
@ -209,25 +217,14 @@ func (r *Reset) Run(out io.Writer, client clientset.Interface) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func removeEtcdMember(client clientset.Interface) error {
|
||||
cfg, err := configutil.FetchInitConfigurationFromCluster(client, os.Stdout, "reset", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return etcdphase.RemoveStackedEtcdMemberFromCluster(client, cfg)
|
||||
}
|
||||
|
||||
func getEtcdDataDir(manifestPath string, client clientset.Interface) (string, error) {
|
||||
func getEtcdDataDir(manifestPath string, cfg *kubeadmapi.InitConfiguration) (string, error) {
|
||||
const etcdVolumeName = "etcd-data"
|
||||
var dataDir string
|
||||
|
||||
if client != nil {
|
||||
cfg, err := configutil.FetchInitConfigurationFromCluster(client, os.Stdout, "reset", false)
|
||||
if err == nil && cfg.Etcd.Local != nil {
|
||||
return cfg.Etcd.Local.DataDir, nil
|
||||
}
|
||||
klog.Warningf("[reset] Unable to fetch the kubeadm-config ConfigMap, using etcd pod spec as fallback: %v", err)
|
||||
if cfg != nil && cfg.Etcd.Local != nil {
|
||||
return cfg.Etcd.Local.DataDir, nil
|
||||
}
|
||||
klog.Warningln("[reset] No kubeadm config, using etcd pod spec to get data directory")
|
||||
|
||||
etcdPod, err := utilstaticpod.ReadStaticPodFromDisk(manifestPath)
|
||||
if err != nil {
|
||||
|
@ -311,13 +308,10 @@ func resetConfigDir(configPathDir, pkiPathDir string) {
|
|||
}
|
||||
}
|
||||
|
||||
func resetDetectCRISocket(client clientset.Interface) (string, error) {
|
||||
if client != nil {
|
||||
// first try to connect to the cluster for the CRI socket
|
||||
cfg, err := configutil.FetchInitConfigurationFromCluster(client, os.Stdout, "reset", false)
|
||||
if err == nil {
|
||||
return cfg.NodeRegistration.CRISocket, nil
|
||||
}
|
||||
func resetDetectCRISocket(cfg *kubeadmapi.InitConfiguration) (string, error) {
|
||||
if cfg != nil {
|
||||
// first try to get the CRI socket from the cluster configuration
|
||||
return cfg.NodeRegistration.CRISocket, nil
|
||||
}
|
||||
|
||||
// if this fails, try to detect it
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
|
||||
"github.com/lithammer/dedent"
|
||||
|
||||
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
|
@ -275,38 +275,38 @@ func TestGetEtcdDataDir(t *testing.T) {
|
|||
podYaml string
|
||||
expectErr bool
|
||||
writeManifest bool
|
||||
validClient bool
|
||||
validConfig bool
|
||||
}{
|
||||
"non-existent file returns error": {
|
||||
expectErr: true,
|
||||
writeManifest: false,
|
||||
validClient: true,
|
||||
validConfig: true,
|
||||
},
|
||||
"return etcd data dir": {
|
||||
dataDir: "/path/to/etcd",
|
||||
podYaml: etcdPod,
|
||||
expectErr: false,
|
||||
writeManifest: true,
|
||||
validClient: true,
|
||||
validConfig: true,
|
||||
},
|
||||
"invalid etcd pod": {
|
||||
podYaml: etcdPodInvalid,
|
||||
expectErr: true,
|
||||
writeManifest: true,
|
||||
validClient: true,
|
||||
validConfig: true,
|
||||
},
|
||||
"etcd pod spec without data volume": {
|
||||
podYaml: etcdPodWithoutDataVolume,
|
||||
expectErr: true,
|
||||
writeManifest: true,
|
||||
validClient: true,
|
||||
validConfig: true,
|
||||
},
|
||||
"kubeconfig file doesn't exist": {
|
||||
dataDir: "/path/to/etcd",
|
||||
podYaml: etcdPod,
|
||||
expectErr: false,
|
||||
writeManifest: true,
|
||||
validClient: false,
|
||||
validConfig: false,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -325,9 +325,9 @@ func TestGetEtcdDataDir(t *testing.T) {
|
|||
|
||||
var dataDir string
|
||||
var err error
|
||||
if test.validClient {
|
||||
client := clientsetfake.NewSimpleClientset()
|
||||
dataDir, err = getEtcdDataDir(manifestPath, client)
|
||||
if test.validConfig {
|
||||
cfg := &kubeadmapi.InitConfiguration{}
|
||||
dataDir, err = getEtcdDataDir(manifestPath, cfg)
|
||||
} else {
|
||||
dataDir, err = getEtcdDataDir(manifestPath, nil)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
testUpgradeDiffConfig = `testdata/diff_master_config.yaml`
|
||||
testUpgradeDiffConfig = `testdata/diff_controlplane_config.yaml`
|
||||
testUpgradeDiffManifest = `testdata/diff_dummy_manifest.yaml`
|
||||
)
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import (
|
|||
)
|
||||
|
||||
var joinCommandTemplate = template.Must(template.New("join").Parse(`` +
|
||||
`kubeadm join {{.MasterHostPort}} --token {{.Token}}{{range $h := .CAPubKeyPins}} --discovery-token-ca-cert-hash {{$h}}{{end}}{{if .UploadCerts}} --certificate-key {{.CertificateKey}}{{end}}`,
|
||||
`kubeadm join {{.ControlPlaneHostPort}} --token {{.Token}}{{range $h := .CAPubKeyPins}} --discovery-token-ca-cert-hash {{$h}}{{end}}{{if .UploadCerts}} --certificate-key {{.CertificateKey}}{{end}}`,
|
||||
))
|
||||
|
||||
// GetJoinCommand returns the kubeadm join command for a given token and
|
||||
|
@ -71,11 +71,11 @@ func GetJoinCommand(kubeConfigFile, token, key string, skipTokenPrint, uploadCer
|
|||
}
|
||||
|
||||
ctx := map[string]interface{}{
|
||||
"Token": token,
|
||||
"CAPubKeyPins": publicKeyPins,
|
||||
"MasterHostPort": strings.Replace(clusterConfig.Server, "https://", "", -1),
|
||||
"UploadCerts": uploadCerts,
|
||||
"CertificateKey": key,
|
||||
"Token": token,
|
||||
"CAPubKeyPins": publicKeyPins,
|
||||
"ControlPlaneHostPort": strings.Replace(clusterConfig.Server, "https://", "", -1),
|
||||
"UploadCerts": uploadCerts,
|
||||
"CertificateKey": key,
|
||||
}
|
||||
|
||||
if skipTokenPrint {
|
||||
|
|
|
@ -172,16 +172,16 @@ func RetrieveValidatedConfigInfo(cfg *kubeadmapi.JoinConfiguration) (*clientcmda
|
|||
|
||||
// buildInsecureBootstrapKubeConfig makes a kubeconfig object that connects insecurely to the API Server for bootstrapping purposes
|
||||
func buildInsecureBootstrapKubeConfig(endpoint, clustername string) *clientcmdapi.Config {
|
||||
masterEndpoint := fmt.Sprintf("https://%s", endpoint)
|
||||
bootstrapConfig := kubeconfigutil.CreateBasic(masterEndpoint, clustername, BootstrapUser, []byte{})
|
||||
controlPlaneEndpoint := fmt.Sprintf("https://%s", endpoint)
|
||||
bootstrapConfig := kubeconfigutil.CreateBasic(controlPlaneEndpoint, clustername, BootstrapUser, []byte{})
|
||||
bootstrapConfig.Clusters[clustername].InsecureSkipTLSVerify = true
|
||||
return bootstrapConfig
|
||||
}
|
||||
|
||||
// buildSecureBootstrapKubeConfig makes a kubeconfig object that connects securely to the API Server for bootstrapping purposes (validating with the specified CA)
|
||||
func buildSecureBootstrapKubeConfig(endpoint string, caCert []byte, clustername string) *clientcmdapi.Config {
|
||||
masterEndpoint := fmt.Sprintf("https://%s", endpoint)
|
||||
bootstrapConfig := kubeconfigutil.CreateBasic(masterEndpoint, clustername, BootstrapUser, caCert)
|
||||
controlPlaneEndpoint := fmt.Sprintf("https://%s", endpoint)
|
||||
bootstrapConfig := kubeconfigutil.CreateBasic(controlPlaneEndpoint, clustername, BootstrapUser, caCert)
|
||||
return bootstrapConfig
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
|||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["uploadcerts.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadcerts",
|
||||
srcs = ["copycerts.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/phases/copycerts",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
|
@ -14,9 +14,12 @@ go_library(
|
|||
"//pkg/apis/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/keyutil:go_default_library",
|
||||
"//staging/src/k8s.io/cluster-bootstrap/token/util:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
],
|
||||
|
@ -38,7 +41,7 @@ filegroup(
|
|||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["uploadcerts_test.go"],
|
||||
srcs = ["copycerts_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package uploadcerts
|
||||
package copycerts
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
@ -28,9 +28,12 @@ import (
|
|||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
keyutil "k8s.io/client-go/util/keyutil"
|
||||
bootstraputil "k8s.io/cluster-bootstrap/token/util"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
|
@ -92,7 +95,7 @@ func UploadCerts(client clientset.Interface, cfg *kubeadmapi.InitConfiguration,
|
|||
return err
|
||||
}
|
||||
|
||||
secretData, err := getSecretData(cfg, decodedKey)
|
||||
secretData, err := getDataFromDisk(cfg, decodedKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -169,7 +172,7 @@ func loadAndEncryptCert(certPath string, key []byte) ([]byte, error) {
|
|||
return cryptoutil.EncryptBytes(cert, key)
|
||||
}
|
||||
|
||||
func certsToUpload(cfg *kubeadmapi.InitConfiguration) map[string]string {
|
||||
func certsToTransfer(cfg *kubeadmapi.InitConfiguration) map[string]string {
|
||||
certsDir := cfg.CertificatesDir
|
||||
certs := map[string]string{
|
||||
kubeadmconstants.CACertName: path.Join(certsDir, kubeadmconstants.CACertName),
|
||||
|
@ -191,15 +194,85 @@ func certsToUpload(cfg *kubeadmapi.InitConfiguration) map[string]string {
|
|||
return certs
|
||||
}
|
||||
|
||||
func getSecretData(cfg *kubeadmapi.InitConfiguration, key []byte) (map[string][]byte, error) {
|
||||
func getDataFromDisk(cfg *kubeadmapi.InitConfiguration, key []byte) (map[string][]byte, error) {
|
||||
secretData := map[string][]byte{}
|
||||
for certName, certPath := range certsToUpload(cfg) {
|
||||
for certName, certPath := range certsToTransfer(cfg) {
|
||||
cert, err := loadAndEncryptCert(certPath, key)
|
||||
if err == nil || (err != nil && os.IsNotExist(err)) {
|
||||
secretData[strings.Replace(certName, "/", "-", -1)] = cert
|
||||
secretData[certOrKeyNameToSecretName(certName)] = cert
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return secretData, nil
|
||||
}
|
||||
|
||||
// DownloadCerts downloads the certificates needed to join a new control plane.
|
||||
func DownloadCerts(client clientset.Interface, cfg *kubeadmapi.InitConfiguration, key string) error {
|
||||
fmt.Printf("[download-certs] downloading the certificates in Secret %q in the %q Namespace\n", kubeadmconstants.KubeadmCertsSecret, metav1.NamespaceSystem)
|
||||
|
||||
decodedKey, err := hex.DecodeString(key)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error decoding certificate key")
|
||||
}
|
||||
|
||||
secret, err := getSecret(client)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error downloading the secret")
|
||||
}
|
||||
|
||||
secretData, err := getDataFromSecret(secret, decodedKey)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error decoding secret data with provided key")
|
||||
}
|
||||
|
||||
for certOrKeyName, certOrKeyPath := range certsToTransfer(cfg) {
|
||||
certOrKeyData, found := secretData[certOrKeyNameToSecretName(certOrKeyName)]
|
||||
if !found {
|
||||
return errors.New("couldn't find required certificate or key in Secret")
|
||||
}
|
||||
if err := writeCertOrKey(certOrKeyPath, certOrKeyData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeCertOrKey(certOrKeyPath string, certOrKeyData []byte) error {
|
||||
if _, err := keyutil.ParsePublicKeysPEM(certOrKeyData); err == nil {
|
||||
return keyutil.WriteKey(certOrKeyPath, certOrKeyData)
|
||||
} else if _, err := certutil.ParseCertsPEM(certOrKeyData); err == nil {
|
||||
return certutil.WriteCert(certOrKeyPath, certOrKeyData)
|
||||
}
|
||||
return errors.New("unknown data found in Secret entry")
|
||||
}
|
||||
|
||||
func getSecret(client clientset.Interface) (*v1.Secret, error) {
|
||||
secret, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Get(kubeadmconstants.KubeadmCertsSecret, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil, errors.Errorf("Secret %q was not found in the %q Namespace. This Secret might have expired. Please, run `kubeadm init phase upload-certs` on a control plane to generate a new one", kubeadmconstants.KubeadmCertsSecret, metav1.NamespaceSystem)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func getDataFromSecret(secret *v1.Secret, key []byte) (map[string][]byte, error) {
|
||||
secretData := map[string][]byte{}
|
||||
for certName, encryptedCert := range secret.Data {
|
||||
cert, err := cryptoutil.DecryptBytes(encryptedCert, key)
|
||||
if err != nil {
|
||||
// If any of the decrypt operations fail do not return a partial result,
|
||||
// return an empty result immediately
|
||||
return map[string][]byte{}, err
|
||||
}
|
||||
secretData[certName] = cert
|
||||
}
|
||||
return secretData, nil
|
||||
}
|
||||
|
||||
func certOrKeyNameToSecretName(certOrKeyName string) string {
|
||||
return strings.Replace(certOrKeyName, "/", "-", -1)
|
||||
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package uploadcerts
|
||||
package copycerts
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
@ -38,7 +38,7 @@ func TestUploadCerts(t *testing.T) {
|
|||
}
|
||||
|
||||
//teste cert name, teste cert can be decrypted
|
||||
func TestGetSecretData(t *testing.T) {
|
||||
func TestGetDataFromInitConfig(t *testing.T) {
|
||||
certData := []byte("cert-data")
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
@ -58,14 +58,14 @@ func TestGetSecretData(t *testing.T) {
|
|||
t.Fatalf(dedent.Dedent("failed to create etcd cert dir.\nfatal error: %v"), err)
|
||||
}
|
||||
|
||||
certs := certsToUpload(cfg)
|
||||
certs := certsToTransfer(cfg)
|
||||
for name, path := range certs {
|
||||
if err := ioutil.WriteFile(path, certData, 0644); err != nil {
|
||||
t.Fatalf(dedent.Dedent("failed to write cert: %s\nfatal error: %v"), name, err)
|
||||
}
|
||||
}
|
||||
|
||||
secretData, err := getSecretData(cfg, decodedKey)
|
||||
secretData, err := getDataFromDisk(cfg, decodedKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get secret data. fatal error: %v", err)
|
||||
}
|
||||
|
@ -83,29 +83,44 @@ func TestGetSecretData(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCertsToUpload(t *testing.T) {
|
||||
func TestCertsToTransfer(t *testing.T) {
|
||||
localEtcdCfg := &kubeadmapi.InitConfiguration{}
|
||||
externalEtcdCfg := &kubeadmapi.InitConfiguration{}
|
||||
externalEtcdCfg.Etcd = kubeadmapi.Etcd{}
|
||||
externalEtcdCfg.Etcd.External = &kubeadmapi.ExternalEtcd{}
|
||||
|
||||
commonExpectedCerts := []string{
|
||||
kubeadmconstants.CACertName,
|
||||
kubeadmconstants.CAKeyName,
|
||||
kubeadmconstants.FrontProxyCACertName,
|
||||
kubeadmconstants.FrontProxyCAKeyName,
|
||||
kubeadmconstants.ServiceAccountPublicKeyName,
|
||||
kubeadmconstants.ServiceAccountPrivateKeyName,
|
||||
}
|
||||
|
||||
tests := map[string]struct {
|
||||
config *kubeadmapi.InitConfiguration
|
||||
expectedCerts []string
|
||||
}{
|
||||
"local etcd": {
|
||||
config: localEtcdCfg,
|
||||
expectedCerts: []string{kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName},
|
||||
config: localEtcdCfg,
|
||||
expectedCerts: append(
|
||||
[]string{kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName},
|
||||
commonExpectedCerts...,
|
||||
),
|
||||
},
|
||||
"external etcd": {
|
||||
config: externalEtcdCfg,
|
||||
expectedCerts: []string{externalEtcdCA, externalEtcdCert, externalEtcdKey},
|
||||
config: externalEtcdCfg,
|
||||
expectedCerts: append(
|
||||
[]string{externalEtcdCA, externalEtcdCert, externalEtcdKey},
|
||||
commonExpectedCerts...,
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t2 *testing.T) {
|
||||
certList := certsToUpload(test.config)
|
||||
certList := certsToTransfer(test.config)
|
||||
for _, cert := range test.expectedCerts {
|
||||
if _, found := certList[cert]; !found {
|
||||
t2.Fatalf(dedent.Dedent("failed to get list of certs to upload\ncert %s not found"), cert)
|
||||
|
@ -114,3 +129,30 @@ func TestCertsToUpload(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertOrKeyNameToSecretName(t *testing.T) {
|
||||
tests := []struct {
|
||||
keyName string
|
||||
expectedSecretName string
|
||||
}{
|
||||
{
|
||||
keyName: "apiserver-kubelet-client.crt",
|
||||
expectedSecretName: "apiserver-kubelet-client.crt",
|
||||
},
|
||||
{
|
||||
keyName: "etcd/ca.crt",
|
||||
expectedSecretName: "etcd-ca.crt",
|
||||
},
|
||||
{
|
||||
keyName: "etcd/healthcheck-client.crt",
|
||||
expectedSecretName: "etcd-healthcheck-client.crt",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
secretName := certOrKeyNameToSecretName(tc.keyName)
|
||||
if secretName != tc.expectedSecretName {
|
||||
t.Fatalf("secret name %s didn't match expected name %s", secretName, tc.expectedSecretName)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ go_library(
|
|||
"//cmd/kubeadm/app/images:go_default_library",
|
||||
"//cmd/kubeadm/app/util/runtime:go_default_library",
|
||||
"//cmd/kubeadm/app/util/system:go_default_library",
|
||||
"//pkg/master/ports:go_default_library",
|
||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||
"//pkg/util/initsystem:go_default_library",
|
||||
"//pkg/util/ipvs:go_default_library",
|
||||
|
|
|
@ -46,6 +46,7 @@ import (
|
|||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
utilruntime "k8s.io/kubernetes/cmd/kubeadm/app/util/runtime"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/system"
|
||||
"k8s.io/kubernetes/pkg/master/ports"
|
||||
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||
"k8s.io/kubernetes/pkg/util/initsystem"
|
||||
ipvsutil "k8s.io/kubernetes/pkg/util/ipvs"
|
||||
|
@ -882,10 +883,10 @@ func RunInitNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.InitConfigura
|
|||
checks := []Checker{
|
||||
NumCPUCheck{NumCPU: kubeadmconstants.ControlPlaneNumCPU},
|
||||
KubernetesVersionCheck{KubernetesVersion: cfg.KubernetesVersion, KubeadmVersion: kubeadmversion.Get().GitVersion},
|
||||
FirewalldCheck{ports: []int{int(cfg.LocalAPIEndpoint.BindPort), 10250}},
|
||||
FirewalldCheck{ports: []int{int(cfg.LocalAPIEndpoint.BindPort), ports.KubeletPort}},
|
||||
PortOpenCheck{port: int(cfg.LocalAPIEndpoint.BindPort)},
|
||||
PortOpenCheck{port: 10251},
|
||||
PortOpenCheck{port: 10252},
|
||||
PortOpenCheck{port: ports.InsecureSchedulerPort},
|
||||
PortOpenCheck{port: ports.InsecureKubeControllerManagerPort},
|
||||
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeAPIServer, manifestsDir)},
|
||||
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeControllerManager, manifestsDir)},
|
||||
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeScheduler, manifestsDir)},
|
||||
|
@ -1037,7 +1038,7 @@ func addCommonChecks(execer utilsexec.Interface, cfg kubeadmapi.CommonConfigurat
|
|||
HostnameCheck{nodeName: cfg.GetNodeName()},
|
||||
KubeletVersionCheck{KubernetesVersion: cfg.GetKubernetesVersion(), exec: execer},
|
||||
ServiceCheck{Service: "kubelet", CheckIfActive: false},
|
||||
PortOpenCheck{port: 10250})
|
||||
PortOpenCheck{port: ports.KubeletPort})
|
||||
return checks
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ func TestPatchNodeNonErrorCases(t *testing.T) {
|
|||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client := fake.NewSimpleClientset()
|
||||
_, err := client.Core().Nodes().Create(&tc.node)
|
||||
_, err := client.CoreV1().Nodes().Create(&tc.node)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create node to fake client: %v", err)
|
||||
}
|
||||
|
|
|
@ -34,16 +34,16 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
masterV1alpha3YAML = "testdata/conversion/master/v1alpha3.yaml"
|
||||
masterV1alpha3YAMLNonLinux = "testdata/conversion/master/v1alpha3_non_linux.yaml"
|
||||
masterV1beta1YAML = "testdata/conversion/master/v1beta1.yaml"
|
||||
masterV1beta1YAMLNonLinux = "testdata/conversion/master/v1beta1_non_linux.yaml"
|
||||
masterInternalYAML = "testdata/conversion/master/internal.yaml"
|
||||
masterInternalYAMLNonLinux = "testdata/conversion/master/internal_non_linux.yaml"
|
||||
masterIncompleteYAML = "testdata/defaulting/master/incomplete.yaml"
|
||||
masterDefaultedYAML = "testdata/defaulting/master/defaulted.yaml"
|
||||
masterDefaultedYAMLNonLinux = "testdata/defaulting/master/defaulted_non_linux.yaml"
|
||||
masterInvalidYAML = "testdata/validation/invalid_mastercfg.yaml"
|
||||
controlPlaneV1alpha3YAML = "testdata/conversion/controlplane/v1alpha3.yaml"
|
||||
controlPlaneV1alpha3YAMLNonLinux = "testdata/conversion/controlplane/v1alpha3_non_linux.yaml"
|
||||
controlPlaneV1beta1YAML = "testdata/conversion/controlplane/v1beta1.yaml"
|
||||
controlPlaneV1beta1YAMLNonLinux = "testdata/conversion/controlplane/v1beta1_non_linux.yaml"
|
||||
controlPlaneInternalYAML = "testdata/conversion/controlplane/internal.yaml"
|
||||
controlPlaneInternalYAMLNonLinux = "testdata/conversion/controlplane/internal_non_linux.yaml"
|
||||
controlPlaneIncompleteYAML = "testdata/defaulting/controlplane/incomplete.yaml"
|
||||
controlPlaneDefaultedYAML = "testdata/defaulting/controlplane/defaulted.yaml"
|
||||
controlPlaneDefaultedYAMLNonLinux = "testdata/defaulting/controlplane/defaulted_non_linux.yaml"
|
||||
controlPlaneInvalidYAML = "testdata/validation/invalid_controlplanecfg.yaml"
|
||||
)
|
||||
|
||||
func diff(expected, actual []byte) string {
|
||||
|
@ -141,15 +141,15 @@ func TestLoadInitConfigurationFromFile(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInitConfigurationMarshallingFromFile(t *testing.T) {
|
||||
masterV1alpha3YAMLAbstracted := masterV1alpha3YAML
|
||||
masterV1beta1YAMLAbstracted := masterV1beta1YAML
|
||||
masterInternalYAMLAbstracted := masterInternalYAML
|
||||
masterDefaultedYAMLAbstracted := masterDefaultedYAML
|
||||
controlPlaneV1alpha3YAMLAbstracted := controlPlaneV1alpha3YAML
|
||||
controlPlaneV1beta1YAMLAbstracted := controlPlaneV1beta1YAML
|
||||
controlPlaneInternalYAMLAbstracted := controlPlaneInternalYAML
|
||||
controlPlaneDefaultedYAMLAbstracted := controlPlaneDefaultedYAML
|
||||
if runtime.GOOS != "linux" {
|
||||
masterV1alpha3YAMLAbstracted = masterV1alpha3YAMLNonLinux
|
||||
masterV1beta1YAMLAbstracted = masterV1beta1YAMLNonLinux
|
||||
masterInternalYAMLAbstracted = masterInternalYAMLNonLinux
|
||||
masterDefaultedYAMLAbstracted = masterDefaultedYAMLNonLinux
|
||||
controlPlaneV1alpha3YAMLAbstracted = controlPlaneV1alpha3YAMLNonLinux
|
||||
controlPlaneV1beta1YAMLAbstracted = controlPlaneV1beta1YAMLNonLinux
|
||||
controlPlaneInternalYAMLAbstracted = controlPlaneInternalYAMLNonLinux
|
||||
controlPlaneDefaultedYAMLAbstracted = controlPlaneDefaultedYAMLNonLinux
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
|
@ -161,32 +161,32 @@ func TestInitConfigurationMarshallingFromFile(t *testing.T) {
|
|||
// and then marshals the internal object to the expected groupVersion
|
||||
{ // v1alpha3 -> internal
|
||||
name: "v1alpha3IsDeprecated",
|
||||
in: masterV1alpha3YAMLAbstracted,
|
||||
in: controlPlaneV1alpha3YAMLAbstracted,
|
||||
expectedErr: true,
|
||||
},
|
||||
{ // v1beta1 -> internal
|
||||
name: "v1beta1ToInternal",
|
||||
in: masterV1beta1YAMLAbstracted,
|
||||
out: masterInternalYAMLAbstracted,
|
||||
in: controlPlaneV1beta1YAMLAbstracted,
|
||||
out: controlPlaneInternalYAMLAbstracted,
|
||||
groupVersion: kubeadm.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1beta1 -> internal -> v1beta1
|
||||
name: "v1beta1Tov1beta1",
|
||||
in: masterV1beta1YAMLAbstracted,
|
||||
out: masterV1beta1YAMLAbstracted,
|
||||
in: controlPlaneV1beta1YAMLAbstracted,
|
||||
out: controlPlaneV1beta1YAMLAbstracted,
|
||||
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
|
||||
},
|
||||
// These tests are reading one file that has only a subset of the fields populated, loading it using LoadInitConfigurationFromFile,
|
||||
// and then marshals the internal object to the expected groupVersion
|
||||
{ // v1beta1 -> default -> validate -> internal -> v1beta1
|
||||
name: "incompleteYAMLToDefaultedv1beta1",
|
||||
in: masterIncompleteYAML,
|
||||
out: masterDefaultedYAMLAbstracted,
|
||||
in: controlPlaneIncompleteYAML,
|
||||
out: controlPlaneDefaultedYAMLAbstracted,
|
||||
groupVersion: kubeadmapiv1beta1.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1beta1 -> validation should fail
|
||||
name: "invalidYAMLShouldFail",
|
||||
in: masterInvalidYAML,
|
||||
in: controlPlaneInvalidYAML,
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ Networking:
|
|||
NodeRegistration:
|
||||
CRISocket: /var/run/dockershim.sock
|
||||
KubeletExtraArgs: null
|
||||
Name: master-1
|
||||
Name: control-plane-1
|
||||
Taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
|
@ -197,7 +197,7 @@ Networking:
|
|||
NodeRegistration:
|
||||
CRISocket: /var/run/dockershim.sock
|
||||
KubeletExtraArgs: null
|
||||
Name: master-1
|
||||
Name: control-plane-1
|
||||
Taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
|
@ -13,7 +13,7 @@ bootstrapTokens:
|
|||
kind: InitConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
name: control-plane-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
|
@ -13,7 +13,7 @@ bootstrapTokens:
|
|||
kind: InitConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
name: control-plane-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
|
@ -13,7 +13,7 @@ localAPIEndpoint:
|
|||
bindPort: 6443
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
name: control-plane-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
|
@ -13,7 +13,7 @@ localAPIEndpoint:
|
|||
bindPort: 6443
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
name: control-plane-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
|
@ -15,7 +15,7 @@ Discovery:
|
|||
NodeRegistration:
|
||||
CRISocket: /var/run/dockershim.sock
|
||||
KubeletExtraArgs: null
|
||||
Name: master-1
|
||||
Name: control-plane-1
|
||||
Taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
|
|
|
@ -13,7 +13,7 @@ discoveryTokenUnsafeSkipCAVerification: true
|
|||
kind: JoinConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
name: control-plane-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
|
|
|
@ -14,7 +14,7 @@ discovery:
|
|||
kind: JoinConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
name: control-plane-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
|
|
|
@ -13,7 +13,7 @@ localAPIEndpoint:
|
|||
bindPort: 6443
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/criruntime.sock
|
||||
name: master-1
|
||||
name: control-plane-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
|
@ -13,7 +13,7 @@ localAPIEndpoint:
|
|||
bindPort: 6443
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/criruntime.sock
|
||||
name: master-1
|
||||
name: control-plane-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
|
@ -6,7 +6,7 @@ localAPIEndpoint:
|
|||
advertiseAddress: 192.168.2.2
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/criruntime.sock
|
||||
name: master-1
|
||||
name: control-plane-1
|
||||
---
|
||||
apiVersion: kubeadm.k8s.io/v1beta1
|
||||
certificatesDir: /var/lib/kubernetes/pki
|
|
@ -225,14 +225,11 @@ pkg/quota/v1/evaluator/core
|
|||
pkg/registry/admissionregistration/mutatingwebhookconfiguration/storage
|
||||
pkg/registry/admissionregistration/rest
|
||||
pkg/registry/admissionregistration/validatingwebhookconfiguration/storage
|
||||
pkg/registry/apps/daemonset
|
||||
pkg/registry/apps/daemonset/storage
|
||||
pkg/registry/apps/deployment
|
||||
pkg/registry/apps/deployment/storage
|
||||
pkg/registry/apps/replicaset
|
||||
pkg/registry/apps/replicaset/storage
|
||||
pkg/registry/apps/rest
|
||||
pkg/registry/apps/statefulset
|
||||
pkg/registry/apps/statefulset/storage
|
||||
pkg/registry/auditregistration/rest
|
||||
pkg/registry/authentication/rest
|
||||
|
@ -241,10 +238,8 @@ pkg/registry/authorization/localsubjectaccessreview
|
|||
pkg/registry/authorization/rest
|
||||
pkg/registry/authorization/selfsubjectaccessreview
|
||||
pkg/registry/authorization/subjectaccessreview
|
||||
pkg/registry/autoscaling/horizontalpodautoscaler
|
||||
pkg/registry/autoscaling/horizontalpodautoscaler/storage
|
||||
pkg/registry/autoscaling/rest
|
||||
pkg/registry/batch/cronjob
|
||||
pkg/registry/batch/cronjob/storage
|
||||
pkg/registry/batch/job
|
||||
pkg/registry/batch/job/storage
|
||||
|
@ -271,7 +266,6 @@ pkg/registry/core/pod/rest
|
|||
pkg/registry/core/podtemplate/storage
|
||||
pkg/registry/core/replicationcontroller
|
||||
pkg/registry/core/replicationcontroller/storage
|
||||
pkg/registry/core/resourcequota
|
||||
pkg/registry/core/resourcequota/storage
|
||||
pkg/registry/core/rest
|
||||
pkg/registry/core/secret
|
||||
|
@ -289,7 +283,6 @@ pkg/registry/extensions/controller/storage
|
|||
pkg/registry/extensions/rest
|
||||
pkg/registry/networking/networkpolicy/storage
|
||||
pkg/registry/networking/rest
|
||||
pkg/registry/policy/poddisruptionbudget
|
||||
pkg/registry/policy/poddisruptionbudget/storage
|
||||
pkg/registry/policy/rest
|
||||
pkg/registry/rbac/clusterrole
|
||||
|
@ -650,29 +643,24 @@ test/e2e/apps
|
|||
test/e2e/auth
|
||||
test/e2e/autoscaling
|
||||
test/e2e/chaosmonkey
|
||||
test/e2e/cloud
|
||||
test/e2e/common
|
||||
test/e2e/framework
|
||||
test/e2e/framework/ingress
|
||||
test/e2e/framework/providers/gce
|
||||
test/e2e/framework/providers/kubemark
|
||||
test/e2e/instrumentation
|
||||
test/e2e/instrumentation/logging
|
||||
test/e2e/instrumentation/monitoring
|
||||
test/e2e/kubectl
|
||||
test/e2e/lifecycle
|
||||
test/e2e/lifecycle/bootstrap
|
||||
test/e2e/network
|
||||
test/e2e/node
|
||||
test/e2e/scalability
|
||||
test/e2e/scheduling
|
||||
test/e2e/servicecatalog
|
||||
test/e2e/storage
|
||||
test/e2e/storage/drivers
|
||||
test/e2e/storage/testsuites
|
||||
test/e2e/storage/utils
|
||||
test/e2e/storage/vsphere
|
||||
test/e2e/ui
|
||||
test/e2e/windows
|
||||
test/e2e_kubeadm
|
||||
test/e2e_node
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: the-map
|
||||
data:
|
||||
altGreeting: "Good Morning!"
|
||||
enableRisky: "false"
|
|
@ -0,0 +1,35 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: the-deployment
|
||||
labels:
|
||||
deployment: hello
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
deployment: hello
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
deployment: hello
|
||||
spec:
|
||||
containers:
|
||||
- name: the-container
|
||||
image: monopole/hello:1
|
||||
command: ["/hello",
|
||||
"--port=8080",
|
||||
"--enableRiskyFeature=$(ENABLE_RISKY)"]
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: ALT_GREETING
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: the-map
|
||||
key: altGreeting
|
||||
- name: ENABLE_RISKY
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: the-map
|
||||
key: enableRisky
|
|
@ -0,0 +1,5 @@
|
|||
nameprefix: test-
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
- configmap.yaml
|
|
@ -0,0 +1,12 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: the-service
|
||||
spec:
|
||||
selector:
|
||||
deployment: hello
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8666
|
||||
targetPort: 8080
|
|
@ -6,7 +6,8 @@
|
|||
""
|
||||
],
|
||||
"ForbiddenPrefixes": [
|
||||
"k8s.io/kubernetes/cmd"
|
||||
"k8s.io/kubernetes/cmd",
|
||||
"github.com/ghodss/yaml"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -24,7 +24,6 @@ filegroup(
|
|||
"//pkg/api/testapi:all-srcs",
|
||||
"//pkg/api/testing:all-srcs",
|
||||
"//pkg/api/v1/endpoints:all-srcs",
|
||||
"//pkg/api/v1/node:all-srcs",
|
||||
"//pkg/api/v1/persistentvolume:all-srcs",
|
||||
"//pkg/api/v1/pod:all-srcs",
|
||||
"//pkg/api/v1/resource:all-srcs",
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["util.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/api/v1/node",
|
||||
deps = ["//staging/src/k8s.io/api/core/v1:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
|
@ -32,6 +32,10 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||
obj.FailurePolicy = &p
|
||||
s := admissionregistration.SideEffectClassUnknown
|
||||
obj.SideEffects = &s
|
||||
if obj.TimeoutSeconds == nil {
|
||||
i := int32(30)
|
||||
obj.TimeoutSeconds = &i
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,6 +208,13 @@ type Webhook struct {
|
|||
// sideEffects == Unknown or Some. Defaults to Unknown.
|
||||
// +optional
|
||||
SideEffects *SideEffectClass
|
||||
|
||||
// TimeoutSeconds specifies the timeout for this webhook. After the timeout passes,
|
||||
// the webhook call will be ignored or the API call will fail based on the
|
||||
// failure policy.
|
||||
// The timeout value must be between 1 and 30 seconds.
|
||||
// +optional
|
||||
TimeoutSeconds *int32
|
||||
}
|
||||
|
||||
// RuleWithOperations is a tuple of Operations and Resources. It is recommended to make
|
||||
|
|
|
@ -40,4 +40,8 @@ func SetDefaults_Webhook(obj *admissionregistrationv1beta1.Webhook) {
|
|||
unknown := admissionregistrationv1beta1.SideEffectClassUnknown
|
||||
obj.SideEffects = &unknown
|
||||
}
|
||||
if obj.TimeoutSeconds == nil {
|
||||
obj.TimeoutSeconds = new(int32)
|
||||
*obj.TimeoutSeconds = 30
|
||||
}
|
||||
}
|
||||
|
|
|
@ -301,6 +301,7 @@ func autoConvert_v1beta1_Webhook_To_admissionregistration_Webhook(in *v1beta1.We
|
|||
out.FailurePolicy = (*admissionregistration.FailurePolicyType)(unsafe.Pointer(in.FailurePolicy))
|
||||
out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector))
|
||||
out.SideEffects = (*admissionregistration.SideEffectClass)(unsafe.Pointer(in.SideEffects))
|
||||
out.TimeoutSeconds = (*int32)(unsafe.Pointer(in.TimeoutSeconds))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -318,6 +319,7 @@ func autoConvert_admissionregistration_Webhook_To_v1beta1_Webhook(in *admissionr
|
|||
out.FailurePolicy = (*v1beta1.FailurePolicyType)(unsafe.Pointer(in.FailurePolicy))
|
||||
out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector))
|
||||
out.SideEffects = (*v1beta1.SideEffectClass)(unsafe.Pointer(in.SideEffects))
|
||||
out.TimeoutSeconds = (*int32)(unsafe.Pointer(in.TimeoutSeconds))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -171,6 +171,9 @@ func validateWebhook(hook *admissionregistration.Webhook, fldPath *field.Path) f
|
|||
if hook.SideEffects != nil && !supportedSideEffectClasses.Has(string(*hook.SideEffects)) {
|
||||
allErrors = append(allErrors, field.NotSupported(fldPath.Child("sideEffects"), *hook.SideEffects, supportedSideEffectClasses.List()))
|
||||
}
|
||||
if hook.TimeoutSeconds != nil && (*hook.TimeoutSeconds > 30 || *hook.TimeoutSeconds < 1) {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath.Child("timeoutSeconds"), *hook.TimeoutSeconds, "the timeout value must be between 1 and 30 seconds"))
|
||||
}
|
||||
|
||||
if hook.NamespaceSelector != nil {
|
||||
allErrors = append(allErrors, metav1validation.ValidateLabelSelector(hook.NamespaceSelector, fldPath.Child("namespaceSelector"))...)
|
||||
|
|
|
@ -26,6 +26,8 @@ import (
|
|||
|
||||
func strPtr(s string) *string { return &s }
|
||||
|
||||
func int32Ptr(i int32) *int32 { return &i }
|
||||
|
||||
func newValidatingWebhookConfiguration(hooks []admissionregistration.Webhook) *admissionregistration.ValidatingWebhookConfiguration {
|
||||
return &admissionregistration.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -544,6 +546,63 @@ func TestValidateValidatingWebhookConfiguration(t *testing.T) {
|
|||
}),
|
||||
expectedError: `clientConfig.service.path: Invalid value: "/apis/foo.bar/v1alpha1/--bad": segment[3]: a DNS-1123 subdomain`,
|
||||
},
|
||||
{
|
||||
name: "timeout seconds cannot be greater than 30",
|
||||
config: newValidatingWebhookConfiguration(
|
||||
[]admissionregistration.Webhook{
|
||||
{
|
||||
Name: "webhook.k8s.io",
|
||||
ClientConfig: validClientConfig,
|
||||
TimeoutSeconds: int32Ptr(31),
|
||||
},
|
||||
}),
|
||||
expectedError: `webhooks[0].timeoutSeconds: Invalid value: 31: the timeout value must be between 1 and 30 seconds`,
|
||||
},
|
||||
{
|
||||
name: "timeout seconds cannot be smaller than 1",
|
||||
config: newValidatingWebhookConfiguration(
|
||||
[]admissionregistration.Webhook{
|
||||
{
|
||||
Name: "webhook.k8s.io",
|
||||
ClientConfig: validClientConfig,
|
||||
TimeoutSeconds: int32Ptr(0),
|
||||
},
|
||||
}),
|
||||
expectedError: `webhooks[0].timeoutSeconds: Invalid value: 0: the timeout value must be between 1 and 30 seconds`,
|
||||
},
|
||||
{
|
||||
name: "timeout seconds must be positive",
|
||||
config: newValidatingWebhookConfiguration(
|
||||
[]admissionregistration.Webhook{
|
||||
{
|
||||
Name: "webhook.k8s.io",
|
||||
ClientConfig: validClientConfig,
|
||||
TimeoutSeconds: int32Ptr(-1),
|
||||
},
|
||||
}),
|
||||
expectedError: `webhooks[0].timeoutSeconds: Invalid value: -1: the timeout value must be between 1 and 30 seconds`,
|
||||
},
|
||||
{
|
||||
name: "valid timeout seconds",
|
||||
config: newValidatingWebhookConfiguration(
|
||||
[]admissionregistration.Webhook{
|
||||
{
|
||||
Name: "webhook.k8s.io",
|
||||
ClientConfig: validClientConfig,
|
||||
TimeoutSeconds: int32Ptr(1),
|
||||
},
|
||||
{
|
||||
Name: "webhook2.k8s.io",
|
||||
ClientConfig: validClientConfig,
|
||||
TimeoutSeconds: int32Ptr(15),
|
||||
},
|
||||
{
|
||||
Name: "webhook3.k8s.io",
|
||||
ClientConfig: validClientConfig,
|
||||
TimeoutSeconds: int32Ptr(30),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
|
|
@ -257,6 +257,11 @@ func (in *Webhook) DeepCopyInto(out *Webhook) {
|
|||
*out = new(SideEffectClass)
|
||||
**out = **in
|
||||
}
|
||||
if in.TimeoutSeconds != nil {
|
||||
in, out := &in.TimeoutSeconds, &out.TimeoutSeconds
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -906,3 +906,34 @@ func TestValidatePSPRunAsGroup(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePSPSELinux(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
name string
|
||||
selinux policy.SELinuxStrategyOptions
|
||||
fail bool
|
||||
}{
|
||||
{"SELinuxStrategyMustRunAs",
|
||||
policy.SELinuxStrategyOptions{
|
||||
Rule: policy.SELinuxStrategyMustRunAs,
|
||||
SELinuxOptions: &api.SELinuxOptions{Level: "s9:z0,z1"}}, false},
|
||||
{"SELinuxStrategyMustRunAs",
|
||||
policy.SELinuxStrategyOptions{
|
||||
Rule: policy.SELinuxStrategyMustRunAs,
|
||||
SELinuxOptions: &api.SELinuxOptions{Level: "s0"}}, false},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
errList := validatePSPSELinux(field.NewPath("Status"), &testCase.selinux)
|
||||
actualErrors := len(errList)
|
||||
expectedErrors := 1
|
||||
if !testCase.fail {
|
||||
expectedErrors = 0
|
||||
}
|
||||
if actualErrors != expectedErrors {
|
||||
t.Errorf("In testCase %v, expected %v errors, got %v errors", testCase.name, expectedErrors, actualErrors)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
@ -194,11 +195,20 @@ func (w lw) Watch(options metav1.ListOptions) (watch.Interface, error) {
|
|||
func TestListWatchUntil(t *testing.T) {
|
||||
fw := watch.NewFake()
|
||||
go func() {
|
||||
var obj *v1.Pod
|
||||
obj := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
}
|
||||
fw.Modify(obj)
|
||||
}()
|
||||
listwatch := lw{
|
||||
list: &v1.PodList{Items: []v1.Pod{{}}},
|
||||
list: &v1.PodList{
|
||||
ListMeta: metav1.ListMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Items: []v1.Pod{{}},
|
||||
},
|
||||
watch: fw,
|
||||
}
|
||||
|
||||
|
@ -213,8 +223,9 @@ func TestListWatchUntil(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
timeout := 10 * time.Second
|
||||
lastEvent, err := watchtools.ListWatchUntil(timeout, listwatch, conditions...)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
lastEvent, err := watchtools.ListWatchUntil(ctx, listwatch, conditions...)
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got %#v", err)
|
||||
}
|
||||
|
|
|
@ -167,7 +167,6 @@
|
|||
"AllowedPrefixes": [
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme",
|
||||
"k8s.io/kubernetes/pkg/api/v1/endpoints",
|
||||
"k8s.io/kubernetes/pkg/api/v1/node",
|
||||
"k8s.io/kubernetes/pkg/api/v1/pod",
|
||||
"k8s.io/kubernetes/pkg/apis/apps/v1",
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling",
|
||||
|
|
|
@ -47,7 +47,7 @@ func TestCertificateController(t *testing.T) {
|
|||
Reason: "test reason",
|
||||
Message: "test message",
|
||||
})
|
||||
_, err := client.Certificates().CertificateSigningRequests().UpdateApproval(csr)
|
||||
_, err := client.CertificatesV1beta1().CertificateSigningRequests().UpdateApproval(csr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@ go_library(
|
|||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/controller/cloud",
|
||||
deps = [
|
||||
"//pkg/api/v1/node:go_default_library",
|
||||
"//pkg/apis/core/v1/helper:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/util/node:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/scheduler/api:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
|
|
|
@ -35,8 +35,8 @@ import (
|
|||
"k8s.io/client-go/tools/record"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
"k8s.io/klog"
|
||||
nodeutilv1 "k8s.io/kubernetes/pkg/api/v1/node"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
nodeutil "k8s.io/kubernetes/pkg/controller/util/node"
|
||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
|
||||
)
|
||||
|
||||
|
@ -133,7 +133,7 @@ func (c *CloudNodeLifecycleController) MonitorNodes() {
|
|||
for _, node := range nodes {
|
||||
// Default NodeReady status to v1.ConditionUnknown
|
||||
status := v1.ConditionUnknown
|
||||
if _, c := nodeutilv1.GetNodeCondition(&node.Status, v1.NodeReady); c != nil {
|
||||
if _, c := nodeutil.GetNodeCondition(&node.Status, v1.NodeReady); c != nil {
|
||||
status = c.Status
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ func TestFinalizeNamespaceFunc(t *testing.T) {
|
|||
},
|
||||
}
|
||||
d := namespacedResourcesDeleter{
|
||||
nsClient: mockClient.Core().Namespaces(),
|
||||
nsClient: mockClient.CoreV1().Namespaces(),
|
||||
finalizerToken: v1.FinalizerKubernetes,
|
||||
}
|
||||
d.finalizeNamespace(testNamespace)
|
||||
|
@ -180,7 +180,7 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, versions *metav1.APIVersio
|
|||
fn := func() ([]*metav1.APIResourceList, error) {
|
||||
return resources, nil
|
||||
}
|
||||
d := NewNamespacedResourcesDeleter(mockClient.Core().Namespaces(), dynamicClient, mockClient.Core(), fn, v1.FinalizerKubernetes, true)
|
||||
d := NewNamespacedResourcesDeleter(mockClient.CoreV1().Namespaces(), dynamicClient, mockClient.CoreV1(), fn, v1.FinalizerKubernetes, true)
|
||||
if err := d.Delete(testInput.testNamespace.Name); err != nil {
|
||||
t.Errorf("scenario %s - Unexpected error when synching namespace %v", scenario, err)
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ func TestRetryOnConflictError(t *testing.T) {
|
|||
}
|
||||
namespace := &v1.Namespace{}
|
||||
d := namespacedResourcesDeleter{
|
||||
nsClient: mockClient.Core().Namespaces(),
|
||||
nsClient: mockClient.CoreV1().Namespaces(),
|
||||
}
|
||||
_, err := d.retryOnConflictError(namespace, retryOnce)
|
||||
if err != nil {
|
||||
|
@ -255,7 +255,7 @@ func TestSyncNamespaceThatIsActive(t *testing.T) {
|
|||
fn := func() ([]*metav1.APIResourceList, error) {
|
||||
return testResources(), nil
|
||||
}
|
||||
d := NewNamespacedResourcesDeleter(mockClient.Core().Namespaces(), nil, mockClient.Core(),
|
||||
d := NewNamespacedResourcesDeleter(mockClient.CoreV1().Namespaces(), nil, mockClient.CoreV1(),
|
||||
fn, v1.FinalizerKubernetes, true)
|
||||
err := d.Delete(testNamespace.Name)
|
||||
if err != nil {
|
||||
|
|
|
@ -42,7 +42,6 @@ go_library(
|
|||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/controller/nodeipam/ipam",
|
||||
deps = [
|
||||
"//pkg/api/v1/node:go_default_library",
|
||||
"//pkg/cloudprovider/providers/gce:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/nodeipam/ipam/cidrset:go_default_library",
|
||||
|
|
|
@ -39,7 +39,6 @@ import (
|
|||
"k8s.io/client-go/kubernetes/scheme"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
v1node "k8s.io/kubernetes/pkg/api/v1/node"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
nodeutil "k8s.io/kubernetes/pkg/controller/util/node"
|
||||
|
@ -118,7 +117,7 @@ func NewCloudCIDRAllocator(client clientset.Interface, cloud cloudprovider.Inter
|
|||
// Even if PodCIDR is assigned, but NetworkUnavailable condition is
|
||||
// set to true, we need to process the node to set the condition.
|
||||
networkUnavailableTaint := &v1.Taint{Key: schedulerapi.TaintNodeNetworkUnavailable, Effect: v1.TaintEffectNoSchedule}
|
||||
_, cond := v1node.GetNodeCondition(&newNode.Status, v1.NodeNetworkUnavailable)
|
||||
_, cond := nodeutil.GetNodeCondition(&newNode.Status, v1.NodeNetworkUnavailable)
|
||||
if cond == nil || cond.Status != v1.ConditionFalse || utiltaints.TaintExists(newNode.Spec.Taints, networkUnavailableTaint) {
|
||||
return ca.AllocateOrOccupyCIDR(newNode)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ go_library(
|
|||
importpath = "k8s.io/kubernetes/pkg/controller/nodelifecycle",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/api/v1/node:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/nodelifecycle/scheduler:go_default_library",
|
||||
"//pkg/controller/util/node:go_default_library",
|
||||
|
|
|
@ -52,7 +52,6 @@ import (
|
|||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
v1node "k8s.io/kubernetes/pkg/api/v1/node"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/controller/nodelifecycle/scheduler"
|
||||
nodeutil "k8s.io/kubernetes/pkg/controller/util/node"
|
||||
|
@ -525,7 +524,7 @@ func (nc *Controller) doNoExecuteTaintingPass() {
|
|||
// retry in 50 millisecond
|
||||
return false, 50 * time.Millisecond
|
||||
}
|
||||
_, condition := v1node.GetNodeCondition(&node.Status, v1.NodeReady)
|
||||
_, condition := nodeutil.GetNodeCondition(&node.Status, v1.NodeReady)
|
||||
// Because we want to mimic NodeStatus.Condition["Ready"] we make "unreachable" and "not ready" taints mutually exclusive.
|
||||
taintToAdd := v1.Taint{}
|
||||
oppositeTaint := v1.Taint{}
|
||||
|
@ -742,7 +741,7 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
|
|||
var err error
|
||||
var gracePeriod time.Duration
|
||||
var observedReadyCondition v1.NodeCondition
|
||||
_, currentReadyCondition := v1node.GetNodeCondition(&node.Status, v1.NodeReady)
|
||||
_, currentReadyCondition := nodeutil.GetNodeCondition(&node.Status, v1.NodeReady)
|
||||
if currentReadyCondition == nil {
|
||||
// If ready condition is nil, then kubelet (or nodecontroller) never posted node status.
|
||||
// A fake ready condition is created, where LastHeartbeatTime and LastTransitionTime is set
|
||||
|
@ -787,10 +786,10 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
|
|||
var savedCondition *v1.NodeCondition
|
||||
var savedLease *coordv1beta1.Lease
|
||||
if found {
|
||||
_, savedCondition = v1node.GetNodeCondition(savedNodeHealth.status, v1.NodeReady)
|
||||
_, savedCondition = nodeutil.GetNodeCondition(savedNodeHealth.status, v1.NodeReady)
|
||||
savedLease = savedNodeHealth.lease
|
||||
}
|
||||
_, observedCondition := v1node.GetNodeCondition(&node.Status, v1.NodeReady)
|
||||
_, observedCondition := nodeutil.GetNodeCondition(&node.Status, v1.NodeReady)
|
||||
if !found {
|
||||
klog.Warningf("Missing timestamp for Node %s. Assuming now as a timestamp.", node.Name)
|
||||
savedNodeHealth = &nodeHealthData{
|
||||
|
@ -885,7 +884,7 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
|
|||
|
||||
nowTimestamp := nc.now()
|
||||
for _, nodeConditionType := range remainingNodeConditionTypes {
|
||||
_, currentCondition := v1node.GetNodeCondition(&node.Status, nodeConditionType)
|
||||
_, currentCondition := nodeutil.GetNodeCondition(&node.Status, nodeConditionType)
|
||||
if currentCondition == nil {
|
||||
klog.V(2).Infof("Condition %v of node %v was never updated by kubelet", nodeConditionType, node.Name)
|
||||
node.Status.Conditions = append(node.Status.Conditions, v1.NodeCondition{
|
||||
|
@ -908,7 +907,7 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
|
|||
}
|
||||
}
|
||||
|
||||
_, currentCondition := v1node.GetNodeCondition(&node.Status, v1.NodeReady)
|
||||
_, currentCondition := nodeutil.GetNodeCondition(&node.Status, v1.NodeReady)
|
||||
if !apiequality.Semantic.DeepEqual(currentCondition, &observedReadyCondition) {
|
||||
if _, err = nc.kubeClient.CoreV1().Nodes().UpdateStatus(node); err != nil {
|
||||
klog.Errorf("Error updating node %s: %v", node.Name, err)
|
||||
|
|
|
@ -665,9 +665,9 @@ func (tc *testCase) setupController(t *testing.T) (*HorizontalController, inform
|
|||
defaultDownscalestabilizationWindow := 5 * time.Minute
|
||||
|
||||
hpaController := NewHorizontalController(
|
||||
eventClient.Core(),
|
||||
eventClient.CoreV1(),
|
||||
testScaleClient,
|
||||
testClient.Autoscaling(),
|
||||
testClient.AutoscalingV1(),
|
||||
testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Scheme),
|
||||
metricsClient,
|
||||
informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(),
|
||||
|
|
|
@ -494,9 +494,9 @@ func (tc *legacyTestCase) runTest(t *testing.T) {
|
|||
defaultDownscaleStabilisationWindow := 5 * time.Minute
|
||||
|
||||
hpaController := NewHorizontalController(
|
||||
eventClient.Core(),
|
||||
eventClient.CoreV1(),
|
||||
testScaleClient,
|
||||
testClient.Autoscaling(),
|
||||
testClient.AutoscalingV1(),
|
||||
testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Scheme),
|
||||
metricsClient,
|
||||
informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(),
|
||||
|
|
|
@ -672,7 +672,7 @@ func TestControllerUpdateStatusWithFailure(t *testing.T) {
|
|||
fakeClient.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
|
||||
return true, &apps.ReplicaSet{}, fmt.Errorf("Fake error")
|
||||
})
|
||||
fakeRSClient := fakeClient.Apps().ReplicaSets("default")
|
||||
fakeRSClient := fakeClient.AppsV1().ReplicaSets("default")
|
||||
numReplicas := int32(10)
|
||||
newStatus := apps.ReplicaSetStatus{Replicas: numReplicas}
|
||||
updateReplicaSetStatus(fakeRSClient, rs, newStatus)
|
||||
|
|
|
@ -14,8 +14,8 @@ go_library(
|
|||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/controller/route",
|
||||
deps = [
|
||||
"//pkg/api/v1/node:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/util/node:go_default_library",
|
||||
"//pkg/util/metrics:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
|
@ -42,9 +42,9 @@ go_test(
|
|||
srcs = ["route_controller_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/api/v1/node:go_default_library",
|
||||
"//pkg/cloudprovider/providers/fake:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/util/node:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
|
|
|
@ -40,10 +40,10 @@ import (
|
|||
"k8s.io/client-go/tools/record"
|
||||
clientretry "k8s.io/client-go/util/retry"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
v1node "k8s.io/kubernetes/pkg/api/v1/node"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
nodeutil "k8s.io/kubernetes/pkg/controller/util/node"
|
||||
"k8s.io/kubernetes/pkg/util/metrics"
|
||||
nodeutil "k8s.io/kubernetes/pkg/util/node"
|
||||
utilnode "k8s.io/kubernetes/pkg/util/node"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -201,7 +201,7 @@ func (rc *RouteController) reconcile(nodes []*v1.Node, routes []*cloudprovider.R
|
|||
}(nodeName, nameHint, route)
|
||||
} else {
|
||||
// Update condition only if it doesn't reflect the current state.
|
||||
_, condition := v1node.GetNodeCondition(&node.Status, v1.NodeNetworkUnavailable)
|
||||
_, condition := nodeutil.GetNodeCondition(&node.Status, v1.NodeNetworkUnavailable)
|
||||
if condition == nil || condition.Status != v1.ConditionFalse {
|
||||
rc.updateNetworkingCondition(types.NodeName(node.Name), true)
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ func (rc *RouteController) updateNetworkingCondition(nodeName types.NodeName, ro
|
|||
// patch in the retry loop.
|
||||
currentTime := metav1.Now()
|
||||
if routeCreated {
|
||||
err = nodeutil.SetNodeCondition(rc.kubeClient, nodeName, v1.NodeCondition{
|
||||
err = utilnode.SetNodeCondition(rc.kubeClient, nodeName, v1.NodeCondition{
|
||||
Type: v1.NodeNetworkUnavailable,
|
||||
Status: v1.ConditionFalse,
|
||||
Reason: "RouteCreated",
|
||||
|
@ -245,7 +245,7 @@ func (rc *RouteController) updateNetworkingCondition(nodeName types.NodeName, ro
|
|||
LastTransitionTime: currentTime,
|
||||
})
|
||||
} else {
|
||||
err = nodeutil.SetNodeCondition(rc.kubeClient, nodeName, v1.NodeCondition{
|
||||
err = utilnode.SetNodeCondition(rc.kubeClient, nodeName, v1.NodeCondition{
|
||||
Type: v1.NodeNetworkUnavailable,
|
||||
Status: v1.ConditionTrue,
|
||||
Reason: "NoRouteCreated",
|
||||
|
|
|
@ -29,9 +29,9 @@ import (
|
|||
"k8s.io/client-go/kubernetes/fake"
|
||||
core "k8s.io/client-go/testing"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
nodeutil "k8s.io/kubernetes/pkg/api/v1/node"
|
||||
fakecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/fake"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
nodeutil "k8s.io/kubernetes/pkg/controller/util/node"
|
||||
)
|
||||
|
||||
func alwaysReady() bool { return true }
|
||||
|
|
|
@ -96,7 +96,7 @@ func (m *FakeNodeHandler) GetUpdatedNodesCopy() []*v1.Node {
|
|||
|
||||
// Core returns fake CoreInterface.
|
||||
func (m *FakeNodeHandler) Core() v1core.CoreV1Interface {
|
||||
return &FakeLegacyHandler{m.Clientset.Core(), m}
|
||||
return &FakeLegacyHandler{m.Clientset.CoreV1(), m}
|
||||
}
|
||||
|
||||
// CoreV1 returns fake CoreV1Interface
|
||||
|
|
|
@ -260,3 +260,17 @@ func CreateDeleteNodeHandler(f func(node *v1.Node) error) func(obj interface{})
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetNodeCondition extracts the provided condition from the given status and returns that.
|
||||
// Returns nil and -1 if the condition is not present, and the index of the located condition.
|
||||
func GetNodeCondition(status *v1.NodeStatus, conditionType v1.NodeConditionType) (int, *v1.NodeCondition) {
|
||||
if status == nil {
|
||||
return -1, nil
|
||||
}
|
||||
for i := range status.Conditions {
|
||||
if status.Conditions[i].Type == conditionType {
|
||||
return i, &status.Conditions[i]
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2
|
|||
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
pods, err := fakeKubeClient.Core().Pods(v1.NamespaceAll).List(metav1.ListOptions{})
|
||||
pods, err := fakeKubeClient.CoreV1().Pods(v1.NamespaceAll).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Run failed with error. Expected: <no error> Actual: %v", err)
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2
|
|||
podInformer.GetIndexer().Add(&podToAdd)
|
||||
podsNum++
|
||||
}
|
||||
nodes, err := fakeKubeClient.Core().Nodes().List(metav1.ListOptions{})
|
||||
nodes, err := fakeKubeClient.CoreV1().Nodes().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Run failed with error. Expected: <no error> Actual: %v", err)
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ func (o AnnotateOptions) Validate() error {
|
|||
if o.all && len(o.fieldSelector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --field-selector at the same time")
|
||||
}
|
||||
if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames) {
|
||||
if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
|
||||
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
||||
}
|
||||
if len(o.newAnnotations) < 1 && len(o.removeAnnotations) < 1 {
|
||||
|
|
|
@ -115,6 +115,9 @@ var (
|
|||
# Apply the configuration in pod.json to a pod.
|
||||
kubectl apply -f ./pod.json
|
||||
|
||||
# Apply resources from a directory containing kustomization.yaml - e.g. dir/kustomization.yaml.
|
||||
kubectl apply -k dir/
|
||||
|
||||
# Apply the JSON passed into stdin to a pod.
|
||||
cat pod.json | kubectl apply -f -
|
||||
|
||||
|
@ -152,7 +155,7 @@ func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions
|
|||
o.cmdBaseName = baseName
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "apply -f FILENAME",
|
||||
Use: "apply (-f FILENAME | -k DIRECTORY)",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Apply a configuration to a resource by filename or stdin"),
|
||||
Long: applyLong,
|
||||
|
@ -170,7 +173,6 @@ func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions
|
|||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmd.Flags().BoolVar(&o.Overwrite, "overwrite", o.Overwrite, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
|
||||
cmd.Flags().BoolVar(&o.Prune, "prune", o.Prune, "Automatically delete resource objects, including the uninitialized ones, that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
|
@ -237,6 +239,10 @@ func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||
return err
|
||||
}
|
||||
o.DeleteOptions = o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
|
||||
err = o.DeleteOptions.FilenameOptions.RequireFilenameOrKustomize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.OpenAPISchema, _ = f.OpenAPISchema()
|
||||
o.Validator, err = f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
|
|
|
@ -107,13 +107,16 @@ func NewCmdReconcile(f cmdutil.Factory, streams genericclioptions.IOStreams) *co
|
|||
cmd.Flags().BoolVar(&o.DryRun, "dry-run", o.DryRun, "If true, display results but do not submit changes")
|
||||
cmd.Flags().BoolVar(&o.RemoveExtraPermissions, "remove-extra-permissions", o.RemoveExtraPermissions, "If true, removes extra permissions added to roles")
|
||||
cmd.Flags().BoolVar(&o.RemoveExtraSubjects, "remove-extra-subjects", o.RemoveExtraSubjects, "If true, removes extra subjects added to rolebindings")
|
||||
cmd.MarkFlagRequired("filename")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Complete completes all the required options
|
||||
func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string) error {
|
||||
if err := o.FilenameOptions.RequireFilenameOrKustomize(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
return errors.New("no arguments are allowed")
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ go_library(
|
|||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/generate:go_default_library",
|
||||
"//pkg/kubectl/generate/versioned:go_default_library",
|
||||
"//pkg/kubectl/polymorphichelpers:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//pkg/kubectl/util/i18n:go_default_library",
|
||||
"//pkg/kubectl/util/templates:go_default_library",
|
||||
|
@ -20,6 +19,7 @@ go_library(
|
|||
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
|
||||
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/typed/autoscaling/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/scale:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
|
|
|
@ -28,11 +28,11 @@ import (
|
|||
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
|
||||
autoscalingv1client "k8s.io/client-go/kubernetes/typed/autoscaling/v1"
|
||||
"k8s.io/client-go/scale"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/generate"
|
||||
generateversioned "k8s.io/kubernetes/pkg/kubectl/generate/versioned"
|
||||
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/templates"
|
||||
|
@ -74,10 +74,10 @@ type AutoscaleOptions struct {
|
|||
namespace string
|
||||
dryRun bool
|
||||
builder *resource.Builder
|
||||
canBeAutoscaled polymorphichelpers.CanBeAutoscaledFunc
|
||||
generatorFunc func(string, *meta.RESTMapping) (generate.StructuredGenerator, error)
|
||||
|
||||
HPAClient autoscalingv1client.HorizontalPodAutoscalersGetter
|
||||
HPAClient autoscalingv1client.HorizontalPodAutoscalersGetter
|
||||
scaleKindResolver scale.ScaleKindResolver
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
@ -133,7 +133,11 @@ func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
|
|||
o.dryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
o.builder = f.NewBuilder()
|
||||
o.canBeAutoscaled = polymorphichelpers.CanBeAutoscaledFn
|
||||
discoveryClient, err := f.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.scaleKindResolver = scale.NewDiscoveryScaleKindResolver(discoveryClient)
|
||||
o.args = args
|
||||
o.RecordFlags.Complete(cmd)
|
||||
|
||||
|
@ -196,7 +200,7 @@ func (o *AutoscaleOptions) Validate() error {
|
|||
|
||||
func (o *AutoscaleOptions) Run() error {
|
||||
r := o.builder.
|
||||
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
|
||||
Unstructured().
|
||||
ContinueOnError().
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, o.FilenameOptions).
|
||||
|
@ -214,8 +218,9 @@ func (o *AutoscaleOptions) Run() error {
|
|||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
if err := o.canBeAutoscaled(mapping.GroupVersionKind.GroupKind()); err != nil {
|
||||
return err
|
||||
gvr := mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource.Resource)
|
||||
if _, err := o.scaleKindResolver.ScaleForResource(gvr); err != nil {
|
||||
return fmt.Errorf("cannot autoscale a %v: %v", mapping.GroupVersionKind.Kind, err)
|
||||
}
|
||||
|
||||
generator, err := o.generatorFunc(info.Name, mapping)
|
||||
|
|
|
@ -104,7 +104,7 @@ func (o *CertificateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
|
|||
}
|
||||
|
||||
func (o *CertificateOptions) Validate() error {
|
||||
if len(o.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames) {
|
||||
if len(o.csrNames) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
|
||||
return fmt.Errorf("one or more CSRs must be specified as <name> or -f <filename>")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -107,12 +107,15 @@ func NewCmdConvert(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *co
|
|||
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "to need to get converted.")
|
||||
cmd.MarkFlagRequired("filename")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Complete collects information required to run Convert command from command line.
|
||||
func (o *ConvertOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) (err error) {
|
||||
err = o.FilenameOptions.RequireFilenameOrKustomize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.builder = f.NewBuilder
|
||||
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
|
|
|
@ -499,7 +499,7 @@ func (o *CopyOptions) execute(options *exec.ExecOptions) error {
|
|||
}
|
||||
|
||||
options.Config = o.ClientConfig
|
||||
options.PodClient = o.Clientset.Core()
|
||||
options.PodClient = o.Clientset.CoreV1()
|
||||
|
||||
if err := options.Validate(); err != nil {
|
||||
return err
|
||||
|
|
|
@ -103,7 +103,8 @@ func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cob
|
|||
Long: createLong,
|
||||
Example: createExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
|
||||
if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
|
||||
ioStreams.ErrOut.Write([]byte("Error: must specify one of -f and -k\n\n"))
|
||||
defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut)
|
||||
defaultRunFunc(cmd, args)
|
||||
return
|
||||
|
@ -119,7 +120,6 @@ func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cob
|
|||
|
||||
usage := "to use to create the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmd.Flags().BoolVar(&o.EditBeforeCreate, "edit", o.EditBeforeCreate, "Edit the API resource before creating")
|
||||
cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows",
|
||||
|
@ -184,7 +184,6 @@ func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error {
|
|||
// Complete completes all the required options
|
||||
func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
|
|
|
@ -71,6 +71,9 @@ var (
|
|||
# Delete a pod using the type and name specified in pod.json.
|
||||
kubectl delete -f ./pod.json
|
||||
|
||||
# Delete resources from a directory containing kustomization.yaml - e.g. dir/kustomization.yaml.
|
||||
kubectl delete -k dir
|
||||
|
||||
# Delete a pod based on the type and name in the JSON passed into stdin.
|
||||
cat pod.json | kubectl delete -f -
|
||||
|
||||
|
@ -102,6 +105,7 @@ type DeleteOptions struct {
|
|||
DeleteNow bool
|
||||
ForceDeletion bool
|
||||
WaitForDeletion bool
|
||||
Quiet bool
|
||||
|
||||
GracePeriod int
|
||||
Timeout time.Duration
|
||||
|
@ -119,7 +123,7 @@ func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra
|
|||
deleteFlags := NewDeleteCommandFlags("containing the resource to delete.")
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
|
||||
Use: "delete ([-f FILENAME] | [-k DIRECTORY] | TYPE [(NAME | -l label | --all)])",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Delete resources by filenames, stdin, resources and names, or by resources and label selector"),
|
||||
Long: deleteLong,
|
||||
|
@ -313,7 +317,9 @@ func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav
|
|||
return nil, cmdutil.AddSourceToErr("deleting", info.Source, err)
|
||||
}
|
||||
|
||||
o.PrintObj(info)
|
||||
if !o.Quiet {
|
||||
o.PrintObj(info)
|
||||
}
|
||||
return deleteResponse, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -156,9 +156,11 @@ func NewDeleteCommandFlags(usage string) *DeleteFlags {
|
|||
|
||||
filenames := []string{}
|
||||
recursive := false
|
||||
kustomize := ""
|
||||
|
||||
return &DeleteFlags{
|
||||
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Recursive: &recursive},
|
||||
// Not using helpers.go since it provides function to add '-k' for FileNameOptions, but not FileNameFlags
|
||||
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Kustomize: &kustomize, Recursive: &recursive},
|
||||
LabelSelector: &labelSelector,
|
||||
FieldSelector: &fieldSelector,
|
||||
|
||||
|
@ -186,10 +188,11 @@ func NewDeleteFlags(usage string) *DeleteFlags {
|
|||
wait := false
|
||||
|
||||
filenames := []string{}
|
||||
kustomize := ""
|
||||
recursive := false
|
||||
|
||||
return &DeleteFlags{
|
||||
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Recursive: &recursive},
|
||||
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Kustomize: &kustomize, Recursive: &recursive},
|
||||
|
||||
Cascade: &cascade,
|
||||
GracePeriod: &gracePeriod,
|
||||
|
|
|
@ -131,7 +131,7 @@ func (o *DescribeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
|
|||
o.EnforceNamespace = false
|
||||
}
|
||||
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
|
||||
return fmt.Errorf("You must specify the type of resource to describe. %s\n", cmdutil.SuggestAPIResources(o.CmdParent))
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,6 @@ func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
|
|||
usage := "contains the configuration to diff"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmdutil.AddServerSideApplyFlags(cmd)
|
||||
cmd.MarkFlagRequired("filename")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -395,6 +394,11 @@ func isConflict(err error) bool {
|
|||
func (o *DiffOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
|
||||
err = o.FilenameOptions.RequireFilenameOrKustomize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.ServerSideApply = cmdutil.GetServerSideApplyFlag(cmd)
|
||||
o.ForceConflicts = cmdutil.GetForceConflictsFlag(cmd)
|
||||
if o.ForceConflicts && !o.ServerSideApply {
|
||||
|
|
|
@ -115,6 +115,9 @@ var (
|
|||
# List a pod identified by type and name specified in "pod.yaml" in JSON output format.
|
||||
kubectl get -f pod.yaml -o json
|
||||
|
||||
# List resources from a directory with kustomization.yaml - e.g. dir/kustomization.yaml.
|
||||
kubectl get -k dir/
|
||||
|
||||
# Return only the phase value of the specified pod.
|
||||
kubectl get -o template pod/web-pod-13je7 --template={{.status.phase}}
|
||||
|
||||
|
@ -257,7 +260,7 @@ func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
|
|||
switch {
|
||||
case o.Watch || o.WatchOnly:
|
||||
default:
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.Filenames) {
|
||||
if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
|
||||
fmt.Fprintf(o.ErrOut, "You must specify the type of resource to get. %s\n\n", cmdutil.SuggestAPIResources(o.CmdParent))
|
||||
fullCmdName := cmd.Parent().CommandPath()
|
||||
usageString := "Required resource not specified."
|
||||
|
|
|
@ -205,7 +205,7 @@ func (o *LabelOptions) Validate() error {
|
|||
if o.all && len(o.fieldSelector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --field-selector at the same time")
|
||||
}
|
||||
if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
|
||||
if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
|
||||
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
||||
}
|
||||
if len(o.newLabels) < 1 && len(o.removeLabels) < 1 && !o.list {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue