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 server_url = config.get_server_url()
99 new_profiles = util.fetch_file_from_web(server_url, "/dcae-cli/profiles.json")
101 # REVIEW: Should we allow users to manually setup their config if not
102 # able to pull from remote server?
103 raise ProfilesInitError("Could not download profiles from remote server")
105 profiles_path = get_profiles_path()
107 if util.pref_exists(profiles_path):
108 existing_profiles = get_profiles(include_active=False)
109 # Make sure to clobber existing values and not other way
110 existing_profiles.update(new_profiles)
111 new_profiles = existing_profiles
113 write_pref(new_profiles, profiles_path)
117 def get_profiles(user_only=False, include_active=True):
118 '''Returns a dict containing all available profiles
120 Example of the returned dict:
123 "some_variable_A": "some_value_A",
124 "some_variable_B": "some_value_B",
125 "some_variable_C": "some_value_C"
130 profiles = get_pref(get_profiles_path(), reinit_profiles)
131 except ProfilesInitError as e:
132 raise DcaeException("Failed to initialize profiles: {0}".format(e))
138 active_name = get_active_name()
139 if active_name not in profiles:
140 raise DcaeException("Active profile '{}' does not exist. How did this happen?".format(active_name))
141 profiles[ACTIVE] = profiles[active_name]
146 def get_profile(name=ACTIVE):
147 '''Returns a `Profile` object'''
148 profiles = get_profiles()
150 if name not in profiles:
151 raise DcaeException("Specified profile '{}' does not exist.".format(name))
154 profile = Profile(**profiles[name])
155 except TypeError as e:
156 raise DcaeException("Specified profile '{}' is malformed.".format(name))
161 def create_profile(name, **kwargs):
162 '''Creates a new profile'''
163 _assert_not_reserved(name)
165 profiles = get_profiles(user_only=True)
167 raise DcaeException("Profile '{}' already exists.".format(name))
169 profile = _create_stub_profile()
170 profile.update(kwargs)
171 _assert_valid_profile(profile)
173 profiles[name] = profile
174 _write_profiles(profiles)
177 def delete_profile(name):
178 '''Deletes a profile'''
179 _assert_not_reserved(name)
180 profiles = get_profiles(user_only=True)
181 if name not in profiles:
182 raise DcaeException("Profile '{}' does not exist.".format(name))
183 if name == get_active_name():
184 logger.warning("Profile '{}' is currently active. Activate another profile first."
188 _write_profiles(profiles)
192 def update_profile(name, **kwargs):
193 '''Creates or updates a profile'''
194 _assert_not_reserved(name)
195 _assert_valid_profile(kwargs)
197 profiles = get_profiles(user_only=True)
198 if name not in profiles:
199 raise DcaeException("Profile '{}' does not exist.".format(name))
201 profiles[name].update(kwargs)
202 _write_profiles(profiles)
205 def _assert_valid_profile(params):
206 '''Raises DcaeException if the profile parameter dict is invalid'''
208 raise DcaeException('No update key-value pairs were provided.')
209 keys = set(params.keys())
210 if not _allowed_keys.issuperset(keys):
211 invalid_keys = keys - _allowed_keys
212 raise DcaeException("Invalid keys {} detected. Only keys {} are supported.".format(_fmt_seq(invalid_keys), _fmt_seq(_allowed_keys)))
215 def _assert_not_reserved(name):
216 '''Raises DcaeException if the profile is reserved'''
217 if name in _reserved_names:
218 raise DcaeException("Profile '{}' is reserved and cannot be modified.".format(name))
221 def _write_profiles(profiles):
222 '''Writes the profiles dictionary to disk'''
223 return write_pref(profiles, path=get_profiles_path())
226 def activate_profile(name):
227 '''Modifies the config and sets a new active profile'''
228 avail_profiles = set(get_profiles().keys()) - {ACTIVE, }
229 if name not in avail_profiles:
230 raise DcaeException("Profile name '{}' does not exist. Please select from {} or create a new profile.".format(name, _fmt_seq(avail_profiles)))
231 _set_active_name(name)