|
| 1 | +require 'aws-sdk' |
| 2 | +require 'net/http' |
| 3 | + |
| 4 | +default_action :create_and_attach |
| 5 | + |
| 6 | +property :description, String |
| 7 | +property :subnet_id, String, required: true |
| 8 | +property :private_ip_address, String |
| 9 | +property :security_groups, Array |
| 10 | +property :network_interface_id, String |
| 11 | + |
| 12 | +action :create_and_attach do |
| 13 | + nic_id_to_attach = network_interface_id || create |
| 14 | + |
| 15 | + if attached_nic_ids.include? nic_id_to_attach |
| 16 | + Chef::Log.debug "NIC with ID #{nic_id_to_attach} is already attached to #{instance_id}" |
| 17 | + else |
| 18 | + converge_by "Attach NIC #{nic_id_to_attach} to #{instance_id} at index #{next_device_index}" do |
| 19 | + ec2.attach_network_interface( |
| 20 | + network_interface_id: nic_id_to_attach, |
| 21 | + instance_id: instance_id, |
| 22 | + device_index: next_device_index |
| 23 | + ) |
| 24 | + end |
| 25 | + end |
| 26 | +end |
| 27 | + |
| 28 | +action :create do |
| 29 | + create |
| 30 | +end |
| 31 | + |
| 32 | +action :delete do |
| 33 | + if existing_nic |
| 34 | + converge_by "Delete the NIC with ID #{existing_nic.network_interface_id}" do |
| 35 | + ec2.delete_network_interface network_interface_id: existing_nic.network_interface_id |
| 36 | + end |
| 37 | + elsif network_interface_id |
| 38 | + Chef::Log.debug "NIC with ID #{network_interface_id} does not exist" |
| 39 | + else |
| 40 | + Chef::Log.debug "NIC with description \"#{description}\" does not exist" |
| 41 | + end |
| 42 | +end |
| 43 | + |
| 44 | +private |
| 45 | + |
| 46 | +def create |
| 47 | + if existing_nic_id |
| 48 | + Chef::Log.debug("NIC already exists: #{existing_nic.network_interface_id}/#{description}") |
| 49 | + return existing_nic.network_interface_id |
| 50 | + end |
| 51 | + |
| 52 | + converge_by "Create new NIC in description: #{description}, subnet_id: #{subnet_id}" do |
| 53 | + options = {} |
| 54 | + |
| 55 | + %w(subnet_id private_ip_address security_groups).each do |prop| |
| 56 | + next unless send prop |
| 57 | + options[prop.to_sym] = send(prop) |
| 58 | + end |
| 59 | + |
| 60 | + ec2.create_network_interface(options).network_interface.network_interface_id |
| 61 | + end |
| 62 | +end |
| 63 | + |
| 64 | +def existing_nic |
| 65 | + @existing_nic ||= begin |
| 66 | + # Use the ID to look up the adapter if we have it |
| 67 | + return ec2.describe_network_interfaces( |
| 68 | + network_interface_id: network_interface_id |
| 69 | + ).network_interfaces.first if network_interface_id |
| 70 | + |
| 71 | + # Otherwise use the description |
| 72 | + results = ec2.describe_network_interfaces( |
| 73 | + filters: [{ name: 'description', values: [description] }] |
| 74 | + ).network_interfaces |
| 75 | + |
| 76 | + # Multiple NICs with the same description == problems |
| 77 | + if results.count > 1 |
| 78 | + fail "More than one NIC matches the description \"#{description}\": " \ |
| 79 | + "#{results.map(&:network_interface_id).join ', '}" |
| 80 | + end |
| 81 | + |
| 82 | + results.first |
| 83 | + end |
| 84 | +end |
| 85 | + |
| 86 | +def ec2 |
| 87 | + @ec2 ||= AWS::EC2::Client.new |
| 88 | +end |
| 89 | + |
| 90 | +def instance_id |
| 91 | + @instance_id ||= Net::HTTP.get URI 'http://169.254.169.254/2016-09-02/meta-data/instance-id' |
| 92 | +end |
| 93 | + |
| 94 | +def next_device_index |
| 95 | + @next_device_index ||= begin |
| 96 | + device_numbers = macs.map do |mac| |
| 97 | + Net::HTTP.get( |
| 98 | + URI "http://169.254.169.254/2016-09-02/meta-data/network/interfaces/macs/#{mac}/device-number" |
| 99 | + ).to_i |
| 100 | + end |
| 101 | + |
| 102 | + device_numbers.sort.last + 1 |
| 103 | + end |
| 104 | +end |
| 105 | + |
| 106 | +def macs |
| 107 | + @macs ||= Net::HTTP.get( |
| 108 | + URI 'http://169.254.169.254/2016-09-02/meta-data/network/interfaces/macs/' |
| 109 | + ).delete('/').split("\n") |
| 110 | +end |
| 111 | + |
| 112 | +def attached_nic_ids |
| 113 | + @attached_nic_ids ||= begin |
| 114 | + macs.map do |mac| |
| 115 | + Net::HTTP.get( |
| 116 | + URI "http://169.254.169.254/2016-09-02/meta-data/network/interfaces/macs/#{mac}" \ |
| 117 | + '/interface-id' |
| 118 | + ) |
| 119 | + end |
| 120 | + end |
| 121 | +end |
0 commit comments