~ubuntu-branches/ubuntu/saucy/cloud-init/saucy

« back to all changes in this revision

Viewing changes to cloudinit/sources/DataSourceSmartOS.py

  • Committer: Package Import Robot
  • Author(s): Scott Moser
  • Date: 2013-08-29 04:54:39 UTC
  • mfrom: (1.4.4)
  • Revision ID: package-import@ubuntu.com-20130829045439-lp1xe1nvv462ko11
Tags: 0.7.3~bzr862-0ubuntu1
* New upstream snapshot.
  * support base64 encoded data in the smart os datasource

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#
28
28
 
29
29
 
 
30
import base64
30
31
from cloudinit import log as logging
31
32
from cloudinit import sources
32
33
from cloudinit import util
34
35
import os.path
35
36
import serial
36
37
 
37
 
 
38
38
DEF_TTY_LOC = '/dev/ttyS1'
39
39
DEF_TTY_TIMEOUT = 60
40
40
LOG = logging.getLogger(__name__)
49
49
    'motd_sys_info': ('motd_sys_info', True),
50
50
}
51
51
 
 
52
# These are values which will never be base64 encoded.
 
53
# They come from the cloud platform, not user
 
54
SMARTOS_NO_BASE64 = ['root_authorized_keys', 'motd_sys_info',
 
55
                     'iptables_disable']
 
56
 
52
57
 
53
58
class DataSourceSmartOS(sources.DataSource):
54
59
    def __init__(self, sys_cfg, distro, paths):
55
60
        sources.DataSource.__init__(self, sys_cfg, distro, paths)
56
61
        self.seed_dir = os.path.join(paths.seed_dir, 'sdc')
57
62
        self.is_smartdc = None
58
 
        self.seed = self.sys_cfg.get("serial_device", DEF_TTY_LOC)
59
 
        self.seed_timeout = self.sys_cfg.get("serial_timeout",
60
 
                                             DEF_TTY_TIMEOUT)
 
63
 
 
64
        self.seed = self.ds_cfg.get("serial_device", DEF_TTY_LOC)
 
65
        self.seed_timeout = self.ds_cfg.get("serial_timeout", DEF_TTY_TIMEOUT)
 
66
        self.smartos_no_base64 = self.ds_cfg.get('no_base64_decode',
 
67
                                                 SMARTOS_NO_BASE64)
 
68
        self.b64_keys = self.ds_cfg.get('base64_keys', [])
 
69
        self.b64_all = self.ds_cfg.get('base64_all', False)
61
70
 
62
71
    def __str__(self):
63
72
        root = sources.DataSource.__str__(self)
79
88
 
80
89
        system_uuid, system_type = dmi_info
81
90
        if 'smartdc' not in system_type.lower():
82
 
            LOG.debug("Host is not on SmartOS")
 
91
            LOG.debug("Host is not on SmartOS. system_type=%s", system_type)
83
92
            return False
84
93
        self.is_smartdc = True
85
94
        md['instance-id'] = system_uuid
86
95
 
 
96
        b64_keys = self.query('base64_keys', strip=True, b64=False)
 
97
        if b64_keys is not None:
 
98
            self.b64_keys = [k.strip() for k in str(b64_keys).split(',')]
 
99
 
 
100
        b64_all = self.query('base64_all', strip=True, b64=False)
 
101
        if b64_all is not None:
 
102
            self.b64_all = util.is_true(b64_all)
 
103
 
87
104
        for ci_noun, attribute in SMARTOS_ATTRIB_MAP.iteritems():
88
105
            smartos_noun, strip = attribute
89
 
            md[ci_noun] = query_data(smartos_noun, self.seed,
90
 
                                     self.seed_timeout, strip=strip)
 
106
            md[ci_noun] = self.query(smartos_noun, strip=strip)
91
107
 
92
108
        if not md['local-hostname']:
93
109
            md['local-hostname'] = system_uuid
94
110
 
 
111
        ud = None
95
112
        if md['user-data']:
96
113
            ud = md['user-data']
97
 
        else:
 
114
        elif md['user-script']:
98
115
            ud = md['user-script']
99
116
 
100
117
        self.metadata = md
104
121
    def get_instance_id(self):
105
122
        return self.metadata['instance-id']
106
123
 
 
124
    def query(self, noun, strip=False, default=None, b64=None):
 
125
        if b64 is None:
 
126
            if noun in self.smartos_no_base64:
 
127
                b64 = False
 
128
            elif self.b64_all or noun in self.b64_keys:
 
129
                b64 = True
 
130
 
 
131
        return query_data(noun=noun, strip=strip, seed_device=self.seed,
 
132
                          seed_timeout=self.seed_timeout, default=default,
 
133
                          b64=b64)
 
134
 
107
135
 
108
136
def get_serial(seed_device, seed_timeout):
109
137
    """This is replaced in unit testing, allowing us to replace
110
 
        serial.Serial with a mocked class
 
138
        serial.Serial with a mocked class.
111
139
 
112
140
        The timeout value of 60 seconds should never be hit. The value
113
141
        is taken from SmartOS own provisioning tools. Since we are reading
124
152
    return ser
125
153
 
126
154
 
127
 
def query_data(noun, seed_device, seed_timeout, strip=False):
 
155
def query_data(noun, seed_device, seed_timeout, strip=False, default=None,
 
156
               b64=None):
128
157
    """Makes a request to via the serial console via "GET <NOUN>"
129
158
 
130
159
        In the response, the first line is the status, while subsequent lines
131
160
        are is the value. A blank line with a "." is used to indicate end of
132
161
        response.
 
162
 
 
163
        If the response is expected to be base64 encoded, then set b64encoded
 
164
        to true. Unfortantely, there is no way to know if something is 100%
 
165
        encoded, so this method relies on being told if the data is base64 or
 
166
        not.
133
167
    """
134
168
 
135
169
    if not noun:
143
177
 
144
178
    if 'SUCCESS' not in status:
145
179
        ser.close()
146
 
        return None
 
180
        return default
147
181
 
148
182
    while not eom_found:
149
183
        m = ser.readline()
153
187
            response.append(m)
154
188
 
155
189
    ser.close()
156
 
    if not strip:
157
 
        return "".join(response)
 
190
 
 
191
    if b64 is None:
 
192
        b64 = query_data('b64-%s' % noun, seed_device=seed_device,
 
193
                            seed_timeout=seed_timeout, b64=False,
 
194
                            default=False, strip=True)
 
195
        b64 = util.is_true(b64)
 
196
 
 
197
    resp = None
 
198
    if b64 or strip:
 
199
        resp = "".join(response).rstrip()
158
200
    else:
159
 
        return "".join(response).rstrip()
160
 
 
161
 
    return None
 
201
        resp = "".join(response)
 
202
 
 
203
    if b64:
 
204
        try:
 
205
            return base64.b64decode(resp)
 
206
        except TypeError:
 
207
            LOG.warn("Failed base64 decoding key '%s'", noun)
 
208
            return resp
 
209
 
 
210
    return resp
162
211
 
163
212
 
164
213
def dmi_data():