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