libvirt-sandbox-builder-container.c 20.1 KB
Newer Older
1 2 3
/*
 * libvirt-sandbox-builder-container.c: libvirt sandbox configuration
 *
4
 * Copyright (C) 2011 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 20 21 22 23 24 25
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>
#include <string.h>

26 27
#include <glib/gi18n.h>

28
#include "libvirt-sandbox/libvirt-sandbox.h"
29
#include "libvirt-sandbox/libvirt-sandbox-builder-private.h"
30

31 32 33 34 35 36 37 38 39 40 41 42
/**
 * SECTION: libvirt-sandbox-builder-container
 * @short_description: Sandbox container construction
 * @include: libvirt-sandbox/libvirt-sandbox.h
 * @see_also: #GVirSandboxBuilder, #GVirSandboxBuilderMachine
 *
 * Provides an object for creating sandboxes using container virtualization
 *
 * The GVirSandboxBuilderContainer object provides a way to builder sandboxes
 * using OS container virtualization technologies such as LXC.
 */

43 44
#define GVIR_SANDBOX_BUILDER_CONTAINER_GET_PRIVATE(obj)                 \
    (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_SANDBOX_TYPE_BUILDER_CONTAINER, GVirSandboxBuilderContainerPrivate))
45 46 47 48 49 50

struct _GVirSandboxBuilderContainerPrivate
{
    gboolean unused;
};

51
G_DEFINE_TYPE_WITH_PRIVATE(GVirSandboxBuilderContainer, gvir_sandbox_builder_container, GVIR_SANDBOX_TYPE_BUILDER);
52 53 54 55 56 57 58 59 60 61 62 63


enum {
    PROP_0,
};

enum {
    LAST_SIGNAL
};

//static gint signals[LAST_SIGNAL];

64
#if 0
65 66 67 68 69 70 71
#define GVIR_SANDBOX_BUILDER_CONTAINER_ERROR gvir_sandbox_builder_container_error_quark()

static GQuark
gvir_sandbox_builder_container_error_quark(void)
{
    return g_quark_from_static_string("gvir-sandbox-builder-container");
}
72
#endif
73 74

static void gvir_sandbox_builder_container_get_property(GObject *object,
75 76 77
                                                        guint prop_id,
                                                        GValue *value G_GNUC_UNUSED,
                                                        GParamSpec *pspec)
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
{
#if 0
    GVirSandboxBuilderContainer *builder = GVIR_SANDBOX_BUILDER_CONTAINER(object);
    GVirSandboxBuilderContainerPrivate *priv = builder->priv;
#endif

    switch (prop_id) {

    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
    }
}


static void gvir_sandbox_builder_container_set_property(GObject *object,
93 94 95
                                                        guint prop_id,
                                                        const GValue *value G_GNUC_UNUSED,
                                                        GParamSpec *pspec)
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
{
#if 0
    GVirSandboxBuilderContainer *builder = GVIR_SANDBOX_BUILDER_CONTAINER(object);
    GVirSandboxBuilderContainerPrivate *priv = builder->priv;
#endif

    switch (prop_id) {

    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
    }
}


static void gvir_sandbox_builder_container_finalize(GObject *object)
{
#if 0
    GVirSandboxBuilderContainer *builder = GVIR_SANDBOX_BUILDER_CONTAINER(object);
    GVirSandboxBuilderContainerPrivate *priv = builder->priv;
#endif

    G_OBJECT_CLASS(gvir_sandbox_builder_container_parent_class)->finalize(object);
}


121 122 123 124
static gchar *gvir_sandbox_builder_container_cmdline(GVirSandboxConfig *config G_GNUC_UNUSED)
{
    GString *str = g_string_new("");
    gchar *ret;
125
    gchar *tmp;
126 127

    /* Now kernel args */
128
    if (getenv("LIBVIRT_SANDBOX_INIT_DEBUG"))
129 130
        g_string_append(str, "debug");

131 132 133 134 135
    if ((tmp = getenv("LIBVIRT_SANDBOX_STRACE"))) {
        g_string_append(str, " strace=");
        g_string_append(str, tmp);
    }

136 137 138 139 140 141
    ret = str->str;
    g_string_free(str, FALSE);
    return ret;
}


142 143
static gboolean gvir_sandbox_builder_container_construct_basic(GVirSandboxBuilder *builder,
                                                               GVirSandboxConfig *config,
144
                                                               const gchar *statedir,
145 146 147
                                                               GVirConfigDomain *domain,
                                                               GError **error)
{
148 149
    gchar **features;

150
    if (!GVIR_SANDBOX_BUILDER_CLASS(gvir_sandbox_builder_container_parent_class)->
151
        construct_basic(builder, config, statedir, domain, error))
152
        return FALSE;
153

154 155 156
    gvir_config_domain_set_virt_type(domain,
                                     GVIR_CONFIG_DOMAIN_VIRT_LXC);

157 158 159 160 161
    features = g_new0(gchar *, 2);
    features[0] = g_strdup("privnet");
    gvir_config_domain_set_features(domain, features);
    g_strfreev(features);

162 163 164 165 166 167
    return TRUE;
}


static gboolean gvir_sandbox_builder_container_construct_os(GVirSandboxBuilder *builder,
                                                            GVirSandboxConfig *config,
168
                                                            const gchar *statedir,
169 170
                                                            GVirConfigDomain *domain,
                                                            GError **error)
171
{
172
    gchar *cmdline = NULL;
173 174 175
    GVirConfigDomainOs *os;

    if (!GVIR_SANDBOX_BUILDER_CLASS(gvir_sandbox_builder_container_parent_class)->
176
        construct_os(builder, config, statedir, domain, error))
177
        return FALSE;
178

179 180
    cmdline = gvir_sandbox_builder_container_cmdline(config);

181 182 183 184 185 186
    os = gvir_config_domain_os_new();
    gvir_config_domain_os_set_os_type(os,
                                      GVIR_CONFIG_DOMAIN_OS_TYPE_EXE);
    gvir_config_domain_os_set_arch(os,
                                   gvir_sandbox_config_get_arch(config));
    gvir_config_domain_os_set_init(os,
187
                                   SANDBOXCONFIGDIR "/.libs/libvirt-sandbox-init-lxc");
188
    gvir_config_domain_os_set_cmdline(os, cmdline);
189 190
    gvir_config_domain_set_os(domain, os);

191 192
    g_free(cmdline);

193 194 195
    return TRUE;
}

196

197 198
static gboolean gvir_sandbox_builder_container_construct_features(GVirSandboxBuilder *builder,
                                                                  GVirSandboxConfig *config,
199
                                                                  const gchar *statedir,
200 201 202 203
                                                                  GVirConfigDomain *domain,
                                                                  GError **error)
{
    if (!GVIR_SANDBOX_BUILDER_CLASS(gvir_sandbox_builder_container_parent_class)->
204
        construct_features(builder, config, statedir, domain, error))
205
        return FALSE;
206

207 208
    return TRUE;
}
209

210 211
static gboolean gvir_sandbox_builder_container_construct_devices(GVirSandboxBuilder *builder,
                                                                 GVirSandboxConfig *config,
212
                                                                 const gchar *statedir,
213 214 215 216
                                                                 GVirConfigDomain *domain,
                                                                 GError **error)
{
    GVirConfigDomainFilesys *fs;
217
    GVirConfigDomainInterfaceNetwork *iface;
218 219
    GVirConfigDomainConsole *con;
    GVirConfigDomainChardevSourcePty *src;
220 221 222
    GVirConfigDomainDisk *disk;
    GVirConfigDomainDiskDriver *diskDriver;
    GList *tmp = NULL, *mounts = NULL, *networks = NULL, *disks = NULL;
223 224
    gchar *configdir = g_strdup_printf("%s/config", statedir);
    gboolean ret = FALSE;
225
    size_t nVirtioDev = 0;
226 227

    if (!GVIR_SANDBOX_BUILDER_CLASS(gvir_sandbox_builder_container_parent_class)->
228 229
        construct_devices(builder, config, statedir, domain, error))
        goto cleanup;
230

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

    tmp = disks = gvir_sandbox_config_get_disks(config);
    while (tmp) {
        GVirSandboxConfigDisk *dconfig = GVIR_SANDBOX_CONFIG_DISK(tmp->data);

        if (GVIR_SANDBOX_IS_CONFIG_DISK(dconfig)) {
            gchar *device = g_strdup_printf("sd%c", (char)('a' + nVirtioDev++));
            disk = gvir_config_domain_disk_new();
            diskDriver = gvir_config_domain_disk_driver_new();
            gvir_config_domain_disk_set_type(disk,
                                             gvir_sandbox_config_disk_get_disk_type(dconfig));
            gvir_config_domain_disk_driver_set_format(diskDriver,
                                                      gvir_sandbox_config_disk_get_format(dconfig));
            gvir_config_domain_disk_set_source(disk,
                                               gvir_sandbox_config_disk_get_source(dconfig));
            gvir_config_domain_disk_set_target_dev(disk, device);
            gvir_config_domain_disk_set_driver(disk, diskDriver);
            gvir_config_domain_add_device(domain,
                                          GVIR_CONFIG_DOMAIN_DEVICE(disk));
            g_object_unref(disk);
        }
        tmp = tmp->next;
    }

    g_list_foreach(disks, (GFunc)g_object_unref, NULL);
    g_list_free(disks);


259 260 261 262 263 264 265 266 267 268 269 270 271
    if (!gvir_sandbox_config_has_root_mount(config)) {
        fs = gvir_config_domain_filesys_new();
        gvir_config_domain_filesys_set_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_MOUNT);
        gvir_config_domain_filesys_set_access_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_ACCESS_PASSTHROUGH);
        gvir_config_domain_filesys_set_source(fs,
                                              gvir_sandbox_config_get_root(config));
        gvir_config_domain_filesys_set_target(fs, "/");
        gvir_config_domain_filesys_set_readonly(fs, TRUE);

        gvir_config_domain_add_device(domain,
                                      GVIR_CONFIG_DOMAIN_DEVICE(fs));
        g_object_unref(fs);
    }
272

273 274 275 276 277 278


    fs = gvir_config_domain_filesys_new();
    gvir_config_domain_filesys_set_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_MOUNT);
    gvir_config_domain_filesys_set_access_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_ACCESS_PASSTHROUGH);
    gvir_config_domain_filesys_set_source(fs, configdir);
279
    gvir_config_domain_filesys_set_target(fs, SANDBOXCONFIGDIR);
280 281 282 283 284 285 286 287
    gvir_config_domain_filesys_set_readonly(fs, TRUE);

    gvir_config_domain_add_device(domain,
                                  GVIR_CONFIG_DOMAIN_DEVICE(fs));
    g_object_unref(fs);



288
    tmp = mounts = gvir_sandbox_config_get_mounts(config);
289
    while (tmp) {
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
        GVirSandboxConfigMount *mconfig = GVIR_SANDBOX_CONFIG_MOUNT(tmp->data);

        if (GVIR_SANDBOX_IS_CONFIG_MOUNT_HOST_BIND(mconfig)) {
            GVirSandboxConfigMountFile *mfile = GVIR_SANDBOX_CONFIG_MOUNT_FILE(mconfig);

            fs = gvir_config_domain_filesys_new();
            gvir_config_domain_filesys_set_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_MOUNT);
            gvir_config_domain_filesys_set_access_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_ACCESS_PASSTHROUGH);
            gvir_config_domain_filesys_set_source(fs,
                                                  gvir_sandbox_config_mount_file_get_source(mfile));
            gvir_config_domain_filesys_set_target(fs,
                                                  gvir_sandbox_config_mount_get_target(mconfig));

            gvir_config_domain_add_device(domain,
                                          GVIR_CONFIG_DOMAIN_DEVICE(fs));
            g_object_unref(fs);
        } else if (GVIR_SANDBOX_IS_CONFIG_MOUNT_HOST_IMAGE(mconfig)) {
            GVirSandboxConfigMountFile *mfile = GVIR_SANDBOX_CONFIG_MOUNT_FILE(mconfig);
308 309 310
            GVirSandboxConfigMountHostImage *mimage = GVIR_SANDBOX_CONFIG_MOUNT_HOST_IMAGE(mconfig);
            GVirConfigDomainDiskFormat format;
            GVirConfigDomainFilesysDriverType type = GVIR_CONFIG_DOMAIN_FILESYS_DRIVER_LOOP;
311 312 313 314 315 316 317 318 319

            fs = gvir_config_domain_filesys_new();
            gvir_config_domain_filesys_set_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_FILE);
            gvir_config_domain_filesys_set_access_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_ACCESS_PASSTHROUGH);
            gvir_config_domain_filesys_set_source(fs,
                                                  gvir_sandbox_config_mount_file_get_source(mfile));
            gvir_config_domain_filesys_set_target(fs,
                                                  gvir_sandbox_config_mount_get_target(mconfig));

320 321 322 323 324 325 326
            format = gvir_sandbox_config_mount_host_image_get_format(mimage);
            if (format != GVIR_CONFIG_DOMAIN_DISK_FORMAT_RAW)
                type = GVIR_CONFIG_DOMAIN_FILESYS_DRIVER_NBD;

            gvir_config_domain_filesys_set_driver_type(fs, type);
            gvir_config_domain_filesys_set_driver_format(fs, format);

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
            gvir_config_domain_add_device(domain,
                                          GVIR_CONFIG_DOMAIN_DEVICE(fs));
            g_object_unref(fs);
        } else if (GVIR_SANDBOX_IS_CONFIG_MOUNT_GUEST_BIND(mconfig)) {
            GVirSandboxConfigMountFile *mfile = GVIR_SANDBOX_CONFIG_MOUNT_FILE(mconfig);

            fs = gvir_config_domain_filesys_new();
            gvir_config_domain_filesys_set_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_BIND);
            gvir_config_domain_filesys_set_access_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_ACCESS_PASSTHROUGH);
            gvir_config_domain_filesys_set_source(fs,
                                                  gvir_sandbox_config_mount_file_get_source(mfile));
            gvir_config_domain_filesys_set_target(fs,
                                                  gvir_sandbox_config_mount_get_target(mconfig));

            gvir_config_domain_add_device(domain,
                                          GVIR_CONFIG_DOMAIN_DEVICE(fs));
            g_object_unref(fs);
344 345 346 347 348 349 350 351 352 353
        } else if (GVIR_SANDBOX_IS_CONFIG_MOUNT_RAM(mconfig)) {
            GVirSandboxConfigMountRam *mram = GVIR_SANDBOX_CONFIG_MOUNT_RAM(mconfig);

            fs = gvir_config_domain_filesys_new();
            gvir_config_domain_filesys_set_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_RAM);
            gvir_config_domain_filesys_set_access_type(fs, GVIR_CONFIG_DOMAIN_FILESYS_ACCESS_PASSTHROUGH);
            gvir_config_domain_filesys_set_ram_usage(fs,
                                                     gvir_sandbox_config_mount_ram_get_usage(mram));
            gvir_config_domain_filesys_set_target(fs,
                                                  gvir_sandbox_config_mount_get_target(mconfig));
354

355 356 357 358
            gvir_config_domain_add_device(domain,
                                          GVIR_CONFIG_DOMAIN_DEVICE(fs));
            g_object_unref(fs);
        }
359 360 361 362 363 364 365

        tmp = tmp->next;
    }
    g_list_foreach(mounts, (GFunc)g_object_unref, NULL);
    g_list_free(mounts);


366 367
    tmp = networks = gvir_sandbox_config_get_networks(config);
    while (tmp) {
368
        const gchar *source, *mac;
369
        GVirSandboxConfigNetwork *network = GVIR_SANDBOX_CONFIG_NETWORK(tmp->data);
Ian Main's avatar
Ian Main committed
370
        GVirSandboxConfigNetworkFilterref *filterref;
371

372
        iface = gvir_config_domain_interface_network_new();
373 374 375 376 377
        source = gvir_sandbox_config_network_get_source(network);
        if (source)
            gvir_config_domain_interface_network_set_source(iface, source);
        else
            gvir_config_domain_interface_network_set_source(iface, "default");
378

379 380 381 382 383
        mac = gvir_sandbox_config_network_get_mac(network);
        if (mac)
            gvir_config_domain_interface_set_mac(GVIR_CONFIG_DOMAIN_INTERFACE(iface),
                                                 mac);

384 385
        gvir_config_domain_add_device(domain,
                                      GVIR_CONFIG_DOMAIN_DEVICE(iface));
Ian Main's avatar
Ian Main committed
386 387 388

        filterref = gvir_sandbox_config_network_get_filterref(network);
        if (filterref) {
389 390 391
            gvir_sandbox_builder_set_filterref(builder,
                                               GVIR_CONFIG_DOMAIN_INTERFACE(iface),
                                               filterref);
Ian Main's avatar
Ian Main committed
392 393
        }

394 395 396 397
        g_object_unref(iface);

        tmp = tmp->next;
    }
398 399
    g_list_foreach(networks, (GFunc)g_object_unref, NULL);
    g_list_free(networks);
400 401


402
    /* The first console is for debug messages from stdout/err of the guest init/kernel */
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
    src = gvir_config_domain_chardev_source_pty_new();
    con = gvir_config_domain_console_new();
    gvir_config_domain_chardev_set_source(GVIR_CONFIG_DOMAIN_CHARDEV(con),
                                          GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE(src));
    gvir_config_domain_add_device(domain,
                                  GVIR_CONFIG_DOMAIN_DEVICE(con));
    g_object_unref(con);


    /* Optional second console is for a interactive shell (useful for
     * troubleshooting stuff */
    if (gvir_sandbox_config_get_shell(config)) {
        src = gvir_config_domain_chardev_source_pty_new();
        con = gvir_config_domain_console_new();
        gvir_config_domain_chardev_set_source(GVIR_CONFIG_DOMAIN_CHARDEV(con),
                                              GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE(src));
        gvir_config_domain_add_device(domain,
                                      GVIR_CONFIG_DOMAIN_DEVICE(con));
        g_object_unref(con);
    }

424 425 426 427 428 429 430 431 432 433 434
    if (GVIR_SANDBOX_IS_CONFIG_INTERACTIVE(config)) {
        /* The third console is for stdio of the sandboxed app */
        src = gvir_config_domain_chardev_source_pty_new();
        con = gvir_config_domain_console_new();
        gvir_config_domain_chardev_set_source(GVIR_CONFIG_DOMAIN_CHARDEV(con),
                                              GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE(src));
        gvir_config_domain_add_device(domain,
                                      GVIR_CONFIG_DOMAIN_DEVICE(con));
        g_object_unref(con);
    }

435
    ret = TRUE;
436
 cleanup:
437 438
    g_free(configdir);
    return ret;
439 440 441
}


442 443 444 445 446 447 448
static const gchar *gvir_sandbox_builder_container_get_disk_prefix(GVirSandboxBuilder *builder,
                                                                   GVirSandboxConfig *config G_GNUC_UNUSED,
                                                                   GVirSandboxConfigDisk *disk G_GNUC_UNUSED)
{
    return "sd";
}

449 450 451 452 453 454 455 456 457 458 459 460

static GList *gvir_sandbox_builder_container_get_files_to_copy(GVirSandboxBuilder *builder,
                                                               GVirSandboxConfig *config G_GNUC_UNUSED)
{
    GList * tocopy = GVIR_SANDBOX_BUILDER_CLASS(gvir_sandbox_builder_container_parent_class)->
                     get_files_to_copy(builder, config);
    gchar *file = g_strdup_printf("%s/libvirt-sandbox-init-lxc", LIBEXECDIR);

    return g_list_append(tocopy, file);
}


461 462 463 464 465 466 467 468 469
static void gvir_sandbox_builder_container_class_init(GVirSandboxBuilderContainerClass *klass)
{
    GObjectClass *object_class = G_OBJECT_CLASS(klass);
    GVirSandboxBuilderClass *builder_class = GVIR_SANDBOX_BUILDER_CLASS(klass);

    object_class->finalize = gvir_sandbox_builder_container_finalize;
    object_class->get_property = gvir_sandbox_builder_container_get_property;
    object_class->set_property = gvir_sandbox_builder_container_set_property;

470 471 472 473
    builder_class->construct_basic = gvir_sandbox_builder_container_construct_basic;
    builder_class->construct_os = gvir_sandbox_builder_container_construct_os;
    builder_class->construct_features = gvir_sandbox_builder_container_construct_features;
    builder_class->construct_devices = gvir_sandbox_builder_container_construct_devices;
474
    builder_class->get_disk_prefix = gvir_sandbox_builder_container_get_disk_prefix;
475
    builder_class->get_files_to_copy = gvir_sandbox_builder_container_get_files_to_copy;
476 477 478 479 480 481 482 483 484 485 486 487 488
}


static void gvir_sandbox_builder_container_init(GVirSandboxBuilderContainer *builder)
{
    builder->priv = GVIR_SANDBOX_BUILDER_CONTAINER_GET_PRIVATE(builder);
}


/**
 * gvir_sandbox_builder_container_new:
 * @connection: (transfer none): the connection
 *
489
 * Create a new pplication sandbox builder for containers
490
 *
491
 * Returns: (transfer full): a new sandbox builder object
492
 */
493
GVirSandboxBuilderContainer *gvir_sandbox_builder_container_new(GVirConnection *connection)
494 495 496 497 498
{
    return GVIR_SANDBOX_BUILDER_CONTAINER(g_object_new(GVIR_SANDBOX_TYPE_BUILDER_CONTAINER,
                                                       "connection", connection,
                                                       NULL));
}
499 500 501 502 503 504 505 506 507

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  indent-tabs-mode: nil
 *  tab-width: 8
 * End:
 */