From 7927c95553c4c696baa8a6f987bfe813a4a0a68e Mon Sep 17 00:00:00 2001 From: Alejandro Huertas Herrero Date: Wed, 19 May 2021 12:24:19 +0200 Subject: [PATCH] F #5387: add Vultr support into OneProvision (#1229) --- install.sh | 62 +++-- share/etc/oned.conf | 3 +- .../ansible/roles/networking/README.md | 20 ++ .../roles/networking/defaults/main.yml | 9 + .../roles/networking/handlers/main.yml | 6 + .../ansible/roles/networking/tasks/main.yml | 13 ++ .../roles/networking/templates/ifcfg.j2 | 6 + share/oneprovision/ansible/vultr.yml | 28 +++ .../metal/providers/vultr/vultr-ams.yml | 23 ++ .../metal/providers/vultr/vultr-ord.yml | 23 ++ .../metal/providers/vultr/vultr-sjc.yml | 23 ++ .../metal/provisions/vultr.d/datastores.yml | 40 ++++ .../metal/provisions/vultr.d/fireedge.yml | 20 ++ .../metal/provisions/vultr.d/inputs.yml | 53 +++++ .../metal/provisions/vultr.d/networks.yml | 41 ++++ .../edge-clusters/metal/provisions/vultr.yml | 65 ++++++ .../virtual/providers/vultr/vultr-ams.yml | 25 +++ .../virtual/providers/vultr/vultr-lhr.yml | 25 +++ .../virtual/providers/vultr/vultr-ord.yml | 25 +++ .../virtual/providers/vultr/vultr-sjc.yml | 25 +++ .../virtual/provisions/vultr.d/datastores.yml | 40 ++++ .../virtual/provisions/vultr.d/fireedge.yml | 20 ++ .../virtual/provisions/vultr.d/inputs.yml | 52 +++++ .../virtual/provisions/vultr.d/networks.yml | 41 ++++ .../virtual/provisions/vultr.yml | 65 ++++++ share/vendor/ruby/gems/vultr/lib/vultr.rb | 212 ++++++++++++++++++ src/ipamm_mad/remotes/vultr/allocate_address | 21 ++ src/ipamm_mad/remotes/vultr/free_address | 21 ++ src/ipamm_mad/remotes/vultr/get_address | 99 ++++++++ .../remotes/vultr/register_address_range | 204 +++++++++++++++++ .../remotes/vultr/unregister_address_range | 121 ++++++++++ src/oneprovision/lib/provision/ansible.rb | 8 +- src/oneprovision/lib/provision/provision.rb | 9 +- src/oneprovision/lib/terraform/providers.rb | 3 + .../templates/vultr_metal/cluster.erb | 0 .../templates/vultr_metal/datastore.erb | 0 .../providers/templates/vultr_metal/host.erb | 23 ++ .../templates/vultr_metal/network.erb | 0 .../templates/vultr_metal/provider.erb | 14 ++ .../templates/vultr_virtual/cluster.erb | 5 + .../templates/vultr_virtual/datastore.erb | 0 .../templates/vultr_virtual/host.erb | 24 ++ .../templates/vultr_virtual/network.erb | 0 .../templates/vultr_virtual/provider.erb | 14 ++ .../lib/terraform/providers/vultr.rb | 95 ++++++++ .../lib/terraform/providers/vultr_metal.rb | 46 ++++ .../lib/terraform/providers/vultr_virtual.rb | 46 ++++ src/oneprovision/lib/terraform/terraform.rb | 14 +- src/vnm_mad/remotes/elastic/aws_vnm.rb | 2 +- src/vnm_mad/remotes/elastic/elastic.rb | 28 ++- src/vnm_mad/remotes/elastic/packet_vnm.rb | 27 ++- src/vnm_mad/remotes/elastic/vultr_vnm.rb | 124 ++++++++++ 52 files changed, 1874 insertions(+), 39 deletions(-) create mode 100644 share/oneprovision/ansible/roles/networking/README.md create mode 100644 share/oneprovision/ansible/roles/networking/defaults/main.yml create mode 100644 share/oneprovision/ansible/roles/networking/handlers/main.yml create mode 100644 share/oneprovision/ansible/roles/networking/tasks/main.yml create mode 100644 share/oneprovision/ansible/roles/networking/templates/ifcfg.j2 create mode 100644 share/oneprovision/ansible/vultr.yml create mode 100644 share/oneprovision/edge-clusters/metal/providers/vultr/vultr-ams.yml create mode 100644 share/oneprovision/edge-clusters/metal/providers/vultr/vultr-ord.yml create mode 100644 share/oneprovision/edge-clusters/metal/providers/vultr/vultr-sjc.yml create mode 100644 share/oneprovision/edge-clusters/metal/provisions/vultr.d/datastores.yml create mode 100644 share/oneprovision/edge-clusters/metal/provisions/vultr.d/fireedge.yml create mode 100644 share/oneprovision/edge-clusters/metal/provisions/vultr.d/inputs.yml create mode 100644 share/oneprovision/edge-clusters/metal/provisions/vultr.d/networks.yml create mode 100644 share/oneprovision/edge-clusters/metal/provisions/vultr.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-ams.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-lhr.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-ord.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-sjc.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/vultr.d/datastores.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/vultr.d/fireedge.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/vultr.d/inputs.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/vultr.d/networks.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/vultr.yml create mode 100644 share/vendor/ruby/gems/vultr/lib/vultr.rb create mode 100755 src/ipamm_mad/remotes/vultr/allocate_address create mode 100755 src/ipamm_mad/remotes/vultr/free_address create mode 100755 src/ipamm_mad/remotes/vultr/get_address create mode 100755 src/ipamm_mad/remotes/vultr/register_address_range create mode 100755 src/ipamm_mad/remotes/vultr/unregister_address_range create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_metal/cluster.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_metal/datastore.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_metal/host.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_metal/network.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_metal/provider.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_virtual/cluster.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_virtual/datastore.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_virtual/host.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_virtual/network.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/vultr_virtual/provider.erb create mode 100644 src/oneprovision/lib/terraform/providers/vultr.rb create mode 100644 src/oneprovision/lib/terraform/providers/vultr_metal.rb create mode 100644 src/oneprovision/lib/terraform/providers/vultr_virtual.rb create mode 100644 src/vnm_mad/remotes/elastic/vultr_vnm.rb diff --git a/install.sh b/install.sh index f355f0ca3e..b40ebfc8de 100755 --- a/install.sh +++ b/install.sh @@ -299,6 +299,8 @@ LIB_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/oneprovision/lib/terraform/providers/templates/google \ $LIB_LOCATION/oneprovision/lib/terraform/providers/templates/digitalocean \ $LIB_LOCATION/oneprovision/lib/terraform/providers/templates/packet \ + $LIB_LOCATION/oneprovision/lib/terraform/providers/templates/vultr_metal \ + $LIB_LOCATION/oneprovision/lib/terraform/providers/templates/vultr_virtual \ $LIB_LOCATION/oneprovision/lib/provision \ $LIB_LOCATION/oneprovision/lib/provision_template \ $LIB_LOCATION/oneprovision/lib/provider \ @@ -501,6 +503,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/auth/dummy \ $VAR_LOCATION/remotes/ipam/dummy \ $VAR_LOCATION/remotes/ipam/packet \ + $VAR_LOCATION/remotes/ipam/vultr \ $VAR_LOCATION/remotes/ipam/aws" SUNSTONE_DIRS="$SUNSTONE_LOCATION/routes \ @@ -712,6 +715,7 @@ INSTALL_FILES=( MARKETPLACE_DRIVER_DH_SCRIPTS:$VAR_LOCATION/remotes/market/dockerhub IPAM_DRIVER_DUMMY_SCRIPTS:$VAR_LOCATION/remotes/ipam/dummy IPAM_DRIVER_PACKET_SCRIPTS:$VAR_LOCATION/remotes/ipam/packet + IPAM_DRIVER_VULTR_SCRIPTS:$VAR_LOCATION/remotes/ipam/vultr IPAM_DRIVER_EC2_SCRIPTS:$VAR_LOCATION/remotes/ipam/aws NETWORK_FILES:$VAR_LOCATION/remotes/vnm NETWORK_HOOKS_PRE_FILES:$VAR_LOCATION/remotes/vnm/hooks/pre @@ -786,6 +790,8 @@ INSTALL_ONEPROVISION_FILES=( ONEPROVISION_LIB_GOOGLE_ERB_FILES:$LIB_LOCATION/oneprovision/lib/terraform/providers/templates/google ONEPROVISION_LIB_DIGITALOCEAN_ERB_FILES:$LIB_LOCATION/oneprovision/lib/terraform/providers/templates/digitalocean ONEPROVISION_LIB_PACKET_ERB_FILES:$LIB_LOCATION/oneprovision/lib/terraform/providers/templates/packet + ONEPROVISION_LIB_VULTR_METAL_ERB_FILES:$LIB_LOCATION/oneprovision/lib/terraform/providers/templates/vultr_metal + ONEPROVISION_LIB_VULTR_VIRTUAL_ERB_FILES:$LIB_LOCATION/oneprovision/lib/terraform/providers/templates/vultr_virtual ONEPROVISION_LIB_PROVISION_FILES:$LIB_LOCATION/oneprovision/lib/provision ONEPROVISION_LIB_RESOURCES_FILES:$LIB_LOCATION/oneprovision/lib/provision/resources ONEPROVISION_LIB_PHYSICAL_R_FILES:$LIB_LOCATION/oneprovision/lib/provision/resources/physical @@ -992,7 +998,8 @@ RUBY_LIB_FILES="src/mad/ruby/ActionManager.rb \ src/vmm_mad/remotes/one/opennebula_driver.rb \ src/vmm_mad/remotes/packet/packet_driver.rb \ src/vnm_mad/remotes/elastic/aws_vnm.rb \ - src/vnm_mad/remotes/elastic/packet_vnm.rb" + src/vnm_mad/remotes/elastic/packet_vnm.rb \ + src/vnm_mad/remotes/elastic/vultr_vnm.rb" #------------------------------------------------------------------------------- # Ruby auth library files, to be installed under $LIB_LOCATION/ruby/opennebula @@ -1767,28 +1774,37 @@ NETWORK_ETC_FILES="src/vnm_mad/remotes/OpenNebulaNetwork.conf" # IPAM dummy drivers to be installed under $REMOTES_LOCATION/ipam #------------------------------------------------------------------------------- IPAM_DRIVER_DUMMY_SCRIPTS="src/ipamm_mad/remotes/dummy/register_address_range \ - src/ipamm_mad/remotes/dummy/unregister_address_range \ - src/ipamm_mad/remotes/dummy/allocate_address \ - src/ipamm_mad/remotes/dummy/get_address \ - src/ipamm_mad/remotes/dummy/free_address" + src/ipamm_mad/remotes/dummy/unregister_address_range \ + src/ipamm_mad/remotes/dummy/allocate_address \ + src/ipamm_mad/remotes/dummy/get_address \ + src/ipamm_mad/remotes/dummy/free_address" #------------------------------------------------------------------------------- # IPAM Packet drivers to be installed under $REMOTES_LOCATION/ipam #------------------------------------------------------------------------------- IPAM_DRIVER_PACKET_SCRIPTS="src/ipamm_mad/remotes/packet/register_address_range \ - src/ipamm_mad/remotes/packet/unregister_address_range \ - src/ipamm_mad/remotes/packet/allocate_address \ - src/ipamm_mad/remotes/packet/get_address \ - src/ipamm_mad/remotes/packet/free_address" + src/ipamm_mad/remotes/packet/unregister_address_range \ + src/ipamm_mad/remotes/packet/allocate_address \ + src/ipamm_mad/remotes/packet/get_address \ + src/ipamm_mad/remotes/packet/free_address" + +#------------------------------------------------------------------------------- +# IPAM Vultr drivers to be installed under $REMOTES_LOCATION/ipam +#------------------------------------------------------------------------------- +IPAM_DRIVER_VULTR_SCRIPTS="src/ipamm_mad/remotes/vultr/register_address_range \ + src/ipamm_mad/remotes/vultr/unregister_address_range \ + src/ipamm_mad/remotes/vultr/allocate_address \ + src/ipamm_mad/remotes/vultr/get_address \ + src/ipamm_mad/remotes/vultr/free_address" #------------------------------------------------------------------------------- # IPAM EC2 drivers to be installed under $REMOTES_LOCATION/ipam #------------------------------------------------------------------------------- IPAM_DRIVER_EC2_SCRIPTS="src/ipamm_mad/remotes/aws/register_address_range \ - src/ipamm_mad/remotes/aws/unregister_address_range \ - src/ipamm_mad/remotes/aws/allocate_address \ - src/ipamm_mad/remotes/aws/get_address \ - src/ipamm_mad/remotes/aws/free_address" + src/ipamm_mad/remotes/aws/unregister_address_range \ + src/ipamm_mad/remotes/aws/allocate_address \ + src/ipamm_mad/remotes/aws/get_address \ + src/ipamm_mad/remotes/aws/free_address" #------------------------------------------------------------------------------- # Transfer Manager commands, to be installed under $LIB_LOCATION/tm_commands @@ -2515,7 +2531,10 @@ ONEPROVISION_LIB_PROVIDERS_FILES="src/oneprovision/lib/terraform/providers/aws.r src/oneprovision/lib/terraform/providers/google.rb \ src/oneprovision/lib/terraform/providers/digitalocean.rb \ src/oneprovision/lib/terraform/providers/dummy.rb \ - src/oneprovision/lib/terraform/providers/packet.rb" + src/oneprovision/lib/terraform/providers/packet.rb \ + src/oneprovision/lib/terraform/providers/vultr.rb \ + src/oneprovision/lib/terraform/providers/vultr_metal.rb \ + src/oneprovision/lib/terraform/providers/vultr_virtual.rb" ONEPROVISION_LIB_AWS_ERB_FILES="src/oneprovision/lib/terraform/providers/templates/aws/cluster.erb \ src/oneprovision/lib/terraform/providers/templates/aws/datastore.erb \ @@ -2541,6 +2560,18 @@ ONEPROVISION_LIB_PACKET_ERB_FILES="src/oneprovision/lib/terraform/providers/temp src/oneprovision/lib/terraform/providers/templates/packet/network.erb \ src/oneprovision/lib/terraform/providers/templates/packet/provider.erb" +ONEPROVISION_LIB_VULTR_METAL_ERB_FILES="src/oneprovision/lib/terraform/providers/templates/vultr_metal/cluster.erb \ + src/oneprovision/lib/terraform/providers/templates/vultr_metal/datastore.erb \ + src/oneprovision/lib/terraform/providers/templates/vultr_metal/host.erb \ + src/oneprovision/lib/terraform/providers/templates/vultr_metal/network.erb \ + src/oneprovision/lib/terraform/providers/templates/vultr_metal/provider.erb" + +ONEPROVISION_LIB_VULTR_VIRTUAL_ERB_FILES="src/oneprovision/lib/terraform/providers/templates/vultr_virtual/cluster.erb \ + src/oneprovision/lib/terraform/providers/templates/vultr_virtual/datastore.erb \ + src/oneprovision/lib/terraform/providers/templates/vultr_virtual/host.erb \ + src/oneprovision/lib/terraform/providers/templates/vultr_virtual/network.erb \ + src/oneprovision/lib/terraform/providers/templates/vultr_virtual/provider.erb" + #----------------------------------------------------------------------------- # Sunstone files #----------------------------------------------------------------------------- @@ -2925,7 +2956,8 @@ DOCS_FILES="LICENSE LICENSE.onsla LICENSE.onsla-nc NOTICE README.md" # Ruby VENDOR files #----------------------------------------------------------------------------- -VENDOR_DIRS="share/vendor/ruby/gems/packethost" +VENDOR_DIRS="share/vendor/ruby/gems/packethost \ + share/vendor/ruby/gems/vultr" #------------------------------------------------------------------------------- # Libvirt RelaxNG schemas diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 67699fa0bb..f257d78d3a 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -668,7 +668,7 @@ MARKET_MAD = [ IPAM_MAD = [ EXECUTABLE = "one_ipam", - ARGUMENTS = "-t 1 -i dummy,aws,packet" + ARGUMENTS = "-t 1 -i dummy,aws,packet,vultr" ] #******************************************************************************* @@ -1068,6 +1068,7 @@ INHERIT_VNET_ATTR = "IP_LINK_CONF" INHERIT_VNET_ATTR = "EXTERNAL_IP" INHERIT_VNET_ATTR = "EXTERNAL" INHERIT_VNET_ATTR = "AWS_ALLOCATION_ID" +INHERIT_VNET_ATTR = "VULTR_IP_ID" INHERIT_VNET_ATTR = "GATEWAY" INHERIT_VNET_ATTR = "VXLAN_MODE" INHERIT_VNET_ATTR = "VXLAN_TEP" diff --git a/share/oneprovision/ansible/roles/networking/README.md b/share/oneprovision/ansible/roles/networking/README.md new file mode 100644 index 0000000000..2bca1a9975 --- /dev/null +++ b/share/oneprovision/ansible/roles/networking/README.md @@ -0,0 +1,20 @@ +# networking + +## Description + +Configures static IP address for network interface. + +These changes are persistent. + +## Requirements + +No special requirements. + +## Variables + +All of the variables in this role are documented in the [defaults](defaults/main.yml) file. + +## Todo list + +None + diff --git a/share/oneprovision/ansible/roles/networking/defaults/main.yml b/share/oneprovision/ansible/roles/networking/defaults/main.yml new file mode 100644 index 0000000000..014028ddcd --- /dev/null +++ b/share/oneprovision/ansible/roles/networking/defaults/main.yml @@ -0,0 +1,9 @@ +################################################################################ +# Mandatory +################################################################################ + +# The network device to configure +networking_iface: 'ens7' + +# Netmask of the interface +networking_prefix: 20 diff --git a/share/oneprovision/ansible/roles/networking/handlers/main.yml b/share/oneprovision/ansible/roles/networking/handlers/main.yml new file mode 100644 index 0000000000..10ca0d77a6 --- /dev/null +++ b/share/oneprovision/ansible/roles/networking/handlers/main.yml @@ -0,0 +1,6 @@ +--- + +- name: restart network + service: + name: network + state: restarted diff --git a/share/oneprovision/ansible/roles/networking/tasks/main.yml b/share/oneprovision/ansible/roles/networking/tasks/main.yml new file mode 100644 index 0000000000..8a589d752b --- /dev/null +++ b/share/oneprovision/ansible/roles/networking/tasks/main.yml @@ -0,0 +1,13 @@ +--- + +- name: Configuration for bridge + template: + src: ifcfg.j2 + dest: /etc/sysconfig/network-scripts/ifcfg-{{ networking_iface }} + notify: restart network + +- name: Force all notified handlers to run now + meta: flush_handlers + +- name: Refresh facts + setup: diff --git a/share/oneprovision/ansible/roles/networking/templates/ifcfg.j2 b/share/oneprovision/ansible/roles/networking/templates/ifcfg.j2 new file mode 100644 index 0000000000..cbe89ec60a --- /dev/null +++ b/share/oneprovision/ansible/roles/networking/templates/ifcfg.j2 @@ -0,0 +1,6 @@ +DEVICE={{ networking_iface }} +BOOTPROTO=static +ONBOOT=yes +NM_CONTROLLED=no +IPADDR={{ private_ip }} +PREFIX={{ networking_prefix }} diff --git a/share/oneprovision/ansible/vultr.yml b/share/oneprovision/ansible/vultr.yml new file mode 100644 index 0000000000..18cfd41280 --- /dev/null +++ b/share/oneprovision/ansible/vultr.yml @@ -0,0 +1,28 @@ +--- + +- hosts: all + gather_facts: false + roles: + - python + +- hosts: nodes + roles: + - networking + - ddc + - opennebula-repository + - { role: opennebula-node-kvm, when: oneprovision_hypervisor == 'kvm' or oneprovision_hypervisor == 'qemu' } + - { role: opennebula-node-firecracker, when: oneprovision_hypervisor == 'firecracker' } + - { role: opennebula-node-lxc, when: oneprovision_hypervisor == 'lxc' } + - opennebula-ssh + - role: iptables + iptables_base_rules_services: + - { protocol: 'tcp', port: 22 } + # TCP/179 bgpd (TODO: only needed on Route Refector(s)) + - { protocol: 'tcp', port: 179 } + # TCP/8742 default VXLAN port on Linux (UDP/4789 default IANA) + - { protocol: 'udp', port: 8472 } + - update-replica + - role: frr + frr_iface: 'ens7' + # Use /20 for the internal management network address + frr_prefix_length: 20 diff --git a/share/oneprovision/edge-clusters/metal/providers/vultr/vultr-ams.yml b/share/oneprovision/edge-clusters/metal/providers/vultr/vultr-ams.yml new file mode 100644 index 0000000000..1259b5a93e --- /dev/null +++ b/share/oneprovision/edge-clusters/metal/providers/vultr/vultr-ams.yml @@ -0,0 +1,23 @@ +name: 'vultr-amsterdam' + +description: 'Edge cluster in Vultr Amsterdam' +provider: 'vultr_metal' + +plain: + image: 'VULTR' + location_key: 'region' + provision_type: 'metal' + +connection: + key: 'Vultr key' + region: 'ams' + +inputs: + - name: 'vultr_os' + type: 'list' + options: + - '362' + - name: 'vultr_plan' + type: 'list' + options: + - 'vbm-8c-132gb' diff --git a/share/oneprovision/edge-clusters/metal/providers/vultr/vultr-ord.yml b/share/oneprovision/edge-clusters/metal/providers/vultr/vultr-ord.yml new file mode 100644 index 0000000000..f1b6ff1b64 --- /dev/null +++ b/share/oneprovision/edge-clusters/metal/providers/vultr/vultr-ord.yml @@ -0,0 +1,23 @@ +name: 'vultr-chicago' + +description: 'Edge cluster in Vultr Chicago' +provider: 'vultr_metal' + +plain: + image: 'VULTR' + location_key: 'region' + provision_type: 'metal' + +connection: + key: 'Vultr key' + region: 'ord' + +inputs: + - name: 'vultr_os' + type: 'list' + options: + - '362' + - name: 'vultr_plan' + type: 'list' + options: + - 'vbm-8c-132gb' diff --git a/share/oneprovision/edge-clusters/metal/providers/vultr/vultr-sjc.yml b/share/oneprovision/edge-clusters/metal/providers/vultr/vultr-sjc.yml new file mode 100644 index 0000000000..23c1f6ca71 --- /dev/null +++ b/share/oneprovision/edge-clusters/metal/providers/vultr/vultr-sjc.yml @@ -0,0 +1,23 @@ +name: 'vultr-san-francisco' + +description: 'Edge cluster in Vultr San Francisco' +provider: 'vultr_metal' + +plain: + image: 'VULTR' + location_key: 'region' + provision_type: 'metal' + +connection: + key: 'Vultr key' + region: 'sjc' + +inputs: + - name: 'vultr_os' + type: 'list' + options: + - '362' + - name: 'vultr_plan' + type: 'list' + options: + - 'vbm-8c-132gb' diff --git a/share/oneprovision/edge-clusters/metal/provisions/vultr.d/datastores.yml b/share/oneprovision/edge-clusters/metal/provisions/vultr.d/datastores.yml new file mode 100644 index 0000000000..d1dda640fe --- /dev/null +++ b/share/oneprovision/edge-clusters/metal/provisions/vultr.d/datastores.yml @@ -0,0 +1,40 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +#------------------------------------------------------------------------------- +# datastores: Defines the storage area for the cluster using the SSH replication +# drivers. It creates the following datastores, using Replica driver: +# 1. Image datastore, ${cluster_name}-image +# 2. System datastore, ${cluster_name}-system +# 3. File datastore, ${cluster_name}-files +# +# Configuration/Input attributes: +# - replica_host: The host that will hold the cluster replicas and snapshots. +#------------------------------------------------------------------------------- +datastores: + + - name: "${provision}-image" + type: 'image_ds' + ds_mad: 'fs' + tm_mad: 'ssh' + safe_dirs: "/var/tmp /tmp" + + - name: "${provision}-system" + type: 'system_ds' + tm_mad: 'ssh' + safe_dirs: "/var/tmp /tmp" + replica_host: "use-first-host" diff --git a/share/oneprovision/edge-clusters/metal/provisions/vultr.d/fireedge.yml b/share/oneprovision/edge-clusters/metal/provisions/vultr.d/fireedge.yml new file mode 100644 index 0000000000..b2ca512b42 --- /dev/null +++ b/share/oneprovision/edge-clusters/metal/provisions/vultr.d/fireedge.yml @@ -0,0 +1,20 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +image: 'OPENNEBULA-VULTR' +provider: 'vultr_metal' +provision_type: 'metal' diff --git a/share/oneprovision/edge-clusters/metal/provisions/vultr.d/inputs.yml b/share/oneprovision/edge-clusters/metal/provisions/vultr.d/inputs.yml new file mode 100644 index 0000000000..6035de64e4 --- /dev/null +++ b/share/oneprovision/edge-clusters/metal/provisions/vultr.d/inputs.yml @@ -0,0 +1,53 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +inputs: + - name: 'number_hosts' + type: text + description: "Number of metal servers to create" + default: '1' + + - name: 'number_public_ips' + type: text + description: 'Number of public IPs to get' + default: '1' + + - name: 'dns' + type: text + description: 'Comma separated list of DNS servers for public network' + default: '1.1.1.1' + + - name: 'vultr_plan' + type: text + description: "Vultr plan (device type)" + default: 'vc2-1c-1gb' + + - name: 'vultr_os' + type: text + description: "Vultr host operating system" + default: '362' + + - name: 'one_hypervisor' + type: list + description: "Virtualization technology for the cluster hosts" + options: + - 'kvm' + - 'firecracker' + - 'lxc' + default: 'kvm' + +... diff --git a/share/oneprovision/edge-clusters/metal/provisions/vultr.d/networks.yml b/share/oneprovision/edge-clusters/metal/provisions/vultr.d/networks.yml new file mode 100644 index 0000000000..887e4a75f2 --- /dev/null +++ b/share/oneprovision/edge-clusters/metal/provisions/vultr.d/networks.yml @@ -0,0 +1,41 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +networks: + - name: "${provision}-public" + vn_mad: 'elastic' + bridge: 'br0' + netrole: 'public' + dns: "${input.dns}" + provision: + count: "${input.number_public_ips}" + ar: + - provison_id: "${provision_id}" + size: '1' + vultr_ip_type: 'v4' + ipam_mad: 'vultr' + +vntemplates: + - name: "${provision}-private" + vn_mad: 'vxlan' + phydev: 'ens7' + automatic_vlan_id: 'yes' + netrole: 'private' + vxlan_mode: 'evpn' + vxlan_tep: 'dev' + ip_link_conf: 'nolearning=' + cluster_ids: "${cluster.0.id}" diff --git a/share/oneprovision/edge-clusters/metal/provisions/vultr.yml b/share/oneprovision/edge-clusters/metal/provisions/vultr.yml new file mode 100644 index 0000000000..7f1f9d460a --- /dev/null +++ b/share/oneprovision/edge-clusters/metal/provisions/vultr.yml @@ -0,0 +1,65 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +#------------------------------------------------------------------------------- +# This is the canonical description file for a cluster build with 'Vultr' +# resources using the KVM hypervisor. +# ------------------------------------------------------------------------------ + +name: 'vultr_metal-cluster' + +extends: + - common.d/defaults.yml + - common.d/resources.yml + - common.d/hosts.yml + - vultr.d/datastores.yml + - vultr.d/fireedge.yml + - vultr.d/inputs.yml + - vultr.d/networks.yml + +#------------------------------------------------------------------------------- +# playbook: Ansible playbook used for hosts configuration. Check +# ansible/vultr.yml for the specific roles applied. +#------------------------------------------------------------------------------- +playbook: + - vultr + +#------------------------------------------------------------------------------- +# defaults: Common configuration attributes for provision objects +#-------------------------------------------------------------------------------- +defaults: + provision: + provider_name: 'vultr_metal' + plan: "${input.vultr_plan}" + os: "${input.vultr_os}" + +#------------------------------------------------------------------------------- +# cluster: Parameters for the OpenNebula cluster. Applies to all the Hosts +#-------------------------------------------------------------------------------- +# name: of the cluster +# description: Additional information +# reserved_cpu: In percentage. It will be subtracted from the TOTAL CPU +# reserved_memory: In percentage. It will be subtracted from the TOTAL MEM +#-------------------------------------------------------------------------------- +cluster: + name: "${provision}" + description: 'Vultr edge cluster' + datastores: + - 1 + - 2 + reserved_cpu: '0' + reserved_mem: '0' diff --git a/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-ams.yml b/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-ams.yml new file mode 100644 index 0000000000..a602089ba8 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-ams.yml @@ -0,0 +1,25 @@ +name: 'vultr-amsterdam' + +description: 'Edge cluster in Vultr Amsterdam' +provider: 'vultr_virtual' + +plain: + image: 'VULTR' + location_key: 'region' + provision_type: 'virtual' + +connection: + key: 'Vultr key' + region: 'ams' + +inputs: + - name: 'vultr_os' + type: 'list' + options: + - '362' + - name: 'vultr_plan' + type: 'list' + options: + - 'vc2-1c-1gb' + - 'vc2-1c-2gb' + - 'vc2-1c-4gb' diff --git a/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-lhr.yml b/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-lhr.yml new file mode 100644 index 0000000000..2b17255889 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-lhr.yml @@ -0,0 +1,25 @@ +name: 'vultr-london' + +description: 'Edge cluster in Vultr London' +provider: 'vultr_virtual' + +plain: + image: 'VULTR' + location_key: 'region' + provision_type: 'virtual' + +connection: + key: 'Vultr key' + region: 'lhr' + +inputs: + - name: 'vultr_os' + type: 'list' + options: + - '362' + - name: 'vultr_plan' + type: 'list' + options: + - 'vc2-1c-1gb' + - 'vc2-1c-2gb' + - 'vc2-1c-4gb' diff --git a/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-ord.yml b/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-ord.yml new file mode 100644 index 0000000000..e498dd223e --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-ord.yml @@ -0,0 +1,25 @@ +name: 'vultr-chicago' + +description: 'Edge cluster in Vultr Chicago' +provider: 'vultr_virtual' + +plain: + image: 'VULTR' + location_key: 'region' + provision_type: 'virtual' + +connection: + key: 'Vultr key' + region: 'ord' + +inputs: + - name: 'vultr_os' + type: 'list' + options: + - '362' + - name: 'vultr_plan' + type: 'list' + options: + - 'vc2-1c-1gb' + - 'vc2-1c-2gb' + - 'vc2-1c-4gb' diff --git a/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-sjc.yml b/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-sjc.yml new file mode 100644 index 0000000000..7dd7bf21d9 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/vultr/vultr-sjc.yml @@ -0,0 +1,25 @@ +name: 'vultr-san-francisco' + +description: 'Edge cluster in Vultr San Francisco' +provider: 'vultr_virtual' + +plain: + image: 'VULTR' + location_key: 'region' + provision_type: 'virtual' + +connection: + key: 'Vultr key' + region: 'sjc' + +inputs: + - name: 'vultr_os' + type: 'list' + options: + - '362' + - name: 'vultr_plan' + type: 'list' + options: + - 'vc2-1c-1gb' + - 'vc2-1c-2gb' + - 'vc2-1c-4gb' diff --git a/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/datastores.yml b/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/datastores.yml new file mode 100644 index 0000000000..d1dda640fe --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/datastores.yml @@ -0,0 +1,40 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +#------------------------------------------------------------------------------- +# datastores: Defines the storage area for the cluster using the SSH replication +# drivers. It creates the following datastores, using Replica driver: +# 1. Image datastore, ${cluster_name}-image +# 2. System datastore, ${cluster_name}-system +# 3. File datastore, ${cluster_name}-files +# +# Configuration/Input attributes: +# - replica_host: The host that will hold the cluster replicas and snapshots. +#------------------------------------------------------------------------------- +datastores: + + - name: "${provision}-image" + type: 'image_ds' + ds_mad: 'fs' + tm_mad: 'ssh' + safe_dirs: "/var/tmp /tmp" + + - name: "${provision}-system" + type: 'system_ds' + tm_mad: 'ssh' + safe_dirs: "/var/tmp /tmp" + replica_host: "use-first-host" diff --git a/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/fireedge.yml b/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/fireedge.yml new file mode 100644 index 0000000000..c122c4cab8 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/fireedge.yml @@ -0,0 +1,20 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +image: 'OPENNEBULA-VULTR' +provider: 'vultr_virtual' +provision_type: 'virtual' diff --git a/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/inputs.yml b/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/inputs.yml new file mode 100644 index 0000000000..505056c88b --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/inputs.yml @@ -0,0 +1,52 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +inputs: + - name: 'number_hosts' + type: text + description: "Number of virtual servers to create" + default: '1' + + - name: 'number_public_ips' + type: text + description: 'Number of public IPs to get' + default: '1' + + - name: 'dns' + type: text + description: 'Comma separated list of DNS servers for public network' + default: '1.1.1.1' + + - name: 'vultr_plan' + type: text + description: "Vultr plan (device type)" + default: 'vc2-1c-1gb' + + - name: 'vultr_os' + type: text + description: "Vultr host operating system" + default: '362' + + - name: 'one_hypervisor' + type: list + description: "Virtualization technology for the cluster hosts" + options: + - 'qemu' + - 'lxc' + default: 'lxc' + +... diff --git a/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/networks.yml b/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/networks.yml new file mode 100644 index 0000000000..887e4a75f2 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/vultr.d/networks.yml @@ -0,0 +1,41 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +networks: + - name: "${provision}-public" + vn_mad: 'elastic' + bridge: 'br0' + netrole: 'public' + dns: "${input.dns}" + provision: + count: "${input.number_public_ips}" + ar: + - provison_id: "${provision_id}" + size: '1' + vultr_ip_type: 'v4' + ipam_mad: 'vultr' + +vntemplates: + - name: "${provision}-private" + vn_mad: 'vxlan' + phydev: 'ens7' + automatic_vlan_id: 'yes' + netrole: 'private' + vxlan_mode: 'evpn' + vxlan_tep: 'dev' + ip_link_conf: 'nolearning=' + cluster_ids: "${cluster.0.id}" diff --git a/share/oneprovision/edge-clusters/virtual/provisions/vultr.yml b/share/oneprovision/edge-clusters/virtual/provisions/vultr.yml new file mode 100644 index 0000000000..ce76403430 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/vultr.yml @@ -0,0 +1,65 @@ +--- +# ---------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +#------------------------------------------------------------------------------- +# This is the canonical description file for a cluster build with 'Vultr' +# resources using the KVM hypervisor. +# ------------------------------------------------------------------------------ + +name: 'vultr_virtual-cluster' + +extends: + - common.d/defaults.yml + - common.d/resources.yml + - common.d/hosts.yml + - vultr.d/datastores.yml + - vultr.d/fireedge.yml + - vultr.d/inputs.yml + - vultr.d/networks.yml + +#------------------------------------------------------------------------------- +# playbook: Ansible playbook used for hosts configuration. Check +# ansible/vultr.yml for the specific roles applied. +#------------------------------------------------------------------------------- +playbook: + - vultr + +#------------------------------------------------------------------------------- +# defaults: Common configuration attributes for provision objects +#-------------------------------------------------------------------------------- +defaults: + provision: + provider_name: 'vultr_virtual' + plan: "${input.vultr_plan}" + os: "${input.vultr_os}" + +#------------------------------------------------------------------------------- +# cluster: Parameters for the OpenNebula cluster. Applies to all the Hosts +#-------------------------------------------------------------------------------- +# name: of the cluster +# description: Additional information +# reserved_cpu: In percentage. It will be subtracted from the TOTAL CPU +# reserved_memory: In percentage. It will be subtracted from the TOTAL MEM +#-------------------------------------------------------------------------------- +cluster: + name: "${provision}" + description: 'Vultr edge cluster' + datastores: + - 1 + - 2 + reserved_cpu: '0' + reserved_mem: '0' diff --git a/share/vendor/ruby/gems/vultr/lib/vultr.rb b/share/vendor/ruby/gems/vultr/lib/vultr.rb new file mode 100644 index 0000000000..1fd896e1e4 --- /dev/null +++ b/share/vendor/ruby/gems/vultr/lib/vultr.rb @@ -0,0 +1,212 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +require 'json' +require 'net/http' + +# Vultr error +class VultrError < StandardError + + # Check if error is really an error + # + # @param error [Object] Error to check + # + # @return [Boolean] True if it is an error, false otherwise + def self.error?(error) + error.class == VultrError + end + +end + +# Ruby bindings to interact with Vultr provider +class Vultr + + ############################################################################ + # + # This Vultr binding has been developed following methods specified here: + # https://www.vultr.com/api + # + ############################################################################ + + # API base URL + BASE_URL = 'https://api.vultr.com/v2' + + # API instances URL + INSTANCE_URL = "#{BASE_URL}/instances" + + # API networks URL + NETWORK_URL = "#{BASE_URL}/reserved-ips" + + # HTTP codes that are good + GOOD_CODES = [Net::HTTPOK, Net::HTTPNoContent, Net::HTTPCreated] + + # Class constructor + # + # @param key [String] Vultr API key + def initialize(key) + @key = key + end + + ############################################################################ + # Instances Methods + ############################################################################ + + # Get instances information + # + # @param id [String] Instances ID + # + # @return [Hash, Error] hash with instance data if no error, error othwerise + def instance(id) + rc = get("#{INSTANCE_URL}/#{id}") + + return rc if VultrError.error?(rc) + + JSON.parse(rc)['instance'] + end + + # Attach Reserved IP to an Instance + # + # @param id [String] Instance ID + # @param nic_id [String] The Reserved IP id to attach to this Instance + # + # @return [nil, Error] nil if no error, error othwerise + def attach_nic(id, nic_id) + data = {} + data['instance_id'] = id + + post("#{NETWORK_URL}/#{nic_id}/attach", data) + end + + # Detach Reserved IP from an Instance + # + # @param id [String] Instance ID + # @param nic_id [String] The Reserved IP id to detach from this Instance + # + # @return [nil, Error] nil if no error, error othwerise + def detach_nic(id, nic_id) + data = {} + data['instance_id'] = id + + post("#{NETWORK_URL}/#{nic_id}/detach", data) + end + + ############################################################################ + # Network methods + ############################################################################ + + # Create a new Reserved IP in a region + # + # @param region [String] Create the Reserved IP in this Region id + # @param ip_type [String] IP version, it can be v4 or v6 + # + # @return [Hash, Error] Reserved IP hash if no error, error othwerise + def create_nic(region, ip_type = 'v4') + data = {} + data['region'] = region + data['ip_type'] = ip_type + + rc = post(NETWORK_URL, data) + + return rc if VultrError.error?(rc) + + JSON.parse(rc)['reserved_ip'] + end + + # Delete aPrivate Network + # + # @param nic_id [String] The Network ID + # + # @return [nil, Error] nil if no error, error othwerise + def delete_nic(nic_id) + delete("#{NETWORK_URL}/#{nic_id}") + end + + private + + ############################################################################ + # HTTP methods + ############################################################################ + + # Execute HTTP Get operation + # + # @param url [String] URL to call + # + # @return [Object, Error] Response if everything went well, error othwerise + def get(url) + req(url, :get) + end + + # Execute HTTP Post operation + # + # @param url [String] URL to call + # @param data [JSON] Data to send in the request + # + # @return [Object, Error] Response if everything went well, error othwerise + def post(url, data) + req(url, :post, data) + end + + # Execute HTTP Delete operation + # + # @param url [String] URL to call + # + # @return [object, error] response if everything went well, error othwerise + def delete(url) + req(url, :delete) + end + + ############################################################################ + # Helpers + ############################################################################ + + # Execute an HTTP request + # + # @param url [String] URL to call + # @param method [Symbol] HTTP method to use + # @param data [JSON] Data to send + # + # @return [object, error] response if everything went well, error othwerise + def req(url, method, data = nil) + uri = URI(url) + + case method + when :get + req = Net::HTTP::Get.new(uri) + when :post + req = Net::HTTP::Post.new(uri) + when :delete + req = Net::HTTP::Delete.new(uri) + else + raise "Undefined method #{method}" + end + + req['Accept'] = 'application/json' + req['Authorization'] = "Bearer #{@key}" + req.body = data.to_json if data + + res = Net::HTTP.new(uri.hostname, uri.port) + res.use_ssl = true + + response = res.request(req) + + unless GOOD_CODES.include?(response.class) + return VultrError.new(JSON.parse(response.body)['error']) + end + + response.body + end + +end diff --git a/src/ipamm_mad/remotes/vultr/allocate_address b/src/ipamm_mad/remotes/vultr/allocate_address new file mode 100755 index 0000000000..d0f953b4c9 --- /dev/null +++ b/src/ipamm_mad/remotes/vultr/allocate_address @@ -0,0 +1,21 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +STDIN = `cat -` + +exit(0) diff --git a/src/ipamm_mad/remotes/vultr/free_address b/src/ipamm_mad/remotes/vultr/free_address new file mode 100755 index 0000000000..d0f953b4c9 --- /dev/null +++ b/src/ipamm_mad/remotes/vultr/free_address @@ -0,0 +1,21 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +STDIN = `cat -` + +exit(0) diff --git a/src/ipamm_mad/remotes/vultr/get_address b/src/ipamm_mad/remotes/vultr/get_address new file mode 100755 index 0000000000..2bd85fd7e2 --- /dev/null +++ b/src/ipamm_mad/remotes/vultr/get_address @@ -0,0 +1,99 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +############################################################################### +# This script is used to get a free IP address (or set of IPs). The IP will be +# used by OpenNebula VMs and should not be allocated to any other host in the +# network. +# +# STDIN Input: +# - Base64 encoded XML with the AR description and the address request +# +# This scrit MUST output the leased IP range, if the "size" IPs cannot be +# assgined the sript must return -1, otherwise it must exit 0. The answer to +# OpenNebula needs to include the ADDRESS spec: +# +# ADDRESS = [ IP = "10.0.0.2", SIZE = 1 ] +# +################################################################################ + +ONE_LOCATION = ENV['ONE_LOCATION'] unless defined?(ONE_LOCATION) + +if !ONE_LOCATION + RUBY_LIB_LOCATION ||= '/usr/lib/one/ruby' + GEMS_LOCATION ||= '/usr/share/one/gems' +else + RUBY_LIB_LOCATION ||= ONE_LOCATION + '/lib/ruby' + GEMS_LOCATION ||= ONE_LOCATION + '/share/gems' +end + +# %%RUBYGEMS_SETUP_BEGIN%% +if File.directory?(GEMS_LOCATION) + real_gems_path = File.realpath(GEMS_LOCATION) + if !defined?(Gem) || Gem.path != [real_gems_path] + $LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ } + + # Suppress warnings from Rubygems + # https://github.com/OpenNebula/one/issues/5379 + begin + verb = $VERBOSE + $VERBOSE = nil + require 'rubygems' + Gem.use_paths(real_gems_path) + ensure + $VERBOSE = verb + end + end +end +# %%RUBYGEMS_SETUP_END%% + +$LOAD_PATH << RUBY_LIB_LOCATION + +require 'base64' +require 'nokogiri' + +begin + data = Nokogiri::XML(Base64.decode64(STDIN.read)) + + size = data.xpath('//ADDRESS/SIZE').text + ip = data.xpath('//AR/IP').text + + if Integer(size) != 1 + STDERR.puts 'Only IP requests of size 1 are supported' + exit(-1) + end + + if ip.empty? + STDERR.puts 'Empty IP address in request' + exit(-1) + end + + puts <<-EOF + ADDRESS = [ + IP = "#{ip}", + SIZE = "1" + ] + EOF +rescue StandardError => e + error_str = "ERROR MESSAGE --8<------\n" + error_str << e.to_s + error_str << "\nERROR MESSAGE ------>8--" + + STDERR.puts error_str + exit(-1) +end diff --git a/src/ipamm_mad/remotes/vultr/register_address_range b/src/ipamm_mad/remotes/vultr/register_address_range new file mode 100755 index 0000000000..42b02249bd --- /dev/null +++ b/src/ipamm_mad/remotes/vultr/register_address_range @@ -0,0 +1,204 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +############################################################################### +# This script is used to register a new IP network in the IPAM. The network may +# be selected by a pool of free networks or if an specific network is requested +# its availability maybe checked by the IPAM driver. +# +# The IPAM driver must return an OpenNebula AddressRange definition, potentially +# augmented with network specific variables to be used by VMs (e.g. GATEWAYS, +# MASK...) +# +# STDIN Input: +# - Base64 encoded XML with AR request +# +# XML format +# +# +# Type of the Ip (public/global) +# Number of IPs to allocate +# ID +# +# +# +# The response MUST include IPAM_MAD, TYPE, IP and SIZE attributes, example: +# - A basic network definition +# AR = [ +# IPAM_MAD = "vultr", +# TYPE = "IP4", +# IP = "10.0.0.1", +# SIZE = "255", +# DEPLOY_ID = "..", +# ] +# +# - A complete network definition. Custom attributes (free form, key-value) +# can be added, named cannot be repeated. +# AR = [ +# IPAM_MAD = "vultr", +# TYPE = "IP4", +# IP = "10.0.0.2", +# SIZE = "200", +# DEPLOY_ID = "..", +# NETWORK_ADDRESS = "10.0.0.0", +# NETWORK_MASK = "255.255.255.0", +# GATEWAY = "10.0.0.1", +# DNS = "10.0.0.1", +# IPAM_ATTR = "10.0.0.240", +# OTHER_IPAM_ATTR = ".mydoamin.com" +# ] +################################################################################ + +ONE_LOCATION = ENV['ONE_LOCATION'] unless defined?(ONE_LOCATION) + +if !ONE_LOCATION + LIB_LOCATION ||= '/usr/lib/one' + VULTR_LOCATION ||= '/usr/lib/one/ruby/vendors/vultr/lib' + RUBY_LIB_LOCATION ||= '/usr/lib/one/ruby' + GEMS_LOCATION ||= '/usr/share/one/gems' +else + LIB_LOCATION ||= ONE_LOCATION + '/lib' + VULTR_LOCATION ||= ONE_LOCATION + '/lib/ruby/vendors/vultr/lib' + RUBY_LIB_LOCATION ||= ONE_LOCATION + '/lib/ruby' + GEMS_LOCATION ||= ONE_LOCATION + '/share/gems' +end + +# %%RUBYGEMS_SETUP_BEGIN%% +if File.directory?(GEMS_LOCATION) + real_gems_path = File.realpath(GEMS_LOCATION) + if !defined?(Gem) || Gem.path != [real_gems_path] + $LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ } + + # Suppress warnings from Rubygems + # https://github.com/OpenNebula/one/issues/5379 + begin + verb = $VERBOSE + $VERBOSE = nil + require 'rubygems' + Gem.use_paths(real_gems_path) + ensure + $VERBOSE = verb + end + end +end +# %%RUBYGEMS_SETUP_END%% + +$LOAD_PATH << VULTR_LOCATION +$LOAD_PATH << RUBY_LIB_LOCATION +$LOAD_PATH << LIB_LOCATION + '/oneprovision/lib' + +require 'base64' +require 'digest' +require 'ipaddr' +require 'nokogiri' + +require 'opennebula' +require 'oneprovision' +require 'vultr' + +IP_TYPE = %w[v4 v6] + +DEFAULT_PRIVATE_CIDR = '172.16.0.0/12' + +# IP Address Class +class IPAddr + + # Add ^ operator to the IPAddr class + def ^(other) + clone.set(@addr ^ other.to_i) + end + +end + +begin + data = Nokogiri::XML(Base64.decode64(STDIN.read)) + + # -------------------------------------------------------------------------- + # Get connection details for the provider + # -------------------------------------------------------------------------- + provision_id = data.xpath('//AR/PROVISION_ID').text + + if provision_id.empty? + STDERR.puts 'Missing provision id in address range' + exit(-1) + end + + one = OpenNebula::Client.new + provision = OneProvision::Provision.new_with_id(provision_id, one) + rc = provision.info + + if OpenNebula.is_error?(rc) + STDERR.puts rc.message + exit(-1) + end + + provider = provision.provider + connect = provider.body['connection'] + + v_key = connect['key'] + v_region = connect['region'] + + # -------------------------------------------------------------------------- + # Connect to Vultr and allocate a new IP + # -------------------------------------------------------------------------- + vultr = Vultr.new(v_key) + + ip_type = data.xpath('//AR/VULTR_IP_TYPE').text + ip_size = Integer(data.xpath('//AR/SIZE').text) + + if Integer(ip_size) != 1 + STDERR.puts 'Only address ranges of size 1 are supported' + exit(-1) + end + + if ip_type.empty? + ip_type = IP_TYPE[0] + elsif !IP_TYPE.include?(ip_type) + STDERR.puts "Type #{ip_type} not supported. " \ + "Must be: #{IP_TYPE.join(', ')}" + exit(-1) + end + + nic = vultr.create_nic(v_region, ip_type) + + raise nic if VultrError.error?(nic) + + eip = IPAddr.new(nic['subnet']) + ipgw = eip ^ 1 + + puts <<-EOF + AR = [ + TYPE = "IP4", + IP = "#{nic['subnet']}", + SIZE = "#{ip_size}", + IPAM_MAD = "vultr", + GATEWAY = "#{ipgw}", + EXTERNAL_IP = "#{nic['subnet']}", + NETWORK_MASK = "255.255.255.254", + VULTR_IP_ID = "#{nic['id']}", + PROVISION_ID = "#{provision_id}" + ] + EOF +rescue StandardError => e + error_str = "ERROR MESSAGE --8<------\n" + error_str << e.to_s + error_str << "\nERROR MESSAGE ------>8--" + + STDERR.puts error_str + exit(-1) +end diff --git a/src/ipamm_mad/remotes/vultr/unregister_address_range b/src/ipamm_mad/remotes/vultr/unregister_address_range new file mode 100755 index 0000000000..0fe2814f52 --- /dev/null +++ b/src/ipamm_mad/remotes/vultr/unregister_address_range @@ -0,0 +1,121 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +############################################################################### +# This script is used to unregister a new IP network in the IPAM. +# +# STDIN Input: +# - Base64 encoded XML with AR request +# +################################################################################ + +ONE_LOCATION = ENV['ONE_LOCATION'] unless defined?(ONE_LOCATION) + +if !ONE_LOCATION + LIB_LOCATION ||= '/usr/lib/one' + VULTR_LOCATION ||= '/usr/lib/one/ruby/vendors/vultr/lib' + RUBY_LIB_LOCATION ||= '/usr/lib/one/ruby' + GEMS_LOCATION ||= '/usr/share/one/gems' +else + LIB_LOCATION ||= ONE_LOCATION + '/lib' + VULTR_LOCATION ||= '/usr/lib/one/ruby/vendors/vultr/lib' + RUBY_LIB_LOCATION ||= ONE_LOCATION + '/lib/ruby' + GEMS_LOCATION ||= ONE_LOCATION + '/share/gems' +end + +# %%RUBYGEMS_SETUP_BEGIN%% +if File.directory?(GEMS_LOCATION) + real_gems_path = File.realpath(GEMS_LOCATION) + if !defined?(Gem) || Gem.path != [real_gems_path] + $LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ } + + # Suppress warnings from Rubygems + # https://github.com/OpenNebula/one/issues/5379 + begin + verb = $VERBOSE + $VERBOSE = nil + require 'rubygems' + Gem.use_paths(real_gems_path) + ensure + $VERBOSE = verb + end + end +end +# %%RUBYGEMS_SETUP_END%% + +$LOAD_PATH << VULTR_LOCATION +$LOAD_PATH << RUBY_LIB_LOCATION +$LOAD_PATH << LIB_LOCATION + '/oneprovision/lib' + +require 'base64' +require 'nokogiri' + +require 'opennebula' +require 'oneprovision' +require 'vultr' + +begin + data = Nokogiri::XML(Base64.decode64(STDIN.read)) + + # -------------------------------------------------------------------------- + # Get connection details for the provider + # -------------------------------------------------------------------------- + provision_id = data.xpath('//AR/PROVISION_ID').text + + if provision_id.empty? + STDERR.puts 'Missing provision id in address range' + exit(-1) + end + + one = OpenNebula::Client.new + provision = OneProvision::Provision.new_with_id(provision_id, one) + rc = provision.info + + if OpenNebula.is_error?(rc) + STDERR.puts rc.message + exit(-1) + end + + provider = provision.provider + connect = provider.body['connection'] + v_key = connect['key'] + + # -------------------------------------------------------------------------- + # Connect to Vultr and delete the IP + # -------------------------------------------------------------------------- + vultr = Vultr.new(v_key) + v_id = data.xpath('//AR/VULTR_IP_ID').text.to_s + + if v_id.empty? + STDERR.puts 'Missing Vultr range ID' + exit(-1) + end + + rc = vultr.delete_nic(v_id) + + raise rc if VultrError.error?(rc) + + exit(0) +rescue StandardError => e + error_str = "ERROR MESSAGE --8<------\n" + error_str << e.to_s + error_str << "\nERROR MESSAGE ------>8--" + + STDERR.puts error_str + exit(-1) +end diff --git a/src/oneprovision/lib/provision/ansible.rb b/src/oneprovision/lib/provision/ansible.rb index 84c04120b8..e12f25b82d 100644 --- a/src/oneprovision/lib/provision/ansible.rb +++ b/src/oneprovision/lib/provision/ansible.rb @@ -264,7 +264,13 @@ module OneProvision host = Resource.object('hosts') host.info(h['id']) - c << "#{host.one['NAME']}\n" + h_vars = host.one['TEMPLATE/ANSIBLE_HOST_VARS'] + + if h_vars + c << "#{host.one['NAME']} #{h_vars}\n" + else + c << "#{host.one['NAME']}\n" + end end c << "\n" diff --git a/src/oneprovision/lib/provision/provision.rb b/src/oneprovision/lib/provision/provision.rb index c322cec824..bf0c5573ee 100644 --- a/src/oneprovision/lib/provision/provision.rb +++ b/src/oneprovision/lib/provision/provision.rb @@ -11,7 +11,6 @@ # See the License for the specific language governing permissions and # # limitations under the License. # #--------------------------------------------------------------------------- # - require 'opennebula/document_json' require 'opennebula/wait_ext' @@ -742,6 +741,14 @@ module OneProvision # Add deployment ID host.one.add_element('//TEMPLATE/PROVISION', 'DEPLOY_ID' => id) + + # Read private IP if any + terraform = Terraform.singleton(@provider, {}) + + if terraform.respond_to? :add_host_vars + terraform.add_host_vars(host) + end + host.one.update(host.one.template_str) h['name'] = name diff --git a/src/oneprovision/lib/terraform/providers.rb b/src/oneprovision/lib/terraform/providers.rb index 2f05a46d90..a7b14bad45 100644 --- a/src/oneprovision/lib/terraform/providers.rb +++ b/src/oneprovision/lib/terraform/providers.rb @@ -19,6 +19,9 @@ require 'terraform/providers/digitalocean' require 'terraform/providers/dummy' require 'terraform/providers/google' require 'terraform/providers/packet' +require 'terraform/providers/vultr' +require 'terraform/providers/vultr_metal' +require 'terraform/providers/vultr_virtual' # Module OneProvision module OneProvision diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_metal/cluster.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_metal/cluster.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_metal/datastore.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_metal/datastore.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_metal/host.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_metal/host.erb new file mode 100644 index 0000000000..01c7c4130c --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/vultr_metal/host.erb @@ -0,0 +1,23 @@ +resource "vultr_startup_script" "device_<%= obj['ID'] %>" { + name = "install_root_ssh_keys" + script = "<%= obj['user_data'] %>" +} + +resource "vultr_bare_metal_server" "device_<%= obj['ID'] %>" { + hostname = "<%= provision['HOSTNAME'] %>" + plan = "<%= provision['PLAN'] %>" + region = "<%= provision['REGION'] %>" + os_id = "<%= provision['OS'] %>" + script_id = vultr_startup_script.device_<%= obj['ID'] %>.id + tag = "OpenNebula - ONE_ID=<%= obj['ID'] %>" + activation_email = false +} + +output "ip_<%= obj['ID'] %>" { + value = vultr_instance.device_<%= obj['ID'] %>.main_ip +} + +output "device_id_<%= obj['ID'] %>" { + value = vultr_instance.device_<%= obj['ID'] %>.id +} + diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_metal/network.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_metal/network.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_metal/provider.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_metal/provider.erb new file mode 100644 index 0000000000..a61f1983c9 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/vultr_metal/provider.erb @@ -0,0 +1,14 @@ +terraform { + + required_providers { + vultr = { + source = "vultr/vultr" + version = "2.2.0" + } + } +} + +provider "vultr" { + api_key = "<%= conn['KEY'] %>" +} + diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/cluster.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/cluster.erb new file mode 100644 index 0000000000..2f62ad6bd9 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/cluster.erb @@ -0,0 +1,5 @@ +resource "vultr_private_network" "device_<%= obj['ID'] %>" { + description = "BGP Network" + region = "<%= provision['REGION'] %>" +} + diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/datastore.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/datastore.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/host.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/host.erb new file mode 100644 index 0000000000..fb786393cd --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/host.erb @@ -0,0 +1,24 @@ +resource "vultr_startup_script" "device_<%= obj['ID'] %>" { + name = "install_root_ssh_keys" + script = "<%= obj['user_data'] %>" +} + +resource "vultr_instance" "device_<%= obj['ID'] %>" { + hostname = "<%= provision['HOSTNAME'] %>" + plan = "<%= provision['PLAN'] %>" + region = "<%= provision['REGION'] %>" + os_id = "<%= provision['OS'] %>" + script_id = vultr_startup_script.device_<%= obj['ID'] %>.id + tag = "OpenNebula - ONE_ID=<%= obj['ID'] %>" + activation_email = false + private_network_ids = [vultr_private_network.device_<%= c['ID'] %>.id] +} + +output "ip_<%= obj['ID'] %>" { + value = vultr_instance.device_<%= obj['ID'] %>.main_ip +} + +output "device_id_<%= obj['ID'] %>" { + value = vultr_instance.device_<%= obj['ID'] %>.id +} + diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/network.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/network.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/provider.erb b/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/provider.erb new file mode 100644 index 0000000000..a61f1983c9 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/vultr_virtual/provider.erb @@ -0,0 +1,14 @@ +terraform { + + required_providers { + vultr = { + source = "vultr/vultr" + version = "2.2.0" + } + } +} + +provider "vultr" { + api_key = "<%= conn['KEY'] %>" +} + diff --git a/src/oneprovision/lib/terraform/providers/vultr.rb b/src/oneprovision/lib/terraform/providers/vultr.rb new file mode 100644 index 0000000000..208054f58c --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/vultr.rb @@ -0,0 +1,95 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +ONE_LOCATION = ENV['ONE_LOCATION'] unless defined?(ONE_LOCATION) + +if !ONE_LOCATION + VULTR_LOCATION ||= '/usr/lib/one/ruby/vendors/vultr/lib' +else + VULTR_LOCATION ||= ONE_LOCATION + '/lib/ruby/vendors/vultr/lib' +end + +$LOAD_PATH << VULTR_LOCATION + +require 'vultr' +require 'terraform/terraform' + +# Module OneProvision +module OneProvision + + # Vultr Terraform Provider + class Vultr < Terraform + + KEYS = %w[key region] + + # Class constructor + # + # @param provider [Provider] + # @param state [String] Terraform state in base64 + # @param conf [String] Terraform config state in base64 + def initialize(provider, state, conf) + # Credentials are not stored in a file + @file_credentials = false + + super + end + + # Get user data to add into the VM + # + # @param ssh_key [String] SSH keys to add + def user_data(ssh_key) + user_data = "#! /bin/bash\n" + user_data << "mkdir ~/.ssh\n" + + ssh_key.split("\n").each do |key| + user_data << "echo #{key} >> ~/.ssh/authorized_keys\n" + end + + user_data << "chmod 700 ~/.ssh\n" + user_data << 'chmod 644 ~/.ssh/authorized_keys' + + Base64.strict_encode64(user_data) + end + + # Add configuration variables to host template + # + # @param host [OneProvision::Host] Host information + def add_host_vars(host) + host.one.add_element( + '//TEMPLATE', + 'ANSIBLE_HOST_VARS' => "private_ip=#{private_ip(host)}" + ) + end + + private + + # Get private IP of an instance + # + # @param host [OneProvision::Host] Host information + # + # @return [String] Instance private IP + def private_ip(host) + v = ::Vultr.new(@provider.connection['KEY']) + i = v.instance(host.one['TEMPLATE/PROVISION/DEPLOY_ID']) + + raise OneProvisionLoopException i if ::VultrError.error?(i) + + i['internal_ip'] + end + + end + +end diff --git a/src/oneprovision/lib/terraform/providers/vultr_metal.rb b/src/oneprovision/lib/terraform/providers/vultr_metal.rb new file mode 100644 index 0000000000..f27a951c54 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/vultr_metal.rb @@ -0,0 +1,46 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +require 'terraform/providers/vultr' + +# Module OneProvision +module OneProvision + + # Vultr Metal Terraform Provider + class VultrMetal < Vultr + + # OpenNebula - Terraform equivalence + TYPES = { + :cluster => '', + :datastore => '', + :host => 'vultr_bare_metal_server', + :network => '' + } + + # Class constructor + # + # @param provider [Provider] + # @param state [String] Terraform state in base64 + # @param conf [String] Terraform config state in base64 + def initialize(provider, state, conf) + @dir = "#{PROVIDERS_LOCATION}/templates/vultr_metal" + + super + end + + end + +end diff --git a/src/oneprovision/lib/terraform/providers/vultr_virtual.rb b/src/oneprovision/lib/terraform/providers/vultr_virtual.rb new file mode 100644 index 0000000000..40d2c773b3 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/vultr_virtual.rb @@ -0,0 +1,46 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +require 'terraform/providers/vultr' + +# Module OneProvision +module OneProvision + + # Vultr Virtual Terraform Provider + class VultrVirtual < Vultr + + # OpenNebula - Terraform equivalence + TYPES = { + :cluster => 'vultr_private_network', + :datastore => '', + :host => 'vultr_instance', + :network => '' + } + + # Class constructor + # + # @param provider [Provider] + # @param state [String] Terraform state in base64 + # @param conf [String] Terraform config state in base64 + def initialize(provider, state, conf) + @dir = "#{PROVIDERS_LOCATION}/templates/vultr_virtual" + + super + end + + end + +end diff --git a/src/oneprovision/lib/terraform/terraform.rb b/src/oneprovision/lib/terraform/terraform.rb index ac3c0f9415..c2ac149689 100644 --- a/src/oneprovision/lib/terraform/terraform.rb +++ b/src/oneprovision/lib/terraform/terraform.rb @@ -46,7 +46,13 @@ module OneProvision class Terraform # Providers that are currently available - PROVIDERS = %w[aws digitalocean google packet dummy] + PROVIDERS = %w[aws + digitalocean + dummy + google + packet + vultr_metal + vultr_virtual] # Class constructor # @@ -77,6 +83,10 @@ module OneProvision tf_class = DigitalOcean when 'dummy' tf_class = Dummy + when 'vultr_metal' + tf_class = VultrMetal + when 'vultr_virtual' + tf_class = VultrVirtual else raise OneProvisionLoopException, "Unknown provider: #{provider.body['provider']}" @@ -101,6 +111,8 @@ module OneProvision keys = DigitalOcean::KEYS when 'dummy' return true + when 'vultr_metal', 'vultr_virtual' + keys = Vultr::KEYS else raise OneProvisionLoopException, "Unknown provider: #{provider['provider']}" diff --git a/src/vnm_mad/remotes/elastic/aws_vnm.rb b/src/vnm_mad/remotes/elastic/aws_vnm.rb index 6f3ff8d6c0..095dfe6bf7 100644 --- a/src/vnm_mad/remotes/elastic/aws_vnm.rb +++ b/src/vnm_mad/remotes/elastic/aws_vnm.rb @@ -101,7 +101,7 @@ class AWSProvider # Unassign a public_ip from an instance # @param ip [String] not used for AWS # @param external [String] the public ip - def unassign(ip, external) + def unassign(ip, external, _opts = {}) filter = [{ :name => 'public-ip', :values => [external] }] aws_ip = @ec2.describe_addresses({ :filters => filter }).addresses[0] diff --git a/src/vnm_mad/remotes/elastic/elastic.rb b/src/vnm_mad/remotes/elastic/elastic.rb index c3f142c661..f819c34de3 100644 --- a/src/vnm_mad/remotes/elastic/elastic.rb +++ b/src/vnm_mad/remotes/elastic/elastic.rb @@ -74,7 +74,8 @@ class ElasticDriver < VNMMAD::VNMDriver next if attach_nic_id && attach_nic_id != nic[:nic_id] cmds.add :ip, "route add #{nic[:ip]}/32 dev #{nic[:bridge]} ||:" - cmds.add :ip, "neighbour add proxy #{nic[:gateway]} dev #{nic[:bridge]}" + cmds.add :ip, + "neighbour add proxy #{nic[:gateway]} dev #{nic[:bridge]}" provider.activate(cmds, nic) if provider.respond_to? :activate end @@ -95,15 +96,18 @@ class ElasticDriver < VNMMAD::VNMDriver process_all do |nic| next if attach_nic_id && attach_nic_id != nic[:nic_id] - cmds.add :ip, "route del #{nic[:ip]}/32 dev #{nic[:bridge]} | true" - cmds.add :ip, "neighbour del proxy #{nic[:gateway]} dev #{nic[:bridge]} | true" + cmds.add :ip, + "route del #{nic[:ip]}/32 dev #{nic[:bridge]} | true" + cmds.add :ip, + "neighbour del proxy #{nic[:gateway]} " \ + "dev #{nic[:bridge]} | true" provider.deactivate(cmds, nic) if provider.respond_to? :deactivate # TODO: MUST check if bridge is empty. Move to remote_clean - #next if nic[:parent_nic] || nic[:conf][:keep_empty_bridge] + # next if nic[:parent_nic] || nic[:conf][:keep_empty_bridge] # - #cmds.add :ip, "link delete #{nic[:bridge]} | true" + # cmds.add :ip, "link delete #{nic[:bridge]} | true" end cmds.run_remote(@ssh) @@ -126,7 +130,9 @@ class ElasticDriver < VNMMAD::VNMDriver next if attach_nic_id && attach_nic_id != nic[:nic_id] # pass aws_allocation_id if present - opts = { :alloc_id => nic[:aws_allocation_id] } + # pass vultr_ip_id if present + opts = { :alloc_id => nic[:aws_allocation_id], + :vultr_id => nic[:vultr_ip_id] } break false \ unless provider.assign(nic[:ip], nic[:external_ip], opts) == 0 @@ -154,7 +160,10 @@ class ElasticDriver < VNMMAD::VNMDriver @vm.each_nic_all do |nic| next if attach_nic_id && attach_nic_id != nic[:nic_id] - provider.unassign(nic[:ip], nic[:external_ip]) + # pass vultr_ip_id if present + opts = { :vultr_id => nic[:vultr_ip_id] } + + provider.unassign(nic[:ip], nic[:external_ip], opts) end end @@ -169,6 +178,9 @@ class ElasticDriver < VNMMAD::VNMDriver when 'packet' require 'packet_vnm' PacketProvider.new(provider, host) + when 'vultr_virtual', 'vultr_metal' + require 'vultr_vnm' + VultrProvider.new(provider, host) else nil end @@ -179,7 +191,5 @@ class ElasticDriver < VNMMAD::VNMDriver nil end - private - end # rubocop:enable Naming/FileName diff --git a/src/vnm_mad/remotes/elastic/packet_vnm.rb b/src/vnm_mad/remotes/elastic/packet_vnm.rb index 23fa3ce2d3..d20d083c23 100644 --- a/src/vnm_mad/remotes/elastic/packet_vnm.rb +++ b/src/vnm_mad/remotes/elastic/packet_vnm.rb @@ -68,7 +68,10 @@ class PacketProvider 0 rescue Packet::Error => e # potential VM poweroff(itself) + resume - return 0 if e.message == '{"errors"=>["Address has already been taken"]}' + + if e.message == '{"errors"=>["Address has already been taken"]}' + return 0 + end OpenNebula.log_error("Error assiging #{external}:#{e.message}") 1 @@ -77,7 +80,7 @@ class PacketProvider 1 end - def unassign(_ip, external) + def unassign(_ip, external, _opts = {}) dev = @client.get_device(@deploy_id) ip = dev.ip_addresses.select do |i| @@ -92,17 +95,21 @@ class PacketProvider end def activate(cmds, nic) - cmds.add :iptables, "-t nat -A POSTROUTING -s #{nic[:ip]} -j SNAT"\ - " --to-source #{nic[:external_ip]}" - cmds.add :iptables, "-t nat -A PREROUTING -d #{nic[:external_ip]} -j DNAT"\ - " --to-destination #{nic[:ip]}" + cmds.add :iptables, + "-t nat -A POSTROUTING -s #{nic[:ip]} -j SNAT " \ + "--to-source #{nic[:external_ip]}" + cmds.add :iptables, + "-t nat -A PREROUTING -d #{nic[:external_ip]} -j DNAT " \ + "--to-destination #{nic[:ip]}" end def deactivate(cmds, nic) - cmds.add :iptables, "-t nat -D POSTROUTING -s #{nic[:ip]} -j SNAT"\ - " --to-source #{nic[:external_ip]}" - cmds.add :iptables, "-t nat -D PREROUTING -d #{nic[:external_ip]} -j DNAT"\ - " --to-destination #{nic[:ip]}" + cmds.add :iptables, + "-t nat -D POSTROUTING -s #{nic[:ip]} -j SNAT " \ + "--to-source #{nic[:external_ip]}" + cmds.add :iptables, + "-t nat -D PREROUTING -d #{nic[:external_ip]} -j DNAT " \ + "--to-destination #{nic[:ip]}" end end diff --git a/src/vnm_mad/remotes/elastic/vultr_vnm.rb b/src/vnm_mad/remotes/elastic/vultr_vnm.rb new file mode 100644 index 0000000000..cb4fc5c803 --- /dev/null +++ b/src/vnm_mad/remotes/elastic/vultr_vnm.rb @@ -0,0 +1,124 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # +# +ONE_LOCATION = ENV['ONE_LOCATION'] unless defined?(ONE_LOCATION) + +if !ONE_LOCATION + LIB_LOCATION ||= '/usr/lib/one' + RUBY_LIB_LOCATION ||= '/usr/lib/one/ruby' + GEMS_LOCATION ||= '/usr/share/one/gems' + VULTR_LOCATION ||= '/usr/lib/one/ruby/vendors/vultr/lib' +else + LIB_LOCATION ||= ONE_LOCATION + '/lib' + RUBY_LIB_LOCATION ||= ONE_LOCATION + '/lib/ruby' + GEMS_LOCATION ||= ONE_LOCATION + '/share/gems' + VULTR_LOCATION ||= ONE_LOCATION + '/lib/ruby/vendors/vultr/lib' +end + +# %%RUBYGEMS_SETUP_BEGIN%% +if File.directory?(GEMS_LOCATION) + real_gems_path = File.realpath(GEMS_LOCATION) + if !defined?(Gem) || Gem.path != [real_gems_path] + $LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ } + + # Suppress warnings from Rubygems + # https://github.com/OpenNebula/one/issues/5379 + begin + verb = $VERBOSE + $VERBOSE = nil + require 'rubygems' + Gem.use_paths(real_gems_path) + ensure + $VERBOSE = verb + end + end +end +# %%RUBYGEMS_SETUP_END%% + +$LOAD_PATH << RUBY_LIB_LOCATION +$LOAD_PATH << VULTR_LOCATION + +require 'vultr' + +# Class covering Vultr functionality for Elastic driver +class VultrProvider + + # Class constructor + # + # @param provider [OpenNebula::Provider] Provider information + # @param host [OpenNebula:Host] Host information + def initialize(provider, host) + connect = provider.body['connection'] + + @client = Vultr.new(connect['key']) + @deploy_id = host['TEMPLATE/PROVISION/DEPLOY_ID'] + end + + # Assign a reserved IP to the instance + # + # @param opts [Hash] opts[:vultr_ip_id] must contain reserved IP ID + # + # @return [Integer] 0 on success, 1 on error + def assign(_, _, opts = {}) + rc = @client.attach_nic(@deploy_id, opts[:vultr_id]) + + if VultrError.error?(rc) + if rc.message == 'IP is already attached to a server' + return 0 + else + OpenNebula.log_error("Error assiging #{rc.message}") + return 1 + end + end + + 0 + end + + # Unassign a reserved IP from the instance + # + # @param opts [Hash] opts[:vultr_ip_id] must contain reserved IP ID + # + # @return [Integer] 0 on success, 1 on error + def unassign(_, _, opts = {}) + rc = @client.detach_nic(@deploy_id, opts[:vultr_id]) + + if VultrError.error?(rc) + OpenNebula.log_error("Error unassiging #{rc.message}") + return 1 + end + + 0 + end + + def activate(cmds, nic) + cmds.add :iptables, + "-t nat -A POSTROUTING -s #{nic[:ip]} -j SNAT " \ + "--to-source #{nic[:external_ip]}" + cmds.add :iptables, + "-t nat -A PREROUTING -d #{nic[:external_ip]} -j DNAT " \ + "--to-destination #{nic[:ip]}" + end + + def deactivate(cmds, nic) + cmds.add :iptables, + "-t nat -D POSTROUTING -s #{nic[:ip]} -j SNAT " \ + "--to-source #{nic[:external_ip]}" + cmds.add :iptables, + "-t nat -D PREROUTING -d #{nic[:external_ip]} -j DNAT " \ + "--to-destination #{nic[:ip]}" + end + +end