From f1a48bdc0d4a6d235afda26f88e1f69eb0daaa33 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 30 Apr 2021 11:49:51 +0200 Subject: [PATCH] F #5270, #5272: Support for Google Compute and DigitalOcean co-authored-by: Alejandro Huertas co-authored-by: Juan Antonio co-authored-by: Sergio Betanzos --- include/AddressRange.h | 18 + install.sh | 27 ++ share/doc/xsd/vnet.xsd | 2 + share/linters/.rubocop.yml | 1 - share/oneprovision/ansible/digitalocean.yml | 27 ++ share/oneprovision/ansible/google.yml | 29 ++ .../ansible/roles/frr/defaults/main.yml | 8 + .../ansible/roles/frr/tasks/centos.yml | 27 ++ .../roles/frr/templates/staticd.conf.j2 | 2 + .../ansible/roles/frr/templates/zebra.conf.j2 | 2 + .../providers/digitalocean/do-ams3.yml | 19 ++ .../providers/digitalocean/do-lon1.yml | 19 ++ .../providers/digitalocean/do-nyc3.yml | 19 ++ .../providers/digitalocean/do-sfo3.yml | 19 ++ .../providers/digitalocean/do-sgp1.yml | 19 ++ .../google/google-europe-west1-b.yml | 27 ++ .../google/google-europe-west2-b.yml | 27 ++ .../providers/google/google-us-east1-b.yml | 27 ++ .../providers/google/google-us-west1-b.yml | 27 ++ .../virtual/provisions/common.d/hosts.yml | 2 +- .../provisions/digitalocean.d/datastores.yml | 39 +++ .../provisions/digitalocean.d/defaults.yml | 24 ++ .../provisions/digitalocean.d/fireedge.yml | 20 ++ .../provisions/digitalocean.d/inputs.yml | 45 +++ .../provisions/digitalocean.d/networks.yml | 40 +++ .../virtual/provisions/digitalocean.yml | 74 ++++ .../provisions/google.d/datastores.yml | 39 +++ .../virtual/provisions/google.d/fireedge.yml | 20 ++ .../virtual/provisions/google.d/inputs.yml | 45 +++ .../virtual/provisions/google.d/networks.yml | 40 +++ .../virtual/provisions/google.yml | 67 ++++ share/shell/bash_completion | 4 +- src/cli/one_helper/onevm_helper.rb | 20 ++ src/cli/one_helper/onevnet_helper.rb | 322 ++++++++++-------- src/cli/onevm | 124 +++++++ .../providers/{GOOGLECLOUD.png => GOOGLE.png} | Bin .../{GOOGLECLOUD.webp => GOOGLE.webp} | Bin ...-GOOGLECLOUD.png => OPENNEBULA-GOOGLE.png} | Bin ...OOGLECLOUD.webp => OPENNEBULA-GOOGLE.webp} | Bin .../Typography/TypographyWithPoint.js | 2 +- .../Widgets/TotalProviders/index.js | 4 +- src/fireedge/src/client/constants/index.js | 4 - .../src/client/constants/provision.js | 19 +- .../src/client/services/flow/application.js | 4 +- src/fireedge/src/client/types/provision.js | 4 +- src/oneprovision/lib/provider/provider.rb | 32 ++ .../lib/provision/provision_config.rb | 2 +- src/oneprovision/lib/terraform/providers.rb | 2 + .../lib/terraform/providers/aws.rb | 23 +- .../lib/terraform/providers/digitalocean.rb | 69 ++++ .../lib/terraform/providers/google.rb | 67 ++++ .../lib/terraform/providers/packet.rb | 19 +- .../templates/digitalocean/cluster.erb | 5 + .../templates/digitalocean/datastore.erb | 0 .../providers/templates/digitalocean/host.erb | 66 ++++ .../templates/digitalocean/network.erb | 0 .../templates/digitalocean/provider.erb | 12 + .../providers/templates/google/cluster.erb | 23 ++ .../providers/templates/google/datastore.erb | 0 .../providers/templates/google/host.erb | 31 ++ .../providers/templates/google/network.erb | 0 .../providers/templates/google/provider.erb | 7 + src/oneprovision/lib/terraform/terraform.rb | 55 +-- src/template/OpenNebulaTemplate.cc | 4 + src/vnm/AddressRange.cc | 161 ++++++--- src/vnm_mad/remotes/nodeport/clean | 40 +++ .../remotes/nodeport/clean.d/.gitignore | 3 + src/vnm_mad/remotes/nodeport/nodeport.rb | 127 +++++++ src/vnm_mad/remotes/nodeport/post | 38 +++ .../remotes/nodeport/post.d/.gitignore | 3 + src/vnm_mad/remotes/nodeport/pre | 29 ++ src/vnm_mad/remotes/nodeport/pre.d/.gitignore | 3 + src/vnm_mad/remotes/nodeport/update_sg | 38 +++ 73 files changed, 1929 insertions(+), 238 deletions(-) create mode 100644 share/oneprovision/ansible/digitalocean.yml create mode 100644 share/oneprovision/ansible/google.yml create mode 100644 share/oneprovision/ansible/roles/frr/templates/staticd.conf.j2 create mode 100644 share/oneprovision/ansible/roles/frr/templates/zebra.conf.j2 create mode 100644 share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-ams3.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-lon1.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-nyc3.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-sfo3.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-sgp1.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/google/google-europe-west1-b.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/google/google-europe-west2-b.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/google/google-us-east1-b.yml create mode 100644 share/oneprovision/edge-clusters/virtual/providers/google/google-us-west1-b.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/datastores.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/defaults.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/fireedge.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/inputs.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/networks.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/digitalocean.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/google.d/datastores.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/google.d/fireedge.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/google.d/inputs.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/google.d/networks.yml create mode 100644 share/oneprovision/edge-clusters/virtual/provisions/google.yml rename src/fireedge/src/client/assets/images/providers/{GOOGLECLOUD.png => GOOGLE.png} (100%) rename src/fireedge/src/client/assets/images/providers/{GOOGLECLOUD.webp => GOOGLE.webp} (100%) rename src/fireedge/src/client/assets/images/provisions/{OPENNEBULA-GOOGLECLOUD.png => OPENNEBULA-GOOGLE.png} (100%) rename src/fireedge/src/client/assets/images/provisions/{OPENNEBULA-GOOGLECLOUD.webp => OPENNEBULA-GOOGLE.webp} (100%) create mode 100644 src/oneprovision/lib/terraform/providers/digitalocean.rb create mode 100644 src/oneprovision/lib/terraform/providers/google.rb create mode 100644 src/oneprovision/lib/terraform/providers/templates/digitalocean/cluster.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/digitalocean/datastore.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/digitalocean/host.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/digitalocean/network.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/digitalocean/provider.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/google/cluster.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/google/datastore.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/google/host.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/google/network.erb create mode 100644 src/oneprovision/lib/terraform/providers/templates/google/provider.erb create mode 100755 src/vnm_mad/remotes/nodeport/clean create mode 100644 src/vnm_mad/remotes/nodeport/clean.d/.gitignore create mode 100644 src/vnm_mad/remotes/nodeport/nodeport.rb create mode 100755 src/vnm_mad/remotes/nodeport/post create mode 100644 src/vnm_mad/remotes/nodeport/post.d/.gitignore create mode 100755 src/vnm_mad/remotes/nodeport/pre create mode 100644 src/vnm_mad/remotes/nodeport/pre.d/.gitignore create mode 100755 src/vnm_mad/remotes/nodeport/update_sg diff --git a/include/AddressRange.h b/include/AddressRange.h index 5191c68e78..93b4e5cf2e 100644 --- a/include/AddressRange.h +++ b/include/AddressRange.h @@ -597,6 +597,14 @@ private: /* NIC setup functions */ /* ---------------------------------------------------------------------- */ + /** + * Writes EXTERNAL_PORT_RANGE and INTERNAL_PORT_RANGE to allocate Forward + * ports to an address lease. + * @param addr_index internal index for the lease + * @param nic attribute of a VMTemplate + */ + void set_port_ranges(unsigned int addr_index, VectorAttribute * nic) const; + /** * Writes MAC address to the given NIC attribute * @param addr_index internal index for the lease @@ -782,6 +790,16 @@ private: */ unsigned int ip6[4] = {0}; + /** + * Port range definition parameters. First port available in the range + */ + unsigned int port_start = 0; + + /** + * Port block size, each lease will have a block of port_size ports + */ + unsigned int port_size = 0; + /** * Security Group IDs for this Address Range */ diff --git a/install.sh b/install.sh index 02349dcabb..42849a1e7b 100755 --- a/install.sh +++ b/install.sh @@ -296,6 +296,8 @@ LIB_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/oneprovision/lib/terraform/providers \ $LIB_LOCATION/oneprovision/lib/terraform/providers/templates \ $LIB_LOCATION/oneprovision/lib/terraform/providers/templates/aws \ + $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/provision \ $LIB_LOCATION/oneprovision/lib/provision_template \ @@ -453,6 +455,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/vnm/vcenter/post.d \ $VAR_LOCATION/remotes/vnm/vcenter/clean.d \ $VAR_LOCATION/remotes/vnm/elastic \ + $VAR_LOCATION/remotes/vnm/nodeport\ $VAR_LOCATION/remotes/vnm/hooks/pre \ $VAR_LOCATION/remotes/vnm/hooks/post \ $VAR_LOCATION/remotes/vnm/hooks/clean \ @@ -720,6 +723,7 @@ INSTALL_FILES=( NETWORK_OVSWITCH_VXLAN_FILES:$VAR_LOCATION/remotes/vnm/ovswitch_vxlan NETWORK_VCENTER_FILES:$VAR_LOCATION/remotes/vnm/vcenter NETWORK_ELASTIC_FILES:$VAR_LOCATION/remotes/vnm/elastic + NETWORK_NODEPORT_FILES:$VAR_LOCATION/remotes/vnm/nodeport EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples EXAMPLE_HOST_HOOKS_SHARE_FILES:$SHARE_LOCATION/examples/host_hooks LXD_NETWORK_HOOKS:$SHARE_LOCATION/examples/network_hooks @@ -775,6 +779,8 @@ INSTALL_ONEPROVISION_FILES=( ONEPROVISION_LIB_TF_FILES:$LIB_LOCATION/oneprovision/lib/terraform ONEPROVISION_LIB_PROVIDERS_FILES:$LIB_LOCATION/oneprovision/lib/terraform/providers ONEPROVISION_LIB_AWS_ERB_FILES:$LIB_LOCATION/oneprovision/lib/terraform/providers/templates/aws + 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_PROVISION_FILES:$LIB_LOCATION/oneprovision/lib/provision ONEPROVISION_LIB_RESOURCES_FILES:$LIB_LOCATION/oneprovision/lib/provision/resources @@ -1740,6 +1746,12 @@ NETWORK_ELASTIC_FILES="src/vnm_mad/remotes/elastic/elastic.rb \ src/vnm_mad/remotes/elastic/pre \ src/vnm_mad/remotes/elastic/update_sg" +NETWORK_NODEPORT_FILES="src/vnm_mad/remotes/nodeport/nodeport.rb \ + src/vnm_mad/remotes/nodeport/clean \ + src/vnm_mad/remotes/nodeport/post \ + src/vnm_mad/remotes/nodeport/pre \ + src/vnm_mad/remotes/nodeport/update_sg" + #------------------------------------------------------------------------------- # Virtual Network Manager drivers configuration to be installed under $REMOTES_LOCATION/etc/vnm #------------------------------------------------------------------------------- @@ -1763,6 +1775,7 @@ IPAM_DRIVER_PACKET_SCRIPTS="src/ipamm_mad/remotes/packet/register_address_range src/ipamm_mad/remotes/packet/allocate_address \ src/ipamm_mad/remotes/packet/get_address \ src/ipamm_mad/remotes/packet/free_address" + #------------------------------------------------------------------------------- # IPAM EC2 drivers to be installed under $REMOTES_LOCATION/ipam #------------------------------------------------------------------------------- @@ -2472,6 +2485,8 @@ ONEPROVISION_LIB_TF_FILES="src/oneprovision/lib/terraform/terraform.rb \ src/oneprovision/lib/terraform/providers.rb" ONEPROVISION_LIB_PROVIDERS_FILES="src/oneprovision/lib/terraform/providers/aws.rb \ + 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" @@ -2481,6 +2496,18 @@ ONEPROVISION_LIB_AWS_ERB_FILES="src/oneprovision/lib/terraform/providers/templat src/oneprovision/lib/terraform/providers/templates/aws/network.erb \ src/oneprovision/lib/terraform/providers/templates/aws/provider.erb" +ONEPROVISION_LIB_GOOGLE_ERB_FILES="src/oneprovision/lib/terraform/providers/templates/google/cluster.erb \ + src/oneprovision/lib/terraform/providers/templates/google/datastore.erb \ + src/oneprovision/lib/terraform/providers/templates/google/host.erb \ + src/oneprovision/lib/terraform/providers/templates/google/network.erb \ + src/oneprovision/lib/terraform/providers/templates/google/provider.erb" + +ONEPROVISION_LIB_DIGITALOCEAN_ERB_FILES="src/oneprovision/lib/terraform/providers/templates/digitalocean/cluster.erb \ + src/oneprovision/lib/terraform/providers/templates/digitalocean/datastore.erb \ + src/oneprovision/lib/terraform/providers/templates/digitalocean/host.erb \ + src/oneprovision/lib/terraform/providers/templates/digitalocean/network.erb \ + src/oneprovision/lib/terraform/providers/templates/digitalocean/provider.erb" + ONEPROVISION_LIB_PACKET_ERB_FILES="src/oneprovision/lib/terraform/providers/templates/packet/cluster.erb \ src/oneprovision/lib/terraform/providers/templates/packet/datastore.erb \ src/oneprovision/lib/terraform/providers/templates/packet/host.erb \ diff --git a/share/doc/xsd/vnet.xsd b/share/doc/xsd/vnet.xsd index 0844eab640..d5bab61087 100644 --- a/share/doc/xsd/vnet.xsd +++ b/share/doc/xsd/vnet.xsd @@ -103,6 +103,8 @@ + + diff --git a/share/linters/.rubocop.yml b/share/linters/.rubocop.yml index 640070fb21..f7724337ce 100644 --- a/share/linters/.rubocop.yml +++ b/share/linters/.rubocop.yml @@ -309,7 +309,6 @@ AllCops: - src/cli/one_helper/onequota_helper.rb - src/cli/one_helper/oneuser_helper.rb - src/cli/one_helper/onegroup_helper.rb - - src/cli/one_helper/onevnet_helper.rb - src/cli/one_helper/onecluster_helper.rb - src/cli/one_helper/onevntemplate_helper.rb - src/cli/one_helper/onevrouter_helper.rb diff --git a/share/oneprovision/ansible/digitalocean.yml b/share/oneprovision/ansible/digitalocean.yml new file mode 100644 index 0000000000..3a05dd1eb1 --- /dev/null +++ b/share/oneprovision/ansible/digitalocean.yml @@ -0,0 +1,27 @@ +--- + +- hosts: all + gather_facts: false + roles: + - python + +- hosts: nodes + roles: + - ddc + - opennebula-repository + - { role: opennebula-node-kvm, when: oneprovision_hypervisor == 'kvm' or oneprovision_hypervisor == 'qemu' } + - { role: opennebula-node-firecracker, when: oneprovision_hypervisor == 'firecracker' } + - 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: 'eth1' + # Use /20 for the internal management network address + frr_prefix_length: 20 + diff --git a/share/oneprovision/ansible/google.yml b/share/oneprovision/ansible/google.yml new file mode 100644 index 0000000000..1a137309e7 --- /dev/null +++ b/share/oneprovision/ansible/google.yml @@ -0,0 +1,29 @@ +--- + +- hosts: all + gather_facts: false + roles: + - python + +- hosts: nodes + roles: + - 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: 'eth0' + # Use /16 for the internal management network address + frr_prefix_length: 16 + frr_zebra: true + frr_ipcalc: true diff --git a/share/oneprovision/ansible/roles/frr/defaults/main.yml b/share/oneprovision/ansible/roles/frr/defaults/main.yml index 13ac9754e2..7eaa3e15d7 100644 --- a/share/oneprovision/ansible/roles/frr/defaults/main.yml +++ b/share/oneprovision/ansible/roles/frr/defaults/main.yml @@ -15,3 +15,11 @@ frr_as: 65000 # Prefix length for the BGP network frr_prefix_length: 16 +# Configure Zebra +frr_zebra: false + +# Install and configure with ipcalc +frr_ipcalc: false + +# Default netmask for ipcalc +frr_net_mask: 20 diff --git a/share/oneprovision/ansible/roles/frr/tasks/centos.yml b/share/oneprovision/ansible/roles/frr/tasks/centos.yml index 3c4630142b..a640aa76e1 100644 --- a/share/oneprovision/ansible/roles/frr/tasks/centos.yml +++ b/share/oneprovision/ansible/roles/frr/tasks/centos.yml @@ -24,6 +24,21 @@ retries: 3 delay: 10 +- name: Install ipcalc + package: + name: ipcalc + state: latest + register: pkg_result + until: pkg_result is succeeded + retries: 3 + delay: 10 + when: frr_ipcalc == true + +- name: Get network address + shell: ipcalc -bn "{{ ansible_default_ipv4.network }}/{{ frr_net_mask }}" | grep NETWORK | cut -d '=' -f2 + register: frr_net + when: frr_ipcalc == true + - name: Configure BGP (RR) template: src: bgpd_rr.conf.j2 @@ -36,6 +51,18 @@ dest: /etc/frr/bgpd.conf when: not vars['ansible_' + frr_iface].ipv4.address in rr_servers +- name: Configure Zebra + template: + src: zebra.conf.j2 + dest: /etc/frr/zebra.conf + when: frr_zebra == true + +- name: Configure Staticd + template: + src: staticd.conf.j2 + dest: /etc/frr/staticd.conf + when: frr_zebra == true + - name: Enable BGP daemon replace: path: /etc/frr/daemons diff --git a/share/oneprovision/ansible/roles/frr/templates/staticd.conf.j2 b/share/oneprovision/ansible/roles/frr/templates/staticd.conf.j2 new file mode 100644 index 0000000000..ea92c0f7c1 --- /dev/null +++ b/share/oneprovision/ansible/roles/frr/templates/staticd.conf.j2 @@ -0,0 +1,2 @@ +hostname {{ ansible_nodename }} +ip route {{ frr_net.stdout }}/{{ frr_net_mask }} {{ ansible_default_ipv4.gateway }} diff --git a/share/oneprovision/ansible/roles/frr/templates/zebra.conf.j2 b/share/oneprovision/ansible/roles/frr/templates/zebra.conf.j2 new file mode 100644 index 0000000000..d425035bf4 --- /dev/null +++ b/share/oneprovision/ansible/roles/frr/templates/zebra.conf.j2 @@ -0,0 +1,2 @@ +hostname {{ ansible_nodename }} +ip nht resolve-via-default diff --git a/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-ams3.yml b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-ams3.yml new file mode 100644 index 0000000000..b94f51cc4b --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-ams3.yml @@ -0,0 +1,19 @@ +name: 'digitalocean-nyc3' + +description: 'cluster on DigitalOcean in Amsterdam 3' +provider: 'digitalocean' + +plain: + image: 'DIGITALOCEAN' + location_key: 'region' + provision_type: 'virtual' + +connection: + token: 'DigitalOcean token' + region: 'ams3' + +inputs: + - name: 'digitalocean_droplet' + type: 'list' + options: + - 'centos-7-x64' diff --git a/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-lon1.yml b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-lon1.yml new file mode 100644 index 0000000000..b21b493474 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-lon1.yml @@ -0,0 +1,19 @@ +name: 'digitalocean-nyc3' + +description: 'cluster on DigitalOcean in London' +provider: 'digitalocean' + +plain: + image: 'DIGITALOCEAN' + location_key: 'region' + provision_type: 'virtual' + +connection: + token: 'DigitalOcean token' + region: 'lon1' + +inputs: + - name: 'digitalocean_droplet' + type: 'list' + options: + - 'centos-7-x64' diff --git a/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-nyc3.yml b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-nyc3.yml new file mode 100644 index 0000000000..88d97ebfc6 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-nyc3.yml @@ -0,0 +1,19 @@ +name: 'digitalocean-nyc3' + +description: 'cluster on DigitalOcean in New York 3' +provider: 'digitalocean' + +plain: + image: 'DIGITALOCEAN' + location_key: 'region' + provision_type: 'virtual' + +connection: + token: 'DigitalOcean token' + region: 'nyc3' + +inputs: + - name: 'digitalocean_droplet' + type: 'list' + options: + - 'centos-7-x64' diff --git a/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-sfo3.yml b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-sfo3.yml new file mode 100644 index 0000000000..ef4e277d12 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-sfo3.yml @@ -0,0 +1,19 @@ +name: 'digitalocean-nyc3' + +description: 'cluster on DigitalOcean in San Franciso 3' +provider: 'digitalocean' + +plain: + image: 'DIGITALOCEAN' + location_key: 'region' + provision_type: 'virtual' + +connection: + token: 'DigitalOcean token' + region: 'sfo3' + +inputs: + - name: 'digitalocean_droplet' + type: 'list' + options: + - 'centos-7-x64' diff --git a/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-sgp1.yml b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-sgp1.yml new file mode 100644 index 0000000000..9d7feb2e86 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/digitalocean/do-sgp1.yml @@ -0,0 +1,19 @@ +name: 'digitalocean-nyc3' + +description: 'cluster on DigitalOcean in Singapore' +provider: 'digitalocean' + +plain: + image: 'DIGITALOCEAN' + location_key: 'region' + provision_type: 'virtual' + +connection: + token: 'DigitalOcean token' + region: 'sgp1' + +inputs: + - name: 'digitalocean_droplet' + type: 'list' + options: + - 'centos-7-x64' diff --git a/share/oneprovision/edge-clusters/virtual/providers/google/google-europe-west1-b.yml b/share/oneprovision/edge-clusters/virtual/providers/google/google-europe-west1-b.yml new file mode 100644 index 0000000000..e6945a24d9 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/google/google-europe-west1-b.yml @@ -0,0 +1,27 @@ +name: 'google-belgium' + +description: 'Elastic cluster on Google in Belgium' +provider: 'google' + +plain: + image: 'GOOGLE' + location_key: 'zone' + provision_type: 'virtual' + +connection: + credentials: 'JSON credentials file' + project: 'Google Cloud Plataform project ID' + region: 'europe-west1' + zone: 'europe-west1-b' + +inputs: + - name: 'google_image' + type: 'list' + options: + - 'centos-8-v20210316' + - name: 'google_machine_type' + type: 'list' + options: + - 'e2-standard-2' + - 'e2-standard-4' + - 'e2-standard-8' diff --git a/share/oneprovision/edge-clusters/virtual/providers/google/google-europe-west2-b.yml b/share/oneprovision/edge-clusters/virtual/providers/google/google-europe-west2-b.yml new file mode 100644 index 0000000000..1b298144cd --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/google/google-europe-west2-b.yml @@ -0,0 +1,27 @@ +name: 'google-london' + +description: 'Elastic cluster on Google in London' +provider: 'google' + +plain: + image: 'GOOGLE' + location_key: 'zone' + provision_type: 'virtual' + +connection: + credentials: 'JSON credentials file' + project: 'Google Cloud Plataform project ID' + region: 'europe-west2' + zone: 'europe-west2-b' + +inputs: + - name: 'google_image' + type: 'list' + options: + - 'centos-8-v20210316' + - name: 'google_machine_type' + type: 'list' + options: + - 'e2-standard-2' + - 'e2-standard-4' + - 'e2-standard-8' diff --git a/share/oneprovision/edge-clusters/virtual/providers/google/google-us-east1-b.yml b/share/oneprovision/edge-clusters/virtual/providers/google/google-us-east1-b.yml new file mode 100644 index 0000000000..74e0e52832 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/google/google-us-east1-b.yml @@ -0,0 +1,27 @@ +name: 'google-moncks' + +description: 'Elastic cluster on Google in Moncks' +provider: 'google' + +plain: + image: 'GOOGLE' + location_key: 'zone' + provision_type: 'virtual' + +connection: + credentials: 'JSON credentials file' + project: 'Google Cloud Plataform project ID' + region: 'us-east1' + zone: 'us-east1-b' + +inputs: + - name: 'google_image' + type: 'list' + options: + - 'centos-8-v20210316' + - name: 'google_machine_type' + type: 'list' + options: + - 'e2-standard-2' + - 'e2-standard-4' + - 'e2-standard-8' diff --git a/share/oneprovision/edge-clusters/virtual/providers/google/google-us-west1-b.yml b/share/oneprovision/edge-clusters/virtual/providers/google/google-us-west1-b.yml new file mode 100644 index 0000000000..3cddfbc3fc --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/providers/google/google-us-west1-b.yml @@ -0,0 +1,27 @@ +name: 'google-oregon' + +description: 'Elastic cluster on Google in Oregon' +provider: 'google' + +plain: + image: 'GOOGLE' + location_key: 'zone' + provision_type: 'virtual' + +connection: + credentials: 'JSON credentials file' + project: 'Google Cloud Plataform project ID' + region: 'us-west1' + zone: 'us-west1-b' + +inputs: + - name: 'google_image' + type: 'list' + options: + - 'centos-8-v20210316' + - name: 'google_machine_type' + type: 'list' + options: + - 'e2-standard-2' + - 'e2-standard-4' + - 'e2-standard-8' diff --git a/share/oneprovision/edge-clusters/virtual/provisions/common.d/hosts.yml b/share/oneprovision/edge-clusters/virtual/provisions/common.d/hosts.yml index 4ff159ce14..040449cea2 100644 --- a/share/oneprovision/edge-clusters/virtual/provisions/common.d/hosts.yml +++ b/share/oneprovision/edge-clusters/virtual/provisions/common.d/hosts.yml @@ -16,7 +16,7 @@ # ---------------------------------------------------------------------------- # #------------------------------------------------------------------------------- -# hosts: Packet or AWS metal servers +# hosts: AWS, Digital Ocean or Google servers # provision: # - count: Number of servers to create # - hostname: kvm-host1, kvm-host2 .... of the server diff --git a/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/datastores.yml b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/datastores.yml new file mode 100644 index 0000000000..78bb9bf37f --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/datastores.yml @@ -0,0 +1,39 @@ +--- +# ---------------------------------------------------------------------------- # +# 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 +# +# 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/digitalocean.d/defaults.yml b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/defaults.yml new file mode 100644 index 0000000000..8b6295f4d8 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/defaults.yml @@ -0,0 +1,24 @@ +--- +# ---------------------------------------------------------------------------- # +# 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. # +# ---------------------------------------------------------------------------- # + +#------------------------------------------------------------------------------- +# defaults: Common configuration attributes for provision objects +#-------------------------------------------------------------------------------- +# configuration: Ansible role parameters. +#-------------------------------------------------------------------------------- +# Check defaults/main.yml in each role for the available variables +#------------------------------------------------------------------------------- diff --git a/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/fireedge.yml b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/fireedge.yml new file mode 100644 index 0000000000..fb3f6c3fab --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.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-DIGITALOCEAN' +provider: 'digitalocean' +provision_type: 'virtual' diff --git a/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/inputs.yml b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/inputs.yml new file mode 100644 index 0000000000..a4682115b7 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/inputs.yml @@ -0,0 +1,45 @@ +--- +# ---------------------------------------------------------------------------- # +# 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: 'digitalocean_image' + type: text + description: "digitalocean host operating system" + default: 'centos-8-x64' + + - name: 'digitalocean_size' + type: text + description: "digitalocean host size" + default: 's-1vcpu-1gb' + + - name: 'one_hypervisor' + type: list + description: "Virtualization technology for the cluster hosts" + options: + - 'qemu' + - 'lxc' +... diff --git a/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/networks.yml b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/networks.yml new file mode 100644 index 0000000000..3246a38925 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.d/networks.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. # +# ---------------------------------------------------------------------------- # + +networks: + - name: "${provision}-public" + vn_mad: 'nodeport' + bridge: 'br0' + netrole: 'public' + ar: + - type: 'IP4' + ip: "192.168.23.2" + size: 250 + port_start: 9000 + port_size: 100 + gateway: "192.168.23.1" + +vntemplates: + - name: "${provision}-private" + vn_mad: 'vxlan' + phydev: 'eth1' + 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/digitalocean.yml b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.yml new file mode 100644 index 0000000000..d6c637507f --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/digitalocean.yml @@ -0,0 +1,74 @@ +--- +# ---------------------------------------------------------------------------- # +# 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 'digitalocean' +# resources using the KVM hypervisor. +# ------------------------------------------------------------------------------ + +name: 'digitalocean-cluster' + +extends: + - common.d/defaults.yml + - common.d/resources.yml + - common.d/hosts.yml + - digitalocean.d/datastores.yml + - digitalocean.d/defaults.yml + - digitalocean.d/fireedge.yml + - digitalocean.d/inputs.yml + - digitalocean.d/networks.yml + +#------------------------------------------------------------------------------- +# playbook: Ansible playbook used for hosts configuration.The digitalocean playbook +# include the following roles: +# - ddc +# - opennebula-repository +# - opennebula-node-kvm +# - opennebula-ssh +# - tuntap +# - bridged-networking +# - iptables +#------------------------------------------------------------------------------- +playbook: + - digitalocean + +#------------------------------------------------------------------------------- +# defaults: Common configuration attributes for provision objects +#-------------------------------------------------------------------------------- +defaults: + provision: + provider_name: 'digitalocean' + image: "${input.digitalocean_image}" + size: "${input.digitalocean_size}" + connection: + remote_user: 'install' + +#------------------------------------------------------------------------------- +# 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: 'digitalocean cluster' + datastores: + - 1 + reserved_cpu: '0' + reserved_mem: '0' diff --git a/share/oneprovision/edge-clusters/virtual/provisions/google.d/datastores.yml b/share/oneprovision/edge-clusters/virtual/provisions/google.d/datastores.yml new file mode 100644 index 0000000000..78bb9bf37f --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/google.d/datastores.yml @@ -0,0 +1,39 @@ +--- +# ---------------------------------------------------------------------------- # +# 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 +# +# 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/google.d/fireedge.yml b/share/oneprovision/edge-clusters/virtual/provisions/google.d/fireedge.yml new file mode 100644 index 0000000000..bd20bfc545 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/google.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-GOOGLE' +provider: 'google' +provision_type: 'virtual' diff --git a/share/oneprovision/edge-clusters/virtual/provisions/google.d/inputs.yml b/share/oneprovision/edge-clusters/virtual/provisions/google.d/inputs.yml new file mode 100644 index 0000000000..3b3cb5d783 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/google.d/inputs.yml @@ -0,0 +1,45 @@ +--- +# ---------------------------------------------------------------------------- # +# 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 Google instances to create' + default: '1' + + - name: 'number_public_ips' + type: text + description: 'Number of public IPs to get' + default: '1' + + - name: 'google_image' + type: text + description: "Google image used for host deployments" + default: '' + + - name: 'google_machine_type' + type: text + description: "Google instance type, use virtual instances" + default: '' + + - name: 'one_hypervisor' + type: list + description: "Virtualization technology for the cluster hosts" + options: + - 'qemu' + - 'lxc' +... diff --git a/share/oneprovision/edge-clusters/virtual/provisions/google.d/networks.yml b/share/oneprovision/edge-clusters/virtual/provisions/google.d/networks.yml new file mode 100644 index 0000000000..eb36f754ac --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/google.d/networks.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. # +# ---------------------------------------------------------------------------- # + +networks: + - name: "${provision}-public" + vn_mad: 'nodeport' + bridge: 'br0' + netrole: 'public' + ar: + - type: 'IP4' + ip: "192.168.23.2" + size: 250 + port_start: 9000 + port_size: 100 + gateway: "192.168.23.1" + +vntemplates: + - name: "${provision}-private" + vn_mad: 'vxlan' + phydev: 'eth0' + 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/google.yml b/share/oneprovision/edge-clusters/virtual/provisions/google.yml new file mode 100644 index 0000000000..3c4337d699 --- /dev/null +++ b/share/oneprovision/edge-clusters/virtual/provisions/google.yml @@ -0,0 +1,67 @@ +--- +# ---------------------------------------------------------------------------- # +# 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 'Google' +# resources using the KVM hypervisor. +# ------------------------------------------------------------------------------ + +name: 'google-cluster' + +extends: + - common.d/defaults.yml + - common.d/resources.yml + - common.d/hosts.yml + - google.d/datastores.yml + - google.d/fireedge.yml + - google.d/inputs.yml + - google.d/networks.yml + +#------------------------------------------------------------------------------- +# playbook: Ansible playbook used for hosts configuration. +# Check ansible/googl.yml for the specific roles applied. +#------------------------------------------------------------------------------- +playbook: + - google + +#------------------------------------------------------------------------------- +# defaults: Common configuration attributes for provision objects +#------------------------------------------------------------------------------- +defaults: + provision: + provider_name: 'google' + image: "${input.google_image}" + machinetype: "${input.google_machine_type}" + connection: + remote_user: 'install' + +#------------------------------------------------------------------------------- +# 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: 'Google virtual edge cluster' + reserved_cpu: '0' + reserved_mem: '0' + datastores: + - 1 + - 2 diff --git a/share/shell/bash_completion b/share/shell/bash_completion index 32cefd6ab0..d94ecda155 100644 --- a/share/shell/bash_completion +++ b/share/shell/bash_completion @@ -723,7 +723,7 @@ _onevm() { rename snapshot-create snapshot-revert snapshot-delete disk-snapshot-create disk-snapshot-revert disk-snapshot-delete disk-snapshot-rename disk-resize list show top resize save updateconf lock unlock create-chart - delete-chart update-chart backup restore" + delete-chart update-chart backup restore ssh port-forward" cmd=onevm if [ "$COMP_CWORD" == 1 ]; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -735,7 +735,7 @@ _onevm() { unresched|rename|snapshot-create|snapshot-revert|snapshot-delete| \ disk-snapshot-create|disk-snapshot-delete|disk-snapshot-revert| \ disk-snapshot-rename|disk-resize|save|updateconf|lock|unlock|create-chart| \ - delete-chart|update-chart|backup|restore) + delete-chart|update-chart|backup|restore|ssh|port-forward) _complete $cmd ;; undeploy|poweroff|reboot|shutdown|suspend|stop|migrate) diff --git a/src/cli/one_helper/onevm_helper.rb b/src/cli/one_helper/onevm_helper.rb index a6940fb288..bf8c9a4180 100644 --- a/src/cli/one_helper/onevm_helper.rb +++ b/src/cli/one_helper/onevm_helper.rb @@ -1086,6 +1086,26 @@ class OneVMHelper < OpenNebulaHelper::OneHelper end end + if vm_hash['VM']['TEMPLATE']['NIC'] + nic = [vm_hash['VM']['TEMPLATE']['NIC']] + nic = nic.flatten + nic = nic.select {|v| !v['EXTERNAL_PORT_RANGE'].nil? }[0] + + if nic + ip = vm_hash['VM']['HISTORY_RECORDS']['HISTORY'] + ip = [ip].flatten[-1]['HOSTNAME'] + port = Integer(nic['EXTERNAL_PORT_RANGE'].split(':')[0]) + 21 + + puts + CLIHelper.print_header(str_h1 % 'PORT FORWARD', false) + + puts "[#{nic['EXTERNAL_PORT_RANGE']}]:" \ + "[#{nic['INTERNAL_PORT_RANGE'].split('/')[0]}]" + + puts "SSH on #{ip} at port #{port}" + end + end + if !options[:all] while vm.has_elements?('/VM/TEMPLATE/NIC') vm.delete_element('/VM/TEMPLATE/NIC') diff --git a/src/cli/one_helper/onevnet_helper.rb b/src/cli/one_helper/onevnet_helper.rb index 37852d1b2b..ce31e8ee19 100644 --- a/src/cli/one_helper/onevnet_helper.rb +++ b/src/cli/one_helper/onevnet_helper.rb @@ -16,174 +16,176 @@ require 'one_helper' require 'one_helper/onevm_helper' +# OneVnet Command Helper class OneVNetHelper < OpenNebulaHelper::OneHelper + AR = { - :name => "address_range", - :short => "-a ar_id", - :large => "--address_range ar_id", + :name => 'address_range', + :short => '-a ar_id', + :large => '--address_range ar_id', :format => Integer, - :description => "ID of the address range" + :description => 'ID of the address range' } SHOW_AR = { - :name => "show_ar", - :large => "--show-ar", - :description => "Show also AR templates" + :name => 'show_ar', + :large => '--show-ar', + :description => 'Show also AR templates' } MAC = { - :name => "mac", - :short => "-m mac", - :large => "--mac mac", + :name => 'mac', + :short => '-m mac', + :large => '--mac mac', :format => String, - :description => "First MAC address in : notation" + :description => 'First MAC address in : notation' } IP = { - :name => "ip", - :short => "-i ip", - :large => "--ip ip", + :name => 'ip', + :short => '-i ip', + :large => '--ip ip', :format => String, - :description => "First IP address in . notation" + :description => 'First IP address in . notation' } IP6 = { - :name => "ip6", - :short => "-6 ip6", - :large => "--ip6 ip6", + :name => 'ip6', + :short => '-6 ip6', + :large => '--ip6 ip6', :format => String, - :description => "First IPv6 address, in CIDR notation e.g. 2001::1/48" + :description => 'First IPv6 address, in CIDR notation e.g. 2001::1/48' } SIZE = { - :name => "size", - :short => "-s size", - :large => "--size size", + :name => 'size', + :short => '-s size', + :large => '--size size', :format => String, - :description => "Number of addresses" + :description => 'Number of addresses' } IP6_GLOBAL = { - :name => "ip6_global", - :short => "-g ip6_pref", - :large => "--ip6_global ip6_pref", + :name => 'ip6_global', + :short => '-g ip6_pref', + :large => '--ip6_global ip6_pref', :format => String, - :description => "IP6 global prefix" + :description => 'IP6 global prefix' } IP6_ULA = { - :name => "ip6_ula", - :short => "-u ip6_pref", - :large => "--ip6_ula ip6_pref", + :name => 'ip6_ula', + :short => '-u ip6_pref', + :large => '--ip6_ula ip6_pref', :format => String, - :description => "IP6 ula prefix" + :description => 'IP6 ula prefix' } NAME = { - :name => "name", - :short => "-n reservation name", - :large => "--name reservation name", + :name => 'name', + :short => '-n reservation name', + :large => '--name reservation name', :format => String, - :description => "Name of the address reservation" + :description => 'Name of the address reservation' } -# R_SIZE = { -# :name => "rsize", -# :short => "-s reservation size", -# :large => "--size reservation size", -# :format => String, -# :description => "Number of addresses to reserve" -# } + # R_SIZE = { + # :name => "rsize", + # :short => "-s reservation size", + # :large => "--size reservation size", + # :format => String, + # :description => "Number of addresses to reserve" + # } GATEWAY = { - :name => "gateway", - :large => "--gateway ip", + :name => 'gateway', + :large => '--gateway ip', :format => String, - :description=> "IP of the gateway" + :description=> 'IP of the gateway' } NETMASK = { - :name => "netmask", - :large => "--netmask mask", + :name => 'netmask', + :large => '--netmask mask', :format => String, - :description=> "Netmask in dot notation" + :description=> 'Netmask in dot notation' } VN_MAD = { - :name => "vn_mad", - :large => "--vn_mad mad", + :name => 'vn_mad', + :large => '--vn_mad mad', :format => String, - :description=> "Use this driver for the network" + :description=> 'Use this driver for the network' } VLAN_ID = { - :name => "vlanid", - :large => "--vlanid id", + :name => 'vlanid', + :large => '--vlanid id', :format => String, - :description=> "VLAN ID assigned" + :description=> 'VLAN ID assigned' } ADDAR_OPTIONS = [ SIZE, MAC, IP, IP6, IP6_GLOBAL, IP6_ULA, GATEWAY, NETMASK, VN_MAD, - VLAN_ID ] + VLAN_ID + ] def self.rname - "VNET" + 'VNET' end def self.conf_file - "onevnet.yaml" + 'onevnet.yaml' end def format_pool(options) config_file = self.class.table_conf - table = CLIHelper::ShowTable.new(config_file, self) do - column :ID, "ONE identifier for Virtual Network", :size=>4 do |d| - d["ID"] + CLIHelper::ShowTable.new(config_file, self) do + column :ID, 'ONE identifier for Virtual Network', :size=>4 do |d| + d['ID'] end - column :USER, "Username of the Virtual Network owner", :left, - :size=>15 do |d| + column :USER, 'Username of the Virtual Network owner', :left, + :size=>15 do |d| helper.user_name(d, options) end - column :GROUP, "Group of the Virtual Network", :left, - :size=>12 do |d| + column :GROUP, 'Group of the Virtual Network', :left, + :size=>12 do |d| helper.group_name(d, options) end - column :NAME, "Name of the Virtual Network", :left, - :size=>19 do |d| - d["NAME"] + column :NAME, 'Name of the Virtual Network', :left, + :size=>19 do |d| + d['NAME'] end - column :CLUSTERS, "Cluster IDs", :left, :size=>10 do |d| - OpenNebulaHelper.clusters_str(d["CLUSTERS"]["ID"]) rescue "-" + column :CLUSTERS, 'Cluster IDs', :left, :size=>10 do |d| + OpenNebulaHelper.clusters_str(d['CLUSTERS']['ID']) rescue '-' end - column :BRIDGE, "Bridge associated to the Virtual Network", :left, - :size=>8 do |d| - d["BRIDGE"] + column :BRIDGE, 'Bridge associated to the Virtual Network', :left, + :size=>8 do |d| + d['BRIDGE'] end column :LEASES, "Number of this Virtual Network's given leases", - :size=>6 do |d| - d["USED_LEASES"] + :size=>6 do |d| + d['USED_LEASES'] end default :ID, :USER, :GROUP, :NAME, :CLUSTERS, :BRIDGE, :LEASES end - - table end def show_ar(vn, ar_id) - CLIHelper.print_header("%-80s" % ["TEMPLATE FOR AR #{ar_id}"], false) + CLIHelper.print_header(format('%-80s', "TEMPLATE FOR AR #{ar_id}"), + false) begin template = vn.template_like_str("AR_POOL/AR[AR_ID=#{ar_id}]") - rescue + rescue StandardError STDERR.puts "Can not get template for AR #{ar_id}" return end @@ -281,7 +283,7 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper private - def factory(id=nil) + def factory(id = nil) if id OpenNebula::VirtualNetwork.new_with_id(id, @client) else @@ -290,55 +292,63 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper end end - def factory_pool(user_flag=-2) + def factory_pool(user_flag = -2) OpenNebula::VirtualNetworkPool.new(@client, user_flag) end def format_resource(vn, options = {}) vn_hash = vn.to_hash - str_h1="%-80s" - CLIHelper.print_header(str_h1 % - ["VIRTUAL NETWORK #{vn.id.to_s} INFORMATION"]) + str_h1='%-80s' + CLIHelper.print_header(format(str_h1, + "VIRTUAL NETWORK #{vn.id} INFORMATION")) - str="%-25s: %-20s" - puts str % ["ID", vn.id.to_s] - puts str % ["NAME", vn['NAME']] - puts str % ["USER", vn['UNAME']] - puts str % ["GROUP", vn['GNAME']] - puts str % ["LOCK", OpenNebulaHelper.level_lock_to_str(vn['LOCK/LOCKED'])] - puts str % ["CLUSTERS", - OpenNebulaHelper.clusters_str(vn.retrieve_elements("CLUSTERS/ID"))] - puts str % ["BRIDGE", vn["BRIDGE"]] - puts str % ["VN_MAD", vn['VN_MAD']] if !vn['VN_MAD'].empty? - puts str % ["PHYSICAL DEVICE", vn["PHYDEV"]] if !vn["PHYDEV"].empty? - puts str % ["VLAN ID", vn["VLAN_ID"]] if !vn["VLAN_ID"].empty? - puts str % ["AUTOMATIC VLAN ID", vn["VLAN_ID_AUTOMATIC"]=="1" ? "YES" : "NO"] - puts str % ["OUTER VLAN ID", vn["OUTER_VLAN_ID"]] if !vn["OUTER_VLAN_ID"] - puts str % ["AUTOMATIC OUTER VLAN ID", vn["OUTER_VLAN_ID_AUTOMATIC"]=="1" ? "YES" : "NO"] - puts str % ["USED LEASES", vn['USED_LEASES']] + str='%-25s: %-20s' + puts format(str, 'ID', vn.id.to_s) + puts format(str, 'NAME', vn['NAME']) + puts format(str, 'USER', vn['UNAME']) + puts format(str, 'GROUP', vn['GNAME']) + puts format(str, 'LOCK', + OpenNebulaHelper.level_lock_to_str(vn['LOCK/LOCKED'])) + puts format(str, 'CLUSTERS', + OpenNebulaHelper.clusters_str( + vn.retrieve_elements('CLUSTERS/ID') + )) + puts format(str, 'BRIDGE', vn['BRIDGE']) + puts format(str, 'VN_MAD', vn['VN_MAD']) unless vn['VN_MAD'].empty? + puts format(str, 'PHYSICAL DEVICE', + vn['PHYDEV']) unless vn['PHYDEV'].empty? + puts format(str, 'VLAN ID', vn['VLAN_ID']) unless vn['VLAN_ID'].empty? + puts format(str, 'AUTOMATIC VLAN ID', + vn['VLAN_ID_AUTOMATIC']=='1' ? 'YES' : 'NO') + puts format(str, 'OUTER VLAN ID', + vn['OUTER_VLAN_ID']) unless vn['OUTER_VLAN_ID'] + puts format(str, 'AUTOMATIC OUTER VLAN ID', + vn['OUTER_VLAN_ID_AUTOMATIC']=='1' ? 'YES' : 'NO') + puts format(str, 'USED LEASES', vn['USED_LEASES']) puts - CLIHelper.print_header(str_h1 % "PERMISSIONS",false) + CLIHelper.print_header(str_h1 % 'PERMISSIONS', false) - ["OWNER", "GROUP", "OTHER"].each { |e| - mask = "---" - mask[0] = "u" if vn["PERMISSIONS/#{e}_U"] == "1" - mask[1] = "m" if vn["PERMISSIONS/#{e}_M"] == "1" - mask[2] = "a" if vn["PERMISSIONS/#{e}_A"] == "1" + %w[OWNER GROUP OTHER].each do |e| + mask = '---' + mask[0] = 'u' if vn["PERMISSIONS/#{e}_U"] == '1' + mask[1] = 'm' if vn["PERMISSIONS/#{e}_M"] == '1' + mask[2] = 'a' if vn["PERMISSIONS/#{e}_A"] == '1' - puts str % [e, mask] - } + puts format(str, e, mask) + end puts - CLIHelper.print_header(str_h1 % ["VIRTUAL NETWORK TEMPLATE"], false) + CLIHelper.print_header(format(str_h1, 'VIRTUAL NETWORK TEMPLATE'), + false) puts vn.template_str(false) puts - CLIHelper.print_header(str_h1 % ["ADDRESS RANGE POOL"], false) + CLIHelper.print_header(format(str_h1, 'ADDRESS RANGE POOL'), false) arlist = [] @@ -347,70 +357,72 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper end arlist.each do |ar| + CLIHelper.print_header(format('%-80s', "AR #{ar['AR_ID']}")) - CLIHelper.print_header("%-80s" % "AR #{ar["AR_ID"]}") - - str="%-15s: %-20s" - puts str % ["SIZE", ar["SIZE"]] - puts str % ["LEASES", ar["USED_LEASES"]] - puts str % ["VN_MAD", ar["VN_MAD"]] if ar["VN_MAD"] - puts str % ["IPAM_MAD", ar["IPAM_MAD"]] if ar["IPAM_MAD"] + str='%-15s: %-20s' + puts format(str, 'SIZE', ar['SIZE']) + puts format(str, 'LEASES', ar['USED_LEASES']) + puts format(str, 'VN_MAD', ar['VN_MAD']) if ar['VN_MAD'] + puts format(str, 'IPAM_MAD', ar['IPAM_MAD']) if ar['IPAM_MAD'] puts - format = "%-10s %34s %34s" - CLIHelper.print_header(format % ["RANGE", "FIRST", "LAST"], false) + format = '%-10s %34s %34s' + CLIHelper.print_header( + format(format, 'RANGE', 'FIRST', 'LAST'), false + ) - puts format % ["MAC", ar["MAC"], ar["MAC_END"]] + puts format(format, 'MAC', ar['MAC'], ar['MAC_END']) - if !ar["IP"].nil? - puts format % ["IP", ar["IP"], ar["IP_END"]] + if !ar['IP'].nil? + puts format(format, 'IP', ar['IP'], ar['IP_END']) end - if !ar["IP6_GLOBAL"].nil? - puts format % ["IP6_GLOBAL", ar["IP6_GLOBAL"], ar["IP6_GLOBAL_END"]] + if !ar['IP6_GLOBAL'].nil? + puts format(format, 'IP6_GLOBAL', ar['IP6_GLOBAL'], + ar['IP6_GLOBAL_END']) end - if !ar["IP6_ULA"].nil? - puts format % ["IP6_ULA", ar["IP6_ULA"], ar["IP6_ULA_END"]] + if !ar['IP6_ULA'].nil? + puts format(format, 'IP6_ULA', ar['IP6_ULA'], ar['IP6_ULA_END']) end - if !ar["IP6"].nil? - puts format % ["IP6", ar["IP6"], ar["IP6_END"]] + if !ar['IP6'].nil? + puts format(format, 'IP6', ar['IP6'], ar['IP6_END']) end puts end puts - CLIHelper.print_header(str_h1 % ["LEASES"], false) + CLIHelper.print_header(format(str_h1, 'LEASES'), false) ar_list = [] if !vn_hash['VNET']['AR_POOL']['AR'].nil? lease_list = [vn_hash['VNET']['AR_POOL']['AR']].flatten - leases = Array.new + leases = [] lease_list.each do |ar| id = ar['AR_ID'] ar_list << id - if ar['LEASES'] && !ar['LEASES']['LEASE'].nil? - lease = [ar['LEASES']['LEASE']].flatten - lease.each do |l| - l['AR_ID'] = id - end - leases << lease + next unless ar['LEASES'] && !ar['LEASES']['LEASE'].nil? + + lease = [ar['LEASES']['LEASE']].flatten + lease.each do |l| + l['AR_ID'] = id end + leases << lease end leases.flatten! end CLIHelper::ShowTable.new(nil, self) do - column :AR, "", :left, :size=>3 do |d| + column :AR, '', :left, :size=>3 do |d| d['AR_ID'] end - column :OWNER, "", :left, :size=>15 do |d| + column :OWNER, '', :left, :size=>10 do |d| if d['VM'] "V:#{d['VM']}" elsif d['VNET'] @@ -420,31 +432,40 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper end end - column :MAC, "", :size=>17 do |d| - d["MAC"] + column :MAC, '', :adjust do |d| + d['MAC'] end - column :IP, "", :size=>15 do |d| - d["IP"]||"-" + column :IP, '', :adjust do |d| + d['IP'] || '-' end - column :IP6, "", :adjust, :size=>26 do |d| - d["IP6"]||d["IP6_GLOBAL"]||"-" + column :PORT_FORWARD, '', :adjust do |d| + if d['EXTERNAL_PORT_RANGE'] + "[#{d['EXTERNAL_PORT_RANGE']}]:" \ + "[#{d['INTERNAL_PORT_RANGE'].split('/')[0]}]" + else + '-' + end + end + + column :IP6, '', :adjust do |d| + d['IP6']||d['IP6_GLOBAL']||'-' end end.show(leases, {}) puts - CLIHelper.print_header("%-15s" % "VIRTUAL ROUTERS") + CLIHelper.print_header(format('%-15s', 'VIRTUAL ROUTERS')) vn.vrouter_ids.each do |id| - puts "%-15s" % [id] + puts format('%-15s', id) end - if options[:show_ar] - ar_list.each do |ar_id| - puts - show_ar(vn, ar_id) - end + return unless options[:show_ar] + + ar_list.each do |ar_id| + puts + show_ar(vn, ar_id) end end @@ -459,4 +480,5 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper # in options hash (add_ar_options-options.keys)!=add_ar_options end + end diff --git a/src/cli/onevm b/src/cli/onevm index 81a009c1de..f62a777130 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -207,6 +207,20 @@ CommandParser::CmdParser.new(ARGV) do :description => 'Market to save oneshot' } + NIC_ID = { + :name => 'nic_id', + :large => '--nic-id nic_id', + :format => String, + :description => 'NIC to use when SSH' + } + + CMD = { + :name => 'cmd', + :large => '--cmd cmd', + :format => String, + :description => 'CMD to run when SSH' + } + ######################################################################## # Global Options ######################################################################## @@ -1526,6 +1540,116 @@ CommandParser::CmdParser.new(ARGV) do end end + ssh_desc = <<-EOT.unindent + SSH into VM + EOT + + command :ssh, ssh_desc, :vmid, [:login, nil], :options => [NIC_ID, CMD] do + helper.perform_action(args[0], options, 'SSH') do |vm| + rc = vm.info + + if OpenNebula.is_error?(rc) + STDERR.puts rc.message + exit(-1) + end + + # Get user to login + args[1].nil? ? login = 'root' : login = args[1] + + # Get CMD to run + options[:cmd].nil? ? cmd = '' : cmd = options[:cmd] + + # Get NIC to connect + if options[:nic_id] + nic = vm.retrieve_xmlelements( + "//TEMPLATE/NIC[NIC_ID=\"#{options[:nic_id]}\"]" + )[0] + else + nic = vm.retrieve_xmlelements('//TEMPLATE/NIC[SSH="YES"]')[0] + end + + nic = vm.retrieve_xmlelements('//TEMPLATE/NIC[1]')[0] if nic.nil? + + if nic.nil? + STDERR.puts 'No NIC found' + exit(-1) + end + + # If there is node port + if nic['EXTERNAL_PORT_RANGE'] + ip = vm.to_hash['VM']['HISTORY_RECORDS']['HISTORY'] + ip = [ip].flatten[-1]['HOSTNAME'] + port = Integer(nic['EXTERNAL_PORT_RANGE'].split(':')[0]) + 21 + else + ip = nic['IP'] + port = 22 + end + + system("ssh #{login}@#{ip} -p #{port} #{cmd}") + end + end + + port_desc = <<-EOT.unindent + Get port forwarding from a NIC, e.g: + + 1.2.3.4@4000 -> 1, means that to connect to VM port 1, you need to + connect to IP 1.2.3.4 in port 4000 + EOT + + command :'port-forward', + port_desc, + :vmid, + [:port, nil], + :options => NIC_ID do + helper.perform_action(args[0], options, 'Port Forward') do |vm| + rc = vm.info + + if OpenNebula.is_error?(rc) + STDERR.puts rc.message + exit(-1) + end + + if options[:nic_id] + nic = vm.retrieve_xmlelements( + "//TEMPLATE/NIC[NIC_ID=\"#{options[:nic_id]}\"]" + )[0] + else + nic = vm.retrieve_xmlelements('//TEMPLATE/NIC[SSH="YES"]')[0] + end + + nic = vm.retrieve_xmlelements('//TEMPLATE/NIC[1]')[0] if nic.nil? + + if nic.nil? + STDERR.puts 'No NIC found' + exit(-1) + end + + if nic['EXTERNAL_PORT_RANGE'].nil? + STDERR.puts 'No PORT_RANGE found' + exit(-1) + end + + ip = vm.to_hash['VM']['HISTORY_RECORDS']['HISTORY'][-1]['HOSTNAME'] + + e_range = nic['EXTERNAL_PORT_RANGE'].split(':') + e_start_p = Integer(e_range[0]) + e_end_p = Integer(e_range[1]) + + i_range = nic['INTERNAL_PORT_RANGE'].split('-') + i_start_p = Integer(i_range[0]) + i_end_p = Integer(i_range[1].split('/')[0]) + + if args[1].nil? + [*e_start_p..e_end_p].zip([*i_start_p..i_end_p]) do |p1, p2| + puts "#{ip}@#{p1} -> #{p2}" + end + else + puts "#{ip}@#{e_start_p + Integer(args[1]) - 1} -> #{args[1]}" + end + end + + end + # Deprecated commands deprecated_command(:shutdown, 'terminate') diff --git a/src/fireedge/src/client/assets/images/providers/GOOGLECLOUD.png b/src/fireedge/src/client/assets/images/providers/GOOGLE.png similarity index 100% rename from src/fireedge/src/client/assets/images/providers/GOOGLECLOUD.png rename to src/fireedge/src/client/assets/images/providers/GOOGLE.png diff --git a/src/fireedge/src/client/assets/images/providers/GOOGLECLOUD.webp b/src/fireedge/src/client/assets/images/providers/GOOGLE.webp similarity index 100% rename from src/fireedge/src/client/assets/images/providers/GOOGLECLOUD.webp rename to src/fireedge/src/client/assets/images/providers/GOOGLE.webp diff --git a/src/fireedge/src/client/assets/images/provisions/OPENNEBULA-GOOGLECLOUD.png b/src/fireedge/src/client/assets/images/provisions/OPENNEBULA-GOOGLE.png similarity index 100% rename from src/fireedge/src/client/assets/images/provisions/OPENNEBULA-GOOGLECLOUD.png rename to src/fireedge/src/client/assets/images/provisions/OPENNEBULA-GOOGLE.png diff --git a/src/fireedge/src/client/assets/images/provisions/OPENNEBULA-GOOGLECLOUD.webp b/src/fireedge/src/client/assets/images/provisions/OPENNEBULA-GOOGLE.webp similarity index 100% rename from src/fireedge/src/client/assets/images/provisions/OPENNEBULA-GOOGLECLOUD.webp rename to src/fireedge/src/client/assets/images/provisions/OPENNEBULA-GOOGLE.webp diff --git a/src/fireedge/src/client/components/Typography/TypographyWithPoint.js b/src/fireedge/src/client/components/Typography/TypographyWithPoint.js index d022f9155b..b28cc48b14 100644 --- a/src/fireedge/src/client/components/Typography/TypographyWithPoint.js +++ b/src/fireedge/src/client/components/Typography/TypographyWithPoint.js @@ -11,7 +11,7 @@ const useStateStyles = makeStyles(theme => ({ content: "''", display: 'inline-flex', marginRight: '0.5rem', - backgroundColor: ({ color }) => color, + background: ({ color }) => color, height: '0.7rem', width: '0.7rem', borderRadius: '50%' diff --git a/src/fireedge/src/client/components/Widgets/TotalProviders/index.js b/src/fireedge/src/client/components/Widgets/TotalProviders/index.js index 927f73e59e..86b9a0dffa 100644 --- a/src/fireedge/src/client/components/Widgets/TotalProviders/index.js +++ b/src/fireedge/src/client/components/Widgets/TotalProviders/index.js @@ -21,10 +21,10 @@ const TotalProviders = () => { const chartData = React.useMemo(() => { const groups = groupBy(providers, 'TEMPLATE.PLAIN.provider') - return PROVIDERS_TYPES?.map(({ name, color }) => ({ + return PROVIDERS_TYPES?.map(({ id, name, color }) => ({ color, title: name, - value: groups[name]?.length ?? 0 + value: groups[id]?.length ?? 0 })) }, [totalProviders]) diff --git a/src/fireedge/src/client/constants/index.js b/src/fireedge/src/client/constants/index.js index d38dbdb204..a02e8b14ce 100644 --- a/src/fireedge/src/client/constants/index.js +++ b/src/fireedge/src/client/constants/index.js @@ -47,10 +47,6 @@ export const LANGUAGES_URL = `${STATIC_FILES_URL}/languages` export const ONEADMIN_ID = '0' -export const REQUEST_ACTIONS = { - INSTANTIATE: 'instantiate' -} - export const FILTER_POOL = { PRIMARY_GROUP_RESOURCES: '-4', USER_RESOURCES: '-3', diff --git a/src/fireedge/src/client/constants/provision.js b/src/fireedge/src/client/constants/provision.js index c3dc48ee46..9f855cd1ed 100644 --- a/src/fireedge/src/client/constants/provision.js +++ b/src/fireedge/src/client/constants/provision.js @@ -36,15 +36,28 @@ export const PROVISIONS_STATES = [ export const PROVIDERS_TYPES = [ { - name: 'aws', + id: 'aws', + name: 'AWS', color: '#ef931f' }, { - name: 'packet', + id: 'packet', + name: 'Packet', color: '#364562' }, { - name: 'dummy', + id: 'dummy', + name: 'Dummy', color: '#436637' + }, + { + id: 'google', + name: 'Google Cloud', + color: 'linear-gradient(90deg, #fbbc05 0%, #ea4335 33%, #34a853 66%, #4285f4 100%)' + }, + { + id: 'digitalocean', + name: 'Digital Ocean', + color: '#2381f5' } ] diff --git a/src/fireedge/src/client/services/flow/application.js b/src/fireedge/src/client/services/flow/application.js index 16a2821781..cccf5760ea 100644 --- a/src/fireedge/src/client/services/flow/application.js +++ b/src/fireedge/src/client/services/flow/application.js @@ -6,7 +6,7 @@ import { } from 'server/routes/api/oneflow/string-routes' import { requestData } from 'client/utils' -import { REQUEST_ACTIONS } from 'client/constants' + const { GET, POST, PUT } = httpMethod export const getApplication = ({ id }) => @@ -77,7 +77,7 @@ export const instantiateTemplate = ({ id, data = {} }) => requestData(`/api/${SERVICE_TEMPLATE}/action/${id}`, { data: { action: { - perform: REQUEST_ACTIONS.INSTANTIATE, + perform: 'instantiate', params: { merge_template: data } } }, diff --git a/src/fireedge/src/client/types/provision.js b/src/fireedge/src/client/types/provision.js index fff933ce85..2326ea8762 100644 --- a/src/fireedge/src/client/types/provision.js +++ b/src/fireedge/src/client/types/provision.js @@ -30,7 +30,9 @@ export const UserInput = PropTypes.shape({ export const ProviderType = PropTypes.oneOf([ 'aws', 'packet', - 'dummy' + 'dummy', + 'google', + 'digitalocean' ]) export const ProvisionType = PropTypes.oneOf([ diff --git a/src/oneprovision/lib/provider/provider.rb b/src/oneprovision/lib/provider/provider.rb index 16093fbf3f..4947012a25 100644 --- a/src/oneprovision/lib/provider/provider.rb +++ b/src/oneprovision/lib/provider/provider.rb @@ -24,6 +24,9 @@ module OneProvision # These attributes can not be changed when updating the provider IMMUTABLE_ATTRS = %w[provider name] + # These providers get the credentials via some file + CREDENTIALS_FILE = { 'google' => 'credentials' } + # Allocates a new document # # @param template [Hash] Document information @@ -181,6 +184,25 @@ module OneProvision document['connection'] = template['connection'] document['registration_time'] = Time.now.to_i + if CREDENTIALS_FILE.keys.include?(template['provider']) + c_key = CREDENTIALS_FILE[template['provider']] + c_file = template['connection'][c_key] + + if base64?(c_file) + credentials = c_file + else + unless File.exist?(c_file) + return OpenNebula::Error.new( + "Credentials file doesn't exist" + ) + end + + credentials = Base64.strict_encode64(File.read(c_file)) + end + + document['connection'][c_key] = credentials + end + template.each do |key, value| next if skip.include?(key) @@ -190,6 +212,16 @@ module OneProvision document.to_json end + # Check if value is in Base64 form + # + # @param value [Object] Object to check + # + # @return [Boolean] True if it is in Base64, false otherwise + def base64?(value) + value.is_a?(String) && + Base64.strict_encode64(Base64.decode64(value)) == value + end + end end diff --git a/src/oneprovision/lib/provision/provision_config.rb b/src/oneprovision/lib/provision/provision_config.rb index d68f39beb9..578c4479db 100644 --- a/src/oneprovision/lib/provision/provision_config.rb +++ b/src/oneprovision/lib/provision/provision_config.rb @@ -298,7 +298,7 @@ module OneProvision check_rules - @config + @config.sort.to_h end ######################################################################## diff --git a/src/oneprovision/lib/terraform/providers.rb b/src/oneprovision/lib/terraform/providers.rb index c7461b64c3..2f05a46d90 100644 --- a/src/oneprovision/lib/terraform/providers.rb +++ b/src/oneprovision/lib/terraform/providers.rb @@ -15,7 +15,9 @@ #--------------------------------------------------------------------------- # require 'terraform/providers/aws' +require 'terraform/providers/digitalocean' require 'terraform/providers/dummy' +require 'terraform/providers/google' require 'terraform/providers/packet' # Module OneProvision diff --git a/src/oneprovision/lib/terraform/providers/aws.rb b/src/oneprovision/lib/terraform/providers/aws.rb index f889aa287b..e045e28ce0 100644 --- a/src/oneprovision/lib/terraform/providers/aws.rb +++ b/src/oneprovision/lib/terraform/providers/aws.rb @@ -31,6 +31,7 @@ module OneProvision } KEYS = %w[access_key secret_key region] + # Class constructor # # @param provider [Provider] @@ -39,12 +40,30 @@ module OneProvision def initialize(provider, state, conf) @dir = "#{PROVIDERS_LOCATION}/templates/aws" - # User data should be encoded in base64 - @base64 = true + # 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) + # Add clod unit information into user_data + # This only applies for a set of spported providers + user_data = "#cloud-config\n" + + user_data << "ssh_authorized_keys:\n" + + ssh_key.split("\n").each {|key| user_data << "- #{key}\n" } + + # Escape \n to avoid multilines in Terraform deploy file + user_data.gsub!("\n", '\\n') + + user_data + end + end end diff --git a/src/oneprovision/lib/terraform/providers/digitalocean.rb b/src/oneprovision/lib/terraform/providers/digitalocean.rb new file mode 100644 index 0000000000..2513257732 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/digitalocean.rb @@ -0,0 +1,69 @@ +# -------------------------------------------------------------------------- # +# 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/terraform' + +# Module OneProvision +module OneProvision + + # DigitalOcean Terraform Provider + class DigitalOcean < Terraform + + # OpenNebula - Terraform equivalence + TYPES = { + :cluster => 'digitalocean_vpc', + :datastore => 'digitalocean_volume', + :host => 'digitalocean_droplet', + :network => '' + } + + KEYS = %w[token 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) + @dir = "#{PROVIDERS_LOCATION}/templates/digitalocean" + + # 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 = "#cloud-config\n" + + user_data << "users:\n" + user_data << " - name: install\n" + user_data << " groups: sudo\n" + user_data << " shell: /bin/bash\n" + user_data << " sudo: ['ALL=(ALL) NOPASSWD:ALL']\n" + user_data << " ssh_authorized_keys:\n" + + ssh_key.split("\n").each {|key| user_data << " - #{key}\n" } + + user_data = user_data.gsub("\n", '\\n') + end + + end + +end diff --git a/src/oneprovision/lib/terraform/providers/google.rb b/src/oneprovision/lib/terraform/providers/google.rb new file mode 100644 index 0000000000..bc5fb63ddf --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/google.rb @@ -0,0 +1,67 @@ +# -------------------------------------------------------------------------- # +# 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/terraform' + +# Module OneProvision +module OneProvision + + # Google Terraform Provider + class Google < Terraform + + # OpenNebula - Terraform equivalence + TYPES = { + :cluster => 'google_compute_network', + :datastore => '', + :host => 'google_compute_instance', + :network => '' + } + + KEYS = %w[credentials project region zone] + + # 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/google" + + # Credentials are stored in a file + @file_credentials = true + + super + end + + # Get user data to add into the VM + # + # @param ssh_key [String] SSH keys to add + def user_data(ssh_key) + # Add clod unit information into user_data + # This only applies for a set of spported providers + user_data = "#cloud-config\n" + + ssh_key.split("\n").each {|key| user_data << "install:#{key}\n" } + + # Escape \n to avoid multilines in Terraform deploy file + user_data.gsub!("\n", '\\n') + + user_data + end + + end + +end diff --git a/src/oneprovision/lib/terraform/providers/packet.rb b/src/oneprovision/lib/terraform/providers/packet.rb index 551634afe7..dda751b3b5 100644 --- a/src/oneprovision/lib/terraform/providers/packet.rb +++ b/src/oneprovision/lib/terraform/providers/packet.rb @@ -39,12 +39,27 @@ module OneProvision def initialize(provider, state, conf) @dir = "#{PROVIDERS_LOCATION}/templates/packet" - # User data is in plain text - @base64 = false + # 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) + # Add clod unit information into user_data + # This only applies for a set of spported providers + user_data = "#cloud-config\n" + + user_data << "ssh_authorized_keys:\n" + + ssh_key.split("\n").each {|key| user_data << "- #{key}\n" } + + Base64.strict_encode64(user_data) + end + end end diff --git a/src/oneprovision/lib/terraform/providers/templates/digitalocean/cluster.erb b/src/oneprovision/lib/terraform/providers/templates/digitalocean/cluster.erb new file mode 100644 index 0000000000..95d4457cab --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/digitalocean/cluster.erb @@ -0,0 +1,5 @@ +resource "digitalocean_vpc" "device_<%= obj['ID'] %>" { + name = "vpc-digitalocean-<%= provision['REGION'] %>" + region = "<%= provision['REGION'] %>" + ip_range = "10.10.10.0/24" +} diff --git a/src/oneprovision/lib/terraform/providers/templates/digitalocean/datastore.erb b/src/oneprovision/lib/terraform/providers/templates/digitalocean/datastore.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/oneprovision/lib/terraform/providers/templates/digitalocean/host.erb b/src/oneprovision/lib/terraform/providers/templates/digitalocean/host.erb new file mode 100644 index 0000000000..51f00c41ec --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/digitalocean/host.erb @@ -0,0 +1,66 @@ +resource "digitalocean_droplet" "device_<%= obj['ID'] %>" { + image = "<%= provision['IMAGE'] %>" + name = "<%= provision['HOSTNAME'] %>" + region = "<%= provision['REGION'] %>" + size = "<%= provision['SIZE'] %>" + user_data = "<%= obj['user_data'] %>" + vpc_uuid = digitalocean_vpc.device_<%= c['ID'] %>.id +} + +resource "digitalocean_firewall" "device_<%= obj['ID'] %>" { + name = "vnc-device-<%= obj['ID'] %>" + + droplet_ids = [digitalocean_droplet.device_<%= obj['ID'] %>.id] + + inbound_rule { + protocol = "tcp" + port_range = "22" + source_addresses = ["0.0.0.0/0", "::/0"] + } + + # BGP traffic from VPC droplets. IP range MUST be consistent with cluster.erb + inbound_rule { + protocol = "tcp" + port_range = "179" + source_addresses = ["10.10.10.0/24"] + } + + # VXLAN traffic from VPC droplets. IP range MUST be consistent with cluster.erb + inbound_rule { + protocol = "udp" + port_range = "8472" + source_addresses = ["10.10.10.0/24"] + } + + # Client Ports for VMs. Port range MUST be consistent with VNET definition + inbound_rule { + protocol = "tcp" + port_range = "9000-65535" + source_addresses = ["0.0.0.0/0"] + } + + outbound_rule { + protocol = "tcp" + port_range = "1-65535" + destination_addresses = ["0.0.0.0/0", "::/0"] + } + + outbound_rule { + protocol = "udp" + port_range = "1-65535" + destination_addresses = ["0.0.0.0/0", "::/0"] + } + + outbound_rule { + protocol = "icmp" + destination_addresses = ["0.0.0.0/0", "::/0"] + } +} + +output "ip_<%= obj['ID'] %>" { + value = digitalocean_droplet.device_<%= obj['ID'] %>.ipv4_address +} + +output "device_id_<%= obj['ID'] %>" { + value = digitalocean_droplet.device_<%= obj['ID'] %>.id +} diff --git a/src/oneprovision/lib/terraform/providers/templates/digitalocean/network.erb b/src/oneprovision/lib/terraform/providers/templates/digitalocean/network.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/oneprovision/lib/terraform/providers/templates/digitalocean/provider.erb b/src/oneprovision/lib/terraform/providers/templates/digitalocean/provider.erb new file mode 100644 index 0000000000..6484816bf6 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/digitalocean/provider.erb @@ -0,0 +1,12 @@ +terraform { + required_providers { + digitalocean = { + source = "digitalocean/digitalocean" + } + } + required_version = ">= 0.13" +} + +provider "digitalocean" { + token = "<%= conn['TOKEN'] %>" +} diff --git a/src/oneprovision/lib/terraform/providers/templates/google/cluster.erb b/src/oneprovision/lib/terraform/providers/templates/google/cluster.erb new file mode 100644 index 0000000000..0fd1eb3152 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/google/cluster.erb @@ -0,0 +1,23 @@ +resource "google_compute_network" "device_<%= obj['ID'] %>" { + name = "<%= obj['NAME'] %>-vpc" +} + +resource "google_compute_firewall" "device_<%= obj['ID'] %>" { + name = "<%= obj['NAME'] %>-firewall" + network = google_compute_network.device_<%= obj['ID'] %>.name + + allow { + protocol = "icmp" + } + + # Client Ports for VMs. Port range MUST be consistent with VNET definition + allow { + protocol = "tcp" + ports = ["22", "179", "5900-6000", "9000-65535"] + } + + allow { + protocol = "udp" + ports = ["8472"] + } +} diff --git a/src/oneprovision/lib/terraform/providers/templates/google/datastore.erb b/src/oneprovision/lib/terraform/providers/templates/google/datastore.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/oneprovision/lib/terraform/providers/templates/google/host.erb b/src/oneprovision/lib/terraform/providers/templates/google/host.erb new file mode 100644 index 0000000000..580877bfb4 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/google/host.erb @@ -0,0 +1,31 @@ +resource "google_compute_instance" "device_<%= obj['ID'] %>" { + name = "<%= provision['HOSTNAME'] %>" + machine_type = "<%= provision['MACHINETYPE'] %>" + + boot_disk { + initialize_params { + image = "<%= provision['IMAGE'] %>" + } + } + + network_interface { + network = google_compute_network.device_<%= c['ID'] %>.name + + access_config { + // Ephemeral IP + } + } + + metadata = { + ssh-keys = "<%= obj['user_data'] %>" + } +} + +output "ip_<%= obj['ID'] %>" { + value = google_compute_instance.device_<%= obj['ID'] %>.network_interface[0].access_config[0].nat_ip +} + +output "device_id_<%= obj['ID'] %>" { + value = google_compute_instance.device_<%= obj['ID'] %>.id +} + diff --git a/src/oneprovision/lib/terraform/providers/templates/google/network.erb b/src/oneprovision/lib/terraform/providers/templates/google/network.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/oneprovision/lib/terraform/providers/templates/google/provider.erb b/src/oneprovision/lib/terraform/providers/templates/google/provider.erb new file mode 100644 index 0000000000..2c3c7e2593 --- /dev/null +++ b/src/oneprovision/lib/terraform/providers/templates/google/provider.erb @@ -0,0 +1,7 @@ +provider "google" { + credentials = "credentials.json" + project = "<%= conn['PROJECT'] %>" + region = "<%= conn['REGION'] %>" + zone = "<%= conn['ZONE'] %>" +} + diff --git a/src/oneprovision/lib/terraform/terraform.rb b/src/oneprovision/lib/terraform/terraform.rb index 2bb75e3f67..ac3c0f9415 100644 --- a/src/oneprovision/lib/terraform/terraform.rb +++ b/src/oneprovision/lib/terraform/terraform.rb @@ -46,7 +46,7 @@ module OneProvision class Terraform # Providers that are currently available - PROVIDERS = %w[aws packet dummy] + PROVIDERS = %w[aws digitalocean google packet dummy] # Class constructor # @@ -71,6 +71,10 @@ module OneProvision tf_class = Packet when 'aws' tf_class = AWS + when 'google' + tf_class = Google + when 'digitalocean' + tf_class = DigitalOcean when 'dummy' tf_class = Dummy else @@ -91,6 +95,10 @@ module OneProvision keys = Packet::KEYS when 'aws' keys = AWS::KEYS + when 'google' + keys = Google::KEYS + when 'digitalocean' + keys = DigitalOcean::KEYS when 'dummy' return true else @@ -146,6 +154,15 @@ module OneProvision def deploy(provision) tempdir = init(provision, false, false) + if @file_credentials + c_key = Provider::CREDENTIALS_FILE[@provider.type] + credentials = @provider.connection[c_key.upcase] + + File.open("#{tempdir}/credentials.json", 'w') do |file| + file.write(Base64.decode64(credentials)) + end + end + # Apply Driver.retry_loop("Driver action 'tf deploy' failed", provision) do _, e, s = Driver.run( @@ -182,7 +199,11 @@ module OneProvision info.gsub!(' ', '') info = info.split("\n") - info.map! {|ip| ip.split('=')[1] } + info.map! {|val| val.split('=')[1] } + + # rubocop:disable Style/StringLiterals + info.map! {|val| val.gsub("\"", '') } + # rubocop:enable Style/StringLiterals # rubocop:disable Style/StringLiterals info.map! {|val| val.gsub("\"", '') } @@ -225,6 +246,15 @@ module OneProvision def destroy(provision, target = nil) tempdir = init(provision) + if @file_credentials + c_key = Provider::CREDENTIALS_FILE[@provider.type] + credentials = @provider.connection[c_key.upcase] + + File.open("#{tempdir}/credentials.json", 'w') do |file| + file.write(Base64.decode64(credentials)) + end + end + # Destroy Driver.retry_loop("Driver action 'tf destroy' failed", provision) do _, e, s = Driver.run( @@ -300,22 +330,7 @@ module OneProvision return if !ssh_key || ssh_key.empty? - # Add clod unit information into user_data - # This only applies for a set of spported providers - user_data = "#cloud-config\n" - - user_data << "ssh_authorized_keys:\n" - - ssh_key.split("\n").each {|key| user_data << "- #{key}\n" } - - if @base64 - user_data = Base64.strict_encode64(user_data) - else - # Escape \n to avoid multilines in Terraform deploy file - user_data = user_data.gsub("\n", '\\n') - end - - obj['user_data'] = user_data + obj['user_data'] = user_data(ssh_key) end end @@ -425,8 +440,10 @@ module OneProvision if version < Gem::Version.new('0.13') cmd = '0.12upgrade' - else + elsif version < Gem::Version.new('0.15') cmd = '0.13upgrade' + else + return end # Upgrade diff --git a/src/template/OpenNebulaTemplate.cc b/src/template/OpenNebulaTemplate.cc index b011b4d252..4df1b56179 100644 --- a/src/template/OpenNebulaTemplate.cc +++ b/src/template/OpenNebulaTemplate.cc @@ -161,6 +161,8 @@ void OpenNebulaTemplate::set_multiple_conf_default() #vcenter #ovswitch_vxlan #bridge +#elastic +#nodeport #****** */ @@ -173,6 +175,8 @@ void OpenNebulaTemplate::set_multiple_conf_default() set_conf_vn("vcenter", "vcenter_port_groups"); set_conf_vn("ovswitch_vxlan", "openvswitch"); set_conf_vn("bridge", "linux"); + set_conf_vn("elastic", "linux"); + set_conf_vn("nodeport", "linux"); register_multiple_conf_default("VN_MAD_CONF"); } diff --git a/src/vnm/AddressRange.cc b/src/vnm/AddressRange.cc index d6454dd137..c6e16045b2 100644 --- a/src/vnm/AddressRange.cc +++ b/src/vnm/AddressRange.cc @@ -84,34 +84,34 @@ AddressRange::AddressType AddressRange::str_to_type(string& str_type) int AddressRange::init_ipv4(string& error_msg) { - if (!is_ipv4()) - { - attr->remove("IP"); - return 0; - } + if (!is_ipv4()) + { + attr->remove("IP"); + return 0; + } - string value = attr->vector_value("IP"); + string value = attr->vector_value("IP"); - if (value.empty() || ip_to_i(value, ip) == -1) - { - error_msg = "Wrong or empty IP attribute"; - return -1; - } + if (value.empty() || ip_to_i(value, ip) == -1) + { + error_msg = "Wrong or empty IP attribute"; + return -1; + } - return 0; + return 0; } /* -------------------------------------------------------------------------- */ int AddressRange::init_ipv6(string& error_msg) { - if (!is_ipv6()) - { - attr->remove("GLOBAL_PREFIX"); - attr->remove("ULA_PREFIX"); + if (!is_ipv6()) + { + attr->remove("GLOBAL_PREFIX"); + attr->remove("ULA_PREFIX"); - return 0; - } + return 0; + } string value = attr->vector_value("GLOBAL_PREFIX"); @@ -129,26 +129,26 @@ int AddressRange::init_ipv6(string& error_msg) return -1; } - return 0; + return 0; } /* -------------------------------------------------------------------------- */ int AddressRange::init_ipv6_static(string& error_msg) { - if (!is_ipv6_static()) - { - attr->remove("IP6"); - return 0; - } + if (!is_ipv6_static()) + { + attr->remove("IP6"); + return 0; + } string value = attr->vector_value("IP6"); - if (value.empty() || ip6_to_i(value, ip6) == -1) - { - error_msg = "Wrong or empty IP6 attribute"; - return -1; - } + if (value.empty() || ip6_to_i(value, ip6) == -1) + { + error_msg = "Wrong or empty IP6 attribute"; + return -1; + } int pl; @@ -158,7 +158,7 @@ int AddressRange::init_ipv6_static(string& error_msg) return -1; } - return 0; + return 0; } /* -------------------------------------------------------------------------- */ @@ -171,14 +171,14 @@ int AddressRange::init_mac(string& error_msg) { mac[1] = VirtualNetworkPool::mac_prefix(); - if ( is_ipv4() ) - { - mac[0] = ip; - } - else - { - mac[0] = one_util::random() & 0xFFFFFFFF; - } + if ( is_ipv4() ) + { + mac[0] = ip; + } + else + { + mac[0] = one_util::random() & 0xFFFFFFFF; + } set_mac(0, attr); } @@ -191,7 +191,7 @@ int AddressRange::init_mac(string& error_msg) }; } - return 0; + return 0; } /* -------------------------------------------------------------------------- */ @@ -255,6 +255,18 @@ int AddressRange::from_attr(VectorAttribute *vattr, string& error_msg) one_util::split_unique(value, ',', security_groups); } + /* ---------------------- Port Range Allocation ------------------------- */ + + if ( vattr->vector_value("PORT_START", port_start) == -1 ) + { + port_start = 0; + } + + if ( vattr->vector_value("PORT_SIZE", port_size) == -1 ) + { + port_size = 0; + } + /* ------------------------ AR Internal Data ---------------------------- */ vattr->replace("AR_ID", id); @@ -358,6 +370,7 @@ int AddressRange::update_attributes( if (keep_restricted && restricted_set) { VectorAttribute va_aux(*attr); + remove_all_except_restricted(&va_aux); vup->merge(&va_aux, true); @@ -434,6 +447,18 @@ int AddressRange::update_attributes( one_util::split_unique(value, ',', security_groups); } + if ( vup->vector_value("PORT_START", port_start) == -1 ) + { + vup->remove("PORT_START"); + port_start = 0; + } + + if ( vup->vector_value("PORT_SIZE", port_size) == -1 ) + { + vup->remove("PORT_SIZE"); + port_size = 0; + } + /* Replace with the new attributes */ attr->replace(vup->value()); @@ -485,6 +510,16 @@ int AddressRange::from_vattr_db(VectorAttribute *vattr) one_util::split_unique(value, ',', security_groups); } + if ( vattr->vector_value("PORT_START", port_start) == -1 ) + { + port_start = 0; + } + + if ( vattr->vector_value("PORT_SIZE", port_size) == -1 ) + { + port_size = 0; + } + if (type == NONE) { rc = -1; @@ -772,6 +807,8 @@ void AddressRange::to_xml(ostringstream &oss, const vector& vms, set_mac(it->first, &lease); + set_port_ranges(it->first, &lease); + if (is_ipv4()) { set_ip(it->first, &lease); @@ -1152,6 +1189,30 @@ bool AddressRange::is_valid_ip6(unsigned int& index, const string& ip_s, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void AddressRange::set_port_ranges(unsigned int addr_index, + VectorAttribute * nic) const +{ + if ( port_size == 0 || port_start == 0 ) + { + return; + } + + unsigned int p_ini = port_start + (addr_index * port_size) + 1; + unsigned int p_end = p_ini + port_size - 1; + + ostringstream erange; + ostringstream irange; + + erange << p_ini << ":" << p_end; + irange << "1-" << port_size << "/" << p_ini; + + nic->replace("EXTERNAL_PORT_RANGE", erange.str()); + nic->replace("INTERNAL_PORT_RANGE", irange.str()); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void AddressRange::set_mac(unsigned int addr_index, VectorAttribute * nic) const { unsigned int new_mac[2]; @@ -1210,20 +1271,20 @@ void AddressRange::set_ip6(unsigned int addr_index, VectorAttribute * nic) const /* -------------------------------------------------------------------------- */ void AddressRange::set_ip6_static(unsigned int addr_index, - VectorAttribute * nic) const + VectorAttribute * nic) const { - unsigned int ip_low[4]; + unsigned int ip_low[4]; string ip6_s; ip_low[3] = ip6[3]; ip_low[2] = ip6[2]; ip_low[1] = ip6[1]; - ip_low[0] = ip6[0] + addr_index; + ip_low[0] = ip6[0] + addr_index; - if ( ip6_to_s(ip_low, ip6_s) == 0 ) - { - nic->replace("IP6", ip6_s); - } + if ( ip6_to_s(ip_low, ip6_s) == 0 ) + { + nic->replace("IP6", ip6_s); + } } /* -------------------------------------------------------------------------- */ @@ -1368,6 +1429,8 @@ void AddressRange::allocate_by_index(unsigned int index, { set_mac(index, nic); + set_port_ranges(index, nic); + if (is_ipv4()) { set_ip(index, nic); @@ -1378,7 +1441,7 @@ void AddressRange::allocate_by_index(unsigned int index, set_ip6(index, nic); } - if (is_ipv6_static()) + if (is_ipv6_static()) { set_ip6_static(index, nic); } @@ -1827,6 +1890,8 @@ int AddressRange::reserve_addr(int vid, unsigned int rsize, AddressRange *rar) set_mac(first_index, new_ar); + set_port_ranges(first_index, new_ar); + if ( is_ipv4() ) { set_ip(first_index, new_ar); @@ -1884,6 +1949,8 @@ int AddressRange::reserve_addr_by_index(int vid, unsigned int rsize, set_mac(sindex, new_ar); + set_port_ranges(sindex, new_ar); + if ( is_ipv4() ) { set_ip(sindex, new_ar); diff --git a/src/vnm_mad/remotes/nodeport/clean b/src/vnm_mad/remotes/nodeport/clean new file mode 100755 index 0000000000..4e6fd37932 --- /dev/null +++ b/src/vnm_mad/remotes/nodeport/clean @@ -0,0 +1,40 @@ +#!/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. # +#--------------------------------------------------------------------------- # + +$LOAD_PATH << File.dirname(__FILE__) +$LOAD_PATH << File.join(File.dirname(__FILE__), '..') + +require 'nodeport' + +template64 = STDIN.read +deploy_id = nil +xpath_filter = NodePortDriver::XPATH_FILTER + +begin + drv = NodePortDriver.new(template64) + drv.deactivate + + filter_driver = VNMMAD::VNMDriver.filter_driver(template64, + xpath_filter, + deploy_id) + filter_driver.deactivate +rescue Exception => e + OpenNebula.log_error(e.message) + OpenNebula.log_error(e.backtrace) + exit 1 +end diff --git a/src/vnm_mad/remotes/nodeport/clean.d/.gitignore b/src/vnm_mad/remotes/nodeport/clean.d/.gitignore new file mode 100644 index 0000000000..cfb6127211 --- /dev/null +++ b/src/vnm_mad/remotes/nodeport/clean.d/.gitignore @@ -0,0 +1,3 @@ +# Do not track files in this directory except for .gitignore file +* +!.gitignore diff --git a/src/vnm_mad/remotes/nodeport/nodeport.rb b/src/vnm_mad/remotes/nodeport/nodeport.rb new file mode 100644 index 0000000000..b4509c85b2 --- /dev/null +++ b/src/vnm_mad/remotes/nodeport/nodeport.rb @@ -0,0 +1,127 @@ +# rubocop:disable Naming/FileName +# -------------------------------------------------------------------------- # +# 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 'vnmmad' + +# Node Port Forwarding Driver +class NodePortDriver < VNMMAD::VNMDriver + + # Driver name + DRIVER = 'nodeport' + + # Filter to look for NICs managed by this diver + XPATH_FILTER = "TEMPLATE/NIC[VN_MAD='nodeport']" + + # Class constructor + def initialize(vm) + @locking = true + + super(Base64.decode64(vm), XPATH_FILTER, nil) + end + + # Adds the following elements: + # + # - Route to the bridge + # - ARP proxy + # - PREROUTING rule + # - POSTROUTING rule + def activate + cmds = VNMMAD::VNMNetwork::Commands.new + + attach_nic_id = @vm['TEMPLATE/NIC[ATTACH="YES"]/NIC_ID'] + attach_nic_id ||= @vm['TEMPLATE/NIC_ALIAS[ATTACH="YES"]/NIC_ID'] + + rc = process do |nic| + next if attach_nic_id && attach_nic_id != nic[:nic_id] + + unless check_nic(nic) + OpenNebula.log_error('NIC information is wrong') + break false + end + + cmds.add :ip, "route add #{nic[:ip]}/32 dev #{nic[:bridge]}" + cmds.add :ip, + "neighbour add proxy #{nic[:gateway]} " \ + "dev #{nic[:bridge]}" + cmds.add :iptables, '-t nat -I PREROUTING -p tcp --dport ' \ + "#{nic[:external_port_range]} -j DNAT --to " \ + "#{nic[:ip]}:#{nic[:internal_port_range]}" + cmds.add :iptables, '-t nat -A POSTROUTING -j MASQUERADE ' \ + "-s #{nic[:ip]}" + end + + if rc != false + cmds.run! + + 0 + else + -1 + end + end + + # Deletes the following elements: + # + # - Route to the bridge + # - ARP proxy + # - PREROUTING rule + # - POSTROUTING rule + def deactivate + cmds = VNMMAD::VNMNetwork::Commands.new + + attach_nic_id = @vm['TEMPLATE/NIC[ATTACH="YES"]/NIC_ID'] + attach_nic_id ||= @vm['TEMPLATE/NIC_ALIAS[ATTACH="YES"]/NIC_ID'] + + rc = process do |nic| + next if attach_nic_id && attach_nic_id != nic[:nic_id] + + unless check_nic(nic) + OpenNebula.log_error('NIC information is wrong') + break false + end + + 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 :iptables, '-t nat -D PREROUTING -p tcp --dport ' \ + "#{nic[:external_port_range]} -j DNAT --to " \ + "#{nic[:ip]}:#{nic[:internal_port_range]}" + cmds.add :iptables, '-t nat -D POSTROUTING -j MASQUERADE ' \ + "-s #{nic[:ip]}" + end + + if rc != false + cmds.run! + + 0 + else + -1 + end + end + + private + + # Check if nic has all the port range information + # + # @param nic[Hash] NIC information + def check_nic(nic) + !nic[:external_port_range].nil? && !nic[:internal_port_range].nil? + end + +end +# rubocop:enable Naming/FileName diff --git a/src/vnm_mad/remotes/nodeport/post b/src/vnm_mad/remotes/nodeport/post new file mode 100755 index 0000000000..160c351191 --- /dev/null +++ b/src/vnm_mad/remotes/nodeport/post @@ -0,0 +1,38 @@ +#!/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. # +#--------------------------------------------------------------------------- # + +$LOAD_PATH << File.dirname(__FILE__) +$LOAD_PATH << File.join(File.dirname(__FILE__), '..') + +require 'nodeport' + +template64 = STDIN.read +deploy_id = ARGV[0] +xpath_filter = NodePortDriver::XPATH_FILTER + +begin + drv = NodePortDriver.new(template64) + filter_driver = VNMMAD::VNMDriver.filter_driver(template64, + xpath_filter, + deploy_id) + filter_driver.activate(true) if drv.activate == 0 +rescue Exception => e + OpenNebula.log_error(e.message) + OpenNebula.log_error(e.backtrace) + exit 1 +end diff --git a/src/vnm_mad/remotes/nodeport/post.d/.gitignore b/src/vnm_mad/remotes/nodeport/post.d/.gitignore new file mode 100644 index 0000000000..cfb6127211 --- /dev/null +++ b/src/vnm_mad/remotes/nodeport/post.d/.gitignore @@ -0,0 +1,3 @@ +# Do not track files in this directory except for .gitignore file +* +!.gitignore diff --git a/src/vnm_mad/remotes/nodeport/pre b/src/vnm_mad/remotes/nodeport/pre new file mode 100755 index 0000000000..341075e694 --- /dev/null +++ b/src/vnm_mad/remotes/nodeport/pre @@ -0,0 +1,29 @@ +#!/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. # +#--------------------------------------------------------------------------- # + +$LOAD_PATH << File.dirname(__FILE__) +$LOAD_PATH << File.join(File.dirname(__FILE__), '..') + +require 'vnmmad' + +template64 = STDIN.read +deploy_id = ARGV[0] +xpath_filter = "TEMPLATE/NIC[VN_MAD='nodeport']" + +drv = VNMMAD::NoVLANDriver.from_base64(template64, xpath_filter, deploy_id) +exit drv.run_hooks(ARGV, template64) if drv.activate == 0 diff --git a/src/vnm_mad/remotes/nodeport/pre.d/.gitignore b/src/vnm_mad/remotes/nodeport/pre.d/.gitignore new file mode 100644 index 0000000000..cfb6127211 --- /dev/null +++ b/src/vnm_mad/remotes/nodeport/pre.d/.gitignore @@ -0,0 +1,3 @@ +# Do not track files in this directory except for .gitignore file +* +!.gitignore diff --git a/src/vnm_mad/remotes/nodeport/update_sg b/src/vnm_mad/remotes/nodeport/update_sg new file mode 100755 index 0000000000..bd411872ed --- /dev/null +++ b/src/vnm_mad/remotes/nodeport/update_sg @@ -0,0 +1,38 @@ +#!/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. # +#--------------------------------------------------------------------------- # + +$: << File.dirname(__FILE__) +$: << File.join(File.dirname(__FILE__), "..") + +require 'vnmmad' + +template64 = STDIN.read +deploy_id = ARGV[0] +xpath_filter = "TEMPLATE/NIC[VN_MAD='nodeport']" + +begin + filter_driver = VNMMAD::VNMDriver.filter_driver(template64, + xpath_filter, + deploy_id, + false) + filter_driver.activate(true) +rescue Exception => e + OpenNebula.log_error(e.message) + OpenNebula.log_error(e.backtrace) + exit 1 +end