示例#1
0
 def __init__(self, common):
     root = '/'
     if common['opts'].dry_run:
         root = os.path.abspath(".subiquity")
     self.locale = LocaleModel(common['signal'])
     self.keyboard = KeyboardModel(root)
     self.network = NetworkModel()
     self.filesystem = FilesystemModel(common['prober'])
     self.identity = IdentityModel()
示例#2
0
 def __init__(self, common):
     root = '/'
     if common['opts'].dry_run:
         root = os.path.abspath(".subiquity")
     self.locale = LocaleModel(common['signal'])
     self.keyboard = KeyboardModel(root)
     self.installpath = InstallpathModel()
     self.network = NetworkModel(support_wlan=False)
     self.filesystem = FilesystemModel(common['prober'])
     self.identity = IdentityModel()
     self.proxy = ProxyModel()
     self.snaplist = SnapListModel()
示例#3
0
 def __init__(self, common):
     self.root = '/'
     self.opts = common['opts']
     if self.opts.dry_run:
         self.root = os.path.abspath(".subiquity")
         self.target = self.root
     self.locale = LocaleModel(common['signal'])
     self.keyboard = KeyboardModel(self.root)
     self.installpath = InstallpathModel(target=self.target,
                                         sources=common['opts'].sources)
     self.network = NetworkModel(support_wlan=False)
     self.filesystem = FilesystemModel(common['prober'])
     self.identity = IdentityModel()
     self.proxy = ProxyModel()
     self.mirror = MirrorModel()
     self.snaplist = SnapListModel()
     self.ssh = SSHModel()
示例#4
0
    def __init__(self, root, sources=()):
        self.root = root
        if root != '/':
            self.target = root

        self.locale = LocaleModel()
        self.keyboard = KeyboardModel(self.root)
        self.network = NetworkModel(support_wlan=False)
        self.proxy = ProxyModel()
        self.mirror = MirrorModel()
        self.filesystem = FilesystemModel()

        # Collect the models that produce data for the curtin config.
        self._install_models = [
            self.keyboard,
            self.network,
            self.proxy,
            self.mirror,
            self.filesystem,
            ]

        self.identity = IdentityModel()
        self.ssh = SSHModel()
        self.snaplist = SnapListModel()
示例#5
0
    def __init__(self, root, sources=()):
        self.root = root
        if root != '/':
            self.target = root

        self.locale = LocaleModel()
        self.keyboard = KeyboardModel(self.root)
        self.network = NetworkModel(support_wlan=False)
        self.proxy = ProxyModel()
        self.mirror = MirrorModel()
        self.filesystem = FilesystemModel()
        self.identity = IdentityModel()
        self.ssh = SSHModel()
        self.snaplist = SnapListModel()

        self._events = {name: asyncio.Event() for name in ALL_MODEL_NAMES}
        self.install_events = {
            self._events[name]
            for name in INSTALL_MODEL_NAMES
        }
        self.postinstall_events = {
            self._events[name]
            for name in POSTINSTALL_MODEL_NAMES
        }
示例#6
0
class SubiquityModel:
    """The overall model for subiquity."""

    def __init__(self, common):
        root = '/'
        if common['opts'].dry_run:
            root = os.path.abspath(".subiquity")
        self.locale = LocaleModel(common['signal'])
        self.keyboard = KeyboardModel(root)
        self.installpath = InstallpathModel()
        self.network = NetworkModel(support_wlan=False)
        self.filesystem = FilesystemModel(common['prober'])
        self.identity = IdentityModel()
        self.proxy = ProxyModel()

    def _cloud_init_config(self):
        user = self.identity.user
        users_and_groups_path = os.path.join(os.environ.get("SNAP", "/does-not-exist"), "users-and-groups")
        if os.path.exists(users_and_groups_path):
            groups = open(users_and_groups_path).read().split()
        else:
            groups = ['admin']
        groups.append('sudo')
        user_info = {
            'name': user.username,
            'gecos': user.realname,
            'passwd': user.password,
            'shell': '/bin/bash',
            'groups': groups,
            'lock-passwd': False,
            }
        if user.ssh_import_id is not None:
            user_info['ssh_import_id'] = [user.ssh_import_id]
        config = {
            'growpart': {
                'mode': 'off',
                },
            'hostname': self.identity.hostname,
            'locale': self.locale.selected_language + '.UTF-8',
            'resize_rootfs': False,
            'users': [user_info],
        }
        return config

    def _cloud_init_files(self):
        # TODO, this should be moved to the in-target cloud-config seed so on first
        # boot of the target, it reconfigures datasource_list to none for subsequent
        # boots.
        # (mwhudson does not entirely know what the above means!)
        userdata = '#cloud-config\n' + yaml.dump(self._cloud_init_config())
        metadata = yaml.dump({'instance-id': str(uuid.uuid4())})
        return [
            ('var/lib/cloud/seed/nocloud-net/meta-data', metadata),
            ('var/lib/cloud/seed/nocloud-net/user-data', userdata),
            ('etc/cloud/ds-identify.cfg', 'policy: enabled\n'),
            ]

    def configure_cloud_init(self, target):
        for path, content in self._cloud_init_files():
            path = os.path.join(target, path)
            os.makedirs(os.path.dirname(path), exist_ok=True)
            with open(path, 'w') as fp:
                fp.write(content)

    def render(self, target, syslog_identifier):
        config = {
            'install': {
                'target': target,
                'unmount': 'disabled',
                'save_install_config': '/var/log/installer/curtin-install-cfg.yaml',
                'save_install_log': '/var/log/installer/curtin-install.log',
                },

            'sources': {
                'rofs': 'cp://%s' % self.installpath.source,
                },

            'verbosity': 3,

            'partitioning_commands': {
                'builtin': 'curtin block-meta custom',
                },

            'pollinate': {
                'user_agent': {
                    'subiquity': "%s_%s"%(os.environ.get("SNAP_VERSION", 'dry-run'), os.environ.get("SNAP_REVISION", 'dry-run')),
                    },
                },

            'reporting': {
                'subiquity': {
                    'type': 'journald',
                    'identifier': syslog_identifier,
                    },
                },

            'storage': {
                'version': 1,
                'config': self.filesystem.render(),
                },

            'write_files': {
                'etc_default_keyboard': {
                    'path': 'etc/default/keyboard',
                    'content': self.keyboard.setting.render(),
                    },
                },
            }

        if self.proxy.proxy != "":
            config['proxy'] = {
                'http_proxy': self.proxy.proxy,
                'https_proxy': self.proxy.proxy,
                }

        if not self.filesystem.add_swapfile():
            config['swap'] = {'size': 0}

        config.update(self.network.render())
        config.update(self.installpath.render())

        return config
示例#7
0
 def __init__(self, common):
     self.network = NetworkModel(support_wlan=True)
     self.identity = IdentityModel()
示例#8
0
class SubiquityModel:
    """The overall model for subiquity."""

    target = '/target'

    def __init__(self, common):
        root = '/'
        self.opts = common['opts']
        if self.opts.dry_run:
            root = os.path.abspath(".subiquity")
            self.target = root
        self.locale = LocaleModel(common['signal'])
        self.keyboard = KeyboardModel(root)
        self.installpath = InstallpathModel(target=self.target,
                                            sources=common['opts'].sources)
        self.network = NetworkModel(support_wlan=False)
        self.filesystem = FilesystemModel(common['prober'])
        self.identity = IdentityModel()
        self.proxy = ProxyModel()
        self.mirror = MirrorModel()
        self.snaplist = SnapListModel()

    def get_target_groups(self):
        command = ['chroot', self.target, 'getent', 'group']
        if self.opts.dry_run:
            del command[:2]
        cp = run_command(command, check=True)
        groups = set()
        for line in cp.stdout.splitlines():
            groups.add(line.split(':')[0])
        return groups

    def _cloud_init_config(self):
        user = self.identity.user
        users_and_groups_path = (os.path.join(os.environ.get("SNAP", "."),
                                              "users-and-groups"))
        if os.path.exists(users_and_groups_path):
            groups = open(users_and_groups_path).read().split()
        else:
            groups = ['admin']
        groups.append('sudo')
        groups = [
            group for group in groups if group in self.get_target_groups()
        ]
        user_info = {
            'name': user.username,
            'gecos': user.realname,
            'passwd': user.password,
            'shell': '/bin/bash',
            'groups': groups,
            'lock-passwd': False,
        }
        if user.ssh_keys:
            user_info['ssh_authorized_keys'] = user.ssh_keys
        config = {
            'growpart': {
                'mode': 'off',
            },
            'hostname': self.identity.hostname,
            'locale': self.locale.selected_language + '.UTF-8',
            'resize_rootfs': False,
            'users': [user_info],
        }
        if self.snaplist.to_install:
            cmds = []
            for snap_name, selection in sorted(
                    self.snaplist.to_install.items()):
                cmd = ['snap', 'install', '--channel=' + selection.channel]
                if selection.is_classic:
                    cmd.append('--classic')
                cmd.append(snap_name)
                cmds.append(' '.join(cmd))
            config['snap'] = {
                'commands': cmds,
            }
        return config

    def _cloud_init_files(self):
        # TODO, this should be moved to the in-target cloud-config seed so on
        # first boot of the target, it reconfigures datasource_list to none
        # for subsequent boots.
        # (mwhudson does not entirely know what the above means!)
        userdata = '#cloud-config\n' + yaml.dump(self._cloud_init_config())
        metadata = yaml.dump({'instance-id': str(uuid.uuid4())})
        return [
            ('var/lib/cloud/seed/nocloud-net/meta-data', metadata),
            ('var/lib/cloud/seed/nocloud-net/user-data', userdata),
            ('etc/cloud/ds-identify.cfg', 'policy: enabled\n'),
        ]

    def configure_cloud_init(self):
        for path, content in self._cloud_init_files():
            path = os.path.join(self.target, path)
            os.makedirs(os.path.dirname(path), exist_ok=True)
            with open(path, 'w') as fp:
                fp.write(content)

    def render(self, syslog_identifier):
        config = {
            'apt': {
                'http_proxy': self.proxy.proxy,
                'https_proxy': self.proxy.proxy,
                'primary': [{
                    'arches': ["default"],
                    'uri': self.mirror.mirror
                }],
                'preserve_sources_list': False,
            },
            'install': {
                'target': self.target,
                'unmount': 'disabled',
                'save_install_config':
                '/var/log/installer/curtin-install-cfg.yaml',
                'save_install_log': '/var/log/installer/curtin-install.log',
            },
            'sources': self.installpath.sources,
            'verbosity': 3,
            'pollinate': {
                'user_agent': {
                    'subiquity':
                    "%s_%s" % (os.environ.get("SNAP_VERSION", 'dry-run'),
                               os.environ.get("SNAP_REVISION", 'dry-run')),
                },
            },
            'proxy': {
                'http_proxy': self.proxy.proxy,
                'https_proxy': self.proxy.proxy,
            },
            'reporting': {
                'subiquity': {
                    'type': 'journald',
                    'identifier': syslog_identifier,
                },
            },
            'storage': {
                'version': 1,
                'config': self.filesystem.render(),
            },
            'write_files': {
                'etc_default_keyboard': {
                    'path': 'etc/default/keyboard',
                    'content': self.keyboard.setting.render(),
                },
            },
        }

        if self.proxy.proxy:
            config['write_files']['snapd_dropin'] = {
                'path': 'etc/systemd/system/snapd.service.d/snap_proxy.conf',
                'content': self.proxy.proxy_systemd_dropin(),
            }

        if not self.filesystem.add_swapfile():
            config['swap'] = {'size': 0}

        config.update(self.network.render())
        config.update(self.installpath.render())

        return config
示例#9
0
 def __init__(self):
     self.network = NetworkModel("console-conf", support_wlan=True)
     self.identity = IdentityModel()
示例#10
0
 def __init__(self, common):
     self.locale = LocaleModel()
     self.network = NetworkModel()
     self.filesystem = FilesystemModel(common['prober'])
     self.identity = IdentityModel()
示例#11
0
class SubiquityModel:
    """The overall model for subiquity."""
    def __init__(self, common):
        self.locale = LocaleModel()
        self.network = NetworkModel()
        self.filesystem = FilesystemModel(common['prober'])
        self.identity = IdentityModel()

    def _cloud_init_config(self):
        user = self.identity.user
        users_and_groups_path = os.path.join(
            os.environ.get("SNAP", "/does-not-exist"), "users-and-groups")
        if os.path.exists(users_and_groups_path):
            groups = open(users_and_groups_path).read().split()
        else:
            groups = ['admin']
        groups.append('sudo')
        user_info = {
            'name': user.username,
            'gecos': user.realname,
            'passwd': user.password,
            'shell': '/bin/bash',
            'groups': groups,
            'lock-passwd': False,
        }
        if user.ssh_import_id is not None:
            user_info['ssh_import_id'] = [user.ssh_import_id]
        # XXX this should set up the locale too.
        return {
            'users': [user_info],
            'hostname': self.identity.hostname,
        }

    def _write_files_config(self):
        # TODO, this should be moved to the in-target cloud-config seed so on first
        # boot of the target, it reconfigures datasource_list to none for subsequent
        # boots.
        # (mwhudson does not entirely know what the above means!)
        userdata = '#cloud-config\n' + yaml.dump(self._cloud_init_config())
        metadata = yaml.dump({'instance-id': str(uuid.uuid4())})
        return {
            'postinst_metadata': {
                'path': 'var/lib/cloud/seed/nocloud-net/meta-data',
                'content': metadata,
            },
            'postinst_userdata': {
                'path': 'var/lib/cloud/seed/nocloud-net/user-data',
                'content': userdata,
            },
            'postinst_enable_cloudinit': {
                'path': 'etc/cloud/ds-identify.cfg',
                'content': 'policy: enabled\n',
            },
        }

    def render(self, install_step, reporting_url=None):
        disk_actions = self.filesystem.render()
        if install_step == "postinstall":
            for a in disk_actions:
                a['preserve'] = True
        config = {
            'partitioning_commands': {
                'builtin': 'curtin block-meta custom',
            },
            'reporting': {
                'subiquity': {
                    'type': 'print',
                },
            },
            'storage': {
                'version': 1,
                'config': disk_actions,
            },
        }
        if install_step == "install":
            config.update(self.network.render())
        else:
            config['write_files'] = self._write_files_config()

        if reporting_url is not None:
            config['reporting']['subiquity'] = {
                'type': 'webhook',
                'endpoint': reporting_url,
            }
        return config