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": "",
107 "config_binding_service": "config_binding_service",
108 "cdap_broker": "cdap_broker", "docker_host": ""}}
110 raise ProfilesInitError("Could not setup dcae-cli profiles")
112 profiles_path = get_profiles_path()
114 if util.pref_exists(profiles_path):
115 existing_profiles = get_profiles(include_active=False)
116 # Make sure to clobber existing values and not other way
117 existing_profiles.update(new_profiles)
118 new_profiles = existing_profiles
120 write_pref(new_profiles, profiles_path)
124 def get_profiles(user_only=False, include_active=True):
125 '''Returns a dict containing all available profiles
127 Example of the returned dict:
130 "some_variable_A": "some_value_A",
131 "some_variable_B": "some_value_B",
132 "some_variable_C": "some_value_C"
137 profiles = get_pref(get_profiles_path(), reinit_profiles)
138 except ProfilesInitError as e:
139 raise DcaeException("Failed to initialize profiles: {0}".format(e))
145 active_name = get_active_name()
146 if active_name not in profiles:
147 raise DcaeException("Active profile '{}' does not exist. How did this happen?".format(active_name))
148 profiles[ACTIVE] = profiles[active_name]
153 def get_profile(name=ACTIVE):
154 '''Returns a `Profile` object'''
155 profiles = get_profiles()
157 if name not in profiles:
158 raise DcaeException("Specified profile '{}' does not exist.".format(name))
161 profile = Profile(**profiles[name])
162 except TypeError as e:
163 raise DcaeException("Specified profile '{}' is malformed.".format(name))
168 def create_profile(name, **kwargs):
169 '''Creates a new profile'''
170 _assert_not_reserved(name)
172 profiles = get_profiles(user_only=True)
174 raise DcaeException("Profile '{}' already exists.".format(name))
176 profile = _create_stub_profile()
177 profile.update(kwargs)
178 _assert_valid_profile(profile)
180 profiles[name] = profile
181 _write_profiles(profiles)
184 def delete_profile(name):
185 '''Deletes a profile'''
186 _assert_not_reserved(name)
187 profiles = get_profiles(user_only=True)
188 if name not in profiles:
189 raise DcaeException("Profile '{}' does not exist.".format(name))
190 if name == get_active_name():
191 logger.warning("Profile '{}' is currently active. Activate another profile first."
195 _write_profiles(profiles)
199 def update_profile(name, **kwargs):
200 '''Creates or updates a profile'''
201 _assert_not_reserved(name)
202 _assert_valid_profile(kwargs)
204 profiles = get_profiles(user_only=True)
205 if name not in profiles:
206 raise DcaeException("Profile '{}' does not exist.".format(name))
208 profiles[name].update(kwargs)
209 _write_profiles(profiles)
212 def _assert_valid_profile(params):
213 '''Raises DcaeException if the profile parameter dict is invalid'''
215 raise DcaeException('No update key-value pairs were provided.')
216 keys = set(params.keys())
217 if not _allowed_keys.issuperset(keys):
218 invalid_keys = keys - _allowed_keys
219 raise DcaeException("Invalid keys {} detected. Only keys {} are supported.".format(_fmt_seq(invalid_keys), _fmt_seq(_allowed_keys)))
222 def _assert_not_reserved(name):
223 '''Raises DcaeException if the profile is reserved'''
224 if name in _reserved_names:
225 raise DcaeException("Profile '{}' is reserved and cannot be modified.".format(name))
228 def _write_profiles(profiles):
229 '''Writes the profiles dictionary to disk'''
230 return write_pref(profiles, path=get_profiles_path())
233 def activate_profile(name):
234 '''Modifies the config and sets a new active profile'''
235 avail_profiles = set(get_profiles().keys()) - {ACTIVE, }
236 if name not in avail_profiles:
237 raise DcaeException("Profile name '{}' does not exist. Please select from {} or create a new profile.".format(name, _fmt_seq(avail_profiles)))
238 _set_active_name(name)