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:
Ivan Kliuk
2015-07-20 14:28:19 +03:00
committed by Ivan Kliuk
parent f85a6eecbb
commit 9fecd471bf
4 changed files with 234 additions and 0 deletions

View File

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

View File

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

View File

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

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