From 40e1ede7b9414fdd262141cb30de2bc910764d6a Mon Sep 17 00:00:00 2001 From: Dmitry Ukov Date: Tue, 27 Sep 2016 10:44:55 +0300 Subject: [PATCH] Introduced master node management strategy * Only one Git repository is allowed to manage Fuel master node * Repo SQL model extended with flag which determines wither a particular repo manages Fuel mater node * Master config mapping moved to a separate section Change-Id: I7137393a5a42bb57cc14ceb738b18e37251e9368 --- fuel_external_git/extension.py | 21 +++++---- fuel_external_git/fuelclient.py | 41 ++++++++++++++++-- fuel_external_git/handlers.py | 23 +++++++++- .../adb78f70605d_manage_fuel_node_flag.py | 43 +++++++++++++++++++ fuel_external_git/models.py | 2 + fuel_external_git/objects.py | 3 +- fuel_external_git/settings.yaml | 1 + 7 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 fuel_external_git/migrations/versions/adb78f70605d_manage_fuel_node_flag.py diff --git a/fuel_external_git/extension.py b/fuel_external_git/extension.py index 77ab772..d9d15b1 100644 --- a/fuel_external_git/extension.py +++ b/fuel_external_git/extension.py @@ -52,7 +52,6 @@ class OpenStackConfigPipeline(BasePipeline): GitRepo.checkout(repo) repo_path = os.path.join(const.REPOS_DIR, repo.repo_name) resource_mapping = ExternalGit.ext_settings['resource_mapping'] - resource_mapping.pop('master_config', {}) exts_list = utils.get_file_exts_list(resource_mapping) global_config = utils.get_config_hash(repo_path, @@ -108,17 +107,17 @@ class OpenStackConfigPipeline(BasePipeline): repo = GitRepo.get_by_cluster_id(cluster.id) if not repo: return data - GitRepo.checkout(repo) - repo_path = os.path.join(const.REPOS_DIR, repo.repo_name) - resource_mapping = ExternalGit.ext_settings['resource_mapping'] - master_config_mapping = resource_mapping.pop('master_config', {}) - master_config = utils.get_config_hash( - repo_path, - {'master_config': master_config_mapping}, - exts=['yaml'] - ) + if repo.manage_master: + GitRepo.checkout(repo) + repo_path = os.path.join(const.REPOS_DIR, repo.repo_name) + resource_mapping = ExternalGit.ext_settings['master_mapping'] + master_config = utils.get_config_hash( + repo_path, + {'master_config': resource_mapping.get('master_config', {})}, + exts=['yaml'] + ) - data['master_config'] = master_config + data['master_config'] = master_config return data diff --git a/fuel_external_git/fuelclient.py b/fuel_external_git/fuelclient.py index d77f532..a64f684 100644 --- a/fuel_external_git/fuelclient.py +++ b/fuel_external_git/fuelclient.py @@ -31,7 +31,8 @@ class GitRepoList(lister.Lister, command.Command): 'repo_name', 'env_id', 'git_url', - 'ref' + 'ref', + 'manage_master', ) def get_parser(self, prog_name): @@ -54,11 +55,13 @@ class AddRepo(command.Command): 'repo_name', 'env_id', 'git_url', - 'ref' + 'ref', + 'manage_master', ) def get_parser(self, prog_name): parser = super(AddRepo, self).get_parser(prog_name) + mm = parser.add_mutually_exclusive_group(required=False) parser.add_argument('--env', type=int, help='ID of environment to configure.', @@ -87,6 +90,19 @@ class AddRepo(command.Command): type=str, help='Path to private key file for accessing repo', required=False) + + mm.add_argument('--manage-master', + dest='manage_master', + help='Enable Fuel master management from this repo', + action='store_true', + required=False) + + mm.add_argument('--no-manage-master', + dest='manage_master', + help='Disable Fuel master management from this repo', + action='store_false', + required=False) + parser.set_defaults(manage_master=False) return parser def take_action(self, parsed_args): @@ -95,6 +111,7 @@ class AddRepo(command.Command): 'env_id': parsed_args.env, 'git_url': parsed_args.url, 'ref': parsed_args.ref, + 'manage_master': parsed_args.manage_master, } if parsed_args.key: @@ -142,11 +159,13 @@ class UpdateRepo(command.Command): 'id', 'repo_name', 'git_url', - 'ref' + 'ref', + 'manage_master', ) def get_parser(self, prog_name): parser = super(UpdateRepo, self).get_parser(prog_name) + mm = parser.add_mutually_exclusive_group(required=False) parser.add_argument('--repo', type=int, help='Repo ID to update', @@ -175,6 +194,19 @@ class UpdateRepo(command.Command): type=str, help='Path to private key file for accessing repo', required=False) + + mm.add_argument('--manage-master', + dest='manage_master', + help='Enable Fuel master management from this repo', + action='store_true', + required=False) + + mm.add_argument('--no-manage-master', + dest='manage_master', + help='Disable Fuel master management from this repo', + action='store_false', + required=False) + parser.set_defaults(manage_master=False) return parser def take_action(self, parsed_args): @@ -182,11 +214,12 @@ class UpdateRepo(command.Command): 'name': 'repo_name', 'url': 'git_url', 'ref': 'ref', + 'manage_master': 'manage_master', } data = {} for param, value in parsed_args.__dict__.items(): - if value and param in param_mapping.keys(): + if value is not None and param in param_mapping.keys(): data[param_mapping[param]] = value repos = APIClient.get_request('/clusters/git-repos/') env = [repo['env_id'] for repo in repos diff --git a/fuel_external_git/handlers.py b/fuel_external_git/handlers.py index 1ff4bdd..8587ca9 100644 --- a/fuel_external_git/handlers.py +++ b/fuel_external_git/handlers.py @@ -24,6 +24,7 @@ from nailgun.api.v1.validators import base from nailgun import errors from nailgun import objects + REPOS_DIR = '/var/lib/fuel_repos' @@ -37,8 +38,28 @@ class GitRepoValidator(base.BasicValidator): ) @classmethod - def validate_update(self, data, instance): + def _validate_master_mgmt(self, data, instance=None): d = self.validate_json(data) + if instance: + repo_id = instance.id + else: + repo_id = d.get('id', None) + if d.get('manage_master', False): + for repo in GitRepoCollection.all(): + if repo.manage_master and repo_id != repo.id: + raise errors.InvalidData( + ("Repo {} already marked for Fuel Master management. " + "Disable it first".format(repo.id)), + log_message=True) + return d + + @classmethod + def validate(self, data): + return self._validate_master_mgmt(data) + + @classmethod + def validate_update(self, data, instance): + d = self._validate_master_mgmt(data, instance) env_id = d.get('env_id') if env_id: cluster = objects.Cluster.get_by_uid(env_id) diff --git a/fuel_external_git/migrations/versions/adb78f70605d_manage_fuel_node_flag.py b/fuel_external_git/migrations/versions/adb78f70605d_manage_fuel_node_flag.py new file mode 100644 index 0000000..f9ffa5f --- /dev/null +++ b/fuel_external_git/migrations/versions/adb78f70605d_manage_fuel_node_flag.py @@ -0,0 +1,43 @@ +# 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. + +"""Manage fuel node flag + +Revision ID: adb78f70605d +Revises: d59114c46ac4 +Create Date: 2016-09-26 10:10:37.779555 + +""" + +# revision identifiers, used by Alembic. +revision = 'adb78f70605d' +down_revision = 'd59114c46ac4' +branch_labels = None +depends_on = None + +import sqlalchemy as sa + +from alembic import context +from alembic import op + + +def upgrade(): + table_prefix = context.config.get_main_option('table_prefix') + op.add_column( + table_prefix + 'repos', + sa.Column('manage_master', sa.Boolean(), nullable=True) + ) + + +def downgrade(): + table_prefix = context.config.get_main_option('table_prefix') + op.drop_column(table_prefix + 'repos', 'manage_master') diff --git a/fuel_external_git/models.py b/fuel_external_git/models.py index 1e678df..5bca03c 100644 --- a/fuel_external_git/models.py +++ b/fuel_external_git/models.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +from sqlalchemy import Boolean from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String @@ -28,3 +29,4 @@ class GitRepo(Base): ref = Column(String(255), default='', server_default='', nullable=False) user_key = Column(String(255), default='', server_default='', nullable=False) + manage_master = Column(Boolean(), nullable=False) diff --git a/fuel_external_git/objects.py b/fuel_external_git/objects.py index 1be0bfd..ea62c1c 100644 --- a/fuel_external_git/objects.py +++ b/fuel_external_git/objects.py @@ -38,7 +38,8 @@ class GitRepoSerializer(BasicSerializer): "env_id", "git_url", "ref", - "user_key" + "user_key", + "manage_master" ) diff --git a/fuel_external_git/settings.yaml b/fuel_external_git/settings.yaml index 2dff6df..ee6f61e 100644 --- a/fuel_external_git/settings.yaml +++ b/fuel_external_git/settings.yaml @@ -62,6 +62,7 @@ resource_mapping: nova_paste_api_ini: alias: nova-api-paste.ini path: /etc/nova/api-paste.ini +master_mapping: master_config: alias: master_config.yaml path: ""