|
| 1 | +class CreateStackJob < DockerApiJob |
| 2 | + queue_as :default |
| 3 | + |
| 4 | + # Takes hash: challenge |
| 5 | + # user_id |
| 6 | + # problem_id |
| 7 | + # network |
| 8 | + # containers |
| 9 | + # lifespan |
| 10 | + def perform(challenge) |
| 11 | + check_existing(challenge) |
| 12 | + create_stack(challenge) |
| 13 | + end |
| 14 | + |
| 15 | + private |
| 16 | + def check_existing(challenge) |
| 17 | + containers = docker_get_containers(challenge) |
| 18 | + networks = docker_get_networks(challenge) |
| 19 | + |
| 20 | + if networks.length > 0 or containers.length > 0 |
| 21 | + user_id = challenge['user_id'] |
| 22 | + User.find(user_id).update_attribute(:container_id, '') |
| 23 | + User.find(user_id).update_attribute(:stack_expiry, DateTime.now) |
| 24 | + User.find(user_id).update_attribute(:problem_id, -1) |
| 25 | + delete_stack(containers, networks) |
| 26 | + end |
| 27 | + end |
| 28 | + |
| 29 | + def create_stack(challenge) |
| 30 | + # Start with network (Name: problem_id-user_id) |
| 31 | + network = JSON(challenge['network']) |
| 32 | + network['Name'] = "hta-#{challenge['problem_id']}-#{challenge['user_id']}" |
| 33 | + network['Labels'] = { |
| 34 | + "user_id" => "#{challenge['user_id']}", |
| 35 | + "problem_id" => "#{challenge['problem_id']}", |
| 36 | + "lifetime" => "#{challenge['lifespan']}" |
| 37 | + } |
| 38 | + res = docker_post_request('/networks/create', network.to_json) |
| 39 | + network_id = JSON(res.body)["Id"] |
| 40 | + |
| 41 | + if res.code != '201' |
| 42 | + raise Exception.new("Couldn't create challenge network.") |
| 43 | + end |
| 44 | + |
| 45 | + # Then build containers |
| 46 | + containers = JSON(challenge['containers']) |
| 47 | + containers.each do |container| |
| 48 | + container['Labels'] = { |
| 49 | + "user_id" => "#{challenge['user_id']}", |
| 50 | + "problem_id" => "#{challenge['problem_id']}", |
| 51 | + "lifetime" => "#{challenge['lifespan']}" |
| 52 | + } |
| 53 | + |
| 54 | + # Make sure the container is reachable by its designed name |
| 55 | + container['Networks'] = [{ |
| 56 | + "Target": network_id, |
| 57 | + "Aliases": [ |
| 58 | + container['Name'], |
| 59 | + container['Name'].gsub("-","."), |
| 60 | + ] |
| 61 | + }] |
| 62 | + |
| 63 | + # find entrypoint |
| 64 | + is_entry = false |
| 65 | + if container['Name'].downcase == "entrypoint" |
| 66 | + is_entry = true |
| 67 | + end |
| 68 | + |
| 69 | + # Add user_id to container name for identification |
| 70 | + container_name = container['Name'] |
| 71 | + container['Name'] = "hta-#{container_name}-#{challenge['user_id']}" |
| 72 | + |
| 73 | + res = docker_post_request('/services/create', container.to_json) |
| 74 | + if res.code != '201' |
| 75 | + raise Exception.new("Couldn't create challenge containers.") |
| 76 | + end |
| 77 | + |
| 78 | + # If container is entry point, assign to user |
| 79 | + if is_entry |
| 80 | + id = JSON(res.body)["ID"] |
| 81 | + User.find(challenge['user_id']).update_attribute(:container_id, id) |
| 82 | + User.find(challenge['user_id']).update_attribute(:stack_expiry, DateTime.now + Integer(challenge['lifespan']).minutes) |
| 83 | + User.find(challenge['user_id']).update_attribute(:problem_id, challenge['problem_id']) |
| 84 | + end |
| 85 | + end |
| 86 | + end |
| 87 | + |
| 88 | +end |
0 commit comments