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