You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

all-in-one.sh 20 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. #!/bin/bash
  2. # Copyright 2021 The KubeEdge 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. # This script installs a all-in-one Sedna environment, including:
  16. # - A Kubernetes v1.21 cluster with multi worker nodes, default none worker node.
  17. # - KubeEdge with multi nodes, default is latest KubeEdge and one edge node.
  18. # - Sedna, default is latest release version.
  19. #
  20. # It requires you:
  21. # - 2 CPUs or more
  22. # - 2GB+ free memory, depends on node number setting
  23. # - 10GB+ free disk space
  24. # - Internet connection(docker hub, github etc.)
  25. # - Linux platform, such as ubuntu/centos
  26. # - Docker 17.06+
  27. #
  28. # Advanced options, influential env vars:
  29. #
  30. # NUM_CLOUD_WORKER_NODES| optional | The number of cloud worker nodes, default 0
  31. # NUM_EDGE_NODES | optional | The number of KubeEdge nodes, default 1
  32. # KUBEEDGE_VERSION | optional | The KubeEdge version to be installed.
  33. # if not specified, it try to get latest version or v1.8.0
  34. # SEDNA_VERSION | optional | The Sedna version to be installed.
  35. # if not specified, it will get latest release or v0.4.1
  36. # CLUSTER_NAME | optional | The all-in-one cluster name, default 'sedna-mini'
  37. # NO_INSTALL_SEDNA | optional | If 'false', install Sedna, else no install, default false.
  38. # FORCE_INSTALL_SEDNA | optional | If 'true', force reinstall Sedna, default false.
  39. # NODE_IMAGE | optional | Custom node image
  40. # REUSE_EDGE_CONTAINER | optional | Whether reuse edge node containers or not, default is true
  41. set -o errexit
  42. set -o nounset
  43. set -o pipefail
  44. DEFAULT_SEDNA_VERSION=v0.4.1
  45. DEFAULT_KUBEEDGE_VERSION=v1.8.0
  46. DEFAULT_NODE_IMAGE_VERSION=v1.21.1
  47. function prepare_env() {
  48. : ${CLUSTER_NAME:=sedna-mini}
  49. # here not use := because it ignore the error of get_latest_version command
  50. if [ -z "${KUBEEDGE_VERSION:-}" ]; then
  51. KUBEEDGE_VERSION=$(get_latest_version kubeedge/kubeedge $DEFAULT_KUBEEDGE_VERSION)
  52. fi
  53. # 1.8.0 => v1.8.0
  54. # v1.8.0 => v1.8.0
  55. KUBEEDGE_VERSION=v${KUBEEDGE_VERSION#v}
  56. if [ -z "${SEDNA_VERSION:-}" ]; then
  57. SEDNA_VERSION=$(get_latest_version kubeedge/sedna $DEFAULT_SEDNA_VERSION)
  58. fi
  59. SEDNA_VERSION=v${SEDNA_VERSION#v}
  60. : ${NUM_CLOUD_WORKER_NODES:=0}
  61. : ${NUM_EDGE_NODES:=1}
  62. : ${ALLINONE_NODE_IMAGE:=kubeedge/sedna-allinone-node:$DEFAULT_NODE_IMAGE_VERSION}
  63. readonly MAX_CLOUD_WORKER_NODES=2
  64. readonly MAX_EDGE_WORKER_NODES=3
  65. # TODO: find a better way to figure this kind control plane
  66. readonly CONTROL_PLANE_NAME=${CLUSTER_NAME}-control-plane
  67. readonly CLOUD_WORKER_NODE_NAME=${CLUSTER_NAME}-worker
  68. # cloudcore default websocket port
  69. : ${CLOUDCORE_WS_PORT:=10000}
  70. # cloudcore default cert port
  71. : ${CLOUDCORE_CERT_PORT:=10002}
  72. # for debug purpose
  73. : ${RETAIN_CONTAINER:=}
  74. # use existing edge node containers
  75. # default is true
  76. : ${REUSE_EDGE_CONTAINER:=true}
  77. # whether install sedna control plane or not
  78. # false means install, other values mean no install
  79. : ${NO_INSTALL_SEDNA:=false}
  80. # force install sedna control plane
  81. # default is false
  82. : ${FORCE_INSTALL_SEDNA:=false}
  83. # The docker network for edge nodes to separate the network of control plane.
  84. # Since `kind` CNI doesn't support edge node, here just use the network 'kind'.
  85. # TODO(llhuii): find a way to use the default docker network 'bridge'.
  86. : ${EDGE_NODE_NETWORK:=kind}
  87. validate_env
  88. }
  89. function validate_env() {
  90. ((NUM_CLOUD_WORKER_NODES<=MAX_CLOUD_WORKER_NODES)) || {
  91. log_fault "Only support NUM_CLOUD_WORKER_NODES at most $MAX_CLOUD_WORKER_NODES"
  92. }
  93. ((NUM_EDGE_NODES<=MAX_EDGE_WORKER_NODES)) || {
  94. log_fault "Only support NUM_EDGE_NODES at most $MAX_EDGE_WORKER_NODES"
  95. }
  96. }
  97. function _log() {
  98. local level=$1
  99. shift
  100. timestamp=$(date +"[$level%m%d %H:%M:%S.%3N]")
  101. echo "$timestamp $@"
  102. }
  103. function log_fault() {
  104. _log E "$@" >&2
  105. exit 2
  106. }
  107. function log_error() {
  108. _log E "$@" >&2
  109. }
  110. function log_info() {
  111. _log I "$@"
  112. }
  113. function gen_kind_config() {
  114. cat <<EOF
  115. kind: Cluster
  116. apiVersion: kind.x-k8s.io/v1alpha4
  117. name: $CLUSTER_NAME
  118. nodes:
  119. - role: control-plane
  120. image: $ALLINONE_NODE_IMAGE
  121. # expose kubeedge cloudcore
  122. extraPortMappings:
  123. - containerPort: $CLOUDCORE_WS_PORT
  124. - containerPort: $CLOUDCORE_CERT_PORT
  125. EOF
  126. for((i=0;i<NUM_CLOUD_WORKER_NODES;i++)); do
  127. cat <<EOF
  128. - role: worker
  129. image: $ALLINONE_NODE_IMAGE
  130. EOF
  131. done
  132. }
  133. function patch_kindnet() {
  134. # Since in edge node, we just use containerd instead of docker, this requires CNI,
  135. # And `kindnet` is the CNI in kind, requires `InClusterConfig`
  136. # which would require KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT environment variables.
  137. # But edgecore(up to 1.8.0) does not inject these environments.
  138. # Here make a patch: can be any value
  139. run_in_control_plane kubectl set env -n kube-system daemonset/kindnet KUBERNETES_SERVICE_HOST=10.96.0.1 KUBERNETES_SERVICE_PORT=443
  140. }
  141. function create_k8s_cluster() {
  142. if kind get clusters | grep -qx -F "$CLUSTER_NAME"; then
  143. log_info "The k8s cluster $CLUSTER_NAME already exists, and just use it!"
  144. log_info "If you want to recreate one, just run \`$0 clean\`."
  145. return
  146. fi
  147. local extra_options=(--wait 90s)
  148. [ -n "$RETAIN_CONTAINER" ] && extra_options+=(--retain)
  149. gen_kind_config | kind create cluster ${extra_options[@]} --config -
  150. }
  151. function clean_k8s_cluster() {
  152. kind delete cluster --name ${CLUSTER_NAME}
  153. }
  154. function run_in_control_plane() {
  155. docker exec -i $CONTROL_PLANE_NAME "$@"
  156. }
  157. function get_control_plane_ip() {
  158. # https://stackoverflow.com/a/20686101
  159. docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $CONTROL_PLANE_NAME
  160. }
  161. function get_control_plane_exposed_port() {
  162. local container_port=$1
  163. docker inspect -f "{{(index (index .NetworkSettings.Ports \"${container_port}/tcp\") 0).HostPort}}" $CONTROL_PLANE_NAME
  164. }
  165. function setup_control_kubeconfig() {
  166. run_in_control_plane bash -euc "
  167. # copy kube config file
  168. mkdir -p ~/.kube
  169. cp /etc/kubernetes/admin.conf ~/.kube/config
  170. "
  171. }
  172. function setup_cloudcore() {
  173. # keadm already built into control plane
  174. CLOUDCORE_LOCAL_IP=$(get_control_plane_ip)
  175. # Use default docker network for edge nodes to separate the network of control plane which uses the defined network 'kind'
  176. CLOUDCORE_EXPOSED_IP=$(get_docker_network_gw $EDGE_NODE_NETWORK)
  177. CLOUDCORE_EXPOSED_WS_PORT=$(get_control_plane_exposed_port $CLOUDCORE_WS_PORT)
  178. CLOUDCORE_EXPOSED_CERT_PORT=$(get_control_plane_exposed_port $CLOUDCORE_CERT_PORT)
  179. CLOUDCORE_ADVERTISE_ADDRESSES=$CLOUDCORE_LOCAL_IP,$CLOUDCORE_EXPOSED_IP
  180. CLOUDCORE_EXPOSED_ADDR=$CLOUDCORE_EXPOSED_IP:$CLOUDCORE_EXPOSED_WS_PORT
  181. # keadm accepts version format: 1.8.0
  182. local version=${KUBEEDGE_VERSION/v}
  183. run_in_control_plane bash -euc "
  184. # install cloudcore
  185. pgrep cloudcore >/dev/null || {
  186. # keadm 1.8.1 is incompatible with 1.9.1 since crds' upgrade
  187. rm -rf /etc/kubeedge/crds
  188. keadm init --kubeedge-version=$version --advertise-address=$CLOUDCORE_ADVERTISE_ADDRESSES"'
  189. }
  190. # wait token to be created
  191. exit_code=1
  192. TIMEOUT=30 # in seconds
  193. for((i=1;i<=TIMEOUT; i++)); do
  194. keadm gettoken >/dev/null 2>&1 && exit_code=0 && break
  195. echo -ne "Waiting cloudcore to generate token, $i seconds...\r"
  196. sleep 1
  197. done
  198. echo
  199. if [ $exit_code -gt 0 ]; then
  200. log_lines=50
  201. tail -$log_lines /var/log/kubeedge/cloudcore.log | sed "s/^/ /"
  202. echo "Timeout to wait cloudcore, above are the last $log_lines log of cloudcore."
  203. fi
  204. exit $exit_code
  205. '
  206. KUBEEDGE_TOKEN=$(run_in_control_plane keadm gettoken)
  207. }
  208. _change_detect_yaml_change() {
  209. # execute the specified yq commands on stdin
  210. # if same, output nothing
  211. # else output the updated yaml
  212. local yq_cmds="${1:-.}"
  213. docker run -i --rm --entrypoint sh mikefarah/yq -c "
  214. yq e . - > a
  215. yq e '$yq_cmds' a > b
  216. cmp -s a b || cat b
  217. "
  218. }
  219. reconfigure_edgecore() {
  220. # update edgecore.yaml for every edge node
  221. local script_name=reconfigure-edgecore
  222. if ((NUM_EDGE_NODES<1)); then
  223. return
  224. fi
  225. local yq_cmds="$1"
  226. # I want to leverage kubectl but k8s has no ways to run job on each node once
  227. # see https://github.com/kubernetes/kubernetes/issues/64623 for more detais
  228. # So I use Daemonset temporarily
  229. kubectl apply -f - <<EOF
  230. apiVersion: apps/v1
  231. kind: DaemonSet
  232. metadata:
  233. name: $script_name
  234. namespace: kubeedge
  235. spec:
  236. selector:
  237. matchLabels:
  238. edgecore: script
  239. template:
  240. metadata:
  241. labels:
  242. edgecore: script
  243. spec:
  244. affinity:
  245. nodeAffinity:
  246. requiredDuringSchedulingIgnoredDuringExecution:
  247. nodeSelectorTerms:
  248. - matchExpressions:
  249. - key: node-role.kubernetes.io/edge
  250. operator: Exists
  251. hostPID: true
  252. volumes:
  253. - name: config
  254. hostPath:
  255. path: /etc/kubeedge/config
  256. containers:
  257. - name: $script_name
  258. env:
  259. - name: NODE_NAME
  260. valueFrom:
  261. fieldRef:
  262. fieldPath: spec.nodeName
  263. securityContext:
  264. runAsUser: 0
  265. volumeMounts:
  266. - name: config
  267. mountPath: /config
  268. image: mikefarah/yq
  269. command:
  270. - sh
  271. - -c
  272. - |
  273. # inject random cmd to reapply when reconfigure
  274. : $$
  275. yq e . /config/edgecore.yaml > a && yq e '$(echo $yq_cmds)' a > b || exit 1
  276. cmp -s a b && echo No need to reconfigure \$NODE_NAME edgecore || {
  277. # backup and overwrite config, kill edgecore and wait systemd restart it
  278. cp /config/edgecore.yaml /config/edgecore.yaml.reconfigure_bk
  279. cp b /config/edgecore.yaml
  280. pkill edgecore
  281. # check to edgecore process status
  282. > pids
  283. for i in 0 1 2 3; do
  284. sleep 10
  285. { pidof edgecore || echo =\$i; } >> pids
  286. done
  287. [ \$(sort -u pids | wc -l) -le 2 ] && echo Reconfigure \$NODE_NAME edgecore successfully || {
  288. echo Failed to reconfigure \$NODE_NAME edgecore >&2
  289. echo And recovery edgecore config yaml >&2
  290. cp a /config/edgecore.yaml
  291. # prevent daemonset execute this script too frequently
  292. sleep 1800
  293. exit 1
  294. }
  295. }
  296. sleep inf
  297. EOF
  298. # wait this script been executed
  299. kubectl -n kubeedge rollout status --timeout=5m ds $script_name
  300. # wait all edge nodes to be ready if restarted
  301. kubectl wait --for=condition=ready node -l node-role.kubernetes.io/edge=
  302. # keep this daemonset script for debugging
  303. # kubectl -n kubeedge delete ds $script_name
  304. }
  305. reconfigure_cloudcore() {
  306. local config_file=/etc/kubeedge/config/cloudcore.yaml
  307. local yq_cmds=$1
  308. run_in_control_plane cat $config_file |
  309. _change_detect_yaml_change "$yq_cmds" |
  310. run_in_control_plane bash -euc "
  311. cat > cc.yaml
  312. ! grep -q . cc.yaml || {
  313. echo reconfigure and restart cloudcore
  314. cp $config_file ${config_file}.reconfigure_bk
  315. cp cc.yaml $config_file
  316. pkill cloudcore || true
  317. # TODO: use a systemd service
  318. (cloudcore &>> /var/log/kubeedge/cloudcore.log &)
  319. }
  320. "
  321. echo Reconfigure cloudcore successfully
  322. }
  323. function install_edgemesh() {
  324. if ((NUM_EDGE_NODES<1)); then
  325. # no edge node, no edgemesh
  326. return
  327. fi
  328. local server_node_name
  329. if ((NUM_CLOUD_WORKER_NODES>0)); then
  330. server_node_name=${CLUSTER_NAME}-worker
  331. else
  332. server_node_name=${CLUSTER_NAME}-control-plane
  333. fi
  334. echo Installing edgemesh with server on $server_node_name
  335. # enable Local APIServer
  336. reconfigure_cloudcore '.modules.dynamicController.enable=true'
  337. reconfigure_edgecore '
  338. .modules.edged.clusterDNS="169.254.96.16"
  339. | .modules.edged.clusterDomain="cluster.local"
  340. | .modules.metaManager.metaServer.enable=true
  341. '
  342. # no server.publicIP
  343. # since allinone is in flat network, we just use private ip for edgemesh server
  344. helm upgrade --install edgemesh \
  345. --set server.nodeName=$server_node_name \
  346. https://raw.githubusercontent.com/kubeedge/edgemesh/main/build/helm/edgemesh.tgz
  347. echo Install edgemesh successfully
  348. }
  349. function gen_cni_config() {
  350. cat <<EOF
  351. {
  352. "cniVersion": "0.3.1",
  353. "name": "edgecni",
  354. "plugins": [
  355. {
  356. "type": "ptp",
  357. "ipMasq": false,
  358. "ipam": {
  359. "type": "host-local",
  360. "dataDir": "/run/cni-ipam-state",
  361. "routes": [
  362. {
  363. "dst": "0.0.0.0/0"
  364. }
  365. ],
  366. "ranges": [
  367. [
  368. {
  369. "subnet": "10.244.0.0/24"
  370. }
  371. ]
  372. ]
  373. },
  374. "mtu": 1500
  375. },
  376. {
  377. "type": "portmap",
  378. "capabilities": {
  379. "portMappings": true
  380. }
  381. }
  382. ]
  383. }
  384. EOF
  385. }
  386. function create_and_setup_edgenodes() {
  387. for((i=0;i<NUM_EDGE_NODES;i++)); do
  388. log_info "Installing $i-th edge node..."
  389. local containername=sedna-mini-edge$i
  390. local hostname=edge$i
  391. local label=sedna.io=sedna-mini-edge
  392. # Many tricky arguments are from the kind code
  393. # https://github.com/kubernetes-sigs/kind/blob/4910c3e221a858e68e29f9494170a38e1c4e8b80/pkg/cluster/internal/providers/docker/provision.go#L148
  394. local run_cmds=(
  395. docker run
  396. --network "$EDGE_NODE_NETWORK"
  397. --hostname "$hostname"
  398. --name "$containername"
  399. --label $label
  400. --privileged
  401. --security-opt seccomp=unconfined
  402. --security-opt apparmor=unconfined
  403. --tmpfs /tmp
  404. --tmpfs /run
  405. --volume /var
  406. # some k8s things want to read /lib/modules
  407. --volume /lib/modules:/lib/modules:ro
  408. --restart=on-failure:1
  409. --tty
  410. --detach $ALLINONE_NODE_IMAGE
  411. )
  412. local existing_id=$(docker ps -qa --filter name=$containername --filter label=$label)
  413. if [ -n "$existing_id" ]; then
  414. if [ "${REUSE_EDGE_CONTAINER,,}" = true ] ; then
  415. log_info "Use existing container for ''$containername'"
  416. log_info "If not your attention, you can do:"
  417. log_info " 1) set REUSE_EDGE_CONTAINER=false"
  418. log_info " Or 2) clean it first."
  419. log_info "And rerun this script."
  420. # start in case stopped
  421. docker start $containername
  422. else
  423. log_error "The container named $containername already exists, you can do:"
  424. log_error " 1) set REUSE_EDGE_CONTAINER=true"
  425. log_error " Or 2) clean it first."
  426. log_fault "And rerun this script."
  427. fi
  428. else
  429. # does not exist, create one container for this edge
  430. "${run_cmds[@]}"
  431. fi
  432. # install edgecore using keadm join
  433. local version=${KUBEEDGE_VERSION/v}
  434. docker exec -i $containername bash -uec "
  435. pgrep edgecore >/dev/null || {
  436. keadm join \
  437. --cloudcore-ipport=${CLOUDCORE_EXPOSED_ADDR} \
  438. --certport=${CLOUDCORE_EXPOSED_CERT_PORT} \
  439. --token=$KUBEEDGE_TOKEN \
  440. --kubeedge-version '$version' \
  441. --edgenode-name '$hostname' \
  442. --remote-runtime-endpoint unix:///var/run/containerd/containerd.sock \
  443. --runtimetype remote
  444. # set imageGCHighThreshold to 100% for no image gc
  445. sed -i 's/imageGCHighThreshold:.*/imageGCHighThreshold: 100/' /etc/kubeedge/config/edgecore.yaml &&
  446. systemctl restart edgecore ||
  447. true # ignore the error
  448. }
  449. "
  450. # fix cni config file
  451. gen_cni_config | docker exec -i $containername tee /etc/cni/net.d/10-edgecni.conflist >/dev/null
  452. {
  453. # wait edge node to be created at background
  454. nwait=20
  455. for((i=0;i<nwait;i++)); do
  456. kubectl get node $hostname &>/dev/null && break
  457. sleep 3
  458. done
  459. } &
  460. done
  461. # wait all edge nodes to be created
  462. wait
  463. }
  464. function clean_edgenodes() {
  465. for cid in $(docker ps -a --filter label=sedna.io=sedna-mini-edge -q); do
  466. docker stop $cid; docker rm $cid
  467. done
  468. }
  469. function get_docker_network_gw() {
  470. docker network inspect ${1-bridge} --format='{{(index .IPAM.Config 0).Gateway}}'
  471. }
  472. function setup_cloud() {
  473. create_k8s_cluster
  474. patch_kindnet
  475. setup_control_kubeconfig
  476. setup_cloudcore
  477. }
  478. function clean_cloud() {
  479. clean_k8s_cluster
  480. }
  481. function setup_edge() {
  482. create_and_setup_edgenodes
  483. }
  484. function clean_edge() {
  485. clean_edgenodes
  486. }
  487. function install_sedna() {
  488. if [[ "$NO_INSTALL_SEDNA" != "false" ]]; then
  489. return
  490. fi
  491. if run_in_control_plane kubectl get ns sedna; then
  492. if [ "$FORCE_INSTALL_SEDNA" != true ]; then
  493. log_info '"sedna" namespace already exists, no install Sedna control components.'
  494. log_info 'If want to reinstall them, you can remove it by `kubectl delete ns sedna` or set FORCE_INSTALL_SEDNA=true!'
  495. log_info
  496. return
  497. fi
  498. run_in_control_plane bash -ec "
  499. curl https://raw.githubusercontent.com/kubeedge/sedna/main/scripts/installation/install.sh | SEDNA_ACTION=clean SEDNA_VERSION=$SEDNA_VERSION bash -
  500. "
  501. fi
  502. log_info "Installing Sedna Control Components..."
  503. run_in_control_plane bash -ec "
  504. curl https://raw.githubusercontent.com/kubeedge/sedna/main/scripts/installation/install.sh | SEDNA_ACTION=create SEDNA_VERSION=$SEDNA_VERSION bash -
  505. "
  506. }
  507. function get_latest_version() {
  508. # get the latest version of specified gh repo
  509. local repo=${1} default_version=${2:-}
  510. # output of this latest page:
  511. # ...
  512. # "tag_name": "v1.0.0",
  513. # ...
  514. # Sometimes this will reach rate limit
  515. # https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting
  516. local url=https://api.github.com/repos/$repo/releases/latest
  517. if ! curl --fail -s $url | awk '/"tag_name":/&&$0=$2' | sed 's/[",]//g'; then
  518. log_error "Error to get latest version of $repo: $(curl -s $url | head)"
  519. [ -n "$default_version" ] && {
  520. log_error "Fall back to default version: $default_version"
  521. echo $default_version
  522. }
  523. fi
  524. }
  525. function arch() {
  526. local arch=$(uname -m)
  527. case "$arch" in
  528. x86_64) arch=amd64;;
  529. *);;
  530. esac
  531. echo "$arch"
  532. }
  533. function _download_tool() {
  534. local name=$1 url=$2
  535. local file=/usr/local/bin/$name
  536. curl -Lo $file $url
  537. chmod +x $file
  538. }
  539. function check_command_exists() {
  540. type $1 >/dev/null 2>&1
  541. }
  542. function ensure_tool() {
  543. local command=$1 download_url=$2
  544. if check_command_exists $command; then
  545. return
  546. fi
  547. _download_tool $command $download_url
  548. }
  549. function ensure_kind() {
  550. local version=${KIND_VERSION:-0.11.1}
  551. ensure_tool kind https://kind.sigs.k8s.io/dl/v${version/v}/kind-linux-$(arch)
  552. }
  553. function ensure_kubectl() {
  554. local version=${KUBECTL_VERSION:-1.21.0}
  555. ensure_tool kubectl https://dl.k8s.io/release/v${version/v}/bin/linux/$(arch)/kubectl
  556. }
  557. function ensure_helm() {
  558. if check_command_exists helm; then
  559. return
  560. fi
  561. curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
  562. }
  563. function ensure_tools() {
  564. ensure_kind
  565. ensure_kubectl
  566. ensure_helm
  567. }
  568. function main() {
  569. ensure_tools
  570. prepare_env
  571. action=${1-create}
  572. case "$action" in
  573. create)
  574. setup_cloud
  575. setup_edge
  576. # wait all nodes to be ready
  577. kubectl wait --for=condition=ready node --all
  578. # edgemesh need to be installed before sedna
  579. install_edgemesh
  580. install_sedna
  581. log_info "Mini Sedna is created successfully"
  582. ;;
  583. delete|clean)
  584. clean_edge
  585. clean_cloud
  586. log_info "Mini Sedna is uninstalled successfully"
  587. ;;
  588. # As a source file, noop
  589. __source__)
  590. ;;
  591. *)
  592. log_fault "Unknown action $action"
  593. ;;
  594. esac
  595. }
  596. main "$@"