1 # ============LICENSE_START=======================================================
3 # ================================================================================
4 # Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
5 # ================================================================================
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 # ============LICENSE_END=========================================================
19 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
21 #!/usr/bin/env python3
22 # -*- coding: utf-8 -*-
24 Provides dcae cli profile variables
27 from collections import namedtuple
31 from dcae_cli import util
32 from dcae_cli.util import get_app_dir, get_pref, write_pref
33 from dcae_cli.util import config
34 from dcae_cli.util.config import get_config, update_config
35 from dcae_cli.util.exc import DcaeException
36 from dcae_cli.util.logger import get_logger
39 logger = get_logger('Profile')
42 # reserved profile names
44 _reserved_names = {ACTIVE}
47 # create enums for profile keys so that they can be imported for testing, instead of using literals
48 CONSUL_HOST = 'consul_host'
49 CONFIG_BINDING_SERVICE = 'config_binding_service'
50 CDAP_BROKER = 'cdap_broker'
51 DOCKER_HOST = 'docker_host'
53 # TODO: Should probably lift this strict list of allowed keys and repurpose to be
54 # keys that are required.
55 _allowed_keys = set([CONSUL_HOST, CONFIG_BINDING_SERVICE, CDAP_BROKER, DOCKER_HOST])
56 Profile = namedtuple('Profile', _allowed_keys)
59 def _create_stub_profile():
60 """Create a new stub of a profile"""
61 return { k: "" for k in _allowed_keys }
65 '''Returns a sorted string formatted list'''
66 return list(sorted(map(str, seq)))
69 def get_profiles_path():
70 '''Returns the absolute path to the profiles file'''
71 return os.path.join(get_app_dir(), 'profiles.json')
74 def get_active_name():
75 '''Returns the active profile name in the config'''
76 return config.get_active_profile()
79 def _set_active_name(name):
80 '''Sets the active profile name in the config'''
81 update_config(active_profile=name)
84 class ProfilesInitError(RuntimeError):
87 def reinit_profiles():
88 """Reinitialize profiles
90 Grab the remote profiles and merge with the local profiles if there is one.
94 Dict of complete new profiles
96 # Grab the remote profiles and merge it in
98 new_profiles = util.fetch_file_from_nexus("/dcae-cli/profiles.json")
100 # REVIEW: Should we allow users to manually setup their config if not
101 # able to pull from remote server?
102 raise ProfilesInitError("Could not download profiles from remote server")
104 profiles_path = get_profiles_path()
106 if util.pref_exists(profiles_path):
107 existing_profiles = get_profiles(include_active=False)
108 # Make sure to clobber existing values and not other way
109 existing_profiles.update(new_profiles)
110 new_profiles = existing_profiles
112 write_pref(new_profiles, profiles_path)
116 def get_profiles(user_only=False, include_active=True):
117 '''Returns a dict containing all available profiles
119 Example of the returned dict:
122 "some_variable_A": "some_value_A",
123 "some_variable_B": "some_value_B",
124 "some_variable_C": "some_value_C"
129 profiles = get_pref(get_profiles_path(), reinit_profiles)
130 except ProfilesInitError as e:
131 raise DcaeException("Failed to initialize profiles: {0}".format(e))
137 active_name = get_active_name()
138 if active_name not in profiles:
139 raise DcaeException("Active profile '{}' does not exist. How did this happen?".format(active_name))
140 profiles[ACTIVE] = profiles[active_name]
145 def get_profile(name=ACTIVE):
146 '''Returns a `Profile` object'''
147 profiles = get_profiles()
149 if name not in profiles:
150 raise DcaeException("Specified profile '{}' does not exist.".format(name))
153 profile = Profile(**profiles[name])
154 except TypeError as e:
155 raise DcaeException("Specified profile '{}' is malformed.".format(name))
160 def create_profile(name, **kwargs):
161 '''Creates a new profile'''
162 _assert_not_reserved(name)
164 profiles = get_profiles(user_only=True)
166 raise DcaeException("Profile '{}' already exists.".format(name))
168 profile = _create_stub_profile()
169 profile.update(kwargs)
170 _assert_valid_profile(profile)
172 profiles[name] = profile
173 _write_profiles(profiles)
176 def delete_profile(name):
177 '''Deletes a profile'''
178 _assert_not_reserved(name)
179 profiles = get_profiles(user_only=True)
180 if name not in profiles:
181 raise DcaeException("Profile '{}' does not exist.".format(name))
182 if name == get_active_name():
183 logger.warning("Profile '{}' is currently active. Activate another profile first."
187 _write_profiles(profiles)
191 def update_profile(name, **kwargs):
192 '''Creates or updates a profile'''
193 _assert_not_reserved(name)
194 _assert_valid_profile(kwargs)
196 profiles = get_profiles(user_only=True)
197 if name not in profiles:
198 raise DcaeException("Profile '{}' does not exist.".format(name))
200 profiles[name].update(kwargs)
201 _write_profiles(profiles)
204 def _assert_valid_profile(params):
205 '''Raises DcaeException if the profile parameter dict is invalid'''
207 raise DcaeException('No update key-value pairs were provided.')
208 keys = set(params.keys())
209 if not _allowed_keys.issuperset(keys):
210 invalid_keys = keys - _allowed_keys
211 raise DcaeException("Invalid keys {} detected. Only keys {} are supported.".format(_fmt_seq(invalid_keys), _fmt_seq(_allowed_keys)))
214 def _assert_not_reserved(name):
215 '''Raises DcaeException if the profile is reserved'''
216 if name in _reserved_names:
217 raise DcaeException("Profile '{}' is reserved and cannot be modified.".format(name))
220 def _write_profiles(profiles):
221 '''Writes the profiles dictionary to disk'''
222 return write_pref(profiles, path=get_profiles_path())
225 def activate_profile(name):
226 '''Modifies the config and sets a new active profile'''
227 avail_profiles = set(get_profiles().keys()) - {ACTIVE, }
228 if name not in avail_profiles:
229 raise DcaeException("Profile name '{}' does not exist. Please select from {} or create a new profile.".format(name, _fmt_seq(avail_profiles)))
230 _set_active_name(name)