azure-provider.sh 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. # |source| this file
  2. #
  3. # Utilities for working with Azure instances
  4. #
  5. # Default zone
  6. cloud_DefaultZone() {
  7. echo "westus"
  8. }
  9. cloud_DefaultCustomMemoryGB() {
  10. : # Not implemented
  11. }
  12. cloud_RestartPreemptedInstances() {
  13. : # Not implemented
  14. }
  15. #
  16. # __cloud_GetConfigValueFromInstanceName
  17. # Return a piece of configuration information about an instance
  18. # Provide the exact name of an instance and the configuration key, and the corresponding value will be returned
  19. #
  20. # example:
  21. # This will return the name of the resource group of the instance named
  22. # __cloud_GetConfigValueFromInstanceName some-instance-name resourceGroup
  23. cloud_GetConfigValueFromInstanceName() {
  24. query="[?name=='$1']"
  25. key="[$2]"
  26. config_value=$(az vm list -d -o tsv --query "$query.$key")
  27. }
  28. cloud_GetResourceGroupFromInstanceName() {
  29. resourceGroup=$(az vm list -o tsv --query "[?name=='$1'].[resourceGroup]")
  30. }
  31. cloud_GetIdFromInstanceName() {
  32. id=$(az vm list -o tsv --query "[?name=='$1'].[id]")
  33. }
  34. #
  35. # __cloud_FindInstances
  36. #
  37. # Find instances matching the specified pattern.
  38. #
  39. # For each matching instance, an entry in the `instances` array will be added with the
  40. # following information about the instance:
  41. # "name:public IP:private IP:location"
  42. #
  43. # filter - The instances to filter on
  44. #
  45. # examples:
  46. # $ __cloud_FindInstances prefix some-machine-prefix
  47. # $ __cloud_FindInstances name exact-machine-name
  48. #
  49. # Examples of plain-text filter command
  50. #
  51. # This will return an exact match for a machine named pgnode
  52. # az vm list -d --query "[?name=='pgnode'].[name,publicIps,privateIps,location]"
  53. #
  54. # This will return a match for any machine with prefix pgnode, ex: pgnode and pgnode2
  55. # az vm list -d --query "[?starts_with(name,'pgnode')].[name,publicIps,privateIps,location]"
  56. __cloud_FindInstances() {
  57. case $1 in
  58. prefix)
  59. query="[?starts_with(name,'$2')]"
  60. ;;
  61. name)
  62. query="[?name=='$2']"
  63. ;;
  64. *)
  65. echo "Unknown filter command: $1"
  66. ;;
  67. esac
  68. keys="[name,publicIps,privateIps,location]"
  69. instances=()
  70. while read -r name publicIp privateIp location; do
  71. instances+=("$name:$publicIp:$privateIp:$location")
  72. done < <(az vm list -d -o tsv --query "$query.$keys")
  73. echo "${instances[*]}"
  74. }
  75. #
  76. # cloud_FindInstances [namePrefix]
  77. #
  78. # Find instances with names matching the specified prefix
  79. #
  80. # For each matching instance, an entry in the `instances` array will be added with the
  81. # following information about the instance:
  82. # "name:public IP:private IP:location"
  83. #
  84. # namePrefix - The instance name prefix to look for
  85. #
  86. # examples:
  87. # $ cloud_FindInstances all-machines-with-a-common-machine-prefix
  88. #
  89. cloud_FindInstances() {
  90. __cloud_FindInstances prefix "$1"
  91. }
  92. #
  93. # cloud_FindInstance [name]
  94. #
  95. # Find an instance with a name matching the exact pattern.
  96. #
  97. # For each matching instance, an entry in the `instances` array will be added with the
  98. # following information about the instance:
  99. # "name:public IP:private IP:location"
  100. #
  101. # name - The instance name to look for
  102. #
  103. # examples:
  104. # $ cloud_FindInstance exact-machine-name
  105. #
  106. cloud_FindInstance() {
  107. __cloud_FindInstances name "$1"
  108. }
  109. #
  110. # cloud_Initialize [networkName]
  111. #
  112. # Perform one-time initialization that may be required for the given testnet.
  113. #
  114. # networkName - unique name of this testnet
  115. #
  116. # This function will be called before |cloud_CreateInstances|
  117. cloud_Initialize() {
  118. declare resourceGroup="$1"
  119. declare location="$2"
  120. declare nsgName=${resourceGroup}-nsg
  121. # Check if resource group exists. If not, create it.
  122. (
  123. set -x
  124. numGroup=$(az group list --query "length([?name=='$resourceGroup'])")
  125. if [[ $numGroup -eq 0 ]]; then
  126. echo Resource Group "$resourceGroup" does not exist. Creating it now.
  127. az group create --name "$resourceGroup" --location "$location"
  128. else
  129. echo Resource group "$resourceGroup" already exists.
  130. az group show --name "$resourceGroup"
  131. fi
  132. az network nsg create --name "$nsgName" --resource-group "$resourceGroup"
  133. )
  134. create_nsg_rule() {
  135. ruleName="$1"
  136. ports="$2"
  137. access="$3"
  138. protocol="$4"
  139. priority="$5"
  140. (
  141. set -x
  142. az network nsg rule create -g "${resourceGroup}" --nsg-name "${nsgName}" -n "${ruleName}" \
  143. --priority "${priority}" --source-address-prefixes "*" --source-port-ranges "*" \
  144. --destination-address-prefixes "*" --destination-port-ranges "${ports}" --access "${access}" \
  145. --protocol "${protocol}"
  146. )
  147. }
  148. create_nsg_rule "InboundTCP" "8000-10000" "Allow" "Tcp" 1000
  149. create_nsg_rule "InboundUDP" "8000-10000" "Allow" "Udp" 1001
  150. create_nsg_rule "InboundHTTP" "80" "Allow" "Tcp" 1002
  151. create_nsg_rule "InboundNetworkExplorerAPI" "3001" "Allow" "Tcp" 1003
  152. create_nsg_rule "InboundDrone" "9900" "Allow" "Tcp" 1004
  153. create_nsg_rule "InboundJsonRpc" "8899-8900" "Allow" "Tcp" 1005
  154. create_nsg_rule "InboundRsync" "873" "Allow" "Tcp" 1006
  155. create_nsg_rule "InboundStun" "3478" "Allow" "Udp" 1007
  156. create_nsg_rule "InboundSSH" "22" "Allow" "Tcp" 1008
  157. }
  158. #
  159. # cloud_CreateInstances [networkName] [namePrefix] [numNodes]
  160. # [machineType] [zone]
  161. # [bootDiskSize] [startupScript] [address]
  162. # [bootDiskType] [additionalDiskSize] [preemptible]
  163. #
  164. # Creates one more identical instances.
  165. #
  166. # networkName - unique name of this testnet
  167. # namePrefix - unique string to prefix all the instance names with
  168. # numNodes - number of instances to create
  169. # machineType - GCE machine type. Note that this may also include an
  170. # `--accelerator=` or other |gcloud compute instances create|
  171. # options
  172. # zone - cloud zone
  173. # bootDiskSize - Optional size of the boot disk in GB
  174. # startupScript - Optional startup script to execute when the instance boots
  175. # address - Optional name of the GCE static IP address to attach to the
  176. # instance. Requires that |numNodes| = 1 and that addressName
  177. # has been provisioned in the GCE region that is hosting `$zone`
  178. # bootDiskType - Optional specify SSD or HDD boot disk
  179. # additionalDiskSize - Optional specify size of additional storage volume
  180. # preemptible - Optionally request a preemptible instance ("true")
  181. #
  182. # Tip: use cloud_FindInstances to locate the instances once this function
  183. # returns
  184. cloud_CreateInstances() {
  185. declare networkName="$1"
  186. declare namePrefix="$2"
  187. declare numNodes="$3"
  188. declare machineType="$4"
  189. declare zone="$5"
  190. declare optionalBootDiskSize="$6"
  191. declare optionalStartupScript="$7"
  192. declare optionalAddress="$8"
  193. declare optionalBootDiskType="${9}"
  194. declare -a nodes
  195. if [[ $numNodes = 1 ]]; then
  196. nodes=("$namePrefix")
  197. else
  198. for node in $(seq -f "${namePrefix}%0${#numNodes}g" 1 "$numNodes"); do
  199. nodes+=("$node")
  200. done
  201. fi
  202. nsgName=${networkName}-nsg
  203. declare -a args
  204. args=(
  205. --resource-group "$networkName"
  206. --tags testnet
  207. --image UbuntuLTS
  208. --size "$machineType"
  209. --ssh-key-values "$(cat "${sshPrivateKey}".pub)"
  210. --location "$zone"
  211. --nsg "$nsgName"
  212. )
  213. if [[ -n $optionalBootDiskSize ]]; then
  214. args+=(
  215. --os-disk-size-gb "$optionalBootDiskSize"
  216. )
  217. fi
  218. if [[ -n $optionalStartupScript ]]; then
  219. args+=(
  220. --custom-data "$optionalStartupScript"
  221. )
  222. fi
  223. if [[ -n $optionalBootDiskType ]]; then
  224. args+=(
  225. --storage-sku "$optionalBootDiskType"
  226. )
  227. else
  228. args+=(
  229. --storage-sku StandardSSD_LRS
  230. )
  231. fi
  232. if [[ -n $optionalAddress ]]; then
  233. [[ $numNodes = 1 ]] || {
  234. echo "Error: address may not be supplied when provisioning multiple nodes: $optionalAddress"
  235. exit 1
  236. }
  237. args+=(
  238. --public-ip-address "$optionalAddress"
  239. )
  240. fi
  241. (
  242. set -x
  243. # For node in numNodes, create VM and put the creation process in the background with --no-wait
  244. for nodeName in "${nodes[@]}"; do
  245. az vm create --name "$nodeName" "${args[@]}" --no-wait
  246. done
  247. for nodeName in "${nodes[@]}"; do
  248. az vm wait --created --name "$nodeName" --resource-group "$networkName" --verbose --timeout 600
  249. done
  250. )
  251. }
  252. #
  253. # cloud_DeleteInstances
  254. #
  255. # Deletes all the instances listed in the `instances` array
  256. #
  257. cloud_DeleteInstances() {
  258. if [[ ${#instances[0]} -eq 0 ]]; then
  259. echo No instances to delete
  260. return
  261. fi
  262. declare names=("${instances[@]/:*/}")
  263. (
  264. set -x
  265. id_list=()
  266. # Build a space delimited list of all resource IDs to delete
  267. for instance in "${names[@]}"; do
  268. cloud_GetIdFromInstanceName "$instance"
  269. id_list+=("$id")
  270. done
  271. # Delete all instances in the id_list and return once they are all deleted
  272. az vm delete --ids "${id_list[@]}" --yes --verbose --no-wait
  273. )
  274. }
  275. #
  276. # cloud_WaitForInstanceReady [instanceName] [instanceIp] [instanceZone] [timeout]
  277. #
  278. # Return once the newly created VM instance is responding. This function is cloud-provider specific.
  279. #
  280. cloud_WaitForInstanceReady() {
  281. declare instanceName="$1"
  282. # declare instanceIp="$2" # unused
  283. # declare instanceZone="$3" # unused
  284. declare timeout="$4"
  285. cloud_GetResourceGroupFromInstanceName "$instanceName"
  286. az vm wait -g "$resourceGroup" -n "$instanceName" --created --interval 10 --timeout "$timeout"
  287. }
  288. #
  289. # cloud_FetchFile [instanceName] [publicIp] [remoteFile] [localFile]
  290. #
  291. # Fetch a file from the given instance. This function uses a cloud-specific
  292. # mechanism to fetch the file
  293. #
  294. cloud_FetchFile() {
  295. declare instanceName="$1"
  296. declare publicIp="$2"
  297. declare remoteFile="$3"
  298. declare localFile="$4"
  299. cloud_GetConfigValueFromInstanceName "$instanceName" osProfile.adminUsername
  300. scp "${config_value}@${publicIp}:${remoteFile}" "$localFile"
  301. }
  302. #
  303. # cloud_CreateAndAttachPersistentDisk
  304. #
  305. # Not yet implemented for this cloud provider
  306. cloud_CreateAndAttachPersistentDisk() {
  307. echo "ERROR: cloud_CreateAndAttachPersistentDisk is not yet implemented for azure"
  308. exit 1
  309. }
  310. #
  311. # cloud_StatusAll
  312. #
  313. # Not yet implemented for this cloud provider
  314. cloud_StatusAll() {
  315. echo "ERROR: cloud_StatusAll is not yet implemented for azure"
  316. }