Blame tests/unittests/test_datasource/test_smartos.py

Packit Service a04d08
# Copyright (C) 2013 Canonical Ltd.
Packit Service a04d08
# Copyright 2019 Joyent, Inc.
Packit Service a04d08
#
Packit Service a04d08
# Author: Ben Howard <ben.howard@canonical.com>
Packit Service a04d08
#
Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service a04d08
'''This is a testcase for the SmartOS datasource.
Packit Service a04d08
Packit Service a04d08
It replicates a serial console and acts like the SmartOS console does in
Packit Service a04d08
order to validate return responses.
Packit Service a04d08
Packit Service a04d08
'''
Packit Service a04d08
Packit Service a04d08
from binascii import crc32
Packit Service a04d08
import json
Packit Service a04d08
import multiprocessing
Packit Service a04d08
import os
Packit Service a04d08
import os.path
Packit Service a04d08
import re
Packit Service a04d08
import signal
Packit Service a04d08
import stat
Packit Service 751c4a
import unittest
Packit Service a04d08
import uuid
Packit Service a04d08
Packit Service a04d08
from cloudinit import serial
Packit Service a04d08
from cloudinit.sources import DataSourceSmartOS
Packit Service a04d08
from cloudinit.sources.DataSourceSmartOS import (
Packit Service a04d08
    convert_smartos_network_data as convert_net,
Packit Service a04d08
    SMARTOS_ENV_KVM, SERIAL_DEVICE, get_smartos_environ,
Packit Service a04d08
    identify_file)
Packit Service a04d08
from cloudinit.event import EventType
Packit Service a04d08
Packit Service a04d08
from cloudinit import helpers as c_helpers
Packit Service 751c4a
from cloudinit.util import (b64e, write_file)
Packit Service 751c4a
from cloudinit.subp import (subp, ProcessExecutionError, which)
Packit Service a04d08
Packit Service a04d08
from cloudinit.tests.helpers import (
Packit Service a04d08
    CiTestCase, mock, FilesystemMockingTestCase, skipIf)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
try:
Packit Service a04d08
    import serial as _pyserial
Packit Service a04d08
    assert _pyserial  # avoid pyflakes error F401: import unused
Packit Service a04d08
    HAS_PYSERIAL = True
Packit Service a04d08
except ImportError:
Packit Service a04d08
    HAS_PYSERIAL = False
Packit Service a04d08
Packit Service a04d08
DSMOS = 'cloudinit.sources.DataSourceSmartOS'
Packit Service a04d08
SDC_NICS = json.loads("""
Packit Service a04d08
[
Packit Service a04d08
    {
Packit Service a04d08
        "nic_tag": "external",
Packit Service a04d08
        "primary": true,
Packit Service a04d08
        "mtu": 1500,
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "gateway": "8.12.42.1",
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "8.12.42.102",
Packit Service a04d08
        "network_uuid": "992fc7ce-6aac-4b74-aed6-7b9d2c6c0bfe",
Packit Service a04d08
        "gateways": [
Packit Service a04d08
            "8.12.42.1"
Packit Service a04d08
        ],
Packit Service a04d08
        "vlan_id": 324,
Packit Service a04d08
        "mac": "90:b8:d0:f5:e4:f5",
Packit Service a04d08
        "interface": "net0",
Packit Service a04d08
        "ips": [
Packit Service a04d08
            "8.12.42.102/24"
Packit Service a04d08
        ]
Packit Service a04d08
    },
Packit Service a04d08
    {
Packit Service a04d08
        "nic_tag": "sdc_overlay/16187209",
Packit Service a04d08
        "gateway": "192.168.128.1",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mac": "90:b8:d0:a5:ff:cd",
Packit Service a04d08
        "netmask": "255.255.252.0",
Packit Service a04d08
        "ip": "192.168.128.93",
Packit Service a04d08
        "network_uuid": "4cad71da-09bc-452b-986d-03562a03a0a9",
Packit Service a04d08
        "gateways": [
Packit Service a04d08
            "192.168.128.1"
Packit Service a04d08
        ],
Packit Service a04d08
        "vlan_id": 2,
Packit Service a04d08
        "mtu": 8500,
Packit Service a04d08
        "interface": "net1",
Packit Service a04d08
        "ips": [
Packit Service a04d08
            "192.168.128.93/22"
Packit Service a04d08
        ]
Packit Service a04d08
    }
Packit Service a04d08
]
Packit Service a04d08
""")
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
SDC_NICS_ALT = json.loads("""
Packit Service a04d08
[
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net0",
Packit Service a04d08
        "mac": "90:b8:d0:ae:64:51",
Packit Service a04d08
        "vlan_id": 324,
Packit Service a04d08
        "nic_tag": "external",
Packit Service a04d08
        "gateway": "8.12.42.1",
Packit Service a04d08
        "gateways": [
Packit Service a04d08
          "8.12.42.1"
Packit Service a04d08
        ],
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "8.12.42.51",
Packit Service a04d08
        "ips": [
Packit Service a04d08
          "8.12.42.51/24"
Packit Service a04d08
        ],
Packit Service a04d08
        "network_uuid": "992fc7ce-6aac-4b74-aed6-7b9d2c6c0bfe",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500,
Packit Service a04d08
        "primary": true
Packit Service a04d08
    },
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net1",
Packit Service a04d08
        "mac": "90:b8:d0:bd:4f:9c",
Packit Service a04d08
        "vlan_id": 600,
Packit Service a04d08
        "nic_tag": "internal",
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "10.210.1.217",
Packit Service a04d08
        "ips": [
Packit Service a04d08
          "10.210.1.217/24"
Packit Service a04d08
        ],
Packit Service a04d08
        "network_uuid": "98657fdf-11f4-4ee2-88a4-ce7fe73e33a6",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500
Packit Service a04d08
    }
Packit Service a04d08
]
Packit Service a04d08
""")
Packit Service a04d08
Packit Service a04d08
SDC_NICS_DHCP = json.loads("""
Packit Service a04d08
[
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net0",
Packit Service a04d08
        "mac": "90:b8:d0:ae:64:51",
Packit Service a04d08
        "vlan_id": 324,
Packit Service a04d08
        "nic_tag": "external",
Packit Service a04d08
        "gateway": "8.12.42.1",
Packit Service a04d08
        "gateways": [
Packit Service a04d08
          "8.12.42.1"
Packit Service a04d08
        ],
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "8.12.42.51",
Packit Service a04d08
        "ips": [
Packit Service a04d08
          "8.12.42.51/24"
Packit Service a04d08
        ],
Packit Service a04d08
        "network_uuid": "992fc7ce-6aac-4b74-aed6-7b9d2c6c0bfe",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500,
Packit Service a04d08
        "primary": true
Packit Service a04d08
    },
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net1",
Packit Service a04d08
        "mac": "90:b8:d0:bd:4f:9c",
Packit Service a04d08
        "vlan_id": 600,
Packit Service a04d08
        "nic_tag": "internal",
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "10.210.1.217",
Packit Service a04d08
        "ips": [
Packit Service a04d08
          "dhcp"
Packit Service a04d08
        ],
Packit Service a04d08
        "network_uuid": "98657fdf-11f4-4ee2-88a4-ce7fe73e33a6",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500
Packit Service a04d08
    }
Packit Service a04d08
]
Packit Service a04d08
""")
Packit Service a04d08
Packit Service a04d08
SDC_NICS_MIP = json.loads("""
Packit Service a04d08
[
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net0",
Packit Service a04d08
        "mac": "90:b8:d0:ae:64:51",
Packit Service a04d08
        "vlan_id": 324,
Packit Service a04d08
        "nic_tag": "external",
Packit Service a04d08
        "gateway": "8.12.42.1",
Packit Service a04d08
        "gateways": [
Packit Service a04d08
          "8.12.42.1"
Packit Service a04d08
        ],
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "8.12.42.51",
Packit Service a04d08
        "ips": [
Packit Service a04d08
          "8.12.42.51/24",
Packit Service a04d08
          "8.12.42.52/24"
Packit Service a04d08
        ],
Packit Service a04d08
        "network_uuid": "992fc7ce-6aac-4b74-aed6-7b9d2c6c0bfe",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500,
Packit Service a04d08
        "primary": true
Packit Service a04d08
    },
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net1",
Packit Service a04d08
        "mac": "90:b8:d0:bd:4f:9c",
Packit Service a04d08
        "vlan_id": 600,
Packit Service a04d08
        "nic_tag": "internal",
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "10.210.1.217",
Packit Service a04d08
        "ips": [
Packit Service a04d08
          "10.210.1.217/24",
Packit Service a04d08
          "10.210.1.151/24"
Packit Service a04d08
        ],
Packit Service a04d08
        "network_uuid": "98657fdf-11f4-4ee2-88a4-ce7fe73e33a6",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500
Packit Service a04d08
    }
Packit Service a04d08
]
Packit Service a04d08
""")
Packit Service a04d08
Packit Service a04d08
SDC_NICS_MIP_IPV6 = json.loads("""
Packit Service a04d08
[
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net0",
Packit Service a04d08
        "mac": "90:b8:d0:ae:64:51",
Packit Service a04d08
        "vlan_id": 324,
Packit Service a04d08
        "nic_tag": "external",
Packit Service a04d08
        "gateway": "8.12.42.1",
Packit Service a04d08
        "gateways": [
Packit Service a04d08
          "8.12.42.1"
Packit Service a04d08
        ],
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "8.12.42.51",
Packit Service a04d08
        "ips": [
Packit Service a04d08
          "2001:4800:78ff:1b:be76:4eff:fe06:96b3/64",
Packit Service a04d08
          "8.12.42.51/24"
Packit Service a04d08
        ],
Packit Service a04d08
        "network_uuid": "992fc7ce-6aac-4b74-aed6-7b9d2c6c0bfe",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500,
Packit Service a04d08
        "primary": true
Packit Service a04d08
    },
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net1",
Packit Service a04d08
        "mac": "90:b8:d0:bd:4f:9c",
Packit Service a04d08
        "vlan_id": 600,
Packit Service a04d08
        "nic_tag": "internal",
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "10.210.1.217",
Packit Service a04d08
        "ips": [
Packit Service a04d08
          "10.210.1.217/24"
Packit Service a04d08
        ],
Packit Service a04d08
        "network_uuid": "98657fdf-11f4-4ee2-88a4-ce7fe73e33a6",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500
Packit Service a04d08
    }
Packit Service a04d08
]
Packit Service a04d08
""")
Packit Service a04d08
Packit Service a04d08
SDC_NICS_IPV4_IPV6 = json.loads("""
Packit Service a04d08
[
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net0",
Packit Service a04d08
        "mac": "90:b8:d0:ae:64:51",
Packit Service a04d08
        "vlan_id": 324,
Packit Service a04d08
        "nic_tag": "external",
Packit Service a04d08
        "gateway": "8.12.42.1",
Packit Service a04d08
        "gateways": ["8.12.42.1", "2001::1", "2001::2"],
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "8.12.42.51",
Packit Service a04d08
        "ips": ["2001::10/64", "8.12.42.51/24", "2001::11/64",
Packit Service a04d08
                "8.12.42.52/32"],
Packit Service a04d08
        "network_uuid": "992fc7ce-6aac-4b74-aed6-7b9d2c6c0bfe",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500,
Packit Service a04d08
        "primary": true
Packit Service a04d08
    },
Packit Service a04d08
    {
Packit Service a04d08
        "interface": "net1",
Packit Service a04d08
        "mac": "90:b8:d0:bd:4f:9c",
Packit Service a04d08
        "vlan_id": 600,
Packit Service a04d08
        "nic_tag": "internal",
Packit Service a04d08
        "netmask": "255.255.255.0",
Packit Service a04d08
        "ip": "10.210.1.217",
Packit Service a04d08
        "ips": ["10.210.1.217/24"],
Packit Service a04d08
        "gateways": ["10.210.1.210"],
Packit Service a04d08
        "network_uuid": "98657fdf-11f4-4ee2-88a4-ce7fe73e33a6",
Packit Service a04d08
        "model": "virtio",
Packit Service a04d08
        "mtu": 1500
Packit Service a04d08
    }
Packit Service a04d08
]
Packit Service a04d08
""")
Packit Service a04d08
Packit Service a04d08
SDC_NICS_SINGLE_GATEWAY = json.loads("""
Packit Service a04d08
[
Packit Service a04d08
  {
Packit Service a04d08
    "interface":"net0",
Packit Service a04d08
    "mac":"90:b8:d0:d8:82:b4",
Packit Service a04d08
    "vlan_id":324,
Packit Service a04d08
    "nic_tag":"external",
Packit Service a04d08
    "gateway":"8.12.42.1",
Packit Service a04d08
    "gateways":["8.12.42.1"],
Packit Service a04d08
    "netmask":"255.255.255.0",
Packit Service a04d08
    "ip":"8.12.42.26",
Packit Service a04d08
    "ips":["8.12.42.26/24"],
Packit Service a04d08
    "network_uuid":"992fc7ce-6aac-4b74-aed6-7b9d2c6c0bfe",
Packit Service a04d08
    "model":"virtio",
Packit Service a04d08
    "mtu":1500,
Packit Service a04d08
    "primary":true
Packit Service a04d08
  },
Packit Service a04d08
  {
Packit Service a04d08
    "interface":"net1",
Packit Service a04d08
    "mac":"90:b8:d0:0a:51:31",
Packit Service a04d08
    "vlan_id":600,
Packit Service a04d08
    "nic_tag":"internal",
Packit Service a04d08
    "netmask":"255.255.255.0",
Packit Service a04d08
    "ip":"10.210.1.27",
Packit Service a04d08
    "ips":["10.210.1.27/24"],
Packit Service a04d08
    "network_uuid":"98657fdf-11f4-4ee2-88a4-ce7fe73e33a6",
Packit Service a04d08
    "model":"virtio",
Packit Service a04d08
    "mtu":1500
Packit Service a04d08
  }
Packit Service a04d08
]
Packit Service a04d08
""")
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
MOCK_RETURNS = {
Packit Service a04d08
    'hostname': 'test-host',
Packit Service a04d08
    'root_authorized_keys': 'ssh-rsa AAAAB3Nz...aC1yc2E= keyname',
Packit Service a04d08
    'disable_iptables_flag': None,
Packit Service a04d08
    'enable_motd_sys_info': None,
Packit Service a04d08
    'test-var1': 'some data',
Packit Service a04d08
    'cloud-init:user-data': '\n'.join(['#!/bin/sh', '/bin/true', '']),
Packit Service a04d08
    'sdc:datacenter_name': 'somewhere2',
Packit Service a04d08
    'sdc:operator-script': '\n'.join(['bin/true', '']),
Packit Service a04d08
    'sdc:uuid': str(uuid.uuid4()),
Packit Service a04d08
    'sdc:vendor-data': '\n'.join(['VENDOR_DATA', '']),
Packit Service a04d08
    'user-data': '\n'.join(['something', '']),
Packit Service a04d08
    'user-script': '\n'.join(['/bin/true', '']),
Packit Service a04d08
    'sdc:nics': json.dumps(SDC_NICS),
Packit Service a04d08
}
Packit Service a04d08
Packit Service a04d08
DMI_DATA_RETURN = 'smartdc'
Packit Service a04d08
Packit Service a04d08
# Useful for calculating the length of a frame body.  A SUCCESS body will be
Packit Service a04d08
# followed by more characters or be one character less if SUCCESS with no
Packit Service a04d08
# payload.  See Section 4.3 of https://eng.joyent.com/mdata/protocol.html.
Packit Service a04d08
SUCCESS_LEN = len('0123abcd SUCCESS ')
Packit Service a04d08
NOTFOUND_LEN = len('0123abcd NOTFOUND')
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class PsuedoJoyentClient(object):
Packit Service a04d08
    def __init__(self, data=None):
Packit Service a04d08
        if data is None:
Packit Service a04d08
            data = MOCK_RETURNS.copy()
Packit Service a04d08
        self.data = data
Packit Service a04d08
        self._is_open = False
Packit Service a04d08
        return
Packit Service a04d08
Packit Service a04d08
    def get(self, key, default=None, strip=False):
Packit Service a04d08
        if key in self.data:
Packit Service a04d08
            r = self.data[key]
Packit Service a04d08
            if strip:
Packit Service a04d08
                r = r.strip()
Packit Service a04d08
        else:
Packit Service a04d08
            r = default
Packit Service a04d08
        return r
Packit Service a04d08
Packit Service a04d08
    def get_json(self, key, default=None):
Packit Service a04d08
        result = self.get(key, default=default)
Packit Service a04d08
        if result is None:
Packit Service a04d08
            return default
Packit Service a04d08
        return json.loads(result)
Packit Service a04d08
Packit Service a04d08
    def exists(self):
Packit Service a04d08
        return True
Packit Service a04d08
Packit Service a04d08
    def open_transport(self):
Packit Service a04d08
        assert(not self._is_open)
Packit Service a04d08
        self._is_open = True
Packit Service a04d08
Packit Service a04d08
    def close_transport(self):
Packit Service a04d08
        assert(self._is_open)
Packit Service a04d08
        self._is_open = False
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestSmartOSDataSource(FilesystemMockingTestCase):
Packit Service a04d08
    jmc_cfact = None
Packit Service a04d08
    get_smartos_environ = None
Packit Service a04d08
Packit Service a04d08
    def setUp(self):
Packit Service a04d08
        super(TestSmartOSDataSource, self).setUp()
Packit Service a04d08
Packit Service a04d08
        self.add_patch(DSMOS + ".get_smartos_environ", "get_smartos_environ")
Packit Service a04d08
        self.add_patch(DSMOS + ".jmc_client_factory", "jmc_cfact")
Packit Service a04d08
        self.legacy_user_d = self.tmp_path('legacy_user_tmp')
Packit Service a04d08
        os.mkdir(self.legacy_user_d)
Packit Service a04d08
        self.add_patch(DSMOS + ".LEGACY_USER_D", "m_legacy_user_d",
Packit Service a04d08
                       autospec=False, new=self.legacy_user_d)
Packit Service a04d08
        self.add_patch(DSMOS + ".identify_file", "m_identify_file",
Packit Service a04d08
                       return_value="text/plain")
Packit Service a04d08
Packit Service a04d08
    def _get_ds(self, mockdata=None, mode=DataSourceSmartOS.SMARTOS_ENV_KVM,
Packit Service a04d08
                sys_cfg=None, ds_cfg=None):
Packit Service a04d08
        self.jmc_cfact.return_value = PsuedoJoyentClient(mockdata)
Packit Service a04d08
        self.get_smartos_environ.return_value = mode
Packit Service a04d08
Packit Service a04d08
        tmpd = self.tmp_dir()
Packit Service a04d08
        dirs = {'cloud_dir': self.tmp_path('cloud_dir', tmpd),
Packit Service a04d08
                'run_dir': self.tmp_path('run_dir')}
Packit Service a04d08
        for d in dirs.values():
Packit Service a04d08
            os.mkdir(d)
Packit Service a04d08
        paths = c_helpers.Paths(dirs)
Packit Service a04d08
Packit Service a04d08
        if sys_cfg is None:
Packit Service a04d08
            sys_cfg = {}
Packit Service a04d08
Packit Service a04d08
        if ds_cfg is not None:
Packit Service a04d08
            sys_cfg['datasource'] = sys_cfg.get('datasource', {})
Packit Service a04d08
            sys_cfg['datasource']['SmartOS'] = ds_cfg
Packit Service a04d08
Packit Service a04d08
        return DataSourceSmartOS.DataSourceSmartOS(
Packit Service a04d08
            sys_cfg, distro=None, paths=paths)
Packit Service a04d08
Packit Service a04d08
    def test_no_base64(self):
Packit Service a04d08
        ds_cfg = {'no_base64_decode': ['test_var1'], 'all_base': True}
Packit Service a04d08
        dsrc = self._get_ds(ds_cfg=ds_cfg)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
Packit Service a04d08
    def test_uuid(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['sdc:uuid'],
Packit Service a04d08
                         dsrc.metadata['instance-id'])
Packit Service a04d08
Packit Service a04d08
    def test_platform_info(self):
Packit Service a04d08
        """All platform-related attributes are properly set."""
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        self.assertEqual('joyent', dsrc.cloud_name)
Packit Service a04d08
        self.assertEqual('joyent', dsrc.platform_type)
Packit Service a04d08
        self.assertEqual('serial (/dev/ttyS1)', dsrc.subplatform)
Packit Service a04d08
Packit Service a04d08
    def test_root_keys(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['root_authorized_keys'],
Packit Service a04d08
                         dsrc.metadata['public-keys'])
Packit Service a04d08
Packit Service a04d08
    def test_hostname_b64(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['hostname'],
Packit Service a04d08
                         dsrc.metadata['local-hostname'])
Packit Service a04d08
Packit Service a04d08
    def test_hostname(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['hostname'],
Packit Service a04d08
                         dsrc.metadata['local-hostname'])
Packit Service a04d08
Packit Service a04d08
    def test_hostname_if_no_sdc_hostname(self):
Packit Service a04d08
        my_returns = MOCK_RETURNS.copy()
Packit Service a04d08
        my_returns['sdc:hostname'] = 'sdc-' + my_returns['hostname']
Packit Service a04d08
        dsrc = self._get_ds(mockdata=my_returns)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(my_returns['hostname'],
Packit Service a04d08
                         dsrc.metadata['local-hostname'])
Packit Service a04d08
Packit Service a04d08
    def test_sdc_hostname_if_no_hostname(self):
Packit Service a04d08
        my_returns = MOCK_RETURNS.copy()
Packit Service a04d08
        my_returns['sdc:hostname'] = 'sdc-' + my_returns['hostname']
Packit Service a04d08
        del my_returns['hostname']
Packit Service a04d08
        dsrc = self._get_ds(mockdata=my_returns)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(my_returns['sdc:hostname'],
Packit Service a04d08
                         dsrc.metadata['local-hostname'])
Packit Service a04d08
Packit Service a04d08
    def test_sdc_uuid_if_no_hostname_or_sdc_hostname(self):
Packit Service a04d08
        my_returns = MOCK_RETURNS.copy()
Packit Service a04d08
        del my_returns['hostname']
Packit Service a04d08
        dsrc = self._get_ds(mockdata=my_returns)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(my_returns['sdc:uuid'],
Packit Service a04d08
                         dsrc.metadata['local-hostname'])
Packit Service a04d08
Packit Service a04d08
    def test_userdata(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['user-data'],
Packit Service a04d08
                         dsrc.metadata['legacy-user-data'])
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['cloud-init:user-data'],
Packit Service a04d08
                         dsrc.userdata_raw)
Packit Service a04d08
Packit Service a04d08
    def test_sdc_nics(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(json.loads(MOCK_RETURNS['sdc:nics']),
Packit Service a04d08
                         dsrc.metadata['network-data'])
Packit Service a04d08
Packit Service a04d08
    def test_sdc_scripts(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['user-script'],
Packit Service a04d08
                         dsrc.metadata['user-script'])
Packit Service a04d08
Packit Service a04d08
        legacy_script_f = "%s/user-script" % self.legacy_user_d
Packit Service a04d08
        print("legacy_script_f=%s" % legacy_script_f)
Packit Service a04d08
        self.assertTrue(os.path.exists(legacy_script_f))
Packit Service a04d08
        self.assertTrue(os.path.islink(legacy_script_f))
Packit Service a04d08
        user_script_perm = oct(os.stat(legacy_script_f)[stat.ST_MODE])[-3:]
Packit Service a04d08
        self.assertEqual(user_script_perm, '700')
Packit Service a04d08
Packit Service a04d08
    def test_scripts_shebanged(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['user-script'],
Packit Service a04d08
                         dsrc.metadata['user-script'])
Packit Service a04d08
Packit Service a04d08
        legacy_script_f = "%s/user-script" % self.legacy_user_d
Packit Service a04d08
        self.assertTrue(os.path.exists(legacy_script_f))
Packit Service a04d08
        self.assertTrue(os.path.islink(legacy_script_f))
Packit Service a04d08
        shebang = None
Packit Service a04d08
        with open(legacy_script_f, 'r') as f:
Packit Service a04d08
            shebang = f.readlines()[0].strip()
Packit Service a04d08
        self.assertEqual(shebang, "#!/bin/bash")
Packit Service a04d08
        user_script_perm = oct(os.stat(legacy_script_f)[stat.ST_MODE])[-3:]
Packit Service a04d08
        self.assertEqual(user_script_perm, '700')
Packit Service a04d08
Packit Service a04d08
    def test_scripts_shebang_not_added(self):
Packit Service a04d08
        """
Packit Service a04d08
            Test that the SmartOS requirement that plain text scripts
Packit Service a04d08
            are executable. This test makes sure that plain texts scripts
Packit Service a04d08
            with out file magic have it added appropriately by cloud-init.
Packit Service a04d08
        """
Packit Service a04d08
Packit Service a04d08
        my_returns = MOCK_RETURNS.copy()
Packit Service a04d08
        my_returns['user-script'] = '\n'.join(['#!/usr/bin/perl',
Packit Service a04d08
                                               'print("hi")', ''])
Packit Service a04d08
Packit Service a04d08
        dsrc = self._get_ds(mockdata=my_returns)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(my_returns['user-script'],
Packit Service a04d08
                         dsrc.metadata['user-script'])
Packit Service a04d08
Packit Service a04d08
        legacy_script_f = "%s/user-script" % self.legacy_user_d
Packit Service a04d08
        self.assertTrue(os.path.exists(legacy_script_f))
Packit Service a04d08
        self.assertTrue(os.path.islink(legacy_script_f))
Packit Service a04d08
        shebang = None
Packit Service a04d08
        with open(legacy_script_f, 'r') as f:
Packit Service a04d08
            shebang = f.readlines()[0].strip()
Packit Service a04d08
        self.assertEqual(shebang, "#!/usr/bin/perl")
Packit Service a04d08
Packit Service a04d08
    def test_userdata_removed(self):
Packit Service a04d08
        """
Packit Service a04d08
            User-data in the SmartOS world is supposed to be written to a file
Packit Service a04d08
            each and every boot. This tests to make sure that in the event the
Packit Service a04d08
            legacy user-data is removed, the existing user-data is backed-up
Packit Service a04d08
            and there is no /var/db/user-data left.
Packit Service a04d08
        """
Packit Service a04d08
Packit Service a04d08
        user_data_f = "%s/mdata-user-data" % self.legacy_user_d
Packit Service a04d08
        with open(user_data_f, 'w') as f:
Packit Service a04d08
            f.write("PREVIOUS")
Packit Service a04d08
Packit Service a04d08
        my_returns = MOCK_RETURNS.copy()
Packit Service a04d08
        del my_returns['user-data']
Packit Service a04d08
Packit Service a04d08
        dsrc = self._get_ds(mockdata=my_returns)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertFalse(dsrc.metadata.get('legacy-user-data'))
Packit Service a04d08
Packit Service a04d08
        found_new = False
Packit Service a04d08
        for root, _dirs, files in os.walk(self.legacy_user_d):
Packit Service a04d08
            for name in files:
Packit Service a04d08
                name_f = os.path.join(root, name)
Packit Service a04d08
                permissions = oct(os.stat(name_f)[stat.ST_MODE])[-3:]
Packit Service a04d08
                if re.match(r'.*\/mdata-user-data$', name_f):
Packit Service a04d08
                    found_new = True
Packit Service a04d08
                    print(name_f)
Packit Service a04d08
                    self.assertEqual(permissions, '400')
Packit Service a04d08
Packit Service a04d08
        self.assertFalse(found_new)
Packit Service a04d08
Packit Service a04d08
    def test_vendor_data_not_default(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['sdc:vendor-data'],
Packit Service a04d08
                         dsrc.metadata['vendor-data'])
Packit Service a04d08
Packit Service a04d08
    def test_default_vendor_data(self):
Packit Service a04d08
        my_returns = MOCK_RETURNS.copy()
Packit Service a04d08
        def_op_script = my_returns['sdc:vendor-data']
Packit Service a04d08
        del my_returns['sdc:vendor-data']
Packit Service a04d08
        dsrc = self._get_ds(mockdata=my_returns)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertNotEqual(def_op_script, dsrc.metadata['vendor-data'])
Packit Service a04d08
Packit Service a04d08
        # we expect default vendor-data is a boothook
Packit Service a04d08
        self.assertTrue(dsrc.vendordata_raw.startswith("#cloud-boothook"))
Packit Service a04d08
Packit Service a04d08
    def test_disable_iptables_flag(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['disable_iptables_flag'],
Packit Service a04d08
                         dsrc.metadata['iptables_disable'])
Packit Service a04d08
Packit Service a04d08
    def test_motd_sys_info(self):
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(MOCK_RETURNS['enable_motd_sys_info'],
Packit Service a04d08
                         dsrc.metadata['motd_sys_info'])
Packit Service a04d08
Packit Service a04d08
    def test_default_ephemeral(self):
Packit Service a04d08
        # Test to make sure that the builtin config has the ephemeral
Packit Service a04d08
        # configuration.
Packit Service a04d08
        dsrc = self._get_ds()
Packit Service a04d08
        cfg = dsrc.get_config_obj()
Packit Service a04d08
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
Packit Service a04d08
        assert 'disk_setup' in cfg
Packit Service a04d08
        assert 'fs_setup' in cfg
Packit Service a04d08
        self.assertIsInstance(cfg['disk_setup'], dict)
Packit Service a04d08
        self.assertIsInstance(cfg['fs_setup'], list)
Packit Service a04d08
Packit Service a04d08
    def test_override_disk_aliases(self):
Packit Service a04d08
        # Test to make sure that the built-in DS is overriden
Packit Service a04d08
        builtin = DataSourceSmartOS.BUILTIN_DS_CONFIG
Packit Service a04d08
Packit Service a04d08
        mydscfg = {'disk_aliases': {'FOO': '/dev/bar'}}
Packit Service a04d08
Packit Service a04d08
        # expect that these values are in builtin, or this is pointless
Packit Service a04d08
        for k in mydscfg:
Packit Service a04d08
            self.assertIn(k, builtin)
Packit Service a04d08
Packit Service a04d08
        dsrc = self._get_ds(ds_cfg=mydscfg)
Packit Service a04d08
        ret = dsrc.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
Packit Service a04d08
        self.assertEqual(mydscfg['disk_aliases']['FOO'],
Packit Service a04d08
                         dsrc.ds_cfg['disk_aliases']['FOO'])
Packit Service a04d08
Packit Service a04d08
        self.assertEqual(dsrc.device_name_to_device('FOO'),
Packit Service a04d08
                         mydscfg['disk_aliases']['FOO'])
Packit Service a04d08
Packit Service a04d08
    def test_reconfig_network_on_boot(self):
Packit Service a04d08
        # Test to ensure that network is configured from metadata on each boot
Packit Service a04d08
        dsrc = self._get_ds(mockdata=MOCK_RETURNS)
Packit Service a04d08
        self.assertSetEqual(set([EventType.BOOT_NEW_INSTANCE, EventType.BOOT]),
Packit Service a04d08
                            dsrc.update_events['network'])
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestIdentifyFile(CiTestCase):
Packit Service a04d08
    """Test the 'identify_file' utility."""
Packit Service a04d08
    @skipIf(not which("file"), "command 'file' not available.")
Packit Service a04d08
    def test_file_happy_path(self):
Packit Service a04d08
        """Test file is available and functional on plain text."""
Packit Service a04d08
        fname = self.tmp_path("myfile")
Packit Service a04d08
        write_file(fname, "plain text content here\n")
Packit Service a04d08
        with self.allow_subp(["file"]):
Packit Service a04d08
            self.assertEqual("text/plain", identify_file(fname))
Packit Service a04d08
Packit Service 751c4a
    @mock.patch(DSMOS + ".subp.subp")
Packit Service a04d08
    def test_returns_none_on_error(self, m_subp):
Packit Service a04d08
        """On 'file' execution error, None should be returned."""
Packit Service a04d08
        m_subp.side_effect = ProcessExecutionError("FILE_FAILED", exit_code=99)
Packit Service a04d08
        fname = self.tmp_path("myfile")
Packit Service a04d08
        write_file(fname, "plain text content here\n")
Packit Service a04d08
        self.assertEqual(None, identify_file(fname))
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            [mock.call(["file", "--brief", "--mime-type", fname])],
Packit Service a04d08
            m_subp.call_args_list)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class ShortReader(object):
Packit Service a04d08
    """Implements a 'read' interface for bytes provided.
Packit Service a04d08
    much like io.BytesIO but the 'endbyte' acts as if EOF.
Packit Service a04d08
    When it is reached a short will be returned."""
Packit Service a04d08
    def __init__(self, initial_bytes, endbyte=b'\0'):
Packit Service a04d08
        self.data = initial_bytes
Packit Service a04d08
        self.index = 0
Packit Service a04d08
        self.len = len(self.data)
Packit Service a04d08
        self.endbyte = endbyte
Packit Service a04d08
Packit Service a04d08
    @property
Packit Service a04d08
    def emptied(self):
Packit Service a04d08
        return self.index >= self.len
Packit Service a04d08
Packit Service a04d08
    def read(self, size=-1):
Packit Service a04d08
        """Read size bytes but not past a null."""
Packit Service a04d08
        if size == 0 or self.index >= self.len:
Packit Service a04d08
            return b''
Packit Service a04d08
Packit Service a04d08
        rsize = size
Packit Service a04d08
        if size < 0 or size + self.index > self.len:
Packit Service a04d08
            rsize = self.len - self.index
Packit Service a04d08
Packit Service a04d08
        next_null = self.data.find(self.endbyte, self.index, rsize)
Packit Service a04d08
        if next_null >= 0:
Packit Service a04d08
            rsize = next_null - self.index + 1
Packit Service a04d08
        i = self.index
Packit Service a04d08
        self.index += rsize
Packit Service a04d08
        ret = self.data[i:i + rsize]
Packit Service a04d08
        if len(ret) and ret[-1:] == self.endbyte:
Packit Service a04d08
            ret = ret[:-1]
Packit Service a04d08
        return ret
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestJoyentMetadataClient(FilesystemMockingTestCase):
Packit Service a04d08
Packit Service a04d08
    invalid = b'invalid command\n'
Packit Service a04d08
    failure = b'FAILURE\n'
Packit Service a04d08
    v2_ok = b'V2_OK\n'
Packit Service a04d08
Packit Service a04d08
    def setUp(self):
Packit Service a04d08
        super(TestJoyentMetadataClient, self).setUp()
Packit Service a04d08
Packit Service a04d08
        self.serial = mock.MagicMock(spec=serial.Serial)
Packit Service a04d08
        self.request_id = 0xabcdef12
Packit Service a04d08
        self.metadata_value = 'value'
Packit Service a04d08
        self.response_parts = {
Packit Service a04d08
            'command': 'SUCCESS',
Packit Service a04d08
            'crc': 'b5a9ff00',
Packit Service a04d08
            'length': SUCCESS_LEN + len(b64e(self.metadata_value)),
Packit Service a04d08
            'payload': b64e(self.metadata_value),
Packit Service a04d08
            'request_id': '{0:08x}'.format(self.request_id),
Packit Service a04d08
        }
Packit Service a04d08
Packit Service a04d08
        def make_response():
Packit Service a04d08
            payloadstr = ''
Packit Service a04d08
            if 'payload' in self.response_parts:
Packit Service a04d08
                payloadstr = ' {0}'.format(self.response_parts['payload'])
Packit Service a04d08
            return ('V2 {length} {crc} {request_id} '
Packit Service a04d08
                    '{command}{payloadstr}\n'.format(
Packit Service a04d08
                        payloadstr=payloadstr,
Packit Service a04d08
                        **self.response_parts).encode('ascii'))
Packit Service a04d08
Packit Service a04d08
        self.metasource_data = None
Packit Service a04d08
Packit Service a04d08
        def read_response(length):
Packit Service a04d08
            if not self.metasource_data:
Packit Service a04d08
                self.metasource_data = make_response()
Packit Service a04d08
                self.metasource_data_len = len(self.metasource_data)
Packit Service a04d08
            resp = self.metasource_data[:length]
Packit Service a04d08
            self.metasource_data = self.metasource_data[length:]
Packit Service a04d08
            return resp
Packit Service a04d08
Packit Service a04d08
        self.serial.read.side_effect = read_response
Packit Service a04d08
        self.patched_funcs.enter_context(
Packit Service a04d08
            mock.patch('cloudinit.sources.DataSourceSmartOS.random.randint',
Packit Service a04d08
                       mock.Mock(return_value=self.request_id)))
Packit Service a04d08
Packit Service a04d08
    def _get_client(self):
Packit Service a04d08
        return DataSourceSmartOS.JoyentMetadataClient(
Packit Service a04d08
            fp=self.serial, smartos_type=DataSourceSmartOS.SMARTOS_ENV_KVM)
Packit Service a04d08
Packit Service a04d08
    def _get_serial_client(self):
Packit Service a04d08
        self.serial.timeout = 1
Packit Service a04d08
        return DataSourceSmartOS.JoyentMetadataSerialClient(None,
Packit Service a04d08
                                                            fp=self.serial)
Packit Service a04d08
Packit Service a04d08
    def assertEndsWith(self, haystack, prefix):
Packit Service a04d08
        self.assertTrue(haystack.endswith(prefix),
Packit Service a04d08
                        "{0} does not end with '{1}'".format(
Packit Service a04d08
                            repr(haystack), prefix))
Packit Service a04d08
Packit Service a04d08
    def assertStartsWith(self, haystack, prefix):
Packit Service a04d08
        self.assertTrue(haystack.startswith(prefix),
Packit Service a04d08
                        "{0} does not start with '{1}'".format(
Packit Service a04d08
                            repr(haystack), prefix))
Packit Service a04d08
Packit Service a04d08
    def assertNoMoreSideEffects(self, obj):
Packit Service a04d08
        self.assertRaises(StopIteration, obj)
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_writes_a_single_line(self):
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        client.get('some_key')
Packit Service a04d08
        self.assertEqual(1, self.serial.write.call_count)
Packit Service a04d08
        written_line = self.serial.write.call_args[0][0]
Packit Service a04d08
        self.assertEndsWith(written_line.decode('ascii'),
Packit Service a04d08
                            b'\n'.decode('ascii'))
Packit Service a04d08
        self.assertEqual(1, written_line.count(b'\n'))
Packit Service a04d08
Packit Service a04d08
    def _get_written_line(self, key='some_key'):
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        client.get(key)
Packit Service a04d08
        return self.serial.write.call_args[0][0]
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_writes_bytes(self):
Packit Service 751c4a
        self.assertIsInstance(self._get_written_line(), bytes)
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_line_starts_with_v2(self):
Packit Service a04d08
        foo = self._get_written_line()
Packit Service a04d08
        self.assertStartsWith(foo.decode('ascii'), b'V2'.decode('ascii'))
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_uses_get_command(self):
Packit Service a04d08
        parts = self._get_written_line().decode('ascii').strip().split(' ')
Packit Service a04d08
        self.assertEqual('GET', parts[4])
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_base64_encodes_argument(self):
Packit Service a04d08
        key = 'my_key'
Packit Service a04d08
        parts = self._get_written_line(key).decode('ascii').strip().split(' ')
Packit Service a04d08
        self.assertEqual(b64e(key), parts[5])
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_calculates_length_correctly(self):
Packit Service a04d08
        parts = self._get_written_line().decode('ascii').strip().split(' ')
Packit Service a04d08
        expected_length = len(' '.join(parts[3:]))
Packit Service a04d08
        self.assertEqual(expected_length, int(parts[1]))
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_uses_appropriate_request_id(self):
Packit Service a04d08
        parts = self._get_written_line().decode('ascii').strip().split(' ')
Packit Service a04d08
        request_id = parts[3]
Packit Service a04d08
        self.assertEqual(8, len(request_id))
Packit Service a04d08
        self.assertEqual(request_id, request_id.lower())
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_uses_random_number_for_request_id(self):
Packit Service a04d08
        line = self._get_written_line()
Packit Service a04d08
        request_id = line.decode('ascii').strip().split(' ')[3]
Packit Service a04d08
        self.assertEqual('{0:08x}'.format(self.request_id), request_id)
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_checksums_correctly(self):
Packit Service a04d08
        parts = self._get_written_line().decode('ascii').strip().split(' ')
Packit Service a04d08
        expected_checksum = '{0:08x}'.format(
Packit Service a04d08
            crc32(' '.join(parts[3:]).encode('utf-8')) & 0xffffffff)
Packit Service a04d08
        checksum = parts[2]
Packit Service a04d08
        self.assertEqual(expected_checksum, checksum)
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_reads_a_line(self):
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        client.get('some_key')
Packit Service a04d08
        self.assertEqual(self.metasource_data_len, self.serial.read.call_count)
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_returns_valid_value(self):
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        value = client.get('some_key')
Packit Service a04d08
        self.assertEqual(self.metadata_value, value)
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_throws_exception_for_incorrect_length(self):
Packit Service a04d08
        self.response_parts['length'] = 0
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        self.assertRaises(DataSourceSmartOS.JoyentMetadataFetchException,
Packit Service a04d08
                          client.get, 'some_key')
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_throws_exception_for_incorrect_crc(self):
Packit Service a04d08
        self.response_parts['crc'] = 'deadbeef'
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        self.assertRaises(DataSourceSmartOS.JoyentMetadataFetchException,
Packit Service a04d08
                          client.get, 'some_key')
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_throws_exception_for_request_id_mismatch(self):
Packit Service a04d08
        self.response_parts['request_id'] = 'deadbeef'
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        client._checksum = lambda _: self.response_parts['crc']
Packit Service a04d08
        self.assertRaises(DataSourceSmartOS.JoyentMetadataFetchException,
Packit Service a04d08
                          client.get, 'some_key')
Packit Service a04d08
Packit Service a04d08
    def test_get_metadata_returns_None_if_value_not_found(self):
Packit Service a04d08
        self.response_parts['payload'] = ''
Packit Service a04d08
        self.response_parts['command'] = 'NOTFOUND'
Packit Service a04d08
        self.response_parts['length'] = NOTFOUND_LEN
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        client._checksum = lambda _: self.response_parts['crc']
Packit Service a04d08
        self.assertIsNone(client.get('some_key'))
Packit Service a04d08
Packit Service a04d08
    def test_negotiate(self):
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        reader = ShortReader(self.v2_ok)
Packit Service a04d08
        client.fp.read.side_effect = reader.read
Packit Service a04d08
        client._negotiate()
Packit Service a04d08
        self.assertTrue(reader.emptied)
Packit Service a04d08
Packit Service a04d08
    def test_negotiate_short_response(self):
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        # chopped '\n' from v2_ok.
Packit Service a04d08
        reader = ShortReader(self.v2_ok[:-1] + b'\0')
Packit Service a04d08
        client.fp.read.side_effect = reader.read
Packit Service a04d08
        self.assertRaises(DataSourceSmartOS.JoyentMetadataTimeoutException,
Packit Service a04d08
                          client._negotiate)
Packit Service a04d08
        self.assertTrue(reader.emptied)
Packit Service a04d08
Packit Service a04d08
    def test_negotiate_bad_response(self):
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        reader = ShortReader(b'garbage\n' + self.v2_ok)
Packit Service a04d08
        client.fp.read.side_effect = reader.read
Packit Service a04d08
        self.assertRaises(DataSourceSmartOS.JoyentMetadataFetchException,
Packit Service a04d08
                          client._negotiate)
Packit Service a04d08
        self.assertEqual(self.v2_ok, client.fp.read())
Packit Service a04d08
Packit Service a04d08
    def test_serial_open_transport(self):
Packit Service a04d08
        client = self._get_serial_client()
Packit Service a04d08
        reader = ShortReader(b'garbage\0' + self.invalid + self.v2_ok)
Packit Service a04d08
        client.fp.read.side_effect = reader.read
Packit Service a04d08
        client.open_transport()
Packit Service a04d08
        self.assertTrue(reader.emptied)
Packit Service a04d08
Packit Service a04d08
    def test_flush_failure(self):
Packit Service a04d08
        client = self._get_serial_client()
Packit Service a04d08
        reader = ShortReader(b'garbage' + b'\0' + self.failure +
Packit Service a04d08
                             self.invalid + self.v2_ok)
Packit Service a04d08
        client.fp.read.side_effect = reader.read
Packit Service a04d08
        client.open_transport()
Packit Service a04d08
        self.assertTrue(reader.emptied)
Packit Service a04d08
Packit Service a04d08
    def test_flush_many_timeouts(self):
Packit Service a04d08
        client = self._get_serial_client()
Packit Service a04d08
        reader = ShortReader(b'\0' * 100 + self.invalid + self.v2_ok)
Packit Service a04d08
        client.fp.read.side_effect = reader.read
Packit Service a04d08
        client.open_transport()
Packit Service a04d08
        self.assertTrue(reader.emptied)
Packit Service a04d08
Packit Service a04d08
    def test_list_metadata_returns_list(self):
Packit Service a04d08
        parts = ['foo', 'bar']
Packit Service a04d08
        value = b64e('\n'.join(parts))
Packit Service a04d08
        self.response_parts['payload'] = value
Packit Service a04d08
        self.response_parts['crc'] = '40873553'
Packit Service a04d08
        self.response_parts['length'] = SUCCESS_LEN + len(value)
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        self.assertEqual(client.list(), parts)
Packit Service a04d08
Packit Service a04d08
    def test_list_metadata_returns_empty_list_if_no_customer_metadata(self):
Packit Service a04d08
        del self.response_parts['payload']
Packit Service a04d08
        self.response_parts['length'] = SUCCESS_LEN - 1
Packit Service a04d08
        self.response_parts['crc'] = '14e563ba'
Packit Service a04d08
        client = self._get_client()
Packit Service a04d08
        self.assertEqual(client.list(), [])
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestNetworkConversion(CiTestCase):
Packit Service a04d08
    def test_convert_simple(self):
Packit Service a04d08
        expected = {
Packit Service a04d08
            'version': 1,
Packit Service a04d08
            'config': [
Packit Service a04d08
                {'name': 'net0', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static', 'gateway': '8.12.42.1',
Packit Service a04d08
                              'address': '8.12.42.102/24'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:f5:e4:f5'},
Packit Service a04d08
                {'name': 'net1', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static',
Packit Service a04d08
                              'address': '192.168.128.93/22'}],
Packit Service a04d08
                 'mtu': 8500, 'mac_address': '90:b8:d0:a5:ff:cd'}]}
Packit Service a04d08
        found = convert_net(SDC_NICS)
Packit Service a04d08
        self.assertEqual(expected, found)
Packit Service a04d08
Packit Service a04d08
    def test_convert_simple_alt(self):
Packit Service a04d08
        expected = {
Packit Service a04d08
            'version': 1,
Packit Service a04d08
            'config': [
Packit Service a04d08
                {'name': 'net0', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static', 'gateway': '8.12.42.1',
Packit Service a04d08
                              'address': '8.12.42.51/24'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:ae:64:51'},
Packit Service a04d08
                {'name': 'net1', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static',
Packit Service a04d08
                              'address': '10.210.1.217/24'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:bd:4f:9c'}]}
Packit Service a04d08
        found = convert_net(SDC_NICS_ALT)
Packit Service a04d08
        self.assertEqual(expected, found)
Packit Service a04d08
Packit Service a04d08
    def test_convert_simple_dhcp(self):
Packit Service a04d08
        expected = {
Packit Service a04d08
            'version': 1,
Packit Service a04d08
            'config': [
Packit Service a04d08
                {'name': 'net0', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static', 'gateway': '8.12.42.1',
Packit Service a04d08
                              'address': '8.12.42.51/24'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:ae:64:51'},
Packit Service a04d08
                {'name': 'net1', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'dhcp4'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:bd:4f:9c'}]}
Packit Service a04d08
        found = convert_net(SDC_NICS_DHCP)
Packit Service a04d08
        self.assertEqual(expected, found)
Packit Service a04d08
Packit Service a04d08
    def test_convert_simple_multi_ip(self):
Packit Service a04d08
        expected = {
Packit Service a04d08
            'version': 1,
Packit Service a04d08
            'config': [
Packit Service a04d08
                {'name': 'net0', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static', 'gateway': '8.12.42.1',
Packit Service a04d08
                              'address': '8.12.42.51/24'},
Packit Service a04d08
                             {'type': 'static',
Packit Service a04d08
                              'address': '8.12.42.52/24'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:ae:64:51'},
Packit Service a04d08
                {'name': 'net1', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static',
Packit Service a04d08
                              'address': '10.210.1.217/24'},
Packit Service a04d08
                             {'type': 'static',
Packit Service a04d08
                              'address': '10.210.1.151/24'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:bd:4f:9c'}]}
Packit Service a04d08
        found = convert_net(SDC_NICS_MIP)
Packit Service a04d08
        self.assertEqual(expected, found)
Packit Service a04d08
Packit Service a04d08
    def test_convert_with_dns(self):
Packit Service a04d08
        expected = {
Packit Service a04d08
            'version': 1,
Packit Service a04d08
            'config': [
Packit Service a04d08
                {'name': 'net0', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static', 'gateway': '8.12.42.1',
Packit Service a04d08
                              'address': '8.12.42.51/24'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:ae:64:51'},
Packit Service a04d08
                {'name': 'net1', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'dhcp4'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:bd:4f:9c'},
Packit Service a04d08
                {'type': 'nameserver',
Packit Service a04d08
                 'address': ['8.8.8.8', '8.8.8.1'], 'search': ["local"]}]}
Packit Service a04d08
        found = convert_net(
Packit Service a04d08
            network_data=SDC_NICS_DHCP, dns_servers=['8.8.8.8', '8.8.8.1'],
Packit Service a04d08
            dns_domain="local")
Packit Service a04d08
        self.assertEqual(expected, found)
Packit Service a04d08
Packit Service a04d08
    def test_convert_simple_multi_ipv6(self):
Packit Service a04d08
        expected = {
Packit Service a04d08
            'version': 1,
Packit Service a04d08
            'config': [
Packit Service a04d08
                {'name': 'net0', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static', 'address':
Packit Service a04d08
                              '2001:4800:78ff:1b:be76:4eff:fe06:96b3/64'},
Packit Service a04d08
                             {'type': 'static', 'gateway': '8.12.42.1',
Packit Service a04d08
                              'address': '8.12.42.51/24'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:ae:64:51'},
Packit Service a04d08
                {'name': 'net1', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'type': 'static',
Packit Service a04d08
                              'address': '10.210.1.217/24'}],
Packit Service a04d08
                 'mtu': 1500, 'mac_address': '90:b8:d0:bd:4f:9c'}]}
Packit Service a04d08
        found = convert_net(SDC_NICS_MIP_IPV6)
Packit Service a04d08
        self.assertEqual(expected, found)
Packit Service a04d08
Packit Service a04d08
    def test_convert_simple_both_ipv4_ipv6(self):
Packit Service a04d08
        expected = {
Packit Service a04d08
            'version': 1,
Packit Service a04d08
            'config': [
Packit Service a04d08
                {'mac_address': '90:b8:d0:ae:64:51', 'mtu': 1500,
Packit Service a04d08
                 'name': 'net0', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'address': '2001::10/64', 'gateway': '2001::1',
Packit Service a04d08
                              'type': 'static'},
Packit Service a04d08
                             {'address': '8.12.42.51/24',
Packit Service a04d08
                              'gateway': '8.12.42.1',
Packit Service a04d08
                              'type': 'static'},
Packit Service a04d08
                             {'address': '2001::11/64', 'type': 'static'},
Packit Service a04d08
                             {'address': '8.12.42.52/32', 'type': 'static'}]},
Packit Service a04d08
                {'mac_address': '90:b8:d0:bd:4f:9c', 'mtu': 1500,
Packit Service a04d08
                 'name': 'net1', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'address': '10.210.1.217/24',
Packit Service a04d08
                              'type': 'static'}]}]}
Packit Service a04d08
        found = convert_net(SDC_NICS_IPV4_IPV6)
Packit Service a04d08
        self.assertEqual(expected, found)
Packit Service a04d08
Packit Service a04d08
    def test_gateways_not_on_all_nics(self):
Packit Service a04d08
        expected = {
Packit Service a04d08
            'version': 1,
Packit Service a04d08
            'config': [
Packit Service a04d08
                {'mac_address': '90:b8:d0:d8:82:b4', 'mtu': 1500,
Packit Service a04d08
                 'name': 'net0', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'address': '8.12.42.26/24',
Packit Service a04d08
                              'gateway': '8.12.42.1', 'type': 'static'}]},
Packit Service a04d08
                {'mac_address': '90:b8:d0:0a:51:31', 'mtu': 1500,
Packit Service a04d08
                 'name': 'net1', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'address': '10.210.1.27/24',
Packit Service a04d08
                              'type': 'static'}]}]}
Packit Service a04d08
        found = convert_net(SDC_NICS_SINGLE_GATEWAY)
Packit Service a04d08
        self.assertEqual(expected, found)
Packit Service a04d08
Packit Service a04d08
    def test_routes_on_all_nics(self):
Packit Service a04d08
        routes = [
Packit Service a04d08
            {'linklocal': False, 'dst': '3.0.0.0/8', 'gateway': '8.12.42.3'},
Packit Service a04d08
            {'linklocal': False, 'dst': '4.0.0.0/8', 'gateway': '10.210.1.4'}]
Packit Service a04d08
        expected = {
Packit Service a04d08
            'version': 1,
Packit Service a04d08
            'config': [
Packit Service a04d08
                {'mac_address': '90:b8:d0:d8:82:b4', 'mtu': 1500,
Packit Service a04d08
                 'name': 'net0', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'address': '8.12.42.26/24',
Packit Service a04d08
                              'gateway': '8.12.42.1', 'type': 'static',
Packit Service a04d08
                              'routes': [{'network': '3.0.0.0/8',
Packit Service a04d08
                                          'gateway': '8.12.42.3'},
Packit Service a04d08
                                         {'network': '4.0.0.0/8',
Packit Service a04d08
                                         'gateway': '10.210.1.4'}]}]},
Packit Service a04d08
                {'mac_address': '90:b8:d0:0a:51:31', 'mtu': 1500,
Packit Service a04d08
                 'name': 'net1', 'type': 'physical',
Packit Service a04d08
                 'subnets': [{'address': '10.210.1.27/24', 'type': 'static',
Packit Service a04d08
                              'routes': [{'network': '3.0.0.0/8',
Packit Service a04d08
                                          'gateway': '8.12.42.3'},
Packit Service a04d08
                                         {'network': '4.0.0.0/8',
Packit Service a04d08
                                         'gateway': '10.210.1.4'}]}]}]}
Packit Service a04d08
        found = convert_net(SDC_NICS_SINGLE_GATEWAY, routes=routes)
Packit Service a04d08
        self.maxDiff = None
Packit Service a04d08
        self.assertEqual(expected, found)
Packit Service a04d08
Packit Service a04d08
Packit Service 751c4a
@unittest.skipUnless(get_smartos_environ() == SMARTOS_ENV_KVM,
Packit Service 751c4a
                     "Only supported on KVM and bhyve guests under SmartOS")
Packit Service 751c4a
@unittest.skipUnless(os.access(SERIAL_DEVICE, os.W_OK),
Packit Service 751c4a
                     "Requires write access to " + SERIAL_DEVICE)
Packit Service 751c4a
@unittest.skipUnless(HAS_PYSERIAL is True, "pyserial not available")
Packit Service a04d08
class TestSerialConcurrency(CiTestCase):
Packit Service a04d08
    """
Packit Service a04d08
       This class tests locking on an actual serial port, and as such can only
Packit Service a04d08
       be run in a kvm or bhyve guest running on a SmartOS host.  A test run on
Packit Service a04d08
       a metadata socket will not be valid because a metadata socket ensures
Packit Service a04d08
       there is only one session over a connection.  In contrast, in the
Packit Service a04d08
       absence of proper locking multiple processes opening the same serial
Packit Service a04d08
       port can corrupt each others' exchanges with the metadata server.
Packit Service a04d08
Packit Service a04d08
       This takes on the order of 2 to 3 minutes to run.
Packit Service a04d08
    """
Packit Service a04d08
    allowed_subp = ['mdata-get']
Packit Service a04d08
Packit Service a04d08
    def setUp(self):
Packit Service a04d08
        self.mdata_proc = multiprocessing.Process(target=self.start_mdata_loop)
Packit Service a04d08
        self.mdata_proc.start()
Packit Service a04d08
        super(TestSerialConcurrency, self).setUp()
Packit Service a04d08
Packit Service a04d08
    def tearDown(self):
Packit Service a04d08
        # os.kill() rather than mdata_proc.terminate() to avoid console spam.
Packit Service a04d08
        os.kill(self.mdata_proc.pid, signal.SIGKILL)
Packit Service a04d08
        self.mdata_proc.join()
Packit Service a04d08
        super(TestSerialConcurrency, self).tearDown()
Packit Service a04d08
Packit Service a04d08
    def start_mdata_loop(self):
Packit Service a04d08
        """
Packit Service a04d08
           The mdata-get command is repeatedly run in a separate process so
Packit Service a04d08
           that it may try to race with metadata operations performed in the
Packit Service a04d08
           main test process.  Use of mdata-get is better than two processes
Packit Service a04d08
           using the protocol implementation in DataSourceSmartOS because we
Packit Service a04d08
           are testing to be sure that cloud-init and mdata-get respect each
Packit Service a04d08
           others locks.
Packit Service a04d08
        """
Packit Service a04d08
        rcs = list(range(0, 256))
Packit Service a04d08
        while True:
Packit Service a04d08
            subp(['mdata-get', 'sdc:routes'], rcs=rcs)
Packit Service a04d08
Packit Service a04d08
    def test_all_keys(self):
Packit Service a04d08
        self.assertIsNotNone(self.mdata_proc.pid)
Packit Service a04d08
        ds = DataSourceSmartOS
Packit Service a04d08
        keys = [tup[0] for tup in ds.SMARTOS_ATTRIB_MAP.values()]
Packit Service a04d08
        keys.extend(ds.SMARTOS_ATTRIB_JSON.values())
Packit Service a04d08
Packit Service a04d08
        client = ds.jmc_client_factory(smartos_type=SMARTOS_ENV_KVM)
Packit Service a04d08
        self.assertIsNotNone(client)
Packit Service a04d08
Packit Service a04d08
        # The behavior that we are testing for was observed mdata-get running
Packit Service a04d08
        # 10 times at roughly the same time as cloud-init fetched each key
Packit Service a04d08
        # once.  cloud-init would regularly see failures before making it
Packit Service a04d08
        # through all keys once.
Packit Service a04d08
        for _ in range(0, 3):
Packit Service a04d08
            for key in keys:
Packit Service a04d08
                # We don't care about the return value, just that it doesn't
Packit Service a04d08
                # thrown any exceptions.
Packit Service a04d08
                client.get(key)
Packit Service a04d08
Packit Service a04d08
        self.assertIsNone(self.mdata_proc.exitcode)
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab