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
32 from dcae_cli import util
33 from dcae_cli.util import get_app_dir, get_pref, write_pref
34 from dcae_cli.util import config
35 from dcae_cli.util.config import get_config, update_config
36 from dcae_cli.util.exc import DcaeException
37 from dcae_cli.util.logger import get_logger
40 logger = get_logger('Profile')
43 # reserved profile names
45 _reserved_names = {ACTIVE}
48 # create enums for profile keys so that they can be imported for testing, instead of using literals
49 CONSUL_HOST = 'consul_host'
50 CONFIG_BINDING_SERVICE = 'config_binding_service'
51 CDAP_BROKER = 'cdap_broker'
52 DOCKER_HOST = 'docker_host'
54 # TODO: Should probably lift this strict list of allowed keys and repurpose to be
55 # keys that are required.
56 _allowed_keys = set([CONSUL_HOST, CONFIG_BINDING_SERVICE, CDAP_BROKER, DOCKER_HOST])
57 Profile = namedtuple('Profile', _allowed_keys)
60 def _create_stub_profile():
61 """Create a new stub of a profile"""
62 return { k: "" for k in _allowed_keys }
66 '''Returns a sorted string formatted list'''
67 return list(sorted(map(str, seq)))
70 def get_profiles_path():
71 '''Returns the absolute path to the profiles file'''
72 return os.path.join(get_app_dir(), 'profiles.json')
75 def get_active_name():
76 '''Returns the active profile name in the config'''
77 return config.get_active_profile()
80 def _set_active_name(name):
81 '''Sets the active profile name in the config'''
82 update_config(active_profile=name)
85 class ProfilesInitError(RuntimeError):
88 def reinit_profiles():
89 """Reinitialize profiles
91 Grab the remote profiles and merge with the local profiles if there is one.
95 Dict of complete new profiles
97 # Grab the remote profiles and merge it in
99 server_url = config.get_server_url()
100 new_profiles = util.fetch_file_from_web(server_url, "/dcae-cli/profiles.json")
102 # Failing to pull seed profiles from remote server is not considered
103 # a problem. Just continue and give user the option to use an empty
105 if click.confirm("Could not download initial profiles from remote server. Set empty default?"):
106 new_profiles = {"default": { "consul_host": "", "config_binding_service": "",
107 "cdap_broker": "", "docker_host": ""}}
109 raise ProfilesInitError("Could not setup dcae-cli profiles")
111 profiles_path = get_profiles_path()
113 if util.pref_exists(profiles_path):
114 existing_profiles = get_profiles(include_active=False)
115 # Make sure to clobber existing values and not other way
116 existing_profiles.update(new_profiles)
117 new_profiles = existing_profiles
119 write_pref(new_profiles, profiles_path)
123 def get_profiles(user_only=False, include_active=True):
124 '''Returns a dict containing all available profiles
126 Example of the returned dict:
129 "some_variable_A": "some_value_A",
130 "some_variable_B": "some_value_B",
131 "some_variable_C": "some_value_C"
136 profiles = get_pref(get_profiles_path(), reinit_profiles)
137 except ProfilesInitError as e:
138 raise DcaeException("Failed to initialize profiles: {0}".format(e))
144 active_name = get_active_name()
145 if active_name not in profiles:
146 raise DcaeException("Active profile '{}' does not exist. How did this happen?".format(active_name))
147 profiles[ACTIVE] = profiles[active_name]
152 def get_profile(name=ACTIVE):
153 '''Returns a `Profile` object'''
154 profiles = get_profiles()
156 if name not in profiles:
157 raise DcaeException("Specified profile '{}' does not exist.".format(name))
160 profile = Profile(**profiles[name])
161 except TypeError as e:
162 raise DcaeException("Specified profile '{}' is malformed.".format(name))
167 def create_profile(name, **kwargs):
168 '''Creates a new profile'''
169 _assert_not_reserved(name)
171 profiles = get_profiles(user_only=True)
173 raise DcaeException("Profile '{}' already exists.".format(name))
175 profile = _create_stub_profile()
176 profile.update(kwargs)
177 _assert_valid_profile(profile)
179 profiles[name] = profile
180 _write_profiles(profiles)
183 def delete_profile(name):
184 '''Deletes a profile'''
185 _assert_not_reserved(name)
186 profiles = get_profiles(user_only=True)
187 if name not in profiles:
188 raise DcaeException("Profile '{}' does not exist.".format(name))
189 if name == get_active_name():
190 logger.warning("Profile '{}' is currently active. Activate another profile first."
194 _write_profiles(profiles)
198 def update_profile(name, **kwargs):
199 '''Creates or updates a profile'''
200 _assert_not_reserved(name)
201 _assert_valid_profile(kwargs)
203 profiles = get_profiles(user_only=True)
204 if name not in profiles:
205 raise DcaeException("Profile '{}' does not exist.".format(name))
207 profiles[name].update(kwargs)
208 _write_profiles(profiles)
211 def _assert_valid_profile(params):
212 '''Raises DcaeException if the profile parameter dict is invalid'''
214 raise DcaeException('No update key-value pairs were provided.')
215 keys = set(params.keys())
216 if not _allowed_keys.issuperset(keys):
217 invalid_keys = keys - _allowed_keys
218 raise DcaeException("Invalid keys {} detected. Only keys {} are supported.".format(_fmt_seq(invalid_keys), _fmt_seq(_allowed_keys)))
221 def _assert_not_reserved(name):
222 '''Raises DcaeException if the profile is reserved'''
223 if name in _reserved_names:
224 raise DcaeException("Profile '{}' is reserved and cannot be modified.".format(name))
227 def _write_profiles(profiles):
228 '''Writes the profiles dictionary to disk'''
229 return write_pref(profiles, path=get_profiles_path())
232 def activate_profile(name):
233 '''Modifies the config and sets a new active profile'''
234 avail_profiles = set(get_profiles().keys()) - {ACTIVE, }
235 if name not in avail_profiles:
236 raise DcaeException("Profile name '{}' does not exist. Please select from {} or create a new profile.".format(name, _fmt_seq(avail_profiles)))
237 _set_active_name(name)