Import upstream version 0.0+git20210525.76e43f7
Debian Janitor
2 years ago
0 | name: Static analysis | |
1 | on: | |
2 | - push | |
3 | - pull_request | |
4 | ||
5 | jobs: | |
6 | test: | |
7 | runs-on: ubuntu-20.04 | |
8 | steps: | |
9 | - name: Install Go | |
10 | uses: actions/setup-go@v2 | |
11 | with: | |
12 | go-version: 1.16.x | |
13 | ||
14 | - name: Checkout code | |
15 | uses: actions/checkout@v2 | |
16 | ||
17 | - name: Validate Go modules | |
18 | run: | | |
19 | make update-gomod | |
20 | git diff --exit-code | |
21 | ||
22 | - name: Install dependencies | |
23 | run: | | |
24 | sudo add-apt-repository ppa:ubuntu-lxc/daily -y | |
25 | sudo apt-get install -qq lxc-dev pkg-config | |
26 | go get golang.org/x/lint/golint | |
27 | go get golang.org/x/tools/cmd/goimports | |
28 | ||
29 | - name: Static analysis | |
30 | run: make all |
0 | name: CI tests | |
1 | on: | |
2 | - push | |
3 | - pull_request | |
4 | ||
5 | jobs: | |
6 | test: | |
7 | strategy: | |
8 | fail-fast: false | |
9 | matrix: | |
10 | go: | |
11 | - 1.13.x | |
12 | - 1.14.x | |
13 | - 1.15.x | |
14 | - 1.16.x | |
15 | os: | |
16 | - ubuntu-18.04 | |
17 | - ubuntu-20.04 | |
18 | runs-on: ${{ matrix.os }} | |
19 | steps: | |
20 | - name: Install Go | |
21 | uses: actions/setup-go@v2 | |
22 | with: | |
23 | go-version: ${{ matrix.go }} | |
24 | ||
25 | - name: Checkout code | |
26 | uses: actions/checkout@v2 | |
27 | ||
28 | - name: Install dependencies | |
29 | run: | | |
30 | sudo add-apt-repository ppa:ubuntu-lxc/daily -y | |
31 | sudo apt-get install -qq lxc lxc-dev pkg-config uidmap busybox | |
32 | ||
33 | - name: Setup test environment | |
34 | run: | | |
35 | # Setup uid/gid and veth allocations | |
36 | echo "${USER}:100000:65536" | sudo tee /etc/subuid | |
37 | echo "${USER}:100000:65536" | sudo tee /etc/subgid | |
38 | echo "${USER} veth lxcbr0 10" | sudo tee -a /etc/lxc/lxc-usernet | |
39 | ||
40 | # Local user configuration for userns | |
41 | mkdir -p ~/.config/lxc/ | |
42 | cp /etc/lxc/default.conf ~/.config/lxc/default.conf | |
43 | echo "lxc.idmap = u 0 100000 65536" | tee -a ~/.config/lxc/default.conf | |
44 | echo "lxc.idmap = g 0 100000 65536" | tee -a ~/.config/lxc/default.conf | |
45 | ||
46 | # Allow traversal to the containers | |
47 | mkdir -p ~/.local/share/lxc | |
48 | chmod +x ~/ ~/.local ~/.local/share ~/.local/share/lxc | |
49 | ||
50 | - name: Build the test | |
51 | run: | |
52 | go test -c -coverprofile=profile | |
53 | ||
54 | - name: Unprivileged tests | |
55 | env: | |
56 | DOWNLOAD_KEYSERVER: keyserver.ubuntu.com | |
57 | run: | | |
58 | # Make all cgroups writable | |
59 | for d in /sys/fs/cgroup/*; do | |
60 | [ -f $d/cgroup.clone_children ] && echo 1 | sudo tee $d/cgroup.clone_children | |
61 | [ -f $d/cgroup.use_hierarchy ] && echo 1 | sudo tee $d/cgroup.use_hierarchy | |
62 | ||
63 | sudo mkdir -p $d/lxc-test | |
64 | sudo chown -R $USER: $d/lxc-test | |
65 | echo $$ | sudo tee $d/lxc-test/cgroup.procs | |
66 | done | |
67 | ||
68 | # Run the unprivileged tests | |
69 | ./go-lxc.test -test.v -test.coverprofile=/tmp/unpriv.out | |
70 | ||
71 | - name: Privileged tests | |
72 | env: | |
73 | DOWNLOAD_KEYSERVER: keyserver.ubuntu.com | |
74 | run: | |
75 | sudo -E ./go-lxc.test -test.v -test.coverprofile=/tmp/priv.out | |
76 | ||
77 | - name: Code coverage | |
78 | run: make cover |
0 | language: go | |
1 | ||
2 | os: | |
3 | - linux | |
4 | ||
5 | go: | |
6 | - 1.10.x | |
7 | - 1.11.x | |
8 | - 1.12.x | |
9 | - 1.13.x | |
10 | - 1.14.x | |
11 | - tip | |
12 | ||
13 | matrix: | |
14 | fast_finish: true | |
15 | allow_failures: | |
16 | - go: tip | |
17 | ||
18 | before_install: | |
19 | - sudo add-apt-repository ppa:ubuntu-lxc/daily -y | |
20 | - sudo apt-get update | |
21 | - sudo apt-get install -qq lxc lxc-dev uidmap busybox | |
22 | - echo "${USER}:100000:65536" | sudo tee /etc/subuid | |
23 | - echo "${USER}:100000:65536" | sudo tee /etc/subgid | |
24 | - echo "${USER} veth lxcbr0 10" | sudo tee -a /etc/lxc/lxc-usernet | |
25 | - mkdir -p ${HOME}/.config/lxc/ | |
26 | - cp /etc/lxc/default.conf ${HOME}/.config/lxc/default.conf | |
27 | - echo "lxc.id_map = u 0 100000 65536" | sudo tee -a ${HOME}/.config/lxc/default.conf | |
28 | - echo "lxc.id_map = g 0 100000 65536" | sudo tee -a ${HOME}/.config/lxc/default.conf | |
29 | - "make setup-test-cgroup" | |
30 | - mkdir -p ${HOME}/.local/share/lxc | |
31 | - chmod +x ${HOME} | |
32 | - chmod +x ${HOME}/.local | |
33 | - chmod +x ${HOME}/.local/share | |
34 | - chmod +x ${HOME}/.local/share/lxc | |
35 | ||
36 | install: | |
37 | - go get golang.org/x/tools/cmd/goimports | |
38 | - go get golang.org/x/sys/unix | |
39 | - go get gopkg.in/lxc/go-lxc.v2 | |
40 | ||
41 | script: | |
42 | - "make all" | |
43 | - "make test" | |
44 | - "make test-race" | |
45 | - "make test-privileged" | |
46 | - "make test-privileged-race" | |
47 | - "make cover" | |
48 | ||
49 | notifications: | |
50 | webhooks: https://linuxcontainers.org/webhook-lxcbot/ |
50 | 50 | ctags: |
51 | 51 | @ctags -R --languages=c,go |
52 | 52 | |
53 | update-gomod: | |
54 | go get -t -v -d -u ./... | |
55 | go mod tidy | |
56 | ||
53 | 57 | scope: |
54 | 58 | @echo "$(OK_COLOR)==> Exported container calls in container.go $(NO_COLOR)" |
55 | 59 | @/bin/grep -E "\bc+\.([A-Z])\w+" container.go || true |
56 | 60 | |
57 | setup-test-cgroup: | |
58 | for d in /sys/fs/cgroup/*; do \ | |
59 | [ -f $$d/cgroup.clone_children ] && echo 1 | sudo tee $$d/cgroup.clone_children; \ | |
60 | [ -f $$d/cgroup.use_hierarchy ] && echo 1 | sudo tee $$d/cgroup.use_hierarchy; \ | |
61 | sudo mkdir -p $$d/lxc; \ | |
62 | sudo chown -R $$USER: $$d/lxc; \ | |
63 | done | |
64 | ||
65 | 61 | .PHONY: all format test doc vet lint ctags |
0 | // Copyright © 2013, 2014, The Go-LXC Authors. All rights reserved. | |
1 | // Use of this source code is governed by a LGPLv2.1 | |
2 | // license that can be found in the LICENSE file. | |
3 | ||
4 | package lxc | |
5 | ||
6 | // #cgo CFLAGS: -fvisibility=hidden | |
7 | import "C" |
0 | // Copyright © 2013, 2014, The Go-LXC Authors. All rights reserved. | |
1 | // Use of this source code is governed by a LGPLv2.1 | |
2 | // license that can be found in the LICENSE file. | |
3 | ||
4 | // +build >go1.10,linux,cgo | |
5 | ||
6 | package lxc | |
7 | ||
8 | // #cgo CFLAGS: -fvisibility=hidden | |
9 | import "C" |
17 | 17 | "os/exec" |
18 | 18 | "path" |
19 | 19 | "path/filepath" |
20 | "reflect" | |
21 | 20 | "strconv" |
22 | 21 | "strings" |
23 | 22 | "sync" |
111 | 110 | if C.lxc_container_put(c.container) == -1 { |
112 | 111 | return ErrReleaseFailed |
113 | 112 | } |
113 | ||
114 | c.container = nil | |
115 | ||
114 | 116 | return nil |
115 | 117 | } |
116 | 118 | |
117 | 119 | func (c *Container) name() string { |
120 | if c.container == nil { | |
121 | return "" | |
122 | } | |
123 | ||
118 | 124 | return C.GoString(c.container.name) |
119 | 125 | } |
120 | 126 | |
136 | 142 | |
137 | 143 | // Caller needs to hold the lock |
138 | 144 | func (c *Container) defined() bool { |
145 | if c.container == nil { | |
146 | return false | |
147 | } | |
148 | ||
139 | 149 | return bool(C.go_lxc_defined(c.container)) |
140 | 150 | } |
141 | 151 | |
149 | 159 | |
150 | 160 | // Caller needs to hold the lock |
151 | 161 | func (c *Container) running() bool { |
162 | if c.container == nil { | |
163 | return false | |
164 | } | |
165 | ||
152 | 166 | return bool(C.go_lxc_running(c.container)) |
153 | 167 | } |
154 | 168 | |
165 | 179 | c.mu.RLock() |
166 | 180 | defer c.mu.RUnlock() |
167 | 181 | |
182 | if c.container == nil { | |
183 | return false | |
184 | } | |
185 | ||
168 | 186 | return bool(C.go_lxc_may_control(c.container)) |
169 | 187 | } |
170 | 188 | |
172 | 190 | func (c *Container) CreateSnapshot() (*Snapshot, error) { |
173 | 191 | c.mu.Lock() |
174 | 192 | defer c.mu.Unlock() |
193 | ||
194 | if c.container == nil { | |
195 | return nil, ErrNotDefined | |
196 | } | |
175 | 197 | |
176 | 198 | if err := c.makeSure(isDefined | isNotRunning); err != nil { |
177 | 199 | return nil, err |
189 | 211 | c.mu.Lock() |
190 | 212 | defer c.mu.Unlock() |
191 | 213 | |
214 | if c.container == nil { | |
215 | return ErrNotDefined | |
216 | } | |
217 | ||
192 | 218 | if err := c.makeSure(isDefined); err != nil { |
193 | 219 | return err |
194 | 220 | } |
210 | 236 | c.mu.Lock() |
211 | 237 | defer c.mu.Unlock() |
212 | 238 | |
239 | if c.container == nil { | |
240 | return ErrNotDefined | |
241 | } | |
242 | ||
213 | 243 | if err := c.makeSure(isDefined); err != nil { |
214 | 244 | return err |
215 | 245 | } |
228 | 258 | c.mu.Lock() |
229 | 259 | defer c.mu.Unlock() |
230 | 260 | |
261 | if c.container == nil { | |
262 | return ErrNotDefined | |
263 | } | |
264 | ||
231 | 265 | if err := c.makeSure(isDefined | isGreaterEqualThanLXC11); err != nil { |
232 | 266 | return err |
233 | 267 | } |
243 | 277 | c.mu.RLock() |
244 | 278 | defer c.mu.RUnlock() |
245 | 279 | |
280 | if c.container == nil { | |
281 | return nil, ErrNotDefined | |
282 | } | |
283 | ||
246 | 284 | if err := c.makeSure(isDefined); err != nil { |
247 | 285 | return nil, err |
248 | 286 | } |
256 | 294 | return nil, ErrNoSnapshot |
257 | 295 | } |
258 | 296 | |
259 | hdr := reflect.SliceHeader{ | |
260 | Data: uintptr(unsafe.Pointer(csnapshots)), | |
261 | Len: size, | |
262 | Cap: size, | |
263 | } | |
264 | gosnapshots := *(*[]C.struct_lxc_snapshot)(unsafe.Pointer(&hdr)) | |
265 | ||
297 | gosnapshots := (*[(1 << 26) - 1]C.struct_lxc_snapshot)(unsafe.Pointer(csnapshots))[:size:size] | |
266 | 298 | snapshots := make([]Snapshot, size, size) |
267 | 299 | for i := 0; i < size; i++ { |
268 | 300 | snapshots[i] = Snapshot{ |
299 | 331 | c.mu.RLock() |
300 | 332 | defer c.mu.RUnlock() |
301 | 333 | |
334 | if c.container == nil { | |
335 | return -1 | |
336 | } | |
337 | ||
302 | 338 | return int(C.go_lxc_init_pid(c.container)) |
303 | 339 | } |
304 | 340 | |
306 | 342 | func (c *Container) InitPidFd() (*os.File, error) { |
307 | 343 | c.mu.RLock() |
308 | 344 | defer c.mu.RUnlock() |
345 | ||
346 | if c.container == nil { | |
347 | return nil, ErrNotDefined | |
348 | } | |
309 | 349 | |
310 | 350 | pidfd := int(C.go_lxc_init_pidfd(c.container)) |
311 | 351 | if pidfd < 0 { |
320 | 360 | c.mu.RLock() |
321 | 361 | defer c.mu.RUnlock() |
322 | 362 | |
363 | if c.container == nil { | |
364 | return nil, ErrNotDefined | |
365 | } | |
366 | ||
323 | 367 | devptsFd := int(C.go_lxc_devpts_fd(c.container)) |
324 | 368 | if devptsFd < 0 { |
325 | 369 | return nil, unix.Errno(unix.EBADF) |
333 | 377 | c.mu.RLock() |
334 | 378 | defer c.mu.RUnlock() |
335 | 379 | |
380 | if c.container == nil { | |
381 | return nil, ErrNotDefined | |
382 | } | |
383 | ||
336 | 384 | notifyFd := int(C.go_lxc_seccomp_notify_fd(c.container)) |
337 | 385 | if notifyFd < 0 { |
338 | 386 | return nil, unix.Errno(unix.EBADF) |
346 | 394 | c.mu.RLock() |
347 | 395 | defer c.mu.RUnlock() |
348 | 396 | |
397 | if c.container == nil { | |
398 | return nil, ErrNotDefined | |
399 | } | |
400 | ||
349 | 401 | notifyFd := int(C.go_lxc_seccomp_notify_fd_active(c.container)) |
350 | 402 | if notifyFd < 0 { |
351 | 403 | return nil, unix.Errno(unix.EBADF) |
359 | 411 | c.mu.RLock() |
360 | 412 | defer c.mu.RUnlock() |
361 | 413 | |
414 | if c.container == nil { | |
415 | return false | |
416 | } | |
417 | ||
362 | 418 | return bool(c.container.daemonize) |
363 | 419 | } |
364 | 420 | |
366 | 422 | func (c *Container) WantDaemonize(state bool) error { |
367 | 423 | c.mu.Lock() |
368 | 424 | defer c.mu.Unlock() |
425 | ||
426 | if c.container == nil { | |
427 | return ErrNotDefined | |
428 | } | |
369 | 429 | |
370 | 430 | if !bool(C.go_lxc_want_daemonize(c.container, C.bool(state))) { |
371 | 431 | return ErrDaemonizeFailed |
379 | 439 | c.mu.Lock() |
380 | 440 | defer c.mu.Unlock() |
381 | 441 | |
442 | if c.container == nil { | |
443 | return ErrNotDefined | |
444 | } | |
445 | ||
382 | 446 | if !bool(C.go_lxc_want_close_all_fds(c.container, C.bool(state))) { |
383 | 447 | return ErrCloseAllFdsFailed |
384 | 448 | } |
397 | 461 | func (c *Container) Freeze() error { |
398 | 462 | c.mu.Lock() |
399 | 463 | defer c.mu.Unlock() |
464 | ||
465 | if c.container == nil { | |
466 | return ErrNotDefined | |
467 | } | |
400 | 468 | |
401 | 469 | // check the state using lockless version |
402 | 470 | if c.state() == FROZEN { |
414 | 482 | func (c *Container) Unfreeze() error { |
415 | 483 | c.mu.Lock() |
416 | 484 | defer c.mu.Unlock() |
485 | ||
486 | if c.container == nil { | |
487 | return ErrNotDefined | |
488 | } | |
417 | 489 | |
418 | 490 | if err := c.makeSure(isRunning); err != nil { |
419 | 491 | return err |
529 | 601 | c.mu.Lock() |
530 | 602 | defer c.mu.Unlock() |
531 | 603 | |
604 | if c.container == nil { | |
605 | return ErrNotDefined | |
606 | } | |
607 | ||
532 | 608 | if err := c.makeSure(isNotRunning); err != nil { |
533 | 609 | return err |
534 | 610 | } |
543 | 619 | func (c *Container) StartWithArgs(args []string) error { |
544 | 620 | c.mu.Lock() |
545 | 621 | defer c.mu.Unlock() |
622 | ||
623 | if c.container == nil { | |
624 | return ErrNotDefined | |
625 | } | |
546 | 626 | |
547 | 627 | if err := c.makeSure(isNotRunning); err != nil { |
548 | 628 | return err |
559 | 639 | func (c *Container) StartExecute(args []string) error { |
560 | 640 | c.mu.Lock() |
561 | 641 | defer c.mu.Unlock() |
642 | ||
643 | if c.container == nil { | |
644 | return ErrNotDefined | |
645 | } | |
562 | 646 | |
563 | 647 | if err := c.makeSure(isNotRunning); err != nil { |
564 | 648 | return err |
607 | 691 | c.mu.Lock() |
608 | 692 | defer c.mu.Unlock() |
609 | 693 | |
694 | if c.container == nil { | |
695 | return ErrNotDefined | |
696 | } | |
697 | ||
610 | 698 | if err := c.makeSure(isRunning); err != nil { |
611 | 699 | return err |
612 | 700 | } |
622 | 710 | c.mu.Lock() |
623 | 711 | defer c.mu.Unlock() |
624 | 712 | |
713 | if c.container == nil { | |
714 | return ErrNotDefined | |
715 | } | |
716 | ||
625 | 717 | if err := c.makeSure(isRunning); err != nil { |
626 | 718 | return err |
627 | 719 | } |
637 | 729 | c.mu.Lock() |
638 | 730 | defer c.mu.Unlock() |
639 | 731 | |
732 | if c.container == nil { | |
733 | return ErrNotDefined | |
734 | } | |
735 | ||
640 | 736 | if err := c.makeSure(isRunning); err != nil { |
641 | 737 | return err |
642 | 738 | } |
652 | 748 | c.mu.Lock() |
653 | 749 | defer c.mu.Unlock() |
654 | 750 | |
751 | if c.container == nil { | |
752 | return ErrNotDefined | |
753 | } | |
754 | ||
655 | 755 | if err := c.makeSure(isDefined | isNotRunning); err != nil { |
656 | 756 | return err |
657 | 757 | } |
666 | 766 | func (c *Container) DestroyWithAllSnapshots() error { |
667 | 767 | c.mu.Lock() |
668 | 768 | defer c.mu.Unlock() |
769 | ||
770 | if c.container == nil { | |
771 | return ErrNotDefined | |
772 | } | |
669 | 773 | |
670 | 774 | if err := c.makeSure(isDefined | isNotRunning | isGreaterEqualThanLXC11); err != nil { |
671 | 775 | return err |
739 | 843 | c.mu.Lock() |
740 | 844 | defer c.mu.Unlock() |
741 | 845 | |
846 | if c.container == nil { | |
847 | return ErrNotDefined | |
848 | } | |
849 | ||
742 | 850 | if err := c.makeSure(isDefined | isNotRunning); err != nil { |
743 | 851 | return err |
744 | 852 | } |
757 | 865 | c.mu.Lock() |
758 | 866 | defer c.mu.Unlock() |
759 | 867 | |
868 | if c.container == nil { | |
869 | return false | |
870 | } | |
871 | ||
760 | 872 | cstate := C.CString(state.String()) |
761 | 873 | defer C.free(unsafe.Pointer(cstate)) |
762 | 874 | |
767 | 879 | func (c *Container) ConfigFileName() string { |
768 | 880 | c.mu.RLock() |
769 | 881 | defer c.mu.RUnlock() |
882 | ||
883 | if c.container == nil { | |
884 | return "" | |
885 | } | |
770 | 886 | |
771 | 887 | // allocated in lxc.c |
772 | 888 | configFileName := C.go_lxc_config_file_name(c.container) |
776 | 892 | } |
777 | 893 | |
778 | 894 | func (c *Container) configItem(key string) []string { |
895 | if c.container == nil { | |
896 | return nil | |
897 | } | |
898 | ||
779 | 899 | ckey := C.CString(key) |
780 | 900 | defer C.free(unsafe.Pointer(ckey)) |
781 | 901 | |
796 | 916 | } |
797 | 917 | |
798 | 918 | func (c *Container) setConfigItem(key string, value string) error { |
919 | if c.container == nil { | |
920 | return ErrNotDefined | |
921 | } | |
922 | ||
799 | 923 | ckey := C.CString(key) |
800 | 924 | defer C.free(unsafe.Pointer(ckey)) |
801 | 925 | |
817 | 941 | } |
818 | 942 | |
819 | 943 | func (c *Container) runningConfigItem(key string) []string { |
944 | if c.container == nil { | |
945 | return nil | |
946 | } | |
947 | ||
820 | 948 | ckey := C.CString(key) |
821 | 949 | defer C.free(unsafe.Pointer(ckey)) |
822 | 950 | |
853 | 981 | } |
854 | 982 | |
855 | 983 | func (c *Container) setCgroupItem(key string, value string) error { |
984 | if c.container == nil { | |
985 | return ErrNotDefined | |
986 | } | |
987 | ||
856 | 988 | ckey := C.CString(key) |
857 | 989 | defer C.free(unsafe.Pointer(ckey)) |
858 | 990 | |
886 | 1018 | c.mu.Lock() |
887 | 1019 | defer c.mu.Unlock() |
888 | 1020 | |
1021 | if c.container == nil { | |
1022 | return | |
1023 | } | |
1024 | ||
889 | 1025 | C.go_lxc_clear_config(c.container) |
890 | 1026 | } |
891 | 1027 | |
894 | 1030 | c.mu.Lock() |
895 | 1031 | defer c.mu.Unlock() |
896 | 1032 | |
1033 | if c.container == nil { | |
1034 | return ErrNotDefined | |
1035 | } | |
1036 | ||
897 | 1037 | ckey := C.CString(key) |
898 | 1038 | defer C.free(unsafe.Pointer(ckey)) |
899 | 1039 | |
907 | 1047 | func (c *Container) ConfigKeys(key ...string) []string { |
908 | 1048 | c.mu.RLock() |
909 | 1049 | defer c.mu.RUnlock() |
1050 | ||
1051 | if c.container == nil { | |
1052 | return nil | |
1053 | } | |
910 | 1054 | |
911 | 1055 | var ret string |
912 | 1056 | if key != nil && len(key) == 1 { |
934 | 1078 | c.mu.Lock() |
935 | 1079 | defer c.mu.Unlock() |
936 | 1080 | |
1081 | if c.container == nil { | |
1082 | return ErrNotDefined | |
1083 | } | |
1084 | ||
937 | 1085 | cpath := C.CString(path) |
938 | 1086 | defer C.free(unsafe.Pointer(cpath)) |
939 | 1087 | |
944 | 1092 | } |
945 | 1093 | |
946 | 1094 | func (c *Container) saveConfigFile(path string) error { |
1095 | if c.container == nil { | |
1096 | return ErrNotDefined | |
1097 | } | |
1098 | ||
947 | 1099 | cpath := C.CString(path) |
948 | 1100 | defer C.free(unsafe.Pointer(cpath)) |
949 | 1101 | |
962 | 1114 | } |
963 | 1115 | |
964 | 1116 | func (c *Container) configPath() string { |
1117 | if c.container == nil { | |
1118 | return "" | |
1119 | } | |
1120 | ||
965 | 1121 | return C.GoString(C.go_lxc_get_config_path(c.container)) |
966 | 1122 | } |
967 | 1123 | |
977 | 1133 | func (c *Container) SetConfigPath(path string) error { |
978 | 1134 | c.mu.Lock() |
979 | 1135 | defer c.mu.Unlock() |
1136 | ||
1137 | if c.container == nil { | |
1138 | return ErrNotDefined | |
1139 | } | |
980 | 1140 | |
981 | 1141 | cpath := C.CString(path) |
982 | 1142 | defer C.free(unsafe.Pointer(cpath)) |
1232 | 1392 | c.mu.Lock() |
1233 | 1393 | defer c.mu.Unlock() |
1234 | 1394 | |
1395 | if c.container == nil { | |
1396 | return -1, ErrNotDefined | |
1397 | } | |
1398 | ||
1235 | 1399 | // FIXME: Make idiomatic |
1236 | 1400 | if err := c.makeSure(isRunning); err != nil { |
1237 | 1401 | return -1, err |
1250 | 1414 | func (c *Container) Console(options ConsoleOptions) error { |
1251 | 1415 | c.mu.Lock() |
1252 | 1416 | defer c.mu.Unlock() |
1417 | ||
1418 | if c.container == nil { | |
1419 | return ErrNotDefined | |
1420 | } | |
1253 | 1421 | |
1254 | 1422 | if err := c.makeSure(isRunning); err != nil { |
1255 | 1423 | return err |
1274 | 1442 | c.mu.Lock() |
1275 | 1443 | defer c.mu.Unlock() |
1276 | 1444 | |
1445 | if c.container == nil { | |
1446 | return ErrNotDefined | |
1447 | } | |
1448 | ||
1277 | 1449 | if err := c.makeSure(isRunning); err != nil { |
1278 | 1450 | return err |
1279 | 1451 | } |
1292 | 1464 | |
1293 | 1465 | cwd := C.CString(options.Cwd) |
1294 | 1466 | defer C.free(unsafe.Pointer(cwd)) |
1467 | ||
1468 | groups := makeGroups(options.Groups) | |
1295 | 1469 | |
1296 | 1470 | ret := int(C.go_lxc_attach(c.container, |
1297 | 1471 | C.bool(options.ClearEnv), |
1299 | 1473 | C.long(options.Arch), |
1300 | 1474 | C.uid_t(options.UID), |
1301 | 1475 | C.gid_t(options.GID), |
1476 | groups, | |
1302 | 1477 | C.int(options.StdinFd), |
1303 | 1478 | C.int(options.StdoutFd), |
1304 | 1479 | C.int(options.StderrFd), |
1305 | 1480 | cwd, |
1306 | 1481 | cenv, |
1307 | 1482 | cenvToKeep, |
1483 | C.int(attachFlags(options)), | |
1308 | 1484 | )) |
1309 | 1485 | if ret < 0 { |
1310 | 1486 | return ErrAttachFailed |
1312 | 1488 | return nil |
1313 | 1489 | } |
1314 | 1490 | |
1491 | func attachFlags(opts AttachOptions) int { | |
1492 | flags := C.LXC_ATTACH_DEFAULT | |
1493 | ||
1494 | if opts.RemountSysProc { | |
1495 | flags |= C.LXC_ATTACH_REMOUNT_PROC_SYS | |
1496 | } | |
1497 | ||
1498 | if opts.ElevatedPrivileges { | |
1499 | flags &^= (C.LXC_ATTACH_MOVE_TO_CGROUP | C.LXC_ATTACH_DROP_CAPABILITIES | C.LXC_ATTACH_LSM_EXEC) | |
1500 | } | |
1501 | return flags | |
1502 | } | |
1503 | ||
1504 | func makeGroups(groups []int) C.struct_lxc_groups_t { | |
1505 | if len(groups) == 0 { | |
1506 | return C.struct_lxc_groups_t{size: 0, list: nil} | |
1507 | } | |
1508 | l := make([]C.gid_t, len(groups)) | |
1509 | for i, g := range groups { | |
1510 | l[i] = C.gid_t(g) | |
1511 | } | |
1512 | return C.struct_lxc_groups_t{size: C.size_t(len(groups)), list: &l[0]} | |
1513 | } | |
1514 | ||
1315 | 1515 | func (c *Container) runCommandStatus(args []string, options AttachOptions) (int, error) { |
1516 | if c.container == nil { | |
1517 | return -1, ErrNotDefined | |
1518 | } | |
1519 | ||
1316 | 1520 | if len(args) == 0 { |
1317 | 1521 | return -1, ErrInsufficientNumberOfArguments |
1318 | 1522 | } |
1341 | 1545 | |
1342 | 1546 | cwd := C.CString(options.Cwd) |
1343 | 1547 | defer C.free(unsafe.Pointer(cwd)) |
1548 | ||
1549 | groups := makeGroups(options.Groups) | |
1344 | 1550 | |
1345 | 1551 | ret := int(C.go_lxc_attach_run_wait( |
1346 | 1552 | c.container, |
1349 | 1555 | C.long(options.Arch), |
1350 | 1556 | C.uid_t(options.UID), |
1351 | 1557 | C.gid_t(options.GID), |
1558 | groups, | |
1352 | 1559 | C.int(options.StdinFd), |
1353 | 1560 | C.int(options.StdoutFd), |
1354 | 1561 | C.int(options.StderrFd), |
1356 | 1563 | cenv, |
1357 | 1564 | cenvToKeep, |
1358 | 1565 | cargs, |
1566 | C.int(attachFlags(options)), | |
1359 | 1567 | )) |
1360 | 1568 | |
1361 | 1569 | if ret < 0 { |
1410 | 1618 | |
1411 | 1619 | cwd := C.CString(options.Cwd) |
1412 | 1620 | defer C.free(unsafe.Pointer(cwd)) |
1621 | ||
1622 | groups := makeGroups(options.Groups) | |
1413 | 1623 | |
1414 | 1624 | var attachedPid C.pid_t |
1415 | 1625 | ret := int(C.go_lxc_attach_no_wait( |
1419 | 1629 | C.long(options.Arch), |
1420 | 1630 | C.uid_t(options.UID), |
1421 | 1631 | C.gid_t(options.GID), |
1632 | groups, | |
1422 | 1633 | C.int(options.StdinFd), |
1423 | 1634 | C.int(options.StdoutFd), |
1424 | 1635 | C.int(options.StderrFd), |
1427 | 1638 | cenvToKeep, |
1428 | 1639 | cargs, |
1429 | 1640 | &attachedPid, |
1641 | C.int(attachFlags(options)), | |
1430 | 1642 | )) |
1431 | 1643 | |
1432 | 1644 | if ret < 0 { |
1457 | 1669 | func (c *Container) Interfaces() ([]string, error) { |
1458 | 1670 | c.mu.RLock() |
1459 | 1671 | defer c.mu.RUnlock() |
1672 | ||
1673 | if c.container == nil { | |
1674 | return nil, ErrNotDefined | |
1675 | } | |
1460 | 1676 | |
1461 | 1677 | if err := c.makeSure(isRunning); err != nil { |
1462 | 1678 | return nil, err |
1526 | 1742 | c.mu.RLock() |
1527 | 1743 | defer c.mu.RUnlock() |
1528 | 1744 | |
1745 | if c.container == nil { | |
1746 | return nil, ErrNotDefined | |
1747 | } | |
1748 | ||
1529 | 1749 | if err := c.makeSure(isRunning); err != nil { |
1530 | 1750 | return nil, err |
1531 | 1751 | } |
1545 | 1765 | c.mu.RLock() |
1546 | 1766 | defer c.mu.RUnlock() |
1547 | 1767 | |
1768 | if c.container == nil { | |
1769 | return nil, ErrNotDefined | |
1770 | } | |
1771 | ||
1548 | 1772 | if err := c.makeSure(isRunning); err != nil { |
1549 | 1773 | return nil, err |
1550 | 1774 | } |
1566 | 1790 | func (c *Container) IPv6Address(interfaceName string) ([]string, error) { |
1567 | 1791 | c.mu.RLock() |
1568 | 1792 | defer c.mu.RUnlock() |
1793 | ||
1794 | if c.container == nil { | |
1795 | return nil, ErrNotDefined | |
1796 | } | |
1569 | 1797 | |
1570 | 1798 | if err := c.makeSure(isRunning); err != nil { |
1571 | 1799 | return nil, err |
1604 | 1832 | } |
1605 | 1833 | |
1606 | 1834 | func (c *Container) ipAddresses() ([]string, error) { |
1835 | if c.container == nil { | |
1836 | return nil, ErrNotDefined | |
1837 | } | |
1838 | ||
1607 | 1839 | if err := c.makeSure(isRunning); err != nil { |
1608 | 1840 | return nil, err |
1609 | 1841 | } |
1629 | 1861 | c.mu.RLock() |
1630 | 1862 | defer c.mu.RUnlock() |
1631 | 1863 | |
1864 | if c.container == nil { | |
1865 | return nil, ErrNotDefined | |
1866 | } | |
1867 | ||
1632 | 1868 | if err := c.makeSure(isRunning); err != nil { |
1633 | 1869 | return nil, err |
1634 | 1870 | } |
1647 | 1883 | func (c *Container) IPv6Addresses() ([]string, error) { |
1648 | 1884 | c.mu.RLock() |
1649 | 1885 | defer c.mu.RUnlock() |
1886 | ||
1887 | if c.container == nil { | |
1888 | return nil, ErrNotDefined | |
1889 | } | |
1650 | 1890 | |
1651 | 1891 | if err := c.makeSure(isRunning); err != nil { |
1652 | 1892 | return nil, err |
1726 | 1966 | c.mu.Lock() |
1727 | 1967 | defer c.mu.Unlock() |
1728 | 1968 | |
1969 | if c.container == nil { | |
1970 | return ErrNotDefined | |
1971 | } | |
1972 | ||
1729 | 1973 | if err := c.makeSure(isRunning | isPrivileged); err != nil { |
1730 | 1974 | return err |
1731 | 1975 | } |
1754 | 1998 | c.mu.Lock() |
1755 | 1999 | defer c.mu.Unlock() |
1756 | 2000 | |
2001 | if c.container == nil { | |
2002 | return ErrNotDefined | |
2003 | } | |
2004 | ||
1757 | 2005 | if err := c.makeSure(isRunning | isPrivileged); err != nil { |
1758 | 2006 | return err |
1759 | 2007 | } |
1782 | 2030 | c.mu.Lock() |
1783 | 2031 | defer c.mu.Unlock() |
1784 | 2032 | |
2033 | if c.container == nil { | |
2034 | return ErrNotDefined | |
2035 | } | |
2036 | ||
1785 | 2037 | if err := c.makeSure(isRunning | isGreaterEqualThanLXC11); err != nil { |
1786 | 2038 | return err |
1787 | 2039 | } |
1803 | 2055 | c.mu.Lock() |
1804 | 2056 | defer c.mu.Unlock() |
1805 | 2057 | |
2058 | if c.container == nil { | |
2059 | return ErrNotDefined | |
2060 | } | |
2061 | ||
1806 | 2062 | if err := c.makeSure(isGreaterEqualThanLXC11); err != nil { |
1807 | 2063 | return err |
1808 | 2064 | } |
1822 | 2078 | func (c *Container) Migrate(cmd uint, opts MigrateOptions) error { |
1823 | 2079 | c.mu.Lock() |
1824 | 2080 | defer c.mu.Unlock() |
2081 | ||
2082 | if c.container == nil { | |
2083 | return ErrNotDefined | |
2084 | } | |
1825 | 2085 | |
1826 | 2086 | if err := c.makeSure(isNotDefined | isGreaterEqualThanLXC20); err != nil { |
1827 | 2087 | return err |
1879 | 2139 | c.mu.Lock() |
1880 | 2140 | defer c.mu.Unlock() |
1881 | 2141 | |
2142 | if c.container == nil { | |
2143 | return ErrNotDefined | |
2144 | } | |
2145 | ||
1882 | 2146 | if err := c.makeSure(isRunning | isPrivileged | isGreaterEqualThanLXC11); err != nil { |
1883 | 2147 | return err |
1884 | 2148 | } |
1900 | 2164 | c.mu.Lock() |
1901 | 2165 | defer c.mu.Unlock() |
1902 | 2166 | |
2167 | if c.container == nil { | |
2168 | return ErrNotDefined | |
2169 | } | |
2170 | ||
1903 | 2171 | if err := c.makeSure(isRunning | isPrivileged | isGreaterEqualThanLXC11); err != nil { |
1904 | 2172 | return err |
1905 | 2173 | } |
1917 | 2185 | func (c *Container) DetachInterfaceRename(source, target string) error { |
1918 | 2186 | c.mu.Lock() |
1919 | 2187 | defer c.mu.Unlock() |
2188 | ||
2189 | if c.container == nil { | |
2190 | return ErrNotDefined | |
2191 | } | |
1920 | 2192 | |
1921 | 2193 | if err := c.makeSure(isRunning | isPrivileged | isGreaterEqualThanLXC11); err != nil { |
1922 | 2194 | return err |
1939 | 2211 | func (c *Container) ConsoleLog(opt ConsoleLogOptions) ([]byte, error) { |
1940 | 2212 | c.mu.Lock() |
1941 | 2213 | defer c.mu.Unlock() |
2214 | ||
2215 | if c.container == nil { | |
2216 | return nil, ErrNotDefined | |
2217 | } | |
1942 | 2218 | |
1943 | 2219 | cl := C.struct_lxc_console_log{ |
1944 | 2220 | clear: C.bool(opt.ClearLog), |
1975 | 2251 | |
1976 | 2252 | // ErrorNum returns the error_num field of the container. |
1977 | 2253 | func (c *Container) ErrorNum() int { |
2254 | if c.container == nil { | |
2255 | return -1 | |
2256 | } | |
2257 | ||
1978 | 2258 | cError := C.go_lxc_error_num(c.container) |
1979 | 2259 | return int(cError) |
1980 | 2260 | } |
6 | 6 | package lxc |
7 | 7 | |
8 | 8 | const ( |
9 | ErrAddDeviceNodeFailed = lxcError("adding device to container failed") | |
10 | ErrAllocationFailed = lxcError("allocating memory failed") | |
11 | ErrAlreadyDefined = lxcError("container already defined") | |
12 | ErrAlreadyFrozen = lxcError("container is already frozen") | |
13 | ErrAlreadyRunning = lxcError("container is already running") | |
14 | ErrAttachFailed = lxcError("attaching to the container failed") | |
15 | ErrAttachInterfaceFailed = lxcError("attaching specified netdev to the container failed") | |
16 | ErrBlkioUsage = lxcError("BlkioUsage for the container failed") | |
17 | ErrCheckpointFailed = lxcError("checkpoint failed") | |
18 | ErrClearingConfigItemFailed = lxcError("clearing config item for the container failed") | |
19 | ErrClearingCgroupItemFailed = lxcError("clearing cgroup item for the container failed") | |
20 | ErrCloneFailed = lxcError("cloning the container failed") | |
21 | ErrCloseAllFdsFailed = lxcError("setting close_all_fds flag for container failed") | |
22 | ErrCreateFailed = lxcError("creating the container failed") | |
23 | ErrCreateSnapshotFailed = lxcError("snapshotting the container failed") | |
24 | ErrDaemonizeFailed = lxcError("setting daemonize flag for container failed") | |
25 | ErrDestroyAllSnapshotsFailed = lxcError("destroying all snapshots failed") | |
26 | ErrDestroyFailed = lxcError("destroying the container failed") | |
27 | ErrDestroySnapshotFailed = lxcError("destroying the snapshot failed") | |
9 | // ErrAddDeviceNodeFailed - adding device to container failed | |
10 | ErrAddDeviceNodeFailed = lxcError("adding device to container failed") | |
11 | ||
12 | // ErrAllocationFailed - allocating memory failed | |
13 | ErrAllocationFailed = lxcError("allocating memory failed") | |
14 | ||
15 | // ErrAlreadyDefined - container already defined | |
16 | ErrAlreadyDefined = lxcError("container already defined") | |
17 | ||
18 | // ErrAlreadyFrozen - container is already frozen | |
19 | ErrAlreadyFrozen = lxcError("container is already frozen") | |
20 | ||
21 | // ErrAlreadyRunning - container is already running | |
22 | ErrAlreadyRunning = lxcError("container is already running") | |
23 | ||
24 | // ErrAttachFailed - attaching to the container failed | |
25 | ErrAttachFailed = lxcError("attaching to the container failed") | |
26 | ||
27 | // ErrAttachInterfaceFailed - attaching specified netdev to the container failed | |
28 | ErrAttachInterfaceFailed = lxcError("attaching specified netdev to the container failed") | |
29 | ||
30 | // ErrBlkioUsage - BlkioUsage for the container failed | |
31 | ErrBlkioUsage = lxcError("BlkioUsage for the container failed") | |
32 | ||
33 | // ErrCheckpointFailed - checkpoint failed | |
34 | ErrCheckpointFailed = lxcError("checkpoint failed") | |
35 | ||
36 | // ErrClearingConfigItemFailed - clearing config item for the container failed | |
37 | ErrClearingConfigItemFailed = lxcError("clearing config item for the container failed") | |
38 | ||
39 | // ErrClearingCgroupItemFailed - clearing cgroup item for the container failed | |
40 | ErrClearingCgroupItemFailed = lxcError("clearing cgroup item for the container failed") | |
41 | ||
42 | // ErrCloneFailed - cloning the container failed | |
43 | ErrCloneFailed = lxcError("cloning the container failed") | |
44 | ||
45 | // ErrCloseAllFdsFailed - setting close_all_fds flag for container failed | |
46 | ErrCloseAllFdsFailed = lxcError("setting close_all_fds flag for container failed") | |
47 | ||
48 | // ErrCreateFailed - creating the container failed | |
49 | ErrCreateFailed = lxcError("creating the container failed") | |
50 | ||
51 | // ErrCreateSnapshotFailed - snapshotting the container failed | |
52 | ErrCreateSnapshotFailed = lxcError("snapshotting the container failed") | |
53 | ||
54 | // ErrDaemonizeFailed - setting daemonize flag for container failed | |
55 | ErrDaemonizeFailed = lxcError("setting daemonize flag for container failed") | |
56 | ||
57 | // ErrDestroyAllSnapshotsFailed - destroying all snapshots failed | |
58 | ErrDestroyAllSnapshotsFailed = lxcError("destroying all snapshots failed") | |
59 | ||
60 | // ErrDestroyFailed - destroying the container failed | |
61 | ErrDestroyFailed = lxcError("destroying the container failed") | |
62 | ||
63 | // ErrDestroySnapshotFailed - destroying the snapshot failed | |
64 | ErrDestroySnapshotFailed = lxcError("destroying the snapshot failed") | |
65 | ||
66 | // ErrDestroyWithAllSnapshotsFailed - destroying the container with all snapshots failed | |
28 | 67 | ErrDestroyWithAllSnapshotsFailed = lxcError("destroying the container with all snapshots failed") |
29 | ErrDetachInterfaceFailed = lxcError("detaching specified netdev to the container failed") | |
30 | ErrExecuteFailed = lxcError("executing the command in a temporary container failed") | |
31 | ErrFreezeFailed = lxcError("freezing the container failed") | |
68 | ||
69 | // ErrDetachInterfaceFailed - detaching specified netdev to the container failed | |
70 | ErrDetachInterfaceFailed = lxcError("detaching specified netdev to the container failed") | |
71 | ||
72 | // ErrExecuteFailed - executing the command in a temporary container failed | |
73 | ErrExecuteFailed = lxcError("executing the command in a temporary container failed") | |
74 | ||
75 | // ErrFreezeFailed - freezing the container failed | |
76 | ErrFreezeFailed = lxcError("freezing the container failed") | |
77 | ||
78 | // ErrInsufficientNumberOfArguments - insufficient number of arguments were supplied | |
32 | 79 | ErrInsufficientNumberOfArguments = lxcError("insufficient number of arguments were supplied") |
33 | ErrInterfaces = lxcError("getting interface names for the container failed") | |
34 | ErrIPAddresses = lxcError("getting IP addresses of the container failed") | |
35 | ErrIPAddress = lxcError("getting IP address on the interface of the container failed") | |
36 | ErrIPv4Addresses = lxcError("getting IPv4 addresses of the container failed") | |
37 | ErrIPv6Addresses = lxcError("getting IPv6 addresses of the container failed") | |
38 | ErrKMemLimit = lxcError("your kernel does not support cgroup kernel memory controller") | |
39 | ErrLoadConfigFailed = lxcError("loading config file for the container failed") | |
40 | ErrMemLimit = lxcError("your kernel does not support cgroup memory controller") | |
41 | ErrMemorySwapLimit = lxcError("your kernel does not support cgroup swap controller") | |
42 | ErrMethodNotAllowed = lxcError("the requested method is not currently supported with unprivileged containers") | |
43 | ErrNewFailed = lxcError("allocating the container failed") | |
44 | ErrNoSnapshot = lxcError("container has no snapshot") | |
45 | ErrNotDefined = lxcError("container is not defined") | |
46 | ErrNotFrozen = lxcError("container is not frozen") | |
47 | ErrNotRunning = lxcError("container is not running") | |
48 | ErrNotSupported = lxcError("method is not supported by this LXC version") | |
49 | ErrRebootFailed = lxcError("rebooting the container failed") | |
50 | ErrRemoveDeviceNodeFailed = lxcError("removing device from container failed") | |
51 | ErrRenameFailed = lxcError("renaming the container failed") | |
52 | ErrRestoreFailed = lxcError("restore failed") | |
53 | ErrRestoreSnapshotFailed = lxcError("restoring the container failed") | |
54 | ErrSaveConfigFailed = lxcError("saving config file for the container failed") | |
55 | ErrSettingCgroupItemFailed = lxcError("setting cgroup item for the container failed") | |
56 | ErrSettingConfigItemFailed = lxcError("setting config item for the container failed") | |
57 | ErrSettingConfigPathFailed = lxcError("setting config file for the container failed") | |
58 | ErrSettingKMemoryLimitFailed = lxcError("setting kernel memory limit for the container failed") | |
59 | ErrSettingMemoryLimitFailed = lxcError("setting memory limit for the container failed") | |
60 | ErrSettingMemorySwapLimitFailed = lxcError("setting memory+swap limit for the container failed") | |
61 | ErrSettingSoftMemoryLimitFailed = lxcError("setting soft memory limit for the container failed") | |
62 | ErrShutdownFailed = lxcError("shutting down the container failed") | |
63 | ErrSoftMemLimit = lxcError("your kernel does not support cgroup memory controller") | |
64 | ErrStartFailed = lxcError("starting the container failed") | |
65 | ErrStopFailed = lxcError("stopping the container failed") | |
66 | ErrTemplateNotAllowed = lxcError("unprivileged users only allowed to use \"download\" template") | |
67 | ErrUnfreezeFailed = lxcError("unfreezing the container failed") | |
68 | ErrUnknownBackendStore = lxcError("unknown backend type") | |
69 | ErrReleaseFailed = lxcError("releasing the container failed") | |
80 | ||
81 | // ErrInterfaces - getting interface names for the container failed | |
82 | ErrInterfaces = lxcError("getting interface names for the container failed") | |
83 | ||
84 | // ErrIPAddresses - getting IP addresses of the container failed | |
85 | ErrIPAddresses = lxcError("getting IP addresses of the container failed") | |
86 | ||
87 | // ErrIPAddress - getting IP address on the interface of the container failed | |
88 | ErrIPAddress = lxcError("getting IP address on the interface of the container failed") | |
89 | ||
90 | // ErrIPv4Addresses - getting IPv4 addresses of the container failed | |
91 | ErrIPv4Addresses = lxcError("getting IPv4 addresses of the container failed") | |
92 | ||
93 | // ErrIPv6Addresses - getting IPv6 addresses of the container failed | |
94 | ErrIPv6Addresses = lxcError("getting IPv6 addresses of the container failed") | |
95 | ||
96 | // ErrKMemLimit - your kernel does not support cgroup kernel memory controller | |
97 | ErrKMemLimit = lxcError("your kernel does not support cgroup kernel memory controller") | |
98 | ||
99 | // ErrLoadConfigFailed - loading config file for the container failed | |
100 | ErrLoadConfigFailed = lxcError("loading config file for the container failed") | |
101 | ||
102 | // ErrMemLimit - your kernel does not support cgroup memory controller | |
103 | ErrMemLimit = lxcError("your kernel does not support cgroup memory controller") | |
104 | ||
105 | // ErrMemorySwapLimit - your kernel does not support cgroup swap controller | |
106 | ErrMemorySwapLimit = lxcError("your kernel does not support cgroup swap controller") | |
107 | ||
108 | // ErrMethodNotAllowed - the requested method is not currently supported with unprivileged containers | |
109 | ErrMethodNotAllowed = lxcError("the requested method is not currently supported with unprivileged containers") | |
110 | ||
111 | // ErrNewFailed - allocating the container failed | |
112 | ErrNewFailed = lxcError("allocating the container failed") | |
113 | ||
114 | // ErrNoSnapshot - container has no snapshot | |
115 | ErrNoSnapshot = lxcError("container has no snapshot") | |
116 | ||
117 | // ErrNotDefined - container is not defined | |
118 | ErrNotDefined = lxcError("container is not defined") | |
119 | ||
120 | // ErrNotFrozen - container is not frozen | |
121 | ErrNotFrozen = lxcError("container is not frozen") | |
122 | ||
123 | // ErrNotRunning - container is not running | |
124 | ErrNotRunning = lxcError("container is not running") | |
125 | ||
126 | // ErrNotSupported - method is not supported by this LXC version | |
127 | ErrNotSupported = lxcError("method is not supported by this LXC version") | |
128 | ||
129 | // ErrRebootFailed - rebooting the container failed | |
130 | ErrRebootFailed = lxcError("rebooting the container failed") | |
131 | ||
132 | // ErrRemoveDeviceNodeFailed - removing device from container failed | |
133 | ErrRemoveDeviceNodeFailed = lxcError("removing device from container failed") | |
134 | ||
135 | // ErrRenameFailed - renaming the container failed | |
136 | ErrRenameFailed = lxcError("renaming the container failed") | |
137 | ||
138 | // ErrRestoreFailed - restore failed | |
139 | ErrRestoreFailed = lxcError("restore failed") | |
140 | ||
141 | // ErrRestoreSnapshotFailed - restoring the container failed | |
142 | ErrRestoreSnapshotFailed = lxcError("restoring the container failed") | |
143 | ||
144 | // ErrSaveConfigFailed - saving config file for the container failed | |
145 | ErrSaveConfigFailed = lxcError("saving config file for the container failed") | |
146 | ||
147 | // ErrSettingCgroupItemFailed - setting cgroup item for the container failed | |
148 | ErrSettingCgroupItemFailed = lxcError("setting cgroup item for the container failed") | |
149 | ||
150 | // ErrSettingConfigItemFailed - setting config item for the container failed | |
151 | ErrSettingConfigItemFailed = lxcError("setting config item for the container failed") | |
152 | ||
153 | // ErrSettingConfigPathFailed - setting config file for the container failed | |
154 | ErrSettingConfigPathFailed = lxcError("setting config file for the container failed") | |
155 | ||
156 | // ErrSettingKMemoryLimitFailed - setting kernel memory limit for the container failed | |
157 | ErrSettingKMemoryLimitFailed = lxcError("setting kernel memory limit for the container failed") | |
158 | ||
159 | // ErrSettingMemoryLimitFailed - setting memory limit for the container failed | |
160 | ErrSettingMemoryLimitFailed = lxcError("setting memory limit for the container failed") | |
161 | ||
162 | // ErrSettingMemorySwapLimitFailed - setting memory+swap limit for the container failed | |
163 | ErrSettingMemorySwapLimitFailed = lxcError("setting memory+swap limit for the container failed") | |
164 | ||
165 | // ErrSettingSoftMemoryLimitFailed - setting soft memory limit for the container failed | |
166 | ErrSettingSoftMemoryLimitFailed = lxcError("setting soft memory limit for the container failed") | |
167 | ||
168 | // ErrShutdownFailed - shutting down the container failed | |
169 | ErrShutdownFailed = lxcError("shutting down the container failed") | |
170 | ||
171 | // ErrSoftMemLimit - your kernel does not support cgroup memory controller | |
172 | ErrSoftMemLimit = lxcError("your kernel does not support cgroup memory controller") | |
173 | ||
174 | // ErrStartFailed - starting the container failed | |
175 | ErrStartFailed = lxcError("starting the container failed") | |
176 | ||
177 | // ErrStopFailed - stopping the container failed | |
178 | ErrStopFailed = lxcError("stopping the container failed") | |
179 | ||
180 | // ErrTemplateNotAllowed - unprivileged users only allowed to use "download" template | |
181 | ErrTemplateNotAllowed = lxcError("unprivileged users only allowed to use \"download\" template") | |
182 | ||
183 | // ErrUnfreezeFailed - unfreezing the container failed | |
184 | ErrUnfreezeFailed = lxcError("unfreezing the container failed") | |
185 | ||
186 | // ErrUnknownBackendStore - unknown backend type | |
187 | ErrUnknownBackendStore = lxcError("unknown backend type") | |
188 | ||
189 | // ErrReleaseFailed - releasing the container failed | |
190 | ErrReleaseFailed = lxcError("releasing the container failed") | |
70 | 191 | ) |
71 | 192 | |
72 | 193 | type lxcError string |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
12 | 12 | "os" |
13 | 13 | "sync" |
14 | 14 | |
15 | "gopkg.in/lxc/go-lxc.v2" | |
15 | "github.com/lxc/go-lxc" | |
16 | 16 | ) |
17 | 17 | |
18 | 18 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
12 | 12 | "strconv" |
13 | 13 | "sync" |
14 | 14 | |
15 | "gopkg.in/lxc/go-lxc.v2" | |
15 | "github.com/lxc/go-lxc" | |
16 | 16 | ) |
17 | 17 | |
18 | 18 | var ( |
12 | 12 | "strconv" |
13 | 13 | "sync" |
14 | 14 | |
15 | "gopkg.in/lxc/go-lxc.v2" | |
15 | "github.com/lxc/go-lxc" | |
16 | 16 | ) |
17 | 17 | |
18 | 18 | var ( |
13 | 13 | "sync" |
14 | 14 | "time" |
15 | 15 | |
16 | "gopkg.in/lxc/go-lxc.v2" | |
16 | "github.com/lxc/go-lxc" | |
17 | 17 | ) |
18 | 18 | |
19 | 19 | var ( |
12 | 12 | "strconv" |
13 | 13 | "sync" |
14 | 14 | |
15 | "gopkg.in/lxc/go-lxc.v2" | |
15 | "github.com/lxc/go-lxc" | |
16 | 16 | ) |
17 | 17 | |
18 | 18 | var ( |
12 | 12 | "strconv" |
13 | 13 | "sync" |
14 | 14 | |
15 | "gopkg.in/lxc/go-lxc.v2" | |
15 | "github.com/lxc/go-lxc" | |
16 | 16 | ) |
17 | 17 | |
18 | 18 | var ( |
13 | 13 | "strconv" |
14 | 14 | "sync" |
15 | 15 | |
16 | "gopkg.in/lxc/go-lxc.v2" | |
16 | "github.com/lxc/go-lxc" | |
17 | 17 | ) |
18 | 18 | |
19 | 19 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
8 | 8 | import ( |
9 | 9 | "log" |
10 | 10 | |
11 | "gopkg.in/lxc/go-lxc.v2" | |
11 | "github.com/lxc/go-lxc" | |
12 | 12 | ) |
13 | 13 | |
14 | 14 | func main() { |
10 | 10 | "log" |
11 | 11 | "time" |
12 | 12 | |
13 | "gopkg.in/lxc/go-lxc.v2" | |
13 | "github.com/lxc/go-lxc" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
10 | 10 | "log" |
11 | 11 | "time" |
12 | 12 | |
13 | "gopkg.in/lxc/go-lxc.v2" | |
13 | "github.com/lxc/go-lxc" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
8 | 8 | import ( |
9 | 9 | "log" |
10 | 10 | |
11 | "gopkg.in/lxc/go-lxc.v2" | |
11 | "github.com/lxc/go-lxc" | |
12 | 12 | ) |
13 | 13 | |
14 | 14 | func main() { |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
10 | 10 | "log" |
11 | 11 | "time" |
12 | 12 | |
13 | "gopkg.in/lxc/go-lxc.v2" | |
13 | "github.com/lxc/go-lxc" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | var ( |
10 | 10 | "log" |
11 | 11 | "time" |
12 | 12 | |
13 | "gopkg.in/lxc/go-lxc.v2" | |
13 | "github.com/lxc/go-lxc" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
9 | 9 | "flag" |
10 | 10 | "log" |
11 | 11 | |
12 | "gopkg.in/lxc/go-lxc.v2" | |
12 | "github.com/lxc/go-lxc" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var ( |
10 | 10 | "log" |
11 | 11 | "time" |
12 | 12 | |
13 | "gopkg.in/lxc/go-lxc.v2" | |
13 | "github.com/lxc/go-lxc" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | var ( |
0 | module github.com/lxc/go-lxc | |
1 | ||
2 | go 1.16 | |
3 | ||
4 | require golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1 |
0 | golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1 h1:lCnv+lfrU9FRPGf8NeRuWAAPjNnema5WtBinMgs1fD8= | |
1 | golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
6 | 6 | package lxc |
7 | 7 | |
8 | 8 | // #cgo CFLAGS: -std=gnu11 -Wvla -Werror |
9 | // #cgo pkg-config: --static lxc | |
9 | // #cgo pkg-config: --static lxc libcrypto | |
10 | 10 | // #cgo LDFLAGS: -static |
11 | 11 | import "C" |
288 | 288 | bool clear_env, |
289 | 289 | int namespaces, |
290 | 290 | long personality, |
291 | uid_t uid, gid_t gid, | |
291 | uid_t uid, gid_t gid, lxc_groups_t groups, | |
292 | 292 | int stdinfd, int stdoutfd, int stderrfd, |
293 | 293 | char *initial_cwd, |
294 | 294 | char **extra_env_vars, |
295 | 295 | char **extra_keep_env, |
296 | 296 | const char * const argv[], |
297 | pid_t *attached_pid) { | |
297 | pid_t *attached_pid, | |
298 | int attach_flags) { | |
298 | 299 | int ret; |
299 | 300 | |
300 | 301 | lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; |
302 | attach_options.attach_flags = attach_flags; | |
303 | ||
301 | 304 | lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL}; |
302 | 305 | |
303 | 306 | attach_options.env_policy = LXC_ATTACH_KEEP_ENV; |
310 | 313 | |
311 | 314 | attach_options.uid = uid; |
312 | 315 | attach_options.gid = gid; |
316 | #if VERSION_AT_LEAST(4, 0, 9) | |
317 | if ( groups.size > 0 ) { | |
318 | attach_options.groups = groups; | |
319 | attach_options.attach_flags &= LXC_ATTACH_SETGROUPS; | |
320 | } | |
321 | #endif | |
313 | 322 | |
314 | 323 | attach_options.stdin_fd = stdinfd; |
315 | 324 | attach_options.stdout_fd = stdoutfd; |
333 | 342 | bool clear_env, |
334 | 343 | int namespaces, |
335 | 344 | long personality, |
336 | uid_t uid, gid_t gid, | |
345 | uid_t uid, gid_t gid, lxc_groups_t groups, | |
337 | 346 | int stdinfd, int stdoutfd, int stderrfd, |
338 | 347 | char *initial_cwd, |
339 | 348 | char **extra_env_vars, |
340 | char **extra_keep_env) { | |
349 | char **extra_keep_env, | |
350 | int attach_flags) { | |
341 | 351 | int ret; |
342 | 352 | pid_t pid; |
343 | 353 | |
344 | 354 | lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; |
355 | attach_options.attach_flags = attach_flags; | |
345 | 356 | |
346 | 357 | attach_options.env_policy = LXC_ATTACH_KEEP_ENV; |
347 | 358 | if (clear_env) { |
353 | 364 | |
354 | 365 | attach_options.uid = uid; |
355 | 366 | attach_options.gid = gid; |
367 | #if VERSION_AT_LEAST(4, 0, 9) | |
368 | if ( groups.size > 0 ) { | |
369 | attach_options.groups = groups; | |
370 | attach_options.attach_flags &= LXC_ATTACH_SETGROUPS; | |
371 | } | |
372 | #endif | |
356 | 373 | |
357 | 374 | attach_options.stdin_fd = stdinfd; |
358 | 375 | attach_options.stdout_fd = stdoutfd; |
361 | 378 | attach_options.initial_cwd = initial_cwd; |
362 | 379 | attach_options.extra_env_vars = extra_env_vars; |
363 | 380 | attach_options.extra_keep_env = extra_keep_env; |
364 | ||
365 | /* | |
366 | remount_sys_proc | |
367 | When using -s and the mount namespace is not included, this flag will cause lxc-attach to remount /proc and /sys to reflect the current other namespace contexts. | |
368 | default_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; | |
369 | ||
370 | elevated_privileges | |
371 | Do not drop privileges when running command inside the container. If this option is specified, the new process will not be added to the container's cgroup(s) and it will not drop its capabilities before executing. | |
372 | default_options.attach_flags &= ~(LXC_ATTACH_MOVE_TO_CGROUP | LXC_ATTACH_DROP_CAPABILITIES | LXC_ATTACH_APPARMOR); | |
373 | */ | |
374 | 381 | |
375 | 382 | ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid); |
376 | 383 | if (ret < 0) |
390 | 397 | bool clear_env, |
391 | 398 | int namespaces, |
392 | 399 | long personality, |
393 | uid_t uid, gid_t gid, | |
400 | uid_t uid, gid_t gid, lxc_groups_t groups, | |
394 | 401 | int stdinfd, int stdoutfd, int stderrfd, |
395 | 402 | char *initial_cwd, |
396 | 403 | char **extra_env_vars, |
397 | 404 | char **extra_keep_env, |
398 | const char * const argv[]) { | |
405 | const char * const argv[], | |
406 | int attach_flags) { | |
399 | 407 | int ret; |
400 | 408 | |
401 | 409 | lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; |
410 | attach_options.attach_flags = attach_flags; | |
402 | 411 | |
403 | 412 | attach_options.env_policy = LXC_ATTACH_KEEP_ENV; |
404 | 413 | if (clear_env) { |
410 | 419 | |
411 | 420 | attach_options.uid = uid; |
412 | 421 | attach_options.gid = gid; |
422 | #if VERSION_AT_LEAST(4, 0, 9) | |
423 | if ( groups.size > 0 ) { | |
424 | attach_options.groups = groups; | |
425 | attach_options.attach_flags &= LXC_ATTACH_SETGROUPS; | |
426 | } | |
427 | #endif | |
413 | 428 | |
414 | 429 | attach_options.stdin_fd = stdinfd; |
415 | 430 | attach_options.stdout_fd = stdoutfd; |
47 | 47 | |
48 | 48 | // Acquire increments the reference counter of the container object. |
49 | 49 | func Acquire(c *Container) bool { |
50 | c.mu.RLock() | |
51 | defer c.mu.RUnlock() | |
52 | ||
50 | 53 | return C.lxc_container_get(c.container) == 1 |
51 | 54 | } |
52 | 55 | |
53 | 56 | // Release decrements the reference counter of the container object. |
54 | 57 | func Release(c *Container) bool { |
55 | if C.lxc_container_put(c.container) == -1 { | |
56 | return false | |
57 | } | |
58 | return true | |
58 | return c.Release() == nil | |
59 | 59 | } |
60 | 60 | |
61 | 61 | // Version returns the LXC version. |
311 | 311 | } |
312 | 312 | |
313 | 313 | // HasApiExtension returns true if the extension is supported. |
314 | // Deprecated: Please use HasAPIExtension instead. | |
314 | 315 | func HasApiExtension(extension string) bool { |
316 | return HasAPIExtension(extension) | |
317 | } | |
318 | ||
319 | // HasAPIExtension returns true if the extension is supported. | |
320 | func HasAPIExtension(extension string) bool { | |
315 | 321 | if runtimeLiblxcVersionAtLeast(3, 1, 0) { |
316 | 322 | apiExtension := C.CString(extension) |
317 | 323 | defer C.free(unsafe.Pointer(apiExtension)) |
0 | 0 | // Copyright © 2013, 2014, The Go-LXC Authors. All rights reserved. |
1 | 1 | // Use of this source code is governed by a LGPLv2.1 |
2 | 2 | // license that can be found in the LICENSE file. |
3 | ||
4 | #include <lxc/attach_options.h> | |
3 | 5 | |
4 | 6 | #define VERSION_AT_LEAST(major, minor, micro) \ |
5 | 7 | ((LXC_DEVEL == 1) || (!(major > LXC_VERSION_MAJOR || \ |
45 | 47 | extern char* go_lxc_get_running_config_item(struct lxc_container *c, const char *key); |
46 | 48 | extern const char* go_lxc_get_config_path(struct lxc_container *c); |
47 | 49 | extern const char* go_lxc_state(struct lxc_container *c); |
50 | ||
51 | #if !VERSION_AT_LEAST(4, 0, 9) && !defined(LXC_ATTACH_SETGROUPS) | |
52 | typedef struct lxc_groups_t { | |
53 | size_t size; | |
54 | gid_t *list; | |
55 | } lxc_groups_t; | |
56 | # endif | |
57 | ||
48 | 58 | extern int go_lxc_attach_run_wait(struct lxc_container *c, |
49 | 59 | bool clear_env, |
50 | 60 | int namespaces, |
51 | 61 | long personality, |
52 | uid_t uid, gid_t gid, | |
53 | int stdinfd, int stdoutfd, int stderrfd, | |
54 | char *initial_cwd, | |
55 | char **extra_env_vars, | |
56 | char **extra_keep_env, | |
57 | const char * const argv[]); | |
58 | extern int go_lxc_attach(struct lxc_container *c, | |
59 | bool clear_env, | |
60 | int namespaces, | |
61 | long personality, | |
62 | uid_t uid, gid_t gid, | |
63 | int stdinfd, int stdoutfd, int stderrfd, | |
64 | char *initial_cwd, | |
65 | char **extra_env_vars, | |
66 | char **extra_keep_env); | |
67 | extern int go_lxc_attach_no_wait(struct lxc_container *c, | |
68 | bool clear_env, | |
69 | int namespaces, | |
70 | long personality, | |
71 | uid_t uid, gid_t gid, | |
62 | uid_t uid, gid_t gid, lxc_groups_t groups, | |
72 | 63 | int stdinfd, int stdoutfd, int stderrfd, |
73 | 64 | char *initial_cwd, |
74 | 65 | char **extra_env_vars, |
75 | 66 | char **extra_keep_env, |
76 | 67 | const char * const argv[], |
77 | pid_t *attached_pid); | |
68 | int attach_flags); | |
69 | extern int go_lxc_attach(struct lxc_container *c, | |
70 | bool clear_env, | |
71 | int namespaces, | |
72 | long personality, | |
73 | uid_t uid, gid_t gid, lxc_groups_t groups, | |
74 | int stdinfd, int stdoutfd, int stderrfd, | |
75 | char *initial_cwd, | |
76 | char **extra_env_vars, | |
77 | char **extra_keep_env, | |
78 | int attach_flags); | |
79 | extern int go_lxc_attach_no_wait(struct lxc_container *c, | |
80 | bool clear_env, | |
81 | int namespaces, | |
82 | long personality, | |
83 | uid_t uid, gid_t gid, lxc_groups_t groups, | |
84 | int stdinfd, int stdoutfd, int stderrfd, | |
85 | char *initial_cwd, | |
86 | char **extra_env_vars, | |
87 | char **extra_keep_env, | |
88 | const char * const argv[], | |
89 | pid_t *attached_pid, | |
90 | int attach_flags); | |
78 | 91 | extern int go_lxc_console_getfd(struct lxc_container *c, int ttynum); |
79 | 92 | extern int go_lxc_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret); |
80 | 93 | extern int go_lxc_snapshot(struct lxc_container *c); |
26 | 26 | DefaultContainerRestoreName = "ipsum" |
27 | 27 | DefaultContainerCloneName = "consectetur" |
28 | 28 | DefaultContainerCloneOverlayName = "adipiscing" |
29 | DefaultContainerCloneAufsName = "pellentesque" | |
30 | 29 | ) |
31 | 30 | |
32 | 31 | func exists(name string) bool { |
75 | 74 | } |
76 | 75 | |
77 | 76 | func template() TemplateOptions { |
78 | if !unprivileged() { | |
79 | return BusyboxTemplateOptions | |
80 | } | |
81 | ||
82 | // travis uses trusy which comes with lxc 1.0.x so use a compatible image | |
83 | 77 | return TemplateOptions{ |
84 | 78 | Template: "download", |
85 | Distro: "ubuntu", | |
86 | Release: "trusty", | |
79 | Distro: "alpine", | |
80 | Release: "edge", | |
87 | 81 | Arch: "amd64", |
88 | 82 | } |
89 | 83 | } |
116 | 110 | return DefaultContainerCloneOverlayName |
117 | 111 | } |
118 | 112 | |
119 | func ContainerCloneAufsName() string { | |
120 | if unprivileged() { | |
121 | return fmt.Sprintf("%s-unprivileged", DefaultContainerCloneAufsName) | |
122 | } | |
123 | return DefaultContainerCloneAufsName | |
124 | } | |
125 | ||
126 | 113 | func TestVersion(t *testing.T) { |
127 | 114 | t.Logf("LXC version: %s", Version()) |
128 | 115 | } |
163 | 150 | } |
164 | 151 | |
165 | 152 | func TestConcurrentDefined_Negative(t *testing.T) { |
153 | t.Skip("Skipping concurrent tests for now") | |
154 | ||
166 | 155 | defer runtime.GOMAXPROCS(runtime.NumCPU()) |
167 | 156 | |
168 | 157 | var wg sync.WaitGroup |
211 | 200 | } |
212 | 201 | defer c.Release() |
213 | 202 | |
203 | c.SetConfigItem("lxc.apparmor.profile", "unconfined") | |
214 | 204 | if _, err := c.Execute("/bin/true"); err != nil { |
215 | 205 | t.Errorf(err.Error()) |
216 | 206 | } |
274 | 264 | } |
275 | 265 | } |
276 | 266 | |
277 | func TestCloneUsingAufs(t *testing.T) { | |
278 | if unprivileged() { | |
279 | t.Skip("skipping test in unprivileged mode.") | |
280 | } | |
281 | ||
282 | if !supported("aufs") { | |
283 | t.Skip("skipping test as aufs support is missing.") | |
284 | } | |
285 | ||
286 | c, err := NewContainer(ContainerName()) | |
287 | if err != nil { | |
288 | t.Errorf(err.Error()) | |
289 | } | |
290 | defer c.Release() | |
291 | ||
292 | err = c.Clone(ContainerCloneAufsName(), CloneOptions{ | |
293 | Backend: Aufs, | |
294 | KeepName: true, | |
295 | KeepMAC: true, | |
296 | Snapshot: true, | |
297 | }) | |
298 | if err != nil { | |
299 | t.Errorf(err.Error()) | |
300 | } | |
301 | } | |
302 | ||
303 | 267 | func TestCreateSnapshot(t *testing.T) { |
304 | 268 | c, err := NewContainer(ContainerName()) |
305 | 269 | if err != nil { |
327 | 291 | } |
328 | 292 | |
329 | 293 | func TestRestoreSnapshot(t *testing.T) { |
294 | if os.Getenv("GITHUB_ACTION") != "" { | |
295 | t.Skip("Test broken on Github") | |
296 | } | |
297 | ||
330 | 298 | c, err := NewContainer(ContainerName()) |
331 | 299 | if err != nil { |
332 | 300 | t.Errorf(err.Error()) |
340 | 308 | } |
341 | 309 | |
342 | 310 | func TestConcurrentCreate(t *testing.T) { |
311 | t.Skip("Skipping concurrent tests for now") | |
312 | ||
343 | 313 | defer runtime.GOMAXPROCS(runtime.NumCPU()) |
344 | ||
345 | if unprivileged() { | |
346 | t.Skip("skipping test in unprivileged mode.") | |
347 | } | |
348 | 314 | |
349 | 315 | var wg sync.WaitGroup |
350 | 316 | |
383 | 349 | } |
384 | 350 | |
385 | 351 | func TestConcurrentStart(t *testing.T) { |
352 | t.Skip("Skipping concurrent tests for now") | |
353 | ||
386 | 354 | defer runtime.GOMAXPROCS(runtime.NumCPU()) |
387 | ||
388 | if unprivileged() { | |
389 | t.Skip("skipping test in unprivileged mode.") | |
390 | } | |
391 | 355 | |
392 | 356 | var wg sync.WaitGroup |
393 | 357 | |
440 | 404 | } |
441 | 405 | |
442 | 406 | func TestConcurrentDefined_Positive(t *testing.T) { |
407 | t.Skip("Skipping concurrent tests for now") | |
408 | ||
443 | 409 | defer runtime.GOMAXPROCS(runtime.NumCPU()) |
444 | ||
445 | if unprivileged() { | |
446 | t.Skip("skipping test in unprivileged mode.") | |
447 | } | |
448 | 410 | |
449 | 411 | var wg sync.WaitGroup |
450 | 412 | |
510 | 472 | } |
511 | 473 | |
512 | 474 | func TestWaitIPAddresses(t *testing.T) { |
513 | if !unprivileged() { | |
514 | t.Skip("skipping test in privileged mode.") | |
515 | } | |
516 | ||
517 | 475 | c, err := NewContainer(ContainerName()) |
518 | 476 | if err != nil { |
519 | 477 | t.Errorf(err.Error()) |
722 | 680 | } |
723 | 681 | defer c.Release() |
724 | 682 | |
725 | if c.ConfigItem("lxc.utsname")[0] != ContainerName() { | |
683 | if c.ConfigItem("lxc.uts.name")[0] != ContainerName() { | |
726 | 684 | t.Errorf("ConfigItem failed...") |
727 | 685 | } |
728 | 686 | } |
734 | 692 | } |
735 | 693 | defer c.Release() |
736 | 694 | |
737 | if err := c.SetConfigItem("lxc.utsname", ContainerName()); err != nil { | |
738 | t.Errorf(err.Error()) | |
739 | } | |
740 | ||
741 | if c.ConfigItem("lxc.utsname")[0] != ContainerName() { | |
695 | if err := c.SetConfigItem("lxc.uts.name", ContainerName()); err != nil { | |
696 | t.Errorf(err.Error()) | |
697 | } | |
698 | ||
699 | if c.ConfigItem("lxc.uts.name")[0] != ContainerName() { | |
742 | 700 | t.Errorf("ConfigItem failed...") |
743 | 701 | } |
744 | 702 | } |
1208 | 1166 | |
1209 | 1167 | options := DefaultAttachOptions |
1210 | 1168 | options.ClearEnv = true |
1211 | options.EnvToKeep = []string{"TERM"} | |
1212 | ||
1213 | args := []string{"/bin/sh", "-c", fmt.Sprintf("test $TERM = '%s'", os.Getenv("TERM"))} | |
1169 | options.EnvToKeep = []string{"USER"} | |
1170 | ||
1171 | args := []string{"/bin/sh", "-c", fmt.Sprintf("test $USER = '%s'", os.Getenv("USER"))} | |
1214 | 1172 | ok, err := c.RunCommand(args, DefaultAttachOptions) |
1215 | 1173 | if err != nil { |
1216 | 1174 | t.Errorf(err.Error()) |
1391 | 1349 | } |
1392 | 1350 | |
1393 | 1351 | func TestIPv4Addresses(t *testing.T) { |
1394 | if !unprivileged() { | |
1395 | t.Skip("skipping test in privileged mode.") | |
1396 | } | |
1397 | ||
1398 | 1352 | c, err := NewContainer(ContainerName()) |
1399 | 1353 | if err != nil { |
1400 | 1354 | t.Errorf(err.Error()) |
1407 | 1361 | } |
1408 | 1362 | |
1409 | 1363 | func TestIPv6Addresses(t *testing.T) { |
1410 | if !unprivileged() { | |
1411 | t.Skip("skipping test in privileged mode.") | |
1412 | } | |
1413 | ||
1414 | 1364 | if !ipv6() { |
1415 | 1365 | t.Skip("skipping test since lxc bridge does not have ipv6 address") |
1416 | 1366 | } |
1440 | 1390 | } |
1441 | 1391 | |
1442 | 1392 | func TestConcurrentShutdown(t *testing.T) { |
1393 | t.Skip("Skipping concurrent tests for now") | |
1394 | ||
1443 | 1395 | defer runtime.GOMAXPROCS(runtime.NumCPU()) |
1444 | ||
1445 | if unprivileged() { | |
1446 | t.Skip("skipping test in unprivileged mode.") | |
1447 | } | |
1448 | 1396 | |
1449 | 1397 | var wg sync.WaitGroup |
1450 | 1398 | |
1551 | 1499 | } |
1552 | 1500 | } |
1553 | 1501 | |
1554 | if !unprivileged() && supported("aufs") { | |
1555 | c, err := NewContainer(ContainerCloneAufsName()) | |
1556 | if err != nil { | |
1557 | t.Errorf(err.Error()) | |
1558 | } | |
1559 | defer c.Release() | |
1560 | ||
1502 | c, err := NewContainer(ContainerCloneName()) | |
1503 | if err != nil { | |
1504 | t.Errorf(err.Error()) | |
1505 | } | |
1506 | defer c.Release() | |
1507 | ||
1508 | if err := c.Destroy(); err != nil { | |
1509 | t.Errorf(err.Error()) | |
1510 | } | |
1511 | ||
1512 | c, err = NewContainer(ContainerRestoreName()) | |
1513 | if err != nil { | |
1514 | t.Errorf(err.Error()) | |
1515 | } | |
1516 | defer c.Release() | |
1517 | ||
1518 | if c.Defined() { | |
1561 | 1519 | if err := c.Destroy(); err != nil { |
1562 | 1520 | t.Errorf(err.Error()) |
1563 | 1521 | } |
1564 | 1522 | } |
1565 | c, err := NewContainer(ContainerCloneName()) | |
1523 | ||
1524 | c, err = NewContainer(ContainerName()) | |
1566 | 1525 | if err != nil { |
1567 | 1526 | t.Errorf(err.Error()) |
1568 | 1527 | } |
1571 | 1530 | if err := c.Destroy(); err != nil { |
1572 | 1531 | t.Errorf(err.Error()) |
1573 | 1532 | } |
1574 | ||
1575 | c, err = NewContainer(ContainerRestoreName()) | |
1576 | if err != nil { | |
1577 | t.Errorf(err.Error()) | |
1578 | } | |
1579 | defer c.Release() | |
1580 | ||
1581 | if err := c.Destroy(); err != nil { | |
1582 | t.Errorf(err.Error()) | |
1583 | } | |
1584 | ||
1585 | c, err = NewContainer(ContainerName()) | |
1586 | if err != nil { | |
1587 | t.Errorf(err.Error()) | |
1588 | } | |
1589 | defer c.Release() | |
1590 | ||
1591 | if err := c.Destroy(); err != nil { | |
1592 | t.Errorf(err.Error()) | |
1593 | } | |
1594 | 1533 | } |
1595 | 1534 | |
1596 | 1535 | func TestConcurrentDestroy(t *testing.T) { |
1536 | t.Skip("Skipping concurrent tests for now") | |
1537 | ||
1597 | 1538 | defer runtime.GOMAXPROCS(runtime.NumCPU()) |
1598 | ||
1599 | if unprivileged() { | |
1600 | t.Skip("skipping test in unprivileged mode.") | |
1601 | } | |
1602 | 1539 | |
1603 | 1540 | var wg sync.WaitGroup |
1604 | 1541 |
27 | 27 | // GID specifies the group id to run as. |
28 | 28 | GID int |
29 | 29 | |
30 | // Groups specifies the list of additional group ids to run with. | |
31 | Groups []int | |
32 | ||
30 | 33 | // If ClearEnv is true the environment is cleared before running the command. |
31 | 34 | ClearEnv bool |
32 | 35 | |
44 | 47 | |
45 | 48 | // StderrFd specifies the fd to write error output to. |
46 | 49 | StderrFd uintptr |
50 | ||
51 | // RemountSysProc remounts /sys and /proc for the executed command. | |
52 | // This is required to reflect the container (PID) namespace context | |
53 | // if the command does not attach to the container's mount namespace. | |
54 | RemountSysProc bool | |
55 | ||
56 | // ElevatedPrivileges runs the command with elevated privileges. | |
57 | // The capabilities, cgroup and security module restrictions of the container are not applied. | |
58 | // WARNING: This may leak privileges into the container. | |
59 | ElevatedPrivileges bool | |
47 | 60 | } |
48 | 61 | |
49 | 62 | // DefaultAttachOptions is a convenient set of options to be used. |
50 | 63 | var DefaultAttachOptions = AttachOptions{ |
51 | Namespaces: -1, | |
52 | Arch: -1, | |
53 | Cwd: "/", | |
54 | UID: -1, | |
55 | GID: -1, | |
56 | ClearEnv: false, | |
57 | Env: nil, | |
58 | EnvToKeep: nil, | |
59 | StdinFd: os.Stdin.Fd(), | |
60 | StdoutFd: os.Stdout.Fd(), | |
61 | StderrFd: os.Stderr.Fd(), | |
64 | Namespaces: -1, | |
65 | Arch: -1, | |
66 | Cwd: "/", | |
67 | UID: -1, | |
68 | GID: -1, | |
69 | Groups: nil, | |
70 | ClearEnv: false, | |
71 | Env: nil, | |
72 | EnvToKeep: nil, | |
73 | StdinFd: os.Stdin.Fd(), | |
74 | StdoutFd: os.Stdout.Fd(), | |
75 | StderrFd: os.Stderr.Fd(), | |
76 | RemountSysProc: false, | |
77 | ElevatedPrivileges: false, | |
62 | 78 | } |
63 | 79 | |
64 | 80 | // TemplateOptions type is used for defining various template options. |
106 | 122 | ExtraArgs []string |
107 | 123 | } |
108 | 124 | |
125 | // BackendStoreSpecs represents a LXC storage backend. | |
109 | 126 | type BackendStoreSpecs struct { |
110 | 127 | FSType string |
111 | 128 | FSSize uint64 |
64 | 64 | case Overlayfs: |
65 | 65 | return "overlayfs" |
66 | 66 | case Loopback: |
67 | return "loopback" | |
67 | return "loop" | |
68 | 68 | case Best: |
69 | 69 | return "best" |
70 | 70 | } |
155 | 155 | type ByteSize float64 |
156 | 156 | |
157 | 157 | const ( |
158 | // B - byte | |
158 | 159 | B = iota |
160 | ||
159 | 161 | // KB - kilobyte |
160 | 162 | KB ByteSize = 1 << (10 * iota) |
163 | ||
161 | 164 | // MB - megabyte |
162 | 165 | MB |
166 | ||
163 | 167 | // GB - gigabyte |
164 | 168 | GB |
169 | ||
165 | 170 | // TB - terabyte |
166 | 171 | TB |
172 | ||
167 | 173 | // PB - petabyte |
168 | 174 | PB |
175 | ||
169 | 176 | // EB - exabyte |
170 | 177 | EB |
178 | ||
171 | 179 | // ZB - zettabyte |
172 | 180 | ZB |
181 | ||
173 | 182 | // YB - yottabyte |
174 | 183 | YB |
175 | 184 | ) |
332 | 341 | type Personality int64 |
333 | 342 | |
334 | 343 | const ( |
335 | X86 Personality = 0x0008 | |
336 | X86_64 = 0x0000 | |
337 | ) | |
338 | ||
339 | const ( | |
340 | MIGRATE_PRE_DUMP = 0 | |
341 | MIGRATE_DUMP = 1 | |
342 | MIGRATE_RESTORE = 2 | |
344 | // X86 - Intel 32bit | |
345 | X86 Personality = 0x0008 | |
346 | ||
347 | // X86_64 - Intel 64bit | |
348 | X86_64 = 0x0000 | |
349 | ) | |
350 | ||
351 | const ( | |
352 | // MIGRATE_PRE_DUMP - pre-dump live migration phase | |
353 | MIGRATE_PRE_DUMP = 0 | |
354 | ||
355 | // MIGRATE_DUMP - main live migration phase | |
356 | MIGRATE_DUMP = 1 | |
357 | ||
358 | // MIGRATE_RESTORE - post migration phase | |
359 | MIGRATE_RESTORE = 2 | |
360 | ||
361 | // MIGRATE_FEATURE_CHECK - migration feature check | |
343 | 362 | MIGRATE_FEATURE_CHECK = 3 |
344 | 363 | ) |
345 | 364 | |
365 | // CriuFeatures represents a set of CRIU features | |
346 | 366 | type CriuFeatures uint64 |
347 | 367 | |
348 | 368 | const ( |
369 | // FEATURE_MEM_TRACK - memory tracking support | |
349 | 370 | FEATURE_MEM_TRACK CriuFeatures = 1 << iota |
371 | ||
372 | // FEATURE_LAZY_PAGES - lazy pages support | |
350 | 373 | FEATURE_LAZY_PAGES |
351 | 374 | ) |
46 | 46 | import "C" |
47 | 47 | |
48 | 48 | import ( |
49 | "reflect" | |
50 | 49 | "unsafe" |
51 | 50 | ) |
52 | 51 | |
81 | 80 | return nil |
82 | 81 | } |
83 | 82 | |
84 | var A []*C.char | |
85 | ||
86 | hdr := reflect.SliceHeader{ | |
87 | Data: uintptr(unsafe.Pointer(cArgs)), | |
88 | Len: size, | |
89 | Cap: size, | |
83 | tmpslice := (*[(1 << 29) - 1]*C.char)(unsafe.Pointer(cArgs))[:size:size] | |
84 | result := make([]string, size) | |
85 | for i, s := range tmpslice { | |
86 | result[i] = C.GoString(s) | |
90 | 87 | } |
91 | cArgsInterface := reflect.NewAt(reflect.TypeOf(A), unsafe.Pointer(&hdr)).Elem().Interface() | |
92 | ||
93 | result := make([]string, size) | |
94 | for i := 0; i < size; i++ { | |
95 | result[i] = C.GoString(cArgsInterface.([]*C.char)[i]) | |
96 | } | |
97 | C.freeCharArray(cArgs, C.size_t(size)) | |
98 | ||
99 | 88 | return result |
100 | 89 | } |
101 | 90 |