Class: Nutkins::CloudManager
- Inherits:
-
Object
- Object
- Nutkins::CloudManager
- Defined in:
- lib/nutkins.rb
Instance Method Summary collapse
- #build(path) ⇒ Object
- #build_secret(path) ⇒ Object
- #create(path, preserve: false, docker_args: [], reuse: false) ⇒ Object
- #delete(path) ⇒ Object
- #delete_all ⇒ Object
- #exec(path, *cmd) ⇒ Object
- #extract_secrets(paths) ⇒ Object
-
#initialize(project_dir: nil) ⇒ CloudManager
constructor
A new instance of CloudManager.
- #run(path, reuse: false, shell: false) ⇒ Object
- #start_etcd_container ⇒ Object
- #stop_etcd_container ⇒ Object
Constructor Details
#initialize(project_dir: nil) ⇒ CloudManager
Returns a new instance of CloudManager.
29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/nutkins.rb', line 29 def initialize(project_dir: nil) @img_configs = {} # when an image is built true is stored against it's name to avoid building it again @built = {} @etcd_running = false @project_root = project_dir || Dir.pwd cfg_path = File.join(@project_root, CONFIG_FILE_NAME) if File.exists? cfg_path @config = OpenStruct.new(YAML.load_file cfg_path) else @config = OpenStruct.new end end |
Instance Method Details
#build(path) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/nutkins.rb', line 43 def build path cfg = get_image_config path img_dir = cfg['directory'] img_name = cfg['image'] return if @built[img_name] raise "directory `#{img_dir}' does not exist" unless Dir.exists? img_dir tag = cfg['tag'] # TODO: flag to suppress building base image? base = cfg['base'] unless @built[base] base_cfg = config_for_image base if base_cfg base_path = base_cfg['path'] puts "building parent of #{img_name}: #{base}" build base_path end end prev_image_id = Docker.image_id_for_tag tag build_cfg = cfg["build"] if build_cfg # download each of the files in the resources section if it doesn't exist resources = build_cfg["resources"] Download.download_resources img_dir, resources if resources end if cfg.dig "build", "commands" # if build commands are available use nutkins built-in builder base_cfg ||= config_for_image base Docker::Builder::build cfg, base_cfg && base_cfg['tag'] else # fallback to `docker build` which is less good if not Docker.run 'build', '-t', cfg['latest_tag'], '-t', tag, img_dir, stdout: true raise "issue building docker image for #{path}" end end image_id = Docker.image_id_for_tag tag if prev_image_id if image_id != prev_image_id puts "deleting previous image #{prev_image_id}" Docker.run "rmi", prev_image_id else puts "unchanged image: #{tag}" end elsif image_id puts "created new image #{image_id}" else puts "no image exists for image... what went wrong?" end @built[img_name] = true end |
#build_secret(path) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/nutkins.rb', line 200 def build_secret path secret = path path_is_dir = Dir.exists? path if path_is_dir secret += '.tar' system "tar", "cf", secret, "-C", File.dirname(path), File.basename(path) end loop do puts "enter passphrase for #{secret}" break if system 'gpg', '-c', secret end File.unlink secret if path_is_dir end |
#create(path, preserve: false, docker_args: [], reuse: false) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/nutkins.rb', line 98 def create path, preserve: false, docker_args: [], reuse: false flags = [] cfg = get_image_config path create_cfg = cfg["create"] if create_cfg (create_cfg["ports"] or []).each do |port| flags.push '-p', "#{port}:#{port}" end img_dir = cfg['directory'] (create_cfg["volumes"] or []).each do |volume| src, dest = volume.split ' -> ' src_dir = File.absolute_path File.join(img_dir, VOLUMES_PATH, src) unless Dir.exists? src_dir src_dir = File.absolute_path File.join(@project_root, VOLUMES_PATH, src) raise "could not find source directory for volume #{src}" unless Dir.exists? src_dir end flags.push '-v', "#{src_dir}:#{dest}" end (create_cfg["env"] or {}).each do |name, val| flags.push '-e', "#{name}=#{val}" end hostname = create_cfg['hostname'] flags.push '-h', hostname if hostname end tag = cfg['tag'] prev_container_id = Docker.container_id_for_tag tag unless preserve if not reuse if prev_container_id puts "deleting previous container #{prev_container_id}" Docker.run "rm", prev_container_id prev_container_id = nil end build path end puts "creating new docker image" unless Docker.run "create", "-it", *flags, tag, *docker_args raise "failed to create `#{path}' container" end unless preserve container_id = Docker.container_id_for_tag tag if not prev_container_id.nil? and container_id != prev_container_id puts "deleting previous container #{prev_container_id}" Docker.run "rm", prev_container_id end end puts "created `#{path}' container" end |
#delete(path) ⇒ Object
187 188 189 190 191 192 193 194 |
# File 'lib/nutkins.rb', line 187 def delete path cfg = get_image_config path tag = cfg['tag'] container_id = Docker.container_id_for_tag tag raise "no container to delete" if container_id.nil? puts "deleting container #{container_id}" Docker.run "rm", container_id end |
#delete_all ⇒ Object
196 197 198 |
# File 'lib/nutkins.rb', line 196 def delete_all puts "TODO: delete_all" end |
#exec(path, *cmd) ⇒ Object
239 240 241 |
# File 'lib/nutkins.rb', line 239 def exec path, *cmd puts "TODO: exec #{path}: #{cmd.join ' '}" end |
#extract_secrets(paths) ⇒ Object
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/nutkins.rb', line 216 def extract_secrets paths if paths.empty? paths = get_all_img_paths # there may be secrets in the root even if there is no image build there paths.push '.' unless paths.include? '.' end paths.each do |path| get_secrets(path).each do |secret| loop do puts "enter passphrase for #{secret}" break if system 'gpg', secret end secret = secret[0..-5] if File.extname(secret) == '.tar' system "tar", "xf", secret, "-C", File.dirname(secret) File.unlink secret end end end end |
#run(path, reuse: false, shell: false) ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/nutkins.rb', line 154 def run path, reuse: false, shell: false cfg = get_image_config path tag = cfg['tag'] start_etcd_container if cfg['etcd'] create_args = [] if shell raise '--shell and --reuse arguments are incompatible' if reuse # TODO: fix crash when image doesn't exist yet... the tag isn't # there to be inspected yet # TODO: test for smell-baron create_args = JSON.parse(`docker inspect #{tag}`)[0]["Config"]["Cmd"] kill_everything = create_args[0] == '-a' create_args.shift if kill_everything create_args.unshift '/bin/bash', '---' create_args.unshift '-f' unless create_args[0] == '-f' create_args.unshift '-a' if kill_everything # TODO: provide version that doesn't require smell-baron end id = reuse && Docker.container_id_for_tag(tag) unless id create path, docker_args: create_args id = Docker.container_id_for_tag tag raise "couldn't create container to run `#{path}'" unless id end Kernel.exec "docker", "start", "-ai", id end |
#start_etcd_container ⇒ Object
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/nutkins.rb', line 243 def start_etcd_container return if @etcd_running # TODO: move this stuff into another file name = get_etcd_container_name return unless name # TODO: update existing etcd server rather than creating new container... # this will let confd instances respond to updates existing = Docker.container_id_for_name name if existing Docker.run 'stop', name rm_etcd_docker_container existing end gateway = Docker.run_get_stdout 'run', '--rm=true', 'quay.io/coreos/etcd', 'sh', '-c', "route -n | grep UG | awk '{ print $2 }'" Docker.run 'create', '--name', name, '-p', "#{ETCD_PORT}:#{ETCD_PORT}", 'quay.io/coreos/etcd', 'etcd', '-name', name, '-advertise-client-urls', "http://#{gateway}:#{ETCD_PORT}", '-listen-client-urls', "http://0.0.0.0:#{ETCD_PORT}" all_paths = get_all_img_paths configs = all_paths.map &method(:get_image_config) etcd_store = {} configs.each do |config| etcd_store.merge! config['etcd']['data'] if config.dig('etcd', 'data') etcd_files = config.dig('etcd', 'files') if etcd_files etcd_files.each do |file| etcd_data_path = File.join config['directory'], file begin etcd_store.merge! YAML.load_file(etcd_data_path) rescue => e puts "failed to load etcd data file: #{etcd_data_path}" puts e end end end end if Docker.run 'start', name puts 'started etcd container' # even after port is open it still refuses http requests for a while # so just sleep until it is ready... ideally test for working HTTP sleep 1 etcd_store.each do |key, val| uri = URI("http://127.0.0.1:#{ETCD_PORT}/v2/keys/#{key}") req = Net::HTTP::Put.new(uri) req.body = 'value=' + val res = Net::HTTP.start(uri.hostname, uri.port) do |http| http.request(req) end if not res.is_a? Net::HTTPCreated puts "etcd: failed to set #{key} to #{val}" puts res end end @etcd_running = true else puts 'failed to start etcd container' end end |
#stop_etcd_container ⇒ Object
313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/nutkins.rb', line 313 def stop_etcd_container name = get_etcd_container_name return unless name existing = Docker.container_id_for_name name if existing if Docker.run 'stop', name puts 'stopped etcd container' rm_etcd_docker_container existing else puts 'failed to stop etcd container' end end end |