├── .gitignore ├── .out └── .gitignore ├── .dockerignore ├── student.sudoers ├── .base └── task ├── essential-commands └── redirect-output1 │ ├── solution │ ├── stderr.txt │ ├── stdout.txt │ ├── both.txt │ ├── show.sh │ └── checker.sh │ ├── print.sh │ ├── task │ ├── setup.sh │ └── README.md ├── README.md ├── tasks-readme-base.md ├── .github └── workflows │ ├── image-push.yml │ └── checks.yml ├── base.Dockerfile ├── LICENSE └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.out/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/README.md 2 | -------------------------------------------------------------------------------- /student.sudoers: -------------------------------------------------------------------------------- 1 | student ALL=NOPASSWD: ALL 2 | -------------------------------------------------------------------------------- /.base/task: -------------------------------------------------------------------------------- 1 | This is the base image, use it for testing or as playground 2 | -------------------------------------------------------------------------------- /essential-commands/redirect-output1/solution/stderr.txt: -------------------------------------------------------------------------------- 1 | This message goes to stderr 2 | -------------------------------------------------------------------------------- /essential-commands/redirect-output1/solution/stdout.txt: -------------------------------------------------------------------------------- 1 | This message goes to stdout 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lfcs-practice 2 | Practice Questions for the Linux Foundation Certified System-Administrator (LFCS) exam 3 | -------------------------------------------------------------------------------- /essential-commands/redirect-output1/print.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo This message goes to stderr >&2 3 | echo This message goes to stdout 4 | -------------------------------------------------------------------------------- /essential-commands/redirect-output1/solution/both.txt: -------------------------------------------------------------------------------- 1 | This should not be removed 2 | This message goes to stderr 3 | This message goes to stdout 4 | -------------------------------------------------------------------------------- /tasks-readme-base.md: -------------------------------------------------------------------------------- 1 | # HEADING 2 | 3 | Run the docker container using `docker run -it IMAGE` and complete the task. 4 | 5 | ## Task Description 6 | -------------------------------------------------------------------------------- /essential-commands/redirect-output1/solution/show.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | case "${1}" in 4 | "1") 5 | echo 'test_printer > /opt/EC001/stdout.txt' 6 | ;; 7 | "2") 8 | echo 'test_printer 2> /opt/EC001/stderr.txt' 9 | ;; 10 | "3") 11 | echo 'test_printer >> /opt/EC001/both.txt 2>&1' 12 | ;; 13 | *) 14 | echo "Usage: ${0} [TASK_NUMBER]" 15 | ;; 16 | esac 17 | -------------------------------------------------------------------------------- /.github/workflows/image-push.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | 10 | push-all: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v1 14 | - run: | 15 | docker login -u ${USERNAME} -p "${DOCKER_REGISTRY_TOKEN}" 16 | make push-base push-tasks 17 | env: 18 | DOCKER_REGISTRY_TOKEN: ${{ secrets.DOCKER_REGISTRY_TOKEN }} 19 | USERNAME: maxbischoff 20 | DOCKER_REPO: maxbischoff 21 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | 10 | build-all: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Build the Docker image 15 | run: make build-base build-tasks 16 | 17 | readme-updated: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v1 21 | - name: Update task README.md files using `make readmes` 22 | run: make clean readmes 23 | - name: Check if README files need to be updated 24 | run: git diff --exit-code 25 | -------------------------------------------------------------------------------- /essential-commands/redirect-output1/task: -------------------------------------------------------------------------------- 1 | An executable named `test_printer` is placed in `/usr/local/bin`, that will output text to both `STDOUT` and `STDERR`. 2 | 3 | 1. Run `test_printer` and redirect *only* it's standard output to `/opt/EC001/stdout.txt` 4 | 2. Run `test_printer` again but this time redirect *only* it's standard error to `/opt/EC001/stderr.txt` 5 | 3. Run `test_printer` a third time and redirect both it's standard output and error to `/opt/EC001/both.txt`, *appending* it to the existing file. 6 | 7 | You can always check if your solution is correct by running `check_solution`. 8 | A sample solution for each subtask can be viewed using `show_solution [SUBTASK_NUMBER]`. 9 | -------------------------------------------------------------------------------- /essential-commands/redirect-output1/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | USER=$(basename $(pwd)) 3 | 4 | # set up the task prerequisites 5 | mkdir /opt/EC001/ 6 | touch /opt/EC001/stdout.txt 7 | touch /opt/EC001/stderr.txt 8 | echo "This should not be removed" > /opt/EC001/both.txt 9 | chown -R $USER /opt/EC001/ 10 | 11 | mv print.sh /usr/local/bin/test_printer 12 | chown $USER /usr/local/bin/test_printer 13 | chmod +x /usr/local/bin/test_printer 14 | 15 | # set up the solution 16 | mkdir /opt/solutions_EC001/ 17 | mv solution/*.txt /opt/solutions_EC001/ 18 | 19 | mv solution/checker.sh /usr/local/bin/check_solution 20 | chmod +x /usr/local/bin/check_solution 21 | 22 | mv solution/show.sh /usr/local/bin/show_solution 23 | chmod +x /usr/local/bin/show_solution 24 | 25 | rmdir solution 26 | -------------------------------------------------------------------------------- /essential-commands/redirect-output1/README.md: -------------------------------------------------------------------------------- 1 | # essential-commands: redirect-output1 2 | 3 | Run the docker container using `docker run -it maxbischoff/essential-commands_redirect-output1` and complete the task. 4 | 5 | ## Task Description 6 | An executable named `test_printer` is placed in `/usr/local/bin`, that will output text to both `STDOUT` and `STDERR`. 7 | 8 | 1. Run `test_printer` and redirect *only* it's standard output to `/opt/EC001/stdout.txt` 9 | 2. Run `test_printer` again but this time redirect *only* it's standard error to `/opt/EC001/stderr.txt` 10 | 3. Run `test_printer` a third time and redirect both it's standard output and error to `/opt/EC001/both.txt`, *appending* it to the existing file. 11 | 12 | You can always check if your solution is correct by running `check_solution`. 13 | A sample solution for each subtask can be viewed using `show_solution [SUBTASK_NUMBER]`. 14 | -------------------------------------------------------------------------------- /essential-commands/redirect-output1/solution/checker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | failed=0 4 | 5 | if cmp /opt/EC001/stdout.txt /opt/solutions_EC001/stdout.txt >/dev/null 2>&1; then 6 | echo "1: Correct" 7 | else 8 | echo "1: Incorrect, see diff below:" 9 | diff /opt/EC001/stdout.txt /opt/solutions_EC001/stdout.txt 10 | echo 11 | ((failed=failed+1)) 12 | fi 13 | 14 | 15 | if cmp /opt/EC001/stderr.txt /opt/solutions_EC001/stderr.txt >/dev/null 2>&1; then 16 | echo "2: Correct" 17 | else 18 | echo "2: Incorrect, see diff below:" 19 | diff /opt/EC001/stderr.txt /opt/solutions_EC001/stderr.txt 20 | echo 21 | ((failed=failed+1)) 22 | fi 23 | 24 | if cmp /opt/EC001/both.txt /opt/solutions_EC001/both.txt >/dev/null 2>&1; then 25 | echo "3: Correct" 26 | else 27 | echo "3: Incorrect, see diff below:" 28 | diff /opt/EC001/both.txt /opt/solutions_EC001/both.txt 29 | echo 30 | ((failed=failed+1)) 31 | fi 32 | 33 | exit $failed 34 | -------------------------------------------------------------------------------- /base.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic as builder 2 | 3 | ARG accountname=student 4 | 5 | # remove man exclusion, see https://stackoverflow.com/a/54814897 6 | RUN sed -i '/path-exclude=\/usr\/share\/man\/*/c\#path-exclude=\/usr\/share\/man\/*' /etc/dpkg/dpkg.cfg.d/excludes 7 | 8 | RUN apt-get update && \ 9 | apt-get -y install sudo \ 10 | man \ 11 | manpages-posix 12 | 13 | # required for docker run 14 | ENV HOME /home/${accountname} 15 | RUN useradd -s /bin/bash -m -d ${HOME} ${accountname} 16 | ADD student.sudoers /etc/sudoers.d/${accountname} 17 | RUN chmod 0440 /etc/sudoers.d/${accountname} 18 | 19 | WORKDIR ${HOME} 20 | 21 | FROM builder 22 | 23 | ARG basedir 24 | 25 | ADD ${basedir}/ ./ 26 | RUN chown ${accountname}:${accountname} ./* 27 | # test that required files are there 28 | RUN bash -c "if [ ! -f \"${HOME}/task\" ]; then exit 1; fi" 29 | # run setup script in container if provided and remove it 30 | RUN bash -c "if [ -f \"${HOME}/setup.sh\" ]; then chmod +x ${HOME}/setup.sh && ${HOME}/setup.sh && rm ${HOME}/setup.sh; fi" 31 | 32 | USER student 33 | CMD cat ${HOME}/task ; bash 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Maximilian Bischoff 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_REPO ?= maxbischoff 2 | TAG ?= latest 3 | task_folders = $(patsubst %/task,%,$(wildcard */*/task)) 4 | 5 | .PHONY: build-tasks build-base readmes push-tasks push-base 6 | 7 | build-base: .out/base 8 | push-base: .out/base_pushed 9 | build-tasks: .out/$(task_folders) 10 | push-tasks: .out/$(task_folders)/pushed 11 | readmes: $(task_folders)/README.md 12 | 13 | .out/base: base.Dockerfile student.sudoers .base/* 14 | docker build -t practice-base -f base.Dockerfile --build-arg basedir=.base/ . 15 | touch .out/base 16 | 17 | .out/base_pushed: .out/base 18 | docker tag practice-base $(DOCKER_REPO)/practice-base 19 | docker push $(DOCKER_REPO)/practice-base:$(TAG) 20 | touch .out/base_pushed 21 | 22 | .out/$(task_folders): $(task_folders)/* 23 | docker build -t $(subst /,_,$(task_folders)) -f base.Dockerfile --build-arg basedir=$(task_folders) . 24 | mkdir -p $@ 25 | 26 | .out/$(task_folders)/pushed: .out/$(task_folders) 27 | docker tag $(subst /,_,$(task_folders)) $(DOCKER_REPO)/$(subst /,_,$(task_folders)) 28 | docker push $(DOCKER_REPO)/$(subst /,_,$(task_folders)):$(TAG) 29 | touch $@ 30 | 31 | $(task_folders)/README.md: $(task_folders)/task tasks-readme-base.md 32 | cp tasks-readme-base.md $@ 33 | @# use sed command that is compatible with MacOS and Linux 34 | @# https://stackoverflow.com/questions/5694228/sed-in-place-flag-that-works-both-on-mac-bsd-and-linux 35 | sed -i.bak -e 's/HEADING/$(subst /,: ,$(task_folders))/g' $@ 36 | sed -i.bak -e 's#IMAGE#$(DOCKER_REPO)/$(subst /,_,$(task_folders))#g' $@ 37 | rm $@.bak 38 | cat $(dir $@)/task >> $@ 39 | 40 | .PHONY: clean clean-readmes 41 | clean: clean-readmes 42 | rm -rf .out/* 43 | 44 | clean-readmes: 45 | rm -f $(task_folders)/README.md 46 | --------------------------------------------------------------------------------