~charmers/charms/xenial/rsyslog/trunk

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/fetch/snap.py

  • Committer: Jorge Niedbalski
  • Date: 2017-06-09 21:53:21 UTC
  • mfrom: (34.1.6 fix-reload)
  • Revision ID: jorge.niedbalski@canonical.com-20170609215321-jdrndwnpqbhio9rv
[freyes,r=niedbalski] Fixes LP: #1694270.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2014-2017 Canonical Limited.
 
2
#
 
3
# Licensed under the Apache License, Version 2.0 (the "License");
 
4
# you may not use this file except in compliance with the License.
 
5
# You may obtain a copy of the License at
 
6
#
 
7
#  http://www.apache.org/licenses/LICENSE-2.0
 
8
#
 
9
# Unless required by applicable law or agreed to in writing, software
 
10
# distributed under the License is distributed on an "AS IS" BASIS,
 
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
12
# See the License for the specific language governing permissions and
 
13
# limitations under the License.
 
14
"""
 
15
Charm helpers snap for classic charms.
 
16
 
 
17
If writing reactive charms, use the snap layer:
 
18
https://lists.ubuntu.com/archives/snapcraft/2016-September/001114.html
 
19
"""
 
20
import subprocess
 
21
from os import environ
 
22
from time import sleep
 
23
from charmhelpers.core.hookenv import log
 
24
 
 
25
__author__ = 'Joseph Borg <joseph.borg@canonical.com>'
 
26
 
 
27
SNAP_NO_LOCK = 1  # The return code for "couldn't acquire lock" in Snap (hopefully this will be improved).
 
28
SNAP_NO_LOCK_RETRY_DELAY = 10  # Wait X seconds between Snap lock checks.
 
29
SNAP_NO_LOCK_RETRY_COUNT = 30  # Retry to acquire the lock X times.
 
30
 
 
31
 
 
32
class CouldNotAcquireLockException(Exception):
 
33
    pass
 
34
 
 
35
 
 
36
def _snap_exec(commands):
 
37
    """
 
38
    Execute snap commands.
 
39
 
 
40
    :param commands: List commands
 
41
    :return: Integer exit code
 
42
    """
 
43
    assert type(commands) == list
 
44
 
 
45
    retry_count = 0
 
46
    return_code = None
 
47
 
 
48
    while return_code is None or return_code == SNAP_NO_LOCK:
 
49
        try:
 
50
            return_code = subprocess.check_call(['snap'] + commands, env=environ)
 
51
        except subprocess.CalledProcessError as e:
 
52
            retry_count += + 1
 
53
            if retry_count > SNAP_NO_LOCK_RETRY_COUNT:
 
54
                raise CouldNotAcquireLockException('Could not aquire lock after %s attempts' % SNAP_NO_LOCK_RETRY_COUNT)
 
55
            return_code = e.returncode
 
56
            log('Snap failed to acquire lock, trying again in %s seconds.' % SNAP_NO_LOCK_RETRY_DELAY, level='WARN')
 
57
            sleep(SNAP_NO_LOCK_RETRY_DELAY)
 
58
 
 
59
    return return_code
 
60
 
 
61
 
 
62
def snap_install(packages, *flags):
 
63
    """
 
64
    Install a snap package.
 
65
 
 
66
    :param packages: String or List String package name
 
67
    :param flags: List String flags to pass to install command
 
68
    :return: Integer return code from snap
 
69
    """
 
70
    if type(packages) is not list:
 
71
        packages = [packages]
 
72
 
 
73
    flags = list(flags)
 
74
 
 
75
    message = 'Installing snap(s) "%s"' % ', '.join(packages)
 
76
    if flags:
 
77
        message += ' with option(s) "%s"' % ', '.join(flags)
 
78
 
 
79
    log(message, level='INFO')
 
80
    return _snap_exec(['install'] + flags + packages)
 
81
 
 
82
 
 
83
def snap_remove(packages, *flags):
 
84
    """
 
85
    Remove a snap package.
 
86
 
 
87
    :param packages: String or List String package name
 
88
    :param flags: List String flags to pass to remove command
 
89
    :return: Integer return code from snap
 
90
    """
 
91
    if type(packages) is not list:
 
92
        packages = [packages]
 
93
 
 
94
    flags = list(flags)
 
95
 
 
96
    message = 'Removing snap(s) "%s"' % ', '.join(packages)
 
97
    if flags:
 
98
        message += ' with options "%s"' % ', '.join(flags)
 
99
 
 
100
    log(message, level='INFO')
 
101
    return _snap_exec(['remove'] + flags + packages)
 
102
 
 
103
 
 
104
def snap_refresh(packages, *flags):
 
105
    """
 
106
    Refresh / Update snap package.
 
107
 
 
108
    :param packages: String or List String package name
 
109
    :param flags: List String flags to pass to refresh command
 
110
    :return: Integer return code from snap
 
111
    """
 
112
    if type(packages) is not list:
 
113
        packages = [packages]
 
114
 
 
115
    flags = list(flags)
 
116
 
 
117
    message = 'Refreshing snap(s) "%s"' % ', '.join(packages)
 
118
    if flags:
 
119
        message += ' with options "%s"' % ', '.join(flags)
 
120
 
 
121
    log(message, level='INFO')
 
122
    return _snap_exec(['refresh'] + flags + packages)