golang.sh 28 KB

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