1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-22 13:33:52 +03:00

F #5270, #5272: Support for Google Compute and DigitalOcean

co-authored-by: Alejandro Huertas <ahuertas@opennebula.io>
co-authored-by: Juan Antonio <jescobar@opennebula.io>
co-authored-by: Sergio Betanzos <sbetanzos@opennebula.io>
This commit is contained in:
Ruben S. Montero 2021-04-30 11:49:51 +02:00
parent f1749061a0
commit f1a48bdc0d
No known key found for this signature in database
GPG Key ID: A0CEA6FA880A1D87
73 changed files with 1929 additions and 238 deletions

View File

@ -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
*/

View File

@ -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 \

View File

@ -103,6 +103,8 @@
<xs:element name="IP6_GLOBAL_END" type="xs:string" minOccurs="0"/>
<xs:element name="IP6" type="xs:string" minOccurs="0"/>
<xs:element name="IP6_END" type="xs:string" minOccurs="0"/>
<xs:element name="PORT_START" type="xs:string" minOccurs="0"/>
<xs:element name="PORT_SIZE" type="xs:string" minOccurs="0"/>
<xs:element name="USED_LEASES" type="xs:string"/>
<xs:element name="LEASES" minOccurs="0" maxOccurs="1">
<xs:complexType>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,2 @@
hostname {{ ansible_nodename }}
ip route {{ frr_net.stdout }}/{{ frr_net_mask }} {{ ansible_default_ipv4.gateway }}

View File

@ -0,0 +1,2 @@
hostname {{ ansible_nodename }}
ip nht resolve-via-default

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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"

View File

@ -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
#-------------------------------------------------------------------------------

View File

@ -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'

View File

@ -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'
...

View File

@ -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}"

View File

@ -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'

View File

@ -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"

View File

@ -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'

View File

@ -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'
...

View File

@ -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}"

View File

@ -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

View File

@ -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)

View File

@ -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')

View File

@ -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

View File

@ -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')

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -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%'

View File

@ -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])

View File

@ -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',

View File

@ -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'
}
]

View File

@ -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 }
}
},

View File

@ -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([

View File

@ -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

View File

@ -298,7 +298,7 @@ module OneProvision
check_rules
@config
@config.sort.to_h
end
########################################################################

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"
}

View File

@ -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
}

View File

@ -0,0 +1,12 @@
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
}
}
required_version = ">= 0.13"
}
provider "digitalocean" {
token = "<%= conn['TOKEN'] %>"
}

View File

@ -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"]
}
}

View File

@ -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
}

View File

@ -0,0 +1,7 @@
provider "google" {
credentials = "credentials.json"
project = "<%= conn['PROJECT'] %>"
region = "<%= conn['REGION'] %>"
zone = "<%= conn['ZONE'] %>"
}

View File

@ -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

View File

@ -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");
}

View File

@ -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<uint32_t>() & 0xFFFFFFFF;
}
if ( is_ipv4() )
{
mac[0] = ip;
}
else
{
mac[0] = one_util::random<uint32_t>() & 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<int>& 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);

View File

@ -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

View File

@ -0,0 +1,3 @@
# Do not track files in this directory except for .gitignore file
*
!.gitignore

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,3 @@
# Do not track files in this directory except for .gitignore file
*
!.gitignore

View File

@ -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

View File

@ -0,0 +1,3 @@
# Do not track files in this directory except for .gitignore file
*
!.gitignore

View File

@ -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