vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / cli / utils.py
1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements.  See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License.  You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 """
17 Miscellaneous CLI utilities.
18 """
19
20 import os
21 import sys
22 from StringIO import StringIO
23
24 from backports.shutil_get_terminal_size import get_terminal_size
25
26 from .env import logger
27 from .exceptions import AriaCliError
28 from ..utils import http
29
30
31 def storage_sort_param(sort_by, descending):
32     return {sort_by: 'desc' if descending else 'asc'}
33
34
35 def get_parameter_templates_as_string(parameter_templates):
36     params_string = StringIO()
37
38     for param_name, param_template in parameter_templates.iteritems():
39         params_string.write('\t{0}:{1}'.format(param_name, os.linesep))
40         param_dict = param_template.to_dict()
41         del param_dict['id']  # not interested in printing the id
42         for k, v in param_dict.iteritems():
43             params_string.write('\t\t{0}: {1}{2}'.format(k, v, os.linesep))
44
45     params_string.write(os.linesep)
46     return params_string.getvalue()
47
48
49 def check_overriding_storage_exceptions(e, model_class, name):
50     """
51     Checks whether the storage exception is a known type where we'd like to override the exception
52     message; If so, it raises a new error. Otherwise it simply returns.
53     """
54     assert isinstance(e, BaseException)
55     if 'UNIQUE constraint failed' in e.message:
56         new_message = \
57             'Could not store {model_class} `{name}`{linesep}' \
58             'There already a exists a {model_class} with the same name' \
59                 .format(model_class=model_class, name=name, linesep=os.linesep)
60         trace = sys.exc_info()[2]
61         raise type(e), type(e)(new_message), trace  # pylint: disable=raising-non-exception
62
63
64 def download_file(url):
65     progress_bar = generate_progress_handler(url, 'Downloading')
66     try:
67         destination = http.download_file(url, logger=logger, progress_handler=progress_bar)
68     except Exception as e:
69         raise AriaCliError(
70             'Failed to download {0}. ({1})'.format(url, str(e)))
71     return destination
72
73
74 def generate_progress_handler(file_path, action='', max_bar_length=80):
75     """
76     Returns a function that prints a progress bar in the terminal.
77
78     :param file_path: the name of the file being transferred
79     :param action: uploading/downloading
80     :param max_bar_length: maximum allowed length of the bar
81     :return: configured ``print_progress`` function
82     """
83     # We want to limit the maximum line length to 80, but allow for a smaller terminal size. We also
84     # include the action string, and some extra chars
85     terminal_width = get_terminal_size().columns
86
87     # This takes care of the case where there is no terminal (e.g. unittest)
88     terminal_width = terminal_width or max_bar_length
89     bar_length = min(max_bar_length, terminal_width) - len(action) - 12
90
91     # Shorten the file name if it's too long
92     file_name = os.path.basename(file_path)
93     if len(file_name) > (bar_length / 4) + 3:
94         file_name = file_name[:bar_length / 4] + '...'
95
96     bar_length -= len(file_name)
97
98     def print_progress(read_bytes, total_bytes):
99         """
100         Print upload/download progress on a single line.
101
102         Call this function in a loop to create a progress bar in the terminal.
103
104         :param read_bytes: number of bytes already processed
105         :param total_bytes: total number of bytes in the file
106         """
107
108         filled_length = min(bar_length, int(round(bar_length * read_bytes / float(total_bytes))))
109         percents = min(100.00, round(100.00 * (read_bytes / float(total_bytes)), 2))
110         bar = '#' * filled_length + '-' * (bar_length - filled_length)  # pylint: disable=blacklisted-name
111
112         # The \r caret makes sure the cursor moves back to the beginning of the line
113         sys.stdout.write('\r{0} {1} |{2}| {3}%'.format(action, file_name, bar, percents))
114         if read_bytes >= total_bytes:
115             sys.stdout.write(os.linesep)
116
117     return print_progress