golang.sh 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. #!/usr/bin/env bash
  2. # Copyright 2014 The Kubernetes Authors.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. # shellcheck disable=SC2034 # Variables sourced in other scripts.
  16. # The golang package that we are building.
  17. readonly KUBE_GO_PACKAGE=k8s.io/kubernetes
  18. readonly KUBE_GOPATH="${KUBE_OUTPUT}/go"
  19. # The server platform we are building on.
  20. readonly KUBE_SUPPORTED_SERVER_PLATFORMS=(
  21. linux/amd64
  22. linux/arm
  23. linux/arm64
  24. linux/s390x
  25. linux/ppc64le
  26. )
  27. # The node platforms we build for
  28. readonly KUBE_SUPPORTED_NODE_PLATFORMS=(
  29. linux/amd64
  30. linux/arm
  31. linux/arm64
  32. linux/s390x
  33. linux/ppc64le
  34. windows/amd64
  35. )
  36. # If we update this we should also update the set of platforms whose standard
  37. # library is precompiled for in build/build-image/cross/Dockerfile
  38. readonly KUBE_SUPPORTED_CLIENT_PLATFORMS=(
  39. linux/amd64
  40. linux/386
  41. linux/arm
  42. linux/arm64
  43. linux/s390x
  44. linux/ppc64le
  45. darwin/amd64
  46. darwin/386
  47. windows/amd64
  48. windows/386
  49. )
  50. # Which platforms we should compile test targets for.
  51. # Not all client platforms need these tests
  52. readonly KUBE_SUPPORTED_TEST_PLATFORMS=(
  53. linux/amd64
  54. linux/arm
  55. linux/arm64
  56. linux/s390x
  57. linux/ppc64le
  58. darwin/amd64
  59. windows/amd64
  60. )
  61. # The set of server targets that we are only building for Linux
  62. # If you update this list, please also update build/BUILD.
  63. kube::golang::server_targets() {
  64. local targets=(
  65. cmd/kube-proxy
  66. cmd/kube-apiserver
  67. cmd/kube-controller-manager
  68. cmd/kubelet
  69. cmd/kubeadm
  70. cmd/kube-scheduler
  71. vendor/k8s.io/apiextensions-apiserver
  72. cluster/gce/gci/mounter
  73. )
  74. echo "${targets[@]}"
  75. }
  76. IFS=" " read -ra KUBE_SERVER_TARGETS <<< "$(kube::golang::server_targets)"
  77. readonly KUBE_SERVER_TARGETS
  78. readonly KUBE_SERVER_BINARIES=("${KUBE_SERVER_TARGETS[@]##*/}")
  79. # The set of server targets we build docker images for
  80. kube::golang::server_image_targets() {
  81. # NOTE: this contains cmd targets for kube::build::get_docker_wrapped_binaries
  82. local targets=(
  83. cmd/kube-apiserver
  84. cmd/kube-controller-manager
  85. cmd/kube-scheduler
  86. cmd/kube-proxy
  87. )
  88. echo "${targets[@]}"
  89. }
  90. IFS=" " read -ra KUBE_SERVER_IMAGE_TARGETS <<< "$(kube::golang::server_image_targets)"
  91. readonly KUBE_SERVER_IMAGE_TARGETS
  92. readonly KUBE_SERVER_IMAGE_BINARIES=("${KUBE_SERVER_IMAGE_TARGETS[@]##*/}")
  93. # The set of conformance targets we build docker image for
  94. kube::golang::conformance_image_targets() {
  95. # NOTE: this contains cmd targets for kube::release::build_conformance_image
  96. local targets=(
  97. vendor/github.com/onsi/ginkgo/ginkgo
  98. test/e2e/e2e.test
  99. cluster/images/conformance/go-runner
  100. cmd/kubectl
  101. )
  102. echo "${targets[@]}"
  103. }
  104. IFS=" " read -ra KUBE_CONFORMANCE_IMAGE_TARGETS <<< "$(kube::golang::conformance_image_targets)"
  105. readonly KUBE_CONFORMANCE_IMAGE_TARGETS
  106. # The set of server targets that we are only building for Kubernetes nodes
  107. # If you update this list, please also update build/BUILD.
  108. kube::golang::node_targets() {
  109. local targets=(
  110. cmd/kube-proxy
  111. cmd/kubeadm
  112. cmd/kubelet
  113. )
  114. echo "${targets[@]}"
  115. }
  116. IFS=" " read -ra KUBE_NODE_TARGETS <<< "$(kube::golang::node_targets)"
  117. readonly KUBE_NODE_TARGETS
  118. readonly KUBE_NODE_BINARIES=("${KUBE_NODE_TARGETS[@]##*/}")
  119. readonly KUBE_NODE_BINARIES_WIN=("${KUBE_NODE_BINARIES[@]/%/.exe}")
  120. # ------------
  121. # NOTE: All functions that return lists should use newlines.
  122. # bash functions can't return arrays, and spaces are tricky, so newline
  123. # separators are the preferred pattern.
  124. # To transform a string of newline-separated items to an array, use kube::util::read-array:
  125. # kube::util::read-array FOO < <(kube::golang::dups a b c a)
  126. #
  127. # ALWAYS remember to quote your subshells. Not doing so will break in
  128. # bash 4.3, and potentially cause other issues.
  129. # ------------
  130. # Returns a sorted newline-separated list containing only duplicated items.
  131. kube::golang::dups() {
  132. # We use printf to insert newlines, which are required by sort.
  133. printf "%s\n" "$@" | sort | uniq -d
  134. }
  135. # Returns a sorted newline-separated list with duplicated items removed.
  136. kube::golang::dedup() {
  137. # We use printf to insert newlines, which are required by sort.
  138. printf "%s\n" "$@" | sort -u
  139. }
  140. # Depends on values of user-facing KUBE_BUILD_PLATFORMS, KUBE_FASTBUILD,
  141. # and KUBE_BUILDER_OS.
  142. # Configures KUBE_SERVER_PLATFORMS, KUBE_NODE_PLATFOMRS,
  143. # KUBE_TEST_PLATFORMS, and KUBE_CLIENT_PLATFORMS, then sets them
  144. # to readonly.
  145. # The configured vars will only contain platforms allowed by the
  146. # KUBE_SUPPORTED* vars at the top of this file.
  147. declare -a KUBE_SERVER_PLATFORMS
  148. declare -a KUBE_CLIENT_PLATFORMS
  149. declare -a KUBE_NODE_PLATFORMS
  150. declare -a KUBE_TEST_PLATFORMS
  151. kube::golang::setup_platforms() {
  152. if [[ -n "${KUBE_BUILD_PLATFORMS:-}" ]]; then
  153. # KUBE_BUILD_PLATFORMS needs to be read into an array before the next
  154. # step, or quoting treats it all as one element.
  155. local -a platforms
  156. IFS=" " read -ra platforms <<< "${KUBE_BUILD_PLATFORMS}"
  157. # Deduplicate to ensure the intersection trick with kube::golang::dups
  158. # is not defeated by duplicates in user input.
  159. kube::util::read-array platforms < <(kube::golang::dedup "${platforms[@]}")
  160. # Use kube::golang::dups to restrict the builds to the platforms in
  161. # KUBE_SUPPORTED_*_PLATFORMS. Items should only appear at most once in each
  162. # set, so if they appear twice after the merge they are in the intersection.
  163. kube::util::read-array KUBE_SERVER_PLATFORMS < <(kube::golang::dups \
  164. "${platforms[@]}" \
  165. "${KUBE_SUPPORTED_SERVER_PLATFORMS[@]}" \
  166. )
  167. readonly KUBE_SERVER_PLATFORMS
  168. kube::util::read-array KUBE_NODE_PLATFORMS < <(kube::golang::dups \
  169. "${platforms[@]}" \
  170. "${KUBE_SUPPORTED_NODE_PLATFORMS[@]}" \
  171. )
  172. readonly KUBE_NODE_PLATFORMS
  173. kube::util::read-array KUBE_TEST_PLATFORMS < <(kube::golang::dups \
  174. "${platforms[@]}" \
  175. "${KUBE_SUPPORTED_TEST_PLATFORMS[@]}" \
  176. )
  177. readonly KUBE_TEST_PLATFORMS
  178. kube::util::read-array KUBE_CLIENT_PLATFORMS < <(kube::golang::dups \
  179. "${platforms[@]}" \
  180. "${KUBE_SUPPORTED_CLIENT_PLATFORMS[@]}" \
  181. )
  182. readonly KUBE_CLIENT_PLATFORMS
  183. elif [[ "${KUBE_FASTBUILD:-}" == "true" ]]; then
  184. KUBE_SERVER_PLATFORMS=(linux/amd64)
  185. readonly KUBE_SERVER_PLATFORMS
  186. KUBE_NODE_PLATFORMS=(linux/amd64)
  187. readonly KUBE_NODE_PLATFORMS
  188. if [[ "${KUBE_BUILDER_OS:-}" == "darwin"* ]]; then
  189. KUBE_TEST_PLATFORMS=(
  190. darwin/amd64
  191. linux/amd64
  192. )
  193. readonly KUBE_TEST_PLATFORMS
  194. KUBE_CLIENT_PLATFORMS=(
  195. darwin/amd64
  196. linux/amd64
  197. )
  198. readonly KUBE_CLIENT_PLATFORMS
  199. else
  200. KUBE_TEST_PLATFORMS=(linux/amd64)
  201. readonly KUBE_TEST_PLATFORMS
  202. KUBE_CLIENT_PLATFORMS=(linux/amd64)
  203. readonly KUBE_CLIENT_PLATFORMS
  204. fi
  205. else
  206. KUBE_SERVER_PLATFORMS=("${KUBE_SUPPORTED_SERVER_PLATFORMS[@]}")
  207. readonly KUBE_SERVER_PLATFORMS
  208. KUBE_NODE_PLATFORMS=("${KUBE_SUPPORTED_NODE_PLATFORMS[@]}")
  209. readonly KUBE_NODE_PLATFORMS
  210. KUBE_CLIENT_PLATFORMS=("${KUBE_SUPPORTED_CLIENT_PLATFORMS[@]}")
  211. readonly KUBE_CLIENT_PLATFORMS
  212. KUBE_TEST_PLATFORMS=("${KUBE_SUPPORTED_TEST_PLATFORMS[@]}")
  213. readonly KUBE_TEST_PLATFORMS
  214. fi
  215. }
  216. kube::golang::setup_platforms
  217. # The set of client targets that we are building for all platforms
  218. # If you update this list, please also update build/BUILD.
  219. readonly KUBE_CLIENT_TARGETS=(
  220. cmd/kubectl
  221. )
  222. readonly KUBE_CLIENT_BINARIES=("${KUBE_CLIENT_TARGETS[@]##*/}")
  223. readonly KUBE_CLIENT_BINARIES_WIN=("${KUBE_CLIENT_BINARIES[@]/%/.exe}")
  224. # The set of test targets that we are building for all platforms
  225. # If you update this list, please also update build/BUILD.
  226. kube::golang::test_targets() {
  227. local targets=(
  228. cmd/gendocs
  229. cmd/genkubedocs
  230. cmd/genman
  231. cmd/genyaml
  232. cmd/genswaggertypedocs
  233. cmd/linkcheck
  234. vendor/github.com/onsi/ginkgo/ginkgo
  235. test/e2e/e2e.test
  236. cluster/images/conformance/go-runner
  237. )
  238. echo "${targets[@]}"
  239. }
  240. IFS=" " read -ra KUBE_TEST_TARGETS <<< "$(kube::golang::test_targets)"
  241. readonly KUBE_TEST_TARGETS
  242. readonly KUBE_TEST_BINARIES=("${KUBE_TEST_TARGETS[@]##*/}")
  243. readonly KUBE_TEST_BINARIES_WIN=("${KUBE_TEST_BINARIES[@]/%/.exe}")
  244. # If you update this list, please also update build/BUILD.
  245. readonly KUBE_TEST_PORTABLE=(
  246. test/e2e/testing-manifests
  247. test/kubemark
  248. hack/e2e-internal
  249. hack/get-build.sh
  250. hack/ginkgo-e2e.sh
  251. hack/lib
  252. )
  253. # Test targets which run on the Kubernetes clusters directly, so we only
  254. # need to target server platforms.
  255. # These binaries will be distributed in the kubernetes-test tarball.
  256. # If you update this list, please also update build/BUILD.
  257. kube::golang::server_test_targets() {
  258. local targets=(
  259. cmd/kubemark
  260. vendor/github.com/onsi/ginkgo/ginkgo
  261. )
  262. if [[ "${OSTYPE:-}" == "linux"* ]]; then
  263. targets+=( test/e2e_node/e2e_node.test )
  264. fi
  265. echo "${targets[@]}"
  266. }
  267. IFS=" " read -ra KUBE_TEST_SERVER_TARGETS <<< "$(kube::golang::server_test_targets)"
  268. readonly KUBE_TEST_SERVER_TARGETS
  269. readonly KUBE_TEST_SERVER_BINARIES=("${KUBE_TEST_SERVER_TARGETS[@]##*/}")
  270. readonly KUBE_TEST_SERVER_PLATFORMS=("${KUBE_SERVER_PLATFORMS[@]:+"${KUBE_SERVER_PLATFORMS[@]}"}")
  271. # Gigabytes necessary for parallel platform builds.
  272. # As of January 2018, RAM usage is exceeding 30G
  273. # Setting to 40 to provide some headroom
  274. readonly KUBE_PARALLEL_BUILD_MEMORY=40
  275. readonly KUBE_ALL_TARGETS=(
  276. "${KUBE_SERVER_TARGETS[@]}"
  277. "${KUBE_CLIENT_TARGETS[@]}"
  278. "${KUBE_TEST_TARGETS[@]}"
  279. "${KUBE_TEST_SERVER_TARGETS[@]}"
  280. )
  281. readonly KUBE_ALL_BINARIES=("${KUBE_ALL_TARGETS[@]##*/}")
  282. readonly KUBE_STATIC_LIBRARIES=(
  283. kube-apiserver
  284. kube-controller-manager
  285. kube-scheduler
  286. kube-proxy
  287. kubeadm
  288. kubectl
  289. )
  290. # Fully-qualified package names that we want to instrument for coverage information.
  291. readonly KUBE_COVERAGE_INSTRUMENTED_PACKAGES=(
  292. k8s.io/kubernetes/cmd/kube-apiserver
  293. k8s.io/kubernetes/cmd/kube-controller-manager
  294. k8s.io/kubernetes/cmd/kube-scheduler
  295. k8s.io/kubernetes/cmd/kube-proxy
  296. k8s.io/kubernetes/cmd/kubelet
  297. )
  298. # KUBE_CGO_OVERRIDES is a space-separated list of binaries which should be built
  299. # with CGO enabled, assuming CGO is supported on the target platform.
  300. # This overrides any entry in KUBE_STATIC_LIBRARIES.
  301. IFS=" " read -ra KUBE_CGO_OVERRIDES <<< "${KUBE_CGO_OVERRIDES:-}"
  302. readonly KUBE_CGO_OVERRIDES
  303. # KUBE_STATIC_OVERRIDES is a space-separated list of binaries which should be
  304. # built with CGO disabled. This is in addition to the list in
  305. # KUBE_STATIC_LIBRARIES.
  306. IFS=" " read -ra KUBE_STATIC_OVERRIDES <<< "${KUBE_STATIC_OVERRIDES:-}"
  307. readonly KUBE_STATIC_OVERRIDES
  308. kube::golang::is_statically_linked_library() {
  309. local e
  310. # Explicitly enable cgo when building kubectl for darwin from darwin.
  311. [[ "$(go env GOHOSTOS)" == "darwin" && "$(go env GOOS)" == "darwin" &&
  312. "$1" == *"/kubectl" ]] && return 1
  313. if [[ -n "${KUBE_CGO_OVERRIDES:+x}" ]]; then
  314. for e in "${KUBE_CGO_OVERRIDES[@]}"; do [[ "${1}" == *"/${e}" ]] && return 1; done;
  315. fi
  316. for e in "${KUBE_STATIC_LIBRARIES[@]}"; do [[ "${1}" == *"/${e}" ]] && return 0; done;
  317. if [[ -n "${KUBE_STATIC_OVERRIDES:+x}" ]]; then
  318. for e in "${KUBE_STATIC_OVERRIDES[@]}"; do [[ "${1}" == *"/${e}" ]] && return 0; done;
  319. fi
  320. return 1;
  321. }
  322. # kube::binaries_from_targets take a list of build targets and return the
  323. # full go package to be built
  324. kube::golang::binaries_from_targets() {
  325. local target
  326. for target; do
  327. # If the target starts with what looks like a domain name, assume it has a
  328. # fully-qualified package name rather than one that needs the Kubernetes
  329. # package prepended.
  330. if [[ "${target}" =~ ^([[:alnum:]]+".")+[[:alnum:]]+"/" ]]; then
  331. echo "${target}"
  332. else
  333. echo "${KUBE_GO_PACKAGE}/${target}"
  334. fi
  335. done
  336. }
  337. # Asks golang what it thinks the host platform is. The go tool chain does some
  338. # slightly different things when the target platform matches the host platform.
  339. kube::golang::host_platform() {
  340. echo "$(go env GOHOSTOS)/$(go env GOHOSTARCH)"
  341. }
  342. # Takes the platform name ($1) and sets the appropriate golang env variables
  343. # for that platform.
  344. kube::golang::set_platform_envs() {
  345. [[ -n ${1-} ]] || {
  346. kube::log::error_exit "!!! Internal error. No platform set in kube::golang::set_platform_envs"
  347. }
  348. export GOOS=${platform%/*}
  349. export GOARCH=${platform##*/}
  350. # Do not set CC when building natively on a platform, only if cross-compiling from linux/amd64
  351. if [[ $(kube::golang::host_platform) == "linux/amd64" ]]; then
  352. # Dynamic CGO linking for other server architectures than linux/amd64 goes here
  353. # If you want to include support for more server platforms than these, add arch-specific gcc names here
  354. case "${platform}" in
  355. "linux/arm")
  356. export CGO_ENABLED=1
  357. export CC=arm-linux-gnueabihf-gcc
  358. ;;
  359. "linux/arm64")
  360. export CGO_ENABLED=1
  361. export CC=aarch64-linux-gnu-gcc
  362. ;;
  363. "linux/ppc64le")
  364. export CGO_ENABLED=1
  365. export CC=powerpc64le-linux-gnu-gcc
  366. ;;
  367. "linux/s390x")
  368. export CGO_ENABLED=1
  369. export CC=s390x-linux-gnu-gcc
  370. ;;
  371. esac
  372. fi
  373. }
  374. kube::golang::unset_platform_envs() {
  375. unset GOOS
  376. unset GOARCH
  377. unset GOROOT
  378. unset CGO_ENABLED
  379. unset CC
  380. }
  381. # Create the GOPATH tree under $KUBE_OUTPUT
  382. kube::golang::create_gopath_tree() {
  383. local go_pkg_dir="${KUBE_GOPATH}/src/${KUBE_GO_PACKAGE}"
  384. local go_pkg_basedir
  385. go_pkg_basedir=$(dirname "${go_pkg_dir}")
  386. mkdir -p "${go_pkg_basedir}"
  387. # TODO: This symlink should be relative.
  388. if [[ ! -e "${go_pkg_dir}" || "$(readlink "${go_pkg_dir}")" != "${KUBE_ROOT}" ]]; then
  389. ln -snf "${KUBE_ROOT}" "${go_pkg_dir}"
  390. fi
  391. # Using bazel with a recursive target (e.g. bazel test ...) will abort due to
  392. # the symlink loop created in this function, so create this special file which
  393. # tells bazel not to follow the symlink.
  394. touch "${go_pkg_basedir}/DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN"
  395. # Additionally, the //:package-srcs glob recursively includes all
  396. # subdirectories, and similarly fails due to the symlink loop. By creating a
  397. # BUILD.bazel file, we effectively create a dummy package, which stops the
  398. # glob from descending further into the tree and hitting the loop.
  399. cat >"${KUBE_GOPATH}/BUILD.bazel" <<EOF
  400. # This dummy BUILD file prevents Bazel from trying to descend through the
  401. # infinite loop created by the symlink at
  402. # ${go_pkg_dir}
  403. EOF
  404. }
  405. # Ensure the go tool exists and is a viable version.
  406. kube::golang::verify_go_version() {
  407. if [[ -z "$(command -v go)" ]]; then
  408. kube::log::usage_from_stdin <<EOF
  409. Can't find 'go' in PATH, please fix and retry.
  410. See http://golang.org/doc/install for installation instructions.
  411. EOF
  412. return 2
  413. fi
  414. local go_version
  415. IFS=" " read -ra go_version <<< "$(go version)"
  416. local minimum_go_version
  417. minimum_go_version=go1.13.4
  418. if [[ "${minimum_go_version}" != $(echo -e "${minimum_go_version}\n${go_version[2]}" | sort -s -t. -k 1,1 -k 2,2n -k 3,3n | head -n1) && "${go_version[2]}" != "devel" ]]; then
  419. kube::log::usage_from_stdin <<EOF
  420. Detected go version: ${go_version[*]}.
  421. Kubernetes requires ${minimum_go_version} or greater.
  422. Please install ${minimum_go_version} or later.
  423. EOF
  424. return 2
  425. fi
  426. }
  427. # kube::golang::setup_env will check that the `go` commands is available in
  428. # ${PATH}. It will also check that the Go version is good enough for the
  429. # Kubernetes build.
  430. #
  431. # Inputs:
  432. # KUBE_EXTRA_GOPATH - If set, this is included in created GOPATH
  433. #
  434. # Outputs:
  435. # env-var GOPATH points to our local output dir
  436. # env-var GOBIN is unset (we want binaries in a predictable place)
  437. # env-var GO15VENDOREXPERIMENT=1
  438. # current directory is within GOPATH
  439. kube::golang::setup_env() {
  440. kube::golang::verify_go_version
  441. kube::golang::create_gopath_tree
  442. export GOPATH="${KUBE_GOPATH}"
  443. export GOCACHE="${KUBE_GOPATH}/cache"
  444. # Append KUBE_EXTRA_GOPATH to the GOPATH if it is defined.
  445. if [[ -n ${KUBE_EXTRA_GOPATH:-} ]]; then
  446. GOPATH="${GOPATH}:${KUBE_EXTRA_GOPATH}"
  447. fi
  448. # Make sure our own Go binaries are in PATH.
  449. export PATH="${KUBE_GOPATH}/bin:${PATH}"
  450. # Change directories so that we are within the GOPATH. Some tools get really
  451. # upset if this is not true. We use a whole fake GOPATH here to collect the
  452. # resultant binaries. Go will not let us use GOBIN with `go install` and
  453. # cross-compiling, and `go install -o <file>` only works for a single pkg.
  454. local subdir
  455. subdir=$(kube::realpath . | sed "s|${KUBE_ROOT}||")
  456. cd "${KUBE_GOPATH}/src/${KUBE_GO_PACKAGE}/${subdir}" || return 1
  457. # Set GOROOT so binaries that parse code can work properly.
  458. GOROOT=$(go env GOROOT)
  459. export GOROOT
  460. # Unset GOBIN in case it already exists in the current session.
  461. unset GOBIN
  462. # This seems to matter to some tools
  463. export GO15VENDOREXPERIMENT=1
  464. }
  465. # This will take binaries from $GOPATH/bin and copy them to the appropriate
  466. # place in ${KUBE_OUTPUT_BINDIR}
  467. #
  468. # Ideally this wouldn't be necessary and we could just set GOBIN to
  469. # KUBE_OUTPUT_BINDIR but that won't work in the face of cross compilation. 'go
  470. # install' will place binaries that match the host platform directly in $GOBIN
  471. # while placing cross compiled binaries into `platform_arch` subdirs. This
  472. # complicates pretty much everything else we do around packaging and such.
  473. kube::golang::place_bins() {
  474. local host_platform
  475. host_platform=$(kube::golang::host_platform)
  476. V=2 kube::log::status "Placing binaries"
  477. local platform
  478. for platform in "${KUBE_CLIENT_PLATFORMS[@]}"; do
  479. # The substitution on platform_src below will replace all slashes with
  480. # underscores. It'll transform darwin/amd64 -> darwin_amd64.
  481. local platform_src="/${platform//\//_}"
  482. if [[ "${platform}" == "${host_platform}" ]]; then
  483. platform_src=""
  484. rm -f "${THIS_PLATFORM_BIN}"
  485. ln -s "${KUBE_OUTPUT_BINPATH}/${platform}" "${THIS_PLATFORM_BIN}"
  486. fi
  487. local full_binpath_src="${KUBE_GOPATH}/bin${platform_src}"
  488. if [[ -d "${full_binpath_src}" ]]; then
  489. mkdir -p "${KUBE_OUTPUT_BINPATH}/${platform}"
  490. find "${full_binpath_src}" -maxdepth 1 -type f -exec \
  491. rsync -pc {} "${KUBE_OUTPUT_BINPATH}/${platform}" \;
  492. fi
  493. done
  494. }
  495. # Try and replicate the native binary placement of go install without
  496. # calling go install.
  497. kube::golang::outfile_for_binary() {
  498. local binary=$1
  499. local platform=$2
  500. local output_path="${KUBE_GOPATH}/bin"
  501. local bin
  502. bin=$(basename "${binary}")
  503. if [[ "${platform}" != "${host_platform}" ]]; then
  504. output_path="${output_path}/${platform//\//_}"
  505. fi
  506. if [[ ${GOOS} == "windows" ]]; then
  507. bin="${bin}.exe"
  508. fi
  509. echo "${output_path}/${bin}"
  510. }
  511. # Argument: the name of a Kubernetes package.
  512. # Returns 0 if the binary can be built with coverage, 1 otherwise.
  513. # NB: this ignores whether coverage is globally enabled or not.
  514. kube::golang::is_instrumented_package() {
  515. kube::util::array_contains "$1" "${KUBE_COVERAGE_INSTRUMENTED_PACKAGES[@]}"
  516. return $?
  517. }
  518. # Argument: the name of a Kubernetes package (e.g. k8s.io/kubernetes/cmd/kube-scheduler)
  519. # Echos the path to a dummy test used for coverage information.
  520. kube::golang::path_for_coverage_dummy_test() {
  521. local package="$1"
  522. local path="${KUBE_GOPATH}/src/${package}"
  523. local name
  524. name=$(basename "${package}")
  525. echo "${path}/zz_generated_${name}_test.go"
  526. }
  527. # Argument: the name of a Kubernetes package (e.g. k8s.io/kubernetes/cmd/kube-scheduler).
  528. # Creates a dummy unit test on disk in the source directory for the given package.
  529. # This unit test will invoke the package's standard entry point when run.
  530. kube::golang::create_coverage_dummy_test() {
  531. local package="$1"
  532. local name
  533. name="$(basename "${package}")"
  534. cat <<EOF > "$(kube::golang::path_for_coverage_dummy_test "${package}")"
  535. package main
  536. import (
  537. "testing"
  538. "k8s.io/kubernetes/pkg/util/coverage"
  539. )
  540. func TestMain(m *testing.M) {
  541. // Get coverage running
  542. coverage.InitCoverage("${name}")
  543. // Go!
  544. main()
  545. // Make sure we actually write the profiling information to disk, if we make it here.
  546. // On long-running services, or anything that calls os.Exit(), this is insufficient,
  547. // so we also flush periodically with a default period of five seconds (configurable by
  548. // the KUBE_COVERAGE_FLUSH_INTERVAL environment variable).
  549. coverage.FlushCoverage()
  550. }
  551. EOF
  552. }
  553. # Argument: the name of a Kubernetes package (e.g. k8s.io/kubernetes/cmd/kube-scheduler).
  554. # Deletes a test generated by kube::golang::create_coverage_dummy_test.
  555. # It is not an error to call this for a nonexistent test.
  556. kube::golang::delete_coverage_dummy_test() {
  557. local package="$1"
  558. rm -f "$(kube::golang::path_for_coverage_dummy_test "${package}")"
  559. }
  560. # Arguments: a list of kubernetes packages to build.
  561. # Expected variables: ${build_args} should be set to an array of Go build arguments.
  562. # In addition, ${package} and ${platform} should have been set earlier, and if
  563. # ${KUBE_BUILD_WITH_COVERAGE} is set, coverage instrumentation will be enabled.
  564. #
  565. # Invokes Go to actually build some packages. If coverage is disabled, simply invokes
  566. # go install. If coverage is enabled, builds covered binaries using go test, temporarily
  567. # producing the required unit test files and then cleaning up after itself.
  568. # Non-covered binaries are then built using go install as usual.
  569. kube::golang::build_some_binaries() {
  570. if [[ -n "${KUBE_BUILD_WITH_COVERAGE:-}" ]]; then
  571. local -a uncovered=()
  572. for package in "$@"; do
  573. if kube::golang::is_instrumented_package "${package}"; then
  574. V=2 kube::log::info "Building ${package} with coverage..."
  575. kube::golang::create_coverage_dummy_test "${package}"
  576. kube::util::trap_add "kube::golang::delete_coverage_dummy_test \"${package}\"" EXIT
  577. go test -c -o "$(kube::golang::outfile_for_binary "${package}" "${platform}")" \
  578. -covermode count \
  579. -coverpkg k8s.io/...,k8s.io/kubernetes/vendor/k8s.io/... \
  580. "${build_args[@]}" \
  581. -tags coverage \
  582. "${package}"
  583. else
  584. uncovered+=("${package}")
  585. fi
  586. done
  587. if [[ "${#uncovered[@]}" != 0 ]]; then
  588. V=2 kube::log::info "Building ${uncovered[*]} without coverage..."
  589. go install "${build_args[@]}" "${uncovered[@]}"
  590. else
  591. V=2 kube::log::info "Nothing to build without coverage."
  592. fi
  593. else
  594. V=2 kube::log::info "Coverage is disabled."
  595. go install "${build_args[@]}" "$@"
  596. fi
  597. }
  598. kube::golang::build_binaries_for_platform() {
  599. local platform=$1
  600. local -a statics=()
  601. local -a nonstatics=()
  602. local -a tests=()
  603. V=2 kube::log::info "Env for ${platform}: GOOS=${GOOS-} GOARCH=${GOARCH-} GOROOT=${GOROOT-} CGO_ENABLED=${CGO_ENABLED-} CC=${CC-}"
  604. for binary in "${binaries[@]}"; do
  605. if [[ "${binary}" =~ ".test"$ ]]; then
  606. tests+=("${binary}")
  607. elif kube::golang::is_statically_linked_library "${binary}"; then
  608. statics+=("${binary}")
  609. else
  610. nonstatics+=("${binary}")
  611. fi
  612. done
  613. local -a build_args
  614. if [[ "${#statics[@]}" != 0 ]]; then
  615. build_args=(
  616. -installsuffix static
  617. ${goflags:+"${goflags[@]}"}
  618. -gcflags "${gogcflags:-}"
  619. -asmflags "${goasmflags:-}"
  620. -ldflags "${goldflags:-}"
  621. -tags "${gotags:-}"
  622. )
  623. CGO_ENABLED=0 kube::golang::build_some_binaries "${statics[@]}"
  624. fi
  625. if [[ "${#nonstatics[@]}" != 0 ]]; then
  626. build_args=(
  627. ${goflags:+"${goflags[@]}"}
  628. -gcflags "${gogcflags:-}"
  629. -asmflags "${goasmflags:-}"
  630. -ldflags "${goldflags:-}"
  631. -tags "${gotags:-}"
  632. )
  633. kube::golang::build_some_binaries "${nonstatics[@]}"
  634. fi
  635. for test in "${tests[@]:+${tests[@]}}"; do
  636. local outfile testpkg
  637. outfile=$(kube::golang::outfile_for_binary "${test}" "${platform}")
  638. testpkg=$(dirname "${test}")
  639. mkdir -p "$(dirname "${outfile}")"
  640. go test -c \
  641. ${goflags:+"${goflags[@]}"} \
  642. -gcflags "${gogcflags:-}" \
  643. -asmflags "${goasmflags:-}" \
  644. -ldflags "${goldflags:-}" \
  645. -tags "${gotags:-}" \
  646. -o "${outfile}" \
  647. "${testpkg}"
  648. done
  649. }
  650. # Return approximate physical memory available in gigabytes.
  651. kube::golang::get_physmem() {
  652. local mem
  653. # Linux kernel version >=3.14, in kb
  654. if mem=$(grep MemAvailable /proc/meminfo | awk '{ print $2 }'); then
  655. echo $(( mem / 1048576 ))
  656. return
  657. fi
  658. # Linux, in kb
  659. if mem=$(grep MemTotal /proc/meminfo | awk '{ print $2 }'); then
  660. echo $(( mem / 1048576 ))
  661. return
  662. fi
  663. # OS X, in bytes. Note that get_physmem, as used, should only ever
  664. # run in a Linux container (because it's only used in the multiple
  665. # platform case, which is a Dockerized build), but this is provided
  666. # for completeness.
  667. if mem=$(sysctl -n hw.memsize 2>/dev/null); then
  668. echo $(( mem / 1073741824 ))
  669. return
  670. fi
  671. # If we can't infer it, just give up and assume a low memory system
  672. echo 1
  673. }
  674. # Build binaries targets specified
  675. #
  676. # Input:
  677. # $@ - targets and go flags. If no targets are set then all binaries targets
  678. # are built.
  679. # KUBE_BUILD_PLATFORMS - Incoming variable of targets to build for. If unset
  680. # then just the host architecture is built.
  681. kube::golang::build_binaries() {
  682. # Create a sub-shell so that we don't pollute the outer environment
  683. (
  684. # Check for `go` binary and set ${GOPATH}.
  685. kube::golang::setup_env
  686. V=2 kube::log::info "Go version: $(go version)"
  687. local host_platform
  688. host_platform=$(kube::golang::host_platform)
  689. local goflags goldflags goasmflags gogcflags gotags
  690. # If GOLDFLAGS is unset, then set it to the a default of "-s -w".
  691. # Disable SC2153 for this, as it will throw a warning that the local
  692. # variable goldflags will exist, and it suggest changing it to this.
  693. # shellcheck disable=SC2153
  694. goldflags="${GOLDFLAGS=-s -w} $(kube::version::ldflags)"
  695. goasmflags="-trimpath=${KUBE_ROOT}"
  696. gogcflags="${GOGCFLAGS:-} -trimpath=${KUBE_ROOT}"
  697. # extract tags if any specified in GOFLAGS
  698. # shellcheck disable=SC2001
  699. gotags="selinux,$(echo "${GOFLAGS:-}" | sed -e 's|.*-tags=\([^-]*\).*|\1|')"
  700. local -a targets=()
  701. local arg
  702. for arg; do
  703. if [[ "${arg}" == -* ]]; then
  704. # Assume arguments starting with a dash are flags to pass to go.
  705. goflags+=("${arg}")
  706. else
  707. targets+=("${arg}")
  708. fi
  709. done
  710. if [[ ${#targets[@]} -eq 0 ]]; then
  711. targets=("${KUBE_ALL_TARGETS[@]}")
  712. fi
  713. local -a platforms
  714. IFS=" " read -ra platforms <<< "${KUBE_BUILD_PLATFORMS:-}"
  715. if [[ ${#platforms[@]} -eq 0 ]]; then
  716. platforms=("${host_platform}")
  717. fi
  718. local -a binaries
  719. while IFS="" read -r binary; do binaries+=("$binary"); done < <(kube::golang::binaries_from_targets "${targets[@]}")
  720. local parallel=false
  721. if [[ ${#platforms[@]} -gt 1 ]]; then
  722. local gigs
  723. gigs=$(kube::golang::get_physmem)
  724. if [[ ${gigs} -ge ${KUBE_PARALLEL_BUILD_MEMORY} ]]; then
  725. kube::log::status "Multiple platforms requested and available ${gigs}G >= threshold ${KUBE_PARALLEL_BUILD_MEMORY}G, building platforms in parallel"
  726. parallel=true
  727. else
  728. kube::log::status "Multiple platforms requested, but available ${gigs}G < threshold ${KUBE_PARALLEL_BUILD_MEMORY}G, building platforms in serial"
  729. parallel=false
  730. fi
  731. fi
  732. if [[ "${parallel}" == "true" ]]; then
  733. kube::log::status "Building go targets for {${platforms[*]}} in parallel (output will appear in a burst when complete):" "${targets[@]}"
  734. local platform
  735. for platform in "${platforms[@]}"; do (
  736. kube::golang::set_platform_envs "${platform}"
  737. kube::log::status "${platform}: build started"
  738. kube::golang::build_binaries_for_platform "${platform}"
  739. kube::log::status "${platform}: build finished"
  740. ) &> "/tmp//${platform//\//_}.build" &
  741. done
  742. local fails=0
  743. for job in $(jobs -p); do
  744. wait "${job}" || (( fails+=1 ))
  745. done
  746. for platform in "${platforms[@]}"; do
  747. cat "/tmp//${platform//\//_}.build"
  748. done
  749. exit ${fails}
  750. else
  751. for platform in "${platforms[@]}"; do
  752. kube::log::status "Building go targets for ${platform}:" "${targets[@]}"
  753. (
  754. kube::golang::set_platform_envs "${platform}"
  755. kube::golang::build_binaries_for_platform "${platform}"
  756. )
  757. done
  758. fi
  759. )
  760. }