From d370a511005a88fc42c08e735111d941f47b72df Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Sat, 9 Apr 2016 22:22:45 +0200 Subject: [PATCH] Add vry basic README.md --- .gitignore | 6 ++ Makefile | 12 +++ README.md | 26 +++++++ ansible.cfg | 11 +++ demo_userns.c | 71 +++++++++++++++++ demo_userns.o | Bin 0 -> 5320 bytes hosts | 1 + lxc-test.py | 171 +++++++++++++++++++++++++++++++++++++++++ lxc_copy.py | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++ playbook.yml | 18 +++++ 10 files changed, 522 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 ansible.cfg create mode 100644 demo_userns.c create mode 100644 demo_userns.o create mode 100644 hosts create mode 100644 lxc-test.py create mode 100644 lxc_copy.py create mode 100644 playbook.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b9af02 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# ignore vim swap files +.*.sw? + +# ignore generated stuff +demo_userns +create_user_cgroup diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a4e12fd --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +PROGRAMS = demo_userns + +demo_userns_OBJS = demo_userns.o +OBJECTS = $(demo_userns_OBJS) + +CFLAGS = -O0 -ggdb -Wall -Werror + +$(PROGRAMS): $(OBJECTS) + $(CC) $(LDFLAGS) -lcap -o $@ $($@_OBJS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/README.md b/README.md new file mode 100644 index 0000000..31860fd --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# LXC-Coding + +Playground for user namespaces and other Linux Container stuff. + +## Requirements + +A proper kernel... + +## License + +> This program is free software: you can redistribute it and/or modify +> it under the terms of the GNU General Public License as published by +> the Free Software Foundation, either version 3 of the License, or +> (at your option) any later version. +> +> This program 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 General Public License for more details. +> +> You should have received a copy of the GNU General Public License +> along with this program. If not, see . + +## Author + +Georg Hopp <> diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..ad887ee --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,11 @@ +[defaults] +inventory = hosts +host_key_checking = False +nocows=0 + +ansible_managed = Ansible managed: {file} on {host} + +# # do redis facts caching +# gathering = smart +# fact_caching = redis +# fact_caching_timeout = 86400 diff --git a/demo_userns.c b/demo_userns.c new file mode 100644 index 0000000..acc4f8d --- /dev/null +++ b/demo_userns.c @@ -0,0 +1,71 @@ +/* + * demo_userns.c + * + * Copyright 2013, Michael Kerrisk + * Licensed under GNU General Public License v2 or later + * + * Demonstrate the use of the clone() CLONE_NEWUSER flag. + * + * Link with "-lcap" and make sure that the "libcap-devel" (or + * similar) package is installed on the system. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ +} while (0) + +static int /* Startup function for cloned child */ +childFunc(void *arg) +{ + cap_t caps; + + for (;;) { + printf("eUID = %ld; eGID = %ld; ", + (long) geteuid(), (long) getegid()); + + caps = cap_get_proc(); + printf("capabilities: %s\n", cap_to_text(caps, NULL)); + + if (arg == NULL) + break; + + sleep(5); + } + + return 0; +} + +#define STACK_SIZE (1024 * 1024) + +static char child_stack[STACK_SIZE]; /* Space for child's stack */ + +int +main(int argc, char *argv[]) +{ + pid_t pid; + + /* Create child; child commences execution in childFunc() */ + + pid = clone(childFunc, child_stack + STACK_SIZE, /* Assume stack + grows downward */ + CLONE_NEWUSER | SIGCHLD, argv[1]); + if (pid == -1) + errExit("clone"); + + /* Parent falls through to here. Wait for child. */ + + if (waitpid(pid, NULL, 0) == -1) + errExit("waitpid"); + + exit(EXIT_SUCCESS); +} + +// vim: ft=c cindent ts=4 sw=4 sts=4: diff --git a/demo_userns.o b/demo_userns.o new file mode 100644 index 0000000000000000000000000000000000000000..9273ee90cc1a03809fa827be5a486f01c1bf5fda GIT binary patch literal 5320 zcmbVQU2IfE6rOu;OShE%K&cA&Z~?0j*}Fv$M(@=tB*`Mj|)&29{yU-FF zjEz4lFE&wMBoR$C#>DvZV2nmVG5UguMiYroeIX%2VvHtgtk!epp4puayDy$*@0|0^ zIcLtCnK?7*so?|rO~YW447QgwB#AQiTyKMq3pUOM*a|k5s9k`H0qBec$3U<^k zgw6Rx?WaWTt8<8bgdYKmPog$_C2@NA%4Y~CYF`tm>n3KVFR`k5b=kRgX@2#LaFv+( za>J3M7jSSG+pbMtOVp}!;Bqc8b3T$d4NgD*csXNzVgxOO+VK3$^!!3~rNG75=Wxn` zJ3T!AF-9c}DYBVATPQaipvnItJ~n!vy~iFbWOvy%A5jFBNmWv5x8MdY_jlTZ{!*4H zluMkQNV!49&9X-!=r%EEM6B3#%hsVFrV&9^)9esUTi8Ux##j>eVVarM*6x-9W=4c0 z1~8vK1RZ9m-5yyIIfY_qB^0bQZz!miZ5!T(jwO-z;48)wQ5dVypQLGGj5EIh*O~Hi z%vgN_SaUY96#I;uUlr0g>k{G?)%tmafQ&PD!*rJkRw$UWkC22N=In#rm^9&hf2K;8~69@jDp1xq2f|MjK`czxmbi;FsB47?7$X*6~^ro z8u5H`!b=sg8a5|L1r+UH7n=22O>bV<^zhe=EGqwcpT$J!UIgRyZ7Tj{(S=e3Xn2i; z27Prqi-~)oE=$H@i_1j=@09GK)(Y$PA`AtKbzg^txboOgG%VJLO@YA=RA7w;L2jlU zZGqp}0^i*NA8mn;wZM-6z5+5W^DeKgV=eS2THsiGo6XB>forF^dFjjXfal2yA?gl5NhoGeDzONalj4~91u86N+q{ zTHXI+3XU;LKW7O?KjG;KSLF=_M_-cOB?d8gI@JAqO1O*%_b1X9VI$(lx+urJsNi^Z zB|fL%s}=lb!lnN$B>$r5tN#B|aMizsg$oGdS8-V((7$^6#nTHg#F5AIf`n_0B=I=; zmHR>BFNJDiEM!ql&F4nyM}6@sBzZ`|aoi6`-mc;EB=6O5d4COSxU@f@;k^|9!x}zF zcuK>6BpJ^)lALdh^x>H#NaEWGe@esOA^BMim*?$84WA?V6%8kmoz?K~NPb_#&y)P2 zhOZ@A_G8%UdR^A^ZJO8b8h(-Ff2oyzWZfJfJDHz9NN>G{uOa!chTl&5oN#Q^+fUuk z>MbX0F6yiEI!XR?+$J1#RsH)kT+WN&|J~SNi809drK318`jZ}YRl+)md5EhZ@W(LG zKyze(H5OT!8>}5jx55u`{iQOZ4}{7c~#5Phwen3GXUH2&T z=@_d2L-w*RN*B5=-ha*F@1v)fw8!|d&g=0%4w&u}AQnZZKyQXk{j2L1pr_gRaT;Il zGaMi5y*@skBlIcb1Xj@ZH2y(tKq<=hInZuqzm^V^tQ+LEK38c!OZKu~wg<>w%CePq zQpWrsrtjYe$sX57B{_eIy#`FP{EatRKRij&UgmW +# +# This file is part of Ansible +# +# This module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This software 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software. If not, see . + +###################################################################### + +DOCUMENTATION = ''' +--- +module: lxc_copy +author: Georg Hopp +version_added: "1.9" +short_description: copy files in an lxc +description: + - Very simple first start to copy files from host to lxc container + even in non privileged containers +options: + name: + description: + - Lxc container name to use + required: true + default: null + aliases: [] + src: + description: + - Path to source file + required: true + default: null + aliases: [] + dest: + description: + - Path to file in container + required: true + default: null + aliases: [] +requirements: [ "lxc", "create_user_cgroup" ] +''' + +EXAMPLES = ''' +Copy a file from the host in the container: + +- hosts: localhost + tasks: + - name: copy host file to container + lxc_copy: + name: ansible_test + src: nicefile + dest: /tmp/verynicefile +''' + +try: + import lxc + import sys + import os + import json + import getpass + import hashlib + from contextlib import contextmanager +except ImportError, e: + print "failed=True msg='failed to import python module: %s'" % e + sys.exit(1) + +class LxcManager: + @contextmanager + def lxc_started(self): + started = self.container.running + + if not started and not self.container.running: + if (os.getuid() != 0): + uname = getpass.getuser() + subprocess.call(["create_user_cgroup"]); + for i in os.listdir('/sys/fs/cgroup'): + if (i == 'openrc'): + continue + with open('/sys/fs/cgroup/'+i+'/'+uname+'/tasks', 'a') as f: + f.write(str(os.getpid())+'\n'); + + self.container.start(); + + yield self + + if not started and self.container.running: + self.container.shutdown(5) + + def __init__(self, module): + self.module = module + self.name = self.module.params.get('name') + self.src = self.module.params.get('src') + self.dest = self.module.params.get('dest') + self.container = lxc.Container(self.name) + self.changed = False + self.log = [] + self.error_msg = None + self.buffer_size = 20480 + + def get_log(self, as_string=True): + return "".join(self.log) if as_string else self.log + + def _verify(self): + def work(dest): + digest = '' + try: + chk = hashlib.sha1() + with open(dest, 'r') as dfile: + data = dfile.read(self.buffer_size) + while(self.buffer_size == len(data)): + chk.update(data) + data = dfile.read(self.buffer_size) + chk.update(data) + digest = chk.hexdigest() + except: + pass + sys.stdout.write(digest) + sys.stdout.flush() + + lxc_read, lxc_write = os.pipe() + + pid = self.container.attach(work, self.dest, stdout=lxc_write) + os.close(lxc_write) + + chk = hashlib.sha1() + with open(self.src, 'r') as dfile: + data = dfile.read(self.buffer_size) + while (self.buffer_size == len(data)): + chk.update(data) + data = dfile.read(self.buffer_size) + chk.update(data) + + lxc_chk = os.read(lxc_read, 100) # read digest from container.... + os.close(lxc_read) + + self.files_equal = lxc_chk == chk.hexdigest() + self.local_sum = chk.hexdigest() + self.container_sum = lxc_chk + + def copy(self): + with self.lxc_started(): + self._verify() + if not self.files_equal: + def work(dest): + infno = sys.stdin.fileno() + with open(dest, 'w') as outfile: + data = os.read(infno, self.buffer_size) + while (self.buffer_size == len(data)): + outfile.write(data) + data = os.read(infno, self.buffer_size) + outfile.write(data) + + lxc_read, lxc_write = os.pipe() + + pid = self.container.attach(work, self.dest, stdin=lxc_read) + os.close(lxc_read) + + with open(self.src, 'r') as infile: + data = infile.read(self.buffer_size) + while (self.buffer_size == len(data)): + os.write(lxc_write, data) + data = infile.read(self.buffer_size) + os.write(lxc_write, data) + + os.close(lxc_write) + os.waitpid(pid, 0) + self.changed = True + + def has_changed(self): + return self.changed + + +def main(): + module = AnsibleModule( + argument_spec = dict( + name = dict(required=True, default=None), + src = dict(required=True, default=None), + dest = dict(required=True, default=None), + ) + ) + + manager = LxcManager(module) + + image_id = None + msg = '' + do_build = False + + manager.copy() + + module.exit_json(failed=False, changed=manager.has_changed(), msg="File copied") + +# import module snippets +from ansible.module_utils.basic import * +if __name__ == '__main__': + main() diff --git a/playbook.yml b/playbook.yml new file mode 100644 index 0000000..a676e4e --- /dev/null +++ b/playbook.yml @@ -0,0 +1,18 @@ +--- +- name: test playbook for lxc_copy + hosts: all + tasks: + - name: copy single file in container + lxc_copy: + args: + name: ansible_test + src: files/verkauf.jpg + dest: /tmp/foo + + - name: copy files in container + lxc_copy: + args: + name: ansible_test + src: files/{{ item }} + dest: /tmp/{{ item }} + with_items: ['a', 'b', 'c', 'd', 'e', 'f', 'g']