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