LXC.pm 4.47 KB
Newer Older
Francesc Guasch's avatar
Francesc Guasch committed
1
2
package Ravada::VM::LXC;

3
4
5
6
use warnings;
use strict;

use Carp qw(carp croak);
Francesc Guasch's avatar
Francesc Guasch committed
7
8
9
10
11
12
13
14
use Data::Dumper;
use Fcntl qw(:flock O_WRONLY O_EXCL O_CREAT);
use Hash::Util qw(lock_hash);
use IPC::Run3 qw(run3);
use Moose;
use Sys::Hostname;
use XML::LibXML;

fv3rdugo's avatar
fv3rdugo committed
15
use Ravada::Domain::LXC;
Francesc Guasch's avatar
Francesc Guasch committed
16
17
18

with 'Ravada::VM';

19
our $CMD_LXC_LS;
20
our $CONNECTOR = \$Ravada::CONNECTOR;
21
22
23

sub BUILD {
    my $self = shift;
24
25
26

    $self->connect()                if !defined $CMD_LXC_LS;
    die "No LXC backend found\n"    if !$CMD_LXC_LS;
27
28
}

fv3rdugo's avatar
fv3rdugo committed
29
30
31
32
33
34
35
36
37
38
39
40
sub connect {

#There are two user-space implementations of containers, each exploiting the same kernel
#features. Libvirt allows the use of containers through the LXC driver by connecting 
#to 'lxc:///'.
#We use the other implementation, called simply 'LXC', is not compatible with libvirt,
#but is more flexible with more userspace tools. 
#Use of libvirt-lxc is not generally recommended due to a lack of Apparmor protection 
#for libvirt-lxc containers.
#
#Reference: https://help.ubuntu.com/lts/serverguide/lxc.html#lxc-startup
#
41
    return $CMD_LXC_LS if defined $CMD_LXC_LS;
42

43
44
    $CMD_LXC_LS = `which lxc-ls`;
    chomp $CMD_LXC_LS;
fv3rdugo's avatar
fv3rdugo committed
45

46
    return $CMD_LXC_LS;
fv3rdugo's avatar
fv3rdugo committed
47
48
49
50
51
52
53
54
55
}

sub create_domain {
 my $self = shift;
    my %args = @_;

    $args{active} = 1 if !defined $args{active};
    
    croak "argument name required"       if !$args{name};
56
57
    croak "argument id_template or id_base required" 
        if !$args{id_template} && !$args{id_base};
fv3rdugo's avatar
fv3rdugo committed
58
59

    my $domain;
60
    if ($args{id_template}) {
fv3rdugo's avatar
fv3rdugo committed
61
        $domain = $self->_domain_create_from_template(@_);
fv3rdugo's avatar
fv3rdugo committed
62
63
64
65
66
67
68
69
70
    } elsif($args{id_base}) {
        $domain = $self->_domain_create_from_base(@_);
    } else {
        confess "TODO";
    }

    return $domain;
}

fv3rdugo's avatar
fv3rdugo committed
71
72
73
74
sub _domain_create_from_template {
    my $self = shift;
    my %args = @_;
    
75
76
    croak "argument id_template required" 
        if !$args{id_template};
fv3rdugo's avatar
fv3rdugo committed
77

fv3rdugo's avatar
fv3rdugo committed
78
79
    die "Domain $args{name} already exists"
        if $self->search_domain($args{name});
fv3rdugo's avatar
fv3rdugo committed
80
    
81
    my $template = $self->_search_template($args{id_template});
fv3rdugo's avatar
fv3rdugo committed
82
    my $name = $args{name};
fv3rdugo's avatar
fv3rdugo committed
83

84
    my @cmd = ('lxc-create','-n',$name,'-t', $template->{name});
fv3rdugo's avatar
fv3rdugo committed
85
86
87
    my ($in,$out,$err);
    run3(\@cmd,\$in,\$out,\$err);
    warn $out  if $out;
fv3rdugo's avatar
fv3rdugo committed
88
    die $err   if $?;
fv3rdugo's avatar
fv3rdugo committed
89

fv3rdugo's avatar
fv3rdugo committed
90
91
    my $domain = Ravada::Domain::LXC->new(domain => $args{name});
    $domain->_insert_db(name => $args{name});
fv3rdugo's avatar
fv3rdugo committed
92
93
    return $domain;
}
fv3rdugo's avatar
fv3rdugo committed
94

95
96
97
98
sub _search_template {
    my $self = shift;
    my $id_template = shift or confess "Missing id_template";

99
    my $sth = $$CONNECTOR->dbh->prepare("SELECT * FROM lxc_templates WHERE id = ?");
100
101
    $sth->execute($id_template);
    my $row = $sth->fetchrow_hashref;
fv3rdugo's avatar
fv3rdugo committed
102
    die "Missing lx_template id=$id_template" if !keys %$row;
103
104
105
106
107
    lock_hash(%$row);
    return $row;

}

Francesc Guasch's avatar
Francesc Guasch committed
108
109
110
sub prepare_base {
}

fv3rdugo's avatar
fv3rdugo committed
111
sub _domain_create_from_base {
fv3rdugo's avatar
fv3rdugo committed
112
113
    my $self = shift;
    my $name = shift or confess "Missing domain name";
fv3rdugo's avatar
fv3rdugo committed
114

fv3rdugo's avatar
fv3rdugo committed
115
116
117
118
119
120
121
    my $newname = $name . "_cow";
    my @cmd = ('lxc-copy','-n',$name,"-N",$newname,"-B","overlayfs","-s");
    my ($in,$out,$err);
    run3(\@cmd,\$in,\$out,\$err);
    warn $out  if $out;
    warn $err   if $err;
    #TODO create $newname in ddbb
fv3rdugo's avatar
fv3rdugo committed
122
123
124
    my $newdomain = Ravada::Domain::LXC->new(domain => $newname);
    $newdomain->_insert_db(name => $newname);
    return $newdomain;
fv3rdugo's avatar
fv3rdugo committed
125
126
127
128
}

sub search_domain {
    my $self = shift;
fv3rdugo's avatar
fv3rdugo committed
129
    my $name = shift or confess "Missing domain name";
Francesc Guasch's avatar
Francesc Guasch committed
130
    my $import = shift;
fv3rdugo's avatar
fv3rdugo committed
131

Francesc Guasch's avatar
Francesc Guasch committed
132
133
134
135
136
    for my $domain_lxc ( $self->_list_domains ) {
        next if $domain_lxc ne $name;
        my $domain ;
        my $id;
        eval{ $domain = Ravada::Domain::LXC->new(
Francesc Guasch's avatar
Francesc Guasch committed
137
                          domain => $domain_lxc
Francesc Guasch's avatar
Francesc Guasch committed
138
                         );
Francesc Guasch's avatar
Francesc Guasch committed
139
              $id = $domain->id()   if $domain && !$import;
Francesc Guasch's avatar
Francesc Guasch committed
140
141
142
        };

        return $domain if $domain && $domain->name eq $name;
fv3rdugo's avatar
fv3rdugo committed
143
    }
fv3rdugo's avatar
fv3rdugo committed
144
    return;
fv3rdugo's avatar
fv3rdugo committed
145
146
}

fv3rdugo's avatar
fv3rdugo committed
147
148


fv3rdugo's avatar
fv3rdugo committed
149
150
151
sub search_domain_by_id {
   }

fv3rdugo's avatar
fv3rdugo committed
152
 sub _list_domains {
fv3rdugo's avatar
fv3rdugo committed
153
154
155
156
    my $self = shift;
    my @list = ('lxc-ls','-1');
    my ($in,$out,$err);
    run3(\@list,\$in,\$out,\$err);
fv3rdugo's avatar
fv3rdugo committed
157
158
159
   
    #warn $out  if !$out;
    warn $err   if $err;   
Francesc Guasch's avatar
Francesc Guasch committed
160
161
162
163
164
165
166
    my @domains;
    for (split /\n/,$out) {
        s/^\s+//;
        s/\s+$//;
        push @domains,($_);
    }
    return @domains;
fv3rdugo's avatar
fv3rdugo committed
167
 }
fv3rdugo's avatar
fv3rdugo committed
168

fv3rdugo's avatar
fv3rdugo committed
169

fv3rdugo's avatar
fv3rdugo committed
170
171
172
173
174
175
176
177
178
179
sub list_domains {
    my $self = shift;

    my @list;
    for my $name ($self->_list_domains()) {
        my $domain ;
        my $id;
        eval{ $domain = Ravada::Domain::LXC->new(
                          domain => $name                          
                         );
Francesc Guasch's avatar
Francesc Guasch committed
180
              $id = $domain->id()   if $domain;
fv3rdugo's avatar
fv3rdugo committed
181
182
183
184
185
          };
        push @list,($domain) if $domain && $id;
    }
    return @list;
}
fv3rdugo's avatar
fv3rdugo committed
186

fv3rdugo's avatar
fv3rdugo committed
187
sub create_volume {
fv3rdugo's avatar
fv3rdugo committed
188
189
}

Francesc Guasch's avatar
Francesc Guasch committed
190
1;