Add network templates functionality
Examples:
* To upload network template from filesystem path for specified environment:
fuel --env 1 network-template --upload --dir path/to/directory
* To download network template to current directory for specified environment:
fuel --env 1 network-template --download
Change-Id: Ic9af092596dca2b6c265b6280cfa85197d561a10
Implements: blueprint templates-for-networking
This commit is contained in:
@@ -26,6 +26,7 @@ from fuelclient.cli.actions.health import HealthCheckAction
|
||||
from fuelclient.cli.actions.interrupt import ResetAction
|
||||
from fuelclient.cli.actions.interrupt import StopAction
|
||||
from fuelclient.cli.actions.network import NetworkAction
|
||||
from fuelclient.cli.actions.network import NetworkTemplateAction
|
||||
from fuelclient.cli.actions.node import NodeAction
|
||||
from fuelclient.cli.actions.nodegroup import NodeGroupAction
|
||||
from fuelclient.cli.actions.notifications import NotificationsAction
|
||||
@@ -53,6 +54,7 @@ actions_tuple = (
|
||||
SettingsAction,
|
||||
VmwareSettingsAction,
|
||||
NetworkAction,
|
||||
NetworkTemplateAction,
|
||||
TaskAction,
|
||||
SnapshotAction,
|
||||
HealthCheckAction,
|
||||
|
||||
@@ -87,3 +87,54 @@ class NetworkAction(Action):
|
||||
" downloaded to {1}"
|
||||
.format(env.id, network_file_path)
|
||||
)
|
||||
|
||||
|
||||
class NetworkTemplateAction(Action):
|
||||
"""Manipulate network templates for a specific environment
|
||||
"""
|
||||
action_name = 'network-template'
|
||||
|
||||
def __init__(self):
|
||||
super(NetworkTemplateAction, self).__init__()
|
||||
self.args = (
|
||||
Args.get_env_arg(required=True),
|
||||
Args.get_dir_arg("Directory with network templates."),
|
||||
group(
|
||||
Args.get_download_arg(
|
||||
"Download current network template configuration."),
|
||||
Args.get_upload_arg(
|
||||
"Upload changed network template configuration."),
|
||||
required=True))
|
||||
|
||||
self.flag_func_map = (
|
||||
("upload", self.upload),
|
||||
("download", self.download))
|
||||
|
||||
def upload(self, params):
|
||||
"""Uploads network template from filesystem path
|
||||
for specified environment:
|
||||
fuel --env 1 network-template --upload --dir path/to/directory
|
||||
"""
|
||||
env = Environment(params.env)
|
||||
network_template_data = env.read_network_template_data(
|
||||
directory=params.dir,
|
||||
serializer=self.serializer)
|
||||
env.set_network_template_data(network_template_data)
|
||||
full_path = self.serializer.prepare_path(
|
||||
env.get_network_template_data_path(directory=params.dir))
|
||||
print("Network template {0} has been uploaded.".format(full_path))
|
||||
|
||||
def download(self, params):
|
||||
"""Downloads network template in current
|
||||
directory for specified environment:
|
||||
fuel --env 1 network-template --download
|
||||
"""
|
||||
env = Environment(params.env)
|
||||
template_data = env.get_network_template_data()
|
||||
network_template_file_path = env.write_network_template_data(
|
||||
template_data,
|
||||
directory=params.dir,
|
||||
serializer=self.serializer)
|
||||
|
||||
print("Network template configuration for environment with id={0}"
|
||||
" downloaded to {1}".format(env.id, network_template_file_path))
|
||||
|
||||
@@ -31,6 +31,7 @@ class Environment(BaseObject):
|
||||
deployment_tasks_path = 'clusters/{0}/deployment_tasks'
|
||||
deployment_tasks_graph_path = 'clusters/{0}/deploy_tasks/graph.gv'
|
||||
attributes_path = 'clusters/{0}/attributes'
|
||||
network_template_path = 'clusters/{0}/network_configuration/template'
|
||||
|
||||
@classmethod
|
||||
def create(cls, name, release_id, net, net_segment_type,
|
||||
@@ -135,6 +136,12 @@ class Environment(BaseObject):
|
||||
"vmware_settings_{0}".format(self.id)
|
||||
)
|
||||
|
||||
def get_network_template_data_path(self, directory=os.curdir):
|
||||
return os.path.join(
|
||||
os.path.abspath(directory),
|
||||
"network_template_{0}".format(self.id)
|
||||
)
|
||||
|
||||
def write_network_data(self, network_data, directory=os.curdir,
|
||||
serializer=None):
|
||||
return (serializer or self.serializer).write_to_path(
|
||||
@@ -156,6 +163,13 @@ class Environment(BaseObject):
|
||||
settings_data
|
||||
)
|
||||
|
||||
def write_network_template_data(self, template_data, directory=os.curdir,
|
||||
serializer=None):
|
||||
return (serializer or self.serializer).write_to_path(
|
||||
self.get_network_template_data_path(directory),
|
||||
template_data
|
||||
)
|
||||
|
||||
def read_network_data(self, directory=os.curdir,
|
||||
serializer=None):
|
||||
network_file_path = self.get_network_data_path(directory)
|
||||
@@ -171,6 +185,13 @@ class Environment(BaseObject):
|
||||
return (serializer or self.serializer).read_from_file(
|
||||
self.get_vmware_settings_data_path(directory))
|
||||
|
||||
def read_network_template_data(self, directory=os.curdir,
|
||||
serializer=None):
|
||||
network_template_file_path = self.get_network_template_data_path(
|
||||
directory)
|
||||
return (serializer or self.serializer).read_from_file(
|
||||
network_template_file_path)
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
return self.get_fresh_data()['status']
|
||||
@@ -197,6 +218,10 @@ class Environment(BaseObject):
|
||||
**self.data
|
||||
)
|
||||
|
||||
@property
|
||||
def network_template_url(self):
|
||||
return self.network_template_path.format(self.id)
|
||||
|
||||
@property
|
||||
def network_verification_url(self):
|
||||
return self.network_url + "/verify"
|
||||
@@ -216,6 +241,9 @@ class Environment(BaseObject):
|
||||
def get_default_vmware_settings_data(self):
|
||||
return self.connection.get_request(self.default_vmware_settings_url)
|
||||
|
||||
def get_network_template_data(self):
|
||||
return self.connection.get_request(self.network_template_url)
|
||||
|
||||
def set_network_data(self, data):
|
||||
return self.connection.put_request(
|
||||
self.network_url, data)
|
||||
@@ -232,6 +260,10 @@ class Environment(BaseObject):
|
||||
return self.connection.put_request(
|
||||
self.network_verification_url, self.get_network_data())
|
||||
|
||||
def set_network_template_data(self, data):
|
||||
return self.connection.put_request(
|
||||
self.network_template_url, data)
|
||||
|
||||
def _get_fact_dir_name(self, fact_type, directory=os.path.curdir):
|
||||
return os.path.join(
|
||||
os.path.abspath(directory),
|
||||
|
||||
149
fuelclient/tests/common/unit/test_network_template.py
Normal file
149
fuelclient/tests/common/unit/test_network_template.py
Normal file
@@ -0,0 +1,149 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2015 Mirantis, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
import mock
|
||||
import requests_mock
|
||||
import yaml
|
||||
|
||||
from fuelclient.tests import base
|
||||
|
||||
YAML_TEMPLATE = """adv_net_template:
|
||||
default:
|
||||
network_assignments:
|
||||
fuelweb_admin:
|
||||
ep: br-fw-admin
|
||||
management:
|
||||
ep: br-mgmt
|
||||
private:
|
||||
ep: br-prv
|
||||
public:
|
||||
ep: br-ex
|
||||
storage:
|
||||
ep: br-storage
|
||||
nic_mapping:
|
||||
default:
|
||||
if1: eth0
|
||||
templates_for_node_role:
|
||||
ceph-osd:
|
||||
- common
|
||||
- storage
|
||||
compute:
|
||||
- common
|
||||
- private
|
||||
- storage
|
||||
controller:
|
||||
- public
|
||||
- private
|
||||
- storage
|
||||
- common
|
||||
"""
|
||||
|
||||
JSON_TEMPLATE = """{
|
||||
"adv_net_template": {
|
||||
"default": {
|
||||
"nic_mapping": {
|
||||
"default": {
|
||||
"if1": "eth0"
|
||||
}
|
||||
},
|
||||
"templates_for_node_role": {
|
||||
"controller": [
|
||||
"public",
|
||||
"private",
|
||||
"storage",
|
||||
"common"
|
||||
],
|
||||
"compute": [
|
||||
"common",
|
||||
"private",
|
||||
"storage"
|
||||
],
|
||||
"ceph-osd": [
|
||||
"common",
|
||||
"storage"
|
||||
]
|
||||
},
|
||||
"network_assignments": {
|
||||
"storage": {
|
||||
"ep": "br-storage"
|
||||
},
|
||||
"private": {
|
||||
"ep": "br-prv"
|
||||
},
|
||||
"public": {
|
||||
"ep": "br-ex"
|
||||
},
|
||||
"management": {
|
||||
"ep": "br-mgmt"
|
||||
},
|
||||
"fuelweb_admin": {
|
||||
"ep": "br-fw-admin"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class TestNetworkTemplate(base.UnitTestCase):
|
||||
def setUp(self):
|
||||
super(TestNetworkTemplate, self).setUp()
|
||||
|
||||
self.env_id = 42
|
||||
self.req_path = ('/api/v1/clusters/{0}/network_configuration/'
|
||||
'template'.format(self.env_id))
|
||||
|
||||
self.mocker = requests_mock.Mocker()
|
||||
self.mocker.start()
|
||||
|
||||
def tearDown(self):
|
||||
self.mocker.stop()
|
||||
|
||||
def test_upload_action(self):
|
||||
self.mocker.put(self.req_path)
|
||||
test_command = [
|
||||
'fuel', 'network-template', '--env', str(self.env_id), '--upload']
|
||||
|
||||
m_open = mock.mock_open(read_data=YAML_TEMPLATE)
|
||||
with mock.patch('__builtin__.open', m_open, create=True):
|
||||
self.execute(test_command)
|
||||
|
||||
self.assertEqual(self.mocker.last_request.method, 'PUT')
|
||||
self.assertEqual(self.mocker.last_request.path, self.req_path)
|
||||
self.assertEqual(self.mocker.last_request.json(),
|
||||
json.loads(JSON_TEMPLATE))
|
||||
m_open().read.assert_called_once_with()
|
||||
|
||||
def test_download_action(self):
|
||||
self.mocker.get(self.req_path, text=JSON_TEMPLATE)
|
||||
|
||||
test_command = [
|
||||
'fuel', 'network-template', '--env', str(self.env_id),
|
||||
'--download']
|
||||
|
||||
m_open = mock.mock_open()
|
||||
with mock.patch('fuelclient.cli.serializers.open', m_open,
|
||||
create=True):
|
||||
self.execute(test_command)
|
||||
|
||||
self.assertEqual(self.mocker.last_request.method, 'GET')
|
||||
self.assertEqual(self.mocker.last_request.path, self.req_path)
|
||||
|
||||
written_yaml = yaml.safe_load(m_open().write.mock_calls[0][1][0])
|
||||
expected_yaml = yaml.safe_load(YAML_TEMPLATE)
|
||||
self.assertEqual(written_yaml, expected_yaml)
|
||||
Reference in New Issue
Block a user