Showing
10 changed files
with
522 additions
and
0 deletions
.gitignore
0 → 100644
Makefile
0 → 100644
README.md
0 → 100644
1 | +# LXC-Coding | ||
2 | + | ||
3 | +Playground for user namespaces and other Linux Container stuff. | ||
4 | + | ||
5 | +## Requirements | ||
6 | + | ||
7 | +A proper kernel... | ||
8 | + | ||
9 | +## License | ||
10 | + | ||
11 | +> This program is free software: you can redistribute it and/or modify | ||
12 | +> it under the terms of the GNU General Public License as published by | ||
13 | +> the Free Software Foundation, either version 3 of the License, or | ||
14 | +> (at your option) any later version. | ||
15 | +> | ||
16 | +> This program is distributed in the hope that it will be useful, | ||
17 | +> but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | +> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | +> GNU General Public License for more details. | ||
20 | +> | ||
21 | +> You should have received a copy of the GNU General Public License | ||
22 | +> along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
23 | + | ||
24 | +## Author | ||
25 | + | ||
26 | +Georg Hopp <<georg@steffers.org>> |
ansible.cfg
0 → 100644
demo_userns.c
0 → 100644
1 | +/* | ||
2 | + * demo_userns.c | ||
3 | + * | ||
4 | + * Copyright 2013, Michael Kerrisk | ||
5 | + * Licensed under GNU General Public License v2 or later | ||
6 | + * | ||
7 | + * Demonstrate the use of the clone() CLONE_NEWUSER flag. | ||
8 | + * | ||
9 | + * Link with "-lcap" and make sure that the "libcap-devel" (or | ||
10 | + * similar) package is installed on the system. | ||
11 | + */ | ||
12 | + | ||
13 | +#define _GNU_SOURCE | ||
14 | + | ||
15 | +#include <sys/capability.h> | ||
16 | +#include <sys/wait.h> | ||
17 | +#include <sched.h> | ||
18 | +#include <stdio.h> | ||
19 | +#include <stdlib.h> | ||
20 | +#include <unistd.h> | ||
21 | + | ||
22 | +#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ | ||
23 | +} while (0) | ||
24 | + | ||
25 | +static int /* Startup function for cloned child */ | ||
26 | +childFunc(void *arg) | ||
27 | +{ | ||
28 | + cap_t caps; | ||
29 | + | ||
30 | + for (;;) { | ||
31 | + printf("eUID = %ld; eGID = %ld; ", | ||
32 | + (long) geteuid(), (long) getegid()); | ||
33 | + | ||
34 | + caps = cap_get_proc(); | ||
35 | + printf("capabilities: %s\n", cap_to_text(caps, NULL)); | ||
36 | + | ||
37 | + if (arg == NULL) | ||
38 | + break; | ||
39 | + | ||
40 | + sleep(5); | ||
41 | + } | ||
42 | + | ||
43 | + return 0; | ||
44 | +} | ||
45 | + | ||
46 | +#define STACK_SIZE (1024 * 1024) | ||
47 | + | ||
48 | +static char child_stack[STACK_SIZE]; /* Space for child's stack */ | ||
49 | + | ||
50 | +int | ||
51 | +main(int argc, char *argv[]) | ||
52 | +{ | ||
53 | + pid_t pid; | ||
54 | + | ||
55 | + /* Create child; child commences execution in childFunc() */ | ||
56 | + | ||
57 | + pid = clone(childFunc, child_stack + STACK_SIZE, /* Assume stack | ||
58 | + grows downward */ | ||
59 | + CLONE_NEWUSER | SIGCHLD, argv[1]); | ||
60 | + if (pid == -1) | ||
61 | + errExit("clone"); | ||
62 | + | ||
63 | + /* Parent falls through to here. Wait for child. */ | ||
64 | + | ||
65 | + if (waitpid(pid, NULL, 0) == -1) | ||
66 | + errExit("waitpid"); | ||
67 | + | ||
68 | + exit(EXIT_SUCCESS); | ||
69 | +} | ||
70 | + | ||
71 | +// vim: ft=c cindent ts=4 sw=4 sts=4: |
demo_userns.o
0 → 100644
No preview for this file type
lxc-test.py
0 → 100644
1 | +import lxc | ||
2 | +import os | ||
3 | +import sys | ||
4 | +import hashlib | ||
5 | +import json | ||
6 | +import getpass | ||
7 | +import subprocess | ||
8 | + | ||
9 | +scriptpath = os.path.dirname(os.path.realpath(__file__)) | ||
10 | + | ||
11 | +def lxc_start(cont): | ||
12 | + if (os.getuid() != 0): | ||
13 | + uname = getpass.getuser() | ||
14 | + subprocess.call([scriptpath + '/create_user_cgroup']); | ||
15 | + for i in os.listdir('/sys/fs/cgroup'): | ||
16 | + if (i == 'openrc'): | ||
17 | + continue | ||
18 | + with open('/sys/fs/cgroup/'+i+'/'+uname+'/tasks', 'a') as f: | ||
19 | + f.write(str(os.getpid())+'\n'); | ||
20 | + | ||
21 | + cont.start(); | ||
22 | + | ||
23 | +def basic(cont): | ||
24 | + def work(data): | ||
25 | + print data | ||
26 | + sys.stdout.flush() | ||
27 | + sys.exit(0) | ||
28 | + | ||
29 | + lxc_read, lxc_write = os.pipe() | ||
30 | + | ||
31 | + cont.attach_wait(work, 'testtest', stdout=lxc_write) | ||
32 | + os.close(lxc_write) | ||
33 | + | ||
34 | + lxc_readfd = os.fdopen(lxc_read) | ||
35 | + data = lxc_readfd.readline().rstrip('\n') | ||
36 | + | ||
37 | + lxc_readfd.close() | ||
38 | + | ||
39 | + print data | ||
40 | + | ||
41 | +def basic2(cont): | ||
42 | + def work(data): | ||
43 | + print data | ||
44 | + sys.stdout.flush() | ||
45 | + sys.exit(0) | ||
46 | + | ||
47 | + lxc_read, lxc_write = os.pipe() | ||
48 | + | ||
49 | + cont.attach(work, 'testtest', stdout=lxc_write) | ||
50 | + os.close(lxc_write) | ||
51 | + | ||
52 | + lxc_readfd = os.fdopen(lxc_read) | ||
53 | + data = lxc_readfd.readline().rstrip('\n') | ||
54 | + | ||
55 | + lxc_readfd.close() | ||
56 | + | ||
57 | + print data | ||
58 | + | ||
59 | +def copy(cont, src, dest): | ||
60 | + def work(dest): | ||
61 | + infno = sys.stdin.fileno() | ||
62 | + data = os.read(infno, 100) | ||
63 | + print(data) | ||
64 | + | ||
65 | + lxc_read, lxc_write = os.pipe() | ||
66 | + | ||
67 | + pid = cont.attach(work, 'foo', stdin=lxc_read) | ||
68 | + os.close(lxc_read) | ||
69 | + | ||
70 | + os.write(lxc_write, 'fooooobadooooo') | ||
71 | + | ||
72 | + os.close(lxc_write) | ||
73 | + os.waitpid(pid, 0) | ||
74 | + | ||
75 | +def copy2(cont, src, dest): | ||
76 | + bufsize = 2048 | ||
77 | + | ||
78 | + def work(dest): | ||
79 | + infno = sys.stdin.fileno() | ||
80 | + with open(dest, 'w') as outfile: | ||
81 | + data = os.read(infno, bufsize) | ||
82 | + while (bufsize == len(data)): | ||
83 | + outfile.write(data) | ||
84 | + data = os.read(infno, bufsize) | ||
85 | + outfile.write(data) | ||
86 | + | ||
87 | + lxc_read, lxc_write = os.pipe() | ||
88 | + | ||
89 | + pid = cont.attach(work, dest, stdin=lxc_read) | ||
90 | + os.close(lxc_read) | ||
91 | + | ||
92 | + with open(src, 'r') as infile: | ||
93 | + data = infile.read(bufsize) | ||
94 | + while (bufsize == len(data)): | ||
95 | + os.write(lxc_write, data) | ||
96 | + data = infile.read(bufsize) | ||
97 | + os.write(lxc_write, data) | ||
98 | + | ||
99 | + os.close(lxc_write) | ||
100 | + os.waitpid(pid, 0) | ||
101 | + | ||
102 | +def verify(cont, src, dest): | ||
103 | + bufsize = 2048 | ||
104 | + | ||
105 | + def work(dest): | ||
106 | + digest = '' | ||
107 | + try: | ||
108 | + chk = hashlib.sha1() | ||
109 | + with open(dest, 'r') as dfile: | ||
110 | + data = dfile.read(bufsize) | ||
111 | + while(bufsize == len(data)): | ||
112 | + chk.update(data) | ||
113 | + data = dfile.read(bufsize) | ||
114 | + chk.update(data) | ||
115 | + digest = chk.hexdigest() | ||
116 | + except: | ||
117 | + pass | ||
118 | + sys.stdout.write(digest) | ||
119 | + sys.stdout.flush() | ||
120 | + | ||
121 | + lxc_read, lxc_write = os.pipe() | ||
122 | + | ||
123 | + pid = cont.attach(work, dest, stdout=lxc_write) | ||
124 | + os.close(lxc_write) | ||
125 | + | ||
126 | + chk = hashlib.sha1() | ||
127 | + with open(src, 'r') as dfile: | ||
128 | + data = dfile.read(bufsize) | ||
129 | + while (bufsize == len(data)): | ||
130 | + chk.update(data) | ||
131 | + data = dfile.read(bufsize) | ||
132 | + chk.update(data) | ||
133 | + | ||
134 | + lxc_chk = os.read(lxc_read, 100) | ||
135 | + os.close(lxc_read) | ||
136 | + | ||
137 | + return json.dumps({ | ||
138 | + 'equal': lxc_chk == chk.hexdigest(), | ||
139 | + 'local_sum': chk.hexdigest(), | ||
140 | + 'container_sum': lxc_chk}) | ||
141 | + | ||
142 | +cont = lxc.Container('ansible_test') | ||
143 | + | ||
144 | +assert cont.defined | ||
145 | + | ||
146 | +started = False | ||
147 | + | ||
148 | +if not cont.running: | ||
149 | + lxc_start(cont) | ||
150 | + if not cont.wait('RUNNING', timeout=5): | ||
151 | + raise EnvironmentError(0x01, '[lxc] unable to start container', cont) | ||
152 | + started = True | ||
153 | + | ||
154 | +#basic(cont) | ||
155 | +#basic2(cont) | ||
156 | +#copy(cont, 'verkauf.jpg', '/tmp/foo') | ||
157 | + | ||
158 | +print __file__ | ||
159 | +print os.path.realpath(__file__) | ||
160 | +print os.path.dirname(os.path.realpath(__file__)) | ||
161 | + | ||
162 | +vres = json.loads(verify(cont, 'verkauf.jpg', '/tmp/foo')) | ||
163 | +if not vres['equal']: | ||
164 | + print "copy file" | ||
165 | + copy2(cont, 'verkauf.jpg', '/tmp/foo') | ||
166 | +else: | ||
167 | + print "files are equal" | ||
168 | + | ||
169 | +if started: | ||
170 | + cont.shutdown(5) | ||
171 | + |
lxc_copy.py
0 → 100644
1 | +#!/usr/bin/python | ||
2 | +# | ||
3 | + | ||
4 | +# (c) 2014, Pavel Antonov <antonov@adwz.ru> | ||
5 | +# | ||
6 | +# This file is part of Ansible | ||
7 | +# | ||
8 | +# This module is free software: you can redistribute it and/or modify | ||
9 | +# it under the terms of the GNU General Public License as published by | ||
10 | +# the Free Software Foundation, either version 3 of the License, or | ||
11 | +# (at your option) any later version. | ||
12 | +# | ||
13 | +# This software is distributed in the hope that it will be useful, | ||
14 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | +# GNU General Public License for more details. | ||
17 | +# | ||
18 | +# You should have received a copy of the GNU General Public License | ||
19 | +# along with this software. If not, see <http://www.gnu.org/licenses/>. | ||
20 | + | ||
21 | +###################################################################### | ||
22 | + | ||
23 | +DOCUMENTATION = ''' | ||
24 | +--- | ||
25 | +module: lxc_copy | ||
26 | +author: Georg Hopp | ||
27 | +version_added: "1.9" | ||
28 | +short_description: copy files in an lxc | ||
29 | +description: | ||
30 | + - Very simple first start to copy files from host to lxc container | ||
31 | + even in non privileged containers | ||
32 | +options: | ||
33 | + name: | ||
34 | + description: | ||
35 | + - Lxc container name to use | ||
36 | + required: true | ||
37 | + default: null | ||
38 | + aliases: [] | ||
39 | + src: | ||
40 | + description: | ||
41 | + - Path to source file | ||
42 | + required: true | ||
43 | + default: null | ||
44 | + aliases: [] | ||
45 | + dest: | ||
46 | + description: | ||
47 | + - Path to file in container | ||
48 | + required: true | ||
49 | + default: null | ||
50 | + aliases: [] | ||
51 | +requirements: [ "lxc", "create_user_cgroup" ] | ||
52 | +''' | ||
53 | + | ||
54 | +EXAMPLES = ''' | ||
55 | +Copy a file from the host in the container: | ||
56 | + | ||
57 | +- hosts: localhost | ||
58 | + tasks: | ||
59 | + - name: copy host file to container | ||
60 | + lxc_copy: | ||
61 | + name: ansible_test | ||
62 | + src: nicefile | ||
63 | + dest: /tmp/verynicefile | ||
64 | +''' | ||
65 | + | ||
66 | +try: | ||
67 | + import lxc | ||
68 | + import sys | ||
69 | + import os | ||
70 | + import json | ||
71 | + import getpass | ||
72 | + import hashlib | ||
73 | + from contextlib import contextmanager | ||
74 | +except ImportError, e: | ||
75 | + print "failed=True msg='failed to import python module: %s'" % e | ||
76 | + sys.exit(1) | ||
77 | + | ||
78 | +class LxcManager: | ||
79 | + @contextmanager | ||
80 | + def lxc_started(self): | ||
81 | + started = self.container.running | ||
82 | + | ||
83 | + if not started and not self.container.running: | ||
84 | + if (os.getuid() != 0): | ||
85 | + uname = getpass.getuser() | ||
86 | + subprocess.call(["create_user_cgroup"]); | ||
87 | + for i in os.listdir('/sys/fs/cgroup'): | ||
88 | + if (i == 'openrc'): | ||
89 | + continue | ||
90 | + with open('/sys/fs/cgroup/'+i+'/'+uname+'/tasks', 'a') as f: | ||
91 | + f.write(str(os.getpid())+'\n'); | ||
92 | + | ||
93 | + self.container.start(); | ||
94 | + | ||
95 | + yield self | ||
96 | + | ||
97 | + if not started and self.container.running: | ||
98 | + self.container.shutdown(5) | ||
99 | + | ||
100 | + def __init__(self, module): | ||
101 | + self.module = module | ||
102 | + self.name = self.module.params.get('name') | ||
103 | + self.src = self.module.params.get('src') | ||
104 | + self.dest = self.module.params.get('dest') | ||
105 | + self.container = lxc.Container(self.name) | ||
106 | + self.changed = False | ||
107 | + self.log = [] | ||
108 | + self.error_msg = None | ||
109 | + self.buffer_size = 20480 | ||
110 | + | ||
111 | + def get_log(self, as_string=True): | ||
112 | + return "".join(self.log) if as_string else self.log | ||
113 | + | ||
114 | + def _verify(self): | ||
115 | + def work(dest): | ||
116 | + digest = '' | ||
117 | + try: | ||
118 | + chk = hashlib.sha1() | ||
119 | + with open(dest, 'r') as dfile: | ||
120 | + data = dfile.read(self.buffer_size) | ||
121 | + while(self.buffer_size == len(data)): | ||
122 | + chk.update(data) | ||
123 | + data = dfile.read(self.buffer_size) | ||
124 | + chk.update(data) | ||
125 | + digest = chk.hexdigest() | ||
126 | + except: | ||
127 | + pass | ||
128 | + sys.stdout.write(digest) | ||
129 | + sys.stdout.flush() | ||
130 | + | ||
131 | + lxc_read, lxc_write = os.pipe() | ||
132 | + | ||
133 | + pid = self.container.attach(work, self.dest, stdout=lxc_write) | ||
134 | + os.close(lxc_write) | ||
135 | + | ||
136 | + chk = hashlib.sha1() | ||
137 | + with open(self.src, 'r') as dfile: | ||
138 | + data = dfile.read(self.buffer_size) | ||
139 | + while (self.buffer_size == len(data)): | ||
140 | + chk.update(data) | ||
141 | + data = dfile.read(self.buffer_size) | ||
142 | + chk.update(data) | ||
143 | + | ||
144 | + lxc_chk = os.read(lxc_read, 100) # read digest from container.... | ||
145 | + os.close(lxc_read) | ||
146 | + | ||
147 | + self.files_equal = lxc_chk == chk.hexdigest() | ||
148 | + self.local_sum = chk.hexdigest() | ||
149 | + self.container_sum = lxc_chk | ||
150 | + | ||
151 | + def copy(self): | ||
152 | + with self.lxc_started(): | ||
153 | + self._verify() | ||
154 | + if not self.files_equal: | ||
155 | + def work(dest): | ||
156 | + infno = sys.stdin.fileno() | ||
157 | + with open(dest, 'w') as outfile: | ||
158 | + data = os.read(infno, self.buffer_size) | ||
159 | + while (self.buffer_size == len(data)): | ||
160 | + outfile.write(data) | ||
161 | + data = os.read(infno, self.buffer_size) | ||
162 | + outfile.write(data) | ||
163 | + | ||
164 | + lxc_read, lxc_write = os.pipe() | ||
165 | + | ||
166 | + pid = self.container.attach(work, self.dest, stdin=lxc_read) | ||
167 | + os.close(lxc_read) | ||
168 | + | ||
169 | + with open(self.src, 'r') as infile: | ||
170 | + data = infile.read(self.buffer_size) | ||
171 | + while (self.buffer_size == len(data)): | ||
172 | + os.write(lxc_write, data) | ||
173 | + data = infile.read(self.buffer_size) | ||
174 | + os.write(lxc_write, data) | ||
175 | + | ||
176 | + os.close(lxc_write) | ||
177 | + os.waitpid(pid, 0) | ||
178 | + self.changed = True | ||
179 | + | ||
180 | + def has_changed(self): | ||
181 | + return self.changed | ||
182 | + | ||
183 | + | ||
184 | +def main(): | ||
185 | + module = AnsibleModule( | ||
186 | + argument_spec = dict( | ||
187 | + name = dict(required=True, default=None), | ||
188 | + src = dict(required=True, default=None), | ||
189 | + dest = dict(required=True, default=None), | ||
190 | + ) | ||
191 | + ) | ||
192 | + | ||
193 | + manager = LxcManager(module) | ||
194 | + | ||
195 | + image_id = None | ||
196 | + msg = '' | ||
197 | + do_build = False | ||
198 | + | ||
199 | + manager.copy() | ||
200 | + | ||
201 | + module.exit_json(failed=False, changed=manager.has_changed(), msg="File copied") | ||
202 | + | ||
203 | +# import module snippets | ||
204 | +from ansible.module_utils.basic import * | ||
205 | +if __name__ == '__main__': | ||
206 | + main() |
playbook.yml
0 → 100644
1 | +--- | ||
2 | +- name: test playbook for lxc_copy | ||
3 | + hosts: all | ||
4 | + tasks: | ||
5 | + - name: copy single file in container | ||
6 | + lxc_copy: | ||
7 | + args: | ||
8 | + name: ansible_test | ||
9 | + src: files/verkauf.jpg | ||
10 | + dest: /tmp/foo | ||
11 | + | ||
12 | + - name: copy files in container | ||
13 | + lxc_copy: | ||
14 | + args: | ||
15 | + name: ansible_test | ||
16 | + src: files/{{ item }} | ||
17 | + dest: /tmp/{{ item }} | ||
18 | + with_items: ['a', 'b', 'c', 'd', 'e', 'f', 'g'] |
Please
register
or
login
to post a comment