github.com/enmand/kubernetes@v1.2.0-alpha.0/docs/getting-started-guides/coreos/azure/lib/azure_wrapper.js (about) 1 var _ = require('underscore'); 2 3 var fs = require('fs'); 4 var cp = require('child_process'); 5 6 var yaml = require('js-yaml'); 7 8 var openssl = require('openssl-wrapper'); 9 10 var clr = require('colors'); 11 var inspect = require('util').inspect; 12 13 var util = require('./util.js'); 14 15 var coreos_image_ids = { 16 'stable': '2b171e93f07c4903bcad35bda10acf22__CoreOS-Stable-717.3.0', 17 'beta': '2b171e93f07c4903bcad35bda10acf22__CoreOS-Beta-723.3.0', // untested 18 'alpha': '2b171e93f07c4903bcad35bda10acf22__CoreOS-Alpha-745.1.0' // untested 19 }; 20 21 var conf = {}; 22 23 var hosts = { 24 collection: [], 25 ssh_port_counter: 2200, 26 }; 27 28 var task_queue = []; 29 30 exports.run_task_queue = function (dummy) { 31 var tasks = { 32 todo: task_queue, 33 done: [], 34 }; 35 36 var pop_task = function() { 37 console.log(clr.yellow('azure_wrapper/task:'), clr.grey(inspect(tasks))); 38 var ret = {}; 39 ret.current = tasks.todo.shift(); 40 ret.remaining = tasks.todo.length; 41 return ret; 42 }; 43 44 (function iter (task) { 45 if (task.current === undefined) { 46 if (conf.destroying === undefined) { 47 create_ssh_conf(); 48 save_state(); 49 } 50 return; 51 } else { 52 if (task.current.length !== 0) { 53 console.log(clr.yellow('azure_wrapper/exec:'), clr.blue(inspect(task.current))); 54 cp.fork('node_modules/azure-cli/bin/azure', task.current) 55 .on('exit', function (code, signal) { 56 tasks.done.push({ 57 code: code, 58 signal: signal, 59 what: task.current.join(' '), 60 remaining: task.remaining, 61 }); 62 if (code !== 0 && conf.destroying === undefined) { 63 console.log(clr.red('azure_wrapper/fail: Exiting due to an error.')); 64 save_state(); 65 console.log(clr.cyan('azure_wrapper/info: You probably want to destroy and re-run.')); 66 process.abort(); 67 } else { 68 iter(pop_task()); 69 } 70 }); 71 } else { 72 iter(pop_task()); 73 } 74 } 75 })(pop_task()); 76 }; 77 78 var save_state = function () { 79 var file_name = util.join_output_file_path(conf.name, 'deployment.yml'); 80 try { 81 conf.hosts = hosts.collection; 82 fs.writeFileSync(file_name, yaml.safeDump(conf)); 83 console.log(clr.yellow('azure_wrapper/info: Saved state into `%s`'), file_name); 84 } catch (e) { 85 console.log(clr.red(e)); 86 } 87 }; 88 89 var load_state = function (file_name) { 90 try { 91 conf = yaml.safeLoad(fs.readFileSync(file_name, 'utf8')); 92 console.log(clr.yellow('azure_wrapper/info: Loaded state from `%s`'), file_name); 93 return conf; 94 } catch (e) { 95 console.log(clr.red(e)); 96 } 97 }; 98 99 var create_ssh_key = function (prefix) { 100 var opts = { 101 x509: true, 102 nodes: true, 103 newkey: 'rsa:2048', 104 subj: '/O=Weaveworks, Inc./L=London/C=GB/CN=weave.works', 105 keyout: util.join_output_file_path(prefix, 'ssh.key'), 106 out: util.join_output_file_path(prefix, 'ssh.pem'), 107 }; 108 openssl.exec('req', opts, function (err, buffer) { 109 if (err) console.log(clr.red(err)); 110 fs.chmod(opts.keyout, '0600', function (err) { 111 if (err) console.log(clr.red(err)); 112 }); 113 }); 114 return { 115 key: opts.keyout, 116 pem: opts.out, 117 } 118 } 119 120 var create_ssh_conf = function () { 121 var file_name = util.join_output_file_path(conf.name, 'ssh_conf'); 122 var ssh_conf_head = [ 123 "Host *", 124 "\tHostname " + conf.resources['service'] + ".cloudapp.net", 125 "\tUser core", 126 "\tCompression yes", 127 "\tLogLevel FATAL", 128 "\tStrictHostKeyChecking no", 129 "\tUserKnownHostsFile /dev/null", 130 "\tIdentitiesOnly yes", 131 "\tIdentityFile " + conf.resources['ssh_key']['key'], 132 "\n", 133 ]; 134 135 fs.writeFileSync(file_name, ssh_conf_head.concat(_.map(hosts.collection, function (host) { 136 return _.template("Host <%= name %>\n\tPort <%= port %>\n")(host); 137 })).join('\n')); 138 console.log(clr.yellow('azure_wrapper/info:'), clr.green('Saved SSH config, you can use it like so: `ssh -F ', file_name, '<hostname>`')); 139 console.log(clr.yellow('azure_wrapper/info:'), clr.green('The hosts in this deployment are:\n'), _.map(hosts.collection, function (host) { return host.name; })); 140 }; 141 142 var get_location = function () { 143 if (process.env['AZ_AFFINITY']) { 144 return '--affinity-group=' + process.env['AZ_AFFINITY']; 145 } else if (process.env['AZ_LOCATION']) { 146 return '--location=' + process.env['AZ_LOCATION']; 147 } else { 148 return '--location=West Europe'; 149 } 150 } 151 var get_vm_size = function () { 152 if (process.env['AZ_VM_SIZE']) { 153 return '--vm-size=' + process.env['AZ_VM_SIZE']; 154 } else { 155 return '--vm-size=Small'; 156 } 157 } 158 159 exports.queue_default_network = function () { 160 task_queue.push([ 161 'network', 'vnet', 'create', 162 get_location(), 163 '--address-space=172.16.0.0', 164 conf.resources['vnet'], 165 ]); 166 } 167 168 exports.queue_storage_if_needed = function() { 169 if (!process.env['AZURE_STORAGE_ACCOUNT']) { 170 conf.resources['storage_account'] = util.rand_suffix; 171 task_queue.push([ 172 'storage', 'account', 'create', 173 '--type=LRS', 174 get_location(), 175 conf.resources['storage_account'], 176 ]); 177 process.env['AZURE_STORAGE_ACCOUNT'] = conf.resources['storage_account']; 178 } else { 179 // Preserve it for resizing, so we don't create a new one by accedent, 180 // when the environment variable is unset 181 conf.resources['storage_account'] = process.env['AZURE_STORAGE_ACCOUNT']; 182 } 183 }; 184 185 exports.queue_machines = function (name_prefix, coreos_update_channel, cloud_config_creator) { 186 var x = conf.nodes[name_prefix]; 187 var vm_create_base_args = [ 188 'vm', 'create', 189 get_location(), 190 get_vm_size(), 191 '--connect=' + conf.resources['service'], 192 '--virtual-network-name=' + conf.resources['vnet'], 193 '--no-ssh-password', 194 '--ssh-cert=' + conf.resources['ssh_key']['pem'], 195 ]; 196 197 var cloud_config = cloud_config_creator(x, conf); 198 199 var next_host = function (n) { 200 hosts.ssh_port_counter += 1; 201 var host = { name: util.hostname(n, name_prefix), port: hosts.ssh_port_counter }; 202 if (cloud_config instanceof Array) { 203 host.cloud_config_file = cloud_config[n]; 204 } else { 205 host.cloud_config_file = cloud_config; 206 } 207 hosts.collection.push(host); 208 return _.map([ 209 "--vm-name=<%= name %>", 210 "--ssh=<%= port %>", 211 "--custom-data=<%= cloud_config_file %>", 212 ], function (arg) { return _.template(arg)(host); }); 213 }; 214 215 task_queue = task_queue.concat(_(x).times(function (n) { 216 if (conf.resizing && n < conf.old_size) { 217 return []; 218 } else { 219 return vm_create_base_args.concat(next_host(n), [ 220 coreos_image_ids[coreos_update_channel], 'core', 221 ]); 222 } 223 })); 224 }; 225 226 exports.create_config = function (name, nodes) { 227 conf = { 228 name: name, 229 nodes: nodes, 230 weave_salt: util.rand_string(), 231 resources: { 232 vnet: [name, 'internal-vnet', util.rand_suffix].join('-'), 233 service: [name, util.rand_suffix].join('-'), 234 ssh_key: create_ssh_key(name), 235 } 236 }; 237 238 }; 239 240 exports.destroy_cluster = function (state_file) { 241 load_state(state_file); 242 if (conf.hosts === undefined) { 243 console.log(clr.red('azure_wrapper/fail: Nothing to delete.')); 244 process.abort(); 245 } 246 247 conf.destroying = true; 248 task_queue = _.map(conf.hosts, function (host) { 249 return ['vm', 'delete', '--quiet', '--blob-delete', host.name]; 250 }); 251 252 task_queue.push(['network', 'vnet', 'delete', '--quiet', conf.resources['vnet']]); 253 task_queue.push(['storage', 'account', 'delete', '--quiet', conf.resources['storage_account']]); 254 255 exports.run_task_queue(); 256 }; 257 258 exports.load_state_for_resizing = function (state_file, node_type, new_nodes) { 259 load_state(state_file); 260 if (conf.hosts === undefined) { 261 console.log(clr.red('azure_wrapper/fail: Nothing to look at.')); 262 process.abort(); 263 } 264 conf.resizing = true; 265 conf.old_size = conf.nodes[node_type]; 266 conf.old_state_file = state_file; 267 conf.nodes[node_type] += new_nodes; 268 hosts.collection = conf.hosts; 269 hosts.ssh_port_counter += conf.hosts.length; 270 process.env['AZURE_STORAGE_ACCOUNT'] = conf.resources['storage_account']; 271 }