Repository: pizzamig/pot Branch: master Commit: 5ef4db1cb181 Files: 189 Total size: 922.2 KB Directory structure: gitextract_cytad9_s/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ └── workflows/ │ ├── ci.yml │ ├── main.yml │ └── shellcheck.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Jenkinsfile ├── LICENSE ├── README.md ├── bin/ │ └── pot ├── etc/ │ ├── pot/ │ │ ├── flavours/ │ │ │ ├── dns │ │ │ ├── dns.sh │ │ │ ├── fbsd-update.sh │ │ │ └── slim.sh │ │ ├── pot.conf.sample │ │ └── pot.default.conf │ └── rc.d/ │ ├── pot │ └── pot_early ├── release.sh ├── share/ │ ├── doc/ │ │ └── pot/ │ │ ├── .gitignore │ │ ├── Description.md │ │ ├── Images.md │ │ ├── Installation.md │ │ ├── Makefile │ │ ├── QuickStart.md │ │ ├── Synopsis.md │ │ ├── conf.py │ │ ├── index.md │ │ └── migration.md │ ├── pot/ │ │ ├── add-dep.sh │ │ ├── clone-fscomp.sh │ │ ├── clone.sh │ │ ├── common-flv.sh │ │ ├── common.sh │ │ ├── config.sh │ │ ├── copy-in.sh │ │ ├── copy-out.sh │ │ ├── create-base.sh │ │ ├── create-fscomp.sh │ │ ├── create-private-bridge.sh │ │ ├── create.sh │ │ ├── de-init.sh │ │ ├── destroy.sh │ │ ├── exec.sh │ │ ├── export-ports.sh │ │ ├── export.sh │ │ ├── get-attribute.sh │ │ ├── get-rss.sh │ │ ├── help.sh │ │ ├── import.sh │ │ ├── info.sh │ │ ├── init.sh │ │ ├── last-run-stats.sh │ │ ├── list.sh │ │ ├── mount-in.sh │ │ ├── mount-out.sh │ │ ├── network.sh │ │ ├── prepare.sh │ │ ├── prune.sh │ │ ├── ps.sh │ │ ├── purge-snapshots.sh │ │ ├── rename.sh │ │ ├── revert.sh │ │ ├── set-attribute.sh │ │ ├── set-cmd.sh │ │ ├── set-env.sh │ │ ├── set-hook.sh │ │ ├── set-hosts.sh │ │ ├── set-rss.sh │ │ ├── set-status.sh │ │ ├── show.sh │ │ ├── signal.sh │ │ ├── snapshot.sh │ │ ├── start.sh │ │ ├── stop.sh │ │ ├── term.sh │ │ ├── top.sh │ │ ├── update-config.sh │ │ ├── version.sh │ │ └── vnet-start.sh │ └── zsh/ │ └── site-functions/ │ └── _pot └── tests/ ├── CI/ │ ├── resolv.conf-dual │ ├── resolv.conf-ipv4 │ ├── resolv.conf-ipv6 │ └── run.sh ├── add-dep1.sh ├── clone-fscomp1.sh ├── clone1.sh ├── clone2.sh ├── common-flv1.sh ├── common-stub.sh ├── common-zfs1.sh ├── common-zfs2.sh ├── common1.sh ├── common2.sh ├── common4.sh ├── common5.sh ├── common6.sh ├── common7.sh ├── common8.sh ├── conf-stub.sh ├── config1.sh ├── copy-in1.sh ├── copy-out1.sh ├── create-base1.sh ├── create-fscomp1.sh ├── create-private-bridge1.sh ├── create1.sh ├── create2.sh ├── create3.sh ├── destroy1.sh ├── export-ports1.sh ├── export1.sh ├── get-rss1.sh ├── import1.sh ├── info1.sh ├── info2.sh ├── list1.sh ├── list2.sh ├── monitor.sh ├── mount-in1.sh ├── mount-out1.sh ├── network1.sh ├── pipefail-stub.sh ├── ps1.sh ├── rename1.sh ├── rename2.sh ├── rename3.sh ├── rename4.sh ├── revert1.sh ├── set-attr1.sh ├── set-attr2.sh ├── set-cmd1.sh ├── set-env1.sh ├── set-env2.sh ├── set-hook1.sh ├── set-hosts1.sh ├── set-rss1.sh ├── show1.sh ├── shunit/ │ ├── .gitignore │ ├── .travis.yml │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE │ ├── README.md │ ├── doc/ │ │ ├── CHANGES-2.1.md │ │ ├── RELEASE_NOTES-2.1.0.txt │ │ ├── RELEASE_NOTES-2.1.1.txt │ │ ├── RELEASE_NOTES-2.1.2.txt │ │ ├── RELEASE_NOTES-2.1.3.txt │ │ ├── RELEASE_NOTES-2.1.4.txt │ │ ├── RELEASE_NOTES-2.1.5.txt │ │ ├── RELEASE_NOTES-2.1.6.txt │ │ ├── RELEASE_NOTES-2.1.7.md │ │ ├── TODO.txt │ │ ├── contributors.md │ │ └── design_doc.txt │ ├── examples/ │ │ ├── equality_test.sh │ │ ├── lineno_test.sh │ │ ├── math.inc │ │ ├── math_test.sh │ │ ├── mkdir_test.sh │ │ ├── mock_file.sh │ │ ├── mock_file_test.sh │ │ ├── party_test.sh │ │ └── suite_test.sh │ ├── lib/ │ │ ├── shflags │ │ └── versions │ ├── shunit2 │ ├── shunit2_args_test.sh │ ├── shunit2_asserts_test.sh │ ├── shunit2_failures_test.sh │ ├── shunit2_macros_test.sh │ ├── shunit2_misc_test.sh │ ├── shunit2_standalone_test.sh │ ├── shunit2_test_helpers │ └── test_runner ├── signal1.sh ├── signal2.sh ├── snapshot1.sh ├── start2.sh ├── start3.sh ├── start4.sh ├── stop1.sh ├── term1.sh ├── test-suite.sh ├── top1.sh └── version1.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Report a bug you found title: "[BUG]" labels: bug assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Create the `pot` with this command: '...' 2. Run this command: '...' 3. See error **Expected behavior** A clear and concise description of what you expected to happen. **System configuration - if possible** - `/usr/local/etc/pot/pot.conf` ** If network related ** - `cat /etc/pf.conf` - `potnet show -v` **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: A nice to have title: '' labels: feature assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the feature you'd like to have** A clear and concise description of what you want to happen. **Describe potential alternatives or workaround you've considered (if any)** A clear and concise description of any alternative solutions or workaround you've considered. ================================================ FILE: .github/workflows/ci.yml ================================================ name: Run CI on: workflow_dispatch: push: branches: [ github-ci-action ] # pull_request: # branches: [ master ] jobs: ci_test_suite: name: CI test suite runs-on: ${{ matrix.job.os }} strategy: fail-fast: false matrix: job: - { os: macos-12 } release: [ "13.1" ] steps: - uses: actions/checkout@v3 - name: Run tests/CI/run.sh uses: vmactions/freebsd-vm@v0 with: mem: 8192 usesh: true copyback: false prepare: pkg install -y curl gmake potnet freebsd-release-manifests nmap run: | ##################################################################################### ### Prepare, build, and test ##################################################################################### ### based on ref: ### and on ref: ### * NOTE: All steps need to be run in this block, otherwise, we are operating back ### on the mac host set -exo pipefail # ### Basic user setup ################################################################ TEST_USER=tester TEST_USER_HOME="/opt/$TEST_USER" REPO_NAME=${GITHUB_WORKSPACE##*/} WORKSPACE_PARENT="/Users/runner/work/${REPO_NAME}" WORKSPACE="${WORKSPACE_PARENT}/${REPO_NAME}" OS_VERSION="$(freebsd-version | awk -F- '{print $1}')" PUB_INTF="$(netstat -4rn | grep default | awk '{ print $4}')" ifconfig # mkdir -p "$TEST_USER_HOME" pw adduser -n "$TEST_USER" -d "$TEST_USER_HOME" -c "Tester" -h - chown -R "$TEST_USER":"$TEST_USER" "$TEST_USER_HOME" chown -R "$TEST_USER":"$TEST_USER" "/$WORKSPACE_PARENT"/ whoami # ### Output some information about the environment ################################## # environment echo "## environment" env | sort # tooling info echo "## installed packages" pkg info # ### Create zpool #################################################################### dd if=/dev/zero of=/zfs1 bs=1 count=1 seek=2G zdev=$(mdconfig -a -t vnode -S 4096 -f /zfs1) zpool create -f zroot "$zdev" # ### Configure pf and pot ############################################################ echo "set skip on lo0" >/etc/pf.conf echo pass >>/etc/pf.conf service pf enable service pf start pw groupadd pot bin/pot init # ### Run CI tests ################################################ cd "$WORKSPACE" cp -f etc/pot/pot.default.conf etc/pot/pot.conf cd tests/CI set +e FAULT=0 ./run.sh || FAULT=1 echo "Log output:" cat pot-ci-* if [ $FAULT -ne 0 ]; then exit 1; fi # ### Finished ######################################################################## echo "Done" ================================================ FILE: .github/workflows/main.yml ================================================ # This is a basic workflow to help you get started with Actions name: unit-test # Controls when the action will run. Triggers the workflow on push or pull request # events but only for the master branch on: push: branches: [ master ] pull_request: branches: [ master ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 # Runs a single command using the runners shell - name: Run a one-line script run: cd tests && ./test-suite.sh ================================================ FILE: .github/workflows/shellcheck.yml ================================================ name: Shellcheck on: [ pull_request ] jobs: shellcheck: name: Shellcheck runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Run ShellCheck uses: ludeeus/action-shellcheck@master with: scandir: share/pot additional_files: bin/pot ================================================ FILE: .gitignore ================================================ /doc *.swp *~ /etc/pot/pot.conf /etc/pot/flavours/* !/etc/pot/flavours/dns.sh !/etc/pot/flavours/dns !/etc/pot/flavours/slim.sh !/etc/pot/flavours/fbsd-update.sh devenv.sh /tests/CI/pot-ci* ================================================ FILE: .travis.yml ================================================ language: bash script: cd tests && ./test-suite.sh ================================================ FILE: CHANGELOG.md ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## Unreleased ### Added - import/prepare: Support setting a default signature public key to verify pot signature (#296) ### Fixed - prune: Only attempt to stop pot if it is running (#295) ## [0.16.0] 2023-12-30 ### Added - tinirc: Write tinirc's pid to /tmp/tinirc.pid (#277) - set-attr/stop: Add attributes exec_stop and stop_timeout (#275) - init/de-init: Add flag "-m" to be minimally intrusive, add flag -p to specify pf file (#284) - init: Add flag -s to not alter syslogd settings, deprecate flag -f pf_file, as it is replaced by -p (#284) - vnet: Add global configuration POT_ISOLATE_VNET_POTS to prevent direct traffic between VNET pots (#283) ### Fixed - tinirc: Overwrite tinirc on start instead of appending to an existing file (#277) - start: Fix setting of nullfs attribute - set-status: Ignore status files that predate system boot (#278) - set-status: Forward verbosity flags (#279) - network: Find bridge interfaces by interface group, this allows custom bridge names (#282) ## [0.15.6] 2023-09-29 ### Added - start: Add custom pf rule configuration hook, POT_EXPORT_PORTS_PF_RULES_HOOK (#273) - Remove basepath from mountpoint, make mount-in/out errors more visible (#259) ## [0.15.5] 2023-06-29 ### Added - set-attr: Add support for setting devfs_ruleset (#270) - set-attr: Add support for setting mlock, sysvshm, sysvsem, sysvmsg, retire sysvipc attribute, which was always a noop (#263) ### Fixed - pot-cmd: Output problems with pot root to stderr (#254) - version: Don't require pot root to exist to run version command (#253) - mount-in: Skip empty lines in fscomp.conf during mount process (#258) ## [0.15.4] 2022-12-15 ### Added - set-attr: add jail attributes "raw_sockets", "sysvipc" (#247, #248) - import/export/prepare: support signing pots (#221) ### Changed - flavours: scripts are made executable when loading - destroy: remove status file when destroying - vnet: use unique epaira interface names (#232) - Add pot group to protect pot root (#240) ### Fixed - Reverted the change of permissions of pot root mountpoint to fix a regression (#233) - set-attr: fix no-etc-hosts attribute handling - Remove leftover mount points on destroy (#236) - set-attr/get-attr: fix help output (#245) - Fix running flavour script on non-persistent pot (#238) ## [0.15.3] 2022-09-17 ### Fixed - stop: Destroy epair interface if stop is not called from start (#229) ## [0.15.2] 2022-09-17 ### Fixed - start: fix pot getting stuck in state "starting" on pot start failure (#227) ## [0.15.1] 2022-09-16 ### Fixed - set-status: fix a bug that deletes the status (#224) ## [0.15.0] 2022-09-11 ### Added - mount-out: new command to remove or unmount a previously mount-in folder or fs - attribute no-tmpfs: an attribute, for single dataset only, to not use tmpfs for /tmp - create/import: inherit ZFS encryption property from parent filesystem (#196) - attribute no-etchosts: an attribute, to not inject additional /etc/hosts entries from `potnet` - last-run-stats: new command to get statistics on the last run of a pot, currently contains "ExitCode", which is the exit code of pot.cmd (#200) - start: return with code 125 in case pot.cmd of a non-persistent pot failed (#200) - tinirc: wait for epair interface, exit early if it doesn't become available (#204) - ifconfig: label and group interfaces created by pot (#206) - clone: add dns option, to customize DNS configuration while cloning (#199) - prepare: add -d option to change dns configuration during clone (#192) - signal: send signals to processes running inside a pot (#216) - exec: command to execute programs inside a running pot (#217) ### Changed - Stop logging trivial commands like get-rss to syslog by default (#190) - get-rss: test if the pot is running, instead of it only exists during input validation - mount-in: mountpoint cannot contain spaces anymore (#187) - start: allow pots to run for less than 5 seconds (#200) - start: always stop and cleanup non-persistent pots once pot.cmd finished, prevents stray background tasks from keeping them alive (#200) - prune: add flag "-g" to delay pruning of pots that just stopped, so users have a chance to inspect last-run-stats (#200) - help: rework usage screens (#209) - prepare: enable attribute no-tmpfs and no-etc-hosts (#192) - tests: improved monitoring of tests, requires sysutils/flock on FreeBSD (#220) - Change permissions of pot root mount point to be only accessible by root user (#218) ### Fixed - start: correct invocation of prestart and poststart hooks (#200) - tinirc: configure address selection policy (#205) - fdescfs/procfs: fixed the correcte behavior of those attribute, such as mount them at start - mount-out: fix it - clone: fix cleanup after failed clone (#214) - start/stop: heavy rework to fix concurrency (#202) ## [0.14.0] 2021-10-31 ### Added - copy-in: -c option to create missing dirs on copy-in (#172) - create: New command copy-in-flv, which is the same as copy-in, but always relative to flavourdir (#173) - init: -f option to specify pf file to patch on init (#181) ### Changed - start: do not write jid files to POT_TMP (#178) - start/stop: remove pot_stopped files from TMP_DIR after stopping non-persistent jails (#179) ### Fixed - prepare: fix -N option to allow network-type "host" as used by nomad-pot-driver (#177) - copy-in: fix tmp source directory creation ## [0.13.0] 2021-09-21 ### Added - import-export: add support for layered images (#151) - POT_TMP: add a parameter to select the folder used to create temporary files - flavour: -f option support a full pathname (#161) - copy-out: new command to copy file or folder out from a pot (#162) ### Changed - start: simplify startup, use jexec to run pot.cmd (#150) - flavour: the current directory is added to the flavour search path (#161) ### Fixed - start/stop: prevent stopping non-persistent jails twice (#152) - stop: garbage collect POSIX shared memory (#150) - start: fix ncat failing to start due to argv handling (#167) ## [0.12.0] 2021-05-22 ### Added - pot.conf: add parameter to control max hostname length inside the pot (#118) - CI: add shellcheck as hard requirements in the PR flow - export-ports: add UDP support, as -e udp:53:53 (#115) - create: dns custom allows to statically provide a resolv.conf - POT_EXTIF_ADDR: new parameter to force which IP of EXTIF should be used for NAT and RDR - clone: add support for applying flavors to cloned pots - clone: add -k flag to keep the cloned pot for debug when the process failed - info: -s to list available snapshots of a pot - clone: -s flag to explicitly choose the snapshot to clone - architecture: remove limitation of amd64 as the only architecture supported (#143 by jmg@) - start/stop/term/run: add support to -p potname on those commands, the only one not supporting it ### Changed - hostname: max default length for hostname set to 64 (#118) - create: adopt the new hostname length parameter (#118) - clone: adopt the new hostname length parameter (#118) - ext-if: do not include interface aliases in the bridges network if EXTIF has them (#120) - start: add support for custom dns resolver - init: create backup of rc.conf and pf.conf before to apply pot related changes - info: -B instead of -b for private bridge information - copy-in: copy is executed in the jail environment, to avoid soft-link related issues in the destination path - copy-in: with running pots, a -F flag is needed to force the copy, an operation that is discouraged for security reasons - fetch base.txz: the base FreeBSD tarball used to be temporarily stored in /tmp. While a POT_CACHE folder is available, use that instead. ### Removed - create-dns: remove this already deprecated command, leaving the user to create a dns for the public bridge ### Fixed - zsh: fix autocompletion for set-hook (#139 by urosgruber) ## [0.11.6] 2020-12-14 ### Fixed - stop: remove resolv.conf only if dns is not off (#117) ## [0.11.5] 2020-11-21 ### Added - create: dns off allows to skip the resolv.conf configuration ### Fixed - start: (FreeBSD 12.2) pf fails to load rdr rule in some cases ## [0.11.4] 2020-09-12 ### Added - set-attr: add many jails attributes: enforce_stats mount fdescfs libprocfs nullfs procfs tmpfs zfs children ### Fixed - localhost-tunnel: fix multiple port support (#108) ## [0.11.3] 2020-08-03 ### Changed - start: remove temporary files (#91 #92) ### Fixes - clone: fix a typo refactoring the grep that remove network parameters (#90) - mount-in: fix mountpoint validation when pot is stopped and -v is passed (#93) - clone: hooks have been ignored by clone (#94) - info: fix withespace quoting with -E flag (#95) - prepare: fix -i command to allow multiple IP addresses (#97) - ifconfig: force IFCONFIG_FORMAT to avoid conflicting user setting (#99) ## [0.11.2] 2020-05-01 ### Added - prepare: the -S option is now used to specify the network stack ### Changed - prepare: the -S flag to start the imported pot changed in -s ### Fixed - fbsd-update: don't assume there is a tty (#86) - clone: duplicate the entry pot.stack (#88) ## [0.11.1] 2020-04-19 ### Fixed - set-attr: attribute early-start-at-boot is now correctly recognized ## [0.11.0] 2020-04-19 ### Added - create-base: automatically call freebsd-update when a base is created (#83) - attribute early-start-at-boot: for pot needed to start early at boot (REQUIRE: NETWORKING syslogd pf) - create: add a -k flag to keep the pot, even if it's creation process failed - network stack: add network stack as framework concept (ipv4, ipv6 or dual) - CI: import the run.sh script, with regression system tests - alias: the new notation -i can be repeated to assign multiple IPs to different NICs - hooks: added variables to provide the full new alias network configuration ### Changed - osrelease: detect it from freebsd-version, deprecating the osrelease field in pot.conf (#83) - start-at-boot: the pot rc.d service will be executed late, with jail - create: if create fails, the partially created pot is automatically destroyed - create: -P will use send/receive from a snapshot, to cut the dependency with the snapshot - create-multi: usr.local and custom dataset are send/received instead of cloned - inherit: it inherits the stack configured in pot.conf - alias: extend -i option to accept netif|ipaddr - alias: -i option can be repeated more than once to add more ip addresses to the same instance - syslogd: initial removal of syslogd forwarding ### Removed - alias: remove option -I, in favour of a more flexible and powerful -i - export: remove option -s, to select a specific snapshot (already deprecated) - snapshot: remove option -n, to specify a snapshot name (already deprecated) - snapshot: remove flag -a, to snapshot external ZFS datasets (already deprecated) - revert: remove flag -a, to restore external ZFS datasets (already deprecated) ### Fixed - mount-in: compute the realpath of the mount-point - create: use pipefail only where implemented - ipv6: rtsold doesn't start in a jail on 11.3 ## [0.10.4] 2020-02-23 ### Added - alias: add ability to use a different network interface for alias network type (#80) - env: add pot info -E output to environment or tinirc - log: add the ability to log activites in syslog ### Fixed - prepare: fix multiple export port support - rc script: extend PATH to make potnet accessible - etc/hosts: add full hostname to localhost ## [0.10.3] 2020-01-07 ### Changed - export-ports: relax the check bout the pot's network type - list: print a message, if there are no pot yet ## [0.10.2] 2019-12-17 ### Added - fbsd-update flavour: add a flavour to run freebsd update ### Changed - slim flavour: remove a bounch of other directories ### Fixed - flavor: set-cmd can cause issue if it has quotes or double quotes in the command string - tinirc: lo1 initialization needed only for public or private bridge - start: background tasks now check if the pot is running - init: fix bridge folder creation - prepare: fix prepare when no command is provided (-c is optional) ## [0.10.1] 2019-12-04 ### Added - set-hooks: add support for pre/post start/stop hooks. Script are executed in the host environment (#61) ### Changed - home-usr/home: those link are not always available. Change create and crate-base to have them always (reported by Philip Jocks) ### Fixed - create: permission of /tmp in single type are wrong (#72) - create: if FreeBSD base fetch is interrupted, a broken file is left and the checksum will always fail (#73) - import: if the image fetch is interrupted, a broken file is left and the checksum will always fail - import: fix hostname rename - localhost-tunnel: fix kill of ncat tunnel, when the pot has a long name ## [0.10.0] 2019-11-01 ### Added - info: support for bridge - set-hosts: new command to add custom etc/hosts entries to a pot - set-env: new command to add environment variable to a pot - network-type private-bridge: add a new network layout, to provide private bridges for a group of pots - create-private-bridge: new subcommand to define and create a private-bridge - create: add option -B, to provide the bridge name if network-type is private-bridge - clone: add option -B, to provide the bridge name if network-type is private-bridge - prepare: add option -B, to provide the bridge name if network-type is private-bridge - destroy: add option -B, to provide a way to destroy a bridge - Image Guide: added a guide about how to create an Image of a pot - POT_EXTRA_EXTIF: add addition network interfaces support ### Changed - start: overwrite /etc/hosts of a pot, adding all pots on the same bridge and custom entries added via set-hosts - flavorable commands: extend support to set-cmd and set-env - pot-rdr anchor: the name of the anchor is now a truncated pot name (the last 54 characters) - export: it's executed only if one snapshot is available. -F force execution, -A fix the number of snapshots, via purge-snapshots or taking a shapshot automagically - start: using exec.start instead of command (it seems more predictable) ### Deprecated - snapshot: -n option to provide custom name to snapshots - support to full pot snapshot (external zfs dataset) in snapshot and start, as well as the _pot_zfs_snap_full function - support to full pot revert (external zfs dataset) in revert/rollback (option -a) - create-dns: undocumented and too hard to maintain - export: -s option, to specify a snapshot. It's misleading, because zfs send -R will send all the previous snapshots anyway ### Fixed - flavorable commands: they cannot exit, but return. create can stop flavour execution otherwise - show: fix single type support and directory in fscomp.conf - start: if the command has arguments with equals, it would have been truncated ## [0.9.2] 2019-08-25 ### Added - prune: invoke a stop, before the destroy, even if the pot is not runing - lockf: introducing lockf to run create, import or clone one at a time ### Fixed - stop: make the pkill on ncat more robust - stop: add a workaround for a race condition in the epair driver ## [0.9.1] 2019-08-20 ### Added - localhost-tunnel attribute: new attribute to create a tunnet to redirect traffic from localhost (consul feature) ### Changed - prepare: allow network type "host" as alias for "inherit" (nomad-friendly feature) - prepare: set localhost-tunnel automatically (consul-friendly feature) ### Fixed - get-rss: fix return code when the pot is not valid - set-cmd: fix potential double quotes surrouding the command - get-rss: TotalTicks is now expressed in Mhz (pcpu * max cpu Frequency) - get-rss: add swap usage statistic - start: fix tinirc permission if no-rc-script is used with network type different than public-bridge - destroy: use -f to remove the 'Device busy' issue ## [0.9.0] 2019-08-13 ### Added - Installation Guide: a more detailed guide, that better explains the installation of pot - fdescfs attribute: new attribute to mount fdescfs inside the pot - init: add a network configuration validation step ### Changed - POT_CACHE: the cache used by import is now a dataset, child of POT_ZFS_ROOT - set-rss: CPU limits is set as maximum amount of CPU. At start, pot decide where to allocate using potcpu - prunable: if a pot is prunable, it has to be started at least once to be pruned (flavour counts) ## [0.8.0] 2019-07-30 ### Added - update-config: implemented -a flag to update all pot configurations in one run - get-rss: show the current resources usage (output available in json) - procfs attribute: new attribute to mount a procfs inside the pot - prunable attribute: new attribute prunable, to automatically delete not running pots (prune) - prune: new command to automatically destro yinactive prunable pots ### Changed - create: rework how to configure the network type of a pot - Quickstart Guide: rework the guide using mount-in and copy-in, listing all possibilities - README: remove the introduction and pointing to the Quickstart guide instead - import: removed -a option, not really needed during import - prepare: optimized, importing once and using clone instead of import+rename every time - clone: add -N option, to change network type while cloning - prepare: add -N option, to change network type while preparing ### Removed - promote: after a long deprecation time, promote has been deleted - add-fscomp: removed, mount-in is its more generic replacement - add-file: removed, copy-in is its more generic replacement - execute: remove this alias of prepare ### Fixed - start: if the start command doesn't go in background, rss and persist weren't managed ## [0.7.0] 2019-07-04 ### Added - update-config: new command that will update a pot configuration - execute: an orchestration oriented command that imports and automatically set several settings on a pot - prepare: new command, taking the place of execute - copy-in: new command, to copy files or directory inside a pot (generalized replacement of add-file) - mount-in: new command, to mount a directory, a zfs dataset or a fscomp inside a pot (replacement for add-fscomp) ### Changed - export-ports: removed -S for static port export - export-ports: add the ability to associate any host port to a pot port to be exported using pot_port:host_port format - execute: an alias for prepare ### Deprecated - add-file: deprecated, replaced by the more general new copy-in command - add-fscomp: deprecated, replaces by the more general new mount-in command ## [0.6.1] 2019-06-25 ### Fixed - init: make pf.conf more robust - vnet-start: make pf start more robust, in case pf as service is not up ## [0.6.0] 2019-06-23 ### Added - add-fscomp: add option -d, to allow to mount generic directories into a pot (-d and -f are mutual) - show: add -q flag, to only show pot names - set-attribute: to set pot attributes (options/flags/configurations) - get-attribute: to get pot attributes (options/flags/configurations) - FreeBSD version usable to create a pot are all the ones listed in the FreeBSD MANIFEST - attributes: add persistent attribute to jail - attributes: add no-rc-script attribute to start a pot without a rc script - add-file: new command to copy a single file inside a pot ### Changed - inherit network: added ipv6 support (automatic) - static IP network: added ipv6 support - pf: adopt anchor with relevant changes in nat rules management ### Deprecated - pot_list: in rc.conf pot_list is not supported anymore. Please use the start-at-boot attribute ### Fixed - syntax error in zsh autocompletion - ls fscomp: using zfs instead of ls (if a fscomp is re-mounted, the mountpoint is not in /opt/pot/fscomp anymore) - static-ip: Fix invocation to potnet to validate ip addresses ## [0.5.11] 2019-03-04 ### Added - export: new command. export generates a compressed file with the entire pot in it. It works only for single type pot - export: -D option to change export directory and -l option to change compression level - POT_CACHE: a place to cache pot images. It's a variable of pot.conf - import: new command. import create a new pot based on an image generated via export - import-export: add skein has verification support ### Changed - rc.d: changed order, to start pot before ntpdate - destroy: extend the usage of -F to be able to destroy corrupted pots ### Fixed - destroy: fix return code - rename: fix single pot support - get_conf_var: using a better RE to avoid to detect variables value in pot names (Thanks to Johan Hendriks to report) ## [0.5.10] 2019-01-15 ### Added - destroy: option -f can be used to delete/destroy a fscomp (no recursive support yet) - vnet-start: add support to VPN and custom pf configuration ### Changed - destroy: option -f (force) is now -F ### Fixed - is_pot: improve support to single pots, that don't have fscomp.conf file - create-base: fix regression introduced on 0.5.9 (RC support and create -F removal) ## [0.5.9] 2018-12-16 ### Added - Add support to RC FreeBSD version - config: add pot_prefix and fscomp_prefix as possible values - snapshot: add option -n to give a name to the snapshot; valid for fscomp only - Add support to FreeBSD 12.0 ### Changed - create: removed -F option and silent default flavor invocation. Default flavor has to be explicitely selected via -f - create-base: removed support for undocumented default-base flavor ## [0.5.8] 2018-11-29 ### Added - QuickStart.md : a markdown quick guide, for new users - create : -i auto (based on potnet) to get automatically a valid IP address - clone : -i auto (based on potnet) to get automatically a valid IP address - clone : add support to single type pot - export-port : new command that allow pot ports to be exposed outside (vnet case) - slim flavor, designed to be used with single dataset pot types - purge-snapshot : new command that will remove all snapshots, except the last one - export-port : static option, to add statically exported ports ### Changed - init : it takes care of syslogd configuration in the host system - create : type=single will install plain FreeBSD and run the default flavour - create : multiple flavour support, executed in sequentially; option -f can be repeated - add-fscomp : exploit the new internal refactorized mount and umount function to avoid to start the pot - add-fscomp : if the pot is running, mount the new fscomp right away ### Fixed - clone : fix a misleading/false positive error message - clone : fix syslogd configuration in the cloned pot - destroy : fix if pot is a single dataset one - start : fix hostname warning - start (#046) : run the jail in a clean enviroment - term (#046) : spawn the shell in a jail using the jailed user environment - add-fscomp (#045) : check the mount point and create it, if missing - list (#052) : fixing xargs invocation ### Deprecated - promote : mark promot as deprecated, so we can remove it in the next major release ## [0.5.7] 2018-06-28 ### Added - create-base : add support to FreeBSD 11.2 ### Fixed - version (#038) : fix the version number showed ## [0.5.6] 2018-05-18 ### Added - create-base : add option -b, to provide a specific name to a base and support multiple bases with the same FreeBSD version - create: add support to single dataset pots. - set-cmd: add the command to manage the command line that starts the container - top: add a new command, to spawn a top only on a pot ## [0.5.5] 2018-04-18 ### Added - ps : add ps subcommand, to show information about which pot is running - config : add config subcommand, to easily access configuration values - zsh autocompletion (#013): pot autocompletion support for zsh - syslogd log unification (#032): when possible, syslogd autoconfigured to log in the host instead of in the pot ### Changed - list : keep it more simple, leaving more information under -v - show : add -r (all running pots) option and made it the new default - show : -a greatly improved show all relevant information per pot ### Removed - fs.conf is not supported anymore ## [0.5.0] 2018-03-16 ### Added - add-fscomp : add the ability to remount a fscomp (-w), instead of mount it via nullfs - add-fscomp : add the ability to mount a fscomp in read-only (-r) - info : new command, to get information about a specific pot - rc.d script (#022) - create (#020) : add option -s, to configure static ip address (alias to external network interface) - create-base (#030) : add sha verification using freebsd-release-manifests - version : add a subcommand the print the current version of the utility - fscomp.conf : new fs component description file - clone : -f option to automatically get a snapshot of a dataset, if needed - promote (#008) : add promote command ### Changed - create: the new wiki page shows the slightly different behavior of all use cases - create: fscomp.conf is generated instead of fs.conf, using dataset instead of mountpoint as first column - private datasets are now mounted changing the mountpoint of the dataset, instead of relying on nullfs For that reasons, an option called "zfs-remount" is added to the fs.conf file ### Deprecated - fs.conf: fs.conf is deprecated. Support will be removed in the next release. ### Removed - create: -S option, not needed anymore ## [0.4.0] 2018-02-13 ### Added - rollback : added rollback as alias of revert - help : add support for aliases - add-fscomp (#027): add support for external ZFS dataset via the option -e - de-init (0#23): new command to completely remove (de-install) pot from your system ### Fixed - stop (#024): check the pot existance - stop : fixed error messages referring to "jail" - list : fix help, option -s never implemented - destroy (0#25): fix pot name validation and add dependency detection ## [0.3.1] 2018-01-26 ### Added - pot.conf.sample : a documentated pot.conf example ## [0.3.0] 2018-01-26 ### Added - Every command that need root privileges perform a check of the user id - create (#010): add a validation of command types executable in a pot flavour - Checks about VIMAGE and rctl usability (#018) ### Changed - set-rss : rename command (it was add-rss) - vnet-start (#019): automatic activation of ip forwarding ### Fixed - create-base (#016): do not re-create the base pot - rename (#017): apply the rename also in dependents pots (level 2 or runtime dependency) - create (#021): -b argument validation ## [0.2.0] 2018-01-23 ### Added - create-dns : new command, to create the dns pot - create : add the option -d to choose the type of dns (inherit or pot) - start : add the support to dns types ### Fixed - rename : remove a misleading error message - start : proper stop, if one mount fails - vnet-start (#009): pf module loaded and firewall enabled ## [0.1.0] 2017-12-14 ### Added - Add resource constraints, via add-rss command - Add clone-fscomp command, to clone a fscomp - Add clone command, to clone a pot - Add rename command, to completely rename a pot - Add dependency support, and related command add-dep - Add support to destroy bases and their related level 0 pot - Add support to recursive destroy - Add support to default flavour with create-base - Add -F option to create, to disable the default flavour - More tests ### Changed - Move packages db to the usr.local dataset - it's a breaking change ## [0.0.2] 2017-12-03 ### Fixed - Fixed start, a typo prevents the correct behavior ## [0.0.1] 2017-12-03 ### Added - Add a revert command, to rollback a pot snapshot - Add snaposhot information in list command - Add a test framework - Add travis-ci support ### Changed - snapshot options has changed to be more consistent and to support fscomp - revert options has changed to be more consistent and to support fscomp ### Fixed - If a start fails, it tries to clean up (umount) ## [0.0.1-rc.1] 2017-11-28 ### Added - Add a vnet-start command, to properly init the vnet network configuration (bridge+pf) - Add an option to show, to show all pot resource usage - Add some command alias: ls is an alias of list - Auto-start of vnet, when needed - Add level 2 pot support, adding special option -P and -S in create command - Add a run command, to start and enter in a pot - Add a -f option to destroy and term, to fix/force the operation - Add -F for flavor and -a for all in list command ### Changed - Changed pot configuration. No jail.conf anymore, but pot.conf - Pots with an ip are now based on epair/vnet/VIMAGE technology - Command show now shows resource usage of all pots by default - Add more information in show and list command ### Deprecated - jail.conf files are currently ignored, please destroy and recreate pots ### Removed - scripts directory and j\* commands in bin. None of them could really works ## [0.0.1-beta] 2017-11-07 ### Added - Add option -b to list, to list available bases - Add option -f to list, to list available fs components - Add a destroy command, to destroy a pot - Add a term command, to start a pot - First implementation of show, that shows memory used by running pots - Add support to flavour- pot subcommand and shell script ### Changed - Remove jail references and use pot instead (not in zfs) - jstart command is now start - jstop command is now stop - create-jail command is not create - create-base creates the related level 0 pot automatically - start doesn't invoke exit if succeeds ### Fixed - Fix add-fscomp that can introduce valid, but imprecise mount-point - Fix create-base that created a wrong usr.local.etc link ## [0.0.1-alpha] 2017-10-20 ### Added - Add the central utility called 'pot' - Add a central configuration file - Add a init command, to initialize the zfs layout - Add a create-base command, to create a new base - Add a create-fscomp command, to create a new base - Add a create-jail command, to create a new base - Add a jstart command, to start a pot - Add a jstop command, to stop a pot - Add an option to jstart, to take a snapshot of the pot before the start - Add a help command, to show subcommand helps - Add a list command, to list of pots - Add a add-fscomp command, to add fscomponents to pots - Add a snapshot command, to take a snapshot of a pot ### Changed - After long time spent on thinking, the project has a new nice name, pot. ================================================ FILE: Jenkinsfile ================================================ pipeline { agent any environment { TERM = 'rxvt' } stages { stage('Test') { steps { sh 'echo "Hello World"' sh ''' cd tests ./test-suite.sh ''' } } } } ================================================ FILE: LICENSE ================================================ BSD 3-Clause License Copyright (c) 2017, Luca Pizzamiglio All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================ # THIS REPOSITORY IS NO LONGER ACTIVELY MAINTAINED, IT HAS MOVED TO https://codeberg.org/bsdpot/pot # pot [![build-badge](https://github.com/pizzamig/pot/workflows/unit-test/badge.svg)](https://github.com/pizzamig/pot/actions) [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) Another container framework based on jails, to run FreeBSD containers on FreeBSD. Every running instance is called `pot`, like the one that I use to cook all the different type of pasta. It's heavily based on FreeBSD, in particular on jails, ZFS, pf and rctl. The project's initial goal was to prove that FreeBSD has all the technologies to have a container-alike environment. The project then evolved into something more robust and feature-rich. The project was presented for the first time at FOSDEM 2018: ([talk page](https://archive.fosdem.org/2018/schedule/event/pot_container_framework/)) If you are more interested in jail orchestration, a nomad driver is provided to interact with `pot` and this work has been presented at FOSDEM 2020 ([talk page](https://archive.fosdem.org/2020/schedule/event/orchestrating_jails/)) ### Documentation The project's documentation is available at [https://pot.pizzamig.dev](https://pot.pizzamig.dev) More in details: * A Getting started guide is available [here](https://pot.pizzamig.dev/Getting) * An installation guide, with detailed description is available [here](https://pot.pizzamig.dev/Installation) ### Nomad pot driver integration A driver to allow [nomad](https://www.nomadproject.io) to interact with `pot` has been developed and available [here](https://github.com/trivago/nomad-pot-driver) ### Ansible Collection There is pot collection for Ansible provided by github user @zilti available at https://galaxy.ansible.com/zilti/pot. ### Online help `pot` provide an online help: ``` # pot help Usage: pot command [options] Commands: help -- Show help version -- Show the pot version config -- Show pot framework configuration ls/list -- List of the installed pots show -- Show pot information info -- Print minimal information on a pot top -- Run the unix top in the pot ps -- Show running pots init -- Initialize the ZFS layout de-init -- Deinstall pot from your system vnet-start -- Start the vnet configuration create-base -- Create a new base image create-fscomp -- Create a new fs component create-private-bridge -- Create a new private bridge create -- Create a new pot (jail) clone -- Clone a pot creating a new one clone-fscomp - Clone a fscomp rename -- Rename a pot destroy -- Destroy a pot prune -- Destroy not running prunable pots copy-in -- Copy a file or a directory into a pot mount-in -- Mount a directory, a zfs dataset or a fscomp into a pot add-dep -- Add a dependency set-rss -- Set a resource constraint get-rss -- Get the current resource usage set-cmd -- Set the command to start the pot set-env -- Set environment variabls inside a pot set-hosts -- Set etc/hosts entries inside a pot set-hook -- Set hook scripts for a pot set-attr -- Set a pot's attribute get-attr -- Get a pot's attribute export-ports -- Let export tcp ports start -- Start a jail (pot) stop -- Stop a jail (pot) term -- Start a terminal in a pot run -- Start and open a terminal in a pot snap/snapshot -- Take a snapshot of a pot rollback/revert -- Restore the last snapshot purge-snapshots -- Remove old/all snapshots export -- Export a pot to a file import -- Import a pot from a file or a URL prepare -- Import and prepare a pot - designed for jail orchestrator update-config -- Update the configuration of a pot ``` Every command has its own online help as well. For instance: ``` pot create [-hv] -p potname [-N network-type] [-i ipaddr] [-l lvl] [-f flavour] [-b base | -P basepot ] [-d dns] [-t type] -h print this help -v verbose -k keep the pot, if create fails -p potname : the pot name (mandatory) -l lvl : pot level (only for type multi) -b base : the base pot -P pot : the pot to be used as reference -d dns : one between inherit(default), pot, off or custom:filename -f flavour : flavour to be used -t type: single or multi (default multi) single: the pot is based on a unique ZFS dataset multi: the pot is composed by a classical collection of 3 ZFS dataset -N network-type: one of those inherit: inherit the host network stack (default) alias: use a static ip as alias configured directly to the host NIC public-bridge: use the internal commonly public bridge private-bridge: use an internal private bridge (with option -B) -i ipaddr : an ip address or the keyword auto (if compatible with the network-type) auto: usable with public-bridge and private-bridge (default) ipaddr: mandatory with alias, usable with public-bridge and private-bridge -B bridge-name : the name of the bridge to be used (private-bridge only) -S network-stack : the network stack (ipv4, ipv6 or dual) ``` ================================================ FILE: bin/pot ================================================ #!/bin/sh # Copyright (c) 2017, Luca Pizzamiglio # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Force ifconfig into expected format export IFCONFIG_FORMAT=addr:default # Environment initialization and initial checks # shellcheck disable=SC2034 _POT_VERSION=0.16.0 _POT_PATHNAME="$(realpath "$0")" _POT_PREFIX="$(dirname "${_POT_PATHNAME}")" _POT_INCLUDE="$( realpath "${_POT_PREFIX}/../share/pot")" _POT_ETC="$( realpath "${_POT_PREFIX}/../etc/pot")" if [ -d "${_POT_ETC}/flavours" ]; then _POT_FLAVOUR_DIR="$( realpath "${_POT_ETC}/flavours")" else # shellcheck disable=SC2034 _POT_FLAVOUR_DIR= fi if [ ! -d "${_POT_INCLUDE}" ]; then echo "Fatal error! Not able to find the subroutines directory as ${_POT_INCLUDE}!" exit 1 fi # loading subroutines if [ ! -r "${_POT_INCLUDE}/common.sh" ]; then echo "Fatal error! Not able to find common subroutines in ${_POT_INCLUDE}!" exit 1 fi # shellcheck disable=SC1090 . "${_POT_INCLUDE}/common.sh" if [ ! -r "${_POT_INCLUDE}/common-flv.sh" ]; then echo "Fatal error! Not able to find flavor subroutines in ${_POT_INCLUDE}!" exit 1 fi # shellcheck disable=SC1090 . "${_POT_INCLUDE}/common-flv.sh" if [ ! -r "${_POT_INCLUDE}/network.sh" ]; then echo "Fatal error! Not able to find network subroutines in ${_POT_INCLUDE}!" exit 1 fi # shellcheck disable=SC1090 . "${_POT_INCLUDE}/network.sh" # loading configuration if [ -r "$_POT_ETC/pot.default.conf" ]; then # shellcheck disable=SC1090 . "$_POT_ETC/pot.default.conf" else _error "Fatal error! Not able to find default configuration file on $_POT_ETC" exit 1 fi if [ -r "$_POT_ETC/pot.conf" ]; then # shellcheck disable=SC1090 . "$_POT_ETC/pot.conf" fi usage() { cat <<-"EOF" Usage: pot command [options] Commands: help -- Show help version -- Show version of the pot command config -- Show pot framework configuration ls/list -- List of the installed pots show -- Show information on pots info -- Print minimal information on a pot top -- Run top(1) inside the pot ps -- Show running pots init -- Initialize the ZFS layout de-init -- Remove pot from your system vnet-start -- Start vnet configuration create-base -- Create a new base image create-fscomp -- Create a new fs component create-private-bridge -- Create a new private bridge create -- Create a new pot (jail) clone -- Clone a pot, creating a new one clone-fscomp -- Clone an fscomp rename -- Rename a pot destroy -- Destroy a pot prune -- Destroy non-running, prunable pots copy-in -- Copy a file or a directory into a pot copy-out -- Copy a file or a directory out of a pot mount-in -- Mount directory, ZFS dataset, or fscomp into a pot mount-out -- Unmount directory, ZFS dataset, or fscomp from a pot add-dep -- Add a dependency set-rss -- Set a resource constraint get-rss -- Get the current resource usage set-cmd -- Set the command to start the pot set-env -- Set environment variables inside a pot set-hosts -- Set /etc/hosts entries inside a pot set-hook -- Set hook scripts for a pot set-attribute/set-attr -- Set an attribute on a pot get-attribute/set-attr -- Get an attribute from a pot export-ports -- Allows exposing tcp and udp ports start -- Start a pot (jail) stop -- Stop a pot (jail) term -- Open terminal inside of a pot run -- Same as term, but start pot if it is not running snap/snapshot -- Take a snapshot of a pot rollback/revert -- Restore the latest snapshot purge-snapshots -- Remove old/all snapshots export -- Export a pot to a file import -- Import a pot from a file or a URL prepare -- Import and prepare a pot, used by orchestrators update-config -- Update the configuration of a pot last-run-stats -- Get statistics about a pot's last run signal -- Send signal to pot exec -- Execute a progam inside of a pot EOF } # shellcheck disable=SC2034 # variable initialization _POT_VERBOSITY=1 # parsing command line subcommand if [ $# -lt 1 ]; then usage exit 1 fi CMD="$1" shift case "${CMD}" in ls) CMD=list ;; rollback) CMD=revert ;; snap) CMD=snapshot ;; set-attr) CMD=set-attribute ;; get-attr) CMD=get-attribute ;; esac case "${CMD}" in help) if [ -n "$1" ]; then pot-cmd "${CMD}" "$1" exit 0 else usage exit 0 fi ;; show|version|config|\ list|info|ps|top|\ init|de-init|vnet-start|\ create-base|create-fscomp|create|\ create-private-bridge|\ copy-in|copy-out|mount-in|mount-out|prune|set-hook|\ destroy|add-dep|set-rss|get-rss|set-cmd|set-env|set-hosts|\ export|import|prepare|\ export-ports|set-attribute|get-attribute|\ start|stop|term|\ rename|clone|clone-fscomp|promote|\ snapshot|revert|purge-snapshots|update-config|\ last-run-stats|signal|exec|set-status) pot-cmd "${CMD}" "$@" exit $? ;; run) pot-cmd term -f "$@" exit $? ;; *) usage exit 1 ;; esac ================================================ FILE: etc/pot/flavours/dns ================================================ set-attribute -A start-at-boot -V YES ================================================ FILE: etc/pot/flavours/dns.sh ================================================ #!/bin/sh pkg install -y dnsmasq pkg install -y consul pkg clean -ayq if [ ! -d /usr/local/etc/consul.d ]; then mkdir -p /usr/local/etc/consul.d fi _epair="$(ifconfig | egrep 'epair.*b' | cut -f 1 -d':')" _ip="$( ifconfig $_epair inet | awk '/inet/ { print $2; }' )" _ip1="$( echo $_ip | cut -f 1 -d'.' )" _ip2="$( echo $_ip | cut -f 2 -d'.' )" _domain="$( hostname | cut -f 2 -d'.' )" echo "server=/${_domain}/127.0.0.1#8600" >> /usr/local/etc/dnsmasq.conf echo "server=/0.${_ip2}.${_ip1}.in-addr.arpa/127.0.0.1#8600" >> /usr/local/etc/dnsmasq.conf echo "listen-address=${_ip}" >> /usr/local/etc/dnsmasq.conf sysrc dnsmasq_enable="YES" sysrc consul_enable="YES" sysrc consul_args="-server -dev -domain=${_domain} -bind=${_ip}" ================================================ FILE: etc/pot/flavours/fbsd-update.sh ================================================ #!/bin/sh export PAGER=/bin/cat freebsd-update --not-running-from-cron fetch install ================================================ FILE: etc/pot/flavours/slim.sh ================================================ #!/bin/sh dirs="/usr/share/bsdconfig /usr/share/doc /usr/share/dtrace /usr/share/examples /usr/share/man /usr/share/openssl /usr/share/sendmail /usr/share/pc-sysinstall /usr/libexec/bsdinstall /usr/libexec/bsdconfig /rescue /usr/tests /usr/lib32 /usr/lib/clang /usr/include /var/db/freebsd-update /var/db/etcupdate /boot" usr_bin="c++ c++filt c89 c99 cc CC cpp clang clang-cpp clang-tblgen clang++ gdb gdbtui gdbserver ld ld.bfd ld.lld lldb llvm-objdump llvm-tblgen nm objcopy objdump strings strip" usr_bin_glob="svnlite yp" usr_sbin="dtrace" usr_sbin_glob="bhyve boot yp" rm -f /usr/lib/*.a ## Remove pkg stuff rm -rf /var/db/pkg/* rm -rf /usr/sbin/pkg rm -rf /usr/local/sbin/pkg for d in $dirs ; do rm -rf ${d} done ( cd /usr/bin for f in $usr_bin ; do rm -f $f done for g in $usr_bin_glob ; do rm -rf ${g}* done ) ( cd /usr/sbin for g in $usr_sbin_glob ; do rm -rf ${g}* done rm -f $usr_sbin ) ================================================ FILE: etc/pot/pot.conf.sample ================================================ # pot configuration file # All datasets related to pot use the some zfs dataset as parent # With this variable, you can choose which dataset has to be used # POT_ZFS_ROOT=zroot/pot # It is also important to know where the root dataset is mounted # POT_FS_ROOT=/opt/pot # This is the cache used to import/export pots # POT_CACHE=/var/cache/pot # This is where pot is going to store temporary files # POT_TMP=/tmp # This is the group owning POT_FS_ROOT # POT_GROUP=pot # This is the suffix added to temporary files created using mktemp, # X is a placeholder for a random character, see mktemp(1) # POT_MKTEMP_SUFFIX=.XXXXXXXX # Define the max length of the hostname inside the pot # POT_HOSTNAME_MAX_LENGTH=64 # Internal Virtual Network configuration # IPv4 Internal Virtual network # POT_NETWORK=10.192.0.0/10 # Internal Virtual Network netmask # POT_NETMASK=255.192.0.0 # The default gateway of the Internal Virtual Network # POT_GATEWAY=10.192.0.1 # The name of the network physical interface, to be used as default gateway # POT_EXTIF=em0 # The list of extra network interface, to make other network segments accessible # POT_EXTRA_EXTIF=vlan20 vlan50 # for each extra interface, a variable is used to sepcify its network segment # POT_NETWORK_vlan20=192.168.100.0/24 # POT_NETWORK_vlan50=10.50.50.0/24 # Do not allow bridge-based pots to forward traffic to each other # POT_ISOLATE_VNET_POTS=true # DNS on the Internal Virtual Network # name of the pot running the DNS # POT_DNS_NAME=dns # IP of the DNS # POT_DNS_IP=10.192.0.2 # Path to default public key to verify pot signatures using signify(1) # on import/prepare - can be overridden using `-C pubkey`. # POT_DEFAULT_SIGNATURE_PUBKEY=/usr/local/etc/pot/sign_key.pub # VPN support # name of the tunnel network interface # POT_VPN_EXTIF=tun0 # POT_VPN_NETWORKS=192.168.0.0/24 192.168.10.0/24 ================================================ FILE: etc/pot/pot.default.conf ================================================ # pot configuration file - default values # All datasets related to pot use the some zfs dataset as parent # With this variable, you can choose which dataset has to be used POT_ZFS_ROOT=zroot/pot # It is also important to know where the root dataset is mounted POT_FS_ROOT=/opt/pot # This is the cache used to import/export pots POT_CACHE=/var/cache/pot # This is where pot is going to store temporary files POT_TMP=/tmp # This is the group owning POT_FS_ROOT POT_GROUP=pot # This is the suffix added to temporary files created using mktemp, # X is a placeholder for a random character, see mktemp(1) POT_MKTEMP_SUFFIX=.XXXXXXXX # Define the max length of the hostname inside the pot POT_HOSTNAME_MAX_LENGTH=64 # Internal Virtual Network configuration # IPv4 Internal Virtual network POT_NETWORK=10.192.0.0/10 # Internal Virtual Network netmask POT_NETMASK=255.192.0.0 # The default gateway of the Internal Virtual Network POT_GATEWAY=10.192.0.1 # The name of the network physical interface, to be used as default gateway POT_EXTIF=em0 # Additional network interfaces POT_EXTRA_EXTIF= # If not empty, it will use this IPv4 on POT_EXTIF as defualt gateway POT_EXTIF_ADDR= # Three possible values: ipv4, ipv6, dual POT_NETWORK_STACK=ipv4 # DNS on the Internal Virtual Network # name of the pot running the DNS POT_DNS_NAME=dns # IP of the DNS POT_DNS_IP=10.192.0.2 # If set to true, isolate pot vnet bridge members # (by using `ifconfig private `, see ifconfig(8)) POT_ISOLATE_VNET_POTS=false # If not empty, this script will be called by pot and the pf rules # returned on stdout will be loaded into "pot-rdr/anchor" instead # of those which pot would usually create. This also skips # creation of netcat-based localhost-tunnels. # Only works with IPv4 at the moment. # # Parameters sent to the script are: # POT_EXTIF BRIDGE POT_NETWORK POT_GATEWAY proto host_port pot_ip pot_port # Example: # igb0 bridge1 10.192.0.0/10 10.192.0.1 tcp 32732 10.192.0.10 80 POT_EXPORT_PORTS_PF_RULES_HOOK= # VPN support # Path to default public key to verify pot signatures using signify(1) # on import/prepare - can be overridden using `-C pubkey`. POT_DEFAULT_SIGNATURE_PUBKEY= # name of the tunnel network interface POT_VPN_EXTIF= POT_VPN_NETWORKS= # POT log facility POT_LOG_FACILITY=local2 ================================================ FILE: etc/rc.d/pot ================================================ #!/bin/sh # PROVIDE: pot # REQUIRE: NETWORKING LOGIN FILESYSTEM # BEFORE: securelevel # KEYWORD: shutdown nojail . /etc/rc.subr PATH=$PATH:/usr/local/bin name="pot" desc="Pot containers" procname="pot" rcvar=pot_enable start_cmd="pot_start" stop_cmd="pot_stop" restart_cmd="pot_restart" status_cmd="pot_status" start_precmd="pot_deprecated_start" stop_postcmd="pot_deprecated_stop" load_rc_config $name : ${pot_enable:=NO} pot_start() { local _pname _dyn_pot_list _start _dyn_pot_list=$(/usr/local/bin/pot ls -q) for _pname in $_dyn_pot_list ; do if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A start-at-boot -q )" = "YES" ]; then /usr/local/bin/pot start "$_pname" fi done } pot_stop() { local _pname _dyn_pot_list _start _dyn_pot_list=$(/usr/local/bin/pot ls -q) for _pname in $_dyn_pot_list ; do if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A start-at-boot -q )" = "YES" ]; then /usr/local/bin/pot stop "$_pname" fi done } pot_early_start() { local _pname _dyn_pot_list _start _dyn_pot_list=$(/usr/local/bin/pot ls -q) for _pname in $_dyn_pot_list ; do if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ]; then /usr/local/bin/pot start "$_pname" fi done } pot_early_stop() { local _pname _dyn_pot_list _start _dyn_pot_list=$(/usr/local/bin/pot ls -q) for _pname in $_dyn_pot_list ; do if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ]; then /usr/local/bin/pot stop "$_pname" fi done } pot_restart() { pot_stop pot_early_stop sleep 5 pot_early_start pot_start } pot_status() { local _pname _dyn_pot_list _dyn_pot_list=$(/usr/local/bin/pot ls -q) for _pname in $_dyn_pot_list ; do if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ] || [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A start-at-boot -q )" = "YES" ]; then if /usr/local/bin/pot info -qrp "$_pname" ; then echo "pot $_pname is up and running" else echo "pot $_pname is not running" fi fi done } run_rc_command "$1" ================================================ FILE: etc/rc.d/pot_early ================================================ #!/bin/sh # PROVIDE: pot_early # REQUIRE: NETWORKING syslogd pf # BEFORE: ntpdate # KEYWORD: shutdown nojail . /etc/rc.subr PATH=$PATH:/usr/local/bin name="pot_early" desc="Pot containers - early start" procname="pot" rcvar=pot_enable start_cmd="pot_early_start" stop_cmd="pot_early_stop" load_rc_config $name : ${pot_enable:=NO} pot_early_start() { local _pname _dyn_pot_list _start _dyn_pot_list=$(/usr/local/bin/pot ls -q) for _pname in $_dyn_pot_list ; do if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ]; then /usr/local/bin/pot start "$_pname" fi done } pot_early_stop() { local _pname _dyn_pot_list _start _dyn_pot_list=$(/usr/local/bin/pot ls -q) for _pname in $_dyn_pot_list ; do if [ "$( /usr/local/bin/pot get-attr -p "$_pname" -A early-start-at-boot -q )" = "YES" ]; then /usr/local/bin/pot stop "$_pname" fi done } run_rc_command "$1" ================================================ FILE: release.sh ================================================ #!/bin/sh print_syntax() { echo "$0" X.Y.Z ; exit "${1:-1}"; } if [ -z "$1" ]; then print_syntax fi if [ "$1" = "$(echo "$1" | sed -E 's/[0-9]+(\.[0-9]+)+//')" ]; then echo invalid verion number $1 print_syntax exit fi version="$1" tag_date="$(date +%Y-%m-%d)" echo applying new version "$version" with date "$tag_date" sed -i '' "s/^_POT_VERSION=.*$/_POT_VERSION=$version/" 'bin/pot' sed -i '' 's/^## \[Unreleased\]/## \[Unreleased\]\ \ ### NEWVERSION/' CHANGELOG.md sed -i '' "s/### NEWVERSION/## \[$version\] $tag_date/" CHANGELOG.md sed -i '' "s/^version = .*$/version = \"$version\"/" 'share/doc/pot/conf.py' sed -i '' "s/^release = .*$/release = \"$version\"/" 'share/doc/pot/conf.py' git diff -p --stat ================================================ FILE: share/doc/pot/.gitignore ================================================ _build ================================================ FILE: share/doc/pot/Description.md ================================================ DESCRIPTION ----------- Another container framework based on jails, to run FreeBSD containers on FreeBSD. Every running instance is called "pot", but less flexible than a VM. It's heavily based on FreeBSD, in particular on jails, ZFS, pf and rctl. ================================================ FILE: share/doc/pot/Images.md ================================================ # Using `pot` images This guide has the ambitious goal of explain how to create `pot` images, a feature that allows `pot` to be used with nomad, but it can be useful in other use cases. This guide assumes that you have already installed `pot` and you are already familiar with it (installation and quickstart guide). ## What is a `pot` image? A `pot` image is a binary blob representing the `pot` configuration file and it's file system. In more detail, it's a compressed archive containing a ZFS snapshot of a file system. ## Create an images `pot` The fundamental steps to create an image of a `pot` container are: * create a `pot` * "customize" the `pot` as needed * take a snapshot * export the image **NOTE** `export` and `import` support `single` type `pot`s. Multi-dataset `pot` are not supported yet. #### Create a `pot` A `pot` named `test` can be created using the command `pot create`: ```console # pot create -p test -b 12.0 -N public-bridge -t single` ``` * `-p test` : the `pot` name * `-b 12.0` : the FreeBSD release version to be used * `-t single` : the `pot` type. Only `single` type are supported at the moment for `import`/`export` * `-N public-bridge` : the network type (it can be changed during `import`, but it can be useful to use a network type that is relevant for the use case) Once the `pot` named `test` is created, it's possible to : * customize its configuration (attributes, starting command, and so on) * enter in it and do whatever is needed, for instance install `nginx` ```console # pot run test [...] root@test:~ # pkg install nginx [...] root@test:~ # exit exit # pot set-cmd -p test -c "nginx -g 'daemon off;'" # pot set-attr -p test -A no-rc-script -V ON # pot set-attr -p test -A persistent -V NO # pot set-rss -p test -C 1 ``` Once you're satisfied with your `pot`, you can stop it and take a snapshot: ```console # pot stop test # pot snapshot -p test ``` The snapshot can be now exported as an image, with the command `export` ```console # pot export -p test -t 1.0 ``` * `-t 1.0`: the same image can have multiple version. The option `-t` allows to provide a tag to the image The `export` command can take quite some time, because of the compression step. Once the `export` command ends, it generates 2 files: ```console test_1.0.xz test_1.0.xz.skein ``` The first file is the image, the second file is a hash file, used by the `import` command to verify the integrity. #### Snapshots management The `export` command will create an image if and only if one snapshot is available. The flag `-A` try to automatically fix the number of available snapshots: * if 0 snapshots are available, `-A` will automatically invoke `pot snapshot` * if 2+ snapshots are available, `-A` will automatically invoke `pot purge-snapshots` The command `pot purge-snapshots` deletes all snapshots, except the last one. ### Images creation automated with flavours Flavour is the way we currently provide to automate the customization of a `pot`. With flavour, it's possible to automatically: * apply configuration parameters to your `pot` * execute a bootstrap script just putting some files in flavour folder (`/usr/local/etc/pot/flavours`). In the example above, we customized the `pot` `test` via: ```console # pot run test [...] root@test:~ # pkg install nginx [...] root@test:~ # exit exit # pot set-cmd -p test -c "nginx -g 'daemon off;'" # pot set-attr -p test -A no-rc-script -V ON # pot set-attr -p test -A persistent -V NO # pot set-rss -p test -C 1 ``` Now we automate those commands in a flavour, called `nginx-test`. In the flavour folder we create one file for the `pot` configuration: ```console # cat /usr/local/etc/pot/flavours/nginx-test set-cmd -c "nginx -g 'daemon off;'" set-attribute -A no-rc-script -V YES set-attribute -A persistent -V NO set-rss -C 1 ``` The bootstrap script, that will be executed inside the jail, would look like this: ```console # chmode a+x /usr/local/etc/pot/flavours/nginx-test.sh # cat /usr/local/etc/pot/flavours/nginx-test.sh #!/bin/sh [ -w /etc/pkg/FreeBSD.conf ] && sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf ASSUME_ALWAYS_YES=yes pkg bootstrap touch /etc/rc.conf sysrc sendmail_enable="NONE" pkg install -y nginx pkg clean -y ``` The flavour `nginx-test` can now be used with the `create` command: ```console # pot create -p test-flavour -b 12.0 -N public-bridge -t single -f nginx-test ``` An important note: while the bootstrap script is a shell script, where you can do whatever you want, the `pot` command usable in a flavour are a small subset: * `add-dep` * `export-ports` * `copy-in` * `mount-in` * `set-attribute` (the abbreviated form `set-attr` is not recognized here) * `set-cmd` * `set-env` * `set-rss` **NOTE** the `mount-in` command has to be used carefully. If the `pot` will be migrated to a different machine, the folders or the ZFS datasets has to be manually migrated as well ### Images registry and import Once an image is created, we've seen it can be exported: ```console # pot export -p test -t 1.0 # ls test_1.0.xz test_1.0.xz.skein ``` The image freshly created can now be used to create new `pot` via the command `import`: ```console # pot import -p test -t 1.0 -U file:///path/to/images ===> importing test @ 1.0 as test_1_0 /var/cache/pot/test_1.0.xz 174 MB 527 MBps 00s /var/cache/pot/test_1.0.xz.skein 257 B 598 kBps 00s ===> Assigning new IP: 10.192.0.15 ``` * `-p potname` : the name of the pot to be imported * `-t tag`: the version of the image to be imported * `-U URL`: the base URL to be used to download the `pot` image The command, when executed, will download the image from the URL (caching them to `/var/cache/pot` and create a new `pot` called `test_1_0` using that image as file system: ```console # pot info -vp test_1_0 pot name : test_1_0 type : single base : 12.0 level : 0 network_type : public-bridge ip : 10.192.0.15 no ports exported active : false datasets: test_1_0/m snapshots: zroot/pot/jails/test_1_0@1569922467 zroot/pot/jails/test_1_0/m@1569922467 attributes: start-at-boot: NO persistent: NO no-rc-script: YES procfs: NO fdescfs: NO prunable: NO localhost-tunnel: NO to-be-pruned: NO resource limits: max amount cpus: 1 ``` The `import` process automatically recognizes that the `pot` uses the `prublic-bridge` and assigns a new available IP to the imported `pot` ================================================ FILE: share/doc/pot/Installation.md ================================================ # `pot` installation guide This is a guide to prepare your FreeBSD installation to use the `pot` jail framework. **NOTE**: 99% of the operations needs `root` privileges. In this guide, we consider to be logged in as `root` **NOTE2**: ZFS is mandatory, so if you don't know what it is or you don't have a ZFS pool, please consider to read this [quick guide](https://www.freebsd.org/doc/handbook/zfs-quickstart.html). ## FreeBSD version `pot` is mainly developed on CURRENT, but it's tested and used on 12.0. Those two are the versions suggested. It should work also on 11.3, even if the kernel has to be rebuild, to activate VNET(9), via the VIMAGE option. If you want to use FreeBSD 11.3, please follow the instruction reported [here](https://www.freebsd.org/doc/handbook/kernelconfig.html) to build a custom kernel with the VIMAGE option enabled. ## Install `pot` `pot` is available as package or port. The suggested way is to install it using the packages: ```console # pkg install -y pot ``` All dependencies will be automatically installed (if not yet present) If you want to install it using ports, you can ```console # cd /usr/ports/sysutils/pot # make install clean ``` **NOTE** A dependency of `pot`, called `potnet` is written in Rust. If you install `potnet` via ports, the build dependencies will be built as well, and it can take really long time (depending on the power of you system, it could be several hours). ## Enable the resource limit database One really useful feature, needed to improve the isolation between jail, is the resource limit database. This feature is normally disabled (it seems it causes a performance penalty), and it can be enabled only at boot. To do so: ```console # echo kern.racct.enable=1 >> /boot/loader.conf # reboot ``` This settings will take effect at the next reboot. #### Known issue We have found a performance issue with the `vtnet` driver. If you are installing `pot` on a VM using `vtnet`, probably you want to add this line to your `/boot/loader.conf`: ```console echo hw.vtnet.lro_disable=1 >> /boot/loader.conf ``` This settings will take effect at the next reboot. ## `pot` framework configuration Under the folder `/usr/local/etc/pot` you'll find two files: * `pot.default.conf` * `pot.conf` The `pot.default.conf` contains all the default values and it shouldn't be touched. All needed changes can be made in the `pot.conf` file. This configuration file provide already a brief explanation for all paramaters, but here we go deep, explaining them one by one ### File system parameters `pot` is based on ZFS. In the configuration file, 2 parameters are used to let `pot` use your ZFS pool correctly. #### `POT_ZFS_ROOT` (default `zroot/pot`) This paramater is the ZFS dataset that will be used by `pot` to store whatever will be needed: jails file systems, bases, and so on. If the dataset doesn't exist, it will be created by the initialization command (See the last chapter). #### `POT_FS_ROOT` (default `/opt/pot`) This parameter is the mountpoint for the `POT_ZFS_ROOT` dataset. You shouldn't use a mountpoint that exists and contains file, otherwise the content will become unreachable. #### `POT_CACHE` (default `/var/cache/pot`) This parameter specifies the mountpoint of the dataset `POT_ZFS_ROOT/cache`. This dataset is used only to store `pot` images for the `import` and the `prepare`command. The default value is the suggested one. ### Network parameters In order to use network types like `alias` or `public-bridge`, some configuration parameters are needed. #### `POT_EXTIF` (default `em0`) Currently, `pot` assumes that all the network traffic is going through one physical network interface. This parameter configures `pot` to use the specified network interface. It's relevant for `alias`, `public-bridge` and `private-bridge` network type. #### `POT_NETWORK` (default `10.192.0.0/10`) This parameter specifies the IPv4 address of you internal virtual network and is used by the `public-bridge` network type only. It's wise to choose a private network segment that doesn't conflict with your current network setup. The default address space is huge, however you can choose the network range that match your needs. #### `POT_NETMASK` (default `255.192.0.0`) This parameter specifies the netmask relative to the `POT_NETWORK`. Theoretically, the netmask can be derived by the `POT_NETWORK`. For now, this is not the case, so you have to provide a netmask consistent with the network specified in `POT_NETWORK` #### `POT_GATEWAY` (default `10.192.0.1`) This parameter specifies the IP address that will be used as default gateway in your internal virtual network. It has to be part of the network specified in `POT_NETWORK` and it will be used as default gateway for all `pot`s attached to the internal virtual network (`public-bridge` network type). #### `POT_EXTRA_EXTIF` (default empty) In case your host has multiple network interfaces connected to multiple network segments, this option allows your `pot`s to access those network segments. For example, let's say that you have 2 vlan interfaces, called `vlan20` and `vlan30`. `vlan20` is configured as 10.0.20.4/24 `vlan30` is configured as 10.0.30.8/24 To make those segments accessible, the configuration file should look like: ``` POT_EXTRA_EXTIF=vlan20 vlan30 POT_NETWORK_vlan20=10.0.20.0/24 POT_NETWORK_vlan30=10.0.30.0/24 ``` Currently there is no way to use additional external interface for the network type `alias`. All other network types are supported #### Network validation If you want to check that your network configuration is valid, you can use the utility `potnet`: ```console # potnet config-check ``` This command will show only the errors. ### Experimental parameters There are other parameters that are used by some experimental features. #### dns `pot` An experimental feature is to provide an internal dns service running in a `pot` attached to the internal virtual network. The dns is still a work in progress, however two parameters are already present for this feature: * `POT_DNS_NAME`: this parameter specifies the name of the `pot` that will run the dns; default => `dns` * `POT_DNS_IP`: this parameter specifies the IP (internal to the `POT_NETWORK` that the "dns `pot`" will have; default => `10.192.0.2` #### VPN support If your host system is using a VPN to reach some network segments, you can add some parameters in order to be able to connect your internal virtual network to those networks * `POT_VPN_EXTIF`: the name of the network interface of the VPN software tunnel; default: `tun0` * `POT_VPN_NETWORKS`: a list of all network segments served by the VPN; default: `192.168.0.0/16` If you have multiple network segments, you have to list them all. For instance: ```sh POT_VPN_NETWORKS="192.168.0.0/24 192.168.10.0/24 10.10.0.0/16" ``` ## Initialize the environment The initialization of the environment will: * Create the ZFS datasets * Validate the network parameters * Configure `pf(4)` to be aware of the internal virtual network If you are already using `pf`, I suggest to make a backup of you `pf` configuration file. When ready, you can initialize the environment with the command (use the flag `-v` if you want a bit more of verbosity): ```console # pot init ``` ### Initialize and test the internal virtual network The internal virtual network is not always active, but it's automatically activated if a `pot` configured to use it get started. However, a command is provided to activate the virtual network: ```console # pot vnet-start ``` From your host, you can now ping the virtual network default gateway (always reachable from the host): ```console # ping 10.192.0.1 ``` ## Remove the `pot` environment In order to remove the `pot` from your system, a command is provided to make it easy: ```console # pot de-init ``` This powerful command will remove everything related to `pot` and it cannot be undone. Even if not mandatory, it would be nice to know why you removed it. Please, consider to write a feedback email to pizzamig at FreeBSD dot org * What's wrong with `pot`? * What's the missing feature I really need? * How bad is to use it? How can it be more user-friendly? ================================================ FILE: share/doc/pot/Makefile ================================================ # Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SPHINXPROJ = pot SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) ================================================ FILE: share/doc/pot/QuickStart.md ================================================ # QuickStart Guide on `pot` This is an introduction at the usage of `pot`, a `jail(8)` wrapper based on ZFS and `pf(4)` that naively tries to emulate containerization on FreeBSD. `pot` uses FreeBSD specific technologies, so you need a FreeBSD machine to run it. **NOTE**: 99% of the operations needs `root` privileges. In this guide, we consider to be logged in as `root` **NOTE2**: ZFS is mandatory, so if you don't know what it is or you don't have a ZFS pool, please consider to read this [quick guide](https://www.freebsd.org/doc/handbook/zfs-quickstart.html). **NOTE3**: Some features, like memory limits and memory usage, rely on the resources limit framework, normally disabled. Even if it's not mandatory, it's suggested to enable it, with the following steps: ```console # echo kern.racct.enable=1 >> /boot/loader.conf ``` This settings will take effect at the next reboot. **NOTE4**: One of the 3 network configuration need `VNET(9)`, the network subsystem virtualization infrastructure, enabled in the kernel. On FreeBSD 12 and later, this kernel feature is already enabled and you don't need to do anything. On FreeBSD 11.x, you have to rebuild the kernel, enabling the VIMAGE options, following the instruction reported [here](https://www.freebsd.org/doc/handbook/kernelconfig.html) ## Install `pot` The installation process is pretty straightforward: ```console # pkg install -y pot ``` That's it, `pot` and its dependencies are installed, but we're not yet ready. #### Configuration [Optional] Under the folder `/usr/local/etc/pot` you'll find two files: * `pot.default.conf` * `pot.conf` The `pot.default.conf` contains all the default values and it shouldn't be touched. All needed changes have to be stored in the `pot.conf` file. Please take your time to give a look to this file and to change configuration accordingly to your system ### Initialization When you are happy with your configuration file, especially with the location of `POT_ZFS_ROOT`, you can run: ```console # pot init ``` This command will just create the needed ZFS datasets. ## Create a simple `pot` We can now create the simplest `pot` ```console # pot create -p mypot -t single -b 11.3 ``` **NOTE** The FreeBSD machine doesn't have to be the same version of your `pot` (jail). However, the hosting machine's version has to be greater or equal than the `pot`'s one. For instance, you can run a FreeBSD 10.4 `pot` on a FreeBSD 11.3 host. You **cannot** run a FreeBSD 12 `pot` on a FreeBSD 11.3 host. So, we created a `pot`, named `mypot`, based on FreeBSD 11.3 consisting of one ZFS dataset. Now you can start it or stop it, via: ```console # pot start mypot # pot stop mypot ``` If you want to have a shell inside your pot: ```console # pot term mypot # pot run mypot # an alias for start+term ``` ## A bit of diagnostic Via the command: ```console # pot ls # pot ls -v # more information ``` You can see a list of the `pot`s available on you local machine. The verbose output would look like this: ```console pot name : mypot ip4 : inherit active : true base : 11.3 level : 0 datasets: snapshot: ``` If you want to get some information on a specific `pot`, this command is more useful: ```console # pot info -v -p mypot pot name : mypot type : single base : 11.3 level : 0 ip4 : inherit active : true datasets: mypot/m snapshot: attributes: start-at-boot: NO persistent: YES no-rc-script: NO procfs: NO prunable: NO ``` Some explanation of this output: * `type`: currently two types of `pot` are supported: `single`, based on one ZFS dataset, and `multi`, based on multiple ZFS dataset. * `base`: the FreeBSD version used to build this `pot`. * `level`: for single type `pot` the level is always `0`. Levels are explained for the multi type `pot`. * `ip4`: the IPv4 address of the `pot` or the keyword `inherit`. By default, `inherit` is chosen, that means that this `pot` is sharing the same network stack of the running machine. * `active`: it's a boolean value, that tells you if your `pot` is running or not. * `datasets`: single type `pot`s have only one dataset. * `snapshot`: the list of snapshots of this `pot`; currently empty. * `attributes`: attributes/properties of this this `pot` If your `pot` is running, runtime information can be obtained via: ```console # pot start mypot # pot show -p mypot pot mypot disk usage : 274M virtual memory : 13M physical memory : 4820K ``` This command will show the current amount of resources used by this `pot` ## Take a snapshot of your `pot` Thanks to ZFS, taking a snapshot of your stopped `pot` is easy and super fast: ```console # pot stop mypot # pot snap mypot # pot info -v -p mypot [..] snapshot: zroot/pot/jails/mypot@1539804703 zroot/pot/jails/mypot/m@1539804703 ``` The snapshot's name is the Unix epoch and it's used to automatically determine the snapshot's chronological sequence. Now you can restart it and do some real damage: ```console # pot run mypot root@mypot:~ # rm -rf /* [..] root@mypot:~ # exit # pot stop mypot ``` We have deleted almost every file in the `pot`, the pot cannot start again (feel free to try!) The snapshot can be used to revert all the modifications occurred between the time that the snapshot was taken and now, using the following command: ```console # pot revert -p mypot # pot run mypot ``` The revert command will automatically select the newest snapshot available. ## Attach a "volume" to your pot Let's say that you want to attach a pre-existent "volume" to your `pot`. There are several way to do that, depending on what your volume is. ### First volume type: fscomp To support users managing ZFS datasets for `pot`, the concept of `fscomp` (AKA file system component) is introduced. You can create a file system component in the `pot` ecosystem, that can be attached to one or more `pot`s. When a `fscomp` is created, the underlaying ZFS dataset is created as well. To create a `fscomp`, you can run: ```console # pot create-fscomp -f myfscomp ``` With this command, you have created an empty ZFS dataset, a "volume", that can be attached to one or more `pot`s A list of available `fscomp`s can be obtained with the command: ```console # pot ls -f ``` To mount your new `fscomp` to a `pot`, you can use the command: ```console # pot mount-in -p mypot -f myfscomp -m /mnt # pot info -p mypot -v ``` The `-m` mandatory option represents the mountpoint (absolute pathname) inside the `pot`. The advantage of this approach, is that `fscomp` are recognized by the `pot` framework, and a set of features is provided, like snapshot, rollback and clone. ### Second volume type: an already existent dataset It could happen that you want to attach to a `pot` a pre-existing ZFS dataset and you don't want to create an emtpy `fscomp` and move all data there. To add and external ZFS dataset, the command would be: ```console # pot mount-in -p mypot -m /mnt -z zroot/mydataset ``` The only difference is the different option used (`-z` instead of `-f`) and the argument of the option is not a `fscomp` name, but a generic valid ZFS dataset. ### Third volume type: a generic directory There two ways to make external directories available in a `pot`: mount them or copy them. The decision to mount or to copy is to the user to take, with obvious pros and cons. To mount a directory, the command would be: ```console # pot mount-in -p mypot -m /mnt -d mydir ``` The directory `mydir` will be mounted at `/mnt` To copy a directory, the command would be: ```console # pot copy-in -p mypot -s mydir -d /mnt ``` The directory `mydir` (and all its file) will be copied in `/mnt`, creating the directory `/mnt/mydir` ### Forth volume type: a single file For single files, only the copy option is available. ```console # pot copy-in -p mypot -s myfile -d /mnt ``` The file `myfile` will be copied in `/mnt`. ### Common consideration The `mount-in` command will change the configuration of the `pot`; the "volume" will be automatically mounted when the `pot` starts and unmounted when the `pot` stops. If you run `mount-in` when the `pot` is already running, the "volume" is mounted on the fly. A "volume" can be used with multiple `pot`s. Potential problems, like concurrent access to the same files, cannot be managed by `pot` and are left to the user. In order to mitigate concurrency access to the same `fscomp`, the option `-r` is introduced: ```console # pot mount-in -p mypot-ro -f myfscomp -m /mnt -r # pot mount-in -p mypot-rw -f myfscomp -m /mnt ``` This option will inform the framework to mount `myfscomp` in `mypot-ro` in read-only mode, while in `mypot-rw` that same `myfscomp` is mounted in read-write mode. ## Network configuration During the creation phase, it's possible to specify which type of network our `pot` should use. `pot` supports three different type of network configurations: * inherit * alias (IPv4 or IPv6) n the host network interface * IPv4 address on the public internal virtual network * IPv4 address on a private internal virtual network By default, `inherit` is the chosen one. ### Network configuration: inherit To use the `inherit` network type, a `pot` can be created with the following command: ```console # pot create -p mypot -t single -b 11.3 -N inherit ``` The option `-N` can be omitted, because `inherit` is the default value. The `inherit` type means that `mypot` will reuse the same network stack of the host machine. This network type works pretty well when your `pot` doesn't provide/export any network services, but it uses the network's host as client, like a `pot` created to build applications. ### Network configuration: IPv4 or IPv6 alias If your host is a network that support static IPs, you can assign one static IP address to your `pot` via this network configuration type. **NOTE** Be sure that in the `pot` configuration file (`/usr/local/etc/pot/pot.conf`) you have correctly set the variable `POT_EXTIF`; this network interface is the one used to route the network traffic and to assign the IP address. For example, your system has 192.168.178.20/24 as IP address and your network administrator reserved you the additional IP address 192.168.178.200. To assing the latter IP address to your `pot` you can create it with the following command: ```console # pot create -p mypot -t single -b 11.3 -N alias -i 192.168.178.200 # pot start mypot # pot info -vp mypot ``` The alias 192.168.178.200 will be assigned to the network interface during the start phase. Now, your `pot` is bound to the address 192.168.178.200 When the `pot` is stopped, the alias will be automatically removed from the inferface. More information about alias addresses on network interfaces are available in the `man` page of `ifconfig(8)` ### Network configuration: public virtual network bridge Thanks to `VNET(9)`, `pot` supports an IPv4 virtual network. This network is configured in configuration file (`/usr/local/etc/pot/pot.conf`), so be sure you have it properly configured. This network type refers to a shared bridge where the public virtual network lives. All `pot`s with this network type will share it. The virtual internal network is connected with the ouside via NAT. To help the `pot` framework and all users to manage the public virtual network, an additional package is required, normally automatically installed as dependency of the package `pot`. It's also manually installable via: ```console # pkg install potnet ``` To verify you virtual network configuration, this command can be used: ```console # potnet show Network topology: network : 10.192.0.0 min addr: 10.192.0.0 max addr: 10.255.255.255 Addresses already taken: 10.192.0.0 10.192.0.1 default gateway 10.192.0.2 dns ``` The output is from my configuration (and also the default one), however your address' range can differ, depending on the configuration values you have adopted. Optionally, you can start the virtual network via the command: ```console # pot vnet-start ``` This command will create and configure the network interfaces properly and will activate `pf` to perform NAT on the virtual network. **NOTE** This command is automatically executed when a `pot` is configured to use the public virtual network. There is no need to run it manually. The following command will create a `pot` running on the internal network: ```console # pot create -p mypot -t single -b 11.3 -N public-bridge -i auto # pot run mypot root@mypot:~ # ping 1.1.1.1 [..] root@mypot:~ # exit # pot stop mypot ``` The `auto` keyword will automatically select an available address in the internal virtual network and it's the default value, hence the `-i` option can be omitted. Commands like `pot info -p mypot` and `potnet show` will show you exactly which address has been assigned to your `pot` If you prefer to assign a specific IP address of your virtual network to your `pot`, you can just do: ```console # pot create -p mypot2 -t single -b 11.3 -N public-bridge -i 10.192.0.10 ``` `pot` will verify if the IP address is available and free to be used. ### Network configuration: private virtual network bridge The public virtual network has the downside that all `pot`s share the same bridge, affecting isolation. To mitigate this issue, private virtual network has been introduced. A private virtual network is just a different bridge, that can be used to connect multiple `pot`s, but it's not automatically shared with all `pot`s. First of all, to use a private virtual network a private bridge has to be created: ```console # pot create-private-bridge -B mybridge -S 4 ``` This command will create a new private bridge, called `mybridge`, with a network segment big enough to connect 4 `pot`s. Using `potnet` it's possible to check the details of the private bridge via the command: ```console # potnet show -b mybridge 10.192.0.16 mybridge bridge - network 10.192.0.17 mybridge bridge - gateway 10.192.0.23 mybridge bridge - broadcast ``` The output is from my configuration, however your address' range can differ, depending on the configuration values you have adopted and the network segment available when the bridge is created. To activate a specific bridge, you can use the command: ```console # pot vnet-start -B mybridge ``` This command will create and configure the network interfaces properly and will activate `pf` to perform NAT on the virtual network. **NOTE** This command is automatically executed when a `pot` is configured to use the public virtual network. There is no need to run it manually. The following command will create a `pot` running on the private internal network: ```console # pot create -p mypot -t single -b 11.3 -N private-bridge -B mybridge -i auto # pot run mypot root@mypot:~ # ping 1.1.1.1 [..] root@mypot:~ # exit # pot stop mypot ``` The `auto` keyword will automatically select an available address in the internal virtual network and it's the default value, hence the `-i` option can be omitted. Commands like `pot info -p mypot` and `potnet show -b mybridge` will show you exactly which address has been assigned to your `pot` If you prefer to assign a specific IP address of your virtual network to your `pot`, you can just do: ```console # pot create -p mypot2 -t single -b 11.3 -N private-bridge -B mybridge -i 10.192.0.19 ``` `pot` will verify if the IP address is available and free to be used. ### Export network services with the internal network The virtual network is not visible outside the host machine, becuase it's based on NAT of the pf's NAT. To make your network services running in your `pot` visible outside the TCP/UDP, desired ports have to be exported/redirected. `pot` provides a command to tell which port has to be exported. ```console # pot export-ports -p mypot -e 80 -e 443 ``` The `export-ports` command will make available the port 80 and 443 outside the virtual network. At start, `pot` look for an available host port that can be used to redirect the traffic from the host to the virtual network. To know which port is used, you can use the `show` command: ```console # pot start mypot # pot show -p mypot pot mypot disk usage : 274M virtual memory : 13M physical memory : 4824K Network port redirection 192.168.178.20 port 1024 -> 10.192.0.3 port 80 192.168.178.20 port 1025 -> 10.192.0.3 port 443 ``` To map the network services to a specific port, instead of leaving the decision to `pot`, the following syntax can be used: ```console # pot export-ports -p mypot -e 80:30080 -e 443:30443 # pot start mypot # pot show -p mypot pot mypot disk usage : 266M virtual memory : 33M physical memory : 17M Network port redirection 192.168.178.20 port 30080 -> 10.192.0.11 port 80 192.168.178.20 port 30443 -> 10.192.0.11 port 443 ``` However, there is no guarantee that the choosen ports are available. ================================================ FILE: share/doc/pot/Synopsis.md ================================================ SYNOPSIS -------- `pot` SUBCOMMAND ================================================ FILE: share/doc/pot/conf.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # pot documentation build configuration file, created by # sphinx-quickstart on Thu Nov 28 15:41:27 2019. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) from recommonmark.transform import AutoStructify # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.githubpages', 'recommonmark'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.md' # The master toctree document. master_doc = 'index' # General information about the project. project = 'pot' copyright = '2019, Luca Pizzamiglio' author = 'Luca Pizzamiglio' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = "0.16.0" # The full version, including alpha/beta/rc tags. release = "0.16.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { '**': [ 'relations.html', # needs 'show_related': True theme option to display 'searchbox.html', ] } # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. htmlhelp_basename = 'potdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'pot.tex', 'pot Documentation', 'Luca Pizzamiglio', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'pot', 'Another container framework based on jails', [author], 8) ] # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'pot', 'pot Documentation', author, 'pot', 'One line description of project.', 'Miscellaneous'), ] # app setup hook def setup(app): app.add_config_value('recommonmark_config', { 'auto_toc_tree_section': 'Contents', 'enable_math': False, 'enable_inline_math': False, 'enable_eval_rst': True, }, True) app.add_transform(AutoStructify) ================================================ FILE: share/doc/pot/index.md ================================================ Contents -------- * [Synopsis](Synopsis.md) * [Description](Description.md) * [QuickStart](QuickStart.md) * [Installation](Installation.md) * [migration](migration.md) * [Images](Images.md) ================================================ FILE: share/doc/pot/migration.md ================================================ ## Manual migration handbook ### Prerequisite * testing with single type pot * a snapshot is already present ### A xz archive of the datasets * `zfs send -R zroot/pot/jails/mypot@1539804703 | xz > mypot.1539804703.xz` Some statistics on FreeBSD 12.0 The file systems are accounted for 801MB, lz4 providing 2.23 as compression ration, leaving 383MB on the disk. xz -9 is extremely slow, using +800MB of RAM and producing an output of 132MB xz -6 (default) is quite slow, producing an output of 148MB xz -3 is decently fast, producing an output of 164MB xz -0 is quite fast, producing an output of 182MB # Speculation ### A migration process send the first xz file and combine with the receive * `xzcat mypot.1539804703.xz | zfs receive ${POT_ZFS_ROOT}/jails/mypot@1539804703 depending on the content of pot.conf and fscomp.conf, get and extract the other datasets propery In this case: * xzcat mypot_m.1539804703.xz | zfs receive ${POT_ZFS_ROOT}/jails/mypot/m@1539804703 ================================================ FILE: share/pot/add-dep.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : add-dep-help() { cat <<-"EOH" pot add-dep [-hv] -p potname -P depPot -h print this help -v verbose -p potname : the working pot -P depPot : the pot to depend on. Will be started automatically before starting the working pot "potname". EOH } # $1 pot # $2 depPot _add_dependency() { local _depPot _pname _cdir _pname="$1" _depPot="$2" _cdir=$POT_FS_ROOT/jails/$_pname/conf echo "pot.depend=$_depPot" >> "$_cdir"/pot.conf } pot-add-dep() { local _pname _depPot _depPot= _pname= OPTIND=1 while getopts "hvp:P:" _o ; do case "$_o" in h) add-dep-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; P) _depPot="$OPTARG" ;; p) _pname="$OPTARG" ;; *) add-dep-help return 1 ;; esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" add-dep-help return 1 fi if [ -z "$_depPot" ]; then _error "A dependency pot is mandatory" add-dep-help return 1 fi if [ "$_pname" = "$_depPot" ]; then _error "a pot cannot be run time dependecy of itself" add-dep-help return 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" add-dep-help return 1 fi if ! _is_pot "$_depPot" ; then _error "dependency pot $_depPot is not valid" add-dep-help return 1 fi if ! _is_uid0 ; then return 1 fi _add_dependency "$_pname" "$_depPot" } ================================================ FILE: share/pot/clone-fscomp.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : clone-fscomp-help() { cat <<-"EOH" pot clone-fscomp [-hv] -f fscomp -F fscomp -h print this help -v verbose -F fscomp : the fscomp to be cloned (mandatory) -f fscomp : the fscomp name (mandatory) EOH } # $1 new fscomp name # $2 old fscomp name _cf_zfs() { local _fscomp _cfscomp _fsdset _fsdir _snap _fscomp=$1 _cfscomp=$2 _fsdset=${POT_ZFS_ROOT}/fscomp _fsdir=${POT_FS_ROOT}/fscomp _snap=$( _zfs_last_snap "$_fsdset/$_cfscomp" ) if [ -z "$_snap" ]; then _error "$_fsdset/$_cfscomp has no snapshots - please take one" return 1 else _debug "Cloning $_cfscomp@$_snap into $_fsdset/$_fscomp" zfs clone -o mountpoint="$_fsdir/$_fscomp" "$_fsdset/$_cfscomp@$_snap" "$_fsdset/$_fscomp" fi return 0 # true } pot-clone-fscomp() { local _fscomp _cfscomp _fscomp= _cfscomp= OPTIND=1 while getopts "hvf:F:" _o ; do case "$_o" in h) clone-fscomp-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; f) _fscomp=$OPTARG ;; F) _cfscomp=$OPTARG ;; *) clone-fscomp-help ${EXIT} 1 ;; esac done # parameter validation if [ -z "$_fscomp" ]; then _error "fscomp name is missing (option -f)" clone-fscomp-help ${EXIT} 1 fi if [ -z "$_cfscomp" ]; then _error "clonable fscomp name is missing (option -F)" clone-fscomp-help ${EXIT} 1 fi if _zfs_dataset_valid "${POT_ZFS_ROOT}/fscomp/$_fscomp" ; then _error "fscomp $_fscomp already exists" ${EXIT} 1 fi if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/fscomp/$_cfscomp" ; then _error "fscomp $_cfscomp doesn't exist" ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi if ! _cf_zfs "$_fscomp" "$_cfscomp" ; then ${EXIT} 1 fi } ================================================ FILE: share/pot/clone.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : trap _cj_undo_clone TERM INT _set_pipefail clone-help() { cat <<-"EOH" pot clone [-hvF] -p potname -P basepot [-i ipaddr] -h print this help -v verbose -k keep the pot, if clone fails -P potname : the pot to be cloned (template) -s snapshot : the snapshot to be used to clone -p potname : the name of the pot that is created -f flavour : flavour to be used -N network-type : new network type of the cloned pot -i ipaddr : an ip address or the keyword auto (if applicable) -B bridge-name : the name of the private bridge to be used -S network-stack : the network stack (ipv4, ipv6 or dual) -d dns : change pot dns resolver configuration, one of inherit - inherit from jailhost pot - the pot configured in POT_DNS_NAME custom: - copy into pot configuration off - leave resolver config unaltered -F : automatically take snapshots of dataset that has none EOH } # $1 pot name _cj_undo_clone() { _POT_VERBOSITY=0 if [ -z "$_cleanup_pname" ]; then ${EXIT} 1 fi # stop in subshell, so it won't end script execution ( pot-cmd stop "$_cleanup_pname" >/dev/null 2>&1 ) if [ "$_cleanup_keep" != "YES" ]; then pot-cmd destroy -Fp "$_cleanup_pname" -q fi unset _cleanup_pname unset _cleanup_keep ${EXIT} 1 } # $1 pot name # $2 pot-base name # $3 auto-snapshot # $4 custom snapshot tag _cj_zfs() { local _pname _potbase _jdset _pdir _pbdir _pbdset _mnt_p _opt _autosnap _snaptag _pb_type _snap __last_snap _pname=$1 _potbase=$2 _autosnap="$3" _snap="$4" __last_snap= _jdset=${POT_ZFS_ROOT}/jails/$_pname _pbdset=${POT_ZFS_ROOT}/jails/$_potbase _pdir=${POT_FS_ROOT}/jails/$_pname _pbdir=${POT_FS_ROOT}/jails/$_potbase _pb_type="$( _get_conf_var "$_potbase" pot.type )" # Create the main jail zfs dataset if ! _zfs_dataset_valid "$_jdset" ; then zfs create "$_jdset" else _info "$_jdset exists already" fi # Create the conf directory if [ ! -d "$_pdir/conf" ]; then _debug "Create conf dir ($_pdir/conf)" mkdir -p "$_pdir/conf" fi if [ -e "$_pdir/conf/fscomp.conf" ]; then rm -f "$_pdir/conf/fscomp.conf" fi _debug "Cloning $_potbase with snap $_snap" _update_fscomp "$_potbase" if [ "$_pb_type" = "single" ]; then _dset="${_pbdset}/m" if [ -z "$_snap" ]; then _snap=$( _zfs_last_snap "$_dset" ) fi if [ -z "$_snap" ]; then if [ "$_autosnap" = "YES" ]; then _snaptag="$(date +%s)" _info "$_dset has no snap - taking a snapshot on the fly with tag $_snaptag" zfs snapshot "${_dset}@${_snaptag}" _snap=$_snaptag else _error "$_dset has no snap - please take a snapshot of $_potbase" _cj_undo_clone return 1 # error fi fi _debug "clone $_dset@$_snap into $_jdset/m" zfs clone -o mountpoint="$_pdir/m" "$_dset@$_snap" "$_jdset/m" cp "${_pbdir}/conf/fscomp.conf" "$_pdir/conf/fscomp.conf" elif [ "$_pb_type" = "multi" ]; then # Create the root mountpoint _create_pot_mountpoint "$_pdir/m" if [ -z "$_snap" ]; then __last_snap="YES" fi while read -r line ; do _dset=$( echo "$line" | awk '{print $1}' ) _mnt_p=$( echo "$line" | awk '{print $2}' ) _opt=$( echo "$line" | awk '{print $3}' ) # ro components are replicated "as is" if [ "$_opt" = ro ] ; then _debug "$_dset ${_mnt_p} $_opt" echo "$_dset ${_mnt_p} $_opt" >> "$_pdir/conf/fscomp.conf" else # managing potbase datasets if [ "$_dset" != "${_dset##"${_pbdset}"}" ]; then _dname="${_dset##"${_pbdset}"/}" if [ "$__last_snap" = "YES" ]; then _snap=$( _zfs_last_snap "$_dset" ) fi if [ -z "$_snap" ]; then if [ "$_autosnap" = "YES" ]; then _snaptag="$(date +%s)" _info "$_dset has no snap - taking a snapshot on the fly with tag $_snaptag" zfs snapshot "${_dset}@${_snaptag}" _snap=$_snaptag else _error "$_dset has no snap - please take a snapshot of $_potbase" _cj_undo_clone "$_pname" return 1 fi fi if _zfs_exist "$_jdset/$_dname" "$_pdir/$_dname" ; then _debug "$_dname dataset already cloned" else _debug "clone $_dset@$_snap into $_jdset/$_dname" zfs clone -o mountpoint="$_pdir/$_dname" "$_dset@$_snap" "$_jdset/$_dname" if [ -z "$_opt" ]; then _debug "$_jdset/$_dname ${_mnt_p}" echo "$_jdset/$_dname ${_mnt_p}" >> "$_pdir/conf/fscomp.conf" else _debug "$_jdset/$_dname ${_mnt_p} $_opt" echo "$_jdset/$_dname ${_mnt_p} $_opt" >> "$_pdir/conf/fscomp.conf" fi fi # managing fscomp datasets - the simple way - no clone support for fscomp elif [ "$_dset" != "${_dset##"${POT_ZFS_ROOT}"/fscomp}" ]; then _debug "$_dset ${_mnt_p}" echo "$_dset ${_mnt_p}" >> "$_pdir/conf/fscomp.conf" else _error "not able to manage $_dset" fi fi done < "${POT_FS_ROOT}/jails/$_potbase/conf/fscomp.conf" fi return 0 # true } # $1 pot name # $2 pot-base name # $3 network type # $4 ip # $5 bridge name # $6 network stack # $7 dns _cj_conf() { local _pname _potbase _ip _network_type _bridge_name _stack _dns _potdns _pname=$1 _potbase=$2 _network_type=$3 _ip=$4 _bridge_name=$5 _stack=$6 _dns=$7 _pdir=${POT_FS_ROOT}/jails/$_pname _pbdir=${POT_FS_ROOT}/jails/$_potbase if [ ! -d "$_pdir/conf" ]; then mkdir -p "$_pdir/conf" fi if [ "$_dns" != "${_dns##custom:}" ]; then # if dns is custom:filename cp "${_dns##custom:}" "$_pdir/conf/resolv.conf" # copy custom dns config to pot config _potdns=custom else _potdns="$_dns" fi grep -vE '^(host.hostname|bridge|ip|vnet|network_type|pot.stack|pot.dns)' "$_pbdir/conf/pot.conf" > "$_pdir/conf/pot.conf" { echo "host.hostname=\"$( _get_usable_hostname "${_pname}" )\"" echo "pot.stack=$_stack" echo "network_type=$_network_type" case "$_network_type" in "inherit") echo "vnet=false" ;; "alias") echo "vnet=false" echo "ip=$_ip" ;; "public-bridge") echo "vnet=true" echo "ip=$_ip" ;; "private-bridge") echo "vnet=true" echo "ip=$_ip" echo "bridge=$_bridge_name" ;; esac echo "pot.dns=$_potdns" } >> "$_pdir/conf/pot.conf" if [ -e "$_pbdir/conf/prestart.sh" ]; then cp "$_pbdir/conf/prestart.sh" "$_pdir/conf/prestart.sh" fi if [ -e "$_pbdir/conf/prestop.sh" ]; then cp "$_pbdir/conf/prestop.sh" "$_pdir/conf/prestop.sh" fi if [ -e "$_pbdir/conf/poststart.sh" ]; then cp "$_pbdir/conf/poststart.sh" "$_pdir/conf/poststart.sh" fi if [ -e "$_pbdir/conf/poststop.sh" ]; then cp "$_pbdir/conf/poststop.sh" "$_pdir/conf/poststop.sh" fi if [ -e "$_pbdir/conf/resolv.conf" ]; then cp "$_pbdir/conf/resolv.conf" "$_pdir/conf/resolv.conf" fi } pot-clone() { local _pname _ipaddr _potbase _pblvl _autosnap _pb_type _pb_network_type _network_type _bridge_name _network_stack _snap _flv _dns _pname= _ipaddr= _potbase= _pblvl=0 _autosnap="NO" _bridge_name= _network_stack= _cleanup_keep="NO" _snap= _flv= _dns= OPTIND=1 while getopts "hvp:i:P:FN:B:S:f:ks:d:" _o ; do case "$_o" in h) clone-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; k) _cleanup_keep="YES" ;; p) if ! _is_valid_potname "$OPTARG" ; then _error "$OPTARG is not a valid name for a pot ('.' is the only character not allowed)" ${EXIT} 1 fi _pname=$OPTARG ;; N) # shellcheck disable=SC2086 if ! _is_in_list "$OPTARG" $_POT_NETWORK_TYPES ; then _error "Network type $OPTARG not recognized" clone-help ${EXIT} 1 fi _network_type="$OPTARG" ;; i) if [ -z "$_ipaddr" ]; then _ipaddr="$OPTARG" else _ipaddr="$_ipaddr $OPTARG" fi ;; P) _potbase=$OPTARG ;; s) _snap=$OPTARG ;; B) _bridge_name=$OPTARG ;; S) if ! _is_in_list "$OPTARG" "ipv4" "ipv6" "dual" ; then _error "Network stack $OPTARG not valid" create-help ${EXIT} 1 fi _network_stack="$OPTARG" ;; F) _autosnap="YES" ;; f) if _is_flavour "$OPTARG" ; then if [ -z "$_flv" ]; then _flv="$OPTARG" else _flv="$_flv $OPTARG" fi else _error "Flavour $OPTARG not found" _debug "Looking in the flavour dir ${_POT_FLAVOUR_DIR}" ${EXIT} 1 fi ;; d) case $OPTARG in inherit|pot|off) _dns=$OPTARG ;; custom:*) if [ -r "${OPTARG##custom:}" ]; then _dns=$OPTARG else _error "The file ${OPTARG##custom:} is not valid or readable" ${EXIT} 1 fi ;; *) _error "'${OPTARG}' is not a valid dns option" clone-help ${EXIT} 1 esac ;; *) clone-help ${EXIT} 1 ;; esac done if [ -z "$_pname" ]; then _error "pot name is missing (option -p)" clone-help ${EXIT} 1 fi if [ -z "$_potbase" ]; then _error "reference pot name is missing (option -P)" clone-help ${EXIT} 1 fi if ! _is_pot "$_potbase" quiet ; then _error "reference pot $_potbase not found" clone-help ${EXIT} 1 fi if _is_pot "$_pname" quiet ; then _error "pot $_pname already exists" clone-help ${EXIT} 1 fi if [ -n "$_snap" ]; then if [ "$_autosnap" = "YES" ]; then _error "-s and -F are incompatible - which snapshot should I use" clone-help ${EXIT} 1 fi # shellcheck disable=SC2046 if ! _is_in_list "$_snap" $(_get_pot_snaps "$_potbase" | tr '\n' ' ') ; then _error "snapshot $_snap not found" _debug "snapshots available $(_get_pot_snaps "$_potbase" | tr '\n' ' ')" clone-help ${EXIT} 1 fi fi if [ -z "$_network_type" ]; then _pb_network_type="$( _get_pot_network_type "$_potbase" )" if [ -z "$_pb_network_type" ] ; then _error "Configuration file for $_potbase contains obsolete elements" _error "Please run pot update-config -p $_potbase to fix" ${EXIT} 1 fi _network_type="$_pb_network_type" fi if [ -z "$_network_stack" ]; then _network_stack="$( _get_pot_network_stack "$_potbase" )" fi if ! _ipaddr="$( _validate_network_param "$_network_type" "$_ipaddr" "$_bridge_name" "$_network_stack" )" ; then echo "$_ipaddr" clone-help ${EXIT} 1 fi if [ -z "$_dns" ]; then _dns="$(_get_conf_var "$_potbase" pot.dns)" fi _pblvl="$( _get_conf_var "$_potbase" pot.level )" _pb_type="$( _get_conf_var "$_potbase" pot.type )" if [ "$_pblvl" = "0" ] && [ "$_pb_type" != "single" ]; then _error "Level 0 pots cannot be cloned" clone-help ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi export _cleanup_pname="$_pname" export _cleanup_keep if ! _cj_zfs "$_pname" "$_potbase" "$_autosnap" "$_snap" ; then ${EXIT} 1 fi if ! _cj_conf "$_pname" "$_potbase" "$_network_type" "$_ipaddr" "$_bridge_name" "$_network_stack" "$_dns"; then ${EXIT} 1 fi if [ -n "$_flv" ]; then for _f in $_flv ; do if ! _exec_flv "$_pname" "$_f" ; then _cj_undo_clone ${EXIT} 1 fi done fi unset _cleanup_pname unset _cleanup_keep } ================================================ FILE: share/pot/common-flv.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 # $1 flavour name _is_flavour() { local _flv_name _flv_name="$1" if [ -n "$( _get_flavour_script "$_flv_name" )" ] || [ -n "$( _get_flavour_cmd_file "$_flv_name" )" ]; then return 0 # true fi return 1 # false } _get_flavour_script() { local _flv_name _flv_name="$1" if [ -f "$_flv_name" ] && [ "$_flv_name" != "${_flv_name%%.sh}" ]; then ## it's a script path name echo "$_flv_name" elif [ -f "$_flv_name.sh" ]; then ## it's a path name echo "$_flv_name.sh" elif [ -f "./$_flv_name.sh" ]; then echo "./$_flv_name.sh" elif [ -f "${_POT_FLAVOUR_DIR}/$_flv_name.sh" ]; then echo "${_POT_FLAVOUR_DIR}/$_flv_name.sh" fi } _get_flavour_cmd_file() { local _flv_name _flv_name="$1" # if the flavor name ends with .sh return immediately if [ "$_flv_name" != "${_flv_name%%.sh}" ]; then return fi if [ -f "$_flv_name" ] && [ -r "$_flv_name" ]; then ## it's a cmd file path name echo "$_flv_name" elif [ -f "./$_flv_name" ] && [ -r "./$_flv_name" ]; then echo "./$_flv_name" elif [ -f "${_POT_FLAVOUR_DIR}/$_flv_name" ] || [ -r "${_POT_FLAVOUR_DIR}/$_flv_name" ]; then echo "${_POT_FLAVOUR_DIR}/$_flv_name" fi } # $1 the cmd # all other parameter will be ignored # tested _is_cmd_flavorable() { local _cmd _cmd=$1 case $_cmd in add-dep|set-attribute|\ copy-in|copy-in-flv|mount-in|\ set-rss|export-ports|\ set-cmd|set-env) return 0 ;; esac return 1 # false } # Special version of set-cmd usable only for flavours # $1 : pot name # $2 : the set-cmd line in the file _flv_set_cmd() { local _pname _line _cmd _pname="$1" _line="$2" _cmd="${_line#set-cmd -c }" if [ "$_line" = "$_cmd" ]; then _error "In flavour only 'set-cmd -c ' is supported" return 1 fi _set_command "$_pname" "$_cmd" } _exec_flv() { local _pname _flv _pdir _flv_cmd_file _flv_script _flv_dir _previous_pwd _persist _pname=$1 _flv=$2 _pdir=${POT_FS_ROOT}/jails/$_pname _debug "Flavour: $_flv" _flv_cmd_file="$( _get_flavour_cmd_file "$_flv" )" _flv_dir=$(dirname "${_flv_cmd_file}") if [ -n "${_flv_cmd_file}" ]; then _debug "Executing $_flv pot commands on $_pname" while read -r line ; do # shellcheck disable=SC2086 if _is_cmd_flavorable $line ; then if [ "$line" != "${line#set-cmd}" ]; then # workaround for set-cmd / damn quoting and shell scripts if ! _flv_set_cmd "$_pname" "$line" ; then return 1 fi elif [ "$line" != "${line#copy-in-flv}" ]; then # copy-in relative to flavour dir _previous_pwd=$PWD if ! cd "$_flv_dir"; then _error "Can't chdir to flavour dir $_flv_dir" return 1 fi line=$(echo "$line" | sed "s/^copy-in-flv/copy-in/") if ! pot-cmd $line -p "$_pname" ; then return 1 fi if ! cd "$_previous_pwd"; then _error "Can't chdir to previous pwd $_previous_pwd" return 1 fi else # shellcheck disable=SC2086 if ! pot-cmd $line -p "$_pname" ; then return 1 fi fi else _error "Flavor $_flv: line $line not valid - ignoring" fi done < "${_flv_cmd_file}" fi _flv_script="$( _get_flavour_script "$_flv" )" if [ -n "${_flv_script}" ]; then _debug "Starting $_pname pot for the initial bootstrap" _persist="$(_get_conf_var "$_pname" "pot.attr.persistent")" if [ "$_persist" = "NO" ]; then _debug "Setting pot $_pname temporarily to persistent" if ! pot-cmd set-attribute -A persistent -V YES -p "$_pname" ; then return 1 fi fi pot-cmd start "$_pname" cp -v "${_flv_script}" "$_pdir/m/tmp" chmod a+x "$_pdir/m/tmp/$(basename "${_flv_script}" )" _debug "Executing $_flv script on $_pname" if ! jexec "$_pname" "/tmp/$(basename "${_flv_script}")" "$_pname" ; then _error "create: flavour $_flv failed (script)" return 1 fi pot-cmd stop "$_pname" if [ "$_persist" = "NO" ]; then _debug "Reverting pot $_pname to non-persistent" if ! pot-cmd set-attribute -A persistent -V NO -p "$_pname" ; then return 1 fi fi else _debug "No shell script available for the flavour $_flv" fi } ================================================ FILE: share/pot/common.sh ================================================ #!/bin/sh # shellcheck disable=SC2034,SC3033,SC3040,SC3043 : "${EXIT:=exit}" : "${ECHO:=echo}" : "${SED:=sed}" _POT_RW_ATTRIBUTES="start-at-boot early-start-at-boot persistent no-rc-script prunable localhost-tunnel no-tmpfs no-etc-hosts" _POT_RO_ATTRIBUTES="to-be-pruned" _POT_NETWORK_TYPES="inherit alias public-bridge private-bridge" # not devfs handles separately _POT_JAIL_RW_ATTRIBUTES='enforce_statfs mount fdescfs linprocfs nullfs procfs tmpfs zfs raw_sockets sysvshm sysvsem sysvmsg children mlock devfs_ruleset exec_stop stop_timeout' # N: arg name jail command, T: type of data, D: deafult value # devfs is always mounted _POT_DEFAULT_mount_N='allow.mount' _POT_DEFAULT_mount_T='bool' _POT_DEFAULT_mount_D='NO' _POT_DEFAULT_fdescfs_N='mount.fdescfs' _POT_DEFAULT_fdescfs_T='bool' _POT_DEFAULT_fdescfs_D='NO' _POT_DEFAULT_linprocfs_N='allow.mount.linprocfs' _POT_DEFAULT_linprocfs_T='bool' _POT_DEFAULT_linprocfs_D='NO' _POT_DEFAULT_nullfs_N='allow.mount.nullfs' _POT_DEFAULT_nullfs_T='bool' _POT_DEFAULT_nullfs_D='NO' _POT_DEFAULT_procfs_N='mount.procfs' _POT_DEFAULT_procfs_T='bool' _POT_DEFAULT_procfs_D='NO' _POT_DEFAULT_tmpfs_N='allow.mount.tmpfs' _POT_DEFAULT_tmpfs_T='bool' _POT_DEFAULT_tmpfs_D='NO' _POT_DEFAULT_zfs_N='allow.mount.zfs' _POT_DEFAULT_zfs_T='bool' _POT_DEFAULT_zfs_D='NO' _POT_DEFAULT_raw_sockets_N='allow.raw_sockets' _POT_DEFAULT_raw_sockets_T='bool' _POT_DEFAULT_raw_sockets_D='NO' _POT_DEFAULT_sysvshm_N='sysvshm' _POT_DEFAULT_sysvshm_T='sysvopt' _POT_DEFAULT_sysvshm_D='new' _POT_DEFAULT_sysvsem_N='sysvsem' _POT_DEFAULT_sysvsem_T='sysvopt' _POT_DEFAULT_sysvsem_D='new' _POT_DEFAULT_sysvmsg_N='sysvmsg' _POT_DEFAULT_sysvmsg_T='sysvopt' _POT_DEFAULT_sysvmsg_D='new' _POT_DEFAULT_children_N='children.max' _POT_DEFAULT_children_T='uint' _POT_DEFAULT_children_D='0' _POT_DEFAULT_devfs_ruleset_N='devfs_ruleset' _POT_DEFAULT_devfs_ruleset_T='uint' _POT_DEFAULT_devfs_ruleset_D='4' _POT_DEFAULT_mlock_N='allow.mlock' _POT_DEFAULT_mlock_T='bool' _POT_DEFAULT_mlock_D='NO' _POT_DEFAULT_exec_stop_N='exec.stop' _POT_DEFAULT_exec_stop_T='string' _POT_DEFAULT_exec_stop_D='' _POT_DEFAULT_stop_timeout_N='stop.timeout' _POT_DEFAULT_stop_timeout_T='uint' _POT_DEFAULT_stop_timeout_D='10' # 0:everything, 1:chroot+below(poudriere), 2:just chroot(normal jail) _POT_DEFAULT_enforce_statfs_N='enforce_statfs' _POT_DEFAULT_enforce_statfs_T='uint' _POT_DEFAULT_enforce_statfs_D='2' __POT_MSG_ERR=0 __POT_MSG_INFO=1 __POT_MSG_DBG=2 # $1 severity _msg() { local _sev _sev=$1 shift if [ "$_sev" -gt "${_POT_VERBOSITY:-0}" ]; then return fi case $_sev in "$__POT_MSG_ERR") echo "###> " "$@" ;; "$__POT_MSG_INFO") echo "===> " "$@" ;; "$__POT_MSG_DBG") echo "=====> " "$@" ;; *) ;; esac } _error() { _msg $__POT_MSG_ERR "$@" } _info() { _msg $__POT_MSG_INFO "$@" } _debug() { _msg $__POT_MSG_DBG "$@" } # $1 quiet / no _error message is emitted _qerror() { if [ "$1" != "quiet" ]; then _error "$@" fi } _set_pipefail() { local _major _version _major="$(sysctl -n kern.osrelease | cut -f 1 -d '.')" if [ "$_major" -ge "13" ]; then # shellcheck disable=SC3040 set -o pipefail return fi _version="$(sysctl -n kern.osrelease | cut -f 1 -d '-')" case "$_version" in "12.1"|"12.2") # shellcheck disable=SC3040 set -o pipefail ;; esac } # tested _is_verbose() { if [ "$_POT_VERBOSITY" -gt $__POT_MSG_INFO ]; then return 0 # true else return 1 # false fi } # $1 quiet / no _error messages are emitted (sometimes useful) _is_uid0() { if [ "$(id -u)" = "0" ]; then return 0 # true else _qerror "$1" "This operation needs 'root' privilegies" return 1 # false fi } # tested # check if the argument is an absolute pathname _is_absolute_path() { if [ "$1" = "${1#/}" ]; then return 1 # false else return 0 # true fi } # save encoded parameters suitable for use in `set --` _save_params () { for i; do printf %s\\n "$i" |\ sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" done echo " " } # get system boot time in seconds since the epoch _get_system_uptime() { sysctl -n kern.boottime | sed -e 's/.*[^u]sec = \([0-9]*\).*$/\1/' } # check if the argument is a valid boolean value # if valid, it returns true and it echo a normalized version of the boolean value (YES/NO) # if not valid, it return false _normalize_true_false() { case $1 in [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]) echo YES return 0 # true ;; [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]) echo NO return 0 # true ;; *) return 1 # false esac } # validate some values of the configuration files # $1 quiet / no _error messages are emitted _conf_check() { if [ -z "${POT_ZFS_ROOT}" ]; then _qerror "$1" "POT_ZFS_ROOT is mandatory" return 1 # false fi if [ -z "${POT_FS_ROOT}" ]; then _qerror "$1" "POT_FS_ROOT is mandatory" return 1 # false fi if ! getent group "${POT_GROUP:-pot}" >/dev/null 2>&1; then _qerror "$1" "Group '${POT_GROUP:-pot}' is missing, create it or change POT_GROUP" return 1 # false fi return 0 # true } # it checkes that the pot environment is initialized # $1 quiet / no _error messages are emitted _is_init() { if ! _conf_check "$1" ; then _qerror "$1" "Configuration not valid, please verify it" return 1 # false fi if ! _zfs_exist "${POT_ZFS_ROOT}" "${POT_FS_ROOT}" ; then _qerror "$1" "Your system is not initialized, please run pot init" return 1 # false fi if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/bases" || \ ! _zfs_dataset_valid "${POT_ZFS_ROOT}/jails" || \ ! _zfs_dataset_valid "${POT_ZFS_ROOT}/fscomp" ; then _qerror "$1" "Your system is not propery initialized, please run pot init to fix it" fi } # check the POT_TMP directory # if missing, it will initialize it _is_pot_tmp_dir() { local _pot_tmp _pot_tmp="${POT_TMP:-/tmp}" if [ ! -d "$_pot_tmp" ]; then mkdir -p "$_pot_tmp" fi if [ ! -d "$_pot_tmp" ]; then return 1 # false fi } # set status of pot, locks properly # $1 pot name # $2 status to set # $3 interfaces for pot (epaira) _set_pot_status() { local _pname _status _interfaces _verbose _param _pname=$1 _status=$2 _interfaces=$3 _param=$(_save_params "-p" "$_pname" "-s" "$_status") if [ -n "$_interfaces" ]; then _param="$_param"$(_save_params "-i" "$_interfaces") fi if [ "$_POT_VERBOSITY" -gt 1 ]; then _verbose=$(printf -- "-%$(( _POT_VERBOSITY - 1 ))s" |\ tr " " "v") _param="$_param"$(_save_params "$_verbose") fi eval "set -- $_param" lockf "${POT_TMP:-/tmp}/pot-lock-$_pname" "${_POT_PATHNAME}"\ set-status "$@" } # check if the dataset is a dataset name # $1 the dataset NAME # tested _zfs_dataset_valid() { [ -z "$1" ] && return 1 # return false if [ "$1" = "$( zfs list -o name -H "$1" 2> /dev/null)" ]; then return 0 # true else return 1 # false fi } # check if the dataset $1 with the mountpoint $2 exists # $1 the dataset NAME # $2 the mountpoint # tested _zfs_exist() { local _mnt_ [ -z "$2" ] && return 1 # false if ! _zfs_dataset_valid "$1" ; then return 1 # false fi _mnt_="$(zfs list -H -o mountpoint "$1" 2> /dev/null )" if [ "$_mnt_" != "$2" ]; then return 1 # false fi return 0 # true } # check if the dataset $1 is mounted # $1 the dataset NAME _zfs_mounted() { if [ "$(zfs get -Ho value mounted "$1")" != "yes" ]; then return 1; # false fi return 0 # true } # given a dataset, look for the corresponding mountpoint # $1 the dataset _get_zfs_mountpoint() { local _mnt_p _dset _dset=$1 _mnt_p="$( zfs list -o mountpoint -H "$_dset" 2> /dev/null )" echo "$_mnt_p" } # given a mountpoint, look for the corresponding dataset # $1 the mountpoint _get_zfs_dataset() { local _mnt_p _dset _mnt_p=$1 _dset=$(zfs list -o name,mountpoint -H 2>/dev/null | awk -v "mntp=${_mnt_p}" '{ if ($2 == mntp) print $1 }') echo "$_dset" } # check if POT_ZFS_ROOT supports given property # $1 the property to check _is_zfs_property_supported() { local _properties _ret _properties=$(zfs get -o property all "${POT_ZFS_ROOT}") _ret=$? if [ $_ret -ne 0 ]; then _error "Could not determine if $POT_ZFS_ROOT supports encryption" return 2 # error fi if echo "$_properties" | grep -xq "$1" ; then return 0 # true else return 1 # false fi } # get extra arguments to be added to the zfs receive command. # Output can be used without addional escaping. # In case of errors, the returned string will make sure # the zfs receive command fails in case the called # didn't check the return value. # # Usage: # zfs receive $(_get_zfs_receive_extra_args) pool/fs _get_zfs_receive_extra_args() { local _ret _is_zfs_property_supported "encryption" _ret=$? case $_ret in 0) # encryption supported echo "-x encryption" return 0 ;; 1) # encryption not supported echo "" return 0 ;; *) # communicate error echo "-x therewasanerror" return 1 ;; esac } # take a zfs recursive snapshot of a pot # $1 pot name _pot_zfs_snap() { local _pname _snaptag _dset _pname=$1 _snaptag="$(date +%s)" _debug "Take snapshot of $_pname" zfs snapshot -r "${POT_ZFS_ROOT}/jails/${_pname}@${_snaptag}" } # recursively remove the oldest snapshot of a pot # $1 pot name _remove_oldest_pot_snap() { local _pname _snap _pdset _pname=$1 _pdset="${POT_ZFS_ROOT}/jails/${_pname}" _snap="$( _zfs_oldest_snap "$_pdset" )" if [ -n "$_snap" ]; then zfs destroy -r "$_pdset@${_snap}" fi } # take a zfs snapshot of all rw dataset found in the fscomp.conf of a pot # $1 pot name # DEPRECATED - but still used by create-base _pot_zfs_snap_full() { local _pname _node _opt _snaptag _dset _pname=$1 _snaptag="$(date +%s)" _debug "Take snapshot of the full $_pname" while read -r line ; do _dset=$( echo "$line" | awk '{print $1}' ) _opt=$( echo "$line" | awk '{print $3}' ) if [ "$_opt" = "ro" ]; then continue fi if _is_absolute_path "$_dset" ; then _debug "Skip $_dset, it's not a dataset" else _debug "snapshot of $_dset" zfs snapshot "${_dset}@${_snaptag}" fi done < "${POT_FS_ROOT}/jails/$_pname/conf/fscomp.conf" } # recursively remove the oldest snapshot of a pot # $1 pot name _remove_oldest_fscomp_snap() { local _fscomp _snap _fdset _fscomp=$1 _fdset="${POT_ZFS_ROOT}/fscomp/${_fscomp}" _snap="$( _zfs_oldest_snap "$_fdset" )" if [ -n "$_snap" ]; then zfs destroy -r "$_fdset@${_snap}" fi } # take a zfs snapshot of a fscomp # $1 fscomp name _fscomp_zfs_snap() { local _fscomp _snaptag _dset _fscomp=$1 _snaptag="$(date +%s)" _debug "Take snapshot of $_fscomp" zfs snapshot "${POT_ZFS_ROOT}/fscomp/${_fscomp}@${_snaptag}" } # get the last available snapshot of a given dataset # $1 the dataset name _zfs_last_snap() { local _dset _output _dset="$1" if [ -z "$_dset" ]; then return 1 # false fi _output="$(zfs list -d 1 -H -t snapshot "$_dset" | sort -r | cut -d'@' -f2 | cut -f1 | head -n1)" if [ -z "$_output" ]; then return 1 # false fi echo "${_output}" return 0 # true } # get the oldest available snapshot of a given dataset # $1 the dataset name _zfs_oldest_snap() { local _dset _output _dset="$1" if [ -z "$_dset" ]; then return 1 # false fi _output="$(zfs list -d 1 -H -t snapshot "$_dset" | sort -r | cut -d'@' -f2 | cut -f1 | tail -n1)" if [ -z "$_output" ]; then return 1 # false fi echo "${_output}" return 0 # true } # get the amount of available snapshots of a given dataset # $1 the dataset name _zfs_count_snap() { local _dset _output _dset="$1" if [ -z "$_dset" ]; then return 1 # false fi _output="$(zfs list -d 1 -H -t snapshot "$_dset" | grep -c . )" if [ -z "$_output" ]; then echo 0 fi echo "${_output}" } # check if the snapshot of the pot does exist # $1 pot name # $2 snapshot name _is_zfs_pot_snap() { local _pname _snap _dset _pname=$1 _snap=$2 if zfs list -t snap "${POT_ZFS_ROOT}/jails/${_pname}@${_snap}" 2>/dev/null ; then return 0 # true else return 1 # false fi } # $1 pot name # tested (common.sh 7) _get_usable_hostname() { local _pname _hname _phname _pname="$1" _hname="$(hostname)" if [ ${#_pname} -gt "${POT_HOSTNAME_MAX_LENGTH:-64}" ]; then echo "$_pname" | awk -v len="${POT_HOSTNAME_MAX_LENGTH:-64}" '{ truncated = substr($1, 1, len); printf("%s", truncated); }' else _phname="${_pname}.$_hname" if [ ${#_phname} -gt "${POT_HOSTNAME_MAX_LENGTH:-64}" ]; then echo "$_pname" else echo "$_phname" fi fi } # $1 bridge name # $2 var name _get_bridge_var() { local _Bname _cfile _var _value _Bname="$1" _cfile="${POT_FS_ROOT}/bridges/$_Bname" _var="$2" _value="$( grep "^$_var=" "$_cfile" | tr -d ' \t"' | cut -f2 -d'=' )" echo "$_value" } # $1 pot name # $2 var name _get_conf_var() { local _pname _cdir _var _value _pname="$1" _cdir="${POT_FS_ROOT}/jails/$_pname/conf" _var="$2" _value="$( grep "^$_var=" "$_cdir/pot.conf" | tr -d ' \t"' | cut -f2 -d'=' )" echo "$_value" } # $1 pot name # $2 var name _get_conf_var_string() { local _pname _cdir _var _value _pname="$1" _cdir="${POT_FS_ROOT}/jails/$_pname/conf" _var="$2" _value="$( grep "^$_var=" "$_cdir/pot.conf" | cut -f2 -d'=' )" echo "$_value" } # $1 pot name # $2 var name _get_ip_var() { local _pname _cdir _var _value _pname="$1" _cdir="${POT_FS_ROOT}/jails/$_pname/conf" _value="$( grep "^ip=" "$_cdir/pot.conf" | sed 's/^ip=//' )" echo "$_value" } _get_pot_export_ports() { local _pname _cdir _var _value _pname="$1" _cdir="${POT_FS_ROOT}/jails/$_pname/conf" _value="$(awk '/pot.export.ports/ { n=split($0,array,"="); if (n==2) { print array[2]; } }' "$_cdir/pot.conf" )" echo "$_value" } # $1 pot name _get_pot_base() { _get_conf_var "$1" pot.base } # $1 pot name _get_pot_lvl() { _get_conf_var "$1" pot.level } # $1 pot name _get_pot_type() { local _type _type="$( _get_conf_var "$1" pot.type )" if [ -z "$_type" ]; then _type="multi" fi echo "$_type" } # $1 pot name _get_pot_network_type() { _get_conf_var "$1" network_type } # $1 pot name _is_ip_inherit() { local _pname _val _pname="$1" if [ "$(_get_pot_network_type "$_pname" )" = "inherit" ]; then return 0 # true else return 1 # false fi } # $1 pot name _is_pot_vnet() { local _pname _val _pname="$1" _val="$( _get_conf_var "$_pname" vnet )" if [ "$_val" = "true" ]; then return 0 # true else return 1 # false fi } # $1 pot name _is_pot_prunable() { local _pname _pname="$1" if [ "$( _get_conf_var "$_pname" "pot.attr.prunable" )" = "YES" ]; then return 0 # true else return 1 fi } # $1 bridge name # $2 quiet / no _error messages are emitted (sometimes useful) _is_bridge() { local _bname _bconf _bname="$1" _bconf="${POT_FS_ROOT}/bridges/$_bname" if [ ! -e "$_bconf" ]; then _qerror "$2" "bridge $_bname not found" return 1 # false fi return 0 # true } # $1 fscomp name # $2 quiet / no _error messages are emitted (sometimes useful) # tested _is_fscomp() { local _fscomp _fdir _fdset _fscomp="$1" _fdir="${POT_FS_ROOT}/fscomp/$_fscomp" _fdset="${POT_ZFS_ROOT}/fscomp/$_fscomp" if [ ! -d "$_fdir" ]; then _qerror "$2" "fscomp $_fscomp not found" return 1 fi if ! _zfs_dataset_valid "$_fdset" ; then _qerror "$2" "dataset $_fdset for fscomp $_fscomp not found" return 2 fi return 0 } # $1 base name # $2 quiet / no _error messages are emitted (sometimes useful) # tested _is_base() { local _base _bdir _bdset _base="$1" _bdir="${POT_FS_ROOT}/bases/$_base" _bdset="${POT_ZFS_ROOT}/bases/$_base" if [ ! -d "$_bdir" ]; then if [ "$2" != "quiet" ]; then _error "Base $_base not found" fi return 1 # false fi if ! _zfs_dataset_valid "$_bdset" ; then if [ "$2" != "quiet" ]; then _error "zfs dataset $_bdset not found" fi return 2 #false fi return 0 # true } # $1 pot name # $2 quiet / no _error messages are emitted (sometimes useful) # tested _is_pot() { local _pname _pdir _pname="$1" _pdir="${POT_FS_ROOT}/jails/$_pname" if [ ! -d "$_pdir" ]; then _qerror "$2" "Pot $_pname not found" return 1 # false fi if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/jails/$_pname" ; then _qerror "$2" "zfs dataset $_pname not found" return 2 # false fi if [ ! -d "$_pdir/m" ] || [ ! -r "$_pdir/conf/pot.conf" ] ; then _qerror "$2" "Some component of the pot $_pname is missing" return 3 # false fi if [ "$( _get_pot_type "$_pname" )" = "multi" ] && [ ! -r "$_pdir/conf/fscomp.conf" ]; then _qerror "$2" "Some component of the pot $_pname is missing" return 4 # false fi return 0 # true } # $1 pot name # tested _is_pot_running() { if [ -z "$1" ]; then return 1 ## false fi jls -j "$1" >/dev/null 2>/dev/null return $? } # $1 pot name # tested (common1) _is_valid_potname() { if echo "$1" | grep -Fq '.' ; then return 1 # false else return 0 # true fi } # $1 the element to search # $2.. the list # tested _is_in_list() { local _e if [ $# -lt 2 ]; then return 1 # false fi _e="$1" shift # shellcheck disable=SC2068 for e in $@ ; do if [ "$_e" = "$e" ]; then return 0 # true fi done return 1 # false } # $1 the number to test # tested ( common8 ) _is_natural_number() { case "$1" in ''|*[!0-9]*) return 1 # false ;; *) return 0 # true ;; esac } # $1 a string # tested ( common8 ) _contains_spaces() { echo "$1" | grep -q "[[:space:]]" } # $1 mountpoint # tested _is_mounted() { local _mnt_p _mounted _mnt_p=$1 if [ -z "$_mnt_p" ]; then return 1 # false fi _mounted=$( mount | grep -F "$_mnt_p" | awk '{print $3}') for m in $_mounted ; do if [ "$m" = "$_mnt_p" ]; then return 0 # true fi done return 1 # false } # $1 mountpoint # tested _umount() { local _mnt_p _mnt_p=$1 if _is_mounted "$_mnt_p" ; then _debug "unmount $_mnt_p" umount -f "$_mnt_p" else _debug "$_mnt_p is already unmounted" fi } # $1 pot # $2 cmd _set_command() { local _pname _cmd _cdir _cmd1 _cmd2 _pname="$1" _cmd="$2" _cdir=$POT_FS_ROOT/jails/$_pname/conf sed -i '' -e "/^pot.cmd=.*/d" "$_cdir/pot.conf" _cmd1="$( echo "$_cmd" | sed 's/^"//' )" if [ "$_cmd" = "$_cmd1" ]; then echo "pot.cmd=$_cmd" >> "$_cdir"/pot.conf else _cmd2="$( echo "$_cmd1" | sed 's/"$//' )" echo "pot.cmd=$_cmd2" >> "$_cdir/pot.conf" fi } # tested _is_rctl_available() { local _racct _racct="$(sysctl -qn kern.racct.enable)" if [ "$_racct" = "1" ]; then return 0 # true fi return 1 # false } _is_vnet_available() { if [ "$(sysctl -n kern.features.vimage 2>/dev/null)" = "1" ]; then return 0 # true else return 1 # false fi } _is_potnet_available() { if which potnet 2> /dev/null > /dev/null ; then return 0 # true else return 1 # false fi } # tested (common7) _get_arch() { echo "$(sysctl -n hw.machine)-$(sysctl -n hw.machine_arch)" } # tested (common7) _get_valid_releases() { local _arch _file_prefix _file_prefix="$(_get_arch)" if [ -z "$_file_prefix" ]; then echo fi releases="$( find /usr/local/share/freebsd/MANIFESTS -type f -name "${_file_prefix}-*" | sed s%/usr/local/share/freebsd/MANIFESTS/"${_file_prefix}"-%% | sort -V | sed 's/-RELEASE//' | tr '\n' ' ' )" echo "$releases" } # tested (common7) _is_valid_release() { local _rel _releases if [ -z "$1" ]; then return 1 # false fi _rel="$1" _releases="$( _get_valid_releases )" # shellcheck disable=SC2086 if _is_in_list "$_rel" $_releases ; then return 0 # true else return 1 # false fi } # $1 potname # it's required to have all the file-system mounted to access /bin/freebsd-version _get_os_release() { local _pname _pname="$1" if [ -r "${POT_FS_ROOT}/jails/$_pname/m/bin/freebsd-version" ]; then grep ^USERLAND "${POT_FS_ROOT}/jails/$_pname/m/bin/freebsd-version" | cut -f 2 -d"=" | tr -d \" else _get_conf_var "$_pname" osrelease fi } # $1 FreeBSD release. # for instance 12.0 or 13.0-RC1 _get_freebsd_release_name() { if echo "$1" | grep -q "RC" ; then echo "$1" else echo "$1-RELEASE" fi } _fetch_freebsd() { local _archpath _rel _archpath="$(_get_arch)" if ! _fetch_freebsd_internal "$1" "$_archpath"; then # remove artifact and retry only once _rel="$( _get_freebsd_release_name "$1" )" rm -f "${POT_CACHE}/${_rel}"_base.txz if ! _fetch_freebsd_internal "$1" "$_archpath"; then return 1 # false fi return 0 # true fi return 0 # true } # $1 release, in short format, major.minor or major.minor-RC# _fetch_freebsd_internal() { local _rel _sha _sha_m _archpath _rel="$( _get_freebsd_release_name "$1" )" _archpath="$( echo "$2" | sed -e 's:-:/:' )" if [ ! -r "${POT_CACHE}/${_rel}"_base.txz ]; then fetch -m https://ftp.freebsd.org/pub/FreeBSD/releases/"$_archpath"/"${_rel}"/base.txz -o "${POT_CACHE}/${_rel}"_base.txz fi if [ ! -r "${POT_CACHE}/${_rel}"_base.txz ]; then return 1 # false fi if [ -r /usr/local/share/freebsd/MANIFESTS/"$2"-"${_rel}" ]; then _sha=$( sha256 -q "${POT_CACHE}/${_rel}"_base.txz ) # shellcheck disable=SC2002 _sha_m=$( cat /usr/local/share/freebsd/MANIFESTS/"$2"-"${_rel}" | awk '/^base.txz/ { print $2 }' ) # This version would remove the useless cat, but the testability of this function is compromised #_sha_m=$( awk '/^base.txz/ { print $2 }' < /usr/local/share/freebsd/MANIFESTS/"$2"-"${_rel}") if [ "$_sha" != "$_sha_m" ]; then _error "sha256 doesn't match! Aborting" return 1 # false fi else _error "No manifests found - please install the package freebsd-release-manifests" return 1 # false fi return 0 # true } # $1 fscomp.conf absolute pathname _print_pot_fscomp() { local _dset _mnt_p while read -r line ; do _dset=$( echo "$line" | awk '{print $1}' ) _mnt_p=$( echo "$line" | awk '{print $2}' ) printf "\\t\\t%s => %s\\n" "${_mnt_p##"${POT_FS_ROOT}"/jails/}" "${_dset##"${POT_ZFS_ROOT}"/}" done < "$1" } # $1 pot name _print_pot_snaps() { if [ -z "$( zfs list -t snapshot -o name -Hr "${POT_ZFS_ROOT}/jails/$1")" ]; then printf "\t\tno snapshots\n" else for _s in $( zfs list -t snapshot -o name -Hr "${POT_ZFS_ROOT}/jails/$1" | tr '\n' ' ' ) ; do printf "\\t\\t%s\\n" "$_s" done fi } #1 pot name _get_pot_snaps() { for _s in $( zfs list -t snapshot -o name -H "${POT_ZFS_ROOT}/jails/$1" | tr '\n' ' ' ) ; do echo "${_s##*@}" done } # $1 mountpoint to create (proper permissions are applied) _create_pot_mountpoint() { local _mp _mp="$1" if [ ! -d "$_mp" ]; then _debug "Creating mountpoint $_mp" mkdir -p "$_mp" || exit 1 fi } # $1 pot name _is_fscomp_old() { local _pname _fsconf _mnt_p _stripped_mnt_p _pname="$1" _fsconf="${POT_FS_ROOT}/jails/$_pname/conf/fscomp.conf" while read -r line; do _mnt_p=$( echo "$line" | awk '{print $2}' ) _stripped_mnt_p="${_mnt_p##"${POT_FS_ROOT}/jails/$_pname/m"}" if [ "$_stripped_mnt_p" != "$_mnt_p" ]; then return 0 # true fi done < "$_fsconf" return 1 # false } # $1 pot name _update_fscomp() { local _pname _fsconf _mnt_p _stripped_mnt_p _dset _opt _tmpfile _pname="$1" if _is_fscomp_old "$_pname" ; then _fsconf="${POT_FS_ROOT}/jails/$_pname/conf/fscomp.conf" _tmpfile=$(mktemp "${POT_TMP:-/tmp}/fscomp.conf.${_pname}${POT_MKTEMP_SUFFIX}") while read -r line; do _dset=$( echo "$line" | awk '{print $1}' ) _mnt_p=$( echo "$line" | awk '{print $2}' ) _opt=$( echo "$line" | awk '{print $3}' ) _stripped_mnt_p="${_mnt_p##"${POT_FS_ROOT}/jails/$_pname/m"}" if [ -z "$_stripped_mnt_p" ]; then _stripped_mnt_p="/" fi ${ECHO} "$_dset $_stripped_mnt_p $_opt" >> "$_tmpfile" done < "$_fsconf" mv "$_tmpfile" "$_fsconf" fi } # $1 pot name _pot_mount() { local _pname _dset _mnt_p _opt _node _pname="$1" if ! _is_pot "$_pname" ; then return 1 # false fi _update_fscomp "$_pname" while read -r line ; do if [ -z "$line" ]; then _debug "Empty line found. Skipping." continue fi _dset=$( echo "$line" | awk '{print $1}' ) _mnt_p=$( echo "$line" | awk '{print $2}' ) _mnt_p="${POT_FS_ROOT}/jails/$_pname/m$_mnt_p" _mnt_p="${_mnt_p%/}" _opt=$( echo "$line" | awk '{print $3}' ) if [ "$_opt" = "zfs-remount" ]; then # if the mountpoint doesn't exist, zfs will create it zfs set mountpoint="$_mnt_p" "$_dset" _node=$( _get_zfs_mountpoint "$_dset" ) if _zfs_exist "$_dset" "$_node" ; then # the information are correct - move the mountpoint _debug "_pot_mount: the dataset $_dset is mounted at $_node" else # mountpoint already moved ? _error "_pot_mount: Dataset $_dset not mounted at $_mnt_p! Aborting" return 1 # false fi else if _is_absolute_path "$_dset" ; then if ! mount_nullfs -o "${_opt:-rw}" "$_dset" "$_mnt_p" ; then _error "Error mounting $_dset on $_mnt_p" return 1 # false else _debug "mount $_mnt_p" fi else _node=$( _get_zfs_mountpoint "$_dset" ) if [ ! -d "$_mnt_p" ]; then _debug "start: creating the missing mountpoint $_mnt_p" if ! mkdir "$_mnt_p" ; then _error "Error creating the missing mountpoint $_mnt_p" return 1 fi fi if ! mount_nullfs -o "${_opt:-rw}" "$_node" "$_mnt_p" ; then _error "Error mounting $_node" return 1 # false else _debug "mount $_mnt_p" fi fi fi done < "${POT_FS_ROOT}/jails/$_pname/conf/fscomp.conf" if [ "$(_get_conf_var "$_pname" pot.attr.no-tmpfs)" = "YES" ]; then _debug "Not mounting tmpfs because of no-tmppfs attribure" else if ! mount -t tmpfs tmpfs "${POT_FS_ROOT}/jails/$_pname/m/tmp" ; then _error "Error mounting tmpfs" return 1 else _debug "mount ${POT_FS_ROOT}/jails/$_pname/m/tmp" fi fi return 0 # true } # $1 pot name _pot_umount() { local _pname _tmpfile _jdir _node _mnt_p _opt _dset _pname="$1" if ! _tmpfile=$(mktemp -t "${_pname}.XXXXXX") ; then _error "not able to create temporary file - umount failed" return 1 # false fi _jdir="${POT_FS_ROOT}/jails/$_pname" if [ "$(_get_conf_var "$_pname" pot.attr.no-tmpfs)" = "YES" ]; then _debug "Not umounting tmpfs because of no-tmppfs attribure" else _umount "$_jdir/m/tmp" fi if [ "$(_get_conf_var "$_pname" "pot.attr.fdescfs")" = "YES" ]; then _umount "$_jdir/m/dev/fs" fi _umount "$_jdir/m/dev" if [ "$(_get_conf_var "$_pname" "pot.attr.procfs")" = "YES" ]; then _umount "$_jdir/m/proc" fi if [ -e "$_jdir/conf/fscomp.conf" ]; then _update_fscomp "$_pname" tail -r "$_jdir/conf/fscomp.conf" > "$_tmpfile" while read -r line ; do _dset=$( echo "$line" | awk '{print $1}' ) _mnt_p=$( echo "$line" | awk '{print $2}' ) _mnt_p="${POT_FS_ROOT}/jails/$_pname/m$_mnt_p" _mnt_p=${_mnt_p%/} _opt=$( echo "$line" | awk '{print $3}' ) if [ "$_opt" = "zfs-remount" ]; then _node=${POT_FS_ROOT}/jails/$_pname/$(basename "$_dset") zfs set mountpoint="$_node" "$_dset" if _zfs_exist "$_dset" "$_node" ; then # the information are correct - move the mountpoint _debug "stop: the dataset $_dset is mounted at $_node" else # mountpoint not moved _error "Dataset $_dset moved to $_node (Fix it manually)" fi else _umount "$_mnt_p" fi done < "$_tmpfile" rm "$_tmpfile" fi } _get_pot_list() { # shellcheck disable=SC2011 ls -d "${POT_FS_ROOT}/jails/"*/ 2>/dev/null | xargs -I {} basename {} | tr '\n' ' ' } _get_bridge_list() { # shellcheck disable=SC2038 find "${POT_FS_ROOT}/bridges" -type f 2>/dev/null | xargs -I {} basename {} | tr '\n' ' ' } pot-cmd() { local _cmd _func _cmd=$1 shift if [ ! -r "${_POT_INCLUDE}/${_cmd}.sh" ]; then _error "Fatal error! $_cmd implementation not found!" ${EXIT} 1 fi if [ "$_cmd" != "init" ] && [ "$_cmd" != "de-init" ] && [ "$_cmd" != "version" ] ; then if [ ! -d "$POT_FS_ROOT" ]; then >&2 _error "$POT_FS_ROOT does not exist, please run 'pot init'" ${EXIT} 1 fi if [ ! -r "$POT_FS_ROOT" ]; then >&2 _error "Current user has no read access to $POT_FS_ROOT" ${EXIT} 1 fi fi # shellcheck disable=SC1090 . "${_POT_INCLUDE}/${_cmd}.sh" _func=pot-${_cmd} case "$_cmd" in create|import|clone|create-private-bridge|prepare|copy-in) if [ "$_POT_RECURSIVE" = "1" ]; then logger -p "${POT_LOG_FACILITY}".info -t pot "$_func $*" $_func "$@" else export _POT_RECURSIVE=1 lockf -k /tmp/pot-lock-file "$_POT_PATHNAME" "$_cmd" "$@" fi ;; config|get-attr|get-rss|info|last-run-stats|list|ps|show|top) if _is_verbose ; then logger -p "${POT_LOG_FACILITY}".debug -t pot "$_func $*" fi $_func "$@" ;; *) logger -p "${POT_LOG_FACILITY}".info -t pot "$_func $*" $_func "$@" ;; esac } ================================================ FILE: share/pot/config.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : "${_config_names:="fs_root zfs_root gateway syslogd pot_prefix fscomp_prefix network_stack"}" config-help() { cat <<-EOH pot config [-hvq] [-g name] -h print this help -v verbose -q quiet -g name : get value of config item "name", one of: $(echo "$_config_names" | xargs -n1 echo " +" | sort) EOH } # $1 quiet # $2 name # $3 value _config_echo() { if [ "$1" = "quiet" ]; then echo "$3" else echo "$2 = $3" fi } pot-config() { local _quiet _quiet="NO" _get= OPTIND=1 while getopts "hvqg:" _o ; do case "$_o" in h) config-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; q) _quiet="quiet" ;; g) if _is_in_list "$OPTARG" "$_config_names" ; then _get="$OPTARG" else _qerror $_quiet "$OPTARG is not a valid name" [ "quiet" != "$_quiet" ] && config-help ${EXIT} 1 fi ;; ?) config-help ${EXIT} 1 ;; esac done if [ -z "$_get" ]; then _qerror $_quiet "option -g is mandatory" [ "quiet" != "$_quiet" ] && config-help ${EXIT} 1 fi case $_get in fs_root) _config_echo $_quiet "fs_root" "$POT_FS_ROOT" ;; zfs_root) _config_echo $_quiet "zfs_root" "$POT_ZFS_ROOT" ;; gateway) _config_echo $_quiet "gateway" "$POT_GATEWAY" ;; syslogd) _config_echo $_quiet "syslogd flags" "-b 127.0.0.1 -b $POT_GATEWAY -a $POT_NETWORK" ;; pot_prefix) _config_echo $_quiet "pot prefix" "$POT_FS_ROOT/jails" ;; fscomp_prefix) _config_echo $_quiet "fscomp prefix" "$POT_FS_ROOT/fscomp" ;; network_stack) _config_echo $_quiet "network stack" "$( _get_network_stack )" ;; esac } ================================================ FILE: share/pot/copy-in.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : copy-in-help() { cat <<-"EOH" pot copy-in [-hv] -p pot -s source -d dest -h print this help -v verbose -F force copy operation for running jails (WARNING: can expose parts of the host file system) -p pot : the working pot -s source : the file or directory to be copied in -d dest : the final location inside the pot -c create any missing path components to `dirname destination` inside the pot EOH } # $1 source _source_validation() { local _source _source="$1" if [ -f "$_source" ] || [ -d "$_source" ]; then if [ -r "$_source" ]; then return 0 # true else _error "$_source not readable" fi else _error "$_source not valid" return 1 # false fi } _make_temp_source() { local _proot _proot="$1" mktemp -d "$_proot/tmp/copy-in${POT_MKTEMP_SUFFIX}" } _mount_source_into_potroot() { local _source _mountpoint _source_mnt _source="$1" _mountpoint="$2" if [ -f "$_source" ]; then _source_mnt="$( dirname "$_source" )" else _source_mnt="$_source" fi if ! mount_nullfs -o ro "$_source_mnt" "$_mountpoint" ; then _error "Failed to mount source inside the pot" return 1 fi } pot-copy-in() { local _pname _source _destination _to_be_umount _rc _force _proot _cp_opt _create_dirs OPTIND=1 _pname= _destination= _force= _cp_opt="-a" _create_dirs= while getopts "hvs:d:p:Fc" _o ; do case "$_o" in h) copy-in-help return 0 ;; F) _force="YES" ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) _cp_opt="-va" ;; s) _source="$OPTARG" ;; p) _pname="$OPTARG" ;; d) _destination="$OPTARG" ;; c) _create_dirs="YES" ;; *) copy-in-help return 1 ;; esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" copy-in-help return 1 fi if [ -z "$_source" ]; then _error "A source is mandatory" copy-in-help return 1 fi if [ -z "$_destination" ]; then _error "A destination is mandatory" copy-in-help return 1 fi if ! _is_absolute_path "$_destination" ; then _error "The destination has to be an absolute pathname" return 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" copy-in-help return 1 fi if ! _is_uid0 ; then return 1 fi if ! _source_validation "$_source" ; then copy-in-help return 1 fi if _is_pot_running "$_pname" ; then if [ "$_force" != "YES" ]; then _error "Copying files on a running pot is discouraged, it can partially expose the host file system to the jail" _info "Using the -F flag, the operation can be executed anyway, but we disagree" return 1 else _debug "Copying files on a running pot allowed, because of the -F flag" fi else _pot_mount "$_pname" _to_be_umount=1 fi _proot=${POT_FS_ROOT}/jails/$_pname/m if [ "$_create_dirs" = "YES" ]; then if _is_pot_running "$_pname" ; then if jexec "$_pname" /bin/mkdir -p "$(dirname "$_destination")" ; then _debug "Destination path $_destination created in the pot $_pname" else _error "Destination path $_destination NOT created because of an error" if [ "$_to_be_umount" = "1" ]; then _pot_umount "$_pname" fi return 1 fi else if jail -c path="$_proot" command=/bin/mkdir -p "$(dirname "$_destination")" ; then _debug "Destination path $_destination created in the pot $_pname" else _error "Destination path $_destination NOT created because of an error" if [ "$_to_be_umount" = "1" ]; then _pot_umount "$_pname" fi return 1 fi fi fi if ! _source_mountpoint="$( _make_temp_source "$_proot" )" ; then _error "Failed to build a temporary folder in the pot /tmp" if [ "$_to_be_umount" = "1" ]; then _pot_umount "$_pname" fi return 1 fi if ! _mount_source_into_potroot "$_source" "$_source_mountpoint" ; then if [ "$_to_be_umount" = "1" ]; then _pot_umount "$_pname" fi return 1 fi if [ -f "$_source" ]; then _cp_source="/tmp/$( basename "$_source_mountpoint" )/$( basename "$_source" )" else _cp_source="/tmp/$( basename "$_source_mountpoint" )" fi if _is_pot_running "$_pname" ; then if jexec "$_pname" /bin/cp "$_cp_opt" "$_cp_source" "$_destination" ; then _debug "Source $_source copied in the pot $_pname" _rc=0 else _error "Source $_source NOT copied because of an error" _rc=1 fi else if jail -c path="$_proot" command=/bin/cp "$_cp_opt" "$_cp_source" "$_destination" ; then _debug "Source $_source copied in the pot $_pname" _rc=0 else _error "Source $_source NOT copied because of an error" _rc=1 fi fi if ! umount -f "$_source_mountpoint" ; then _error "Failed to unmount the source tmp folder from the pot" _rc=1 fi if [ "$_to_be_umount" = "1" ]; then _pot_umount "$_pname" else rmdir "$_source_mountpoint" fi return $_rc } ================================================ FILE: share/pot/copy-out.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : copy-out-help() { cat <<-"EOH" pot copy-out [-hv] -p pot -s source -d dest -h print this help -v verbose -F force copy operation for running jails (warning: can expose parts of the host file system) -p pot : the working pot -s source : the file or directory inside the pot -d dest : the location (directory) on the host to copy-out to EOH } # $1 source _destination_validation() { local _destination _destination="$1" if [ -r "$_destination" ] && [ -d "$_destination" ] && [ -x "$_destination" ]; then return 0 # true else _error "$_destination not valid" fi } _make_temp_destination() { local _proot _proot="$1" mktemp -d "$_proot/tmp/copy-out${POT_MKTEMP_SUFFIX}" } _mount_destination_into_potroot() { local _destination _mountpoint _destination="$1" _mountpoint="$2" if ! mount_nullfs "$_destination" "$_mountpoint" ; then _error "Failed to mount destination inside the pot" return 1 fi } pot-copy-out() { local _pname _source _destination _to_be_umount _rc _force _proot _cp_opt _destination_mountpoint OPTIND=1 _pname= _destination= _force= _cp_opt="-a" while getopts "hvs:d:p:F" _o ; do case "$_o" in h) copy-out-help return 0 ;; F) _force="YES" ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) _cp_opt="-va" ;; s) _source="$OPTARG" ;; p) _pname="$OPTARG" ;; d) _destination="$OPTARG" ;; *) copy-out-help return 1 ;; esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" copy-out-help return 1 fi if [ -z "$_source" ]; then _error "A source is mandatory" copy-out-help return 1 fi if [ -z "$_destination" ]; then _error "A destination is mandatory" copy-out-help return 1 fi if ! _is_absolute_path "$_source" ; then _error "The source has to be an absolute pathname" return 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" copy-out-help return 1 fi if ! _is_uid0 ; then return 1 fi if ! _destination_validation "$_destination" ; then copy-out-help return 1 fi if _is_pot_running "$_pname" ; then if [ "$_force" != "YES" ]; then _error "Copying files from a running pot is discouraged, it can partially expose the host file system to the jail" _info "Using the -F flag, the operation can be executed anyway, but we disagree" return 1 else _debug "Copying files from a running pot allowed, because of the -F flag" fi else _pot_mount "$_pname" _to_be_umount=1 fi _proot=${POT_FS_ROOT}/jails/$_pname/m if ! _destination_mountpoint="$( _make_temp_destination "$_proot" )" ; then _error "Failed to build a temporary folder in the pot /tmp" if [ "$_to_be_umount" = "1" ]; then _pot_umount "$_pname" fi return 1 fi if ! _mount_destination_into_potroot "$_destination" "$_destination_mountpoint" ; then if [ "$_to_be_umount" = "1" ]; then _pot_umount "$_pname" fi return 1 fi _cp_destination="/tmp/$( basename "$_destination_mountpoint" )" if _is_pot_running "$_pname" ; then if jexec "$_pname" /bin/cp "$_cp_opt" "$_source" "$_cp_destination" ; then _debug "Source $_source copied from the pot $_pname" _rc=0 else _error "Source $_source NOT copied because of an error" _rc=1 fi else if jail -c path="$_proot" command=/bin/cp "$_cp_opt" "$_source" "$_cp_destination" ; then _debug "Source $_source copied from the pot $_pname" _rc=0 else _error "Source $_source NOT copied because of an error" _rc=1 fi fi if ! umount -f "$_destination_mountpoint" ; then _error "Failed to unmount the source tmp folder from the pot" _rc=1 fi if [ "$_to_be_umount" = "1" ]; then _pot_umount "$_pname" else rmdir "$_destination_mountpoint" fi return $_rc } ================================================ FILE: share/pot/create-base.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : # supported releases are defined in common.sh create-base-help() { cat <<-EOH pot create-base [-h] [-r RELEASE] [-b basename] -h print this help -v verbose -r RELEASE : supported release are: $( _get_valid_releases ) $( _get_valid_releases | xargs -n1 echo " +" | sort) -b basename : optional, (default: the release) EOH } # $1 base name _cb_zfs() { local _bname _dset _mnt _bname=$1 _dset="${POT_ZFS_ROOT}/bases/${_bname}" _mnt="${POT_FS_ROOT}/bases/${_bname}" _info "Create the zfs datasets for base release $_dset" if ! _zfs_exist "${_dset}" "${_mnt}" ; then if ! zfs create "$_dset" ; then return 1 fi fi if ! _zfs_exist "${_dset}/usr.local" "${_mnt}/usr/local" ; then if ! zfs create -o mountpoint="${_mnt}/usr/local" "$_dset/usr.local" ; then return 1 fi fi if ! _zfs_exist "${_dset}/custom" "${_mnt}/opt/custom" ; then if ! zfs create -o mountpoint="${_mnt}/opt/custom" "$_dset/custom" ; then return 1 fi fi return 0 } # $1 release # $2 base name _cb_tar_dir() { local _rel _bname _mnt if echo "$1" | grep -q "RC" ; then _rel="$1" else _rel="$1"-RELEASE fi _bname=$2 _mnt="${POT_FS_ROOT}/bases/${_bname}" ( set -e cd "$_mnt" tar xkf "${POT_CACHE}/${_rel}"_base.txz # add release information echo "$_rel" > .osrelease cp -a root opt/custom/ cp -a etc opt/custom/ cp -a var opt/custom/ mkdir -p opt/custom/usr.local.etc mkdir -p opt/custom/usr.home # they could be part of flavor mkdir -p usr/ports # remove duplicated dirs chflags -R noschg var/empty rm -rf etc/ root/ var/ # create links ln -s opt/custom/etc etc ln -s opt/custom/root root ln -s opt/custom/var var if [ ! -e home ]; then ln -s opt/custom/usr.home home fi cd usr ln -s ../opt/custom/usr.home home cd local ln -s ../../opt/custom/usr.local.etc etc mkdir -p var.db.pkg cd ../../opt/custom/var/db rm -rf pkg ln -s ../../../../usr/local/var.db.pkg pkg ) } # $1 base name _cb_base_pot() { local _bname _pname _tmp _bname=$1 _tmp=$(echo "$_bname" | sed 's/\./_/') _pname="base-$_tmp" _info "Create the related pot [$_pname]" if ! _is_pot "$_pname" quiet ; then pot-cmd create -l 0 -b "$_bname" -p "$_pname" -f fbsd-update fi _debug "Taking a snapshot fo $_pname" _pot_zfs_snap_full "$_pname" } pot-create-base() { local _rel _bname OPTIND=1 while getopts "hr:b:v" _o ; do case "$_o" in h) create-base-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; r) if ! _is_valid_release "$OPTARG" ; then _error "$OPTARG is not a supported release" create-base-help ${EXIT} 1 fi _rel=$OPTARG ;; b) if _is_base "$OPTARG" quiet ; then _error "$OPTARG is already a base" ${EXIT} 1 fi _bname="$OPTARG" ;; *) create-base-help ${EXIT} 1 ;; esac done if [ -z "$_rel" ]; then _error "option -r is mandatory" create-base-help ${EXIT} 1 fi if [ -z "$_bname" ]; then _bname=$_rel _info "Automatically use $_rel as base name" fi if [ "$_bname" != "$_rel" ] && _is_valid_release "$_bname" ; then _error "$_bname has the name of another valid release and that's forbidden" create-base-help ${EXIT} 1 fi if _is_base "$_bname" quiet ; then _error "$_bname already exist" ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi if ! _is_init ; then ${EXIT} 1 fi _info "Create a base with release $_rel" # fetch binaries if ! _fetch_freebsd "${_rel}" ; then _error "fetch of ${_rel} RELEASE failed" ${EXIT} 1 fi # create zfs dataset if ! _cb_zfs "${_bname}" ; then _error "zfs dataset of ${_bname} failed" ${EXIT} 1 fi # move binaries to the dataset and create linkx _cb_tar_dir "${_rel}" "${_bname}" # create jail level 0 _cb_base_pot "${_bname}" } ================================================ FILE: share/pot/create-fscomp.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : create-fscomp-help() { cat <<-"EOH" pot create-fscomp [-hv] -f name -h print this help -v verbose -f name : the fs component name (mandatory) EOH } pot-create-fscomp() { local _dset _dset= OPTIND=1 while getopts "hvf:" _o ; do case "$_o" in h) create-fscomp-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; f) _dset="${POT_ZFS_ROOT}/fscomp/$OPTARG" ;; ?) create-fscomp-help ${EXIT} 1 esac done if [ -z "$_dset" ]; then _error "fs component name is missing" create-fscomp-help ${EXIT} 1 fi if ! _is_init ; then ${EXIT} 1 fi if ! _zfs_dataset_valid "$_dset" ; then if ! _is_uid0 ; then ${EXIT} 1 fi if ! zfs create "$_dset" ; then _error "fs component $_dset creation failed" ${EXIT} 1 fi else _info "fs component $_dset already exists" fi return 0 } ================================================ FILE: share/pot/create-private-bridge.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : create-private-bridge-help() { cat <<-"EOH" pot create-private-bridge [-hv] [-B name] [-S size] -h print this help -v verbose -B bridge name -S bridge size (number of host expected) EOH } # $1 bridge-name # $2 bridge-size create-bridge() { local _bconf _bname _bsize _bname=$1 _bsize=$2 _bconf="${POT_FS_ROOT}/bridges/$_bname" if potnet new-net -s "$_bsize" > "$_bconf" ; then echo "name=$_bname" >> "$_bconf" else rm -f "$_bconf" _error "Not able to get a valid network with size $_bsize" ${EXIT} 1 fi } pot-create-private-bridge() { local _bname _host_amount OPTIND=1 while getopts "hvB:S:" _o ; do case "$_o" in h) create-private-bridge-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; B) _bname="$OPTARG" ;; S) _host_amount="$OPTARG" ;; ?) create-private-bridge-help ${EXIT} 1 esac done if [ -z "$_bname" ]; then _error "A bridge name is mandatory (-B option)" ${EXIT} 1 fi if [ -z "$_host_amount" ]; then _error "The amount of host is mandatory (-S option)" ${EXIT} 1 fi if ! _is_potnet_available ; then _error "potnet is not available! It's needed - cannot proceed" ${EXIT} 1 fi if _is_bridge "$_bname" quiet ; then _error "A bridge with name $_bname already exists" ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi mkdir -p "${POT_FS_ROOT}/bridges" create-bridge "$_bname" "$_host_amount" } ================================================ FILE: share/pot/create.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : trap _cj_undo_create TERM INT _set_pipefail create-help() { cat <<-"EOH" pot create [-hv] -p potname [-N network-type] [-i ipaddr] [-l lvl] [-f flavour] [-b base|-P basepot] [-d dns] [-t type] -h print this help -v verbose -k keep the pot, if create fails -p potname : the pot name (mandatory) -l lvl : pot level (only for type multi) -b base : the base pot -P pot : the pot to be used as reference -d dns : pot dns resolver configuration, one of inherit* - inherit from jailhost (*default) pot - the pot configured in POT_DNS_NAME custom: - copy into pot configuration off - leave resolver config unaltered -f flavour : flavour to be used -t type: pot file system layout, one of single - the pot is based on a unique ZFS dataset multi* - the pot is composed by a classical collection of 3 ZFS datasets (*default) -N network-type: pot network layout, one of inherit* - inherit the host network stack (*default) alias - configure a static ip alias directly on the host's NIC public-bridge - use the common internal public bridge private-bridge - use an internal private bridge (with -B) -i ipaddr : IP address selection, one of auto* - automatically assign address (*default), only works with (public|private)-bridge ipaddr - mandatory with alias, also works with (public|private)-bridge -B bridge-name : the name of the private bridge to be used -S network-stack : the network stack (ipv4, ipv6 or dual) EOH } _cj_undo_create() { _POT_VERBOSITY=0 if [ -z "$_cleanup_pname" ]; then ${EXIT} 1 fi pot-cmd stop "$_cleanup_pname" if [ "$_cleanup_keep" != "YES" ]; then pot-cmd destroy -Fp "$_cleanup_pname" -q fi unset _cleanup_pname unset _cleanup_keep ${EXIT} 1 } # $1 pot name # $2 pot-base name _c_zfs_single() { local _pname _base _potbase _jdset _snap _dset _pname=$1 _potbase=$2 _pdset=${POT_ZFS_ROOT}/jails/$_pname _pdir=${POT_FS_ROOT}/jails/$_pname # Create the main jail zfs dataset if ! _zfs_dataset_valid "$_pdset" ; then if ! zfs create "$_pdset" ; then _error "create: failed to create $_pdset dataset" _cj_undo_create return 1 fi else _info "$_pdset exists already" fi if [ -z "$_potbase" ]; then # create an empty dataset if ! zfs create "$_pdset/m" ; then _error "create: failed to create $_pdset/m dataset" _cj_undo_create return 1 fi # create the minimum needed tree mkdir -p "$_pdir/m/tmp" chmod 1777 "$_pdir/m/tmp" mkdir -p "$_pdir/m/dev" else # send/receive the last snapshot of _potbase _dset=${POT_ZFS_ROOT}/jails/$_potbase/m _snap=$(_zfs_last_snap "$_dset") if [ -n "$_snap" ]; then _debug "Clone zfs snapshot $_dset@$_snap" # shellcheck disable=SC2046 if ! zfs send "$_dset@$_snap" | zfs receive \ $(_get_zfs_receive_extra_args) "$_pdset/m" ; then _error "create: zfs send/receive failed" _cj_undo_create return 1 # false fi else # TODO - autofix _error "no snapshot found for $_dset/m" _cj_undo_create return 1 # false fi fi return 0 } # $1 pot name # $2 level # $3 base name # $4 pot-base name _c_zfs_multi() { local _pname _base _potbase _jdset _snap _dset _pname=$1 _lvl=$2 _base=$3 _potbase=$4 _pdset="${POT_ZFS_ROOT}/jails/$_pname" _pdir="${POT_FS_ROOT}/jails/$_pname" # Create the main jail zfs dataset if ! _zfs_dataset_valid "$_pdset" ; then if ! zfs create "$_pdset" ; then _error "create: failed to create $_pdset dataset" _cj_undo_create return 1 fi else _info "$_pdset exists already" fi # Create the root mountpoint _create_pot_mountpoint "$_pdir/m" # lvl 0 images mount directly usr.local and custom if [ "$_lvl" = "0" ]; then return 0 fi # usr.local if [ "$_lvl" -eq 1 ]; then # lvl 1 images send/receive the usr.local dataset if ! _zfs_dataset_valid "$_pdset/usr.local" ; then if [ -n "$_potbase" ]; then _dset=${POT_ZFS_ROOT}/jails/$_potbase else _dset=${POT_ZFS_ROOT}/bases/$_base fi _snap=$(_zfs_last_snap "$_dset/usr.local") if [ -n "$_snap" ]; then _debug "Import zfs snapshot $_dset/usr.local@$_snap" # shellcheck disable=SC2046 if ! zfs send "$_dset/usr.local@$_snap" | zfs receive \ $(_get_zfs_receive_extra_args) "$_pdset/usr.local" ; then _error "create: zfs send/receive failed" _cj_undo_create return 1 # false fi if ! zfs destroy "$_pdset/usr.local@$_snap" ; then _info "create: not able to destroy the snapshot of usr.local - please, do it manually" fi else # TODO - autofix _error "no snapshot found for $_dset/usr.local" return 1 # false fi else _info "$_pdset/usr.local exists already" fi fi # custom dataset if ! _zfs_dataset_valid "$_pdset/custom" ; then if [ -n "$_potbase" ]; then _dset=${POT_ZFS_ROOT}/jails/$_potbase/custom else _dset=${POT_ZFS_ROOT}/bases/$_base/custom fi _snap=$(_zfs_last_snap "$_dset") if [ -n "$_snap" ]; then _debug "Clone zfs snapshot $_dset@$_snap" # shellcheck disable=SC2046 if ! zfs send "$_dset@$_snap" | zfs receive \ $(_get_zfs_receive_extra_args) "$_pdset/custom" ; then _error "create: zfs send/receive failed" _cj_undo_create return 1 # false fi if ! zfs destroy "$_pdset/custom@$_snap" ; then _info "create: not able to destroy the snapshot of custom - please, do it manually" fi else # TODO - autofix _error "no snapshot found for $_dset" return 1 # false fi else _info "$_pdset/custom exists already" fi return 0 # true } # $1 pot name # $2 type # $3 level # $4 base name # $5 pot-base name _cj_zfs() { local _pname _base _type _potbase _jdset _snap _dset _pname=$1 _type=$2 _lvl=$3 _base=$4 _potbase=$5 case "$_type" in "multi") _c_zfs_multi "$_pname" "$_lvl" "$_base" "$_potbase" ;; "single") _c_zfs_single "$_pname" "$_potbase" ;; esac } # $1 pot name # $2 base name # $3 network type # $4 ip # $5 level # $6 dns # $7 type # $8 private bridge (if network type is private_bridge) # $9 pot-base name # $10 network-stack _cj_conf() { local _pname _base _ip _network_type _lvl _jdir _bdir _potbase _dns _type _pblvl _pbpb local _jdset _bdset _pbdset _baseos _bridge_name _stack _pname=$1 _base=$2 _network_type=$3 _ip=$4 _lvl=$5 _dns=$6 _type=$7 _bridge_name=$8 _potbase=$9 _stack=${10} _jdir=${POT_FS_ROOT}/jails/$_pname _bdir=${POT_FS_ROOT}/bases/$_base _jdset=${POT_ZFS_ROOT}/jails/$_pname _bdset=${POT_ZFS_ROOT}/bases/$_base if [ -n "$_potbase" ]; then _pblvl=$( _get_conf_var "$_potbase" pot.level ) _pbdset=${POT_ZFS_ROOT}/jails/$_potbase else _pblvl= fi if [ ! -d "$_jdir/conf" ]; then mkdir -p "$_jdir/conf" fi ( if [ "$_type" = "multi" ]; then case $_lvl in 0) echo "$_bdset /" echo "$_bdset/usr.local /usr/local" echo "$_bdset/custom /opt/custom" ;; 1) echo "$_bdset / ro" echo "$_jdset/usr.local /usr/local zfs-remount" echo "$_jdset/custom /opt/custom zfs-remount" ;; 2) echo "$_bdset / ro" if [ "$_pblvl" -eq 1 ]; then echo "$_pbdset/usr.local /usr/local ro" else _pbpb="$( _get_conf_var "$_potbase" pot.potbase )" echo "${POT_ZFS_ROOT}/jails/$_pbpb/usr.local /usr/local ro" fi echo "$_jdset/custom /opt/custom zfs-remount" ;; esac fi ) > "$_jdir/conf/fscomp.conf" ( if [ "$_type" = "multi" ]; then _baseos="$( cat "$_bdir/.osrelease" )" else _baseos="${_base}" fi echo "pot.level=${_lvl}" echo "pot.type=${_type}" echo "pot.base=${_base}" echo "pot.potbase=${_potbase}" if [ "$_dns" = "${_dns##custom:}" ]; then echo "pot.dns=${_dns}" else echo "pot.dns=custom" fi echo "pot.cmd=sh /etc/rc" echo "host.hostname=\"$( _get_usable_hostname "${_pname}" )\"" if echo "$_baseos" | grep -q "RC" ; then echo "osrelease=\"${_baseos}\"" elif echo "$_baseos" | grep -q "RELEASE" ; then echo "osrelease=\"${_baseos}\"" else echo "osrelease=\"${_baseos}-RELEASE\"" fi # pot attributes echo "pot.attr.no-rc-script=NO" echo "pot.attr.persistent=YES" echo "pot.attr.start-at-boot=NO" echo "pot.attr.prunable=NO" echo "pot.attr.no-tmpfs=NO" # jail attributes for _attr in ${_POT_JAIL_RW_ATTRIBUTES} ; do if [ -z "$(_get_conf_var "$_pname" "pot.attr.${_attr}")" ]; then # shellcheck disable=SC1083,SC2086 eval _value=\"\${_POT_DEFAULT_${_attr}_D}\" # shellcheck disable=SC2154 echo "pot.attr.${_attr}=${_value}" fi done echo "pot.stack=$_stack" echo "network_type=$_network_type" case $_network_type in "inherit") echo "vnet=false" ;; "alias") echo "vnet=false" echo "ip=${_ip}" ;; "public-bridge") echo "vnet=true" echo "ip=${_ip}" ;; "private-bridge") echo "vnet=true" echo "ip=${_ip}" echo "bridge=${_bridge_name}" ;; esac if [ "${_dns}" = "pot" ]; then echo "pot.depend=${POT_DNS_NAME}" fi ) > "$_jdir/conf/pot.conf" if [ "$_dns" != "${_dns##custom:}" ]; then cp "${_dns##custom:}" "$_jdir/conf/resolv.conf" fi if [ "$_lvl" -eq 2 ]; then if [ "$_pblvl" -eq 1 ]; then # CHANGE the potbase usr.local to be not zfs-remount # Add an info here would be nice if [ -w "${POT_FS_ROOT}/jails/$_potbase/conf/fscomp.conf" ]; then _info "${POT_FS_ROOT}/jails/$_potbase/conf/fscomp.conf fix (${POT_FS_ROOT}/jails/$_potbase/m/usr/local zfs-remount)" # shellcheck disable=SC2086 ${SED} -i '' s%${POT_FS_ROOT}/jails/$_potbase/m/usr/local\ zfs-remount%${POT_FS_ROOT}/jails/$_potbase/m/usr/local% ${POT_FS_ROOT}/jails/$_potbase/conf/fscomp.conf else _info "$_potbase fscomp.conf has not fscomp.conf" fi fi fi if [ "$_type" = "multi" ]; then _cj_internal_conf "$_pname" "$_type" "$_lvl" "$_ip" fi } # $1 pot name # $2 type # $3 level # $4 ip _cj_internal_conf() { local _pname _type _lvl _ip _jdir _pname=$1 _type=$2 _lvl=$3 _ip=$4 _jdir=${POT_FS_ROOT}/jails/$_pname if [ "$_type" = "multi" ]; then _etcdir="${POT_FS_ROOT}/jails/$_pname/custom/etc" else _etcdir="${POT_FS_ROOT}/jails/$_pname/m/etc" fi # disable some cron jobs, not relevant in a jail if [ "$_type" = "single" ] || [ "$_lvl" -ne 0 ]; then ${SED} -i '' 's/^.*save-entropy$/# &/g' "${_etcdir}/crontab" ${SED} -i '' 's/^.*adjkerntz.*$/# &/g' "${_etcdir}/crontab" fi # TODO: to be verified # add remote syslogd capability, if not inherit # if [ -n "$_ip" ]; then # # configure syslog in the pot # ${SED} -i '' 's%^[^#].*/var/log.*$%# &%g' "${_etcdir}/syslog.conf" # echo "*.* @${POT_GATEWAY}:514" > "${_etcdir}/syslog.d/pot.conf" # if [ ! -r "${_etcdir}/rc.conf" ]; then # touch "${_etcdir}/rc.conf" # fi # sysrc -f "${_etcdir}/rc.conf" "syslogd_flags=-vv -s -b $_ip" > /dev/null # # configure syslogd in the host # ( # echo +"$_ip" # echo '*.* '"/var/log/pot/${_pname}.log" # ) > /usr/local/etc/syslog.d/"${_pname}".conf # touch /var/log/pot/"${_pname}".log # ( # echo "# log rotation for pot ${_pname}" # echo "/var/log/pot/${_pname}.log 644 7 * @T00 CX" # ) > /usr/local/etc/newsyslog.conf.d/"${_pname}".conf # service syslogd reload # fi } # $1 pot name # $2 freebsd version _cj_single_install() { local _pname _base _proot _rel _pname=$1 _base=$2 _proot=${POT_FS_ROOT}/jails/$_pname/m _info "Fetching FreeBSD $_base" if ! _fetch_freebsd "$_base" ; then _error "FreeBSD $_base fetch failed - try to continue" _cj_undo_create return 1 # false fi if echo "$_base" | grep -q "RC" ; then _rel="$_base" else _rel="$_base"-RELEASE fi if [ ! -r "${POT_CACHE}/${_rel}_base.txz" ]; then _error "FreeBSD base tarball ${POT_CACHE}/${_rel}_base.txz is missing" _cj_undo_create return 1 # falase fi ( set -e cd "$_proot" _info "Extract the tarball" tar xkf "${POT_CACHE}/${_rel}_base.txz" if [ ! -d usr/home ]; then mkdir -p usr/home fi if [ ! -e home ]; then ln -s usr/home home fi ) return 0 } pot-create() { local _pname _ipaddr _lvl _base _flv _potbase _dns _type _new_lvl _network_type _private_bridge _network_stack OPTIND=1 _type="multi" _network_type="inherit" _pname= _base= _ipaddr= _lvl=1 _new_lvl= _flv= _potbase= _dns=inherit _private_bridge= _network_stack="$( _get_network_stack )" _cleanup_keep="NO" while getopts "hvp:t:N:i:l:b:f:P:d:B:S:k" _o ; do case "$_o" in h) create-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; k) _cleanup_keep="YES" ;; p) if ! _is_valid_potname "$OPTARG" ; then _error "$OPTARG is not a valid name for a pot ('.' is the only character not allowed)" ${EXIT} 1 fi _pname="$OPTARG" ;; t) if [ "$OPTARG" = "multi" ] || [ "$OPTARG" = "single" ]; then _type="$OPTARG" else _error "Type $OPTARG not supported" create-help ${EXIT} 1 fi ;; N) # shellcheck disable=SC2086 if ! _is_in_list "$OPTARG" $_POT_NETWORK_TYPES ; then _error "Network type $OPTARG not recognized" create-help ${EXIT} 1 fi _network_type="$OPTARG" ;; B) _private_bridge="$OPTARG" ;; S) if ! _is_in_list "$OPTARG" "ipv4" "ipv6" "dual" ; then _error "Network stack $OPTARG not valid" create-help ${EXIT} 1 fi _network_stack="$OPTARG" ;; i) if [ -z "$_ipaddr" ]; then _ipaddr="$OPTARG" else _ipaddr="$_ipaddr $OPTARG" fi ;; l) _lvl="$OPTARG" _new_lvl="$OPTARG" ;; b) _base=$OPTARG ;; P) _potbase=$OPTARG ;; d) case $OPTARG in "inherit"|"pot"|"off") _dns=$OPTARG ;; custom:*) if [ -r "${OPTARG##custom:}" ]; then _dns=$OPTARG else _error "The file ${OPTARG##custom:} is not valid or readable" ${EXIT} 1 fi ;; *) _error "'${OPTARG}' is not a valid dns option" create-help ${EXIT} 1 esac ;; f) if _is_flavour "$OPTARG" ; then if [ -z "$_flv" ]; then _flv=$OPTARG else _flv="$_flv $OPTARG" fi else _error "Flavour $OPTARG not found" _debug "Looking in the flavour dir ${_POT_FLAVOUR_DIR}" ${EXIT} 1 fi ;; *) create-help ${EXIT} 1 ;; esac done # check options consitency if [ "$_type" = "single" ]; then if [ -n "$_new_lvl" ] && [ "$_new_lvl" != "0" ]; then _error "single pot level can only be zero (omit -l option)" create-help ${EXIT} 1 fi _lvl=0 if [ -n "$_potbase" ]; then if ! _is_pot "$_potbase" quiet ; then _error "pot $_potbase not found" create-help ${EXIT} 1 fi if [ "$( _get_pot_type "$_potbase" )" != "single" ]; then _error "pot $_potbase has the wrong type, it has to be of type single" create-help ${EXIT} 1 fi if [ -z "$_base" ]; then _base="$( _get_pot_base "$_potbase" )" elif [ "$( _get_pot_base "$_potbase" )" != "$_base" ]; then _error "-b $_base and -P $_potbase are not compatible" create-help ${EXIT} 1 fi else if [ -z "$_base" ]; then _error "at least one of -b and -P has to be used" create-help ${EXIT} 1 fi if ! _is_valid_release "$_base" ; then _error "$_base is not a valid release" create-help ${EXIT} 1 fi fi else case $_lvl in 0) if [ -z "$_base" ]; then _error "level $_lvl needs option -b" create-help ${EXIT} 1 fi if [ -n "$_potbase" ]; then _error "-P option is not allowed with level $_lvl" create-help ${EXIT} 1 fi if ! _is_base "$_base" quiet ; then _error "$_base is not a valid base" create-help ${EXIT} 1 fi ;; 1) if [ -z "$_base" ] && [ -z "$_potbase" ]; then _error "at least one of -b and -P has to be used" create-help ${EXIT} 1 fi if [ -n "$_base" ] && [ -n "$_potbase" ]; then if [ "$( _get_pot_base "$_potbase" )" != "$_base" ]; then _error "-b $_base and -P $_potbase are not compatible" create-help ${EXIT} 1 fi # TODO: an info or debug message che be showned fi if [ -n "$_potbase" ]; then if ! _is_pot "$_potbase" ; then _error "-P $_potbase : is not a pot" create-help ${EXIT} 1 fi if [ "$( _get_conf_var "$_potbase" pot.level )" != "1" ]; then _error "-P $_potbase : it has to be of level 1" create-help ${EXIT} 1 fi fi if [ -z "$_base" ]; then _base=$( _get_pot_base "$_potbase" ) if [ -z "$_base" ]; then _error "-P $_potbase has no base??" ${EXIT} 1 fi _debug "-P $_potbase induced -b $_base" fi if ! _is_base "$_base" quiet ; then _error "$_base is not a valid base" create-help ${EXIT} 1 fi ;; 2) if [ -z "$_potbase" ]; then _error "level $_lvl pots need another pot as reference" create-help ${EXIT} 1 fi if [ "$( _get_conf_var "$_potbase" pot.level )" -lt 1 ]; then _error "-P $_potbase : it has to be at least of level 1" create-help ${EXIT} 1 fi if ! _is_pot "$_potbase" ; then _error "-P $_potbase : is not a pot" create-help ${EXIT} 1 fi if [ -n "$_base" ]; then if ! _is_base "$_base" quiet ; then _error "$_base is not a valid base" create-help ${EXIT} 1 fi if [ "$( _get_pot_base "$_potbase" )" != "$_base" ]; then _error "-b $_base and -P $_potbase are not compatible" ${EXIT} 1 fi else _base=$( _get_pot_base "$_potbase" ) if [ -z "$_base" ]; then _error "-P $_potbase has no base??" ${EXIT} 1 fi if ! _is_base "$_base" quiet ; then _error "$_base (induced by the pot $_potbase) is not a valid base" create-help ${EXIT} 1 fi fi ;; *) _error "level $_lvl is not supported" ${EXIT} 1 ;; esac fi if [ -z "$_pname" ]; then _error "pot name is missing" create-help ${EXIT} 1 fi if _is_pot "$_pname" quiet ; then _error "pot $_pname already exists" ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi if ! _ipaddr="$( _validate_network_param "$_network_type" "$_ipaddr" "$_private_bridge" "$_network_stack" )" ; then echo "$_ipaddr" ${EXIT} 1 fi if [ "$_dns" = "pot" ]; then if ! _is_vnet_available ; then _error "This kernel doesn't support VIMAGE! No vnet possible (needed by the dns)" ${EXIT} 1 fi if ! _is_pot "${POT_DNS_NAME}" quiet ; then _error "dns pot not found ($POT_DNS_NAME) - please fix it" ${EXIT} 1 fi fi _info "Creating a new pot" _info "pot name : $_pname" _info "type : $_type" _info "base : $_base" _info "pot_base : $_potbase" _info "level : $_lvl" _info "network-type : $_network_type" _info "network-stack: $_network_stack" _info "ip : $_ipaddr" _info "bridge : $_private_bridge" _info "dns : $_dns" _info "flavours : $_flv" export _cleanup_pname="$_pname" # for the cleanup function export _cleanup_keep if ! _cj_zfs "$_pname" "$_type" "$_lvl" "$_base" "$_potbase" ; then ${EXIT} 1 fi if ! _cj_conf "$_pname" "$_base" "$_network_type" "$_ipaddr" "$_lvl" "$_dns" "$_type" "$_private_bridge" "$_potbase" "$_network_stack" ; then ${EXIT} 1 fi if [ "$_type" = "single" ]; then if [ -z "$_potbase" ]; then _cj_single_install "$_pname" "$_base" fi _cj_internal_conf "$_pname" "$_type" "0" "$_ipaddr" fi if [ -n "$_flv" ]; then for _f in $_flv ; do if ! _exec_flv "$_pname" "$_f" ; then _cj_undo_create ${EXIT} 1 fi done fi unset _cleanup_pname unset _cleanup_keep } ================================================ FILE: share/pot/de-init.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : de-init-help() { cat <<-"EOH" pot de-init [-hmvf] [-p pf_file] -f force : stop all running pots -p pf_file : remove anchors to this file (empty to skip), defaults to result of `sysrc -n pf_rules` -h print this help -m minimal modifications (alias for `-p ''`) WARNING: Still destroys POT_ZFS_ROOT -v verbose EOH } pot-de-init() { local _pots _p _force _zopt _pf_file _force= _zopt= _pf_file="$(sysrc -n pf_rules)" OPTIND=1 while getopts "fhmvp:" _o ; do case "$_o" in f) _force="force" ;; h) de-init-help ${EXIT} 0 ;; m) _pf_file="" ;; p) _pf_file="$OPTARG" ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) _zopt="-v" ;; ?) de-init-help ${EXIT} 1 ;; esac done _pots=_get_pot_list if ! _is_uid0 ; then ${EXIT} 1 fi for _p in $_pots ; do if _is_pot_running "$_p" ; then if [ -n "$_force" ]; then _debug "Stop the pot $_p" pot-cmd stop "$_p" else _error "At least on pot is still running. Use -f to force the stop of all pots" ${EXIT} 1 fi fi done # Remove pot dataset if ! _zfs_dataset_valid "${POT_ZFS_ROOT}" ; then _info "no root dataset found ($POT_ZFS_ROOT)" else _info "Deinstall pot ($POT_ZFS_ROOT)" zfs destroy -r $_zopt "${POT_ZFS_ROOT}" fi echo "zfs datasets have been removed" # Remove pf entries if needed if [ -n "$_pf_file" ]; then sed -i '' '/^nat-anchor pot-nat$/d' "$_pf_file" sed -i '' '/^rdr-anchor "pot-rdr\/\*"$/d' "$_pf_file" echo "pf configuration file should be clean" echo " - please check $_pf_file and reload it" fi # Final message echo "check your rc.conf for potential leftovers variable like:" echo ' syslogd_flags' echo ' pot_enable' echo "Please, consider to write a feedback email to pizzamig at FreeBSD dot org" echo "It gives us the opportunity to learn and improve" } ================================================ FILE: share/pot/destroy.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : destroy-help() { cat <<-"EOH" pot destroy [-hvFr] [-p potname|-b basename|-f fscomp|-B bridge] -h print this help -v verbose -q quiet -F force the stop and destroy -p potname : the pot name (mandatory) -b basename : the base name (mandatory) -f fscomp : the fscomp name (mandatory) -B bridge-name : the name of the bridge to be deleted (mandatory) -r : destroy recursively all pots based on this base/pot EOH } # $1 zfs dataset _zfs_dataset_destroy() { local _dset _zopt _dset=$1 _zopt= if _is_verbose ; then _zopt="-v" fi zfs destroy -f -r $_zopt "$_dset" return $? } # $1 pot name # $2 force parameter _pot_zfs_destroy() { local _pname _zopt _jdset _force _pname=$1 _force=$2 _jdset=${POT_ZFS_ROOT}/jails/$_pname if ! _zfs_dataset_valid "$_jdset" ; then ## if a directory is found, just remove if if [ -d "${POT_FS_ROOT}/jails/$_pname" ]; then _debug "Dataset of $_pname not found, but removing the directory anyway" rm -rf "${POT_FS_ROOT}/jails/$_pname" return 0 # true fi _error "$_pname not found" return 1 # false fi if _is_pot_running "$_pname" ; then if [ "$_force" = "YES" ]; then pot-cmd stop "$_pname" else _error "pot $_pname is running" ${EXIT} 1 fi fi if ! _zfs_dataset_destroy "$_jdset" ; then _error "zfs failed to destroy the dataset $_jdset" return 1 # false fi if [ -d "${POT_FS_ROOT}/jails/$_pname" ]; then _debug "Removing leftover mountpoint ${POT_FS_ROOT}/jails/$_pname" rm -rf "${POT_FS_ROOT}/jails/$_pname" fi rm -f "/usr/local/etc/syslog.d/${_pname}.conf" "/usr/local/etc/newsyslog.conf.d/${_pname}.conf" "/var/log/pot/${_pname}.log" return $? } # $1 base name _base_zfs_destroy() { local _bname _bdset _bname=$1 _bdset=${POT_ZFS_ROOT}/bases/$_bname if ! _zfs_dataset_destroy "$_bdset" ; then _error "zfs failed to destroy the dataset $_bdset" return 1 # false fi if [ -d "${POT_FS_ROOT}/bases/$_bname" ]; then _debug "Removing leftover mountpoint ${POT_FS_ROOT}/bases/$_bname" rm -rf "${POT_FS_ROOT}/bases/$_bname" fi return 0 } # $1 base name _fscomp_zfs_destroy() { local _fname _fdset _fname=$1 _fdset=${POT_ZFS_ROOT}/fscomp/$_fname if ! _zfs_dataset_destroy "$_fdset" ; then _error "zfs failed to destroy the dataset $_fdset" return 1 # false fi if [ -d "${POT_FS_ROOT}/fscomp/$_fname" ]; then _debug "Removing leftover mountpoint ${POT_FS_ROOT}/fscomp/$_fname" rm -rf "${POT_FS_ROOT}/fscomp/$_fname" fi return 0 } pot-destroy() { local _pname _bname _fname _force _recursive _pots _depPot _bridge_name _pname= _bname= _fname= _bridge_name= _force= _recursive="NO" OPTIND=1 while getopts "hvrf:p:b:FB:q" _o ; do case "$_o" in h) destroy-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; q) _POT_VERBOSITY=0 ;; F) _force="YES" ;; r) _recursive="YES" ;; p) _pname=$OPTARG ;; b) _bname=$OPTARG ;; f) _fname=$OPTARG ;; B) _bridge_name=$OPTARG ;; *) destroy-help ${EXIT} 1 ;; esac done if [ -z "$_pname" ] && [ -z "$_bname" ] && [ -z "$_fname" ] && [ -z "$_bridge_name" ]; then _error "-b or -p or -f or -B are missing" destroy-help ${EXIT} 1 fi if [ -n "$_pname" ]; then if [ -n "$_bname" ] || [ -n "$_fname" ] || [ -n "$_bridge_name" ] ; then _error "-b, -p, -f and -B cannot be used at the same time" destroy-help ${EXIT} 1 fi fi if [ -n "$_bname" ]; then if [ -n "$_fname" ] || [ -n "$_bridge_name" ] ; then _error "-b, -p, -f and -B cannot be used at the same time" destroy-help ${EXIT} 1 fi fi if [ -n "$_fname" ] && [ -n "$_bridge_name" ] ; then _error "-b, -p, -f and -B cannot be used at the same time" destroy-help ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi if [ -n "$_bridge_name" ]; then if [ "$_force" = "YES" ] || [ "$_recursive" = "YES" ] ; then _info "Destroy bridge will ignore force and recursive" fi if ! _is_bridge "$_bridge_name" ; then _error "$_bridge_name is not a valid bridge name" ${EXIT} 1 fi _pots=$( _get_pot_list ) for _p in $_pots ; do _bridge="$( _get_conf_var "$_p" bridge)" if [ "$_bridge" = "$_bridge_name" ]; then _error "the bridge $_bridge_name is still used by the pot $_p - unable to delete" ${EXIT} 1 fi done _info "Destroying bridge $_bridge_name" rm -f "${POT_FS_ROOT}/bridges/$_bridge_name" ${EXIT} $? fi if [ -n "$_fname" ]; then if [ "$_force" = "YES" ] || [ "$_recursive" = "YES" ] ; then _info "Destroy fscomps will ignore force and recursive" fi if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/fscomp/$_fname" ; then _error "$_fname is not a fscomp" ${EXIT} 1 fi _info "Destroying fscomp $_fname" _fscomp_zfs_destroy "$_fname" ${EXIT} $? fi if [ -n "$_bname" ]; then # check the base if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/bases/$_bname" ; then _error "$_bname is not a base" ${EXIT} 1 fi if [ "$_recursive" = "YES" ]; then for _lvl in 2 1 0 ; do _pots=$( _get_pot_list ) for _p in $_pots ; do if [ "$( _get_conf_var "$_p" pot.level )" = "$_lvl" ]; then if [ "$( _get_conf_var "$_p" pot.base )" = "$_bname" ]; then _info "Destroying recursively pot $_p based on $_bname" _pot_zfs_destroy "$_p" $_force fi fi done done else # check if some pot depends on it _pots=$( _get_pot_list ) _pname="base-$(echo "$_bname" | sed 's/\./_/')" for _p in $_pots ; do if [ "$_p" = "$_pname" ]; then continue fi if [ "$( _get_conf_var "$_p" pot.base )" = "$_bname" ]; then _error "base $_bname is used at least by one pot - use option -r to destroy it recursively" ${EXIT} 1 fi done # if present, destroy the lvl 0 pot _debug "Destroying lvl 0 pot $_pname" _pot_zfs_destroy "$_pname" "$_force" fi _info "Destroying base $_bname" _base_zfs_destroy "$_bname" ${EXIT} $? fi if [ -n "$_pname" ]; then if ! _is_pot "$_pname" quiet ; then if _zfs_dataset_valid "${POT_ZFS_ROOT}/jails/$_pname" && [ "$_force" = "YES" ] ; then # we can destroy forcibly if ! _pot_zfs_destroy "$_pname" "$_force" ; then _error "Failed to destroy pot $_pname" ${EXIT} 1 else _info "Forcibly destroyed pot $_pname" ${EXIT} 0 fi else _is_pot "$_pname" _error "pot $_pname not found or corrupted. Try to use the -F flag" ${EXIT} 1 # false fi fi if [ "$( _get_conf_var "$_pname" pot.level )" = "0" ]; then # if single we can remove a level 0 pot if [ "$( _get_conf_var "$_pname" pot.type )" = "single" ]; then _pots=$( _get_pot_list ) for _p in $_pots ; do if [ "$( _get_conf_var "$_p" pot.potbase )" = "$_pname" ]; then if [ "$_recursive" = "YES" ]; then _debug "Destroying recursively pot $_p based on $_pname" _pot_zfs_destroy "$_p" $_force else _error "$_pname is used at least by another pot ($_p) - use option -r to destroy it recursively" ${EXIT} 1 fi fi done else _error "The pot $_pname has level 0. Please destroy the related base insted" ${EXIT} 1 fi fi if [ "$( _get_conf_var "$_pname" pot.level )" = "1" ]; then _pots=$( _get_pot_list ) for _p in $_pots ; do if [ "$( _get_conf_var "$_p" pot.potbase )" = "$_pname" ]; then if [ "$_recursive" = "YES" ]; then _debug "Destroying recursively pot $_p based on $_pname" _pot_zfs_destroy "$_p" $_force else _error "$_pname is used at least by one level 2 pot - use option -r to destroy it recursively" ${EXIT} 1 fi fi done fi if [ "$( _get_conf_var "$_pname" pot.level )" = "2" ] && [ "$_recursive" = "YES" ]; then _debug "$_pname has level 2. No recursive destroy possible (ignored)" fi ## dependency detection _pots=$( _get_pot_list ) for _p in $_pots ; do _depPot="$( _get_conf_var "$_p" pot.depend )" if [ -z "$_depPot" ]; then continue fi for _d in $_depPot ; do if [ "$_d" = "$_pname" ]; then _info "pot $_p is losing his dependency $_pname" continue fi done done _info "Destroying pot $_pname" if ! _pot_zfs_destroy "$_pname" $_force ; then _error "$_pname destruction failed" ${EXIT} 1 fi fi if [ -f "${POT_TMP:-/tmp}/pot_status_${_pname}" ]; then rm -f "${POT_TMP:-/tmp}/pot_status_${_pname}" fi } ================================================ FILE: share/pot/exec.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : exec-help() { cat <<-"EOH" pot exec [-hvdt] [-e var=value] [-u username] [-U username] -p pot COMMAND -h print this help -v verbose -d detach, run in background -t allocate pty -e var=value : set environment variable, can be repeated -u username: The username from the host environment as whom the command should run -U username: The username from the pot environment as whom the command should run -p pot : the pot image COMMAND is the command to execute and will be executed in the username's $HOME EOH } # Actually send signal to process inside pot # $1 pot name # $2 detach # $3 env (encoded with save_params) # $4 alloc_pty # $5 user_host # $6 user_pot # $7-$n command/args _exec_cmd() { local _pname _detach _env _alloc_pty _user_host _user_pot local _cmd _pname=$1 _detach=$2 _env=$3 _alloc_pty=$4 _user_host=$5 _user_pot=$6 shift 6 # $@ contains command/args now _debug "Exec in $_pname, cmd: $*" # assemble command _cmd= if [ "$_alloc_pty" = "YES" ]; then _cmd="$_cmd"$(_save_params "script" "-q" "/dev/null") fi _cmd="$_cmd"$(_save_params "jexec" "-l") if [ -n "$_user_host" ]; then _cmd="$_cmd"$(_save_params "-u" "$_user_host") elif [ -n "$_user_pot" ]; then _cmd="$_cmd"$(_save_params "-U" "$_user_pot") fi _cmd="$_cmd"$(_save_params "$_pname") _cmd="$_cmd$_env"$(_save_params "$@") # execute command eval "set -- $_cmd" if [ "$_detach" = "YES" ]; then nohup "$@" >/dev/null 2>&1 & else "$@" fi _ret=$? return "$_ret" } pot-exec() { local _pname _detach _env _alloc_pty _user_host _user_pot _ret _pname= _detach="NO" _env=$(_save_params "env") _alloc_pty="NO" _user_host= _user_pot= OPTIND=1 while getopts "hvdtp:e:u:U:" _o ; do case "$_o" in h) exec-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; d) _detach="YES" ;; t) _alloc_pty="YES" ;; e) if [ "$OPTARG" = "${OPTARG#*=}" ]; then # the argument doesn't have an equal sign _error "$OPTARG not in a valid form" _error "VARIABLE=value is accetped" exec-help ${EXIT} 1 fi _env="$_env"$(_save_params "$OPTARG") ;; u) _user_host="$OPTARG" ;; U) _user_pot="$OPTARG" ;; p) _pname="$OPTARG" ;; *) exec-help ${EXIT} 1 esac done shift $((OPTIND-1)) if [ "$#" -eq 0 ]; then _error "A command is mandatory" ${EXIT} 1 fi if [ -z "$_pname" ]; then _error "A pot name is mandatory" exec-help ${EXIT} 1 fi if [ -n "$_user_host" ] && [ -n "$_user_pot" ]; then _error "Parameters -u and -U are mutually exclusive" ${EXIT} 1 fi if ! _is_pot_running "$_pname" ; then _error "The pot is not running" ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi _exec_cmd "$_pname" "$_detach" "$_env" \ "$_alloc_pty" "$_user_host" "$_user_pot" "$@" } ================================================ FILE: share/pot/export-ports.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : export-ports-help() { cat <<-"EOH" pot export-ports configure exported ports - public-bridge only pot export-ports [-hv] -p pot [-S] -e [proto:]port[:pot_port] ... -h print this help -v verbose -p pot : the working pot -e [proto:]port[:pot_port] : port(s) to export proto can be tcp (default) or udp port is the port to export pot_port : a static port to NAT to inside the pot dynamically allocated by default This option can be repeated to export multiple ports. Examples: -e 80 export proto tcp port 80 to a dynamic port -e 80:30000 export proto tcp port 80 to pot_port 30000 -e tcp:80:30000 export proto tcp port 80 to pot_port 30000 -e udp:53:30053 export proto udp port 53 to pot_port 30053 EOH } # $1 pot # $2 port list _export_ports() { local _pname _ports _cdir _pname="$1" _ports="$2" _cdir=$POT_FS_ROOT/jails/$_pname/conf sed -i '' -e "/pot.export.ports=.*/d" "$_cdir/pot.conf" echo "pot.export.ports=$_ports" >> "$_cdir/pot.conf" } pot-export-ports() { local _pname _ports _pname= _ports= OPTIND=1 while getopts "hvp:e:" _o ; do case "$_o" in h) export-ports-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; e) if ! _is_export_port_valid "${OPTARG}" ; then _error "$OPTARG is not a valid port number" export-ports-help return 1 fi if [ -z "$_ports" ]; then _ports="$OPTARG" else _ports="$_ports $OPTARG" fi ;; *) export-ports-help return 1 ;; esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" export-ports-help return 1 fi if ! _is_pot "$_pname" ; then _error "$_pname is not a valid pot name" export-ports-help return 1 fi if [ -z "${_ports}" ]; then _error "One port has to be specified" export-ports-help return 1 fi if [ "$(_get_pot_network_type "$_pname")" != "public-bridge" ] && [ "$(_get_pot_network_type "$_pname")" != "private-bridge" ] ; then _info "Only public-bridge and private-bridge network type can export ports - this setting will be ignored during start" fi if [ "$( _get_pot_network_stack "$_pname" )" = "ipv6" ]; then _info "Only ipv4 can export ports, on ipv6 the pot has already a unique address - this setting will be ignored during start" fi _debug "Exporting the following ports: $_ports" if ! _is_uid0 ; then return 1 fi _export_ports "$_pname" "$_ports" } ================================================ FILE: share/pot/export.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : # TODO # Add a way to directly upload the compressed file # Add a way to change compression utility export-help() { cat <<-"EOH" pot export [-hv] -p pot [-S seckey] [-t tag] [-D dir] [-l level] -h print this help -v verbose -p pot : the working pot -t tag : the tag to be used as suffix in the filename if not specified, the snapshot name will be used as suffix -c : treat tags as versions and check if they are decreasing -D dir : where to store the compressed file with the pot -l level : compression level from 0 (fast) to 9 (best). Default level 6. (see `man xz` for more information) -F : force export of multiple snapshot (by default, only one snapshot is allowed) -A : auto-fix number of snapshots (only one snapshot is allowed) -S : sign with secure key 'seckey' using signify(1) EOH } # $1 : pot name # $2 : snapshot # $3 : tag name # $4 : check tag - if 'YES', make sure tags are not decreasing # $5 : target directory - where to write the file # $6 : compression level # $7 : key to sign with signify _export_pot() { local _pname _dset _snap _tag _check_tag _prev_tag _prev_snap local _dir _file _clvl _sign_seckey _meta _origin _origin_pname_snapshot local _origin_pname _origin_snapshot _origin_tag _highest_version local _noerr _pname="$1" _snap="$2" _tag="$3" _check_tag="$4" _dir="$5" _clvl="$6" _sign_seckey="$7" _file="${_dir}/${_pname}_${_tag}.xz" _dset="${POT_ZFS_ROOT}/jails/$_pname" _meta="-" _prev_tag=$(zfs get -H -o value :pot.tag "${_dset}") _prev_snap=$(zfs get -H -o value :pot.snap "${_dset}") if [ "$_check_tag" = "YES" ] && \ [ -n "$_prev_tag" ] && [ "$_prev_tag" != "-" ]; then if [ "$_prev_tag" = "$_tag" ] && [ "$_prev_snap" != "$_snap" ]; then _error "Already exported a different snapshot tagged as this version" return 1 # false fi _highest_version="$( \ (echo "$_tag"; echo "$_prev_tag") | sort -V | tail -n1)" if [ "$_tag" != "$_highest_version" ]; then _error "Tag version lower than the previously exported one" return 1 # false fi fi _origin=$(zfs get -H -o value origin "${_dset}/m") if [ -n "$_origin" ] && [ "$_origin" != "-" ]; then _origin=$(echo "${_origin}" | sed 's|/m@|@|g') _origin_pname_snapshot=$(basename "${_origin}") _origin_pname=$(echo "${_origin_pname_snapshot}" | awk -F\@ '{ print $1 }') _origin_snapshot=$(echo "${_origin_pname_snapshot}" | awk -F@ '{ print $2 }') _origin_tag=$(zfs get -H -o value :pot.tag "${_origin}") if [ -z "$_origin_tag" ] || [ "$_origin_tag" = "-" ]; then _error "Origin ${_origin_pname} has no :pot.tag, please export first" return 1 # false fi _meta="${_origin_pname}:${_origin_tag}@${_origin_snapshot}" fi if ! zfs send -R "${_dset}"@"${_snap}" | xz -"${_clvl}" -T 0 > "${_file}" ; then rm -f "${_file}" return 1 # false elif [ ! -r "${_file}" ]; then return 1 # false else _noerr=0 echo "$_meta" > "${_file}.meta" # shellcheck disable=SC2320 _noerr=$((_noerr+$?)) (cat "${_file}" "${_file}.meta") | skein1024 -q > "${_file}.skein" _noerr=$((_noerr+$?)) if [ -n "$_sign_seckey" ]; then signify -S -s "$_sign_seckey" -m "${_file}.skein" _noerr=$((_noerr+$?)) fi if [ "$_noerr" != 0 ]; then _error "Export failed" rm -f "${_file}" "${_file}.meta" "${_file}.skein" "${_file}.skein.sig" fi zfs set :pot.tag="${_tag}" "${_dset}" zfs set :pot.snap="${_snap}" "${_dset}" return 0 # true fi } pot-export() { local _pname _snap _tag _dir _auto_purge _force _check_tag _sign_seckey _pname= _snap= _tag= _dir="." _clvl=6 _auto_purge= _force= _check_tag= _sign_seckey= OPTIND=1 while getopts "hvcp:t:D:l:FAS:" _o ; do case "$_o" in h) export-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; c) _check_tag="YES" ;; p) _pname="$OPTARG" ;; t) _tag="$OPTARG" ;; D) _dir="$OPTARG" if [ ! -d "$_dir" ]; then _error "$_dir is not a directory" ${EXIT} 1 fi ;; l) if echo "$OPTARG" | grep -q '^[0-9]$' ; then _clvl="$OPTARG" else _error "$OPTARG is an invalid compression level" export-help ${EXIT} 1 fi ;; F) _force="YES" ;; A) _auto_purge="YES" ;; S) _sign_seckey="$OPTARG" ;; *) export-help ${EXIT} 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" export-help ${EXIT} 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" export-help ${EXIT} 1 fi if [ "$(_get_pot_type "$_pname")" != "single" ]; then _error "pot $_pname not supported - only single type pot can be exported" ${EXIT} 1 fi if [ -n "$_sign_seckey" ]; then if [ ! -r "$_sign_seckey" ]; then _error "Signature key $_sign_seckey not found" ${EXIT} 1 fi if ! type "signify" >/dev/null 2>&1; then _error "Could not find 'signify',"\ "try 'pkg install signify'" ${EXIT} 1 fi fi _snap="$(_zfs_last_snap "${POT_ZFS_ROOT}/jails/$_pname" )" if [ -z "$_snap" ]; then if [ "$_auto_purge" = "YES" ]; then _info "Taking a snapshot of $_pname" if ! pot-cmd snapshot -p "$_pname" ; then _error "Failed to take a snapshot of pot $_pname" ${EXIT} 1 else _snap="$(_zfs_last_snap "${POT_ZFS_ROOT}/jails/$_pname" )" _debug "A snapshot of $_pname has been automatically taken (@$_snap)" fi else _error "Pot $_pname has no snapshots - please use pot snapshot for that" ${EXIT} 1 fi fi if [ "$( _zfs_count_snap "${POT_ZFS_ROOT}/jails/$_pname" )" -gt 1 ]; then if [ "$_force" = "YES" ]; then _info "Pot $_pname has multiple snapshots and they all will be exported" elif [ "$_auto_purge" = "YES" ]; then _info "Pot $_pname has more than 1 snapshot - auto-purge will delete older snapshots" if ! pot-cmd purge-snapshots -p "$_pname" ; then _error "purge-snapshots failed" ${EXIT} 1 fi else _error "Pot $_pname has more than 1 snapshot - use -A to auto-purge old snapshots or -F to force exporting" return 1 # false fi fi if [ -z "$_tag" ]; then _tag="$_snap" fi if ! _is_uid0 ; then ${EXIT} 1 fi _info "exporting $_pname @ $_snap to ${_dir}/${_pname}_${_tag}.xz" _export_pot "$_pname" "$_snap" "$_tag" "$_check_tag" "${_dir}" "${_clvl}" "$_sign_seckey" return $? } ================================================ FILE: share/pot/get-attribute.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : get-attribute-help() { cat <<-EOH pot get-attribute [-hvq] -p pot -A attribute -h print this help -v verbose -q quiet -p pot : the working pot -A attribute : get value of attribute, one of $(echo "$_POT_RW_ATTRIBUTES $_POT_RO_ATTRIBUTES \ $_POT_JAIL_RW_ATTRIBUTES" | xargs -n1 echo " +" | sort) EOH } pot-get-attribute() { local _pname _attr _value _quiet _pname= _attr= _value= _quiet="no" OPTIND=1 while getopts "hvqp:A:V:" _o ; do case "$_o" in h) get-attribute-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; q) _quiet="quiet" ;; p) _pname="$OPTARG" ;; A) _attr="$OPTARG" ;; *) get-attribute-help ${EXIT} 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" get-attribute-help ${EXIT} 1 fi if [ -z "$_attr" ]; then _error "Option -A is mandatory" get-attribute-help ${EXIT} 1 fi if ! _is_pot "$_pname" "$_quiet" ; then if [ "$_quiet" != "quiet" ]; then _error "$_pname is not a valid pot" get-attribute-help fi ${EXIT} 1 fi # shellcheck disable=SC2086 if ! _is_in_list "$_attr" $_POT_RW_ATTRIBUTES $_POT_RO_ATTRIBUTES $_POT_JAIL_RW_ATTRIBUTES ; then _error "$_attr is not a valid attribute" get-attribute-help ${EXIT} 1 fi _value=$(_get_conf_var "$_pname" "pot.attr.$_attr") if [ "$_quiet" = "quiet" ]; then echo "$_value" else if [ -z "$_value" ]; then _info "The attribute $_attr is not set for the pot $_pname" else _info "$_attr: $_value" fi fi return 0 } ================================================ FILE: share/pot/get-rss.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : get-rss-help() { cat <<-"EOH" pot get-rss [-h] -p pot -h print this help -v verbose -p pot : the working pot -J : output in JSON format EOH } # $1 pot name # $2 json format print_rss() { local _rss _pname _json _pcpu _mem _cputime _vmem _clockrate _cputimecounter _swap _pname=$1 _json=$2 _clockrate="$( sysctl -n hw.clockrate )" _rss="$( rctl -u jail:"$_pname" )" _pcpu="$( echo "$_rss" | grep ^pcpu | cut -d'=' -f 2 )" _cputimecounter="$( echo "$_rss" | grep ^cputime | cut -d'=' -f 2 )" _mem="$( echo "$_rss" | grep ^memoryuse | cut -d'=' -f 2 )" _vmem="$( echo "$_rss" | grep ^vmemoryuse | cut -d'=' -f 2 )" _swap="$( echo "$_rss" | grep ^swapuse | cut -d'=' -f 2 )" _cputime="$( printf "scale=3\n %s * %s / 100\n" "$_clockrate" "$_pcpu" | bc )" if [ "$_json" = "YES" ]; then echo "{ \"ResourceUsage\": { \"MemoryStats\": { \"RSS\" : $_mem, \"Swap\" : $_swap }, \"CpuStats\": { \"TotalTicks\": $_cputime, \"Percent\": $_pcpu } } } " else echo "Resource usage by the pot $_pname" printf "\\tcpu time (ticks spent) : %s\\n" "$_cputimecounter" printf "\\tcpu time (MHz) : %s\\n" "$_cputime" printf "\\tpcpu (%%) : %s\\n" "$_pcpu" printf "\\tvirtual memory : %s\\n" "$_vmem" printf "\\tphysical memory : %s\\n" "$_mem" printf "\\tswap memory : %s\\n" "$_swap" fi } pot-get-rss() { local _pname _o _json _pname= _json= OPTIND=1 while getopts "hvp:J" _o ; do case "$_o" in h) get-rss-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; J) _json="YES" ;; *) get-rss-help ${EXIT} 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" get-rss-help ${EXIT} 1 fi if ! _is_pot_running "$_pname" ; then _error "The pot $_pname is not running" ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi if ! _is_rctl_available ; then _error "To get resource usage, rctl has to be enabled" ${EXIT} 1 fi print_rss "$_pname" "$_json" ${EXIT} 0 } ================================================ FILE: share/pot/help.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 pot-help() { local _cmd _func _cmd=$1 shift case "${_cmd}" in ls) _cmd=list ;; rollback) _cmd=revert ;; run) _cmd=term ;; snap) _cmd=snapshot ;; set-attr) _cmd=set-attribute ;; get-attr) _cmd=get-attribute ;; esac if [ ! -r "${_POT_INCLUDE}/${_cmd}.sh" ]; then _error "Command ${_cmd} unkown" exit 1 fi # shellcheck disable=SC1090 . "${_POT_INCLUDE}/${_cmd}.sh" _func=${_cmd}-help $_func "$@" } ================================================ FILE: share/pot/import.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : # TODO # add sha256 check on fetch pot and option to disable it # add fscomp.conf management import-help() { cat <<-"EOH" pot import [-hv] -p pot -t tag -U URL [-C pubkey] -h print this help -v verbose -p pot : the remote pot name -t tag : the tag of the pot -U URL : the base URL where to find the image file -C pubkey : verify with public key 'pubkey' using signify(1) EOH } # $1 : remote pot name # $2 : tag # $3 : pubkey (if non-empty, signature is fetched) # $4 : URL _fetch_pot() { local _filename _filename="${1}_${2}.xz" if ! _fetch_pot_internal "$1" "$2" "$3" "$4" ; then # remove the artifacts and retry, but only once rm -f "${POT_CACHE}/${_filename}" \ "${POT_CACHE}/${_filename}.meta" \ "${POT_CACHE}/${_filename}.skein" \ "${POT_CACHE}/${_filename}.skein.sig" if ! _fetch_pot_internal "$1" "$2" "$3" "$4"; then return 1 # false fi return 0 # true fi return 0 # true } # $1 : remote pot name # $2 : tag # $3 : pubkey (if non-empty, signature is fetched) # $4 : URL _fetch_pot_internal() { local _rpname _tag _sign_pubkey _URL _filename _rpname=$1 _tag=$2 _sign_pubkey=$3 _filename="${1}_${2}.xz" if [ -z "$4" ]; then _URL="file://" else _URL="$4" fi if [ ! -r "${POT_CACHE}/$_filename.skein" ]; then if ! fetch "$_URL/$_filename.skein" --output "${POT_CACHE}/$_filename.skein" ; then return 1 # false fi fi if [ -n "$_sign_pubkey" ]; then if [ ! -r "${POT_CACHE}/$_filename.skein.sig" ]; then if ! fetch "$_URL/$_filename.skein.sig" \ --output "${POT_CACHE}/$_filename.skein.sig" ; then return 1 # false fi fi if signify -V -p "$_sign_pubkey" -x "${POT_CACHE}/$_filename.skein.sig" \ -m "${POT_CACHE}/$_filename.skein"; then _debug "Signature verification succeeded" else _error "Signature verification failed" return 1 # false fi fi if [ ! -r "${POT_CACHE}/$_filename" ]; then if ! fetch "$_URL/$_filename" --output "${POT_CACHE}/$_filename" ; then return 1 # false fi fi if [ ! -r "${POT_CACHE}/$_filename.meta" ]; then if ! fetch "$_URL/$_filename.meta" --output "${POT_CACHE}/$_filename.meta" ; then # At the moment, ignore this to be backwards compatible _info "No ${POT_CACHE}/$_filename.meta, ignoring" touch "${POT_CACHE}/$_filename.meta" fi fi if (cat "${POT_CACHE}/$_filename" "${POT_CACHE}/$_filename.meta" |\ skein1024 -q) | cmp "${POT_CACHE}/$_filename.skein" - ; then _debug "Hash confirmed" else _error "The image and its hash do not overlap" return 1 # false fi return 0 # false } # $1 : remote pot name # $2 : tag # $3 : local pot name _import_pot() { local _pname _rpname _tag _filename _network_type _newip _cdir local _sign_pubkey _origin_pname _origin_snap _rpname="$1" _tag="$2" _pname="$3" _sign_pubkey="$4" _origin_pname="$5" _origin_snap="$6" _filename="${_rpname}_${_tag}.xz" _cdir="${POT_FS_ROOT}/jails/$_pname/conf" if [ -n "$_origin_pname" ] && [ -n "$_origin_snap" ]; then # shellcheck disable=SC2046 xzcat "${POT_CACHE}/$_filename" | zfs receive -uo \ "origin=${POT_ZFS_ROOT}/jails/$_origin_pname@$_origin_snap" \ $(_get_zfs_receive_extra_args) \ "${POT_ZFS_ROOT}/jails/$_pname" zfs inherit mountpoint "${POT_ZFS_ROOT}/jails/$_pname/m" zfs mount "${POT_ZFS_ROOT}/jails/$_pname" zfs mount "${POT_ZFS_ROOT}/jails/$_pname/m" else # shellcheck disable=SC2046 xzcat "${POT_CACHE}/$_filename" | zfs receive \ $(_get_zfs_receive_extra_args) "${POT_ZFS_ROOT}/jails/$_pname" fi # pot.conf modifications _hostname="${_pname}.$( hostname )" ${SED} -i '' -e "/^host.hostname=.*/d" "$_cdir/pot.conf" echo "host.hostname=\"${_hostname}.$( hostname )\"" >> "$_cdir/pot.conf" # network rework _network_type="$( _get_pot_network_type "$_pname" )" case "$_network_type" in "inherit") _debug "network_type set to inherit, nothing to rework" ;; "alias") _error "Static IP not supported by import. Moving the pot to the internal network" ${SED} -i '' -e "s%^vnet=.*$%vnet=true%" "${POT_FS_ROOT}/jails/$_pname/conf/pot.conf" _newip="$(potnet next)" sed -i '' -e "s%^ip=.*$%ip=${_newip}%" "${POT_FS_ROOT}/jails/$_pname/conf/pot.conf" _info "Assigning new IP: $_newip" ;; "public-bridge") _newip="$(potnet next)" sed -i '' -e "s%^ip=.*$%ip=${_newip}%" "${POT_FS_ROOT}/jails/$_pname/conf/pot.conf" _info "Assigning new IP: $_newip" ;; esac } pot-import() { local _rpname _tag _URL _pname _sign_pubkey _rpname= _tag= _URL= _sign_pubkey="$POT_DEFAULT_SIGNATURE_PUBKEY" local _meta _dep_pname_tag _dep_snap _dep_pname _dep_tag _dep_origin local _filename OPTIND=1 while getopts "hvp:t:U:C:" _o ; do case "$_o" in h) import-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _rpname="$OPTARG" ;; t) _tag="$OPTARG" ;; U) if [ -z "$OPTARG" ]; then _error "Argument of -U cannot be empty" import-help ${EXIT} 1 fi _URL="$OPTARG" ;; C) _sign_pubkey="$OPTARG" ;; *) import-help ${EXIT} 1 esac done if [ -z "$_rpname" ]; then _error "A remote pot name is mandatory" import-help ${EXIT} 1 fi if [ -z "$_tag" ]; then _error "A tag name is mandatory" import-help ${EXIT} 1 fi _pname="${_rpname}_${_tag}" _pname="$(echo "$_pname" | tr '.' '_')" if _is_pot "$_pname" quiet ; then _error "pot $_pname is already present" import-help ${EXIT} 1 fi if [ -n "$_sign_pubkey" ]; then if [ ! -r "$_sign_pubkey" ]; then _error "Public key $_sign_pubkey not found" ${EXIT} 1 fi if ! type "signify" >/dev/null 2>&1; then _error "Could not find 'signify',"\ "try 'pkg install signify'" ${EXIT} 1 fi fi if ! _is_uid0 ; then ${EXIT} 1 fi _info "importing $_rpname @ $_tag as $_pname" if ! _fetch_pot "$_rpname" "$_tag" "$_sign_pubkey" "$_URL" ; then ${EXIT} 1 fi _dep_origin="" _dep_snap="" _filename="${_rpname}_${_tag}.xz" _meta=$(head -n1 "${POT_CACHE}/$_filename.meta") if [ -n "${_meta}" ] && [ "${_meta}" != "-" ]; then _dep_pname_tag=$(echo "${_meta}" | awk -F@ '{ print $1 }') _dep_snap=$(echo "${_meta}" | awk -F@ '{ print $2 }') _dep_pname=$(echo "${_dep_pname_tag}" | awk -F: '{ print $1 }') _dep_tag=$(echo "${_dep_pname_tag}" | awk -F: '{ print $2 }') _dep_origin=$(echo "${_dep_pname}_${_dep_tag}" | sed "s/\./_/g") _info "Pot $_pname depends on ${_dep_origin} (@${_dep_snap})" # XXX: assumes remote name equals local name if ! _is_pot "${_dep_origin}" quiet ; then _info "Installing dependency ${_dep_origin}" if ! pot-cmd import -p "$_dep_pname" -t "$_dep_tag" \ -U "$_URL" -C "$_sign_pubkey"; then ${EXIT} 1 fi else _info "${_dep_origin} already installed" fi #exit 1 else _info "Pot $_pname has no dependencies" fi if ! _import_pot "$_rpname" "$_tag" "$_pname" "$_sign_pubkey" \ "$_dep_origin" "$_dep_snap"; then ${EXIT} 1 fi return 0 } ================================================ FILE: share/pot/info.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : info-help() { cat <<-"EOH" pot info [-hvqr] [-p pname|-B bname] -h print this help -v verbose -q quiet -p pname : pot name -B bname : bridge name -r check only if the pot is running -E output some pot information as environment variables -s list the available snapshots for the pot EOH } # $! pot name _info_pot_env() { local _pname _ips _idx _all_ips _pname=$1 echo "export _POT_NAME=$_pname" if [ "$( _get_pot_network_type "$_pname" )" != "alias" ]; then echo "export _POT_IP=$( _get_ip_var "$_pname" )" else _all_ips="$( _get_ip_var "$_pname" ) " _ips="$( _get_alias_ipv4 "$_pname" "$_all_ips" ) $( _get_alias_ipv6 "$_pname" "$_all_ips" )" _idx=0 _ipvar_list="" _nicvar_list="" for ip in $_ips ; do nic="${ip%%|*}" ip="${ip##*|}" if [ "$_idx" = "0" ]; then echo "export _POT_IP=$ip" _ipvar_list="_POT_IP_$_idx" _nicvar_list="_POT_NIC_$_idx" else _ipvar_list="$_ipvar_list\\ _POT_IP_$_idx" _nicvar_list="$_nicvar_list\\ _POT_NIC_$_idx" fi echo "export _POT_IP_$_idx=$ip" echo "export _POT_NIC_$_idx=$nic" _idx=$(( _idx + 1 )) done echo "export _POT_IP_LIST=$_ipvar_list" echo "export _POT_NIC_LIST=$_nicvar_list" fi if [ "$( _get_pot_network_type "$_pname" )" = "private-bridge" ]; then echo "export _POT_BRIDGE=$( _get_conf_var "$_pname" bridge)" fi if _is_pot_running "$_pname" ; then echo "export _POT_JID=$( jls -j "$_pname" jid )" fi } # $1 pot name _info_pot() { local _pname _cdir _lvl _ports _type _pname=$1 _cdir="${POT_FS_ROOT}/jails/$_pname/conf" _lvl=$( _get_conf_var "$_pname" pot.level) _type=$( _get_conf_var "$_pname" pot.type) printf "pot name : %s\n" "$_pname" printf "\ttype : %s\n" "$_type" printf "\tbase : %s\n" "$( _get_conf_var "$_pname" pot.base)" printf "\tlevel : %s\n" "$_lvl" if [ "$_lvl" -eq 2 ]; then printf "\tbase pot : %s\n" "$( _get_conf_var "$_pname" pot.potbase)" fi printf "\tnetwork_type : %s\n" "$( _get_pot_network_type "$_pname" )" if [ "$( _get_pot_network_type "$_pname" )" != "inherit" ]; then printf "\tip : %s\n" "$( _get_ip_var "$_pname" )" if [ "$( _get_pot_network_type "$_pname" )" = "private-bridge" ]; then printf "\tbridge : %s\n" "$( _get_conf_var "$_pname" bridge)" fi if _is_verbose ; then _ports="$( _get_pot_export_ports "$_pname" )" if [ -z "$_ports" ]; then printf "\t\tno ports exported\n" else printf "\t\texported ports: %s\n" "$_ports" fi fi fi if _is_pot_running "$_pname" ; then printf "\tactive : true\n" else printf "\tactive : false\n" fi if _is_verbose ; then printf "\tdatasets:\n" if [ "$_type" = "single" ]; then printf "\\t\\t%s\\n" "$_pname/m" fi _print_pot_fscomp "$_cdir/fscomp.conf" printf "\tsnapshots:\n" _print_pot_snaps "$_pname" fi printf "\tattributes:\n" for _a in $_POT_RW_ATTRIBUTES $_POT_RO_ATTRIBUTES ; do _value=$( _get_conf_var "$_pname" "pot.attr.$_a") printf "\t\t%s: %s\n" "$_a" "${_value:-"NO"}" done printf "\tjail attributes:\n" for _a in $_POT_JAIL_RW_ATTRIBUTES ; do _value=$( _get_conf_var "$_pname" "pot.attr.$_a") if [ -z "$_value" ]; then eval _value="\$_POT_DEFAULT_${_a}_D" fi printf "\t\t%s: %s\n" "$_a" "${_value:-"NO"}" done if _is_verbose ; then _cpu="$( _get_conf_var "$_pname" pot.rss.cpus)" _mem="$( _get_conf_var "$_pname" pot.rss.memory)" if [ -n "${_cpu}${_mem}" ]; then printf "\tresource limits:\n" if [ -n "${_cpu}" ]; then printf "\t\tmax amount cpus: %s\n" "$_cpu" fi if [ -n "${_mem}" ]; then printf "\t\tmax amount memory: %s\n" "$_mem" fi fi fi echo } # $1 pot name _info_pot_snapshots() { local _pname _snaps _pname="$1" if _is_verbose ; then _snaps="$( _get_pot_snaps "$_pname" )" for _s in $_snaps ; do echo "$_s: -> " "$( date -r "$_s" )" done else _get_pot_snaps "$_pname" fi } # $1 bridge name _info_bridge() { local _bname _bname="$1" if _is_potnet_available ; then potnet show -b "$_bname" else _error "potnet is needed to show bridge information" fi } pot-info() { local _pname _quiet _run _bname _env_output _snaps _pname="" _quiet="NO" _run="NO" _env_output="NO" _snaps="NO" OPTIND=1 while getopts "hvqp:rB:Es" _o ; do case "$_o" in h) info-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; q) _quiet="quiet" ;; p) _pname="$OPTARG" ;; B) _bname="$OPTARG" ;; r) _run="YES" ;; E) _env_output="YES" ;; s) _snaps="YES" ;; *) info-help ${EXIT} 1 ;; esac done if [ -z "$_pname" ] && [ -z "$_bname" ]; then _error "Option -p or -b are mandatory" info-help ${EXIT} 1 fi if [ -n "$_pname" ] && [ -n "$_bname" ]; then _error "Option -p and -b are mutually exclusive" info-help ${EXIT} 1 fi if [ "$_quiet" = "quiet" ] && _is_verbose ; then _error "Option -q and -v are mutually exclusive" info-help ${EXIT} 1 fi if [ "$_env_output" = "YES" ] && [ -z "$_pname" ]; then _error "Environment variable output available for pot only" info-help ${EXIT} 1 fi if [ -n "$_bname" ] && [ "$_snaps" = "YES" ]; then _info "Bridges has no snapshots - -s ignored" _snaps="NO" fi if [ -n "$_pname" ]; then if ! _is_pot "$_pname" quiet ; then _qerror "$_quiet" "$_pname is not a pot" info-help ${EXIT} 1 fi if [ "$_run" = "YES" ]; then if _is_pot_running "$_pname" ; then ${EXIT} 0 else ${EXIT} 1 fi fi if [ "$_quiet" = "quiet" ]; then ${EXIT} 0 fi if [ "$_snaps" = "YES" ]; then _info_pot_snapshots "$_pname" elif [ "$_env_output" = "YES" ]; then _info_pot_env "$_pname" else _info_pot "$_pname" fi fi if [ -n "$_bname" ]; then if ! _is_bridge "$_bname" quiet ; then _qerror "$_quiet" "$_bname is not a bridge" ${EXIT} 1 fi if [ "$_quiet" = "quiet" ]; then ${EXIT} 0 fi _info_bridge "$_bname" fi } ================================================ FILE: share/pot/init.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : # TODO # check the return code of all commands init-help() { cat <<-"EOH" pot init [-hmsv] [-p pf_file] -h print this help -m minimal modifications (alias for `-sp ''`) -p pf_file : write pot anchors to this file (empty to skip), defaults to result of `sysrc -n pf_rules` -f pf_file : alias for -p pf_file (deprecated) -s do not alter syslogd config -v verbose EOH } pot-init() { local _pf_file _dataset _skip_alter_syslog _pf_file="$(sysrc -n pf_rules)" _skip_alter_syslog= OPTIND=1 while getopts "hmsvf:p:" _o ; do case "$_o" in f|p) _pf_file="$OPTARG" ;; h) init-help ${EXIT} 0 ;; m) _pf_file="" _skip_alter_syslog="YES" ;; s) _skip_alter_syslog="YES" ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; *) init-help ${EXIT} 1 esac done if ! _is_uid0 ; then ${EXIT} 1 fi if ! _conf_check "init" ; then _qerror "init" "Configuration not valid, please verify it" return 1 # false fi if ! _zfs_exist "${POT_ZFS_ROOT}" "${POT_FS_ROOT}" ; then if _zfs_dataset_valid "${POT_ZFS_ROOT}" ; then _error "${POT_ZFS_ROOT} is an invalid POT root" return 1 # false fi # create the pot root _debug "creating ${POT_ZFS_ROOT} file system (mountpoint ${POT_FS_ROOT}" zfs create -o mountpoint="${POT_FS_ROOT}" -o canmount=off -o compression=lz4 -o atime=off "${POT_ZFS_ROOT}" else _info "${POT_ZFS_ROOT} already present" fi # create the root directory if [ ! -d "${POT_FS_ROOT}" ]; then mkdir -p "${POT_FS_ROOT}" if [ ! -d "${POT_FS_ROOT}" ]; then _error "Not able to create the dir ${POT_FS_ROOT}" return 1 # false fi fi # set root directory permissions and ownership chmod 750 "${POT_FS_ROOT}" || ${EXIT} 1 chown root:"${POT_GROUP:-pot}" "${POT_FS_ROOT}" || ${EXIT} 1 # create mandatory datasets for _dataset in bases jails fscomp; do if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/$_dataset" ; then _debug "creating ${POT_ZFS_ROOT}/$_dataset" zfs create "${POT_ZFS_ROOT}/$_dataset" || ${EXIT} 1 fi if ! _zfs_mounted "${POT_ZFS_ROOT}/$_dataset"; then _debug "mounting ${POT_ZFS_ROOT}/$_dataset" zfs mount "${POT_ZFS_ROOT}/$_dataset" || ${EXIT} 1 fi done if ! _zfs_exist "${POT_ZFS_ROOT}/cache" "${POT_CACHE}" ; then _debug "creating ${POT_ZFS_ROOT}/cache mounted as ${POT_CACHE}" if ! _zfs_dataset_valid "${POT_ZFS_ROOT}/cache" ; then zfs create -o mountpoint="${POT_CACHE}" -o compression=off "${POT_ZFS_ROOT}/cache" fi fi # create the bridges folder mkdir -p "${POT_FS_ROOT}/bridges" if [ "$_skip_alter_syslog" != "YES" ]; then # create mandatory directories for logs mkdir -p /usr/local/etc/syslog.d mkdir -p /usr/local/etc/newsyslog.conf.d mkdir -p /var/log/pot fi if ! _is_pot_tmp_dir ; then _error "The POT_TMP directory has not been created - aborting" ${EXIT} 1 fi if ! potnet config-check ; then _error "The network configuration in the pot configuration file is not valid" ${EXIT} 1 fi if ! _is_valid_netif "$POT_EXTIF" ; then _error "The network interface $POT_EXTIF seems not valid [POT_EXTIF]" ${EXIT} 1 fi if [ -n "$POT_EXTIF_ADDR" ]; then if ! potnet ip4check --host "$POT_EXTIF_ADDR" ; then _error "The value $POT_EXTIF_ADDR [POT_EXTIF_ADDR] is not a valid IPv4 address" ${EXIT} 1 fi if ! _is_valid_extif_addr "$POT_EXTIF" "$POT_EXTIF_ADDR" ; then _error "The IP address $POT_EXTIF_ADDR [POT_EXTIF_ADDR] is not available on the network interface $POT_EXTIF [POT_EXTIF]" ${EXIT} 1 fi fi for extra_netif in $POT_EXTRA_EXTIF ; do if ! _is_valid_netif "$extra_netif" ; then _error "The network interface $extra_netif seems not valid [POT_EXTRA_EXTIF]" ${EXIT} 1 fi done if [ "$_skip_alter_syslog" != "YES" ]; then if [ -w /etc/rc.conf ]; then echo "Creating a backup of your /etc/rc.conf" cp -v /etc/rc.conf /etc/rc.conf.bkp-pot fi # add proper syslogd flags and restart it sysrc -q syslogd_flags="-b 127.0.0.1 -b $POT_GATEWAY -a $POT_NETWORK" # service syslogd restart fi # Add pot anchors if needed if [ -n "$_pf_file" ]; then if [ -r "$_pf_file" ] && [ "$(grep -c '^nat-anchor pot-nat$' "$_pf_file" )" -eq 1 ] && [ "$(grep -c '^rdr-anchor "pot-rdr/\*"$' "$_pf_file" )" -eq 1 ] ; then _debug "pf already properly configured" else if [ -w "$_pf_file" ]; then echo "Creating a backup of your $_pf_file" cp -v "$_pf_file" "$_pf_file".bkp-pot # delete incomplete/broken ancory entries - just in case sed -i '' '/^nat-anchor pot-nat$/d' "$_pf_file" sed -i '' '/^rdr-anchor "pot-rdr\/\*"$/d' "$_pf_file" else touch "$_pf_file" fi echo "auto-magically editing your $_pf_file" printf "%s\n" 0a "nat-anchor pot-nat" "rdr-anchor \"pot-rdr/*\"" . x | ex "$_pf_file" echo "Please, check that your PF configuration file $_pf_file is still valid and reload it!" fi else _debug "pf configuration skipped" fi } ================================================ FILE: share/pot/last-run-stats.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : last-run-stats-help() { cat <<-"EOH" pot last-run-stats [-hv] [-p pname] -h print this help -v verbose -p pname : pot name EOH } pot-last-run-stats() { local _pname _pname="" OPTIND=1 while getopts "hvp:" _o ; do case "$_o" in h) last-run-stats-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; *) last-run-stats-help ${EXIT} 1 ;; esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" last-run-stats-help ${EXIT} 1 fi if ! _is_pot "$_pname"; then _error "$_pname is not a pot" ${EXIT} 1 fi _confdir="${POT_FS_ROOT}/jails/$_pname/conf" cat "$_confdir/.last_run_stats" 2>/dev/null || echo "{}" } ================================================ FILE: share/pot/list.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : list-help() { cat <<-"EOH" pot list [-hpbfFa] [-qv] -h print this help -v verbose -q quiet -p list pots (default) -b list bases instead of pots -f list fs components instead of pots -F list available flavours -B list available bridges (network type) -a list everything (incompatible with -q) EOH } # $1 pot name _ls_info_pot() { local _pname _cdir _lvl _pname=$1 _cdir="${POT_FS_ROOT}/jails/$_pname/conf" _lvl=$( _get_conf_var "$_pname" pot.level) printf "pot name : %s\\n" "$_pname" printf "\\tnetwork : %s\\n" "$( _get_conf_var "$_pname" network_type)" if [ "$( _get_conf_var "$_pname" network_type)" != "inherit" ]; then printf "\\tip : %s\\n" "$( _get_ip_var "$_pname" )" fi if _is_pot_running "$_pname" ; then printf "\\tactive : true\\n" else printf "\\tactive : false\\n" fi if _is_verbose ; then printf "\\tbase : %s\\n" "$( _get_conf_var "$_pname" pot.base)" printf "\\tlevel : %s\\n" "$_lvl" if [ "$_lvl" -eq 2 ]; then printf "\\tbase pot : %s\\n" "$( _get_conf_var "$_pname" pot.potbase)" fi printf "\\tdatasets:\\n" _print_pot_fscomp "$_cdir/fscomp.conf" printf "\\tsnapshot:\\n" _print_pot_snaps "$_pname" fi echo } _ls_pots() { local _pots _q _q=$1 _pots=$( _get_pot_list ) if [ -z "$_pots" ]; then if [ "$_q" != "quiet" ]; then echo "No pot created yet..." fi return fi for _p in $_pots; do if [ "$_q" = "quiet" ]; then echo "$_p" else _ls_info_pot "$_p" fi done } _ls_bases() { local _bdir _bases _q _q=$1 _bdir="${POT_FS_ROOT}/bases/" # shellcheck disable=SC2011 _bases=$( ls -d "$_bdir"/*/ 2> /dev/null | xargs -I {} basename {} | tr '\n' ' ' ) if [ "$_q" = "quiet" ]; then for _b in $_bases; do echo "$_b" done else for _b in $_bases; do echo "bases: $_b" done fi } _ls_fscomp() { local _fscomps _q _q=$1 _fscomps=$( zfs list -d 1 -Ho name "${POT_ZFS_ROOT}/fscomp" | sed '1d' | xargs -I {} basename {} | tr '\n' ' ' ) if [ "$_q" = "quiet" ]; then for _f in $_fscomps; do echo "$_f" done else for _f in $_fscomps; do echo "fscomp: $_f" done fi } _ls_flavour() { local _flv1 _flv2 _flv _q _q=$1 # shellcheck disable=SC2010 _flv1=$( ls "${_POT_FLAVOUR_DIR}" | grep -v .sh$ | xargs basename ) # shellcheck disable=SC2011 _flv2=$( ls "${_POT_FLAVOUR_DIR}"/*.sh | xargs basename | sed 's/\.sh//' ) # shellcheck disable=SC2086 _flv=$( printf "%s\\n%s\\n" $_flv1 $_flv2 | sort -u | tr '\n' ' ' ) if [ "$_q" = "quiet" ]; then for _f in $_flv ; do echo "$_f" done else for _f in $_flv ; do echo "flavour: $_f" done fi } _ls_bridges() { local _bridges _q _q=$1 _bridges=$( _get_bridge_list ) if [ "$_q" = "quiet" ]; then for _B in $_bridges; do echo "$_B" done else for _B in $_bridges; do echo "bridge: $_B" done fi } pot-list() { local _obj _q _obj="pots" _q= OPTIND=1 while getopts "hvbfFapqB" _o ; do case "$_o" in h) list-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; q) _q="quiet" ;; p) if [ "$_obj" != "pots" ]; then _error "Options -b -p -f -F -B -a are mutually exclusive" list-help ${EXIT} 1 fi _obj="ppots" ;; b) if [ "$_obj" != "pots" ]; then _error "Options -b -p -f -F -B -a are mutually exclusive" list-help ${EXIT} 1 fi _obj="bases" ;; f) if [ "$_obj" != "pots" ]; then _error "Options -b -p -f -F -B -a are mutually exclusive" list-help ${EXIT} 1 fi _obj="fscomp" ;; F) if [ "$_obj" != "pots" ]; then _error "Options -b -p -f -F -B -a are mutually exclusive" list-help ${EXIT} 1 fi _obj="flavour" ;; B) if [ "$_obj" != "pots" ]; then _error "Options -b -p -f -F -B -a are mutually exclusive" list-help ${EXIT} 1 fi _obj="bridges" ;; a) if [ "$_obj" != "pots" ]; then _error "Options -b -p -f -F -B -a are mutually exclusive" list-help ${EXIT} 1 fi _obj="all" ;; *) list-help ${EXIT} 1 ;; esac done if [ "$_obj" = all ] && [ "$_q" = "quiet" ]; then _error "Options -a and -q are incompatible" list-help ${EXIT} 1 fi case $_obj in "pots"|"ppots") _ls_pots "$_q" ;; "bases") _ls_bases "$_q" ;; "fscomp") _ls_fscomp "$_q" ;; "flavour") _ls_flavour "$_q" ;; "bridges") _ls_bridges "$_q" ;; "all") _ls_bases _ls_pots _ls_fscomp _ls_flavour _ls_bridges ;; esac } ================================================ FILE: share/pot/mount-in.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : mount-in-help() { cat <<-"EOH" pot mount-in [-hvwr] -p pot -m mnt -f fscomp|-d dir|-z dataset -h print this help -v verbose -p pot : the working pot -f fscomp : a fs component to be mounted -z zfs dataset : a ZFS dataset to be mounted -d dir : a directory on the host to be mounted, absolute pathname -m mnt : the mount point inside of the pot -w : change the ZFS mount point instead of using nullfs, potentially DANGEROUS and only usable with -z and -f -r : mount-in read-only EOH } # $1 pot # $2 mount point _is_mountpoint_used() { local _pname _mnt_p _proot _pname="$1" _mnt_p="${2#/}" _conf=$POT_FS_ROOT/jails/$_pname/conf/fscomp.conf _proot=$POT_FS_ROOT/jails/$_pname/m if grep -q " $_proot/$_mnt_p$" "$_conf" || grep -q " $_proot/$_mnt_p " "$_conf" ; then # mount point already used return 0 # true fi if grep -q "$_proot/$_mnt_p " "$_conf" ; then # mountpoint used as source directory ?? wtf _error "The mountpoint is already used as source directory mount-in" return 0 # true fi return 1 # false, mountpoint not used } # $1 pot # $2 mount point _mountpoint_validation() { local _pname _mnt_p _mpdir _mounted _real_mnt _pname="$1" _mnt_p="$2" _mpdir=$POT_FS_ROOT/jails/$_pname/m _mounted=false # false if _is_mountpoint_used "$_pname" "$_mnt_p" ; then _error "The mount point $_mnt_p is already in use" return 1 # false fi if ! _is_pot_running "$_pname" ; then _mounted=true # true if ! _pot_mount "$_pname" >/dev/null ; then _error "Pot $_pname failed to mount" return 1 # false fi fi # if the mountpoint doesn't exist, make it if [ ! -d "$_mpdir/$_mnt_p" ]; then if ! mkdir -p "$_mpdir/$_mnt_p" ; then if eval $_mounted ; then _pot_umount "$_pname" >/dev/null fi return 1 # false fi fi _real_mnt=$( chroot "$_mpdir" /bin/realpath "$_mnt_p") if eval $_mounted ; then _pot_umount "$_pname" >/dev/null fi echo "$_real_mnt" return 0 # true } _directory_validation() { local _pname _dir _proot _conf _pname="$1" _dir="$2" _proot=$POT_FS_ROOT/jails/$_pname _conf=$POT_FS_ROOT/jails/$_pname/conf/fscomp.conf if [ "$_dir" != "${_dir%"$_proot"}" ]; then # dir is inside the pot return 1 # false fi if grep -q "$_dir " "$_conf" ; then # the directory is already used return 1 # false fi return 0 # true } # $1 zfs dataset # $2 pot # $3 mount point # $4 mount option (zfs-remount, ro) _mount_dataset() { local _dset _pname _mnt_p _pdir _opt _dset="$1" _pname="$2" # Removing the trailing / _mnt_p="${3#/}" _opt="${4}" _pdir=$POT_FS_ROOT/jails/$_pname _debug "mount zfs dataset:$_dset mnt_p:$_pdir/m/$_mnt_p opt:$_opt" if [ -z "$_opt" ]; then ${ECHO} "$_dset $_pdir/m/$_mnt_p" >> "$_pdir/conf/fscomp.conf" else ${ECHO} "$_dset $_pdir/m/$_mnt_p $_opt" >> "$_pdir/conf/fscomp.conf" fi if _is_pot_running "$_pname" ; then if [ "$_opt" = "zfs-remount" ]; then zfs set mountpoint="$_pdir/m/$_mnt_p" "$_dset" else _node=$( _get_zfs_mountpoint "$_dset" ) if ! mount_nullfs -o "${_opt:-rw}" "$_node" "$_pdir/m/$_mnt_p" ; then _error "Error mounting $_node on $_pname" else _debug "Mounted $_node on $_pname" fi fi fi } # $1 directory # $2 pot # $3 mount point # $4 mount option (ro) _mount_dir() { local _dir _pname _mnt_p _pdir _opt _dir="$1" _pname="$2" # Removing the trailing / _mnt_p="${3#/}" _opt="${4}" _pdir=$POT_FS_ROOT/jails/$_pname _debug "add directory:$_dir mnt_p:/$_mnt_p opt:$_opt" if [ -z "$_opt" ]; then ${ECHO} "$_dir /$_mnt_p" >> "$_pdir/conf/fscomp.conf" else ${ECHO} "$_dir /$_mnt_p $_opt" >> "$_pdir/conf/fscomp.conf" fi if _is_pot_running "$_pname" ; then if ! mount_nullfs -o "${_opt:-rw}" "$_dir" "$_pdir/m/$_mnt_p" ; then _error "Error mounting $_dir on $_pname" else _debug "Mounted $_dir on $_pname" fi fi } pot-mount-in() { local _pname _fscomp _mnt_p _remount _readonly _opt _dir _real_mnt_p OPTIND=1 _pname= _mnt_p= _remount="NO" _readonly="NO" _opt= _dir= _fscomp= _dset= logger -t pot -p local0.debug -- "mount-in: $*" while getopts "hvf:d:z:p:m:wr" _o ; do case "$_o" in h) mount-in-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; f) _fscomp="$OPTARG" ;; d) _dir="${OPTARG%/}" ;; z) _dset="$OPTARG" ;; p) _pname="$OPTARG" ;; m) _mnt_p="$OPTARG" ;; w) _remount="YES" ;; r) _readonly="YES" ;; *) mount-in-help return 1 ;; esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" mount-in-help return 1 fi if [ -z "$_fscomp" ] && [ -z "$_dir" ] && [ -z "$_dset" ] ; then _error "One of -f|-d|-z option has to be used" mount-in-help return 1 fi if [ -n "$_fscomp" ] && [ -n "$_dir" ]; then _error "-f and -d options are mutually exclusive" mount-in-help return 1 fi if [ -n "$_fscomp" ] && [ -n "$_dset" ]; then _error "-f and -z options are mutually exclusive" mount-in-help return 1 fi if [ -n "$_dir" ] && [ -n "$_dset" ]; then _error "-d and -z options are mutually exclusive" mount-in-help return 1 fi if [ -z "$_mnt_p" ]; then _error "A mount point is mandatory" mount-in-help return 1 fi if _contains_spaces "$_mnt_p" ; then _error "The mountpoint cannot contain spaces" return 1 fi if ! _is_absolute_path "$_mnt_p" ; then _error "The mount point has to be an absolute pathname" return 1 fi if [ "${_mnt_p}" = "/" ]; then _error "/ is not a valid mount point" return 1 fi if [ "$_remount" = "YES" ]; then if [ -n "$_dir" ]; then _error "Remount cannot be used with directories, but with fscomp only" mount-in-help return 1 fi _opt="zfs-remount" # TODO: investigate if [ "$_readonly" = "YES" ]; then _info "Readonly and remount are mutually exclusive: readonly considered, remount ignored" _remount="NO" _opt="ro" fi else if [ "$_readonly" = "YES" ]; then _opt="ro" fi fi if [ -n "$_fscomp" ]; then if ! _is_fscomp "$_fscomp" ; then _error "fscomp $_fscomp is not valid" mount-in-help return 1 fi fi if [ -n "$_dset" ]; then if ! _zfs_dataset_valid "$_dset" ; then _error "dataset $_dset is not valid" mount-in-help return 1 fi fi # TODO: check that the directory doesn't conflict with anything already mounted if [ -n "$_dir" ]; then if [ ! -d "$_dir" ]; then _error "$_dir is not a directory" mount-in-help return 1 fi if ! _is_absolute_path "$_dir" ; then if ! _dir="$(realpath -q "$_dir")" > /dev/null ; then _error "Not able to convert $_dir as an absolute pathname" mount-in-help return 1 fi fi if ! _directory_validation "$_pname" "$_dir" ; then _error "Directory $_dir not valid, already used or already part of the pot" return 1 fi fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" mount-in-help return 1 fi if ! _is_uid0 ; then return 1 fi if ! _real_mnt_p="$(_mountpoint_validation "$_pname" "$_mnt_p" )" ; then echo "$_real_mnt_p" _error "The mountpoint is not valid!" return 1 fi if [ -n "$_dir" ]; then _mount_dir "$_dir" "$_pname" "$_real_mnt_p" $_opt return $? fi if [ -n "$_dset" ]; then _mount_dataset "$_dset" "$_pname" "$_real_mnt_p" $_opt return $? fi if [ -n "$_fscomp" ]; then _mount_dataset "$POT_ZFS_ROOT/fscomp/$_fscomp" "$_pname" "$_real_mnt_p" $_opt return $? fi } ================================================ FILE: share/pot/mount-out.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : mount-out-help() { cat <<-"EOH" pot mount-out [-hvwr] -p pot -m mnt -h print this help -v verbose -p pot : the working pot -m mnt : the mount point inside the pot EOH } # $1 pot # $2 mount point _is_mountpoint_used() { local _pname _mnt_p _proot _pname="$1" _mnt_p="${2}" _conf=$POT_FS_ROOT/jails/$_pname/conf/fscomp.conf _proot=$POT_FS_ROOT/jails/$_pname/m ## spaces in this sequences of grep have been introduced to detect exact matches only ## a pattern like /mnt/test would match /mnt/test and /mnt/test2 ## with those spaces we try be more precise in detecting the exact match if grep -q " $_mnt_p$" "$_conf" || grep -q " $_mnt_p " "$_conf" ; then # mount point already used return 0 # true fi if grep -q "$_proot/$_mnt_p " "$_conf" ; then # mountpoint used as source directory ?? wtf _error "The mountpoint is already used as source directory mount-out" return 0 # true fi return 1 # false, mountpoint not used } # $1 pot # $2 mount point _mountpoint_validation() { local _pname _mnt_p _mpdir _mounted _real_mnt _pname="$1" _mnt_p="$2" _mpdir=$POT_FS_ROOT/jails/$_pname/m _mounted=false # false if ! _is_pot_running "$_pname" ; then _mounted=true # true if ! _pot_mount "$_pname" >/dev/null ; then _error "Pot $_pname failed to mount" return 1 # false fi fi _real_mnt=$( chroot "$_mpdir" /bin/realpath "$_mnt_p") if eval $_mounted ; then _pot_umount "$_pname" >/dev/null fi if ! _is_mountpoint_used "$_pname" "$_real_mnt" ; then _error "The mount point $_mnt_p is not in use" return 1 # false fi echo "$_real_mnt" return 0 # true } # $1 pot # $2 mount point _umount_mnt_p() { local _pname _mnt_p _pdir _pname="$1" # Removing the trailing / _mnt_p="${2#/}" _pdir=$POT_FS_ROOT/jails/$_pname # absolute pathname of the mount point with escape character _sed_string="$(echo "$_pdir/m/$_mnt_p" | sed 's#/#\\/#g')" _debug "umount_mnt_p: mnt_p:$_pdir/m/$_mnt_p" ${SED} -E -i '' " $_sed_string$| $_sed_string /d" "$_pdir/conf/fscomp.conf" if _is_pot_running "$_pname" ; then if _umount "$_pdir/m/$_mnt_p" ; then _debug "Umounted $_mnt_p on $_pname" else _error "Error umounting $_mnt_p on $_pname" fi fi } pot-mount-out() { local _pname _mnt_p _real_mnt_p OPTIND=1 _pname= _mnt_p= logger -t pot -p local0.debug -- "mount-out: $*" while getopts "hvp:m:" _o ; do case "$_o" in h) mount-out-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; m) _mnt_p="$OPTARG" ;; *) mount-out-help return 1 ;; esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" mount-out-help return 1 fi if [ -z "$_mnt_p" ]; then _error "A mount point is mandatory" mount-out-help return 1 fi if ! _is_absolute_path "$_mnt_p" ; then _error "The mount point has to be an absolute pathname" return 1 fi if [ "${_mnt_p}" = "/" ]; then _error "/ is not a valid mount point" return 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" mount-out-help return 1 fi if ! _is_uid0 ; then return 1 fi if ! _real_mnt_p="$(_mountpoint_validation "$_pname" "$_mnt_p" )" ; then echo "$_real_mnt_p" _error "The mountpoint is not valid!" return 1 fi _umount_mnt_p "$_pname" "$_real_mnt_p" return $? } ================================================ FILE: share/pot/network.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 # tested _pot_bridge() { _pot_bridge_ipv4 } _pot_bridge_ipv4() { local _bridges _bridges=$( ifconfig -g bridge ) if [ -z "$_bridges" ]; then return fi for _b in $_bridges ; do _ip=$( ifconfig "$_b" inet | awk '/inet/ { print $2 }' ) if [ "$_ip" = "$POT_GATEWAY" ]; then echo "$_b" return fi done } _pot_bridge_ipv6() { local _bridges _bridges=$( ifconfig -g bridge ) if [ -z "$_bridges" ]; then return fi for _b in $_bridges ; do if ifconfig "$_b" |grep -q "member: $POT_EXTIF" ; then echo "$_b" return fi done } # $1 bridge name _private_bridge() { local _bridges _bridge _bridge_ip _bridge="$1" _bridges=$( ifconfig -g bridge ) if [ -z "$_bridges" ]; then return fi _bridge_ip="$(_get_bridge_var "$_bridge" gateway)" for _b in $_bridges ; do _ip=$( ifconfig "$_b" inet | awk '/inet/ { print $2 }' ) if [ "$_ip" = "$_bridge_ip" ]; then echo "$_b" return fi done } _get_pot_rdr_anchor_name() { local _pname _pname=$1 if [ "${#_pname}" -gt "55" ]; then echo "$_pname" | awk '{ truncated = substr($1, length($1)-54); printf("%s", truncated);}' | sed 's/^__*//' else echo "$_pname" fi } _is_vnet_up() { _is_vnet_ipv4_up "$1" } # $1 bridge name (optional) _is_vnet_ipv4_up() { local _bridge if [ -z "$1" ]; then _bridge=$(_pot_bridge) else _bridge="$( _private_bridge "$1" )" fi if [ -z "$_bridge" ]; then return 1 # false elif [ ! -c /dev/pf ]; then return 1 # false elif ! pfctl -s Anchors | grep -q '^[ \t]*pot-nat$' ; then return 1 # false elif ! pfctl -s Anchors | grep -q '^[ \t]*pot-rdr$' ; then return 1 # false elif [ -z "$(pfctl -s nat -a pot-nat)" ]; then return 1 # false else return 0 # true fi } _is_vnet_ipv6_up() { local _bridge _bridge="$(_pot_bridge_ipv6)" if [ -z "$_bridge" ]; then return 1 # false fi return 0 } # $1 the number to test _is_port_number() { local _port _port=$1 if [ -z "$_port" ]; then return 1 fi # check if it's a number if [ -n "$( echo "$_port" | sed 's/[0-9][0-9]*//' )" ]; then return 1 fi # check if it's a 16 bit number if [ "$_port" -le 0 ] || [ "$_port" -gt 65535 ]; then return 1 # false fi return 0 } # $1: the -e option argument _is_export_port_valid() { local _pot_port _host_port _arg if [ "${1#tcp:}" != "${1}" ]; then _arg="${1#tcp:}" elif [ "${1#udp:}" != "${1}" ]; then _arg="${1#udp:}" else _arg="${1}" fi _pot_port="$( echo "${_arg}" | cut -d':' -f 1)" if [ "$_arg" = "${_pot_port}" ]; then if ! _is_port_number "$_pot_port" ; then return 1 # false fi else _host_port="$( echo "${_arg}" | cut -d':' -f 2)" if ! _is_port_number "$_pot_port" ; then return 1 # false fi if ! _is_port_number "$_host_port" ; then return 1 # false fi fi } # $1 name of the network interface _is_valid_netif() { local _netif _netif="$1" if ifconfig "$_netif" > /dev/null 2> /dev/null ; then return 0 # true else return 1 # false fi } _is_valid_extif_addr() { local _netif _ip _netif="$1" _ip="$2" ifconfig "$_netif" | grep -F "inet " | grep -qF " $_ip " } # get the network stack defined in the global configuration _get_network_stack() { local _stack _stack="${POT_NETWORK_STACK:-ipv4}" case $_stack in ipv4|ipv6|dual) echo "$_stack" ;; *) echo ipv4 return 1 ;; esac } # get the network stack for the specific pot # $1 pot name _get_pot_network_stack() { local _stack _pname _pname="$1" _stack="$( _get_conf_var "$_pname" pot.stack )" if [ -z "$_stack" ]; then _get_network_stack else echo "$_stack" fi } # $1 pot name # $2 ipaddr _get_alias_ipv4() { local _i _ip _nic _output _output= if [ "$( _get_pot_network_stack "$1" )" != "ipv6" ]; then for _i in $2 ; do if echo "$_i" | grep -qF '|' ; then _nic="$( echo "$_i" | cut -f 1 -d '|' )" _ip="$( echo "$_i" | cut -f 2 -d '|' )" else _nic="$POT_EXTIF" _ip="$_i" fi if potnet ip4check -H "$_ip" 2> /dev/null ; then if [ -z "$_output" ]; then _output="$_nic|$_ip" else _output="$_output,$_nic|$_ip" fi fi done fi echo "$_output" } # $1 pot name # $2 ipaddr _get_alias_ipv6() { local _i _ip _nic _output _output= if [ "$( _get_pot_network_stack "$1" )" != "ipv4" ]; then for _i in $2 ; do if echo "$_i" | grep -qF '|' ; then _nic="$( echo "$_i" | cut -f 1 -d '|' )" _ip="$( echo "$_i" | cut -f 2 -d '|' )" else _nic="$POT_EXTIF" _ip="$_i" fi if potnet ip6check -H "$_ip" 2> /dev/null ; then if [ -z "$_output" ]; then _output="$_nic|$_ip" else _output="$_output,$_nic|$_ip" fi fi done fi echo "$_output" } # $1 ipaddr # $2 network stack _validate_alias_ipaddr() { local _i _nic _ip _ipv4_empty _ipv6_empty _stack _stack="$2" _ipv4_empty="YES" _ipv6_empty="YES" for _i in $1 ; do if echo "$_i" | grep -qF '|' ; then _nic="$( echo "$_i" | cut -f 1 -d '|' )" _ip="$( echo "$_i" | cut -f 2 -d '|' )" if ! _is_valid_netif "$_nic" ; then _error "$_nic is not a valid network interface" return 1 # false fi else _ip="$_i" fi if ! potnet ipcheck -H "$_ip" 2> /dev/null ; then _error "$_ip is not a valid IP address" return 1 # false fi if potnet ip4check -H "$_ip" 2> /dev/null ; then _ipv4_empty="NO" fi if potnet ip6check -H "$_ip" 2> /dev/null ; then _ipv6_empty="NO" fi done if [ "$_stack" = "ipv4" ] && [ "$_ipv4_empty" = "YES" ]; then _error "Stack is ipv4 but not ipv4 address has been provided" return 1 # false fi if [ "$_stack" = "ipv6" ] && [ "$_ipv6_empty" = "YES" ]; then _error "Stack is ipv6 but not ipv6 address has been provided" return 1 # false fi return 0 } # $1 network type # $2 ipaddr # $3 bridge-name (private-bridge only) # $4 network stack # if success, then print the ip addr (it could be empty) # otherwise it print the an error message _validate_network_param() { local _network_type _ipaddr _private_bridge _network_type=$1 _ipaddr=$2 _private_bridge=$3 _network_stack=$4 if [ -z "$_network_stack" ]; then _network_stack="$( _get_network_stack )" fi case "$_network_type" in "inherit") _ipaddr= ;; "alias") if [ -z "$_ipaddr" ]; then _error "option -i is mandatory with network type is alias" return 1 elif [ "$_ipaddr" = "auto" ]; then _error "-i auto not usable with network type alias - a real IP address has to be provided" return 1 fi if ! _validate_alias_ipaddr "$_ipaddr" "$_network_stack" ; then _error "$_ipaddr is not a valid alias configuration" return 1 fi ;; "public-bridge") if ! _is_vnet_available ; then _error "This kernel doesn't support VIMAGE! No vnet possible" return 1 fi if [ "$_ipaddr" = "auto" ] || [ -z "$_ipaddr" ]; then if ! _is_potnet_available ; then _error "potnet is not available! It's needed by -i auto" return 1 fi _ipaddr="$(potnet next)" else if ! potnet validate -H "$_ipaddr" 2> /dev/null ; then _error "The $_ipaddr IP is not valid - run potnet validate -H $_ipaddr for more information" return 1 fi fi ;; "private-bridge") if ! _is_vnet_available ; then _error "This kernel doesn't support VIMAGE! No vnet possible" return 1 fi if [ "$_network_stack" = "ipv6" ]; then _error "private-bridge network type is not supported on ipv6 stack only" return 1 fi if [ -z "$_private_bridge" ]; then _error "private-bridge network type requires -B option, to specify which private bridge to use" return 1 fi if ! _is_bridge "$_private_bridge" ; then _error "bridge $_private_bridge is not valid. Have you already created it?" return 1 fi if [ "$_ipaddr" = "auto" ] || [ -z "$_ipaddr" ]; then if ! _is_potnet_available ; then _error "potnet is not available! It's needed by -i auto" return 1 fi _ipaddr="$(potnet next -b "$_private_bridge")" elif ! potnet validate -H "$_ipaddr" -b "$_private_bridge" 2> /dev/null ; then _error "The $_ipaddr IP is not valid for bridge $_private_bridge - run potnet validate -H $_ipaddr -b $_private_bridge for more information" return 1 fi ;; *) _error "Network type $_network_type not recognized" return 1 ;; esac echo "$_ipaddr" return 0 } ================================================ FILE: share/pot/prepare.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : prepare-help() { cat <<-"EOH" pot prepare [-hvS] -p pot -U URL -t tag -a aID -n potname -c cmd [-e [proto:]port[:pot_port]] [-N network-type] [-i ipaddr] [-B bridge-name] [-C pubkey] -h print this help -h verbose -p pot : the pot image -U URL : the base URL where to find the image file -t tag : the tag of the pot -a aID : the allocation ID -n potname : the new potname (used instead of pot_tag) -c cmd : the command line to start the container -N network-type : new network type of the imported pot -i ipaddr : an ip address or the keyword auto (if applicable) -e [proto:]port[:pot_port] : port(s) to export This option can be repeated to export multiple ports. See `pot help export-ports` for details. -B bridge-name : the name of the private bridge to be used -S network-stack : the network stack (ipv4, ipv6 or dual) -d dns : change pot dns resolver configuration, one of inherit - inherit from jailhost pot - the pot configured in POT_DNS_NAME custom: - copy into pot configuration off - leave resolver config unaltered -s : start the newly generated pot immediately -C pubkey : verify with public key 'pubkey' using signify(1) on pot import EOH } pot-prepare() { local _pname _o _URL _tag _tpname _cmd _ports _allocation_tag _new_pname local _auto_start _network_type _ipaddr _ipaddr_list _bridge_name _dns local _sign_pubkey _pname= _ports= _network_type= _ipaddr= _ipaddr_list= _auto_start="NO" _bridge_name= _cmd= _dns= _sign_pubkey="$POT_DEFAULT_SIGNATURE_PUBKEY" OPTIND=1 while getopts "hvp:U:t:c:e:a:n:sN:i:B:S:d:C:" _o ; do case "$_o" in h) prepare-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; U) _URL="$OPTARG" ;; t) _tag="$OPTARG" ;; c) _cmd="$OPTARG" ;; a) _allocation_tag="$OPTARG" ;; n) _tpname="$OPTARG" ;; e) if ! _is_export_port_valid "$OPTARG" ; then _error "$OPTARG is not a valid port number" prepare-help ${EXIT} 1 fi if [ -z "$_ports" ]; then _ports="$OPTARG" else _ports="$_ports $OPTARG" fi ;; s) _auto_start="YES" ;; N) if [ "$OPTARG" = "host" ]; then _network_type="inherit" else _network_type="$OPTARG" fi # shellcheck disable=SC2086 if ! _is_in_list "$_network_type" $_POT_NETWORK_TYPES ; then _error "Network type $_network_type not recognized" prepare-help ${EXIT} 1 fi ;; B) _bridge_name="$OPTARG" ;; i) _ipaddr_list="$_ipaddr_list $OPTARG" ;; S) if ! _is_in_list "$OPTARG" "ipv4" "ipv6" "dual" ; then _error "Network stack $OPTARG not valid" create-help ${EXIT} 1 fi _network_stack="$OPTARG" ;; d) case $OPTARG in inherit|pot|off) _dns=$OPTARG ;; custom:*) if [ -r "${OPTARG##custom:}" ]; then _dns=$OPTARG else _error "The file ${OPTARG##custom:} is not valid or readable" ${EXIT} 1 fi ;; *) _error "'${OPTART}' is not a valid dns option" prepare-help ${EXIT} 1 esac ;; C) _sign_pubkey="$OPTARG" ;; *) prepare-help ${EXIT} 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" prepare-help ${EXIT} 1 fi if [ -z "$_tag" ]; then _error "A tag is mandatory" prepare-help ${EXIT} 1 fi if [ -z "$_allocation_tag" ]; then _error "An allocation id is mandatory" prepare-help ${EXIT} 1 fi if [ "$_network_type" = "private-bridge" ] && [ -z "$_bridge_name" ]; then _error "A bridge name has to be provided if private-bridge is selected as network-type" prepare-help ${EXIT} 1 fi _imported_pname="${_pname}_${_tag}" _imported_pname="$(echo "$_imported_pname" | tr '.' '_')" if [ -z "$_tpname" ]; then _tpname="${_imported_pname}" fi _new_pname="${_tpname}_${_allocation_tag}" _new_pname="$(echo "$_new_pname" | tr '.' '_')" if _is_pot "$_new_pname" quiet ; then _error "A pot with name $_new_pname already exists" prepare-help ${EXIT} 1 fi if ! _is_pot "$_imported_pname" quiet ; then if ! pot-cmd import -U "$_URL" -t "$_tag" -p "$_pname" \ -C "$_sign_pubkey"; then _error "pot import failed" pot-cmd stop "$_imported_pname" ${EXIT} 1 fi if ! _is_pot "$_imported_pname" quiet ; then _error "imported pot is weirdly not found after import - cannot proceed" pot-cmd destroy -p "$_imported_pname" ${EXIT} 1 fi else _debug "pot $_imported_pname already imported - reusing it" fi _clone_network_opt= if [ -n "$_network_type" ]; then _clone_network_opt="-N $_network_type" fi if [ "$_network_type" = "private-bridge" ]; then _clone_network_opt="$_clone_network_opt -B $_bridge_name" fi for _ipaddr in $_ipaddr_list; do _clone_network_opt="$_clone_network_opt -i $_ipaddr" done if [ -n "$_network_stack" ]; then _clone_network_opt="$_clone_network_opt -S $_network_stack" fi if [ -n "$_dns" ]; then _clone_network_opt="$_clone_network_opt -d $_dns" fi # shellcheck disable=SC2086 if ! pot-cmd clone -P "${_imported_pname}" -p "${_new_pname}" $_clone_network_opt ; then _error "Not able to clone imported pot as $_new_pname" fi if [ -n "$_cmd" ]; then if ! pot-cmd set-cmd -p "$_new_pname" -c "$_cmd" ; then _error "Couldn't set the command $_cmd ot the pot - ignoring" fi fi if ! pot-cmd set-attribute -A persistent -V OFF -p "$_new_pname" ; then _error "Couldn't disable the persistent attribute - ignoring" fi if ! pot-cmd set-attribute -A no-rc-script -V ON -p "$_new_pname" ; then _error "Couldn't enable the no-rc-script attribute - ignoring" fi if ! pot-cmd set-attribute -A prunable -V ON -p "$_new_pname" ; then _error "Couldn't enable the no-rc-script attribute - ignoring" fi if ! pot-cmd set-attribute -A localhost-tunnel -V YES -p "$_new_pname" ; then _error "Couldn't enable the localhost-tunnel attribute - ignoring" fi if ! pot-cmd set-attribute -A no-etc-hosts -V YES -p "$_new_pname" ; then _error "Couldn't disable the enrichment of /etc/hosts - ignoring" fi if ! pot-cmd set-attribute -A no-tmpfs -V YES -p "$_new_pname" ; then _error "Couldn't disable tmpfs for /tmp - ignoring" fi if [ -n "$_ports" ]; then for _p in $_ports ; do _port_args="-e $_p $_port_args" done # shellcheck disable=SC2086 if ! pot-cmd export-ports -p "$_new_pname" $_port_args ; then _error "Couldn't export ports $_ports - ignoring" fi fi if [ "$_auto_start" = "YES" ]; then _debug "Auto starting the pot $_new_pname" if ! pot-cmd start "$_new_pname" ; then _error "pot $_new_pname failed to start" pot-cmd stop "$_new_pname" ${EXIT} 1 fi else _info "Prepared the pot $_new_pname" fi return 0 } ================================================ FILE: share/pot/prune.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 prune-help() { cat <<-"EOH" pot prune [-hvq] -h print this help -v verbose -q quite - prune with no output -g grace_period - do not prune pots that just finished executing -n dry-run - do not destroy anything EOH } # $1 pot name _prune_pot() { local _pname _quiet _dry_run _grace_period _confdir _pname=$1 _dry_run=$2 _quiet=$3 _grace_period=$4 _confdir="${POT_FS_ROOT}/jails/$_pname/conf" if ! _is_pot_running "$_pname" ; then if ! _is_pot_prunable "$_pname" ; then return fi if [ "$( _get_conf_var "$_pname" "pot.attr.to-be-pruned" )" != "YES" ]; then return fi if [ "$_grace_period" = "YES" ]; then # check if just finished running if find "$_confdir/.last_run_stats" -mtime -1m 2>/dev/null | \ grep -q "."; then return fi sleep 2 # give pot-start a chance to write .last_run_stats # check again if just finished running if find "$_confdir/.last_run_stats" -mtime -1m 2>/dev/null | \ grep -q "."; then return fi if _is_pot_running "$_pname" ; then return fi fi _info "Pruning $_pname" if [ "$_dry_run" = "YES" ]; then return fi if _is_pot_running "$_pname" ; then pot-cmd stop "$_pname" fi if ! pot-cmd destroy -p "$_pname" ; then _qerror "$_quiet" "Error while pruning $_pname" else _info "Pruned $_pname" fi fi } _prune_pots() { local _pots _dry_run _quiet _grace_period _p _dry_run="$1" _quiet="$2" _grace_period="$3" _pots="$( _get_pot_list )" for _p in $_pots; do _prune_pot "$_p" "$_dry_run" "$_quiet" "$_grace_period" done } pot-prune() { local _quiet _dry_run _quiet= _grace_period="NO" _dry_run="NO" OPTIND=1 while getopts "hvqgn" _o ; do case "$_o" in h) prune-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; q) _quiet="quiet" ;; g) _grace_period="YES" ;; n) _dry_run="YES" ;; *) prune-help ${EXIT} 1 ;; esac done if ! _is_uid0 ; then ${EXIT} 1 fi _prune_pots "$_dry_run" "$_quiet" "$_grace_period" } ================================================ FILE: share/pot/ps.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 ps-help() { cat <<-"EOH" pot ps [-hvq] -h print this help -v verbose -q quiet : only print pot names EOH } # $1 pot name _ps_pot() { local _pname _quiet _pname=$1 _quiet=$2 if _is_pot_running "$_pname" ; then if [ "$_quiet" = "quiet" ]; then echo "$_pname" return fi echo "$_pname" fi } _ps_pots() { local _pots _quiet _p _quiet="$1" _pots="$( _get_pot_list )" for _p in $_pots ; do _ps_pot "$_p" "$_quiet" done } pot-ps() { local _quiet _quiet= OPTIND=1 while getopts "hvq" _o ; do case "$_o" in h) ps-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; q) _quiet="quiet" ;; *) ps-help ${EXIT} 1 ;; esac done if [ -z "$_quiet" ]; then if ! _is_uid0 quiet ; then _info "Need privileges to read internal network status" elif _is_vnet_up ; then _info "Internal network up" else _info "Internal network down" fi fi _ps_pots "$_quiet" } ================================================ FILE: share/pot/purge-snapshots.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : purge-snapshots-help() { cat <<-"EOH" pot purge-snapshots [-hva] -p potname|-f fscomp -h print this help -v verbose -p potname : the pot target of the purge-snapshots -f fscomp : the fs component target of the purge-snapshots -a remove all snapshot, including the latest one EOH } # $1 zfs dataset _zfs_old_snapshots() { local _dset _output="$(zfs list -d 1 -H -t snap "$_dset" | sort -r | sed '1d' | sort | cut -d'@' -f2 | cut -f1 )" echo "$_output" } # $1 zfs dataset _zfs_all_snapshots() { local _dset _output="$(zfs list -d 1 -H -t snap "$_dset" | sort | cut -d'@' -f2 | cut -f1 )" echo "$_output" } _purge_dset() { local _dset _snaps _all_snap _dset=$1 _all_snap=${2:-"NO"} if [ "$_all_snap" = "YES" ]; then _snaps="$(_zfs_all_snapshots "$_dset")" else _snaps="$(_zfs_old_snapshots "$_dset")" fi if [ -z "$_snaps" ]; then return fi for _s in $_snaps ; do zfs destroy -r "${_dset}@${_s}" done } pot-purge-snapshots() { local _obj _objname _all_snap _all_snap="NO" _obj="" OPTIND=1 while getopts "hvp:f:a" _o ; do case "$_o" in h) purge-snapshots-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) if [ -z "$_obj" ]; then _obj="pot" _objname="$OPTARG" else _error "-p|-f are exclusive" purge-snapshots-help ${EXIT} 1 fi ;; f) if [ -z "$_obj" ]; then _obj="fscomp" _objname="$OPTARG" else _error "-p|-f are exclusive" purge-snapshots-help ${EXIT} 1 fi ;; a) _all_snap="YES" ;; *) purge-snapshots-help ${EXIT} 1 ;; esac done if [ -z "$_obj" ]; then _error "one of -p|-f has to be used" purge-snapshots-help return 1 fi if [ -z "$_objname" ]; then _error "-p|-f options need an argument" purge-snapshots-help return 1 fi case $_obj in "pot") if ! _is_pot "$_objname" ; then _error "$_objname is not a pot!" purge-snapshots-help return 1 fi _purge_dset "${POT_ZFS_ROOT}/jails/$_objname" "$_all_snap" ;; "fscomp") if ! _zfs_exist "${POT_ZFS_ROOT}/fscomp/$_objname" "${POT_FS_ROOT}/fscomp/$_objname" ; then _error "$_objname is not a valid fscomp" purge-snapshots-help return 1 fi if ! _is_uid0 ; then return 1 fi _purge_dset "${POT_ZFS_ROOT}/fscomp/$_objname" "$_all_snap" ;; esac return 0 } ================================================ FILE: share/pot/rename.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : rename-help() { cat <<-"EOH" pot rename [-hv] -p oldname -n newname -h print this help -v verbose -p oldname : the name of an existing pot to rename -n newname : the new name for an existing pot EOH } _rn_conf() { local _pname _newname _cdir _pname=$1 _newname=$2 _cdir=${POT_FS_ROOT}/jails/$_pname/conf ${SED} -i '' -e "s%/jails/$_pname/%/jails/$_newname/%g" "$_cdir/fscomp.conf" ${SED} -i '' -e "/^host.hostname=.*/d" "$_cdir/pot.conf" echo "host.hostname=\"${_newname}.$( hostname )\"" >> "$_cdir/pot.conf" if [ -w /usr/local/etc/syslog.d/"${_pname}".conf ]; then mv /usr/local/etc/syslog.d/"${_pname}".conf /usr/local/etc/syslog.d/"${_newname}".conf ${SED} -i '' "s/$_pname.log/$_newname.log/" /usr/local/etc/syslog.d/"${_newname}".conf touch "/var/log/pot/$_newname.log" service syslogd reload fi if [ -w /usr/local/etc/newsyslog.conf.d/"${_pname}".conf ]; then mv /usr/local/etc/newsyslog.conf.d/"${_pname}".conf /usr/local/etc/newsyslog.conf.d/"${_newname}".conf ${SED} -i '' "s%pot/$_pname.log%pot/$_newname.log%" /usr/local/etc/newsyslog.conf.d/"${_newname}".conf fi } _rn_zfs() { local _pname _newname _dset _nset _type _pname=$1 _newname=$2 _dset=${POT_ZFS_ROOT}/jails/$_pname _nset=${POT_ZFS_ROOT}/jails/$_newname _type=$( _get_pot_type "$_pname" ) if [ "$_type" = "multi" ]; then #sudo zfs umount zroot/pot/jails/dns1/usr.local #sudo zfs set mountpoint=/opt/pot/jails/dns2/usr.local zroot/pot/jails/dns2/usr.local #sudo zfs umount zroot/pot/jails/dns1/custom #sudo zfs set mountpoint=/opt/pot/jails/dns2/custom zroot/pot/jails/dns2/custom #sudo zfs umount zroot/pot/jails/dns1 if _zfs_dataset_valid "$_dset/usr.local" ; then _debug "Preparing $_dset/usr.local" zfs umount -f "$_dset/usr.local" zfs set mountpoint="${POT_FS_ROOT}/jails/$_newname/usr.local" "$_dset/usr.local" fi if _zfs_dataset_valid "$_dset/custom" ; then _debug "Preparing $_dset/custom" zfs umount -f "$_dset/custom" zfs set mountpoint="${POT_FS_ROOT}/jails/$_newname/custom" "$_dset/custom" fi if _zfs_dataset_valid "$_dset" ; then _debug "Preparing $_dset" zfs umount -f "$_dset" fi #sudo zfs rename zroot/pot/jails/dns1 zroot/pot/jails/dns2 _debug "Renaming $_dset in $_nset" zfs rename "$_dset" "$_nset" #sudo zfs mount zroot/pot/jails/dns2 _debug "Mount $_nset" zfs mount "$_nset" #sudo zfs mount zroot/pot/jails/dns2/custom #sudo zfs mount zroot/pot/jails/dns2/usr.local zfs mount "$_nset/custom" if _zfs_dataset_valid "$_nset/usr.local" ; then zfs mount "$_nset/usr.local" fi else # type single if _zfs_dataset_valid "$_dset/m" ; then _debug "Preparing $_dset/m" zfs umount -f "$_dset/m" zfs set mountpoint="${POT_FS_ROOT}/jails/$_newname/m" "$_dset/m" fi if _zfs_dataset_valid "$_dset" ; then _debug "Preparing $_dset" zfs umount -f "$_dset" fi _debug "Renaming $_dset in $_nset" zfs rename "$_dset" "$_nset" _debug "Mount $_nset" zfs mount "$_nset" if _zfs_dataset_valid "$_nset/m" ; then zfs mount "$_nset/m" fi fi } # rename also on all lvl2 and dependencies _rn_recursive() { local _pname _newname _pots _cdir _pname=$1 _newname=$2 _pots=$( _get_pot_list ) for _p in $_pots ; do _cdir=${POT_FS_ROOT}/jails/$_p/conf ${SED} -i '' -e "s%/jails/$_pname/%/jails/$_newname/%g" "$_cdir/fscomp.conf" ${SED} -i '' -e "s/^pot.potbase=$_pname$/pot.potbase=$_newname/" "$_cdir/pot.conf" ${SED} -i '' -e "s/^pot.depend=$_pname$/pot.depend=$_newname/" "$_cdir/pot.conf" done } pot-rename() { local _pname _newname _pname= _newname= OPTIND=1 while getopts "hvp:n:" _o ; do case "$_o" in h) rename-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; n) _newname="$OPTARG" ;; *) rename-help ${EXIT} 1 esac done if [ -z "$_pname" ]; then _error "pot name is missing (-p)" rename-help $EXIT 1 fi if [ -z "$_newname" ]; then _error "new name is missing (-n)" rename-help ${EXIT} 1 fi if ! _is_pot "$_pname" ; then _error "$_pname is not a valid pot" ${EXIT} 1 fi if _is_pot "$_newname" quiet ; then _error "pot $_newname exists already" ${EXIT} 1 fi if _is_pot_running "$_pname" ; then _error "pot $_pname is still running" ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi _rn_conf "$_pname" "$_newname" _rn_zfs "$_pname" "$_newname" _rn_recursive "$_pname" "$_newname" return 0 } ================================================ FILE: share/pot/revert.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : revert-help() { cat <<-"EOH" pot revert [-hv] -p potname|-f fscomp -h print this help -v verbose -p potname : the pot target of the revert -f fscomp : the fs component target of the revert EOH } # $1 pot name _pot_zfs_rollback() { local _pname _pdset _snap _pname=$1 _pdset=${POT_ZFS_ROOT}/jails/$_pname for _dset in $( zfs list -o name -H -r "$_pdset" | sort -r | tr '\n' ' ') ; do _snap="$( _zfs_last_snap "$_dset")" if [ -z "$_snap" ]; then _info "$_dset has not snapshot - no possible rollback" continue fi zfs rollback "$_dset"@"$_snap" done } _fscomp_zfs_rollback() { local _fscomp _fdset _snap _fscomp=$1 _fdset=${POT_ZFS_ROOT}/fscomp/$_fscomp for _dset in $( zfs list -o name -H -r "$_fdset" | sort -r | tr '\n' ' ') ; do _snap="$( _zfs_last_snap "$_dset")" if [ -z "$_snap" ]; then _info "$_dset has not snapshot - no possible rollback" continue fi zfs rollback "$_dset@$_snap" done } pot-revert() { local _obj _obj= OPTIND=1 while getopts "hvp:f:" _o ; do case "$_o" in h) revert-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) if [ -z "$_obj" ]; then _obj="pot" _objname="$OPTARG" else _error "-p|-f are exclusive" revert-help ${EXIT} 1 fi ;; f) if [ -z "$_obj" ]; then _obj="fscomp" _objname="$OPTARG" else _error "-p|-f are exclusive" revert-help ${EXIT} 1 fi ;; ?) revert-help ${EXIT} 1 ;; esac done if [ -z "$_obj" ]; then _error "one of -p|-f has to be used" revert-help $EXIT 1 fi if [ -z "$_objname" ]; then _error "-p|-f options need an argument" revert-help ${EXIT} 1 fi case $_obj in "pot") if ! _is_pot "$_objname" ; then _error "$_objname is not a pot!" revert-help ${EXIT} 1 fi if _is_pot_running "$_objname" ; then _error "The pot $_objname is still running. Revert is possible only for stopped pots" ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi _pot_zfs_rollback "$_objname" ;; "fscomp") if ! _zfs_exist "${POT_ZFS_ROOT}/fscomp/$_objname" "${POT_FS_ROOT}/fscomp/$_objname" ; then _error "$_objname is not a valid fscomp" revert-help ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi _fscomp_zfs_rollback "$_objname" ;; esac } ================================================ FILE: share/pot/set-attribute.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : set-attribute-help() { cat <<-EOH pot set-attribute [-hv] -p pot -A attr -V value -h print this help -v verbose -p pot : the working pot -A attribute : one of $(echo "$_POT_RW_ATTRIBUTES $_POT_JAIL_RW_ATTRIBUTES" | xargs -n1 echo " +" | sort) -V value : the new value for "attribute" EOH } # $1 pot name # $2 attribute name # $3 value _set_boolean_attribute() { local _pname _value _cdir _pname=$1 _attr=$2 _value=$3 if ! _value=$(_normalize_true_false "$_value") ; then _error "value $_value is not a valid boolean value" set-attribute-help return 1 fi _cdir="$POT_FS_ROOT/jails/$_pname/conf" ${SED} -i '' -e "/^pot.attr.$_attr=.*/d" "$_cdir/pot.conf" echo "pot.attr.$_attr=$_value" >> "$_cdir/pot.conf" } # $1 pot name # $2 attribute name # $3 value _set_uint_attribute() { local _pname _value _cdir _pname=$1 _attr=$2 _value=$3 if [ -n "$(printf '%s' "${_value}" | tr -d '0-9')" ] ; then _error "value $_value is not a valid uint value" set-attribute-help return 1 fi _cdir="$POT_FS_ROOT/jails/$_pname/conf" ${SED} -i '' -e "/^pot.attr.$_attr=.*/d" "$_cdir/pot.conf" echo "pot.attr.$_attr=$_value" >> "$_cdir/pot.conf" } # $1 pot name # $2 attribute name # $3 value _set_string_attribute() { local _pname _value _cdir _pname=$1 _attr=$2 _value=$3 _cdir="$POT_FS_ROOT/jails/$_pname/conf" ${SED} -i '' -e "/^pot.attr.$_attr=.*/d" "$_cdir/pot.conf" echo "pot.attr.$_attr=$_value" >> "$_cdir/pot.conf" } # $1 pot name # $2 attribute name # $3 value _set_sysvopt_attribute() { local _pname _value _cdir _pname=$1 _attr=$2 _value=$3 if [ "$_value" != "new" ] && [ "$_value" != "inherit" ] && \ [ "$_value" != "disable" ]; then _error "value must be one of 'new', 'inherit', 'disable'" set-attribute-help return 1 fi _cdir="$POT_FS_ROOT/jails/$_pname/conf" ${SED} -i '' -e "/^pot.attr.$_attr=.*/d" "$_cdir/pot.conf" echo "pot.attr.$_attr=$_value" >> "$_cdir/pot.conf" } _ignored_parameter() { local _attr _attr=$1 _info "The attribute $_attr is not implemented and it will be ignored" } pot-set-attribute() { local _pname _attr _value _type _pname= _attr= _value= OPTIND=1 while getopts "hvp:A:V:" _o ; do case "$_o" in h) set-attribute-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; V) _value="$OPTARG" ;; A) _attr="$OPTARG" ;; *) set-attribute-help return 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" set-attribute-help return 1 fi if [ -z "$_attr" ]; then _error "Option -A is mandatory" set-attribute-help return 1 fi if [ -z "$_value" ]; then _error "Option -V is mandatory" set-attribute-help return 1 fi if ! _is_pot "$_pname" ; then _error "$_pname is not a valid pot" set-attribute-help return 1 fi # shellcheck disable=SC2086 if ! _is_in_list "$_attr" $_POT_RW_ATTRIBUTES ${_POT_JAIL_RW_ATTRIBUTES} ; then _error "$_attr is not a valid attribute" set-attribute-help return 1 fi if ! _is_uid0 ; then return 1 fi case $_attr in "start-at-boot"|\ "early-start-at-boot"|\ "persistent"|\ "no-rc-script"|\ "no-etc-hosts"|\ "prunable"|\ "localhost-tunnel") _cmd=_set_boolean_attribute ;; "no-tmpfs") if [ "$(_get_conf_var "$_pname" pot.type)" = "single" ] ; then if ! _is_pot_running "$_pname" ; then _cmd=_set_boolean_attribute else _error "pot $_pname is still running" fi else _error "Attribute no-tmpfs is only usable with single type pot" return 1 fi ;; *) # shellcheck disable=SC1083,2086 eval _type=\"\${_POT_DEFAULT_${_attr}_T}\" case "${_type}" in (bool) _cmd=_set_boolean_attribute ;; (uint) _cmd=_set_uint_attribute ;; (string) _cmd=_set_string_attribute ;; (sysvopt) _cmd=_set_sysvopt_attribute ;; (*) _ignored_parameter "$_attr" return 0 ;; esac ;; esac if ! $_cmd "$_pname" "$_attr" "$_value" ; then return 1 # false fi return 0 } ================================================ FILE: share/pot/set-cmd.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : set-cmd-help() { cat <<-"EOH" pot set-cmd [-hv] -p pot -c cmd -h print this help -v verbose -p pot : the working pot -c cmd : the command line to start the container EOH } pot-set-cmd() { local _pname _cmd _cmd= _pname= OPTIND=1 while getopts "hvp:c:" _o ; do case "$_o" in h) set-cmd-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; c) _cmd="$OPTARG" ;; p) _pname="$OPTARG" ;; *) set-cmd-help return 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" set-cmd-help return 1 fi if [ -z "$_cmd" ]; then _error "A command is mandatory" set-cmd-help return 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" set-cmd-help return 1 fi if ! _is_uid0 ; then return 1 fi _set_command "$_pname" "$_cmd" } ================================================ FILE: share/pot/set-env.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : set-env-help() { cat <<-"EOH" pot set-env [-hv] -p pot -E env -h print this help -v verbose -p pot : the working pot -E var=value : the variable and the value to be added this option can be repeated more than once EOH } # $1 pot # $2 env _set_environment() { local _pname _tmpfile _cfile _pname="$1" _tmpfile="$2" _cfile=$POT_FS_ROOT/jails/$_pname/conf/pot.conf ${SED} -i '' -e "/^pot.env=.*/d" "$_cfile" sed 's/.*/pot.env=&/g' "$_tmpfile" >> "$_cfile" } pot-set-env() { local _pname _env _tmpfile _env= _pname= if ! _is_pot_tmp_dir ; then _error "Failed to create the POT_TMP directory" return 1 fi _tmpfile="$(mktemp "${POT_TMP:-/tmp}/pot-set-env${POT_MKTEMP_SUFFIX}")" || exit 1 OPTIND=1 while getopts "hvp:E:" _o ; do case "$_o" in h) set-env-help rm -f "$_tmpfile" return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; E) if [ "$OPTARG" = "${OPTARG#*=}" ]; then # the argument doesn't have an equal sign _error "$OPTARG not in a valid form" _error "VARIABLE=value is accetped" set-env-help rm -f "$_tmpfile" return 1 fi _tmp="$( echo "$OPTARG" | sed 's%"%\\"%g' )" echo "\"$_tmp\"" >> "$_tmpfile" _env=1 ;; p) _pname="$OPTARG" ;; ?) set-env-help rm -f "$_tmpfile" return 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" set-env-help rm -f "$_tmpfile" return 1 fi if [ -z "$_env" ]; then _error "A command is mandatory" set-env-help rm -f "$_tmpfile" return 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" set-env-help rm -f "$_tmpfile" return 1 fi if ! _is_uid0 ; then rm -f "$_tmpfile" return 1 fi _set_environment "$_pname" "$_tmpfile" rm -f "$_tmpfile" } ================================================ FILE: share/pot/set-hook.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : set-hook-help() { cat <<-"EOH" pot set-hook [-hv] -p pot [-s hook] -h print this help -v verbose -p pot : the working pot -s hook : the pre-start hook -S hook : the post-start hook -t hook : the pre-stop hook -T hook : the post-stop hook EOH } # $1 pot # $2 script name # $3 hook type _set_hook() { local _pname _script _pname="$1" _script="$2" _hooktype="$3" cp "$_script" "$POT_FS_ROOT/jails/$_pname/conf/${_hooktype}.sh" } # $1 hook script _is_valid_hook() { if [ -x "$1" ]; then return 0 # true fi _error "$1 not a valid hook" return 1 # false } pot-set-hook() { local _pname _prestart _poststart _prestop _poststop _pname= _prestart= _poststart= _prestop= _poststop= OPTIND=1 while getopts "hvp:s:S:t:T:" _o ; do case "$_o" in h) set-hook-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; s) if _is_valid_hook "${OPTARG}" ; then _prestart="${OPTARG}" fi ;; S) if _is_valid_hook "${OPTARG}" ; then _poststart="${OPTARG}" fi ;; t) if _is_valid_hook "${OPTARG}" ; then _prestop="${OPTARG}" fi ;; T) if _is_valid_hook "${OPTARG}" ; then _poststop="${OPTARG}" fi ;; p) _pname="$OPTARG" ;; ?) set-hook-help return 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" set-hook-help return 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" set-hook-help return 1 fi if [ -z "$_prestart" ] && [ -z "$_poststart" ] && [ -z "$_prestop" ] && [ -z "$_poststop" ]; then _error "No hooks provided - at least one hook as to be set" set-hook-help return 1 fi if ! _is_uid0 ; then return 1 fi if [ -n "$_prestart" ]; then _set_hook "$_pname" "$_prestart" "prestart" fi if [ -n "$_poststart" ]; then _set_hook "$_pname" "$_poststart" "poststart" fi if [ -n "$_prestop" ]; then _set_hook "$_pname" "$_prestop" "prestop" fi if [ -n "$_poststop" ]; then _set_hook "$_pname" "$_poststop" "poststop" fi } ================================================ FILE: share/pot/set-hosts.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : set-hosts-help() { cat <<-"EOH" pot set-hosts [-hv] -p pot -H hostname:IP -h print this help -v verbose -p pot : the working pot -H hostname:IP : hostname-to-IP resolution to be added to /etc/hosts, can be used multiple times EOH } # $1 pot # $2 hostfile _set_hosts() { local _pname _tmpfile _cfile _pname="$1" _tmpfile="$2" _cfile=$POT_FS_ROOT/jails/$_pname/conf/pot.conf ${SED} -i '' -e "/^pot.hosts=.*/d" "$_cfile" sed 's/.*/pot.hosts=&/g' "$_tmpfile" >> "$_cfile" } pot-set-hosts() { local _pname _tmpfile _ip _hostname _pname= if ! _is_pot_tmp_dir ; then _error "Failed to create the POT_TMP directory" return 1 fi _tmpfile="$(mktemp "${POT_TMP:-/tmp}/pot-set-hosts${POT_MKTMP_SUFFIX}")" || exit 1 OPTIND=1 while getopts "hvp:H:" _o ; do case "$_o" in h) set-hosts-help rm -f "$_tmpfile" return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; H) if [ "$OPTARG" = "${OPTARG#*:}" ]; then # the argument doesn't have an equal sign _error "$OPTARG not in a valid form" _error "hostname:IP is accepted" set-hosts-help rm -f "$_tmpfile" return 1 fi # validate IP address _ip="${OPTARG#*:}" _hostname="${OPTARG%%:*}" if [ -z "$_ip" ] || [ -z "$_hostname" ]; then _error "Submitted ip or hostname are empty" set-hosts-help rm -f "$_tmpfile" return 1 fi if ! potnet ipcheck -H "$_ip" ; then _error "Submitted ip $_ip is not a valid one" set-hosts-help rm -f "$_tmpfile" return 1 fi echo "$_ip $_hostname" >> "$_tmpfile" ;; p) _pname="$OPTARG" ;; ?) set-hosts-help rm -f "$_tmpfile" return 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" set-hosts-help rm -f "$_tmpfile" return 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" set-hosts-help rm -f "$_tmpfile" return 1 fi if ! _is_uid0 ; then rm -f "$_tmpfile" return 1 fi _set_hosts "$_pname" "$_tmpfile" rm -f "$_tmpfile" } ================================================ FILE: share/pot/set-rss.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : set-rss-help() { cat <<-"EOH" pot set-rss [-hv] -p pot [-C cpus] [-M memory] -h print this help -v verbose -p pot : the working pot -C cpus : the max amount of CPUs -M memory : max memory usable (integer values) EOH } # $1 pot # $2 rss name # $3 rss limit _set_rss() { local _rssname _rsslimit _pname _cdir _pname="$1" _rssname="$2" _rsslimit="$3" _cdir=$POT_FS_ROOT/jails/$_pname/conf ${SED} -i '' -e "/^pot.rss.$_rssname=.*/d" "$_cdir/pot.conf" echo "pot.rss.$_rssname=$_rsslimit" >> "$_cdir/pot.conf" } # $1 the amount of memory _memory_validation() { : # Implement local _number if ! echo "$1" | grep -q -E '^[0-9]+[bBkKmMgG]?$' ; then _error "$1 is not a valid memory constraint" return 1 fi _number="$( echo "$1" | sed 's/[bBkKmMgG]$//')" if ! echo "$_number" | grep -q -E '^[0-9]+' ; then _error "$1 has wrong suffix or format" return 1 fi if echo "$_number" | grep -q '^00*$' ; then _error "Memory constraint has to be greater than zero" return 1 fi return 0 } # $1 pot # $2 cpus amount _set_cpu() { local _pname _cpus _pname=$1 _cpus=$2 if _is_natural_number "$_cpus" ; then if [ "$_cpus" -gt 0 ]; then _set_rss "$_pname" cpus "$_cpus" return 0 # true fi fi return 1 # false } _set_memory() { local _pname _memory _pname=$1 _memory=$2 _set_rss "$_pname" memory "$_memory" } pot-set-rss() { local _pname _cpus _memory _pname= _cpus= _memory= OPTIND=1 while getopts "hvp:C:M:" _o ; do case "$_o" in h) set-rss-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; C) _cpus="$OPTARG" ;; M) if _memory_validation "$OPTARG" ; then _memory="$OPTARG" else set-rss-help return 1 fi ;; *) set-rss-help return 1 ;; esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" set-rss-help return 1 fi if ! _is_pot "$_pname" ; then _error "$_pname is not a valid pot name" set-rss-help return 1 fi if [ -z "${_cpus}${_memory}" ]; then _error "One resource has to be specified (-C or -M)" set-rss-help return 1 fi if ! _is_uid0 ; then return 1 fi if [ -n "$_cpus" ]; then if ! _set_cpu "$_pname" "$_cpus" ; then _error "$_cpus is a not valid amount of CPUs!" return 1 fi fi if [ -n "$_memory" ]; then _set_memory "$_pname" "$_memory" fi } ================================================ FILE: share/pot/set-status.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : : "${_POT_INTERNAL_STATUS:="starting doa started stopping stopped"}" set-status-help() { cat <<-EOH Internal command, DO NOT USE IF YOU DON'T KNOW WHAT YOU ARE DOING! This command is meant to be invoked using lockf pot set-status [-hv] [-p pname] [-s status] -h print this help -v verbose -i interface(s) : network interface (epaira) -p pname : pot name -s status : the status [$_POT_INTERNAL_STATUS] EOH } # $1 pot name _get_status() { local _pname _status_file _uptime _mod_time _pname="$1" _status_file="${POT_TMP:-/tmp}/pot_status_${_pname}" if [ ! -e "$_status_file" ]; then return fi _mod_time=$(stat -f "%m" "$_status_file") _uptime=$(_get_system_uptime) if [ "$_uptime" -gt "$_mod_time" ]; then >&2 _debug "Ignoring outdated status file $_status_file of pot $_pname" return fi _value="$(grep "^pot.status=" "$_status_file" | tail -n 1 \ |tr -d ' \t"' | cut -f2 -d'=' )" echo "$_value" } # $1 pot name # $2 new status _set_status() { local _pname _status_file _new_status _pname="$1" _new_status="$2" _status_file="${POT_TMP:-/tmp}/pot_status_${_pname}" echo "pot.status=$_new_status" >> "$_status_file" # remove first (and outdated) occurrence of pot.status if [ "$(grep -c "^pot\.status=" "$_status_file")" -gt 1 ]; then ${SED} -i '' -n -e ":a" \ -e '/^pot\.status=/{n;bc' -e ':c' -e 'p;n;bc' -e '}' \ -e "p;n;ba" "$_status_file" fi } pot-set-status() { local _pname _new_status _tmp _current_status _current_ifnames _conf local _ifnames _ifnames="" _pname="" _new_status="" OPTIND=1 while getopts "hvp:i:s:" _o ; do case "$_o" in h) set-status-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; i) _ifnames="$OPTARG" ;; s) # shellcheck disable=SC2086 if _is_in_list "$OPTARG" $_POT_INTERNAL_STATUS ; then _new_status="$OPTARG" else _error "$OPTARG is not a valid status" fi ;; *) set-status-help return 1 ;; esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" set-status-help return 1 fi if ! _is_pot "$_pname"; then _error "$_pname is not a pot" return 1 fi _tmp=$(_get_status "$_pname") _current_status=$(echo "$_tmp" | cut -d, -f1) _current_ifnames=$(echo "$_tmp" | cut -d, -f2) # if current status is equal to new status, it means that some other pot command is # taking care of the execution of the transition and an exit code 2 is returned if [ "$_current_status" = "$_new_status" ]; then return 2 fi # new status can only be accepted from a specific current status # any other case, the command return an exit code 1 case "$_new_status" in "starting") if [ -n "$_current_status" ] && [ "$_current_status" != "stopped" ]; then return 1 fi _ifnames="" ;; "started" | "doa") if [ "$_current_status" != "starting" ]; then return 1 fi ;; "stopping") # you can always stop a stopped pot (for cleanup reasons) if [ "$_current_status" != "started" ] && \ [ "$_current_status" != "doa" ] && [ "$_current_status" != "stopped" ]; then return 1 fi _ifnames="$_current_ifnames" echo "$_ifnames" ;; "stopped") if [ "$_current_status" != "stopping" ]; then return 1 fi _ifnames="" ;; esac _set_status "$_pname" "$_new_status,$_ifnames" } ================================================ FILE: share/pot/show.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : show-help() { cat <<-"EOH" pot show [-hvq] [-a|-r|-p potname] -h print this help -v verbose -q quiet -a all pots -r all running pots (default) -p potname : select pot by name EOH } # show pot static information _show_pot() { local _pname _bname line _dset _pname=$1 printf "pot %s\\n" "$_pname" printf "\\tdisk usage : %s\\n" "$( zfs list -o used -H "${POT_ZFS_ROOT}/jails/$_pname")" if _is_verbose ; then # TODO show external dataset usage _bname=$( _get_pot_base "$_pname" ) if [ "$( _get_pot_type "$_pname")" = "multi" ]; then printf "\\tbase usage : %s\\n" "$( zfs list -o used -H "${POT_ZFS_ROOT}/bases/$_bname")" fi while read -r line ; do _dset=$( echo "$line" | awk '{print $1}' ) if _is_absolute_path "$_dset" ; then # dset is a folder mounted via nullfs continue; fi if [ "$_dset" = "${_dset#"${POT_ZFS_ROOT}/jails/$_pname"}" ] && [ "$_dset" = "${_dset#"${POT_ZFS_ROOT}/bases/$_bname"}" ]; then printf "\\tdataset %s usage : %s\\n" "${_dset##"${POT_ZFS_ROOT}"/}" "$( zfs list -o used -H "$_dset")" fi done < "${POT_FS_ROOT}/jails/$_pname/conf/fscomp.conf" fi if _is_pot_running "$_pname" ; then _show_pot_run "$_pname" fi } # show pot runtime information # $1 pot name _show_pot_run() { local _pname _res _vm _pm _ip _network_type _aname _pname=$1 if ! _is_uid0 quiet; then _info "some runtime information requires root privileges" return fi if ! _is_rctl_available ; then _info "runtime memory usage require rctl enabled" else _res="$(rctl -hu jail:"$_pname" )" _vm="$(echo "$_res" | tr ' ' '\n' | grep ^vmemoryuse | cut -d'=' -f2)" _pm="$(echo "$_res" | tr ' ' '\n' | grep ^memoryuse | cut -d'=' -f2)" printf "\\tvirtual memory : %s\\n" "$_vm" printf "\\tphysical memory : %s\\n" "$_pm" fi _cpus="$( _get_conf_var "$_pname" pot.rss.cpus)" if [ -n "$_cpus" ]; then printf "\tmax amount of CPUs: %s\n" "$_cpus" _cpu_allocation="$( cpuset -g -j "$_pname" | grep -F -v domain | cut -f 2 -d ':' | tr -d '[:blank:]')" printf "\tallocated CPUs : %s\n" "$_cpu_allocation" fi _network_type="$(_get_pot_network_type "$_pname" )" _ip="$( _get_ip_var "$_pname" )" if [ "$_network_type" = "public-bridge" ]; then _aname="$( _get_pot_rdr_anchor_name "$_pname")" if pfctl -a "pot-rdr" -s Anchors 2>/dev/null | grep -q "pot-rdr/${_aname}$" ; then printf "\\n\\tNetwork port redirection\\n" pfctl -a "pot-rdr/$_aname" -s nat -P | grep -F \ "${_ip}"\ | sed 's/rdr pass on .* inet proto tcp from any to //g' | sed 's/ =//g' | while read -r rule ; do printf "\\t\\t%s\\n" "$rule" done fi fi } _show_running_pots() { local _pots _p _q _q=$1 _pots=$( _get_pot_list ) for _p in $_pots; do if _is_pot_running "$_p" ; then if [ "$_q" = "YES" ]; then echo "$_p" else _show_pot "$_p" fi fi done } _show_all_pots() { local _pots _p _q _q=$1 _pots=$( _get_pot_list ) for _p in $_pots; do if [ "$_q" = "YES" ]; then echo "$_p" else _show_pot "$_p" fi done } pot-show() { local _pname _running _all _pname= _running= _all= _quiet="NO" OPTIND=1 while getopts "hvp:arq" _o ; do case "$_o" in h) show-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; r) _running="YES" ;; a) _all="YES" ;; q) _quiet="YES" ;; *) show-help ${EXIT} 1 ;; esac done # shellcheck disable=SC2030,SC2031,SC2235 if ( [ -n "$_pname" ] && [ -n "$_all" ] ) || ( [ -n "$_pname" ] && [ -n "$_running" ] ) || ( [ -n "$_all" ] && [ -n "$_running" ] ); then _error "-p -r -a are mutually exclusive" show-help ${EXIT} 1 fi # shellcheck disable=SC2031 if [ -z "$_pname" ] && [ -z "$_all" ] && [ -z "$_running" ]; then _running="YES" fi if [ -n "$_all" ]; then _show_all_pots $_quiet elif [ -n "$_running" ]; then _show_running_pots $_quiet else if ! _is_pot "$_pname" ; then _error "$_pname is not a valid pot" ${EXIT} 1 fi _show_pot "$_pname" fi } ================================================ FILE: share/pot/signal.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : signal-help() { cat <<-"EOH" pot signal [-hvflC] [-s signal] [-P pid] [-m pattern] -p pot -h print this help -v verbose -C : check/dry-run: show processes that would match -f : force - always returns success, even if signalling failed -l : list supported signals -s signal : the symbolic name of the signal to send to the process, defaults to SIGINFO -P pid : the pid inside the pot to send the signal to -m pattern : A pattern to match -p pot : the pot image Parameters -P and -m are mutually exclusive. If neither of them is is specified and the pot is non-persistent, the signal is delivered to the main process of the pot. For persistent pots, specifying one of -P and -m is mandatory. EOH } # Get a list of supported signal names _get_signal_names() { killall -l | xargs } # Validate if symbolic signal name is supported _validate_signal_name() { local _signame _signame="$1" if ! _get_signal_names | xargs | tr ' ' '\n' |\ sed 's/^\(.*\)$/\1\nSIG\1/g' | grep -qFx "$_signame"; then return 1 fi } # Validate if a pid is syntactically acceptable _validate_pid() { case "$_pid" in ''|*[!0-9]*) return 1 ;; *) ;; esac } # Actually send signal to process inside pot # $1 pot name # $2 signal # $3 pid # $4 match # $5 force (YES/NO) # $6 dry-run (YES/NO) _send_signal() { local _pname _signal _pid _match _force _dry_run local _cmd _tmpfile _persist _ret _pname="$1" _signal="$2" _pid="$3" _match="$4" _force="$5" _dry_run="$6" if [ "$_dry_run" = "YES" ]; then _cmd=$(_save_params "pgrep") else _cmd=$(_save_params "pkill" "-$_signal") fi # load kill command into $@ eval "set -- $_cmd" if [ -n "$_match" ]; then _info "Sending $_signal by pattern to pot $_pname" "$@" -j "$_pname" "$_match" _ret=$? elif [ -n "$_pid" ]; then _info "Sending $_signal to pid $_pid in pot $_pname" _tmpfile=$(mktemp \ "${POT_TMP:-/tmp}/pot_sigpid_${_pname}${POT_MKTEMP_SUFFIX}" ) || ${EXIT} 1 echo "$_pid" >"$_tmpfile" || ${EXIT} 1 "$@" -j "$_pname" -F "$_tmpfile" _ret=$? rm -f "$_tmpfile" else _info "Sending $_signal to main process of pot $_pname" _persist="$(_get_conf_var "$_pname" "pot.attr.persistent")" if [ "$_persist" != "NO" ]; then if [ "$_force" = "YES" ]; then _info "Persistent pots have no main process" return 0 else _error "Persistent pots have no main process" return 1 fi fi "$@" -j "$_pname" -F "${POT_TMP:-/tmp}/pot_main_pid_${_pname}" _ret=$? fi if [ $_ret -ne 0 ]; then if [ "$_force" = "YES" ]; then _info "Sending signal failed" _ret=0 else _error "Sending signal failed" fi fi return $_ret } pot-signal() { local _pname _signal _pid _match _force _dry_run _pname= _pid= _match= _signal="SIGINFO" _force="NO" _dry_run="NO" OPTIND=1 while getopts "hvflCs:P:m:p:" _o ; do case "$_o" in h) signal-help ${EXIT} 0 ;; l) _get_signal_names ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; f) _force="YES" ;; C) _dry_run="YES" ;; s) _signal="$OPTARG" ;; P) _pid="$OPTARG" ;; m) _match="$OPTARG" ;; p) _pname="$OPTARG" ;; *) signal-help ${EXIT} 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" signal-help ${EXIT} 1 fi if ! _validate_signal_name "$_signal"; then _error "Invalid signal, valid signals: $(_get_signal_names)" ${EXIT} 1 fi if [ -n "$_pid" ] && [ -n "$_match" ]; then _error "Process ID and pattern match are mutually exclusive" ${EXIT} 1 fi if [ -n "$_pid" ] && ! _validate_pid "$_pid"; then _error "Invalid pid" ${EXIT} 1 fi if ! _is_pot_running "$_pname" ; then if [ "$_force" = "YES" ]; then _info "The pot is not running" return 0 fi _error "The pot is not running" ${EXIT} 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi _send_signal "$_pname" "$_signal" "$_pid" "$_match" "$_force" "$_dry_run" } ================================================ FILE: share/pot/snapshot.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : snapshot-help() { cat <<-"EOH" pot snapshot [-hv] -p potname|-f fscomp -h print this help -v verbose -r replace the oldest available snapshot with the new one -p potname : the pot target of the snapshot -f fscomp : the fs component target of the snapshot EOH } pot-snapshot() { local _full_pot _obj _objname _full_pot="NO" _obj="" _objname= _replace= OPTIND=1 while getopts "hvp:f:r" _o ; do case "$_o" in h) snapshot-help return 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; r) _replace="YES" ;; p) if [ -z "$_obj" ]; then _obj="pot" _objname="$OPTARG" else _error "-p|-f are exclusive" snapshot-help return 1 fi ;; f) if [ -z "$_obj" ]; then _obj="fscomp" _objname="$OPTARG" else _error "-p|-f are exclusive" snapshot-help return 1 fi ;; *) snapshot-help return 1 ;; esac done if [ -z "$_obj" ]; then _error "one of -p|-f has to be used" snapshot-help return 1 fi if [ -z "$_objname" ]; then _error "-p|-f options need an argument" snapshot-help return 1 fi case $_obj in "pot") if ! _is_pot "$_objname" ; then _error "$_objname is not a pot!" snapshot-help return 1 fi if _is_pot_running "$_objname" ; then _error "The pot $_objname is still running. Snapshot is possible only for stopped pots" return 1 fi if ! _is_uid0 ; then return 1 fi if [ "$_full_pot" = "YES" ]; then _pot_zfs_snap_full "$_objname" else if [ "$_replace" = "YES" ]; then _remove_oldest_pot_snap "$_objname" fi _pot_zfs_snap "$_objname" fi ;; "fscomp") if ! _zfs_exist "${POT_ZFS_ROOT}/fscomp/$_objname" "${POT_FS_ROOT}/fscomp/$_objname" ; then _error "$_objname is not a valid fscomp" snapshot-help return 1 fi if ! _is_uid0 ; then return 1 fi if [ "$_replace" = "YES" ]; then _remove_oldest_fscomp_snap "$_objname" fi _fscomp_zfs_snap "$_objname" ;; esac return 0 } ================================================ FILE: share/pot/start.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : start-help() { cat <<-"EOH" pot start [-h] -p potname [pname] -h print this help -v verbose -s take a snapshot before starting the pot snapshots are identified by the epoch all ZFS datasets under the jail dataset are considered -S take a snapshot before starting the pot [DEPRECATED] snapshots are identified by the epoch all ZFS datasets mounted in rw are considered (full) -p potname : the pot to be started pname : the pot to be started if "-p potname" not given EOH } # $1 pot name # $2 the network interface, if created start-cleanup() { local _pname _epaira _epaira2 _ifaces _pname=$1 _epaira=$2 _epaira2=$3 _ifaces= if [ -z "$_pname" ]; then return fi # doa state will only be set if pot is in state "starting" _set_pot_status "$_pname" doa if [ -n "$_epaira" ] && _is_valid_netif "$_epaira" ; then _ifaces="$_epaira" fi if [ -n "$_epaira2" ] && _is_valid_netif "$_epaira2" ; then _ifaces="$_ifaces:$_epaira2" fi _ifaces="${_ifaces#:}" if [ -n "$_ifaces" ]; then pot-cmd stop -p "$_pname" -i "$_ifaces" -s else pot-cmd stop -p "$_pname" -s fi } # $1 pot name _js_dep() { local _pname _depPot _pname=$1 _depPot="$( _get_conf_var "$_pname" pot.depend )" if [ -z "$_depPot" ]; then return 0 # true fi for _d in $_depPot ; do pot-start "$_d" done return 0 # true } # $1 pot name _js_resolv() { local _pname _jdir _dns _pname="$1" _jdir="${POT_FS_ROOT}/jails/$_pname" _dns="$(_get_conf_var "$_pname" pot.dns)" if [ -z "$_dns" ]; then _dns=inherit fi case "$_dns" in "inherit") if [ ! -r /etc/resolv.conf ]; then _error "No resolv.conf found in /etc" return 1 # false fi if [ -d "$_jdir/m/etc" ]; then cp /etc/resolv.conf "$_jdir/m/etc" else _info "No custom etc directory found, resolv.conf not loaded" fi ;; "pot" ) # resolv.conf generation _domain="$( _get_conf_var "$_pname" host.hostname | cut -f 2 -d'.' )" echo "# Generated by pot" > "$_jdir/m/etc/resolv.conf" echo "search $_domain" >> "$_jdir/m/etc/resolv.conf" echo "nameserver ${POT_DNS_IP}" >> "$_jdir/m/etc/resolv.conf" ;; "custom") if [ ! -r "$_jdir/conf/resolv.conf" ]; then _error "No custom resolv.conf! pot configuration corrupted?" return 1 fi if [ -d "$_jdir/m/etc" ]; then cp "$_jdir/conf/resolv.conf" "$_jdir/m/etc" else _info "No custom etc directory found, resolv.conf not loaded" fi ;; "off") ;; esac return 0 } # tests in start4.sh # $1 pot name _js_etc_hosts() { local _pname _phosts _hostname _bridge_name _cfile _pname="$1" _phosts="${POT_FS_ROOT}/jails/$_pname/m/etc/hosts" _hostname="$( _get_conf_var "$_pname" host.hostname )" printf "::1 localhost %s\n" "$_hostname" > "$_phosts" printf "127.0.0.1 localhost %s\n" "$_hostname" >> "$_phosts" if [ "$(_get_conf_var "$_pname" "pot.attr.no-etc-hosts")" = "YES" ]; then _debug "Attribute no-etchosts: no additional /etc/hosts entries injected" else case "$( _get_conf_var "$_pname" network_type )" in "public-bridge") potnet etc-hosts >> "$_phosts" ;; "private-bridge") _bridge_name="$( _get_conf_var "$_pname" bridge )" potnet etc-hosts -b "$_bridge_name" >> "$_phosts" ;; esac fi _cfile="${POT_FS_ROOT}/jails/$_pname/conf/pot.conf" grep '^pot.hosts=' "$_cfile" | sed 's/^pot.hosts=//g' >> "$_phosts" } # returns interface names of epaira and epairb # $1 pot name # $2 prefix (optional) _js_create_epair() { local _epaira _epaira_renamed _epairb _pname _prefix _pname="$1" _prefix="$2" _epaira=$(ifconfig epair create descr "$_pname" group "pot") if [ -z "${_epaira}" ]; then _error "ifconfig epair failed" >&2 start-cleanup "$_pname" ${EXIT} 1 # false fi _epairb="${_epaira%a}b" _epaira_renamed=$(ifconfig "$_epaira" name \ "$(printf "p%s%x%x" "$_prefix" "$(date +%s)" "$$")") if [ -z "${_epaira_renamed}" ]; then _error "ifconfig epair rename failed" >&2 start-cleanup "$_pname" "$_epaira" ${EXIT} 1 # false fi echo "$_epaira_renamed" echo "$_epairb" } # $1 pot name # $2 epaira interface # $3 epairb interface _js_vnet() { local _pname _bridge _epaira _epairb _ip _param _pname=$1 if ! _is_vnet_ipv4_up ; then _info "Internal network not found! Calling vnet-start to fix the issue" pot-cmd vnet-start fi _bridge=$(_pot_bridge_ipv4) _epaira=$2 _epairb=$3 ifconfig "$_epaira" up _param=$(_save_params "addm" "$_epaira") if [ "$(_normalize_true_false "$POT_ISOLATE_VNET_POTS")" = "YES" ]; then _param="$_param"$(_save_params "private" "$_epaira") fi eval "set -- $_param" ifconfig "$_bridge" "$@" _ip=$( _get_ip_var "$_pname" ) ## if norcscript - write an ad-hoc one if [ "$(_get_conf_var "$_pname" "pot.attr.no-rc-script")" = "YES" ]; then cat >>"${POT_FS_ROOT}/jails/$_pname/m/tmp/tinirc" <<-EOT if ! ifconfig ${_epairb} >/dev/null 2>&1; then sleep 1 if ! ifconfig ${_epairb} >/dev/null 2>&1; then >&2 echo "Interface ${_epairb} does not exist" exit 1 fi fi ifconfig ${_epairb} inet $_ip netmask $POT_NETMASK route add default $POT_GATEWAY EOT else # use rc scripts # set the network configuration in the pot's rc.conf if [ -w "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" ]; then sed -i '' '/ifconfig_epair[0-9][0-9]*[ab]=/d' "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" fi echo "ifconfig_${_epairb}=\"inet $_ip netmask $POT_NETMASK\"" >> "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" sysrc -f "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" defaultrouter="$POT_GATEWAY" fi } # $1 pot name # $2 epaira interface # $3 epairb interface # $4 stack (ipv6 or dual) _js_vnet_ipv6() { local _pname _bridge _epaira _epairb _ip _param _pname=$1 if ! _is_vnet_ipv6_up ; then _info "Internal network not found! Calling vnet-start to fix the issue" pot-cmd vnet-start fi _bridge=$(_pot_bridge_ipv6) _epaira=$2 _epairb=$3 ifconfig "$_epaira" up _param=$(_save_params "addm" "$_epaira") if [ "$(_normalize_true_false "$POT_ISOLATE_VNET_POTS")" = "YES" ]; then _param="$_param"$(_save_params "private" "$_epaira") fi eval "set -- $_param" ifconfig "$_bridge" "$@" if [ "$(_get_conf_var "$_pname" "pot.attr.no-rc-script")" = "YES" ]; then cat >>"${POT_FS_ROOT}/jails/$_pname/m/tmp/tinirc" <<-EOT if ! ifconfig ${_epairb} >/dev/null 2>&1; then sleep 1 if ! ifconfig ${_epairb} >/dev/null 2>&1; then >&2 echo "Interface ${_epairb} does not exist" exit 1 fi fi ifconfig ${_epairb} inet6 up accept_rtadv -ifdisabled /sbin/rtsol -d ${_epairb} EOT else # use rc scripts # set the network configuration in the pot's rc.conf if [ -w "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" ]; then sed -i '' '/ifconfig_epair[0-9][0-9]*[ab]_ipv6/d' "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" fi echo "ifconfig_${_epairb}_ipv6=\"inet6 accept_rtadv auto_linklocal -ifdisabled\"" >> "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" sysrc -f "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" rtsold_enable="YES" # Fix a bug in the rtsold rc script in 11.3 sed -i '' 's/nojail/nojailvnet/' "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.d/rtsold" fi } # $1 pot name # $2 epaira interface # $3 epairb interface _js_private_vnet() { local _pname _bridge_name _bridge _epaira _epairb _ip _net_size local _gateway _param _pname=$1 _bridge_name="$( _get_conf_var "$_pname" bridge )" if ! _is_vnet_ipv4_up "$_bridge_name" ; then _debug "No pot bridge found! Calling vnet-start to fix the issue" pot-cmd vnet-start -B "$_bridge_name" fi _bridge="$(_private_bridge "$_bridge_name")" _epaira=$2 _epairb=$3 ifconfig "$_epaira" up _param=$(_save_params "addm" "$_epaira") if [ "$(_normalize_true_false "$POT_ISOLATE_VNET_POTS")" = "YES" ]; then _param="$_param"$(_save_params "private" "$_epaira") fi eval "set -- $_param" ifconfig "$_bridge" "$@" ifconfig "$_bridge" addm "$_epaira" _ip=$( _get_ip_var "$_pname" ) _net_size="$(_get_bridge_var "$_bridge_name" net)" _net_size="${_net_size##*/}" _gateway="$(_get_bridge_var "$_bridge_name" gateway)" ## if norcscript - write an ad-hoc one if [ "$(_get_conf_var "$_pname" "pot.attr.no-rc-script")" = "YES" ]; then cat >>"${POT_FS_ROOT}/jails/$_pname/m/tmp/tinirc" <<-EOT if ! ifconfig ${_epairb} >/dev/null 2>&1; then sleep 1 if ! ifconfig ${_epairb} >/dev/null 2>&1; then >&2 echo "Interface ${_epairb} does not exist" exit 1 fi fi ifconfig ${_epairb} inet $_ip/$_net_size route add default $_gateway EOT else # use rc scripts # set the network configuration in the pot's rc.conf if [ -w "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.con"f ]; then sed -i '' '/ifconfig_epair/d' "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" fi echo "ifconfig_${_epairb}=\"inet $_ip/$_net_size\"" >> "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" sysrc -f "${POT_FS_ROOT}/jails/$_pname/m/etc/rc.conf" defaultrouter="$_gateway" fi } # $1: exclude list _js_get_free_rnd_port() { local _min _max excl_ports used_ports rdr_ports rand excl_ports="$1" _min=$( sysctl -n net.inet.ip.portrange.reservedhigh ) _min=$(( _min + 1 )) _max=$( sysctl -n net.inet.ip.portrange.first ) _max=$(( _max - 1 )) used_ports="$(sockstat -p ${_min}-${_max} -4l | awk '!/USER/ { n=split($6,a,":"); if ( n == 2 ) { print a[2]; }}' | sort -u)" anchors="$(pfctl -a pot-rdr -s Anchors)" for a in $anchors ; do new_ports="$( pfctl -a "$a" -s nat -P | awk '/rdr/ { n=split($0,a," "); for(i=1;i<=n;i++) { if (a[i] == "=" ) { print a[i+1];break;}}}')" rdr_ports="$rdr_ports $new_ports" done rand=$_min while [ $rand -le $_max ]; do for p in $excl_ports $used_ports $rdr_ports ; do if [ "$p" = "$rand" ]; then rand=$(( rand + 1 )) continue 2 fi done echo $rand break done } # $1 pot name _js_export_ports() { local _pname _ip _ports _excl_list _pot_port _host_port _proto_port _aname _pdir _ncat_opt _to_arg _bridge _pname=$1 _ip="$( _get_ip_var "$_pname" )" _ports="$( _get_pot_export_ports "$_pname" )" if [ -z "$_ports" ]; then return fi _pfrules=$(mktemp "${POT_TMP:-/tmp}/pot_pfrules_${_pname}${POT_MKTEMP_SUFFIX}") || exit 1 _lo_tunnel="$(_get_conf_var "$_pname" "pot.attr.localhost-tunnel")" _bridge=$(_pot_bridge_ipv4) for _port in $_ports ; do _proto_port="tcp" if [ "${_port#udp:}" != "${_port}" ]; then _proto_port="udp" _port="${_port#udp:}" _ncat_opt="-u" elif [ "${_port#tcp:}" != "${_port}" ]; then _proto_port="tcp" _port="${_port#tcp:}" fi _pot_port="$( echo "${_port}" | cut -d':' -f 1)" _host_port="$( echo "${_port}" | cut -d':' -f 2)" if [ "$_pot_port" = "$_port" ]; then _host_port=$( _js_get_free_rnd_port "$_excl_list" ) fi if [ -n "$POT_EXTIF_ADDR" ]; then _to_arg="$POT_EXTIF_ADDR" else _to_arg="($POT_EXTIF)" fi _debug "Redirect: from $_to_arg : $_proto_port:$_host_port to $_ip : $_proto_port:$_pot_port" if [ -n "$POT_EXPORT_PORTS_PF_RULES_HOOK" ]; then "$POT_EXPORT_PORTS_PF_RULES_HOOK" \ "$POT_EXTIF" "$_bridge" "$POT_NETWORK" "$POT_GATEWAY" \ "$_proto_port" "$_host_port" "$_ip" "$_pot_port" >> "$_pfrules" else echo "rdr pass on $POT_EXTIF proto $_proto_port from any to $_to_arg port $_host_port -> $_ip port $_pot_port" >> "$_pfrules" _excl_list="$_excl_list $_host_port" if [ -n "$POT_EXTRA_EXTIF" ]; then for extra_netif in $POT_EXTRA_EXTIF ; do echo "rdr pass on $extra_netif proto $_proto_port from any to ($extra_netif) port $_host_port -> $_ip port $_pot_port" >> "$_pfrules" done fi if [ "$_lo_tunnel" = "YES" ]; then _pdir="${POT_FS_ROOT}/jails/$_pname" if [ -x "/usr/local/bin/ncat" ]; then cp /usr/local/bin/ncat "$_pdir/ncat-$_pname-$_pot_port" daemon -f -p "$_pdir/ncat-$_pot_port.pid" "$_pdir/ncat-$_pname-$_pot_port" -lk $_ncat_opt "$_host_port" -c "/usr/local/bin/ncat $_ncat_opt $_ip $_pot_port" else _error "nmap package is missing, localhost-tunnel attribute ignored" fi fi fi done _aname="$( _get_pot_rdr_anchor_name "$_pname" )" if ! pfctl -a "pot-rdr/$_aname" -f "$_pfrules" ; then _error "pfctl failed to apply redirection rules - ignoring but no redirection is performed" if _is_verbose ; then cat "$_pfrules" fi fi rm -f "$_pfrules" } # $1 jail name _js_rss() { local _pname _jid _cpus _cpuset _memory _pname=$1 _cpus="$( _get_conf_var "$_pname" pot.rss.cpus)" _memory="$( _get_conf_var "$_pname" pot.rss.memory)" if [ -n "$_cpus" ]; then _jid="$( jls -j "$_pname" | sed 1d | awk '{ print $1 }' )" _cpuset="$( potcpu get-cpu -n "$_cpus" )" cpuset -l "$_cpuset" -j "$_jid" fi if [ -n "$_memory" ]; then if ! _is_rctl_available ; then _info "memory constraint cannot be applies because rctl is not enabled - ignoring" else rctl -a jail:"$_pname":memoryuse:deny="$_memory" fi fi } # $1 pot name _js_get_cmd() { local _pname _cdir _value _pname="$1" _cdir="${POT_FS_ROOT}/jails/$_pname/conf" _value="$( grep "^pot.cmd=" "$_cdir/pot.conf" | sed 's/^pot.cmd=//' )" [ -z "$_value" ] && _value="sh /etc/rc" echo "$_value" } _js_norc() { local _pname _pname="$1" _cmd="$(_js_get_cmd "$_pname")" case "$( _get_conf_var "$_pname" network_type )" in "public-bridge"|\ "private-bridge") echo "ifconfig lo0 inet 127.0.0.1 alias" >> "${POT_FS_ROOT}/jails/$_pname/m/tmp/tinirc" ;; esac echo "exec $_cmd" >> "${POT_FS_ROOT}/jails/$_pname/m/tmp/tinirc" chmod a+x "${POT_FS_ROOT}/jails/$_pname/m/tmp/tinirc" } _js_env() { local _pname _shfile _cfile _pname="$1" _cfile="${POT_FS_ROOT}/jails/$_pname/conf/pot.conf" _shfile=$(mktemp "${POT_TMP:-/tmp}/pot_environment_${_pname}${POT_MKTEMP_SUFFIX}") || exit 1 grep '^pot.env=' "$_cfile" | sed 's/^pot.env=/export /g' > "$_shfile" pot-cmd info -E -p "$_pname" >> "$_shfile" if [ "$(_get_conf_var "$_pname" "pot.attr.no-rc-script")" = "YES" ]; then cat "$_shfile" >> "${POT_FS_ROOT}/jails/$_pname/m/tmp/tinirc" else cp "$_shfile" "${POT_FS_ROOT}/jails/$_pname/m/tmp/environment.sh" fi rm -f "$_shfile" } # $1 jail name _js_start() { local _pname _confdir _epaira _epairb _ipv6_epaira _ipv6_epairb local _ifaces _hostname _osrelease _param _ip _cmd _persist local _stack _value _name _type _wait_pid _exit_code _tmp local _default _pname="$1" _confdir="${POT_FS_ROOT}/jails/$_pname/conf" _param=$(_save_params "allow.set_hostname=false" "allow.raw_sockets" \ "allow.socket_af" "allow.chflags" "exec.clean" "mount.devfs") for _attr in ${_POT_JAIL_RW_ATTRIBUTES} ; do # shellcheck disable=SC1083,2086 eval _name=\"\${_POT_DEFAULT_${_attr}_N}\" # shellcheck disable=SC1083,2086 eval _type=\"\${_POT_DEFAULT_${_attr}_T}\" # shellcheck disable=SC1083,2086 eval _default=\"\${_POT_DEFAULT_${_attr}_D}\" if [ "$_type" = "string" ]; then _value="$(_get_conf_var_string "$_pname" "pot.attr.${_attr}")" else _value="$(_get_conf_var "$_pname" "pot.attr.${_attr}")" fi if [ "$_type" = "bool" ] && [ "$_value" = "YES" ]; then _param="$_param"$(_save_params "$_name") elif [ "$_type" != "bool" ] && [ -n "$_value" ]; then _param="$_param"$(_save_params "$_name=$_value") elif [ "$_type" = "sysvopt" ] && [ -z "$_value" ]; then _param="$_param"$(_save_params "$_name=$_default") fi done _hostname="$( _get_conf_var "$_pname" host.hostname )" _osrelease="$( _get_os_release "$_pname" )" _param="$_param"$(_save_params "name=$_pname" \ "host.hostname=$_hostname" \ "osrelease=$_osrelease" \ "path=${POT_FS_ROOT}/jails/$_pname/m") _persist="$(_get_conf_var "$_pname" "pot.attr.persistent")" if [ "$_persist" != "NO" ]; then _param="$_param"$(_save_params "persist") else _param="$_param"$(_save_params "nopersist") fi if [ "$(_get_conf_var "$_pname" "pot.attr.no-rc-script")" = "YES" ]; then if [ "$( _get_pot_network_stack "$_pname" )" = "ipv4" ]; then prec=100 else prec=35 fi cat >"${POT_FS_ROOT}/jails/$_pname/m/tmp/tinirc" <<-EOT # created automatically by pot, changes will be overwritten echo \$\$ >/tmp/tinirc.pid if sysctl -n kern.features.inet6 >/dev/null 2>&1; then ip6addrctl flush >/dev/null 2>&1 ip6addrctl install /dev/stdin <> "$_confdir/pot.conf" fi if _is_pot_running "$_pname" ; then _js_rss "$_pname" fi # shellcheck disable=SC2086 jexec "$_pname" $_cmd & _wait_pid=$! if [ -x "$_confdir/poststart.sh" ]; then _info "Executing the post-start script for the pot $_pname" ( # shellcheck disable=SC2046 eval $( pot info -E -p "$_pname" ) "$_confdir/poststart.sh" ) fi sleep 0.5 pkill -f -j "$_pname" "^sleep 1234$" if [ "$_persist" = "NO" ]; then echo "$_wait_pid" >"${POT_TMP:-/tmp}/pot_main_pid_${_pname}" fi # Here is where the pot is marked as started _set_pot_status "$_pname" started "$_ifaces" rc=$? if [ $rc -eq 2 ]; then _info "pot $_pname is already started (???)" elif [ $rc -eq 1 ]; then # should we retry (in case it's stopping?) _error "pot $_pname is not in a state where it can be started" # not returning, it could be catastrophic, but the situation is quite messed up fi wait "$_wait_pid" _exit_code=$? echo "{ \"ExitCode\": $_exit_code }" > "$_confdir/.last_run_stats" if [ "$_persist" = "NO" ]; then rm -f "${POT_TMP:-/tmp}/pot_main_pid_${_pname}" # non-persistent jails always need to die # Here is where the pot is stopping _set_pot_status "$_pname" stopping rc=$? if [ $rc -eq 2 ]; then _debug "pot $_pname is already stopping (maybe by a pot stop)" return 0 elif [ $rc -eq 1 ]; then # should we retry (in case it's stopping?) _error "pot $_pname is not in a state where it can be stopped" # returning, but the situation is quite messed up return 1 fi start-cleanup "$_pname" "${_epaira}" "${_ipv6_epaira}" if [ "$_exit_code" -ne 0 ]; then # return code to signal application exit error return 125 fi elif ! _is_pot_running "$_pname" ; then # persistent jail didn't come up, this is an error _set_pot_status "$_pname" stopping rc=$? if [ $rc -eq 2 ]; then _debug "pot $_pname is already stopping (maybe by a pot stop?)" return 0 fi if [ $rc -eq 1 ]; then # should we retry (in case it's stopping?) _error "pot $_pname is not in a state where it can be stopped" # returning, but the situation is quite messed up return 1 fi start-cleanup "$_pname" "${_epaira}" "${_ipv6_epaira}" return 1 fi } pot-start() { local _pname _snap _start_result _snap=none _pname= OPTIND=1 while getopts "hvsSp:" _o ; do case "$_o" in h) start-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; s) _snap=normal ;; S) _snap=full ;; p) _pname="$OPTARG" ;; *) start-help ${EXIT} 1 ;; esac done if [ -z "$_pname" ]; then _pname="$( eval echo \$$OPTIND)" fi if [ -z "$_pname" ]; then _error "A pot name is mandatory" start-help return 1 fi if ! _is_pot "$_pname" ; then return 1 fi if _is_pot_running "$_pname" ; then _debug "pot $_pname is already running" return 0 fi ## detect obsolete config parameter if [ -n "$(_get_conf_var "$_pname" "pot.export.static.ports")" ] || [ -n "$(_get_conf_var "$_pname" "ip4")" ]; then _error "Configuration file for $_pname contains obsolete elements" _error "Please run pot update-config -p $_pname to fix" return 1 fi if [ -n "$(_get_conf_var "$_pname" "pot.rss.cpuset")" ]; then _info "Found old cpuset rss limitation - it will be ignored" _info "Please run pot update-config -p $_pname to clean up the configuration" fi if [ "$( _get_pot_network_stack "$_pname" )" = "ipv6" ] && [ "$( _get_conf_var "$_pname" network_type )" = "private-bridge" ]; then _error "The framework is configured to run ipv6 only and private-bridge are supported only on ipv4 - abort" return 1 fi if [ "$( _get_pot_network_stack "$_pname" )" = "dual" ] && [ "$( _get_conf_var "$_pname" network_type )" = "private-bridge" ]; then _info "The framework is configured to run dual stack, but private-bridge are supported only on ipv4 - ipv6 ignored" fi if _is_pot_vnet "$_pname" ; then if ! _is_vnet_available ; then _error "This kernel doesn't support VIMAGE! No vnet possible - abort" return 1 fi fi if ! _is_uid0 ; then return 1 fi if ! _is_pot_tmp_dir ; then _error "failed to create the POT_TMP directory" return 1 fi # Here is where the pot is starting _set_pot_status "$_pname" starting rc=$? if [ $rc -eq 2 ]; then _error "pot $_pname is already starting" return 1 fi if [ $rc -eq 1 ]; then # should we retry (in case it's stopping?) _error "pot $_pname is not in a state where it can start" return 1 fi if ! _js_dep "$_pname" ; then _error "dependecy failed to start" fi case $_snap in normal) _pot_zfs_snap "$_pname" ;; full) _pot_zfs_snap_full "$_pname" ;; none|*) ;; esac if ! _pot_mount "$_pname" ; then _error "Mount failed " start-cleanup "$_pname" return 1 fi if ! _js_resolv "$_pname" ; then start-cleanup "$_pname" return 1 fi _js_etc_hosts "$_pname" _js_start "$_pname" _start_result=$? if [ $_start_result -eq 125 ]; then _error "$_pname reported application error" return 125 elif [ $_start_result -ne 0 ]; then _error "$_pname failed to start" return 1 fi return 0 } ================================================ FILE: share/pot/stop.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : stop-help() { cat <<-"EOH" pot stop [-hv] -p potname | potname -h print this help -v verbose -i interface(s) : network interface (epaira) (INTERNAL USE ONLY) -s called from start (INTERNAL USE ONLY) -p potname : the pot to be stopped the -p can be omitted and the last argument will be interpreted as the potname The option -i is intended to be used only by internal cleanup functions that knows in advance what interface pot is/was using. Usually, -i is NOT needed and it SHOULDN'T be used by users EOH } _js_cpu_rebalance() { if ! _tmpfile=$(mktemp -t "${POT_TMP:-/tmp}/potcpu.XXXXXX") ; then _error "not able to create temporary file - umount failed" return fi potcpu rebalance > "$_tmpfile" while read -r cpuset_cmd ; do eval "$cpuset_cmd" done < "$_tmpfile" } # $1 pot name _js_stop() { local _pname _pdir _epaira _epaira_ifs _ip _aname _from_start local _exec_stop _stop_timeout _pname="$1" _from_start="$2" _epaira_ifs="$3" _pdir="${POT_FS_ROOT}/jails/$_pname" _network_type=$( _get_pot_network_type "$_pname" ) if _is_pot_running "$_pname" ; then if [ -x "$_pdir/conf/prestop.sh" ]; then _info "Executing the pre-stop script for the pot $_pname" ( # shellcheck disable=SC2086,2046 eval $( pot info -E -p "$_pname" ) "$_pdir"/conf/prestop.sh ) fi _debug "Stop the pot $_pname" _exec_stop="$(_get_conf_var_string "$_pname" "pot.attr.exec_stop")" _stop_timeout="$(_get_conf_var "$_pname" "pot.attr.stop_timeout")" ( echo "$_pname {" if [ -n "$_exec_stop" ]; then printf " %s=%s;\n" "exec.stop" \ "$(echo "$_exec_stop" | sed 's/["\]/\\&/g; s/.*/"&"/')" # balance quotes for cheap syntax highlighting editors' fi if [ -n "$_stop_timeout" ]; then printf " %s=%s;\n" "stop.timeout" "$_stop_timeout" fi echo "}" ) | jail -f- -q -r "$_pname" fi # those are clean up operations for a pot already stopped if [ -n "$_epaira_ifs" ]; then for _epaira in $(echo "$_epaira_ifs" | tr : ' '); do _debug "Remove ${_epaira} epair network interfaces" sleep 1 # try to avoid a race condition in the epair driver, # potentially causing a kernel panic, which should # be fixed in FreeBSD 13.1: # https://cgit.freebsd.org/src/commit/?h=stable/13&id=f4aba8c9f0c ifconfig "${_epaira}" destroy done elif [ "$_network_type" = "alias" ]; then _ip=$( _get_ip_var "$_pname" ) _debug "Remove $_ip aliases" for _i in $_ip ; do if echo "$_i" | grep -qF '|' ; then _nic="$( echo "$_i" | cut -f 1 -d '|' )" _ipaddr="$( echo "$_i" | cut -f 2 -d '|' )" else _nic="$POT_EXTIF" _ipaddr="$_i" fi if potnet ip4check -H "$_ipaddr" ; then if ifconfig "${_nic}" | grep -q "inet $_ipaddr " ; then ifconfig "${_nic}" inet "$_ipaddr" -alias fi else if ifconfig "${_nic}" | grep -q "inet6 $_ipaddr " ; then ifconfig "${_nic}" inet6 "$_ipaddr" -alias fi fi done fi if [ -c "/dev/pf" ]; then _aname="$( _get_pot_rdr_anchor_name "$_pname" )" pfctl -a "pot-rdr/$_aname" -F nat -q fi _ports="$( _get_pot_export_ports "$_pname" )" if [ -n "$_ports" ]; then for _port in $_ports ; do _pot_port="$( echo "${_port}" | cut -d':' -f 1)" if [ -r "$_pdir/ncat-$_pot_port.pid" ]; then pkill -F "$_pdir/ncat-$_pot_port.pid" -f "ncat-$_pname-$_pot_port" rm -f "$_pdir/ncat-$_pot_port.pid" elif pgrep -q -f "$_pdir/ncat-$_pname-$_pot_port" ; then pkill -f "$_pdir/ncat-$_pname-$_pot_port" fi done fi # For compatibility reason with the previous implementations if [ -r "$_pdir/ncat.pid" ]; then pkill -F "$_pdir/ncat.pid" -f "ncat-$_pname" rm -f "$_pdir/ncat.pid" elif pgrep -q -f "$_pdir/ncat-$_pname" ; then pkill -f "$_pdir/ncat-$_pname" fi # Garbage collect POSIX shared memory if command -v posixshmcontrol >/dev/null; then _shm_paths=$( posixshmcontrol ls | cut -f 5 | grep "^$_pdir/" ) for _shm_path in $_shm_paths ; do posixshmcontrol rm "$_shm_path" done fi if [ -x "$_pdir/conf/poststop.sh" ]; then _info "Executing the post-stop script for the pot $_pname" ( # shellcheck disable=SC2086,2046 eval $( pot info -E -p "$_pname" ) "${_pdir}"/conf/poststop.sh ) fi rm -f "${POT_TMP:-/tmp}/pot_pfrules_${_pname}*" rm -f "${POT_TMP:-/tmp}/pot_environment_${_pname}*.sh" return 0 # true } # $1 pot name _js_rm_resolv() { local _pname _jdir _dns _pname="$1" _jdir="${POT_FS_ROOT}/jails/$_pname" if [ -f "$_jdir/m/etc/resolv.conf" ]; then _dns="$(_get_conf_var "$_pname" pot.dns)" if [ "$_dns" != "off" ]; then rm -f "$_jdir/m/etc/resolv.conf" fi fi } pot-stop() { local _pname _ifnames _from_start _pname= _ifnames= _from_start="NO" OPTIND=1 while getopts "hvp:i:s" _o; do case "$_o" in h) stop-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; i) _ifnames="$OPTARG" ;; s) _from_start="YES" ;; ?) stop-help ${EXIT} 1 ;; esac done if [ -z "$_pname" ]; then _pname="$( eval echo \$$OPTIND)" fi if [ -z "$_pname" ]; then _error "A pot name is mandatory" stop-help ${EXIT} 1 fi if ! _is_pot "$_pname" quiet ; then _error "The pot $_pname is not a valid pot" ${EXIT} 0 fi if ! _is_uid0 ; then ${EXIT} 1 fi # Here is where the pot is stopping _epaira_ifs="$(_set_pot_status "$_pname" stopping)" rc=$? if [ $rc -eq 2 ]; then if [ $_from_start = "YES" ]; then _debug "pot $_pname is already stopping, but we are cleaning up from start-cleanup" else _error "pot $_pname is already stopping!" ${EXIT} 1 fi fi if [ $rc -eq 1 ]; then _error "pot $_pname is not in a state where it can be stopped" ${EXIT} 1 fi if [ -z "$_ifnames" ]; then _ifnames="$_epaira_ifs" fi if ! _js_stop "$_pname" "$_from_start" "$_ifnames"; then _error "Stop the pot $_pname failed" ${EXIT} 1 fi _js_rm_resolv "$_pname" _pot_umount "$_pname" _set_pot_status "$_pname" stopped rc=$? if [ $rc -eq 2 ]; then _error "pot $_pname is already stopped!" ${EXIT} 1 fi if [ $rc -eq 1 ]; then _error "pot $_pname is not in a state where it can marked as stopped" ${EXIT} 1 fi } ================================================ FILE: share/pot/term.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : term-help() { cat <<-"EOH" pot term [-hvf] -p potname [pname] pot run [-hv] -p potname [pname] -h print this help -v verbose -f : start the pot if it is not running -p potname : the pot to open terminal in pname : pot to open terminal in if "-p potname" not given EOH } # TODO a configurable shell or a login shell # $1 pot name _term() { local _pname _pname="$1" jexec -l -U root "$_pname" # This would perform a login (poudriere approach) # jexec "$_pname" env -i TERM="$TERM" /usr/bin/login -fp root } pot-term() { local _pname _force _pname= _force= OPTIND=1 while getopts "hvfp:" _o; do case "$_o" in h) term-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; f) _force="YES" ;; p) _pname="$OPTARG" ;; ?) break ;; esac done if [ -z "$_pname" ]; then _pname="$(eval echo \$$OPTIND)" fi if [ -z "$_pname" ]; then _error "A pot name is mandatory" term-help ${EXIT} 1 fi # shellcheck disable=2086 if ! _is_pot_running $_pname ; then if [ "$_force" = "YES" ]; then if ! _is_uid0 ; then ${EXIT} 1 fi pot-cmd start "$_pname" if ! _is_pot_running "$_pname" ; then _error "The pot $_pname doesn't start" ${EXIT} 1 fi else _error "The pot $_pname is not running" ${EXIT} 1 fi fi if ! _is_uid0 ; then ${EXIT} 1 fi _term "$_pname" } ================================================ FILE: share/pot/top.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : top-help() { cat <<-"EOH" pot top [-h] -p pot -h print this help -p pot : the working pot EOH } pot-top() { local _pname _o _pname= OPTIND=1 while getopts "hp:" _o ; do case "$_o" in h) top-help ${EXIT} 0 ;; p) _pname="$OPTARG" ;; *) top-help ${EXIT} 1 esac done if [ -z "$_pname" ]; then _error "A pot name is mandatory" top-help ${EXIT} 1 fi if ! _is_pot "$_pname" ; then _error "pot $_pname is not valid" top-help ${EXIT} 1 fi if ! _is_pot_running "$_pname" ; then _error "pot $_pname is not in execution" top-help ${EXIT} 1 fi top -J "$_pname" } ================================================ FILE: share/pot/update-config.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : update-config-help() { cat <<-"EOH" pot update-config [-h] -p pot|-a -h print this help -v verbose -p pot : the working pot -a : apply to all pots EOH } # $1 pname _get_conf_static_ports() { local _pname _cdir _value _pname="$1" _cdir="${POT_FS_ROOT}/jails/$_pname/conf" _value="$( grep "^pot.export.static.ports=" "$_cdir/pot.conf" | cut -f2 -d'=' )" echo "$_value" } # $1 pname _update_one_pot() { local _pname _conf _attr _value _pname="$1" if ! _is_pot "$_pname" ; then _error "Invalid pot name" return 1 fi _conf="${POT_FS_ROOT}/jails/${_pname}/conf/pot.conf" # default configuration values if [ -z "$(_get_conf_var "$_pname" pot.dns)" ]; then _debug "pot.dns=inherit" echo "pot.dns=inherit" >> "$_conf" fi if [ -z "$(_get_conf_var "$_pname" pot.cmd)" ]; then _debug "pot.cmd=sh /etc/rc" echo "pot.cmd=sh /etc/rc" >> "$_conf" fi # default attributes values if [ -z "$(_get_conf_var "$_pname" "pot.attr.no-rc-script")" ]; then _debug "pot.attr.no-rc-script=NO" echo "pot.attr.no-rc-script=NO" >> "$_conf" fi if [ -z "$(_get_conf_var "$_pname" "pot.attr.persistent")" ]; then _debug "pot.attr.persistent=YES" echo "pot.attr.persistent=YES" >> "$_conf" fi if [ -z "$(_get_conf_var "$_pname" "pot.attr.start-at-boot")" ]; then _debug "pot.attr.start-at-boot=NO" echo "pot.attr.start-at-boot=NO" >> "$_conf" fi if [ -z "$(_get_conf_var "$_pname" "pot.attr.early.start-at-boot")" ]; then _debug "pot.attr.early.start-at-boot=NO" echo "pot.attr.early.start-at-boot=NO" >> "$_conf" fi for _attr in ${_POT_JAIL_RW_ATTRIBUTES} ; do if [ -z "$(_get_conf_var "$_pname" "pot.attr.${_attr}")" ]; then # shellcheck disable=SC1083,2086 eval _value=\"\${_POT_DEFAULT_${_attr}_D}\" _debug "pot.attr.${_attr}=${_value}" echo "pot.attr.${_attr}=${_value}" >> "$_conf" fi done if [ -z "$(_get_conf_var "$_pname" "pot.attr.prunable")" ]; then _debug "pot.attr.prunable=NO" echo "pot.attr.prunable=NO" >> "$_conf" fi if [ -z "$(_get_conf_var "$_pname" "pot.attr.localhost-tunnel")" ]; then _debug "pot.attr.localhost-tunnel=NO" echo "pot.attr.localhost-tunnel=NO" >> "$_conf" fi if [ -z "$(_get_conf_var "$_pname" "pot.attr.no-tmpfs")" ]; then _debug "pot.attr.no-tmpfs=NO" echo "pot.attr.no-tmpfs=NO" >> "$_conf" fi if [ -z "$(_get_conf_var "$_pname" "pot.attr.no-etc-hosts")" ]; then _debug "pot.attr.no-etc-hosts=NO" echo "pot.attr.no-etc-hosts=NO" >> "$_conf" fi # convert pot.export.static.ports=80 to the new format pot.export.ports=80:80 # being aware that pot.export.ports may already exist if [ -n "$(_get_conf_static_ports "$_pname")" ]; then _debug "converting exported static ports using the new format" _static_ports="$( _get_conf_static_ports "$_pname")" ${SED} -i '' -e "/pot.export.static.ports=.*/d" "$_conf" _new_ports= for p in $_static_ports ; do if [ -z "$_new_ports" ]; then _new_ports="$p:$p" else _new_ports="$_new_ports $p:$p" fi done if [ -n "$(_get_pot_export_ports "$_pname")" ]; then _ports="$(_get_pot_export_ports "$_pname")" _new_ports="$_ports $_new_ports" ${SED} -i '' -e "/pot.export.ports=.*/d" "$_conf" fi echo "pot.export.ports=$_new_ports" >> "$_conf" fi # convert ip4 and static entries with the new network_type and ip if [ -n "$(_get_conf_var "$_pname" "ip4")" ]; then _debug "converting the network configuration using the new format" _ip4="$(_get_conf_var "$_pname" "ip4")" _vnet="$(_get_conf_var "$_pname" "vnet")" ${SED} -i '' -e "/ip4=.*/d" "$_conf" if [ "$_ip4" = "inherit" ]; then echo "network_type=inherit" >> "$_conf" else if [ "$_vnet" = "false" ]; then echo "network_type=alias" >> "$_conf" else echo "network_type=public-bridge" >> "$_conf" fi echo "ip=$_ip4" >> "$_conf" fi fi # remove the fixed cpuset rss allocation if [ -n "$(_get_conf_var "$_pname" "pot.rss.cpuset")" ]; then _info "Removing cpuset rss allocation: $(_get_conf_var "$_pname" "pot.rss.cpuset")" _info "rss.cpuset has been deprecated; please use the more generic rss.cpus" ${SED} -i '' -e "/pot.rss.cpuset=.*/d" "$_conf" fi # remove the base pot path from mountpoints in fscomp.conf _update_fscomp "$_pname" } _update_all_pots() { local _pots _pots="$( _get_pot_list )" for _pname in $_pots ; do if ! _update_one_pot "$_pname" ; then return 1 else _debug "Updated $_pname configuration" fi done } pot-update-config() { local _pname _o _all _pname= _all= OPTIND=1 while getopts "hvp:a" _o ; do case "$_o" in h) update-config-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; p) _pname="$OPTARG" ;; a) _all="YES" ;; *) update-config-help ${EXIT} 1 esac done if ! _is_uid0 ; then ${EXIT} 1 fi if [ -n "$_pname" ]; then if ! _update_one_pot "$_pname" ; then ${EXIT} 1 fi elif [ "$_all" = "YES" ]; then if ! _update_all_pots ; then ${EXIT} 1 fi else _error "A pot name or -a are mandatory" update-config-help ${EXIT} 1 fi ${EXIT} 0 } ================================================ FILE: share/pot/version.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : version-help() { cat <<-"EOH" pot version [-hvq] -h print this help -v verbose -q quiet EOH } pot-version() { local _quiet _quiet="NO" OPTIND=1 while getopts "hvq" _o ; do case "$_o" in h) version-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; q) _quiet="YES" ;; ?) version-help ${EXIT} 1 ;; *) ;; esac done if [ "$_quiet" = "YES" ]; then ${ECHO} "${_POT_VERSION}" ${EXIT} 0 fi echo "pot version: $_POT_VERSION" } ================================================ FILE: share/pot/vnet-start.sh ================================================ #!/bin/sh # shellcheck disable=SC3033,SC3040,SC3043 : vnet-start-help() { cat <<-"EOH" pot vnet-start [-hv] [-B bridge-name] -h print this help -v verbose -B bridge-name (optional) EOH } _public_bridge_start() { local _bridge _bridge=$(_pot_bridge) if [ -z "$_bridge" ]; then if _bridge=$(ifconfig bridge create descr "pot public bridge" group "pot") ; then _debug "Bridge created $_bridge" else _error "Bridge not created" fi if ! ifconfig "$_bridge" inet "$POT_GATEWAY" netmask "$POT_NETMASK" ; then _error "Error during bridge configuration ($_bridge)" else _debug "Bridge $_bridge configured with IP $POT_GATEWAY netmask $POT_NETMASK" fi else _debug "Bridge $_bridge already present" fi } # $1 bridge_name _private_bridge_start() { local _bridge_name _bridge _gateway _bridge_net _bridge_name="$1" _bridge=$(_private_bridge "$_bridge_name") if [ -z "$_bridge" ]; then if _bridge=$(ifconfig bridge create descr "pot private bridge" group "pot") ; then _debug "Bridge created $_bridge" else _error "Bridge not created" fi _gateway="$(_get_bridge_var "$_bridge_name" gateway)" _bridge_net="$(_get_bridge_var "$_bridge_name" net)" _bridge_net="${_bridge_net##*/}" if ! ifconfig "$_bridge" inet "${_gateway}/${_bridge_net}" ; then _error "Error during bridge configuration ($_bridge)" else _debug "Bridge $_bridge configured with IP ${_gateway}/${_bridge_net}" fi else _debug "Bridge $_bridge already present" fi } _ipv4_start() { local _bridge_name pf_file _nat_rules _ext_addr _bridge_name="$1" # activate ip forwarding if _is_verbose ; then sysctl net.inet.ip.forwarding=1 else sysctl -qn net.inet.ip.forwarding=1 > /dev/null fi if [ -z "$_bridge_name" ]; then _public_bridge_start elif _is_bridge "$_bridge_name" quiet ; then _private_bridge_start "$_bridge_name" else _error "$_bridge_name is not a valid bridge" return fi # load pf module kldload -n pf pf_file="$(sysrc -n pf_rules)" # check anchors if ! pfctl -s Anchors | grep -q '^[ \t]*pot-nat$' || ! pfctl -s Anchors | grep -q '^[ \t]*pot-rdr$' ; then _debug "Pot anchors are missing - load $pf_file" pfctl -f "$pf_file" fi _nat_rules="${POT_TMP:-/tmp}/pot_pf_nat_rules" if [ -w "$_nat_rules" ]; then rm -f "$_nat_rules" fi if [ -n "$POT_EXTIF_ADDR" ]; then if ! potnet ip4check --host "$POT_EXTIF_ADDR" ; then _info "The value $POT_EXTIF_ADDR [POT_EXTIF_ADDR] is not a valid IPv4 address - ignoring" _ext_addr= elif ! _is_valid_extif_addr "$POT_EXTIF" "$POT_EXTIF_ADDR" ; then _info "The IP address $POT_EXTIF_ADDR [POT_EXTIF_ADDR] is not available on the network interface $POT_EXTIF [POT_EXTIF] " _ext_addr= else _ext_addr=$POT_EXTIF_ADDR fi fi # NAT rules ( echo "ext_if = \"${POT_EXTIF}\"" echo "localnet = \"${POT_NETWORK}\"" if [ -n "$_ext_addr" ]; then echo "ext_addr = \"${_ext_addr}\"" echo "nat on \$ext_if from \$localnet to any -> \$ext_addr" else echo "nat on \$ext_if from \$localnet to any -> (\$ext_if:0)" fi ) > "$_nat_rules" # EXTRA_EXTIF NAT rules if [ -n "$POT_EXTRA_EXTIF" ]; then for extra_netif in $POT_EXTRA_EXTIF ; do eval extra_net="\$POT_NETWORK_$extra_netif" # shellcheck disable=SC2154 if [ -n "$extra_net" ]; then echo "nat on $extra_netif from \$localnet to $extra_net -> ($extra_netif:0)" >> "$_nat_rules" fi done fi # VPN NAT rules if [ -n "$POT_VPN_EXTIF" ] && [ -n "$POT_VPN_NETWORKS" ]; then for net in $POT_VPN_NETWORKS ; do echo "nat on $POT_VPN_EXTIF from \$localnet to $net -> ($POT_VPN_EXTIF:0)" >> "$_nat_rules" done fi pfctl -a pot-nat -f "$_nat_rules" rm -f "$_nat_rules" # load the rules if _is_verbose ; then pfctl -s nat -a pot-nat fi pfctl -e } _ipv6_bridge_start() { local _bridge _bridge=$(_pot_bridge_ipv6) if [ -z "$_bridge" ]; then if _bridge=$(ifconfig bridge create descr "pot ipv6 bridge" group "pot") ; then _debug "Bridge created $_bridge" else _error "Bridge not created" fi if ! ifconfig "$_bridge" inet6 up ; then _error "Error during bridge configuration ($_bridge)" else _debug "Bridge $_bridge inet6 up" fi if ! ifconfig "$_bridge" addm "$POT_EXTIF" ; then _error "Error while adding $POT_EXTIF to the bridge ($_bridge)" else _debug "Bridge $_bridge addm $POT_EXTIF" fi else _debug "Bridge $_bridge already present" fi } _ipv6_start() { _ipv6_bridge_start } pot-vnet-start() { local _bridge_name OPTIND=1 while getopts "hvB:" _o ; do case "$_o" in h) vnet-start-help ${EXIT} 0 ;; v) _POT_VERBOSITY=$(( _POT_VERBOSITY + 1)) ;; B) _bridge_name="$OPTARG" ;; ?) break ;; esac done # Check configuration if [ -z "${POT_NETWORK}" ] || [ -z "${POT_GATEWAY}" ]; then _error "No network or gateway defined" exit 1 fi if [ -z "${POT_EXTIF}" ]; then _error "No external interface defined" exit 1 fi if ! _is_uid0 ; then ${EXIT} 1 fi if ! _is_pot_tmp_dir ; then _error "The POT_TMP directory is not available - aborting" ${EXIT} 1 fi case "$( _get_network_stack )" in ipv4) _ipv4_start "$_bridge_name" ;; dual) _ipv4_start "$_bridge_name" _ipv6_start ;; ipv6) _ipv6_start ;; esac } ================================================ FILE: share/zsh/site-functions/_pot ================================================ #compdef pot : ${POT_FS_ROOT:=$( pot config -qg fs_root )} _pot_pots() { _values "pot pots" ${${(f)"$(${service} ls -qp)"}%% *} } _pot_run_pots() { _values "pot pots" ${${(f)"$(${service} ps -q)"}%% *} } _pot_bases() { _values "pot pots" ${${(f)"$(${service} ls -qb)"}%% *} } _pot_fscomps() { _values "pot flavors" ${${(f)"$(${service} ls -qf)"}%% *} } _pot_bridges() { _values "pot bridges" ${${(f)"$(${service} ls -qB)"}%% *} } _pot_flavours() { _values "pot flavors" ${${(f)"$(${service} ls -qF)"}%% *} } _pot_attributes() { _values "pot attributes" 'start-at-boot' 'early-start-at-boot' 'persistent' 'no-rc-script' 'prunable' 'localhost-tunnel' 'no-tmpfs' 'no-etc-hosts' 'enforce_statfs' 'mount' 'fdescfs' 'linprocfs' 'nullfs' 'procfs' 'tmpfs' 'zfs' 'children' } _pot_network_type() { _values "pot network type" "inherit" "alias" "public-bridge" "private-bridge" "private-bridge" } _pot_network_stack_type() { _values "pot network stack type" "ipv4" "ipv6" "dual" } _pot() { _arguments \ '1: :_pot_cmds' \ '*:: :->args' case $state in args) case $words[1] in init) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' ;; vnet-start) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-B[bridge name]:bridge name:_pot_bridges' ;; config) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-q[Quiet output]' \ '-g[Element name]:config element name:(fs_root zfs_root gateway syslogd pot_prefix fscomp_prefix network_stack)' ;; de-init) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-f[Force stop of all running pots]' ;; version|ps) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-q[Quiet output]' ;; list|ls) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-q[Quiet output]' \ '-p[List pots]' \ '-b[List bases]' \ '-f[List fscomps]' \ '-B[List bridges]' \ '-F[List flavours]' \ '-a[List them all]' ;; info) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-q[Quiet output]' \ '-p[pot name]:pot name:_pot_pots' \ '-B[bridge name]:bridge name:_pot_bridges' \ '-r[Check only if the pos is running]' \ '-s[List only the available snapshots of the pot]' \ '-E[Print few pot information as environment variables]' ;; show) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-q[Quiet output]' \ '-a[All pots]' \ '-r[All running pots]' \ '-p[pot name]:pot name:_pot_pots' ;; create-base) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-r[Release number]:supported releases:_normal' \ '-b[base name]:base name:_normal' ;; create-fscomp) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-f[fscomp name]:fscomp name:_normal' ;; create-private-bridge) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-S[host number]:host number:_normal' \ '-B[bridge name]:bridge name:_normal' ;; create) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-k[keep pot if it fails]' \ '-t[pot type]:pot type:(single multi)' \ '-N[network type]:network type:_pot_network_type' \ '-p[pot name]:pot name:_normal' \ '-P[pot reference]:pot reference name:_pot_pots' \ '-b[base version]:base version:_pot_bases' \ '-l[pot level]:level:(0 1 2)' \ '-t[pot type]:type:(multi single)' \ '*-i[network config]::_normal' \ '-d[dns type]:dns types:(inherit pot off custom:)' \ '-B[bridge name]:bridge name:_pot_bridges' \ '-S[network stack]:network stack:_pot_network_stack_type' \ '*-f[flavour name]:flavour name:_pot_flavours' ;; clone-fscomp) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-f[fscomp name]::_normal' \ '-F[fscomp reference]:fscomp reference name:_pot_fscomps' ;; clone) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-k[keep pot if it fails]' \ '-p[pot name]::_normal' \ '-P[pot reference]:pot reference name:_pot_pots' \ '*-f[flavour name]:flavour name:_pot_flavours' \ '-N[network type]:network type:_pot_network_type' \ '-i[network config]::_normal' \ '-B[bridge name]:bridge name:_pot_bridges' \ '-S[network stack]:network stack:_pot_network_stack_type' \ '-F[force snapshot of the pot reference]' ;; rename) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-n[pot new name]::_normal' \ '-p[pot old name]:pot old name:_pot_pots' ;; destroy) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-q[Quiet output]' \ '-F[Force the pot to stop]' \ '-p[pot name]:pot name:_pot_pots' \ '-b[base name]:base name:_pot_bases' \ '-f[fscomp name]:fscomp name:_pot_fscomps' \ '-B[bridge name]:bridge name:_pot_bridges' \ '-r[Recursive destroying]' ;; prune) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-q[Quiet outpu]' \ '-n[dry-run]' ;; copy-in) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-F[Force with running pots]' \ '-p[pot name]:pot name:_pot_pots' \ '-s[source]:source:_normal' \ '-d[destination]:destination:_normal' ;; copy-out) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-F[Force with running pots]' \ '-p[pot name]:pot name:_pot_pots' \ '-s[source]:source:_normal' \ '-d[destination]:destination:_normal' ;; mount-in) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-m[mount point]:mount point:' \ '-d[directory]:directory:' \ '-z[zfs dataset]:zfs dataset:' \ '-f[fscomp name]:fscomp name:_pot_fscomps' \ '-w[zfs remount]' \ '-r[readonly]' ;; mount-out) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-m[mount point]:mount point:' ;; add-dep) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-P[dependency pot name]:dependency pot name:_pot_pots' ;; set-rss) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-C[Cpuset config]::_normal' \ '-M[Memory size]::_normal' ;; get-rss) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-J[JSON output]' ;; set-cmd) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-c[command]::_normal' ;; set-env) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '*-E[variable list]::_normal' ;; set-hosts) _arguments \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '*-H[hosts entry]::_normal' ;; set-hook) _arguments \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-s[prestart hook]:prestart hook:_normal' \ '-S[poststart hook]:poststart hook:_normal' \ '-t[prestop hook]:prestop hook:_normal' \ '-T[poststop hook]:poststop hook:_normal' ;; set-attr|set-attribute) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-A[attribute]:attribute:_pot_attributes' \ '-V[value]:value:_normal' ;; get-attr|get-attribute) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-A[attribute]:attribute:_pot_attributes' \ '-q[Quiet output]' ;; export-ports) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '*-e[port to be exported]::_normal' ;; snap|snapshot) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-r[replace the oldest snapshot]' \ '-p[pot name]:pot name:_pot_pots' \ '-f[fscomp name]:fscomp name:_pot_fscomps' ;; revert|rollback) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-f[fscomp name]:fscomp name:_pot_fscomps' ;; purge-snapshots) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-f[fscomp name]:fscomp name:_pot_fscomps' \ '-a[all snapshots, instead of the old ones]' ;; update-config) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-a[all pots]' ;; export) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:_pot_pots' \ '-t[tag name]::_normal' \ '-D[target directory]:target directory:_normal' \ '-l[compression level]:compression level:(0 1 2 3 4 5 6 7 8 9)' ;; import) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-p[pot name]:pot name:' \ '-t[tag name]::_normal' \ '-U[URL]:URL:_normal' ;; prepare) _arguments -s \ '-h[Show help]' \ '-v[Verbose output]' \ '-S[auto start]' \ '-p[pot name]:pot name:' \ '-t[tag name]::_normal' \ '-a[allocation id]::_normal' \ '-n[the new pot name]::_normal' \ '-U[URL]:URL:_normal' \ '-N[network type]:network type:(inherit alias public-bridge)' \ '-B[bridge name]:bridge name:_pot_bridges' \ '-i[network config]::_normal' \ '*-e[port to be exported]::_normal' \ '-c[command]::_normal' ;; top) _arguments -s \ '-h[Show help]' \ '-p[pot name]:pot name:_pot_pots' \ ;; stop) _arguments '1:pot name:_pot_run_pots' ;; start|term|run) _arguments '1:pot name:_pot_pots' ;; esac case "$state" in pot_names) _files -/ -W "${POT_FS_ROOT}/jails/" -S' ' ;; fscomp_names) _files -/ -W "${POT_FS_ROOT}/fscomp/" -S' ' ;; base_names) _files -/ -W "${POT_FS_ROOT}/bases/" -S' ' ;; esac esac } _pot_cmds() { local -a commands; commands=( 'help:Show help' 'version:Show version' 'config:Show framework config values' 'top:Run top in pot' 'ls:List elements' 'list:List elements' 'show:Show pot resources' 'info:Show info on pot' 'top:Show processes (top) running in the pot' 'ps:Show running pots' 'init:Init ZFS' 'de-init:Remove all ZFS datasets' 'vnet-start:Start the vnet configuration' 'create-base:Create a new base image' 'create-fscomp:Create a new fs component' 'create-private-bridge:Create a new private bridge' 'create:Create a new pot' 'clone:Clone a pot' 'clone-fscomp:Clone a fs component' 'rename:Rename a pot' 'destroy:Destroy a pot' 'prune:Destroy not running prunable pots' 'copy-in:Copy a file or a directory into a pot' 'mount-in:Mount a directory, a zfs dataset or a fscomp into a pot' 'add-dep:Add a dependency to a pot' 'set-rss:Set a resource constraint to a pot' 'get-rss:Get the current resource usage' 'set-cmd:Set the initial command of a pot' 'set-env:Set environment variables inside a pot' 'set-hosts:Set etc/hosts entries inside a pot' 'set-hook:Set hook scripts for a pot' 'set-attr:Set the value of a pot attribute' 'set-attribute:Set the value of a pot attribute' 'get-attr:Get the value of a pot attribute' 'get-attribute:Get the value of a pot attribute' 'export-ports:export ports of a pot' 'start:Start a pot' 'stop:Stop a pot' 'run:Start a pot and open a shell in it' 'term:Open a shell in a pot' 'snap:Take a snapshot of a pot' 'snapshot:Take a snapshot of a pot' 'revert:Restore the last snapshot of a pot' 'rollback:Restore the last snapshot of a pot' 'purge-snapshots:Remove old or all snapshots' 'export:Export a single-type pot' 'import:Import a single-type pot' 'prepare:Import and prepare a pot - designed for jail orchestrator' 'update-config:Update the configuration of a pot' ) _describe 'command' commands } _pot ================================================ FILE: tests/CI/resolv.conf-dual ================================================ nameserver 1.1.1.1 nameserver 1.0.0.1 nameserver 2606:4700:4700::1111 nameserver 2606:4700:4700::1001 ================================================ FILE: tests/CI/resolv.conf-ipv4 ================================================ nameserver 1.1.1.1 nameserver 1.0.0.1 ================================================ FILE: tests/CI/resolv.conf-ipv6 ================================================ nameserver 2606:4700:4700::1111 nameserver 2606:4700:4700::1001 ================================================ FILE: tests/CI/run.sh ================================================ #!/bin/sh export POT_PATH=$( realpath $( dirname $(realpath $0))/../..) export PATH=$POT_PATH/bin:$PATH timestamp="$(date +%Y%m%d%H%M)" export logfile="pot-ci-${timestamp}" error() { test_name="${1:-unknown}" echo "Test ${test_name} failed ($2)" >> $logfile end exit 1 } begin() { echo "Start pot-ci at $(date)" > $logfile if [ ! -d /var/cache/pot ]; then mkdir -p /var/cache/pot fi if [ ! -d /var/cache/pot ]; then echo "pot's cache cannot be generated - aborting" exit 1 fi } end() { echo "End pot-ci at $(date)" >> $logfile } success() { echo "The test execution was succesfull :+1:" } empty_check() { if [ -n "$(pot ls -q)" ]; then echo "POT LS IS:" pot ls -q ls -al /opt/pot/jails ls -al /opt/pot/jails/* zfs list error "$1" "pot not deleted" fi if [ -n "$(pot ls -qb)" ]; then error "$1" "base not deleted" fi if [ -n "$(pot ls -qf)" ]; then error "$1" "fscomp not deleted" fi if [ -n "$(pot ls -qB)" ]; then error "$1" "bridge not deleted" fi } set_stack() { local s=$1 local conf=$POT_PATH/etc/pot/pot.conf if grep -q ^POT_NETWORK_STACK $conf ; then if [ -L $conf ]; then echo POT_NETWORK_STACK=$s >> $conf else sed -i '' -e "s/POT_NETWORK_STACK=.*$/POT_NETWORK_STACK=$s/" $conf fi else echo POT_NETWORK_STACK=$s >> $conf fi } # $1 type # $2 base_version # $3 network # $4 stack get_pot_name() { t=$1 b=$( echo $2 | tr '.' '_' ) n=$3 s=$4 echo $t-$b-$n-$s-test } # $1 type # $2 base_version # $3 network type # $4 stack create_test() { local name=$( get_pot_name $1 $2 $3 $4 ) local fopt t=$1 b=$2 n=$3 s=$4 f=$5 fopt= if [ "$t" = "multi" ]; then if ! pot create-base -v -r $b ; then error $name create-base fi elif [ "$f" = "slim" ]; then fopt="-f slim" fi case $n in alias) if ! pot create -v -p $name -t $t -b $b -N $n -i fdf2:f389:1f56:164b::1 -i 172.20.135.253 $fopt ; then error $name create fi ;; private-bridge) # create bridge if ! pot create-private-bridge -v -B testprivate -S 5 ; then error $name create-private-bridge fi if [ "$s" = "ipv6" ]; then if pot create -v -p $name -t $t -b $b -N $n -B testprivate $fopt ; then error $name create fi if ! pot destroy -B testprivate ; then error $name destroy-bridge-after-nocreate fi if [ "$t" = "multi" ]; then if ! pot destroy -v -b $b ; then error $name destroy-base-after-nocreate fi fi else if ! pot create -v -p $name -t $t -b $b -N $n -B testprivate -d custom:resolv.conf-ipv4 $fopt ; then error $name create fi fi ;; *) if ! pot create -v -p $name -t $t -b $b -N $n -d custom:resolv.conf-$s $fopt ; then error $name create fi esac } # $1 name # $2 type snap_test() { local name=${1} case $2 in single) snaps=2 ;; multi) snaps=3 ;; esac if ! pot snap -p $name ; then error $name snap fi if [ "$(pot info -v -p $name | grep -A 10 snapshot | grep -Fv snapshot | grep -Fc $name )" -ne $snaps ]; then error $name snap-info fi } # $1 pot name # $2 type export_test() { local name=$1 local type=$2 case $type in single) if ! pot export -p $name -t 0 -l 0; then error $name export-single fi ;; multi) if pot export -p $name -l 0; then error $name export-no-multi fi return ;; esac if ! pot import -p $name -t 0 -U file://. ; then error $name import fi if ! pot destroy -p ${name}_0 ; then error $name import-destroy fi rm -rf *.xz* rm -rf /var/cache/pot/*.xz* } # $1 pot name fscomp_test() { local name=$1 if ! pot create-fscomp -f fscomp ; then error $name create-fscomp fi if ! pot mount-in -p $name -f fscomp -m /media ; then error $name mount-in fi } copy_test() { local name=$1 if ! pot copy-in -p $name -s /etc/protocols -d /root ; then error $name copy-in fi } # $1 pot name _get_ip() { local name=$1 pot info -p $name | grep "ip " | awk '{ print $3 }' } # $1 pot name # $2 network # $3 stack startstop_test() { local name=$1 local n=$2 local s=$3 if [ $s = "ipv6" ] && [ $n = "private-bridge" ]; then if pot start $name ; then error $name no-start fi return 0 fi if ! pot start $name ; then error $name start fi if [ "$4" = "check-copy-in" ]; then if ! jexec $name test -f /root/protocols ; then error $name no-copied-file fi fi # runtime checks if [ "$(pot show | grep -c $name)" -ne 1 ]; then error $name show fi if [ $s = "ipv4" ] || [ $s = "dual" ]; then if [ $n = "public-bridge" ] || [ $n = "private-bridge" ] ; then ip4="$( _get_ip $name )" if ! ping -c 1 $ip4 ; then error $name ping-bridge fi fi # temporary disable ping tests for alias if [ "$n" = "alias" ]; then if ! pot stop $name ; then error $name stop fi return 0 fi # test ICMP if ! jexec $name ping -c 1 1.1.1.1 ; then error $name ping-nat fi if ! jexec $name drill google.com @1.1.1.1 A ; then error $name udp-nat fi if ! jexec $name fetch -4 -o /dev/null http://neverssl.com ; then error $name tcp-nat fi fi if [ $s = "ipv6" ] || [ $s = "dual" ]; then # temporary disable ping tests for alias if [ "$n" = "alias" ]; then if ! pot stop $name ; then error $name stop fi return 0 fi if [ $n != "private-bridge" ]; then if ! jexec $name ping6 -c 1 2606:4700:4700::1111 ; then error $name ping6-ipv6 fi if ! jexec $name drill google.com @2606:4700:4700::1111 AAAA ; then error $name ping6-ipv6 fi if ! jexec $name fetch -6 -o /dev/null http://www.google.com ; then error $name tcp-nat fi fi fi if [ "$name" != "${name%%clone}" ]; then if ! jexec $name /usr/local/sbin/pkg -v ; then error $name flavor on clone fi fi if ! pot stop $name ; then error $name stop fi } # $1 type # $2 base # $3 network # $4 stack destroy_test() { local name=$( get_pot_name $1 $2 $3 $4 ) case $1 in single) if ! pot destroy -p $name ; then error $name destroy fi ;; multi) if pot destroy -b $2 ; then error $name no-destroy-base-$2 fi if ! pot destroy -rb $2 ; then error $name destroy-base-$2 fi ;; esac if ! pot destroy -f fscomp ; then error $name destroy-fscomp fi if [ "$3" = "private-bridge" ]; then if ! pot destroy -B testprivate ; then error $name destroy-bridge fi fi } # $1 type # $2 base # $3 network destroy_corrupted_test() { local name=$( get_pot_name $1 $2 $3 $4 ) case $1 in single) if pot destroy -p $name ; then error $name not-destroy-corrupted fi if ! pot destroy -p $name -F ; then error $name destroy-corrupted fi ;; multi) if pot destroy -p $name ; then error $name not-destroy-corrupted fi if ! pot destroy -p $name -F ; then error $name destroy-corrupted fi if ! pot destroy -rb $2 ; then error $name destroy-base-$2 fi ;; esac if [ "$3" = "private-bridge" ]; then if ! pot destroy -B testprivate ; then error $name destroy-bridge fi fi } # $1 pot name # $2 new name rename_test() { local name=$1 local new_name=$2 if ! pot rename -p $name -n $new_name ; then error $name rename fi if [ "$( pot ls -q | grep -c "^${name}$")" != "0" ]; then error $name rename-not-renamed fi if [ "$( pot ls -q | grep -c "^${new_name}$")" != "1" ]; then error $name rename-no-new-name fi } # $1 pot name # $2 type # $3 base # $4 network destroy_rename_test() { local name=${1} local t=${2} local b=${3} local n=${4} case $t in single) if ! pot destroy -p $name ; then error $name destroy fi ;; multi) if pot destroy -b $b ; then error $name no-destroy-base-$b fi if ! pot destroy -rb $b ; then error $name destroy-base-$b fi ;; esac if ! pot destroy -f fscomp ; then error $name destroy-fscom fi if [ "$n" = "private-bridge" ]; then if ! pot destroy -B testprivate ; then error $name destroy-bridge fi fi } # $1 base pot name # $2 network # $3 stack clone_test() { local name=${1} local cloned_name=${1}-clone local n=${2} local s=${3} flv_dir=$POT_PATH/etc/pot/flavours # add a flavour ( cat << PKG_FLV #!/bin/sh ASSUME_ALWAYS_YES=yes pkg bootstrap PKG_FLV ) > $flv_dir/pkg.sh chmod a+x $flv_dir/pkg.sh if [ "$n" = "private-bridge" ]; then if ! pot clone -p $cloned_name -P $name -f pkg -F -B testprivate ; then error $name clone fi else if ! pot clone -p $cloned_name -P $name -f pkg -F ; then error $name clone fi fi startstop_test $cloned_name $n $s if ! pot destroy -p $cloned_name ; then error $name destroy fi rm $flv_dir/pkg.sh } # $1 type # $2 base_version # $3 network # $4 stack pot_test() { local name=$( get_pot_name $1 $2 $3 $4 ) logger -p local2.info -t pot-CI "pot_test: $name" create_test $1 $2 $3 $4 slim if [ $4 = "ipv6" ] && [ $3 = "private-bridge" ]; then return fi copy_test $name snap_test $name $1 export_test $name $1 fscomp_test $name startstop_test $name $3 $4 check-copy-in local new_name=${name}_new rename_test $name $new_name startstop_test $new_name $3 $4 destroy_rename_test $new_name $1 $2 $3 empty_check $name } # $1 type # $2 base_version # $3 network # $4 stack pot_corrupted_test() { local name=$( get_pot_name $1 $2 $3 $4 ) logger -p local2.info -t pot-CI "pot_corrupted_test: $name" create_test $1 $2 $3 $4 clone_test $name $3 $4 rm -rf /opt/pot/jails/$name/conf destroy_corrupted_test $1 $2 $3 $4 empty_check $name } # $1 type # $2 base_version # $3 network # $4 stack pot_rename_test() { local name=$( get_pot_name $1 $2 $3 $4 ) logger -p local2.info -t pot-CI "pot_rename_test: $name" local new_name=${name}_new create_test $1 $2 $3 $4 rename_test $name $new_name startstop_test $new_name $3 $4 destroy_rename_test $new_name $1 $2 $3 empty_check $name } # $1 type # $2 base_version # $3 network # $4 stack pot_create_fail_test() { local name=$( get_pot_name $1 $2 $3 $4 ) logger -p local2.info -t pot-CI "pot_create_fail_test: $name" local flv_dir if [ "$3" != "inherit" ]; then return 0 fi flv_dir=$POT_PATH/etc/pot/flavours # add a broken flavour ( cat << BROKEN_FLV #!/bin/sh false BROKEN_FLV ) > $flv_dir/broken.sh chmod a+x $flv_dir/broken.sh if [ "$1" = "multi" ]; then if ! pot create-base -v -r $b ; then error $name create-base fi fi if pot create -p -v -p $name -t $1 -b $2 -N $3 -f broken ; then error $name create_fail fi rm $flv_dir/broken.sh if [ "$1" = "multi" ]; then pot destroy -b $2 fi empty_check $name } STACKS="ipv4" if ping6 -c3 www.kame.net; then echo "IPv6 seems to work, add dual and ipv6 stacks" STACKS="$STACKS dual ipv6" else echo "IPv6 not available, only testing $STACKS" fi VERSIONS="12.3 13.1" TYPES="single multi" #NETWORKS="alias inherit public-bridge private-bridge" NETWORKS="inherit public-bridge private-bridge" begin empty_check initial_check pfctl -F all for s in $STACKS ; do set_stack $s for b in $VERSIONS ; do for t in $TYPES ; do for n in $NETWORKS ; do echo "testing $t $b $n $s $(date)" >> $logfile pot_test $t $b $n $s if [ $n = "private-bridge" ] && [ $s = "ipv6" ]; then continue fi pot_corrupted_test $t $b $n $s pot_create_fail_test $t $b $n $s echo "tested $t $b $n $s $(date)" >> $logfile done done done done end success ================================================ FILE: tests/add-dep1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/add-dep.sh # common stubs . common-stub.sh # app specific stubs add-dep-help() { __monitor HELP "$@" } _add_dependency() { __monitor ADDDEP "$@" } test_pot_add_dep_001() { pot-add-dep assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "0" ADDDEP_CALLS setUp pot-add-dep -vb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "0" ADDDEP_CALLS setUp pot-add-dep -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "0" ADDDEP_CALLS setUp pot-add-dep -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "0" ADDDEP_CALLS } test_pot_add_dep_002() { pot-add-dep -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "0" ADDDEP_CALLS setUp pot-add-dep -P test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "0" ADDDEP_CALLS setUp pot-add-dep -P test-pot -p test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "0" ADDDEP_CALLS setUp pot-add-dep -p test-pot -P test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "2" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "0" ADDDEP_CALLS setUp pot-add-dep -P test-pot -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "0" ADDDEP_CALLS } test_pot_add_dep_020() { pot-add-dep -P test-pot -p test-pot-2 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "2" ISPOT_CALLS assertEqualsMon "_add_dependency calls" "1" ADDDEP_CALLS assertEqualsMon "pot name " "test-pot-2" ADDDEP_CALL1_ARG1 assertEqualsMon "run time dependency" "test-pot" ADDDEP_CALL1_ARG2 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/clone-fscomp1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/clone-fscomp.sh # common stubs . common-stub.sh _zfs_dataset_valid() { __monitor ZDSET "$@" if [ "$1" = "/fscomp/test-fscomp" ]; then return 0 # true fi if [ "$1" = "/fscomp/test-fscomp2" ]; then return 0 # true fi return 1 # false } # app specific stubs clone-fscomp-help() { __monitor HELP "$@" } _cf_zfs() { __monitor CFZFS "$@" return 0 # true } test_pot_add_fscomp_001() { pot-clone-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-clone-fscomp -vb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-clone-fscomp -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-clone-fscomp -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_add_fscomp_002() { pot-clone-fscomp -f new-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cf_zfs calls" "0" CFZFS_CALLS setUp pot-clone-fscomp -F test-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cf_zfs calls" "0" CFZFS_CALLS } test_pot_add_fscomp_003() { pot-clone-fscomp -f new-fscomp -F test-no-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "2" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cf_zfs calls" "0" CFZFS_CALLS setUp pot-clone-fscomp -f test-fscomp2 -F test-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "1" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cf_zfs calls" "0" CFZFS_CALLS } test_pot_add_fscomp_020() { pot-clone-fscomp -f new-fscomp -F test-fscomp assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "2" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cf_zfs calls" "1" CFZFS_CALLS assertEqualsMon "_cf_zfs arg1" "new-fscomp" CFZFS_CALL1_ARG1 assertEqualsMon "_cf_zfs arg2" "test-fscomp" CFZFS_CALL1_ARG2 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/clone1.sh ================================================ #!/bin/sh # system utilities stubs potnet() { # no monitor, potnet is called in a subshell if [ "$1" = "next" ]; then if [ "$2" = "-b" ] && [ "$3" = "test-bridge" ]; then echo "10.1.3.4" else echo "10.123.123.123" fi return 0 # true fi if [ "$1" = "validate" ] && [ "$2" = "-H" ] ; then if [ "$4" = "-b" ] && [ "$5" = "test-bridge" ]; then if [ "$3" = "10.1.3.4" ]; then return 0 # true fi fi if [ "$3" = "10.123.123.123" ] || [ "$3" = "10.1.2.4" ]; then return 0 # true fi fi if [ "$1" = "ipcheck" ]; then return 0 # true fi return 1 # false } . pipefail-stub.sh # UUT . ../share/pot/clone.sh # common stubs . common-stub.sh _is_potnet_available() { return 0 # true } _is_vnet_available() { return 0 # true } _get_pot_snaps() { echo 12341234 echo 12345678 } # app specific stubs _cj_zfs() { __monitor CJZFS "$@" } _cj_conf() { __monitor CJCONF "$@" } _exec_flv() { __monitor EXEC_FLV "$@" } clone-help() { __monitor HELP "$@" } test_pot_clone_001() { pot-clone assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-clone -vL assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-clone -L bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-clone -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-clone -S assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_002() { pot-clone -p new-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-clone -P test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_003() { pot-clone -p new-pot -P no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-clone -p test-pot -P test-pot-2 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_004() { # missing -i parameter when needed pot-clone -p new-pot -P test-pot-3 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_006() { # ip address already in use pot-clone -p new-pot -P test-pot-2 -i 10.1.2.3 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_007() { # invalid pot name pot-clone -p new.pot -P test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_020() { pot-clone -p new-pot -P test-pot-0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_021() { pot-clone -p new-pot -P test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "test-pot" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "NO" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_022() { pot-clone -p new-pot-2 -P test-pot-2 -i 10.1.2.4 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg0" "new-pot-2" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg1" "test-pot-2" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot-2" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot-2" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.1.2.4" CJCONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_023() { pot-clone -p new-pot -P test-pot -F assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "test-pot" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "YES" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_024() { pot-clone -p new-pot-2 -P test-pot-2 -i auto assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg0" "new-pot-2" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg1" "test-pot-2" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot-2" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot-2" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.123.123.123" CJCONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_040() { pot-clone -p new-pot-single -P test-pot-single -i auto assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg0" "new-pot-single" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg1" "test-pot-single" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot-single" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot-single" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.123.123.123" CJCONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_041() { pot-clone -p new-pot-single -P test-pot-single -f flop assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg0" "new-pot-single" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg1" "test-pot-single" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot-single" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot-single" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.123.123.123" CJCONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "1" EXEC_FLV_CALLS assertEqualsMon "_exec_flv arg1" "new-pot-single" EXEC_FLV_CALL1_ARG1 assertEqualsMon "_exec_flv arg2" "flop" EXEC_FLV_CALL1_ARG2 } test_pot_clone_041() { pot-clone -p new-pot-single -P test-pot-single -f flip -f flop assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg0" "new-pot-single" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg1" "test-pot-single" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot-single" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot-single" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.123.123.123" CJCONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "2" EXEC_FLV_CALLS assertEqualsMon "_exec_flv arg1" "new-pot-single" EXEC_FLV_CALL1_ARG1 assertEqualsMon "_exec_flv arg2" "flip" EXEC_FLV_CALL1_ARG2 assertEqualsMon "_exec_flv arg1" "new-pot-single" EXEC_FLV_CALL2_ARG1 assertEqualsMon "_exec_flv arg2" "flop" EXEC_FLV_CALL2_ARG2 } test_pot_clone_060() { pot-clone -p new-pot-public -P test-pot-multi-private -N public-bridge assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg0" "new-pot-public" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg1" "test-pot-multi-private" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot-public" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot-multi-private" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.123.123.123" CJCONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_061() { pot-clone -p new-pot-private -P test-pot-multi-private -N private-bridge -B test-bridge assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg0" "new-pot-private" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg1" "test-pot-multi-private" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot-private" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot-multi-private" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "private-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.1.3.4" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "test-bridge" CJCONF_CALL1_ARG5 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_062() { pot-clone -p new-pot-private -P test-pot-3 -N private-bridge -B test-bridge assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg0" "new-pot-private" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg1" "test-pot-3" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot-private" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot-3" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "private-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.1.3.4" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "test-bridge" CJCONF_CALL1_ARG5 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_clone_080() { pot-clone -p new-pot -P test-pot -s 12345678 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "test-pot" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "NO" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "12345678" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "test-pot" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/clone2.sh ================================================ #!/bin/sh # system utilities stubs zfs() { __monitor ZFS "$@" } ECHO=echo_stub echo_stub() { __monitor ECHO "$@" } mkdir() { __monitor MKDIR "$@" /bin/mkdir $@ } date() { __monitor DATE "$@" if [ "$1" = '+%s' ]; then echo "55555" fi } . pipefail-stub.sh # UUT . ../share/pot/clone.sh # common stubs . common-stub.sh . conf-stub.sh _zfs_dataset_valid() { __monitor ZFSDATASETVALID "$@" case "$1" in ${POT_ZFS_ROOT}/jails/test-pot|\ ${POT_ZFS_ROOT}/jails/test-pot/usr.local|\ ${POT_ZFS_ROOT}/jails/test-pot/custom|\ ${POT_ZFS_ROOT}/jails/test-pot-single) return 0 # true ;; esac return 1 # false } _zfs_last_snap() { __monitor ZFSLASTSNAP "$@" case $1 in ${POT_ZFS_ROOT}/bases/11.1/usr.local|\ ${POT_ZFS_ROOT}/bases/11.1/custom) echo 1234 ;; ${POT_ZFS_ROOT}/jails/test-pot/usr.local|\ ${POT_ZFS_ROOT}/jails/test-pot/custom|\ ${POT_ZFS_ROOT}/jails/test-pot-2/custom) echo 4321 ;; ${POT_ZFS_ROOT}/jails/test-pot-single/m|\ ${POT_ZFS_ROOT}/jails/test-pot-single-run/m) echo 6688 ;; esac } _cj_undo_clone() { __monitor UNDO_CLONE "$@" } _update_fscomp() { : } test_cj_zfs_001() { _cj_zfs new-pot test-pot NO assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "3" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "2" MKDIR_CALLS assertEqualsMon "mkdir c1 arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "mkdir c2 arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL2_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL2_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/usr.local" ZFS_CALL2_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot/usr.local@4321" ZFS_CALL2_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/usr.local" ZFS_CALL2_ARG5 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/custom" ZFS_CALL3_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot/custom@4321" ZFS_CALL3_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL3_ARG5 } test_cj_zfs_002() { _cj_zfs new-pot test-pot-2 NO assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "2" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "2" MKDIR_CALLS assertEqualsMon "mkdir c1 arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "mkdir c2 arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL2_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL2_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/custom" ZFS_CALL2_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot-2/custom@4321" ZFS_CALL2_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL2_ARG5 } test_cj_zfs_003() { _cj_zfs new-pot test-pot YES assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "3" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "2" MKDIR_CALLS assertEqualsMon "mkdir c1 arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "mkdir c2 arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL2_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL2_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/usr.local" ZFS_CALL2_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot/usr.local@4321" ZFS_CALL2_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/usr.local" ZFS_CALL2_ARG5 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/custom" ZFS_CALL3_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot/custom@4321" ZFS_CALL3_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL3_ARG5 } test_cj_zfs_004() { _cj_zfs new-pot test-pot-2 YES assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "2" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "2" MKDIR_CALLS assertEqualsMon "mkdir c1 arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "mkdir c2 arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL2_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL2_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/custom" ZFS_CALL2_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot-2/custom@4321" ZFS_CALL2_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL2_ARG5 } test_cj_zfs_005() { _cj_zfs new-pot test-pot-nosnap YES assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "5" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "2" MKDIR_CALLS assertEqualsMon "mkdir c1 arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "mkdir c2 arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL2_ARG2 assertEqualsMon "zfs arg1" "snapshot" ZFS_CALL2_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/test-pot-nosnap/usr.local@55555" ZFS_CALL2_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL3_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/usr.local" ZFS_CALL3_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot-nosnap/usr.local@55555" ZFS_CALL3_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/usr.local" ZFS_CALL3_ARG5 assertEqualsMon "zfs arg1" "snapshot" ZFS_CALL4_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/test-pot-nosnap/custom@55555" ZFS_CALL4_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL5_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/custom" ZFS_CALL5_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot-nosnap/custom@55555" ZFS_CALL5_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL5_ARG5 } test_cj_zfs_020() { _cj_zfs new-pot test-pot-nosnap NO assertNotEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "1" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "undo_clone calls" "1" UNDO_CLONE_CALLS } test_cj_zfs_040() { _cj_zfs new-pot test-pot-single NO assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "2" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL2_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/m" ZFS_CALL2_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot-single/m@6688" ZFS_CALL2_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/m" ZFS_CALL2_ARG5 } test_cj_zfs_041() { _cj_zfs new-pot test-pot-single-run NO assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "2" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL2_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/m" ZFS_CALL2_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot-single-run/m@6688" ZFS_CALL2_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/m" ZFS_CALL2_ARG5 } test_cj_zfs_060() { _cj_zfs new-pot test-pot-single NO 12345678 assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "2" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL2_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/m" ZFS_CALL2_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot-single/m@12345678" ZFS_CALL2_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/m" ZFS_CALL2_ARG5 assertEqualsMon "zfs last snap calls" "0" ZFSLASTSNAP_CALLS } test_cj_zfs_061() { _cj_zfs new-pot test-pot NO 12345678 assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "3" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "2" MKDIR_CALLS assertEqualsMon "mkdir c1 arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "mkdir c2 arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL2_ARG2 assertEqualsMon "zfs arg1" "clone" ZFS_CALL2_ARG1 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/usr.local" ZFS_CALL2_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot/usr.local@12345678" ZFS_CALL2_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/usr.local" ZFS_CALL2_ARG5 assertEqualsMon "zfs arg3" "mountpoint=${POT_FS_ROOT}/jails/new-pot/custom" ZFS_CALL3_ARG3 assertEqualsMon "zfs arg4" "${POT_ZFS_ROOT}/jails/test-pot/custom@12345678" ZFS_CALL3_ARG4 assertEqualsMon "zfs arg5" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL3_ARG5 assertEqualsMon "zfs last snap calls" "0" ZFSLASTSNAP_CALLS } setUp() { common_setUp conf_setUp } tearDown() { common_tearDown conf_tearDown } . shunit/shunit2 ================================================ FILE: tests/common-flv1.sh ================================================ #!/bin/sh # system utilities stubs . monitor.sh # UUT . ../share/pot/common-flv.sh # app specific stubs _get_flavour_cmd_file() { case "$1" in test) echo test ;; testnoscript) echo testnoscript ;; *) ;; esac } _get_flavour_script() { case "$1" in test) echo test.sh ;; testnocmd) echo testnocmd.sh ;; *) ;; esac } test_is_cmd_flavorable_01() { _is_cmd_flavorable assertNotEquals "$?" "0" _is_cmd_flavorable help assertNotEquals "$?" "0" _is_cmd_flavorable help create assertNotEquals "$?" "0" _is_cmd_flavorable create -p help assertNotEquals "$?" "0" _is_cmd_flavorable add-fscomp assertNotEquals "$?" "0" _is_cmd_flavorable add-file assertNotEquals "$?" "0" } test_is_cmd_flavorable_02() { _is_cmd_flavorable add-dep assertEquals "$?" "0" _is_cmd_flavorable add-dep -v -p me -P you assertEquals "$?" "0" _is_cmd_flavorable set-rss assertEquals "$?" "0" _is_cmd_flavorable copy-in assertEquals "$?" "0" _is_cmd_flavorable mount-in assertEquals "$?" "0" } test_is_flavour_001() { assertTrue "_is_flavour test" assertTrue "_is_flavour testnoscript" assertTrue "_is_flavour testnocmd" assertFalse "_is_flavour notest" } setUp() { __mon_init _POT_VERBOSITY=1 } tearDown() { __mon_tearDown } . shunit/shunit2 ================================================ FILE: tests/common-stub.sh ================================================ #!/bin/sh . ../share/pot/common.sh . ../share/pot/common-flv.sh . ../share/pot/network.sh EXIT="return" # common stubs . monitor.sh ##### recognized pots # name running type level ip vnet network_type # test-pot no multi 1 inherit undef inherit # test-pot-2 no multi 2 10.1.2.3 yes public-bridge # test-pot-run yes multi 1 undef undef undef # test-pot-run-2 yes multi 2 undef undef undef # test-pot-0 no multi 0 inherit undef inherit # test-pot-nosnap no multi 1 inherit undef inherit # test-pot-single no single 0 10.1.2.3 yes public-bridge # test-pot-single-run yes single 0 undef yes public-bridge # test-pot-single-2 no single 0 10.1.2.3 yes public-bridge # test-pot-single-0 no single 0 10.1.2.3 yes public-bridge # test-pot-3 no multi 1 10.1.2.3 no alias # test-pot-multi-inherit no multi 1 no inherit # test-pot-multi-private no multi 1 10.1.3.3 yes private-bridge # test-pot-dns-inherit # test-pot-dns-pot # test-pot-dns-custom # test-pot-dns-off ##### recognized bridges # name net gateway # test-bridge 10.1.3.0/28 10.1.3.1 _error() { __monitor ERROR "$@" [ "$ERROR_DEBUG" = "YES" ] && echo "_error: $*" } _info() { __monitor INFO "$@" [ "$INFO_DEBUG" = "YES" ] && echo "_info: $*" } _debug() { __monitor DEBUG "$@" [ "$DEBUG_DEBUG" = "YES" ] && echo "_debug: $*" } _is_verbose() { if [ $_POT_VERBOSITY -gt 1 ]; then return 0 else return 1 fi } _is_uid0() { __monitor ISUID0 "$@" return 0 # true } _is_flavourdir() { __monitor ISFLVDIR "$@" return 0 # true } _is_pot() { __monitor ISPOT "$@" case "$1" in test-pot|test-pot-run|\ test-pot-2|test-pot-run-2|\ test-pot-0|test-pot-nosnap|test-pot-3|\ test-pot-single|test-pot-single-run|test-pot-single-2|test-pot-single-0|\ test-pot-multi-inherit|test-pot-multi-private|\ ${POT_DNS_NAME}) return 0 # true ;; esac return 1 # false } _is_pot_running() { __monitor ISPOTRUN "$@" case "$1" in test-pot-run|test-pot-run-2|\ test-pot-single-run) return 0 # true ;; esac return 1 # false } _is_base() { __monitor ISBASE "$@" case "$1" in test-base|11.1) return 0 # true ;; esac return 1 # false } _is_fscomp() { __monitor ISFSCOMP "$@" case "$1" in test-fscomp) return 0 # true ;; esac return 1 # false } _is_flavour() { case $1 in default|flap|flap2|flip|flop) return 0 # true ;; esac return 1 # false } _get_conf_var() { __monitor GETCONFVAR "$@" case "$2" in "pot.level") case "$1" in test-pot|test-pot-run|test-pot-3|\ test-pot-nosnap|test-pot-multi-inherit|\ test-pot-multi-private) echo "1" ;; test-pot-2|test-pot-run-2) echo "2" ;; test-pot-0|test-pot-single|test-pot-single-run|\ test-pot-single-2|test-pot-single-0) echo "0" ;; esac ;; "pot.potbase") case "$1" in test-pot-2) echo "test-pot" ;; test-pot-run-2) echo "test-pot-run" ;; esac ;; "ip") case $1 in test-pot|test-pot-0) echo "" ;; test-pot-2|test-pot-3|\ test-pot-single|test-pot-single-2|test-pot-single-0) echo "10.1.2.3" ;; test-pot-multi-private) echo "10.1.3.3" ;; esac ;; "network_type") case $1 in test-pot|test-pot-0|\ test-pot-multi-inherit) echo "inherit" ;; test-pot-3) echo "alias" ;; test-pot-2|test-pot-single-run|\ test-pot-single|test-pot-single-2|test-pot-single-0) echo "public-bridge" ;; test-pot-multi-private) echo "private-bridge" ;; esac ;; "pot.type") case $1 in test-pot|test-pot-0|test-pot-3|\ test-pot-run|test-pot-nosnap|\ test-pot-2|test-pot-run-2|\ test-pot-multi-inherit|test-pot-multi-private) echo "multi" ;; test-pot-single|test-pot-single-run|test-pot-single-2|test-pot-single-0) echo "single" esac ;; "vnet") case $1 in test-pot-2|test-pot-single|test-pot-single-run|\ test-pot-multi-private|test-pot-single-2|test-pot-single-0) echo "true" ;; test-pot-3|test-pot-multi-inherit) echo "false" ;; esac ;; "bridge") case $1 in test-pot-multi-private) echo "test-bridge" ;; esac ;; "host.hostname") echo "$1.test-domain" ;; "pot.dns") case $1 in test-pot-dns-inherit) echo "inherit" ;; test-pot-dns-pot) echo "pot" ;; test-pot-dns-custom) echo "custom" ;; test-pot-dns-off) echo "off" ;; esac esac } _get_pot_base() { __monitor GETPOTBASE "$@" case "$1" in test-pot|test-pot-run|\ test-pot-2|test-pot-run-2|\ test-pot-single|test-pot-single-run) echo "11.1" ;; esac } _zfs_exist() { __monitor ZFSEXIST "$@" case "$1" in /fscomp/test-fscomp) return 0 # true ;; esac return 1 # false } _pot_zfs_snap() { __monitor POTZFSSNAP "$@" } _remove_oldest_pot_snap() { __monitor RMVPOTSNAP "$@" } _pot_zfs_snap_full() { __monitor POTZFSSNAPFULL "$@" } _fscomp_zfs_snap() { __monitor FSCOMPZFSSNAP "$@" } _remove_oldest_fscomp_snap() { __monitor RMVFSCOMPSNAP "$@" } _is_valid_release() { case "$1" in 10.1|10.4|11.0|11.1) return 0 # true ;; *) return 1 # false ;; esac } _is_valid_netif() { if [ "$1" = "lagg0" ]; then return 0 # true else return 1 # false fi } _is_bridge() { case "$1" in test-bridge) return 0 # return true ;; esac return 1 # false } _get_bridge_var() { __monitor GETBRIDGEVAR "$@" case "$2" in name) case "$1" in test-bridge) echo "test-bridge" ;; esac ;; net) case "$1" in test-bridge) echo "10.1.3.0/28" ;; esac ;; gateway) case "$1" in test-bridge) echo "10.1.3.1" ;; esac ;; esac } common_setUp() { __mon_init _POT_VERBOSITY=1 POT_DNS_NAME=dns } common_tearDown() { __mon_tearDown } # can be overridden by tests tearDown() { common_tearDown } ================================================ FILE: tests/common-zfs1.sh ================================================ #!/bin/sh # system utilities stubs zfs() { if [ "$2" = "zfs-dataset" ]; then return 0 # true fi if [ "$2" = "-H" ]; then if [ "$5" = "zfs-dataset" ]; then echo "/path/to/mnt" return 0 # true fi fi if [ "$2" = "-o" ]; then case "$5" in zfs-dataset) echo zfs-dataset ;; /path/to/mnt) echo zfs-dataset ;; esac fi return 1 # false } # UUT . ../share/pot/common.sh # app specific stubs test_zfs_exist_001() { _zfs_exist assertNotEquals "0" "$?" _zfs_exist zfs-nodataset assertNotEquals "0" "$?" _zfs_exist zfs-dataset assertNotEquals "0" "$?" } test_zfs_exist_002() { _zfs_exist zfs-nodataset /path/to/mnt assertNotEquals "0" "$?" _zfs_exist zfs-dataset /path/to/chaos assertNotEquals "0" "$?" _zfs_exist zfs-dataset /path/to/mnt assertEquals "0" "$?" } test_zfs_dataset_valid_001() { _zfs_dataset_valid assertNotEquals "0" "$?" _zfs_dataset_valid zfs-nodataset assertNotEquals "0" "$?" _zfs_dataset_valid /path/to/mnt assertNotEquals "0" "$?" } test_zfs_dataset_valid_002() { _zfs_dataset_valid zfs-dataset assertEquals "0" "$?" } . shunit/shunit2 ================================================ FILE: tests/common-zfs2.sh ================================================ #!/bin/sh . monitor.sh # system utilities stubs zfs() { __monitor ZFS "$@" } date() { echo "123454321" } # UUT . ../share/pot/common.sh # app specific stubs test_fscomp_zfs_snap_001() { _fscomp_zfs_snap fscomp_name assertEqualsMon "zfs calls" "1" ZFS_CALLS assertEqualsMon "zfs args" "/zroot/fscomp/fscomp_name@123454321" ZFS_CALL1_ARG2 } test_fscomp_zfs_snap_002() { # the argument "new_snap" is ignored _fscomp_zfs_snap fscomp_name new_snap assertEqualsMon "zfs calls" "1" ZFS_CALLS assertEqualsMon "zfs arg1" "snapshot" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "/zroot/fscomp/fscomp_name@123454321" ZFS_CALL1_ARG2 } setUp() { __mon_init POT_ZFS_ROOT=/zroot } tearDown() { __mon_tearDown } . shunit/shunit2 ================================================ FILE: tests/common1.sh ================================================ #!/bin/sh # system utilities stubs . monitor.sh mount() { cat << EOF-- zroot on /zroot (zfs, local, noatime, nfsv4acls) zroot/ROOT/default on / (zfs, local, noatime, nfsv4acls) devfs on /dev (devfs, local, multilabel) zroot/tmp on /tmp (zfs, local, noatime, nosuid, nfsv4acls) zroot/usr/home on /usr/home (zfs, local, noatime, nfsv4acls) zroot/usr/src on /usr/src (zfs, local, noatime, nfsv4acls) zroot/var/audit on /var/audit (zfs, local, noatime, noexec, nosuid, nfsv4acls) zroot/var/crash on /var/crash (zfs, local, noatime, noexec, nosuid, nfsv4acls) zroot/var/log on /var/log (zfs, local, noatime, noexec, nosuid, nfsv4acls) zroot/var/mail on /var/mail (zfs, local, nfsv4acls) zroot/var/tmp on /var/tmp (zfs, local, noatime, nosuid, nfsv4acls) /opt/pot/fscomp/distfiles on /opt/distfiles (nullfs, local) EOF-- } umount() { __monitor UMOUNT "$@" } fetch() { __monitor FETCH "$@" } jls() { if [ "$1" = "-j" ]; then case "$2" in "pot-test"|\ "pot-test-2") return 0 ## return true esac return 1 fi cat << EOF-- JID IP Address Hostname Path pot-test pot-test.pot-net /opt/pot/jails/pot-test/m pot-test-2 pot-test-2.pot-net /opt/pot/jails/pot-test-2/m EOF-- } sysctl() { if [ -n "$SYSCTL_OUTPUT" ]; then echo $SYSCTL_OUTPUT fi return $SYSCTL_RC } which() { if [ "$1" = potnet ]; then if [ "$WHICH_POTNET_FAIL" = "YES" ]; then return 1 # false else return 0 # true fi fi } # UUT . ../share/pot/common.sh # app specific stubs test_is_verbose() { _is_verbose assertNotEquals "0" "$?" _POT_VERBOSITY=2 _is_verbose assertEquals "0" "$?" } test_is_pot_running() { _is_pot_running assertNotEquals "0" "$?" _is_pot_running pot assertNotEquals "0" "$?" _is_pot_running pot-test assertNotEquals "1" "$?" _is_pot_running pot-test-2 assertNotEquals "1" "$?" } test_is_valid_potname() { _is_valid_potname "test-pot" assertEquals "Refusing valid name" "0" "$?" _is_valid_potname "test.pot" assertNotEquals "Invalid name not detected" "0" "$?" } test_is_in_list() { _is_in_list assertNotEquals "0" "$?" _is_in_list "asdf" assertNotEquals "0" "$?" _is_in_list "asdf" "" assertNotEquals "0" "$?" _is_in_list "asdf" "asdf1 asdf2" assertNotEquals "0" "$?" _is_in_list "val" "val val1 val2" assertEquals "0" "$?" _is_in_list "val" "val1 val val2" assertEquals "0" "$?" _is_in_list "val" "val1 val2 val" assertEquals "0" "$?" _is_in_list "val" "val" assertEquals "0" "$?" _is_in_list "val" "val val" assertEquals "0" "$?" } test_is_mounted() { _is_mounted assertNotEquals "0" "$?" _is_mounted /path/to/the/error assertNotEquals "0" "$?" _is_mounted /path/to/the/error ignored assertNotEquals "0" "$?" _is_mounted zroot/var/log assertNotEquals "0" "$?" _is_mounted /opt/distfiles assertEquals "0" "$?" _is_mounted /opt/distfiles ignored assertEquals "0" "$?" } test_umount() { _umount assertEqualsMon "umount calls1" "0" UMOUNT_CALLS _umount /path/to/the/error assertEqualsMon "umount calls2" "0" UMOUNT_CALLS _umount /opt/distfiles assertEqualsMon "umount calls3" "1" UMOUNT_CALLS assertEqualsMon "umount c1 arg1" "-f" UMOUNT_CALL1_ARG1 assertEqualsMon "umount c1 arg2" "/opt/distfiles" UMOUNT_CALL1_ARG2 } test_is_rctl_available() { _is_rctl_available assertEquals "$?" "0" SYSCTL_OUTPUT="0" _is_rctl_available assertNotEquals "$?" "0" SYSCTL_OUTPUT="" SYSCTL_RC=1 _is_rctl_available assertNotEquals "$?" "0" } test_is_potnet_available() { _is_potnet_available assertEquals "$?" "0" WHICH_POTNET_FAIL="YES" _is_potnet_available assertNotEquals "$?" "0" } test_is_absolute_path() { _is_absolute_path assertEquals "$?" "1" _is_absolute_path "../blah" assertEquals "$?" "1" _is_absolute_path "/blah" assertEquals "$?" "0" } setUp() { __mon_init _POT_VERBOSITY=1 SYSCTL_OUTPUT="1" SYSCTL_RC=0 WHICH_POTNET_FAIL="NO" } tearDown() { __mon_tearDown } . shunit/shunit2 ================================================ FILE: tests/common2.sh ================================================ #!/bin/sh # system utilities stubs if [ "$(uname)" = "Linux" ]; then TEST=/usr/bin/[ else TEST=/bin/[ fi [() { if ${TEST} "$1" = "!" ]; then if ${TEST} "$2" = "-d" ]; then if ${TEST} "$3" = "/jails/pot-test" ]; then return 1 # false elif ${TEST} "$3" = "/jails/pot-test-single" ]; then return 1 # false elif ${TEST} "$3" = "/jails/pot-test-nodset" ]; then return 1 # false elif ${TEST} "$3" = "/jails/pot-test-noconf" ]; then return 1 # false elif ${TEST} "$3" = "/jails/pot-test/m" ]; then return 1 # false elif ${TEST} "$3" = "/jails/pot-test-single/m" ]; then return 1 # false elif ${TEST} "$3" = "/bases/base-test" ]; then return 1 # false elif ${TEST} "$3" = "/bases/base-test-nodset" ]; then return 1 # false elif ${TEST} "$3" = "/fscomp/fscomp-test" ]; then return 1 # false elif ${TEST} "$3" = "/fscomp/fscomp-test-nodset" ]; then return 1 # false else return 0 # true fi fi if ${TEST} "$2" = "-r" ]; then if ${TEST} "$3" = "/jails/pot-test/conf/pot.conf" ]; then return 1 # false elif ${TEST} "$3" = "/jails/pot-test/conf/fscomp.conf" ]; then return 1 # false elif ${TEST} "$3" = "/jails/pot-test-single/conf/pot.conf" ]; then return 1 # false elif ${TEST} "$3" = "/jails/pot-test-single/conf/fscomp.conf" ]; then return 0 # true else return 0 fi fi fi ${TEST} "$@" return $? } # UUT . ../share/pot/common.sh # app specific stubs POT_FS_ROOT= POT_ZFS_ROOT= _error() { : } _zfs_dataset_valid() { if ${TEST} "$1" = "/jails/pot-test" ]; then return 0 # true elif ${TEST} "$1" = "/jails/pot-test-single" ]; then return 0 # true elif ${TEST} "$1" = "/jails/pot-test-noconf" ]; then return 0 # true fi if ${TEST} "$1" = "/bases/base-test" ]; then return 0 fi if ${TEST} "$1" = "/fscomp/fscomp-test" ]; then return 0 fi return 1 # false } _get_pot_type() { if ${TEST} "$1" = "pot-test" ]; then echo "multi" fi if ${TEST} "$1" = "pot-test-single" ]; then echo "single" fi } test_is_pot() { _is_pot assertEquals "1" "$?" _is_pot nopot assertEquals "1" "$?" _is_pot pot-test-nodset assertEquals "2" "$?" _is_pot pot-test-noconf assertEquals "3" "$?" _is_pot pot-test assertEquals "0" "$?" _is_pot pot-test-single assertEquals "0" "$?" } test_is_base() { _is_base assertEquals "1" "$?" _is_base nobase assertEquals "1" "$?" _is_base base-test-nodset assertEquals "2" "$?" _is_base base-test assertEquals "0" "$?" } test_is_fscomp() { _is_fscomp assertEquals "1" "$?" _is_fscomp nofscomp assertEquals "1" "$?" _is_fscomp fscomp-test-nodset assertEquals "2" "$?" _is_fscomp fscomp-test assertEquals "0" "$?" } . shunit/shunit2 ================================================ FILE: tests/common4.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/common.sh # common stubs . ./monitor.sh _qerror() { __monitor QERR $* } _zfs_exist() { if [ "$1" = "zpot" ] && [ "$2" = "/opt" ]; then return 0 # true fi return 1 } _zfs_dataset_valid() { return 0 } # app specific stubs test_is_init_001() { POT_ZFS_ROOT= _is_init quiet assertEquals "1" "$?" } test_is_init_002() { POT_FS_ROOT= _is_init quiet assertEquals "1" "$?" } test_is_init_003() { POT_FS_ROOT=/usr/local/pot _is_init quiet assertEquals "1" "$?" } test_is_init_004() { POT_ZFS_ROOT=zroot _is_init quiet assertEquals "1" "$?" } test_is_init_020() { _is_init quiet assertEquals "0" "$?" } setUp() { __mon_init POT_ZFS_ROOT=zpot POT_FS_ROOT=/opt POT_GROUP="$(id -ng)" } tearDown() { __mon_tearDown } . shunit/shunit2 ================================================ FILE: tests/common5.sh ================================================ #!/bin/sh # system utilities stubs if [ "$(uname)" = "Linux" ]; then TEST=/usr/bin/[ else TEST=/bin/[ fi [() { #echo test: "$@" >&2 if ${TEST} "$1" = "!" ]; then if ${TEST} "$__didfetch" != "1" ]; then # pretend these files don't exist yet return 0 # false fi if ${TEST} "$2" = "-r" ]; then if ${TEST} "$3" = "/tmp/11.1-RELEASE_base.txz" ]; then return 1 # false elif ${TEST} "$3" = "/tmp/12.0-RC3_base.txz" ]; then return 1 # false elif ${TEST} "$3" = "/tmp/12.0-RELEASE_base.txz" ]; then return 1 # false elif ${TEST} "$3" = "/tmp/8.1-RELEASE_base.txz" ]; then return 1 # false elif ${TEST} "$3" = "/tmp/2.1-RELEASE_base.txz" ]; then return 0 # true fi fi elif ${TEST} "$1" = "-r" ]; then if ${TEST} "$2" = "/usr/local/share/freebsd/MANIFESTS/amd64-amd64-11.1-RELEASE" ]; then return 0 # true elif ${TEST} "$2" = "/usr/local/share/freebsd/MANIFESTS/amd64-amd64-12.0-RELEASE" ]; then return 0 # true elif ${TEST} "$2" = "/usr/local/share/freebsd/MANIFESTS/amd64-amd64-12.0-RC3" ]; then return 0 # true elif ${TEST} "$2" = "/usr/local/share/freebsd/MANIFESTS/amd64-amd64-8.1-RELEASE" ]; then return 1 # false elif ${TEST} "$2" = "/usr/local/share/freebsd/MANIFESTS/arm64-aarch64-11.1-RELEASE" ]; then return 0 # true elif ${TEST} "$2" = "/usr/local/share/freebsd/MANIFESTS/arm64-aarch64-12.0-RELEASE" ]; then return 0 # true elif ${TEST} "$2" = "/usr/local/share/freebsd/MANIFESTS/arm64-aarch64-12.0-RC3" ]; then return 0 # true elif ${TEST} "$2" = "/usr/local/share/freebsd/MANIFESTS/arm64-aarch64-8.1-RELEASE" ]; then return 1 # false fi fi ${TEST} "$@" return $? } fetch() { __didfetch="1" #echo fetch: "$@" >&2 __monitor FETCH "$@" } sha256() { if [ "$__arch" = "amd64" ]; then if [ "$2" = /tmp/11.1-RELEASE_base.txz ]; then echo "0123456789abcdef" elif [ "$2" = /tmp/12.0-RELEASE_base.txz ]; then echo "fedcba9876543210" elif [ "$2" = /tmp/12.0-RC3_base.txz ]; then echo "aaaaaaaaaaaaaaaa" else echo "" fi else if [ "$2" = /tmp/11.1-RELEASE_base.txz ]; then echo "other0123456789abcdef" elif [ "$2" = /tmp/12.0-RELEASE_base.txz ]; then echo "otherfedcba9876543210" elif [ "$2" = /tmp/12.0-RC3_base.txz ]; then echo "otheraaaaaaaaaaaaaaaa" else echo "" fi fi } sysctl() { if [ "$2" = "hw.machine_arch" ]; then echo "$__arch" elif [ "$2" = "hw.machine" ]; then echo "$__machine" else return 1 # failure fi } cat() { if [ "$1" = "/usr/local/share/freebsd/MANIFESTS/amd64-amd64-12.0-RELEASE" ]; then echo "base.txz 0123456789abcdef" elif [ "$1" = "/usr/local/share/freebsd/MANIFESTS/amd64-amd64-11.1-RELEASE" ]; then echo "base.txz 0123456789abcdef" elif [ "$1" = "/usr/local/share/freebsd/MANIFESTS/amd64-amd64-12.0-RC3" ]; then echo "base.txz aaaaaaaaaaaaaaaa" elif [ "$1" = "/usr/local/share/freebsd/MANIFESTS/arm64-aarch64-12.0-RELEASE" ]; then echo "base.txz other0123456789abcdef" elif [ "$1" = "/usr/local/share/freebsd/MANIFESTS/arm64-aarch64-11.1-RELEASE" ]; then echo "base.txz other0123456789abcdef" elif [ "$1" = "/usr/local/share/freebsd/MANIFESTS/arm64-aarch64-12.0-RC3" ]; then echo "base.txz otheraaaaaaaaaaaaaaaa" else /bin/cat "$@" fi } rm() { __monitor RM "$@" } # UUT . ../share/pot/create-base.sh # common stubs . common-stub.sh test_fetch_freebsd_001() { # not downloaded _fetch_freebsd 2.1 assertEquals "return code" "1" "$?" assertEqualsMon "fetch calls" "2" FETCH_CALLS assertEqualsMon "fetch arg4" "/tmp/2.1-RELEASE_base.txz" FETCH_CALL1_ARG4 assertEqualsMon "error calls" "0" ERROR_CALLS } test_fetch_freebsd_002() { # No Manifest file _fetch_freebsd 8.1 assertEquals "return code" "1" "$?" assertEqualsMon "fetch calls" "0" FETCH_CALLS assertEqualsMon "error calls" "2" ERROR_CALLS } test_fetch_freebsd_003() { # Wrong sha _fetch_freebsd 12.0 assertEquals "return code" "1" "$?" assertEqualsMon "fetch calls" "0" FETCH_CALLS assertEqualsMon "error calls" "2" ERROR_CALLS } test_fetch_freebsd_004() { # Everything fine _fetch_freebsd 11.1 assertEquals "return code" "0" "$?" assertEqualsMon "fetch calls" "0" FETCH_CALLS assertEqualsMon "error calls" "0" ERROR_CALLS } test_fetch_freebsd_005() { # Everything fine _fetch_freebsd 12.0-RC3 assertEquals "return code" "0" "$?" assertEqualsMon "fetch calls" "0" FETCH_CALLS assertEqualsMon "error calls" "0" ERROR_CALLS } test_fetch_freebsd_006() { # Need fetch first __didfetch="0" _fetch_freebsd 12.0-RC3 assertEquals "return code" "0" "$?" assertEqualsMon "fetch calls" "1" FETCH_CALLS assertEqualsMon "fetch arg1" "-m" FETCH_CALL1_ARG1 assertEqualsMon "fetch arg2" "https://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/12.0-RC3/base.txz" FETCH_CALL1_ARG2 assertEqualsMon "fetch arg3" "-o" FETCH_CALL1_ARG3 assertEqualsMon "fetch arg4" "/tmp/12.0-RC3_base.txz" FETCH_CALL1_ARG4 assertEqualsMon "error calls" "0" ERROR_CALLS } test_fetch_freebsd_007() { # Need fetch first __machine="arm64" __arch="aarch64" __didfetch="0" _fetch_freebsd 12.0-RC3 assertEquals "return code" "0" "$?" assertEqualsMon "fetch calls" "1" FETCH_CALLS assertEqualsMon "fetch arg2" "https://ftp.freebsd.org/pub/FreeBSD/releases/arm64/aarch64/12.0-RC3/base.txz" FETCH_CALL1_ARG2 assertEqualsMon "error calls" "0" ERROR_CALLS } setUp() { __machine="amd64" # default to amd64 __arch="amd64" __didfetch="1" common_setUp POT_CACHE="/tmp" } . shunit/shunit2 ================================================ FILE: tests/common6.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/common.sh # common stubs . conf-stub.sh test_get_conf_vnet_001() { rc=$(_get_conf_var test-pot-vnet-ip4 vnet ) assertEquals "vnet value" "true" "$rc" } test_is_pot_vnet() { _is_pot_vnet test-pot-vnet-ip4 rc=$? assertEquals "is_pot_vnet" "0" "$rc" } setUp() { conf_setUp } tearDown() { conf_tearDown } . shunit/shunit2 ================================================ FILE: tests/common7.sh ================================================ #!/bin/sh # system utilities stubs find() { cat << MANIFEST-EOF /usr/local/share/freebsd/MANIFESTS/amd64-amd64-12.0-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-10.0-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-10.4-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-11.0-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-9.1-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-9.0-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-10.1-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-11.1-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-9.2-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-10.3-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-11.2-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-10.2-RELEASE /usr/local/share/freebsd/MANIFESTS/amd64-amd64-9.3-RELEASE MANIFEST-EOF } sysctl() { if [ "$2" = "hw.machine_arch" ]; then echo "$__arch" elif [ "$2" = "hw.machine" ]; then echo "$__machine" else return 1 # failure fi } hostname() { echo "test-host" } # UUT . ../share/pot/common.sh # common stubs . ./monitor.sh # app specific stubs test_get_arch_001() { result="$(_get_arch)" assertEquals "amd64-amd64" "$result" __machine="i386" __arch="i386" result="$(_get_arch)" assertEquals "i386-i386" "$result" __machine="arm64" __arch="aarch64" result="$(_get_arch)" assertEquals "arm64-aarch64" "$result" } test_get_valid_releases_001() { result="$( _get_valid_releases )" assertEquals "9.0 9.1 9.2 9.3 10.0 10.1 10.2 10.3 10.4 11.0 11.1 11.2 12.0 " "$result" } test_is_valid_release_001() { # valid release _is_valid_release 11.0 assertEquals "0" "$?" } test_is_valid_release_002() { # invalid release _is_valid_release 10.8 assertEquals "1" "$?" # invalid call _is_valid_release assertEquals "1" "$?" } test_get_usable_hostname_001() { result="$( _get_usable_hostname pot-short-name )" assertEquals "pot-short-name.test-host" "$result" } test_get_usable_hostname_002() { result="$( _get_usable_hostname pot-long-name-01234567890123456789012345678901234567890123456789 )" assertEquals "pot-long-name-01234567890123456789012345678901234567890123456789" "$result" } test_get_usable_hostname_003() { result="$( _get_usable_hostname pot-long-name-012345678901234567890123456789012345678901234567890123456789 )" assertEquals "pot-long-name-01234567890123456789012345678901234567890123456789" "$result" } test_get_usable_hostname_004() { export POT_HOSTNAME_MAX_LENGTH=62 result="$( _get_usable_hostname pot-long-name-012345678901234567890123456789012345678901234567890123456789 )" assertEquals "pot-long-name-012345678901234567890123456789012345678901234567" "$result" } setUp() { __mon_init __machine="amd64" __arch="amd64" } tearDown() { __mon_tearDown } . shunit/shunit2 ================================================ FILE: tests/common8.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/common.sh test_is_natural_number_001() { _is_natural_number 123 assertTrue "number is not a number" "$?" } test_contains_spaces_001() { _contains_spaces "no-spaces" assertFalse "found spaces in a string with no spaces" "$?" } test_contains_spaces_002() { _contains_spaces "with spaces" assertTrue "not found spaces in a string with spaces" "$?" _contains_spaces "/mnt/with space" assertTrue "not found spaces in a string with spaces" "$?" _contains_spaces "/mnt/space " assertTrue "not found spaces in a string with spaces" "$?" } . shunit/shunit2 ================================================ FILE: tests/conf-stub.sh ================================================ #!/bin/sh conf_setUp() { POT_FS_ROOT=/tmp POT_ZFS_ROOT=zpot /bin/mkdir -p /tmp/jails/test-pot/conf { echo "zpot/bases/11.1 /tmp/jails/test-pot/m ro" echo "zpot/jails/test-pot/usr.local /tmp/jails/test-pot/m/usr/local zfs-remount" echo "zpot/jails/test-pot/custom /tmp/jails/test-pot/m/opt/custom zfs-remount" } > /tmp/jails/test-pot/conf/fscomp.conf { echo "host.hostname=\"test-pot.test\"" echo "pot.potbase=" } > /tmp/jails/test-pot/conf/pot.conf /bin/mkdir -p /tmp/jails/test-pot-2/conf { echo "zpot/bases/11.1 /tmp/jails/test-pot-2/m ro" echo "zpot/jails/test-pot/usr.local /tmp/jails/test-pot-2/m/usr/local ro" echo "zpot/jails/test-pot-2/custom /tmp/jails/test-pot-2/m/opt/custom zfs-remount" } > /tmp/jails/test-pot-2/conf/fscomp.conf { echo "host.hostname=\"test-pot-2.test\"" echo "pot.potbase=test-pot" } > /tmp/jails/test-pot-2/conf/pot.conf /bin/mkdir -p /tmp/jails/test-pot-nosnap/conf { echo "zpot/bases/11.1 /tmp/jails/test-pot-nosnap/m ro" echo "zpot/jails/test-pot-nosnap/usr.local /tmp/jails/test-pot-nosnap/m/usr/local zfs-remount" echo "zpot/jails/test-pot-nosnap/custom /tmp/jails/test-pot-nosnap/m/opt/custom zfs-remount" } > /tmp/jails/test-pot-nosnap/conf/fscomp.conf { echo "host.hostname=\"test-pot-nosnap.test\"" echo "pot.potbase=" echo "pot.depend=test-pot" } > /tmp/jails/test-pot-nosnap/conf/pot.conf /bin/mkdir -p /tmp/jails/test-pot-single/conf touch /tmp/jails/test-pot-single/conf/fscomp.conf { echo "host.hostname=\"test-pot-single.test\"" echo "pot.potbase=" } > /tmp/jails/test-pot-single/conf/pot.conf /bin/mkdir -p /tmp/jails/test-pot-single-run/conf { echo "zpot/fscomp/examples /tmp/jails/test-pot-single-run/m/tmp/examples ro" } > /tmp/jails/test-pot-single-run/conf/fscomp.conf { echo "host.hostname=\"test-pot-single-run.test\"" echo "pot.potbase=" } > /tmp/jails/test-pot-single-run/conf/pot.conf /bin/mkdir -p /tmp/jails/test-pot-vnet-ip4/conf touch /tmp/jails/test-pot-vnet-ip4/conf/fscomp.conf { echo "pot.level=0" echo "pot.type=single" echo "pot.base=12.0" echo "pot.potbase=" echo "pot.dns=inherit" echo "pot.cmd=sh /etc/rc" echo "host.hostname=\"test-pot-vnet-ip4.test\"" echo "0" echo "osrelease=\"12.0-RELEASE\"" echo "ip=10.192.0.3" echo "network_type=public-network" echo "vnet=true" echo "pot.export.ports=80 443" } > /tmp/jails/test-pot-vnet-ip4/conf/pot.conf } conf_tearDown() { rm -rf /tmp/jails } ================================================ FILE: tests/config1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/config.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs config-help() { __monitor HELP "$@" } _config_echo() { __monitor CONFECHO "$@" } test_pot_config_001() { pot-config assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "config_echo calls" "0" CONFECHO_CALLS setUp pot-config -k bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "config_echo calls" "0" CONFECHO_CALLS setUp pot-config -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "config_echo calls" "0" CONFECHO_CALLS } test_pot_config_002() { pot-config -q assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "config_echo calls" "0" CONFECHO_CALLS } test_pot_config_010() { pot-config -g noname assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "config_echo calls" "0" CONFECHO_CALLS } test_pot_config_020() { pot-config -g gateway assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "config_echo calls" "1" CONFECHO_CALLS assertEqualsMon "config_echo arg" "NO" CONFECHO_CALL1_ARG1 assertEqualsMon "config_echo arg" "gateway" CONFECHO_CALL1_ARG2 assertEqualsMon "config_echo arg" "10.1.2.3" CONFECHO_CALL1_ARG3 } setUp() { common_setUp POT_GATEWAY="10.1.2.3" } . shunit/shunit2 ================================================ FILE: tests/copy-in1.sh ================================================ #!/bin/sh # system utilities stubs if [ "$(uname)" = "Linux" ]; then TEST=/usr/bin/[ else TEST=/bin/[ fi [() { if ${TEST} "$1" = "-f" ]; then if ${TEST} "$2" = "test-file" ]; then return 0 # false fi fi ${TEST} "$@" return $? } jexec() { __monitor JEXEC "$@" } jail() { __monitor JAIL "$@" } mktemp() { __monitor MKTEMP "$@" echo /tmp/copy-in.asdf } umount() { __monitor UMOUNT "$@" } rmdir() { __monitor RMDIR "$@" } # UUT . ../share/pot/copy-in.sh # common stubs . common-stub.sh # app specific stubs copy-in-help() { __monitor HELP "$@" return 0 # true } _source_validation() { __monitor SRCVALID "$@" if [ "$1" = "test-file" ]; then return 0 # true elif [ "$1" = "test-dir" ]; then return 0 # true fi return 1 # false } _mount_source_into_potroot() { return 0 # true } _pot_mount() { __monitor PMOUNT "$@" } _pot_umount() { __monitor PUMOUNT "$@" } test_pot_copy_in_001() { pot-copy-in assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-copy-in -vb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-copy-in -b bb assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-copy-in -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS } test_pot_copy_in_002() { pot-copy-in -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-in -s test-file assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-in -d test-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-in -p test-pot -s test-file assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-in -d test-mnt -s test-file assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-in -d test-mnt -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS } test_pot_copy_in_003() { pot-copy-in -p test-no-pot -s test-no-file -d /test-no-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS } test_pot_copy_in_004() { pot-copy-in -p test-no-pot -s test-file -d /test-no-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_copy_in_005() { pot-copy-in -p test-pot -s test-no-file -d /test-no-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_source_validation calls" "1" SRCVALID_CALLS } test_pot_copy_in_006() { pot-copy-in -p test-pot-run -s test-file -d /test-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_source_validation calls" "1" SRCVALID_CALLS assertEqualsMon "_pot_mount calls" "0" PMOUNT_CALLS assertEqualsMon "_jexec calls" "0" JEXEC_CALLS assertEqualsMon "_jail calls" "0" JAIL_CALLS } test_pot_copy_in_020() { pot-copy-in -p test-pot -s test-file -d /test-mnt assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_source_validation calls" "1" SRCVALID_CALLS assertEqualsMon "_pot_mount calls" "1" PMOUNT_CALLS assertEqualsMon "_jexec calls" "0" JEXEC_CALLS assertEqualsMon "_jail calls" "1" JAIL_CALLS assertEqualsMon "_jail args" "-c" JAIL_CALL1_ARG1 assertEqualsMon "_jail args" "/tmp/copy-in.asdf/test-file" JAIL_CALL1_ARG5 assertEqualsMon "_jail args" "/test-mnt" JAIL_CALL1_ARG6 assertEqualsMon "_pot_umount calls" "1" PUMOUNT_CALLS assertEqualsMon "_rmdir calls" "0" RMDIR_CALLS } test_pot_copy_in_021() { pot-copy-in -p test-pot-run -s test-file -d /test-mnt -F assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_source_validation calls" "1" SRCVALID_CALLS assertEqualsMon "_pot_mount calls" "0" PMOUNT_CALLS assertEqualsMon "_jexec calls" "1" JEXEC_CALLS assertEqualsMon "_jexec args" "test-pot-run" JEXEC_CALL1_ARG1 assertEqualsMon "_jexec args" "-a" JEXEC_CALL1_ARG3 assertEqualsMon "_jexec args" "/tmp/copy-in.asdf/test-file" JEXEC_CALL1_ARG4 assertEqualsMon "_jexec args" "/test-mnt" JEXEC_CALL1_ARG5 assertEqualsMon "_jail calls" "0" JAIL_CALLS assertEqualsMon "_pot_umount calls" "0" PUMOUNT_CALLS assertEqualsMon "_rmdir calls" "1" RMDIR_CALLS } test_pot_copy_in_022() { pot-copy-in -p test-pot-run -s test-file -d /test-mnt -vF assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_source_validation calls" "1" SRCVALID_CALLS assertEqualsMon "_pot_mount calls" "0" PMOUNT_CALLS assertEqualsMon "_jexec calls" "1" JEXEC_CALLS assertEqualsMon "_jexec args" "test-pot-run" JEXEC_CALL1_ARG1 assertEqualsMon "_jexec args" "-va" JEXEC_CALL1_ARG3 assertEqualsMon "_jexec args" "/tmp/copy-in.asdf/test-file" JEXEC_CALL1_ARG4 assertEqualsMon "_jexec args" "/test-mnt" JEXEC_CALL1_ARG5 assertEqualsMon "_jail calls" "0" JAIL_CALLS assertEqualsMon "_pot_umount calls" "0" PUMOUNT_CALLS assertEqualsMon "_rmdir calls" "1" RMDIR_CALLS } test_pot_copy_in_023() { pot-copy-in -p test-pot -s test-dir -d /test-mnt -v assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_source_validation calls" "1" SRCVALID_CALLS assertEqualsMon "_pot_mount calls" "1" PMOUNT_CALLS assertEqualsMon "_jexec calls" "0" JEXEC_CALLS assertEqualsMon "_jail calls" "1" JAIL_CALLS assertEqualsMon "_jail args" "-c" JAIL_CALL1_ARG1 assertEqualsMon "_jail args" "/tmp/copy-in.asdf" JAIL_CALL1_ARG5 assertEqualsMon "_jail args" "/test-mnt" JAIL_CALL1_ARG6 assertEqualsMon "_pot_umount calls" "1" PUMOUNT_CALLS assertEqualsMon "_rmdir calls" "0" RMDIR_CALLS } setUp() { common_setUp ERROR_DEBUG="NO" DEBUG_DEBUG="NO" POT_FS_ROOT=/tmp POT_ZFS_ROOT=zpot } . shunit/shunit2 ================================================ FILE: tests/copy-out1.sh ================================================ #!/bin/sh # system utilities stubs if [ "$(uname)" = "Linux" ]; then TEST=/usr/bin/[ else TEST=/bin/[ fi [() { if ${TEST} "$1" = "-f" ]; then if ${TEST} "$2" = "test-file" ]; then return 0 # false fi fi ${TEST} "$@" return $? } jexec() { __monitor JEXEC "$@" } jail() { __monitor JAIL "$@" } mktemp() { __monitor MKTEMP "$@" echo /tmp/copy-out.asdf } rmdir() { __monitor RMDIR "$@" } umount() { __monitor UMOUNT "$@" } # UUT . ../share/pot/copy-out.sh # common stubs . common-stub.sh # app specific stubs copy-out-help() { __monitor HELP "$@" return 0 # true } _destination_validation() { __monitor DSTVALID "$@" if [ "$1" = "test-mnt" ]; then return 0 # true fi return 1 # false } _mount_destination_into_potroot() { return 0 # true } _pot_mount() { __monitor PMOUNT "$@" } _pot_umount() { __monitor PUMOUNT "$@" } test_pot_copy_out_001() { pot-copy-out assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-copy-out -vb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-copy-out -b bb assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-copy-out -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS } test_pot_copy_out_002() { pot-copy-out -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-out -s test-file assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-out -d test-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-out -p test-pot -s test-file assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-out -d test-mnt -s test-file assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS setUp pot-copy-out -d test-mnt -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS } test_pot_copy_out_003() { pot-copy-out -p test-no-pot -s /test-no-file -d test-no-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS } test_pot_copy_out_004() { pot-copy-out -p test-no-pot -s /test-file -d test-no-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_copy_out_005() { pot-copy-out -p test-pot -s /test-no-file -d test-no-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_destination_validation calls" "1" DSTVALID_CALLS } test_pot_copy_out_006() { pot-copy-out -p test-pot-run -s /test-file -d test-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_destination_validation calls" "1" DSTVALID_CALLS assertEqualsMon "_pot_mount calls" "0" PMOUNT_CALLS assertEqualsMon "_jexec calls" "0" JEXEC_CALLS assertEqualsMon "_jail calls" "0" JAIL_CALLS } test_pot_copy_out_020() { pot-copy-out -p test-pot -s /test-file -d test-mnt assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_destination_validation calls" "1" DSTVALID_CALLS assertEqualsMon "_pot_mount calls" "1" PMOUNT_CALLS assertEqualsMon "_jexec calls" "0" JEXEC_CALLS assertEqualsMon "_jail calls" "1" JAIL_CALLS assertEqualsMon "_jail args" "-c" JAIL_CALL1_ARG1 assertEqualsMon "_jail args" "/test-file" JAIL_CALL1_ARG5 assertEqualsMon "_jail args" "/tmp/copy-out.asdf" JAIL_CALL1_ARG6 assertEqualsMon "_pot_umount calls" "1" PUMOUNT_CALLS assertEqualsMon "_rmdir calls" "0" RMDIR_CALLS } test_pot_copy_out_021() { pot-copy-out -p test-pot-run -s /test-file -d test-mnt -F assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_destination_validation calls" "1" DSTVALID_CALLS assertEqualsMon "_pot_mount calls" "0" PMOUNT_CALLS assertEqualsMon "_jexec calls" "1" JEXEC_CALLS assertEqualsMon "_jexec args" "test-pot-run" JEXEC_CALL1_ARG1 assertEqualsMon "_jexec args" "-a" JEXEC_CALL1_ARG3 assertEqualsMon "_jexec args" "/test-file" JEXEC_CALL1_ARG4 assertEqualsMon "_jexec args" "/tmp/copy-out.asdf" JEXEC_CALL1_ARG5 assertEqualsMon "_jail calls" "0" JAIL_CALLS assertEqualsMon "_pot_umount calls" "0" PUMOUNT_CALLS assertEqualsMon "_rmdir calls" "1" RMDIR_CALLS } test_pot_copy_out_022() { pot-copy-out -p test-pot-run -s /test-file -d test-mnt -vF assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_destination_validation calls" "1" DSTVALID_CALLS assertEqualsMon "_pot_mount calls" "0" PMOUNT_CALLS assertEqualsMon "_jexec calls" "1" JEXEC_CALLS assertEqualsMon "_jexec args" "test-pot-run" JEXEC_CALL1_ARG1 assertEqualsMon "_jexec args" "-va" JEXEC_CALL1_ARG3 assertEqualsMon "_jexec args" "/test-file" JEXEC_CALL1_ARG4 assertEqualsMon "_jexec args" "/tmp/copy-out.asdf" JEXEC_CALL1_ARG5 assertEqualsMon "_jail calls" "0" JAIL_CALLS assertEqualsMon "_pot_umount calls" "0" PUMOUNT_CALLS assertEqualsMon "_rmdir calls" "1" RMDIR_CALLS } test_pot_copy_out_023() { pot-copy-out -p test-pot -s /test-dir -d test-mnt -v assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_destination_validation calls" "1" DSTVALID_CALLS assertEqualsMon "_pot_mount calls" "1" PMOUNT_CALLS assertEqualsMon "_jexec calls" "0" JEXEC_CALLS assertEqualsMon "_jail calls" "1" JAIL_CALLS assertEqualsMon "_jail args" "-c" JAIL_CALL1_ARG1 assertEqualsMon "_jail args" "/test-dir" JAIL_CALL1_ARG5 assertEqualsMon "_jail args" "/tmp/copy-out.asdf" JAIL_CALL1_ARG6 assertEqualsMon "_pot_umount calls" "1" PUMOUNT_CALLS assertEqualsMon "_rmdir calls" "0" RMDIR_CALLS } setUp() { common_setUp ERROR_DEBUG="NO" DEBUG_DEBUG="NO" POT_FS_ROOT=/tmp POT_ZFS_ROOT=zpot } . shunit/shunit2 ================================================ FILE: tests/create-base1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/create-base.sh # common stubs . common-stub.sh _is_init() { __monitor ISINIT "$@" } # app specific stubs create-base-help() { __monitor HELP "$@" } _fetch_freebsd() { __monitor FETCHBSD "$@" if [ "$1" = "10.1" ]; then return 1 # false fi } _cb_zfs() { __monitor CBZFS "$@" if [ "$1" = "11.0" ]; then return 1 # false fi } _cb_tar_dir() { __monitor CBTAR "$@" } _cb_base_pot() { __monitor CBPOT "$@" } test_base_create_base_001() { pot-create-base assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_fetch calls" "0" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS setUp pot-create-base -vL assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_fetch calls" "0" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS setUp pot-create-base -L bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_fetch calls" "0" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS setUp pot-create-base -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_fetch calls" "0" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS } test_base_create_base_002() { pot-create-base -r 1234 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_fetch calls" "0" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS } test_base_create_base_003() { pot-create-base -b 104x64 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_fetch calls" "0" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS } test_base_create_base_004() { # base name is invalid pot-create-base -r 11.1 -b 10.4 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_fetch calls" "0" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS } test_base_create_base_010() { # simulate fetch issue pot-create-base -r 10.1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_fetch calls" "1" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS } test_base_create_base_011() { # simulate zfs issue pot-create-base -r 11.0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_fetch calls" "1" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "1" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS } test_base_create_base_012() { pot-create-base -r 11.1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_fetch calls" "0" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS } test_base_create_base_013() { pot-create-base -r 11.1 -b test-base assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_fetch calls" "0" FETCHBSD_CALLS assertEqualsMon "_cb_zfs calls" "0" CBZFS_CALLS assertEqualsMon "_cb_tar_dir calls" "0" CBTAR_CALLS assertEqualsMon "_cb_base_pot calls" "0" CBPOT_CALLS } test_base_create_base_020() { pot-create-base -r 11.1 -b new-test-base assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_fetch calls" "1" FETCHBSD_CALLS assertEqualsMon "_fetch arg" "11.1" FETCHBSD_CALL1_ARG1 assertEqualsMon "_cb_zfs calls" "1" CBZFS_CALLS assertEqualsMon "_cb_zfs arg" "new-test-base" CBZFS_CALL1_ARG1 assertEqualsMon "_cb_tar_dir calls" "1" CBTAR_CALLS assertEqualsMon "_cb_tar_dir arg" "11.1" CBTAR_CALL1_ARG1 assertEqualsMon "_cb_tar_dir arg" "new-test-base" CBTAR_CALL1_ARG2 assertEqualsMon "_cb_base_pot calls" "1" CBPOT_CALLS assertEqualsMon "_cb_base_pot arg" "new-test-base" CBPOT_CALL1_ARG1 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/create-fscomp1.sh ================================================ #!/bin/sh # system utilities stubs zfs() { __monitor ZFS "$@" return 0 # true } # UUT . ../share/pot/create-fscomp.sh # common stubs . common-stub.sh _zfs_dataset_valid() { __monitor ZDSET "$@" if [ "$1" = "/fscomp/test-fscomp" ]; then return 0 # true fi return 1 # false } _is_init() { return 0 # true } # app specific stubs create-fscomp-help() { __monitor HELP "$@" } test_pot_create_fscomp_001() { pot-create-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-create-fscomp -vb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-create-fscomp -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-create-fscomp -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_create_fscomp_002() { pot-create-fscomp -f test-fscomp assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "1" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "zfs calls" "0" ZFS_CALLS } test_pot_create_fscomp_020() { pot-create-fscomp -f new-fscomp assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_zfs_dataset_valid calls" "1" ZDSET_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "zfs calls" "1" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "/fscomp/new-fscomp" ZFS_CALL1_ARG2 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/create-private-bridge1.sh ================================================ #!/bin/sh # system utilities stubs mkdir() { __monitor MKDIR "$@" } # UUT . ../share/pot/create-private-bridge.sh # common stubs . common-stub.sh _is_potnet_available() { return 0 # true } _is_bridge() { if [ "$1" = "test-bridge" ]; then return 0 # true fi return 1 } # app specific stubs create-private-bridge-help() { __monitor HELP "$@" } create-bridge() { __monitor CB "$@" } test_create_private_bridge_001() { pot-create-private-bridge assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-create-private-bridge -vL assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-create-private-bridge -L bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS setUp pot-create-private-bridge -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_create_private_bridge_002() { pot-create-private-bridge -B test-bridge assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_create_bridge calls" "0" CB_CALLS } test_create_private_bridge_003() { pot-create-private-bridge -S 5 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_create_bridge calls" "0" CB_CALLS } test_create_private_bridge_010() { # bridge already exists pot-create-private-bridge -B test-bridge -S 5 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_create_bridge calls" "0" CB_CALLS } test_create_private_bridge_020() { pot-create-private-bridge -B new-test-bridge -S 5 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_create_bridge calls" "1" CB_CALLS assertEqualsMon "_create_bridge arg1" "new-test-bridge" CB_CALL1_ARG1 assertEqualsMon "_create_bridge arg2" "5" CB_CALL1_ARG2 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/create1.sh ================================================ #!/bin/sh # system utilities stubs potnet() { __monitor POTNET "$@" if [ "$1" = "next" ]; then echo "10.192.123.123" return 0 # true fi if [ "$1" = "validate" ] && [ "$2" = "-H" ] ; then if [ "$3" = "10.192.123.123" ] || [ "$3" = "10.1.2.3" ]; then return 0 # true fi fi if [ "$1" = "ipcheck" ]; then return 0 # true fi return 1 # false } . pipefail-stub.sh # UUT . ../share/pot/create.sh # common stubs . common-stub.sh . ../share/pot/network.sh _is_vnet_available() { __monitor ISVNETAVAIL "$@" return 0 # true } _is_potnet_available() { __monitor ISPOTNETAVAIL "$@" return 0 # true } _fetch_freebsd() { __monitor FETCHBSD "$@" return 0 # true } _get_network_stack() { echo "dual" } # app specific stubs _cj_zfs() { __monitor CJZFS "$@" } _cj_conf() { __monitor CJCONF "$@" } _cj_internal_conf() { __monitor CJICONF "$@" } _cj_single_install() { __monitor CJSINGLE "$@" } _exec_flv() { __monitor EXEC_FLV "$@" } create-help() { __monitor HELP "$@" } test_pot_create_001() { pot-create assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-create -vL assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-create -L bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-create -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-create -S assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_002() { pot-create -p test-pot -b 11.1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_003() { pot-create -p new-pot -P test-pot -l 0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-create -p new-pot -b 11.1 -P test-pot -l 0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_004() { pot-create -p new-pot -P test-pot2 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-create -p new-pot -P test-pot2 -l 1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-create -p new-pot -b 11.1 -l 2 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_005() { pot-create -p new-pot -b 12.1 -N alias -I assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS setUp pot-create -p new-pot -b 12.1 -N alias -I removed-option assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_006() { pot-create -p new-pot -b 12.1 -N alias -S no-valid-stack assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_007() { pot-create -p new.pot -b 12.1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_020() { pot-create -p new-pot -b 11.1 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "multi" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_021() { pot-create -p new-pot -P test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "multi" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "test-pot" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "test-pot" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_022() { pot-create -p new-pot -P test-pot -S assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_023() { pot-create -p new-pot -P test-pot -b 10.4 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_024() { pot-create -p new-pot -P test-pot-0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_025() { pot-create -p new-pot -b 11.1 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "multi" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_026() { pot-create -p new-pot -b 11.1 -f flap assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "multi" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "1" EXEC_FLV_CALLS assertEqualsMon "_exec_flv arg2" "flap" EXEC_FLV_CALL1_ARG2 } test_pot_create_027() { pot-create -p new-pot -b 11.1 -S ipv6 -f flap assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "multi" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "ipv6" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "1" EXEC_FLV_CALLS assertEqualsMon "_exec_flv arg2" "flap" EXEC_FLV_CALL1_ARG2 } test_pot_create_028() { pot-create -p new-pot -b 11.1 -f flap -f flap2 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "multi" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "2" EXEC_FLV_CALLS assertEqualsMon "_exec_flv arg2" "flap" EXEC_FLV_CALL1_ARG2 assertEqualsMon "_exec_flv arg2" "flap2" EXEC_FLV_CALL2_ARG2 } test_pot_create_030() { pot-create -p new-pot -b 11.1 -f no-flav assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_040() { pot-create -p new-pot -P test-pot -l 2 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "2" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "test-pot" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "2" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "test-pot" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_041() { pot-create -p new-pot -b 11.1 -P test-pot -l 2 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "2" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "test-pot" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "2" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "test-pot" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_042() { pot-create -p new-pot -P test-pot -b 10.4 -l 2 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_060() { pot-create -p new-pot -b 11.1 -N inherit assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_is_vnet_available calls" "0" ISVNETAVAIL_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS assertEqualsMon "_potnet calls" "0" POTNET_CALLS } test_pot_create_061() { pot-create -p new-pot -b 11.1 -N inherit -s assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_062() { pot-create -p new-pot -b 11.1 -N public-bridge -i 10.1.2.3 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.1.2.3" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_063() { pot-create -p new-pot -b 11.1 -N alias -i 10.1.2.3 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_is_vnet_available calls" "0" ISVNETAVAIL_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "alias" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.1.2.3" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_064() { pot-create -p new-pot -b 11.1 -N public-bridge -i auto assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.192.123.123" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_065() { # -s is ignored in this case pot-create -p new-pot -b 11.1 -N alias -i auto assertEquals "Exit rc" "1" "$?" assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS # an empty error message is printed because _error is re-implemented in the stub } test_pot_create_080() { pot-create -p new-pot -b 11.1 -d asdf assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "0" CJZFS_CALLS assertEqualsMon "_cj_conf calls" "0" CJCONF_CALLS assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_081() { pot-create -p new-pot -b 11.1 -d pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_is_vnet_available calls" "1" ISVNETAVAIL_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "pot" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_082() { pot-create -p new-pot -b 11.1 -N public-bridge -i 10.1.2.3 -d pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_is_vnet_available calls" "2" ISVNETAVAIL_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.1.2.3" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "pot" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_083() { pot-create -p new-pot -b 11.1 -N alias -i 10.1.2.3 -d pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_is_vnet_available calls" "1" ISVNETAVAIL_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "alias" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.1.2.3" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "pot" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_084() { pot-create -p new-pot -b 11.1 -N public-bridge -i 10.1.2.3 -d off assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_is_vnet_available calls" "1" ISVNETAVAIL_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg3" "1" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.1.2.3" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "1" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "off" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "multi" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "0" CJICONF_CALLS assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_100() { pot-create -p new-pot -t single assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_create_101() { pot-create -p new-pot -t single -b no-base assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_create_102() { pot-create -p new-pot -t single -P no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_create_103() { pot-create -p new-pot -t single -P test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_create_104() { pot-create -p test-pot -t single -b 11.1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_create_105() { pot-create -p new-pot -t single -P test-pot-0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_create_106() { pot-create -p new-pot -t single -P test-pot-single -b 10.3 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_create_107() { pot-create -p new-pot -t single -b 11.1 -l 1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS } test_pot_create_120() { pot-create -p new-pot -b 11.1 -t single assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_is_vnet_available calls" "0" ISVNETAVAIL_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "single" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "0" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "0" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "single" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "1" CJSINGLE_CALLS assertEqualsMon "_cj_single_install arg1" "new-pot" CJSINGLE_CALL1_ARG1 assertEqualsMon "_cj_single_install arg2" "11.1" CJSINGLE_CALL1_ARG2 assertEqualsMon "_cj_interal_conf calls" "1" CJICONF_CALLS assertEqualsMon "_cj_interal_conf arg1" "new-pot" CJICONF_CALL1_ARG1 assertEqualsMon "_cj_interal_conf arg2" "single" CJICONF_CALL1_ARG2 assertEqualsMon "_cj_interal_conf arg3" "0" CJICONF_CALL1_ARG3 assertEqualsMon "_cj_interal_conf arg4" "" CJICONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_121() { pot-create -p new-pot -b 11.1 -t single -N public-bridge -i 10.1.2.3 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "single" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "0" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "public-bridge" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "10.1.2.3" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "0" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "single" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "1" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "1" CJICONF_CALLS assertEqualsMon "_cj_single_install arg1" "new-pot" CJSINGLE_CALL1_ARG1 assertEqualsMon "_cj_single_install arg2" "11.1" CJSINGLE_CALL1_ARG2 assertEqualsMon "_cj_interal_conf arg1" "new-pot" CJICONF_CALL1_ARG1 assertEqualsMon "_cj_interal_conf arg2" "single" CJICONF_CALL1_ARG2 assertEqualsMon "_cj_interal_conf arg3" "0" CJICONF_CALL1_ARG3 assertEqualsMon "_cj_interal_conf arg4" "10.1.2.3" CJICONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS } test_pot_create_122() { pot-create -p new-pot -P test-pot-single -t single assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_is_vnet_available calls" "0" ISVNETAVAIL_CALLS assertEqualsMon "_cj_zfs calls" "1" CJZFS_CALLS assertEqualsMon "_cj_zfs arg1" "new-pot" CJZFS_CALL1_ARG1 assertEqualsMon "_cj_zfs arg2" "single" CJZFS_CALL1_ARG2 assertEqualsMon "_cj_zfs arg3" "0" CJZFS_CALL1_ARG3 assertEqualsMon "_cj_zfs arg4" "11.1" CJZFS_CALL1_ARG4 assertEqualsMon "_cj_zfs arg5" "test-pot-single" CJZFS_CALL1_ARG5 assertEqualsMon "_cj_conf calls" "1" CJCONF_CALLS assertEqualsMon "_cj_conf arg1" "new-pot" CJCONF_CALL1_ARG1 assertEqualsMon "_cj_conf arg2" "11.1" CJCONF_CALL1_ARG2 assertEqualsMon "_cj_conf arg3" "inherit" CJCONF_CALL1_ARG3 assertEqualsMon "_cj_conf arg4" "" CJCONF_CALL1_ARG4 assertEqualsMon "_cj_conf arg5" "0" CJCONF_CALL1_ARG5 assertEqualsMon "_cj_conf arg6" "inherit" CJCONF_CALL1_ARG6 assertEqualsMon "_cj_conf arg7" "single" CJCONF_CALL1_ARG7 assertEqualsMon "_cj_conf arg8" "" CJCONF_CALL1_ARG8 assertEqualsMon "_cj_conf arg9" "test-pot-single" CJCONF_CALL1_ARG9 assertEqualsMon "_cj_conf_arg10" "dual" CJCONF_CALL1_ARG10 assertEqualsMon "_cj_single_install calls" "0" CJSINGLE_CALLS assertEqualsMon "_cj_interal_conf calls" "1" CJICONF_CALLS assertEqualsMon "_cj_interal_conf arg1" "new-pot" CJICONF_CALL1_ARG1 assertEqualsMon "_cj_interal_conf arg2" "single" CJICONF_CALL1_ARG2 assertEqualsMon "_cj_interal_conf arg3" "0" CJICONF_CALL1_ARG3 assertEqualsMon "_cj_interal_conf arg4" "" CJICONF_CALL1_ARG4 assertEqualsMon "_exec_flv calls" "0" EXEC_FLV_CALLS assertEqualsMon "_potnet calls" "0" POTNET_CALLS } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/create2.sh ================================================ #!/bin/sh # system utilities stubs zfs() { __monitor ZFS "$@" } ECHO=echo_stub echo_stub() { __monitor ECHO "$@" } mkdir() { __monitor MKDIR "$@" } chmod() { __monitor CHMOD "$@" if [ "$2" = "/tmp/jails/new-pot/m/tmp" ]; then return 0 # true fi if [ "$2" = "/tmp/jails/test-pot/m/tmp" ]; then return 0 # true fi /bin/chmod $@ } . pipefail-stub.sh # UUT . ../share/pot/create.sh # common stubs . common-stub.sh _zfs_dataset_valid() { __monitor ZFSDATASETVALID "$@" case "$1" in ${POT_ZFS_ROOT}/jails/test-pot|\ ${POT_ZFS_ROOT}/jails/test-pot/usr.local|\ ${POT_ZFS_ROOT}/jails/test-pot/custom) return 0 # true ;; esac return 1 # false } _zfs_last_snap() { __monitor ZFSLASTSNAP "$@" case $1 in ${POT_ZFS_ROOT}/bases/11.1/usr.local|\ ${POT_ZFS_ROOT}/bases/11.1/custom) echo 1234 ;; ${POT_ZFS_ROOT}/jails/test-pot/usr.local|\ ${POT_ZFS_ROOT}/jails/test-pot/custom) echo 4321 ;; ${POT_ZFS_ROOT}/jails/test-pot/m) echo 9999 ;; esac } test_cj_zfs_001() { # level 0 _c_zfs_multi new-pot 0 11.1 assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "1" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL1_ARG2 assertEqualsMon "chmod calls" "0" CHMOD_CALLS } test_cj_zfs_002() { _c_zfs_multi new-pot 1 11.1 assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "9" ZFS_CALLS assertEqualsMon "zfs c1 arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs c1 arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "zfs c2 arg1" "send" ZFS_CALL2_ARG1 assertEqualsMon "zfs c2 arg2" "${POT_ZFS_ROOT}/bases/11.1/usr.local@1234" ZFS_CALL2_ARG2 assertEqualsMon "zfs c3 arg1" "get" ZFS_CALL3_ARG1 assertEqualsMon "zfs c3 arg2" "-o" ZFS_CALL3_ARG2 assertEqualsMon "zfs c3 arg3" "property" ZFS_CALL3_ARG3 assertEqualsMon "zfs c3 arg4" "all" ZFS_CALL3_ARG4 assertEqualsMon "zfs c3 arg5" "${POT_ZFS_ROOT}" ZFS_CALL3_ARG5 assertEqualsMon "zfs c4 arg1" "receive" ZFS_CALL4_ARG1 assertEqualsMon "zfs c4 arg2" "${POT_ZFS_ROOT}/jails/new-pot/usr.local" ZFS_CALL4_ARG2 assertEqualsMon "zfs c5 arg1" "destroy" ZFS_CALL5_ARG1 assertEqualsMon "zfs c5 arg2" "${POT_ZFS_ROOT}/jails/new-pot/usr.local@1234" ZFS_CALL5_ARG2 assertEqualsMon "zfs c6 arg1" "send" ZFS_CALL6_ARG1 assertEqualsMon "zfs c6 arg2" "${POT_ZFS_ROOT}/bases/11.1/custom@1234" ZFS_CALL6_ARG2 assertEqualsMon "zfs c7 arg1" "get" ZFS_CALL7_ARG1 assertEqualsMon "zfs c7 arg2" "-o" ZFS_CALL7_ARG2 assertEqualsMon "zfs c7 arg3" "property" ZFS_CALL7_ARG3 assertEqualsMon "zfs c7 arg4" "all" ZFS_CALL7_ARG4 assertEqualsMon "zfs c7 arg5" "${POT_ZFS_ROOT}" ZFS_CALL7_ARG5 assertEqualsMon "zfs c8 arg1" "receive" ZFS_CALL8_ARG1 assertEqualsMon "zfs c8 arg2" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL8_ARG2 assertEqualsMon "zfs c9 arg1" "destroy" ZFS_CALL9_ARG1 assertEqualsMon "zfs c9 arg2" "${POT_ZFS_ROOT}/jails/new-pot/custom@1234" ZFS_CALL9_ARG2 assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL1_ARG2 assertEqualsMon "chmod calls" "0" CHMOD_CALLS } test_cj_zfs_003() { _c_zfs_multi new-pot 1 11.1 test-pot assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "9" ZFS_CALLS assertEqualsMon "zfs c1 arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs c1 arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "zfs c2 arg1" "send" ZFS_CALL2_ARG1 assertEqualsMon "zfs c2 arg2" "${POT_ZFS_ROOT}/jails/test-pot/usr.local@4321" ZFS_CALL2_ARG2 assertEqualsMon "zfs c3 arg1" "get" ZFS_CALL3_ARG1 assertEqualsMon "zfs c3 arg2" "-o" ZFS_CALL3_ARG2 assertEqualsMon "zfs c3 arg3" "property" ZFS_CALL3_ARG3 assertEqualsMon "zfs c3 arg4" "all" ZFS_CALL3_ARG4 assertEqualsMon "zfs c3 arg5" "${POT_ZFS_ROOT}" ZFS_CALL3_ARG5 assertEqualsMon "zfs c4 arg1" "receive" ZFS_CALL4_ARG1 assertEqualsMon "zfs c4 arg2" "${POT_ZFS_ROOT}/jails/new-pot/usr.local" ZFS_CALL4_ARG2 assertEqualsMon "zfs c5 arg1" "destroy" ZFS_CALL5_ARG1 assertEqualsMon "zfs c5 arg2" "${POT_ZFS_ROOT}/jails/new-pot/usr.local@4321" ZFS_CALL5_ARG2 assertEqualsMon "zfs c6 arg1" "send" ZFS_CALL6_ARG1 assertEqualsMon "zfs c6 arg2" "${POT_ZFS_ROOT}/jails/test-pot/custom@4321" ZFS_CALL6_ARG2 assertEqualsMon "zfs c7 arg1" "get" ZFS_CALL7_ARG1 assertEqualsMon "zfs c7 arg2" "-o" ZFS_CALL7_ARG2 assertEqualsMon "zfs c7 arg3" "property" ZFS_CALL7_ARG3 assertEqualsMon "zfs c7 arg4" "all" ZFS_CALL7_ARG4 assertEqualsMon "zfs c7 arg5" "${POT_ZFS_ROOT}" ZFS_CALL7_ARG5 assertEqualsMon "zfs c8 arg1" "receive" ZFS_CALL8_ARG1 assertEqualsMon "zfs c8 arg2" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL8_ARG2 assertEqualsMon "zfs c9 arg1" "destroy" ZFS_CALL9_ARG1 assertEqualsMon "zfs c9 arg2" "${POT_ZFS_ROOT}/jails/new-pot/custom@4321" ZFS_CALL9_ARG2 assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL1_ARG2 assertEqualsMon "chmod calls" "0" CHMOD_CALLS } test_cj_zfs_004() { _c_zfs_multi new-pot 2 11.1 test-pot assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "5" ZFS_CALLS assertEqualsMon "zfs c1 arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs c1 arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "zfs c2 arg1" "send" ZFS_CALL2_ARG1 assertEqualsMon "zfs c2 arg2" "${POT_ZFS_ROOT}/jails/test-pot/custom@4321" ZFS_CALL2_ARG2 assertEqualsMon "zfs c3 arg1" "get" ZFS_CALL3_ARG1 assertEqualsMon "zfs c3 arg2" "-o" ZFS_CALL3_ARG2 assertEqualsMon "zfs c3 arg3" "property" ZFS_CALL3_ARG3 assertEqualsMon "zfs c3 arg4" "all" ZFS_CALL3_ARG4 assertEqualsMon "zfs c3 arg5" "${POT_ZFS_ROOT}" ZFS_CALL3_ARG5 assertEqualsMon "zfs c4 arg1" "receive" ZFS_CALL4_ARG1 assertEqualsMon "zfs c4 arg2" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL4_ARG2 assertEqualsMon "zfs c5 arg1" "destroy" ZFS_CALL5_ARG1 assertEqualsMon "zfs c5 arg2" "${POT_ZFS_ROOT}/jails/new-pot/custom@4321" ZFS_CALL5_ARG2 assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/m" MKDIR_CALL1_ARG2 assertEqualsMon "chmod calls" "0" CHMOD_CALLS } test_cj_zfs_021() { _cj_zfs test-pot multi 0 11.1 assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "0" ZFS_CALLS assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/test-pot/m" MKDIR_CALL1_ARG2 assertEqualsMon "info calls" "1" INFO_CALLS assertEqualsMon "chmod calls" "0" CHMOD_CALLS } test_cj_zfs_022() { _cj_zfs test-pot multi 1 11.1 assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "0" ZFS_CALLS assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/test-pot/m" MKDIR_CALL1_ARG2 assertEqualsMon "info calls" "3" INFO_CALLS assertEqualsMon "chmod calls" "0" CHMOD_CALLS } test_cj_zfs_023() { _cj_zfs test-pot multi 2 11.1 test-pot2 assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "0" ZFS_CALLS assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/test-pot/m" MKDIR_CALL1_ARG2 assertEqualsMon "info calls" "2" INFO_CALLS assertEqualsMon "chmod calls" "0" CHMOD_CALLS } test_cj_zfs_041() { _cj_zfs new-pot single 0 11.1 assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "2" ZFS_CALLS assertEqualsMon "zfs c1 arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs c1 arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "zfs c2 arg1" "create" ZFS_CALL2_ARG1 assertEqualsMon "zfs c2 arg2" "${POT_ZFS_ROOT}/jails/new-pot/m" ZFS_CALL2_ARG2 assertEqualsMon "mkdir calls" "2" MKDIR_CALLS assertEqualsMon "mkdir 1 arg2" "${POT_FS_ROOT}/jails/new-pot/m/tmp" MKDIR_CALL1_ARG2 assertEqualsMon "mkdir 2 arg2" "${POT_FS_ROOT}/jails/new-pot/m/dev" MKDIR_CALL2_ARG2 assertEqualsMon "chmod calls" "1" CHMOD_CALLS assertEqualsMon "chmod arg1" "1777" CHMOD_CALL1_ARG1 assertEqualsMon "chmod arg2" "${POT_FS_ROOT}/jails/new-pot/m/tmp" CHMOD_CALL1_ARG2 } test_cj_zfs_042() { _cj_zfs test-pot single 0 11.1 assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "1" ZFS_CALLS assertEqualsMon "zfs arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs arg2" "${POT_ZFS_ROOT}/jails/test-pot/m" ZFS_CALL1_ARG2 assertEqualsMon "mkdir calls" "2" MKDIR_CALLS assertEqualsMon "mkdir 1 arg2" "${POT_FS_ROOT}/jails/test-pot/m/tmp" MKDIR_CALL1_ARG2 assertEqualsMon "mkdir 2 arg2" "${POT_FS_ROOT}/jails/test-pot/m/dev" MKDIR_CALL2_ARG2 assertEqualsMon "chmod calls" "1" CHMOD_CALLS assertEqualsMon "chmod arg1" "1777" CHMOD_CALL1_ARG1 assertEqualsMon "chmod arg2" "${POT_FS_ROOT}/jails/test-pot/m/tmp" CHMOD_CALL1_ARG2 } test_cj_zfs_043() { _cj_zfs new-pot single 0 11.1 test-pot assertEquals "return code" "0" "$?" assertEqualsMon "zfs calls" "4" ZFS_CALLS assertEqualsMon "zfs c1 arg1" "create" ZFS_CALL1_ARG1 assertEqualsMon "zfs c1 arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL1_ARG2 assertEqualsMon "zfs c2 arg1" "send" ZFS_CALL2_ARG1 assertEqualsMon "zfs c2 arg2" "${POT_ZFS_ROOT}/jails/test-pot/m@9999" ZFS_CALL2_ARG2 assertEqualsMon "zfs c3 arg1" "get" ZFS_CALL3_ARG1 assertEqualsMon "zfs c3 arg2" "-o" ZFS_CALL3_ARG2 assertEqualsMon "zfs c3 arg3" "property" ZFS_CALL3_ARG3 assertEqualsMon "zfs c3 arg4" "all" ZFS_CALL3_ARG4 assertEqualsMon "zfs c3 arg5" "${POT_ZFS_ROOT}" ZFS_CALL3_ARG5 assertEqualsMon "zfs c4 arg1" "receive" ZFS_CALL4_ARG1 assertEqualsMon "zfs c4 arg2" "${POT_ZFS_ROOT}/jails/new-pot/m" ZFS_CALL4_ARG2 assertEqualsMon "mkdir calls" "0" MKDIR_CALLS assertEqualsMon "chmod calls" "0" CHMOD_CALLS } setUp() { common_setUp POT_FS_ROOT=/tmp POT_ZFS_ROOT=zpot } . shunit/shunit2 ================================================ FILE: tests/create3.sh ================================================ #!/bin/sh # system utilities stubs mkdir() { __monitor MKDIR "$@" /bin/mkdir "$@" } SED=sed_stub sed_stub() { __monitor SED "$@" if [ "$4" = "${POT_FS_ROOT}/jails/$_pname/custom/etc/crontab" ]; then return 0 # true fi if [ "$4" = "${POT_FS_ROOT}/jails/$_pname/custom/etc/syslog.conf" ]; then return 0 # true fi if [ "$(uname)" = "Linux" ]; then sed -i'' "$3" "$4" else sed "$@" fi } sysrc() { __monitor SYSRC "$@" } service() { __monitor SERVICE "$@" } cat() { if [ "$1" = "${POT_FS_ROOT}/bases/11.1/.osrelease" ]; then echo 11.1 fi } cp() { __monitor CP "$@" } . pipefail-stub.sh # UUT . ../share/pot/create.sh # common stubs . common-stub.sh _cj_internal_conf() { __monitor ICONF "$@" } test_cj_conf_001() { # level 0 _cj_conf new-pot 11.1 inherit "" 0 inherit multi assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "zpot/bases/11.1 /" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/bases/11.1/usr.local /usr/local" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/bases/11.1/custom /opt/custom" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=0" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "network_type" "network_type=inherit" "$(grep ^network_type= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=false" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "sed calls" "0" SED_CALLS assertEqualsMon "internal_conf calls" "1" ICONF_CALLS assertEqualsMon "internal_conf arg1" "new-pot" ICONF_CALL1_ARG1 assertEqualsMon "internal_conf arg2" "multi" ICONF_CALL1_ARG2 assertEqualsMon "internal_conf arg3" "0" ICONF_CALL1_ARG3 assertEqualsMon "internal_conf arg4" "" ICONF_CALL1_ARG4 } test_cj_conf_002() { _cj_conf new-pot 11.1 inherit "" 1 inherit multi assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "zpot/bases/11.1 / ro" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/jails/new-pot/usr.local /usr/local zfs-remount" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/jails/new-pot/custom /opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=1" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "network_type" "network_type=inherit" "$(grep ^network_type= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=false" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "internal_conf calls" "1" ICONF_CALLS assertEqualsMon "internal_conf arg1" "new-pot" ICONF_CALL1_ARG1 assertEqualsMon "internal_conf arg2" "multi" ICONF_CALL1_ARG2 assertEqualsMon "internal_conf arg3" "1" ICONF_CALL1_ARG3 assertEqualsMon "internal_conf arg4" "" ICONF_CALL1_ARG4 assertEqualsMon "sed calls" "0" SED_CALLS } test_cj_conf_003() { /bin/mkdir -p /tmp/jails/test-pot/conf echo "zpot/bases/11.1 / ro" >> /tmp/jails/test-pot/conf/fscomp.conf echo "zpot/jails/test-pot/usr.local /usr/local zfs-remount" >> /tmp/jails/test-pot/conf/fscomp.conf echo "zpot/jails/test-pot/custom /opt/custom zfs-remount" >> /tmp/jails/test-pot/conf/fscomp.conf _cj_conf new-pot 11.1 inherit "" 1 inherit multi "" test-pot assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "zpot/bases/11.1 / ro" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/jails/new-pot/usr.local /usr/local zfs-remount" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/jails/new-pot/custom /opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=1" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=test-pot" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "network_type" "network_type=inherit" "$(grep ^network_type= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=false" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "internal_conf calls" "1" ICONF_CALLS assertEqualsMon "internal_conf arg1" "new-pot" ICONF_CALL1_ARG1 assertEqualsMon "internal_conf arg2" "multi" ICONF_CALL1_ARG2 assertEqualsMon "internal_conf arg3" "1" ICONF_CALL1_ARG3 assertEqualsMon "internal_conf arg4" "" ICONF_CALL1_ARG4 assertEqualsMon "sed calls" "0" SED_CALLS } test_cj_conf_004() { /bin/mkdir -p /tmp/jails/test-pot/conf echo "zpot/bases/11.1 / ro" >> /tmp/jails/test-pot/conf/fscomp.conf echo "zpot/jails/test-pot/usr.local /usr/local zfs-remount" >> /tmp/jails/test-pot/conf/fscomp.conf echo "zpot/jails/test-pot/custom /opt/custom zfs-remount" >> /tmp/jails/test-pot/conf/fscomp.conf _cj_conf new-pot 11.1 inherit "" 2 inherit multi "" test-pot assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "zpot/bases/11.1 / ro" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/jails/test-pot/usr.local /usr/local ro" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/jails/new-pot/custom /opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=2" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=test-pot" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=false" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "internal_conf calls" "1" ICONF_CALLS assertEqualsMon "internal_conf arg1" "new-pot" ICONF_CALL1_ARG1 assertEqualsMon "internal_conf arg2" "multi" ICONF_CALL1_ARG2 assertEqualsMon "internal_conf arg3" "2" ICONF_CALL1_ARG3 assertEqualsMon "internal_conf arg4" "" ICONF_CALL1_ARG4 assertEqualsMon "sed calls" "1" SED_CALLS } test_cj_conf_005() { _cj_conf new-pot 11.1 inherit "" 2 inherit multi "" test-pot-2 assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "zpot/bases/11.1 / ro" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/jails/test-pot/usr.local /usr/local ro" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/jails/new-pot/custom /opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=2" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=test-pot-2" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "network_type" "network_type=inherit" "$(grep ^network_type= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=false" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "internal_conf calls" "1" ICONF_CALLS assertEqualsMon "internal_conf arg1" "new-pot" ICONF_CALL1_ARG1 assertEqualsMon "internal_conf arg2" "multi" ICONF_CALL1_ARG2 assertEqualsMon "internal_conf arg3" "2" ICONF_CALL1_ARG3 assertEqualsMon "internal_conf arg4" "" ICONF_CALL1_ARG4 assertEqualsMon "sed calls" "0" SED_CALLS } test_cj_conf_006() { _cj_conf new-pot 11.1 public-bridge 10.1.2.3 1 inherit multi assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "zpot/bases/11.1 / ro" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/jails/new-pot/usr.local /usr/local zfs-remount" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/jails/new-pot/custom /opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=1" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "network_type" "network_type=public-bridge" "$(grep ^network_type= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "ip=10.1.2.3" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=true" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "internal_conf calls" "1" ICONF_CALLS assertEqualsMon "internal_conf arg1" "new-pot" ICONF_CALL1_ARG1 assertEqualsMon "internal_conf arg2" "multi" ICONF_CALL1_ARG2 assertEqualsMon "internal_conf arg3" "1" ICONF_CALL1_ARG3 assertEqualsMon "internal_conf arg4" "10.1.2.3" ICONF_CALL1_ARG4 assertEqualsMon "sed calls" "0" SED_CALLS } test_cj_conf_007() { _cj_conf new-pot 11.1 inherit "" 1 pot multi assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "zpot/bases/11.1 / ro" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/jails/new-pot/usr.local /usr/local zfs-remount" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/jails/new-pot/custom /opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=1" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "network_type" "network_type=inherit" "$(grep ^network_type= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=false" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.depend" "pot.depend=${POT_DNS_NAME}" "$(grep ^pot.depend /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "sed calls" "0" SED_CALLS assertEqualsMon "internal_conf calls" "1" ICONF_CALLS assertEqualsMon "internal_conf arg1" "new-pot" ICONF_CALL1_ARG1 assertEqualsMon "internal_conf arg2" "multi" ICONF_CALL1_ARG2 assertEqualsMon "internal_conf arg3" "1" ICONF_CALL1_ARG3 assertEqualsMon "internal_conf arg4" "" ICONF_CALL1_ARG4 } test_cj_conf_008() { _cj_conf new-pot 11.1 public-bridge 10.1.2.3 1 pot multi assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "zpot/bases/11.1 / ro" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/jails/new-pot/usr.local /usr/local zfs-remount" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/jails/new-pot/custom /opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=1" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "network_type" "network_type=public-bridge" "$(grep ^network_type= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "ip=10.1.2.3" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=true" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.depend" "pot.depend=${POT_DNS_NAME}" "$(grep ^pot.depend /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "internal_conf calls" "1" ICONF_CALLS assertEqualsMon "internal_conf arg1" "new-pot" ICONF_CALL1_ARG1 assertEqualsMon "internal_conf arg2" "multi" ICONF_CALL1_ARG2 assertEqualsMon "internal_conf arg3" "1" ICONF_CALL1_ARG3 assertEqualsMon "internal_conf arg4" "10.1.2.3" ICONF_CALL1_ARG4 assertEqualsMon "sed calls" "0" SED_CALLS } test_cj_conf_009() { _cj_conf new-pot 11.1 alias 10.1.2.3 1 pot multi assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "zpot/bases/11.1 / ro" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/jails/new-pot/usr.local /usr/local zfs-remount" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/jails/new-pot/custom /opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=1" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "network_type" "network_type=alias" "$(grep ^network_type= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "ip=10.1.2.3" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=false" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.depend" "pot.depend=${POT_DNS_NAME}" "$(grep ^pot.depend /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "internal_conf calls" "1" ICONF_CALLS assertEqualsMon "internal_conf arg1" "new-pot" ICONF_CALL1_ARG1 assertEqualsMon "internal_conf arg2" "multi" ICONF_CALL1_ARG2 assertEqualsMon "internal_conf arg3" "1" ICONF_CALL1_ARG3 assertEqualsMon "internal_conf arg4" "10.1.2.3" ICONF_CALL1_ARG4 assertEqualsMon "sed calls" "0" SED_CALLS } test_cj_conf_020() { _cj_conf new-pot 11.1 inherit "" 0 pot single assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.level" "pot.level=0" "$(grep ^pot.level /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.base" "pot.base=11.1" "$(grep ^pot.base /tmp/jails/new-pot/conf/pot.conf)" assertEquals "osrelease" "osrelease=\"11.1-RELEASE\"" "$(grep ^osrelease /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.potbase" "pot.potbase=" "$(grep ^pot.potbase /tmp/jails/new-pot/conf/pot.conf)" assertEquals "network_type" "network_type=inherit" "$(grep ^network_type= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "ip" "" "$(grep ^ip= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "vnet" "vnet=false" "$(grep ^vnet= /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.depend" "pot.depend=${POT_DNS_NAME}" "$(grep ^pot.depend /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "mkdir calls" "1" MKDIR_CALLS assertEqualsMon "mkdir arg2" "${POT_FS_ROOT}/jails/new-pot/conf" MKDIR_CALL1_ARG2 assertEqualsMon "internal_conf calls" "0" ICONF_CALLS assertEqualsMon "sed calls" "0" SED_CALLS } test_cj_conf_040() { _cj_conf new-pot 11.1 inherit "" 0 pot single assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.dns" "pot.dns=pot" "$(grep ^pot.dns /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.depend" "pot.depend=${POT_DNS_NAME}" "$(grep ^pot.depend /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "cp calls" "0" CP_CALLS } test_cj_conf_041() { _cj_conf new-pot 11.1 inherit "" 0 off single assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.dns" "pot.dns=off" "$(grep ^pot.dns /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.depend" "" "$(grep ^pot.depend /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "cp calls" "0" CP_CALLS } test_cj_conf_042() { _cj_conf new-pot 11.1 inherit "" 0 inherit single assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.dns" "pot.dns=inherit" "$(grep ^pot.dns /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.depend" "" "$(grep ^pot.depend /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "cp calls" "0" CP_CALLS } test_cj_conf_043() { _cj_conf new-pot 11.1 inherit "" 0 custom:/etc/resolv.conf single assertEquals "return code" "0" "$?" assertEquals "fscomp args1" "" "$(sed '1!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "" "$(sed '2!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "" "$(sed '3!d' /tmp/jails/new-pot/conf/fscomp.conf)" assertEquals "pot.dns" "pot.dns=custom" "$(grep ^pot.dns /tmp/jails/new-pot/conf/pot.conf)" assertEquals "pot.depend" "" "$(grep ^pot.depend /tmp/jails/new-pot/conf/pot.conf)" assertEqualsMon "cp calls" "1" CP_CALLS assertEqualsMon "cp arg1" "/etc/resolv.conf" CP_CALL1_ARG1 assertEqualsMon "cp arg2" "/tmp/jails/new-pot/conf/resolv.conf" CP_CALL1_ARG2 } setUp() { common_setUp POT_FS_ROOT=/tmp POT_ZFS_ROOT=zpot POT_DNS_NAME=foobar-dns /bin/mkdir -p /tmp/jails/new-pot/custom/etc/syslog.d } tearDown() { common_tearDown rm -rf /tmp/jails } . shunit/shunit2 ================================================ FILE: tests/destroy1.sh ================================================ #!/bin/sh # system utilities stubs ls() { cat << LS_EOL /opt/pot/jails/base-11_1/ /opt/pot/jails/test-pot/ /opt/pot/jails/test-pot-2/ /opt/pot/jails/test-pot-run/ /opt/pot/jails/test-pot-run-2/ LS_EOL } # UUT . ../share/pot/destroy.sh # common stubs . common-stub.sh # app specific stubs destroy-help() { __monitor HELP "$@" } _zfs_dataset_valid() { __monitor ZFSDATASETVALID "$@" if [ "$1" = "/fscomp/test-fscomp" ]; then return 0 # true fi return 1 # false } _zfs_dataset_destroy() { __monitor ZFSDDESTROY "$@" } _pot_zfs_destroy() { __monitor POTDESTROY "$@" if [ "$1" = "test-pot-run-2" ]; then if [ "$2" != "YES" ]; then return 1 # false fi fi return 0 # true } _base_zfs_destroy() { __monitor BASEDESTROY "$@" } _fscomp_zfs_destroy() { __monitor FSCOMPDESTROY "$@" } test_pot_destroy_001() { pot-destroy assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS setUp pot-destroy -k bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS setUp pot-destroy -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS setUp pot-destroy -va assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_002() { pot-destroy -p test-pot -b 11.1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_003() { pot-destroy -p test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_004() { pot-destroy -p test-pot-0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_005() { pot-destroy -p test-pot-2 -f test-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_006() { pot-destroy -f test-fscomp -b 11.1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_010() { # error - recursion is needed pot-destroy -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_011() { # error - still running, force is needed pot-destroy -p test-pot-run-2 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "1" POTDESTROY_CALLS assertEqualsMon "_pot_zfs_destroy arg1" "test-pot-run-2" POTDESTROY_CALL1_ARG1 assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_020() { pot-destroy -p test-pot -r assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "2" POTDESTROY_CALLS assertEqualsMon "_pot_zfs_destroy arg1" "test-pot-2" POTDESTROY_CALL1_ARG1 assertEqualsMon "_pot_zfs_destroy arg2" "" POTDESTROY_CALL1_ARG2 assertEqualsMon "_pot_zfs_destroy arg1" "test-pot" POTDESTROY_CALL2_ARG1 assertEqualsMon "_pot_zfs_destroy arg2" "" POTDESTROY_CALL2_ARG2 assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_021() { pot-destroy -p test-pot-run-2 -F assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "1" POTDESTROY_CALLS assertEqualsMon "_pot_zfs_destroy arg1" "test-pot-run-2" POTDESTROY_CALL1_ARG1 assertEqualsMon "_pot_zfs_destroy arg2" "YES" POTDESTROY_CALL1_ARG2 assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_022() { pot-destroy -p test-pot-2 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "1" POTDESTROY_CALLS assertEqualsMon "_pot_zfs_destroy arg1" "test-pot-2" POTDESTROY_CALL1_ARG1 assertEqualsMon "_pot_zfs_destroy arg2" "" POTDESTROY_CALL1_ARG2 assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_060() { pot-destroy -f test-no-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "0" FSCOMPDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy arg1" "" FSCOMPDESTROY_CALL1_ARG1 assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } test_pot_destroy_061() { pot-destroy -f test-fscomp assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_destroy calls" "0" POTDESTROY_CALLS assertEqualsMon "_base_zfs_destroy calls" "0" BASEDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy calls" "1" FSCOMPDESTROY_CALLS assertEqualsMon "_fscomp_zfs_destroy arg1" "test-fscomp" FSCOMPDESTROY_CALL1_ARG1 assertEqualsMon "_zfs_dataset_destroy calls" "0" ZFSDDESTROY_CALLS } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/export-ports1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/export-ports.sh # common stubs . common-stub.sh # app specific stubs export-ports-help() { __monitor HELP "$@" } _export_ports() { __monitor EXPORTS "$@" } test_pot_export_ports_001() { pot-export-ports -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS setUp pot-export-ports -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_020() { pot-export-ports -p assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_021() { pot-export-ports -p "" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_022() { pot-export-ports -p no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_023() { pot-export-ports -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_024() { pot-export-ports -e assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_025() { pot-export-ports -e "" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_026() { pot-export-ports -p test-pot -e http assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_027() { pot-export-ports -p test-pot -e "" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_027() { pot-export-ports -p test-pot -e -1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_028() { pot-export-ports -p test-pot -e "12 34" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_029() { pot-export-ports -p test-pot -e 65536 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_030() { pot-export-ports -p test-pot -e 80: assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_031() { pot-export-ports -p test-pot -e :80 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_032() { pot-export-ports -p test-pot -e 80:100000 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } test_pot_export_ports_033() { pot-export-ports -p test-pot -e 100000:80 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS } #test_pot_export_ports_034() #{ # pot-export-ports -p test-pot -e 80:80: # assertEquals "Exit rc" "1" "$?" # assertEqualsMon "Help calls" "1" HELP_CALLS # assertEqualsMon "Error calls" "1" ERROR_CALLS # assertEqualsMon "_export_ports calls" "0" EXPORTS_CALLS #} test_pot_export_ports_040() { pot-export-ports -p test-pot-2 -e 80 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export_ports calls" "1" EXPORTS_CALLS assertEqualsMon "_export_ports arg1" "test-pot-2" EXPORTS_CALL1_ARG1 assertEqualsMon "_export_ports arg2" "80" EXPORTS_CALL1_ARG2 } test_pot_export_ports_041() { pot-export-ports -p test-pot-2 -e 80 -e 443 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export_ports calls" "1" EXPORTS_CALLS assertEqualsMon "_export_ports arg1" "test-pot-2" EXPORTS_CALL1_ARG1 assertEqualsMon "_export_ports arg2" "80 443" EXPORTS_CALL1_ARG2 } test_pot_export_ports_042() { pot-export-ports -p test-pot-2 -e 80:8080 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export_ports calls" "1" EXPORTS_CALLS assertEqualsMon "_export_ports arg1" "test-pot-2" EXPORTS_CALL1_ARG1 assertEqualsMon "_export_ports arg2" "80:8080" EXPORTS_CALL1_ARG2 } test_pot_export_ports_043() { pot-export-ports -p test-pot-2 -e 80:8080 -e 443:30443 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export_ports calls" "1" EXPORTS_CALLS assertEqualsMon "_export_ports arg1" "test-pot-2" EXPORTS_CALL1_ARG1 assertEqualsMon "_export_ports arg2" "80:8080 443:30443" EXPORTS_CALL1_ARG2 } test_pot_export_ports_044() { pot-export-ports -p test-pot-multi-private -e 80:8080 -e 443:30443 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export_ports calls" "1" EXPORTS_CALLS assertEqualsMon "_export_ports arg1" "test-pot-multi-private" EXPORTS_CALL1_ARG1 assertEqualsMon "_export_ports arg2" "80:8080 443:30443" EXPORTS_CALL1_ARG2 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/export1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/export.sh . ../share/pot/common.sh # common stubs . common-stub.sh # only has to exist, isn't called in tests signify() { true } _is_zfs_pot_snap() { __monitor ISZFSSNAP "$@" if [ "$1" = "test-pot-single" ] && [ "$2" = "666" ]; then return 0 else return 1 fi } _zfs_last_snap() { __monitor ZFSLASTSNAP "$@" if [ "$1" = "/jails/test-pot-single" ]; then echo 1234321 elif [ "$1" = "/jails/test-pot-single-2" ]; then echo 4321234 elif [ "$1" = "/jails/test-pot-single-0" ]; then if [ -e /tmp/pot_test_last_snap ]; then echo 123123123 rm -f /tmp/pot_test_last_snap else touch /tmp/pot_test_last_snap fi fi } _zfs_count_snap() { if [ "$1" = "/jails/test-pot-single-2" ]; then echo 2 else echo 1 fi } pot-cmd() { __monitor POTCMD "$@" } # app specific stubs export-help() { __monitor HELP "$@" } _export_pot() { __monitor EXPORTS "$@" return 0 # true } test_pot_export_001() { pot-export -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS setUp pot-export -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_020() { pot-export -p assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_021() { pot-export -p "" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_022() { pot-export -p no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_023() { pot-export -s assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_024() { pot-export -s "" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_025() { # correct snapshot, but no pot pot-export -s 666 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_026() { # pot is not single pot-export -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_027() { # snapshot already existing pot-export -p test-pot-single -s 666 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_028() { # directory doesn't exist pot-export -p test-pot-single -D asdfasdf assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_029() { # wrong compression level pot-export -p test-pot-single -l max assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_030() { # wrong compression level pot-export -p test-pot-single -l 10 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_031() { # wrong number of snapshost pot-export -p test-pot-single-2 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_032() { # no snapshosts available pot-export -p test-pot-single-0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_040() { pot-export -p test-pot-single assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_zfs_pot_snap calls" "0" ISZFSSNAP_CALLS assertEqualsMon "_export calls" "1" EXPORTS_CALLS assertEqualsMon "_export arg1" "test-pot-single" EXPORTS_CALL1_ARG1 assertEqualsMon "_export arg2" "1234321" EXPORTS_CALL1_ARG2 assertEqualsMon "_export arg3" "1234321" EXPORTS_CALL1_ARG3 assertEqualsMon "_export arg4" "" EXPORTS_CALL1_ARG4 assertEqualsMon "_export arg5" "." EXPORTS_CALL1_ARG5 } test_pot_export_041() { pot-export -p test-pot-single -t v1.0 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_zfs_pot_snap calls" "0" ISZFSSNAP_CALLS assertEqualsMon "_export calls" "1" EXPORTS_CALLS assertEqualsMon "_export arg1" "test-pot-single" EXPORTS_CALL1_ARG1 assertEqualsMon "_export arg2" "1234321" EXPORTS_CALL1_ARG2 assertEqualsMon "_export arg3" "v1.0" EXPORTS_CALL1_ARG3 assertEqualsMon "_export arg4" "" EXPORTS_CALL1_ARG4 assertEqualsMon "_export arg5" "." EXPORTS_CALL1_ARG5 } test_pot_export_042() { pot-export -p test-pot-single -s 1234 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_043() { pot-export -p test-pot-single -s 1234 -t 1.0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_044() { pot-export -p test-pot-single -s 1234 -t 1.0 -D /tmp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_export calls" "0" EXPORTS_CALLS } test_pot_export_050() { pot-export -p test-pot-single-2 -t 1.0 -F assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_zfs_pot_snap calls" "0" ISZFSSNAP_CALLS assertEqualsMon "_export calls" "1" EXPORTS_CALLS assertEqualsMon "_export arg1" "test-pot-single-2" EXPORTS_CALL1_ARG1 assertEqualsMon "_export arg2" "4321234" EXPORTS_CALL1_ARG2 assertEqualsMon "_export arg3" "1.0" EXPORTS_CALL1_ARG3 assertEqualsMon "_export arg4" "" EXPORTS_CALL1_ARG4 assertEqualsMon "_export arg5" "." EXPORTS_CALL1_ARG5 } test_pot_export_051() { pot-export -p test-pot-single-2 -t 1.0 -A assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_zfs_pot_snap calls" "0" ISZFSSNAP_CALLS assertEqualsMon "pot-cmd calls" "1" POTCMD_CALLS assertEqualsMon "pot-cmd arg1" "purge-snapshots" POTCMD_CALL1_ARG1 assertEqualsMon "_export calls" "1" EXPORTS_CALLS assertEqualsMon "_export arg1" "test-pot-single-2" EXPORTS_CALL1_ARG1 assertEqualsMon "_export arg2" "4321234" EXPORTS_CALL1_ARG2 assertEqualsMon "_export arg3" "1.0" EXPORTS_CALL1_ARG3 assertEqualsMon "_export arg4" "" EXPORTS_CALL1_ARG4 assertEqualsMon "_export arg5" "." EXPORTS_CALL1_ARG5 } test_pot_export_052() { pot-export -p test-pot-single-0 -t 1.0 -A assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_zfs_pot_snap calls" "0" ISZFSSNAP_CALLS assertEqualsMon "pot-cmd calls" "1" POTCMD_CALLS assertEqualsMon "pot-cmd arg1" "snapshot" POTCMD_CALL1_ARG1 assertEqualsMon "_export calls" "1" EXPORTS_CALLS assertEqualsMon "_export arg1" "test-pot-single-0" EXPORTS_CALL1_ARG1 assertEqualsMon "_export arg2" "123123123" EXPORTS_CALL1_ARG2 assertEqualsMon "_export arg3" "1.0" EXPORTS_CALL1_ARG3 assertEqualsMon "_export arg4" "" EXPORTS_CALL1_ARG4 assertEqualsMon "_export arg5" "." EXPORTS_CALL1_ARG5 } test_pot_export_053() { pot-export -p test-pot-single-0 -t 1.0 -A -S export1.sh assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_zfs_pot_snap calls" "0" ISZFSSNAP_CALLS assertEqualsMon "pot-cmd calls" "1" POTCMD_CALLS assertEqualsMon "pot-cmd arg1" "snapshot" POTCMD_CALL1_ARG1 assertEqualsMon "_export calls" "1" EXPORTS_CALLS assertEqualsMon "_export arg1" "test-pot-single-0" EXPORTS_CALL1_ARG1 assertEqualsMon "_export arg2" "123123123" EXPORTS_CALL1_ARG2 assertEqualsMon "_export arg3" "1.0" EXPORTS_CALL1_ARG3 assertEqualsMon "_export arg4" "" EXPORTS_CALL1_ARG4 assertEqualsMon "_export arg5" "." EXPORTS_CALL1_ARG5 } test_pot_export_054() { pot-export -p test-pot-single-0 -t 1.0 -A -S nonexistent assertEquals "Exit rc" "1" "$?" } setUp() { common_setUp } tearDown() { common_tearDown rm -f /tmp/pot_test_last_snap } . shunit/shunit2 ================================================ FILE: tests/get-rss1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/get-rss.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs get-rss-help() { __monitor HELP "$@" } _is_rctl_available() { return 0 # true } print_rss() { __monitor PRINT "$@" } test_pot_get_rss_001() { pot-get-rss assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "print_rss calls" "0" PRINT_CALLS setUp pot-get-rss -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "print_rss calls" "0" PRINT_CALLS setUp pot-get-rss -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "print_rss calls" "0" PRINT_CALLS } test_pot_get_rss_002() { pot-get-rss -p test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "print_rss calls" "0" PRINT_CALLS } test_pot_get_rss_020() { pot-get-rss -p test-pot-run assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "print_rss calls" "1" PRINT_CALLS assertEqualsMon "print_rss arg1" "test-pot-run" PRINT_CALL1_ARG1 assertEqualsMon "print_rss arg2" "" PRINT_CALL1_ARG2 } test_pot_get_rss_021() { pot-get-rss -p test-pot-run-2 -J assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "print_rss calls" "1" PRINT_CALLS assertEqualsMon "print_rss arg1" "test-pot-run-2" PRINT_CALL1_ARG1 assertEqualsMon "print_rss arg2" "YES" PRINT_CALL1_ARG2 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/import1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/import.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs import-help() { __monitor HELP "$@" } _fetch_pot() { __monitor FETCHPOT "$@" } _import_pot() { __monitor IMPORTS "$@" } # only has to exist, isn't called in tests signify() { true } test_pot_import_001() { pot-import -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS setUp pot-import -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS } test_pot_import_020() { pot-import -p assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS } test_pot_import_021() { pot-import -p "" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS } test_pot_import_022() { pot-import -p no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS } test_pot_import_023() { pot-import -t assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS } test_pot_import_024() { pot-import -t "" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS } test_pot_import_025() { # correct snapshot, but no pot pot-import -t 666 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS } test_pot_import_026() { pot-import -p test-pot-single -t 1.0 -U assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS } test_pot_import_027() { pot-import -p test-pot-single -t 1.0 -U "" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_fetch_pot calls" "0" FETCHPOT_CALLS assertEqualsMon "_import calls" "0" IMPORTS_CALLS } test_pot_import_040() { pot-import -p test-pot-single -t 1.0 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "1" FETCHPOT_CALLS assertEqualsMon "_fetch_pot arg1" "test-pot-single" FETCHPOT_CALL1_ARG1 assertEqualsMon "_fetch_pot arg2" "1.0" FETCHPOT_CALL1_ARG2 assertEqualsMon "_fetch_pot arg3" "" FETCHPOT_CALL1_ARG3 assertEqualsMon "_import calls" "1" IMPORTS_CALLS assertEqualsMon "_import arg1" "test-pot-single" IMPORTS_CALL1_ARG1 assertEqualsMon "_import arg2" "1.0" IMPORTS_CALL1_ARG2 assertEqualsMon "_import arg3" "test-pot-single_1_0" IMPORTS_CALL1_ARG3 } test_pot_import_041() { pot-import -p test-pot-single -t v1.0 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "1" FETCHPOT_CALLS assertEqualsMon "_fetch_pot arg1" "test-pot-single" FETCHPOT_CALL1_ARG1 assertEqualsMon "_fetch_pot arg2" "v1.0" FETCHPOT_CALL1_ARG2 assertEqualsMon "_fetch_pot arg3" "" FETCHPOT_CALL1_ARG3 assertEqualsMon "_import calls" "1" IMPORTS_CALLS assertEqualsMon "_import arg1" "test-pot-single" IMPORTS_CALL1_ARG1 assertEqualsMon "_import arg2" "v1.0" IMPORTS_CALL1_ARG2 assertEqualsMon "_import arg3" "test-pot-single_v1_0" IMPORTS_CALL1_ARG3 } test_pot_import_042() { pot-import -p test-pot-single -t 1.0 -U https://example.org assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "1" FETCHPOT_CALLS assertEqualsMon "_fetch_pot arg1" "test-pot-single" FETCHPOT_CALL1_ARG1 assertEqualsMon "_fetch_pot arg2" "1.0" FETCHPOT_CALL1_ARG2 assertEqualsMon "_fetch_pot arg3" "" FETCHPOT_CALL1_ARG3 assertEqualsMon "_fetch_pot arg4" "https://example.org" FETCHPOT_CALL1_ARG4 assertEqualsMon "_import calls" "1" IMPORTS_CALLS assertEqualsMon "_import arg1" "test-pot-single" IMPORTS_CALL1_ARG1 assertEqualsMon "_import arg2" "1.0" IMPORTS_CALL1_ARG2 assertEqualsMon "_import arg3" "test-pot-single_1_0" IMPORTS_CALL1_ARG3 } test_pot_import_043() { pot-import -p test-pot-single -t 1.0 -U https://example.org -C import1.sh assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_fetch_pot calls" "1" FETCHPOT_CALLS assertEqualsMon "_fetch_pot arg1" "test-pot-single" FETCHPOT_CALL1_ARG1 assertEqualsMon "_fetch_pot arg2" "1.0" FETCHPOT_CALL1_ARG2 assertEqualsMon "_fetch_pot arg3" "import1.sh" FETCHPOT_CALL1_ARG3 assertEqualsMon "_fetch_pot arg4" "https://example.org" FETCHPOT_CALL1_ARG4 assertEqualsMon "_import calls" "1" IMPORTS_CALLS assertEqualsMon "_import arg1" "test-pot-single" IMPORTS_CALL1_ARG1 assertEqualsMon "_import arg2" "1.0" IMPORTS_CALL1_ARG2 assertEqualsMon "_import arg3" "test-pot-single_1_0" IMPORTS_CALL1_ARG3 } test_pot_import_044() { pot-import -p test-pot-single -t 1.0 -U https://example.org -C nonexistent assertEquals "Exit rc" "1" "$?" } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/info1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/info.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs info-help() { __monitor HELP "$@" } _info_pot() { __monitor INFOPOT "$@" } _info_pot_env() { __monitor INFOPOTENV "$@" } _info_pot_snapshots() { __monitor INFOPOTSNAP "$@" } test_pot_info_001() { pot-info assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS setUp pot-info -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS setUp pot-info -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS setUp pot-info -v assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS } test_pot_info_002() { pot-info -p test-pot -v -q assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS setUp pot-info -p test-pot -v -q -r assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS } test_pot_info_003() { pot-info -p test-pot -B test-bridge assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS } test_pot_info_020() { pot-info -p assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS setUp pot-info -p not-a-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS } test_pot_info_021() { pot-info -p test-pot -q assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS } test_pot_info_022() { pot-info -p test-pot -qr assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS } test_pot_info_023() { pot-info -p test-pot-run -qr assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS } test_pot_info_040() { pot-info -p test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "Info calls" "1" INFOPOT_CALLS assertEqualsMon "Info arg" "test-pot" INFOPOT_CALL1_ARG1 } test_pot_info_041() { pot-info -p test-pot -v assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "Info calls" "1" INFOPOT_CALLS assertEqualsMon "Info arg" "test-pot" INFOPOT_CALL1_ARG1 } test_pot_info_042() { pot-info -p test-pot -r assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS } test_pot_info_043() { pot-info -p test-pot -s assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "Info calls" "0" INFOPOT_CALLS assertEqualsMon "InfoSnap calls" "1" INFOPOTSNAP_CALLS } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/info2.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/info.sh . ../share/pot/common.sh # common stubs _get_pot_network_stack() { echo "${_TEST_STACK:-"dual"}" } _get_pot_network_type() { case "$1" in test-pot-alias*) echo "alias" ;; *) echo "inherit" ;; esac } _get_ip_var() { case "$1" in test-pot-alias) echo "em0|192.168.0.1 em0|fe80::0" ;; *) echo "" ;; esac } _get_alias_ipv4() { if [ "$_TEST_STACK" = "ipv6" ]; then return fi case "$1" in test-pot-alias) echo "em0|192.168.0.1" ;; *) echo "" ;; esac } _get_alias_ipv6() { if [ "$_TEST_STACK" = "ipv4" ]; then return fi case "$1" in test-pot-alias) echo "em0|fe80::0" ;; *) echo "" ;; esac } # app specific stubs test_info_pot_env_001() { assertEquals "inherit has IP" "export _POT_IP=" "$(_info_pot_env test-pot-inherit | grep _POT_IP= )" } test_info_pot_env_020() { assertEquals "alias has wrong IP" "export _POT_IP=192.168.0.1" "$( _info_pot_env test-pot-alias | grep _POT_IP= )" assertEquals "alias has wrong IP LIST" "$( _info_pot_env test-pot-alias | grep _POT_IP_LIST= )" "export _POT_IP_LIST=_POT_IP_0\ _POT_IP_1" assertEquals "alias has wrong NIC LIST" "$( _info_pot_env test-pot-alias | grep _POT_NIC_LIST= )" "export _POT_NIC_LIST=_POT_NIC_0\ _POT_NIC_1" assertEquals "alias has wrong IP 0" "$( _info_pot_env test-pot-alias | grep _POT_IP_0= )" "export _POT_IP_0=192.168.0.1" assertEquals "alias has wrong IP 1" "$( _info_pot_env test-pot-alias | grep _POT_IP_1= )" "export _POT_IP_1=fe80::0" assertEquals "alias has wrong NIC 0" "$( _info_pot_env test-pot-alias | grep _POT_NIC_0= )" "export _POT_NIC_0=em0" assertEquals "alias has wrong NIC 1" "$( _info_pot_env test-pot-alias | grep _POT_NIC_1= )" "export _POT_NIC_1=em0" } test_info_pot_env_021() { _TEST_STACK="ipv4" assertEquals "alias has wrong IP" "$( _info_pot_env test-pot-alias | grep _POT_IP= )" "export _POT_IP=192.168.0.1" assertEquals "alias has wrong IP LIST" "$( _info_pot_env test-pot-alias | grep _POT_IP_LIST= )" "export _POT_IP_LIST=_POT_IP_0" assertEquals "alias has wrong NIC LIST" "$( _info_pot_env test-pot-alias | grep _POT_NIC_LIST= )" "export _POT_NIC_LIST=_POT_NIC_0" assertEquals "alias has wrong IP 0" "$( _info_pot_env test-pot-alias | grep _POT_IP_0= )" "export _POT_IP_0=192.168.0.1" assertEquals "alias has wrong NIC 0" "$( _info_pot_env test-pot-alias | grep _POT_NIC_0= )" "export _POT_NIC_0=em0" } test_info_pot_env_022() { _TEST_STACK="ipv6" assertEquals "alias has wrong IP" "$( _info_pot_env test-pot-alias | grep _POT_IP= )" "export _POT_IP=fe80::0" assertEquals "alias has wrong IP LIST" "$( _info_pot_env test-pot-alias | grep _POT_IP_LIST= )" "export _POT_IP_LIST=_POT_IP_0" assertEquals "alias has wrong NIC LIST" "$( _info_pot_env test-pot-alias | grep _POT_NIC_LIST= )" "export _POT_NIC_LIST=_POT_NIC_0" assertEquals "alias has wrong IP 0" "$( _info_pot_env test-pot-alias | grep _POT_IP_0= )" "export _POT_IP_0=fe80::0" assertEquals "alias has wrong NIC 0" "$( _info_pot_env test-pot-alias | grep _POT_NIC_0= )" "export _POT_NIC_0=em0" } . shunit/shunit2 ================================================ FILE: tests/list1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/list.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs list-help() { __monitor HELP "$@" } _ls_pots() { __monitor LSPOTS "$@" } _ls_bases() { __monitor LSBASES "$@" } _ls_fscomp() { __monitor LSFSCOMP "$@" } _ls_flavour() { __monitor LSFLAVOUR "$@" } test_pot_list_001() { pot-list -k bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS setUp pot-list -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS } test_pot_list_002() { pot-list -pb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS setUp pot-list -bp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS setUp pot-list -ba assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS setUp pot-list -fpF assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS } test_pot_list_003() { pot-list -aq assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS } test_pot_list_020() { pot-list assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "1" LSPOTS_CALLS assertEqualsMon "list_pots args" "" LSPOTS_CALL1_ARG1 assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS setUp pot-list -q assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "1" LSPOTS_CALLS assertEqualsMon "list_pots args" "quiet" LSPOTS_CALL1_ARG1 assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS } test_pot_list_021() { pot-list -p assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "1" LSPOTS_CALLS assertEqualsMon "list_pots args" "" LSPOTS_CALL1_ARG1 assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS setUp pot-list -pq assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "1" LSPOTS_CALLS assertEqualsMon "list_pots args" "quiet" LSPOTS_CALL1_ARG1 assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS } test_pot_list_022() { pot-list -b assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "1" LSBASES_CALLS assertEqualsMon "list_bases args" "" LSBASES_CALL1_ARG1 assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS setUp pot-list -bq assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "1" LSBASES_CALLS assertEqualsMon "list_bases args" "quiet" LSBASES_CALL1_ARG1 assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS } test_pot_list_023() { pot-list -f assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "1" LSFSCOMP_CALLS assertEqualsMon "list_fscomp args" "" LSFSCOMP_CALL1_ARG1 assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS setUp pot-list -fq assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "1" LSFSCOMP_CALLS assertEqualsMon "list_fscomp args" "quiet" LSFSCOMP_CALL1_ARG1 assertEqualsMon "list_flavour calls" "0" LSFLAVOUR_CALLS } test_pot_list_024() { pot-list -F assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "1" LSFLAVOUR_CALLS assertEqualsMon "list_flavour args" "" LSFLAVOUR_CALL1_ARG1 setUp pot-list -Fq assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "0" LSPOTS_CALLS assertEqualsMon "list_bases calls" "0" LSBASES_CALLS assertEqualsMon "list_fscomp calls" "0" LSFSCOMP_CALLS assertEqualsMon "list_flavour calls" "1" LSFLAVOUR_CALLS assertEqualsMon "list_flavour args" "quiet" LSFLAVOUR_CALL1_ARG1 } test_pot_list_025() { pot-list -a assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "list_pots calls" "1" LSPOTS_CALLS assertEqualsMon "list_port args" "" LSPOTS_CALL1_ARG1 assertEqualsMon "list_bases calls" "1" LSBASES_CALLS assertEqualsMon "list_bases args" "" LSBASES_CALL1_ARG1 assertEqualsMon "list_fscomp calls" "1" LSFSCOMP_CALLS assertEqualsMon "list_fscomp args" "" LSFSCOMP_CALL1_ARG1 assertEqualsMon "list_flavour calls" "1" LSFLAVOUR_CALLS assertEqualsMon "list_flavour args" "" LSFLAVOUR_CALL1_ARG1 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/list2.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/list.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs zfs() { if [ "$1" = "list" ]; then if [ "$6" = "zroot/pot1/fscomp" ]; then echo "zroot/pot1/fscomp" echo "zroot/pot1/fscomp/fscomp1" elif [ "$6" = "zroot/pot2/fscomp" ]; then echo "zroot/pot1/fscomp" echo "zroot/pot2/fscomp/fscomp1" echo "zroot/pot2/fscomp/fscomp2" elif [ "$6" = "zroot/pot3/fscomp" ]; then echo "zroot/pot1/fscomp" echo "zroot/pot3/fscomp/fscomp1" echo "zroot/pot3/fscomp/fscomp2" echo "zroot/pot3/fscomp/fscomp3" else echo "error2" fi else echo "error" fi } test_pot_list_fscomp001() { POT_ZFS_ROOT=zroot/pot1 rc=$( _ls_fscomp ) assertEquals "rc" "fscomp: fscomp1" "$rc" } test_pot_list_fscomp002() { POT_ZFS_ROOT=zroot/pot2 rc=$( _ls_fscomp | tr '\n' ' ') assertEquals "rc" "fscomp: fscomp1 fscomp: fscomp2 " "$rc" } test_pot_list_fscomp003() { POT_ZFS_ROOT=zroot/pot3 rc=$( _ls_fscomp | tr '\n' ' ') assertEquals "rc" "fscomp: fscomp1 fscomp: fscomp2 fscomp: fscomp3 " "$rc" } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/monitor.sh ================================================ #!/bin/sh # shellcheck disable=SC3043 if [ -z "$POT_MONITOR_TMP" ]; then if [ "$(command uname)" = "Linux" ]; then POT_MONITOR_TMP=/dev/shm else POT_MONITOR_TMP="${TMPDIR:-/tmp}" fi POT_MONITOR_TMP=$(command mktemp -d \ "${POT_MONITOR_TMP}/pot-monitor.XXXXXX") || exit 1 export POT_MONITOR_TMP fi __mon_put() { local k v k="$1" shift v="$*" printf %s "$v" >"$POT_MONITOR_TMP/$k" } __mon_get() { local k d r k="$1" d="$2" if [ -e "$POT_MONITOR_TMP/$k" ]; then r=$(command cat "$POT_MONITOR_TMP/$k") fi if [ -n "$r" ]; then echo "$r" elif [ -n "$d" ]; then echo "$d" fi } __mon_export() { local k v for k in "$POT_MONITOR_TMP"/*; do v=$(command cat "$k") export "$k"="$v" done } __mon_init() { command mkdir -p "$POT_MONITOR_TMP" || exit 1 command rm -f "$POT_MONITOR_TMP"/* || exit 1 } __monitor_int() { local M i C i=0 M=$1 shift C="$(__mon_get "${M}_CALLS" 0)" C=$(( C + 1 )) __mon_put "${M}_CALLS" "$C" while [ -n "$1" ] || [ -n "$2" ] || [ -n "$3" ]; do i=$(( i + 1 )) __mon_put "${M}_CALL${C}_ARG${i}" "$1" shift done } __monitor() { # requires "pkg install flock" on FreebSD ( command flock -x -w 10 9 __monitor_int "$@" ) 9>"$POT_MONITOR_TMP.lock" } __mon_tearDown() { if [ -e "$POT_MONITOR_TMP" ]; then command rm -rf "$POT_MONITOR_TMP" fi if [ -e "$POT_MONITOR_TMP.lock" ]; then command rm "$POT_MONITOR_TMP.lock" fi } # $1 name # $2 left hand # $3 key of right hand mon var # $4 default value to compare to # "" defaults to 0 in case key ends on "_CALLS" assertEqualsMon() { local n l k d n="$1" l="$2" k="$3" d="$4" if [ -z "$d" ] && [ "$k" != "${k%%_CALLS}" ]; then d="0" fi assertEquals "$n" "$l" "$(__mon_get "$k" "$d")" } # $1 name # $2 left hand # $3 key of right hand mon var # $4 default value to compare to # "" defaults to 0 in case key ends on "_CALLS" assertNotEqualsMon() { local n l k d n="$1" l="$2" k="$3" d="$4" if [ -z "$d" ] && [ "$k" != "${k%%_CALLS}" ]; then d="0" fi assertNotEquals "$n" "$l" "$(__mon_get "$k" "$d")" } ================================================ FILE: tests/mount-in1.sh ================================================ #!/bin/sh # system utilities stubs if [ "$(uname)" = "Linux" ]; then TEST=/usr/bin/[ else TEST=/bin/[ fi [() { if ${TEST} "$1" = "!" ]; then if ${TEST} "$2" = "-d" ]; then if ${TEST} "$3" = "test-dir" ]; then return 1 # false fi fi fi ${TEST} "$@" return $? } realpath() { __monitor REALPATH "$@" if [ "$2" = "test-dir" ]; then echo "/home/test-dir" return 0 # true fi return 1 # false } logger() { : } # UUT . ../share/pot/mount-in.sh # common stubs . common-stub.sh _zfs_dataset_valid() { __monitor ZDVALID "$@" if [ "$1" = "zroot/test-dataset" ]; then return 0 # true fi return 1 # false } # app specific stubs mount-in-help() { __monitor HELP "$@" return 0 # true } _directory_validation() { __monitor DIRVALID "$@" } _mountpoint_validation() { __monitor MPVALID "$@" echo "$2" } _mount_dir() { __monitor MOUNTDIR "$@" } _mount_dataset() { __monitor MOUNTDSET "$@" } test_pot_mount_in_001() { pot-mount-in assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -vb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -b bb assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_002() { pot-mount-in -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -f test-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -m /test-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -d /test-dir assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -z zroot/test-dataset assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_003() { pot-mount-in -p test-pot -f test-fscomp assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -m /test-mnt -f test-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -m /test-mnt -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_004() { pot-mount-in -p test-pot -d /test-dir assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -m /test-mnt -d /test-dir assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -m /test-mnt -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_005() { pot-mount-in -p test-pot -z zroot/test-dataset assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -m /test-mnt -z zroot/test-dataset assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -m /test-mnt -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_006() { pot-mount-in -p test-pot -m /test-mnt -z zroot/test-dataset -d /test-dir assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-pot -m /test-mnt -z zroot/test-dataset -f test-fscomp assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-pot -m /test-mnt -f test-fscomp -d /test-dir assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_zfs_dataset_valid calls" "0" ZDVALID_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_007() { pot-mount-in -p test-no-pot -m /test-no-mnt -f zroot/test-no-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-no-pot -m /test-no-mnt -z test-no-dataset assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-no-pot -m /test-no-mnt -d test-no-dir assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_008() { pot-mount-in -p test-no-pot -m /test-no-mnt -f test-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-no-pot -m /test-no-mnt -z zroot/test-dataset assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-no-pot -m /test-no-mnt -d test-dir assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_009() { pot-mount-in -p test-pot -f test-fscomp -m test-no-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-pot -d test-dir -m test-no-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-pot -z zroot/test-dataset -m test-no-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_010() { pot-mount-in -p test-pot -f test-fscomp -m / assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-pot -d test-dir -m / assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-pot -z zroot/test-dataset -m / assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_011() { pot-mount-in -p test-pot -f test-fscomp -m "/mnt/with space" assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-pot -d test-dir -m "/mnt/with space" assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS setUp pot-mount-in -p test-pot -z zroot/test-dataset -m "/mnt/with space" assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS pot-mount-in -p test-pot -f test-fscomp -m "/mnt/space " assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS } test_pot_mount_in_020() { pot-mount-in -p test-pot -f test-fscomp -m /test-mnt assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_mount_dataset calls" "1" MOUNTDSET_CALLS assertEqualsMon "_mount_dataset arg" "zpot/fscomp/test-fscomp" MOUNTDSET_CALL1_ARG1 assertEqualsMon "_mount_dataset arg" "test-pot" MOUNTDSET_CALL1_ARG2 assertEqualsMon "_mount_dataset arg" "/test-mnt" MOUNTDSET_CALL1_ARG3 assertEqualsMon "_mount_dataset arg" "" MOUNTDSET_CALL1_ARG4 assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS } test_pot_mount_in_021() { pot-mount-in -p test-pot -f test-fscomp -m /test-mnt -r assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_mount_dataset calls" "1" MOUNTDSET_CALLS assertEqualsMon "_mount_dataset arg" "zpot/fscomp/test-fscomp" MOUNTDSET_CALL1_ARG1 assertEqualsMon "_mount_dataset arg" "test-pot" MOUNTDSET_CALL1_ARG2 assertEqualsMon "_mount_dataset arg" "/test-mnt" MOUNTDSET_CALL1_ARG3 assertEqualsMon "_mount_dataset arg" "ro" MOUNTDSET_CALL1_ARG4 assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS } test_pot_mount_in_022() { pot-mount-in -p test-pot -f test-fscomp -m /test-mnt -w assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_mount_dataset calls" "1" MOUNTDSET_CALLS assertEqualsMon "_mount_dataset arg" "zpot/fscomp/test-fscomp" MOUNTDSET_CALL1_ARG1 assertEqualsMon "_mount_dataset arg" "test-pot" MOUNTDSET_CALL1_ARG2 assertEqualsMon "_mount_dataset arg" "/test-mnt" MOUNTDSET_CALL1_ARG3 assertEqualsMon "_mount_dataset arg" "zfs-remount" MOUNTDSET_CALL1_ARG4 assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS } test_pot_mount_in_040() { pot-mount-in -p test-pot -z zroot/test-dataset -m /test-mnt assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_mount_dataset calls" "1" MOUNTDSET_CALLS assertEqualsMon "_mount_dataset arg" "zroot/test-dataset" MOUNTDSET_CALL1_ARG1 assertEqualsMon "_mount_dataset arg" "test-pot" MOUNTDSET_CALL1_ARG2 assertEqualsMon "_mount_dataset arg" "/test-mnt" MOUNTDSET_CALL1_ARG3 assertEqualsMon "_mount_dataset arg" "" MOUNTDSET_CALL1_ARG4 assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS } test_pot_mount_in_041() { pot-mount-in -p test-pot -z zroot/test-dataset -m /test-mnt -r assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_mount_dataset calls" "1" MOUNTDSET_CALLS assertEqualsMon "_mount_dataset arg" "zroot/test-dataset" MOUNTDSET_CALL1_ARG1 assertEqualsMon "_mount_dataset arg" "test-pot" MOUNTDSET_CALL1_ARG2 assertEqualsMon "_mount_dataset arg" "/test-mnt" MOUNTDSET_CALL1_ARG3 assertEqualsMon "_mount_dataset arg" "ro" MOUNTDSET_CALL1_ARG4 assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS } test_pot_mount_in_042() { pot-mount-in -p test-pot -z zroot/test-dataset -m /test-mnt -w assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_mount_dataset calls" "1" MOUNTDSET_CALLS assertEqualsMon "_mount_dataset arg" "zroot/test-dataset" MOUNTDSET_CALL1_ARG1 assertEqualsMon "_mount_dataset arg" "test-pot" MOUNTDSET_CALL1_ARG2 assertEqualsMon "_mount_dataset arg" "/test-mnt" MOUNTDSET_CALL1_ARG3 assertEqualsMon "_mount_dataset arg" "zfs-remount" MOUNTDSET_CALL1_ARG4 assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS } test_pot_mount_in_060() { pot-mount-in -p test-pot -d test-dir -m /test-mnt assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS assertEqualsMon "_mount_dir calls" "1" MOUNTDIR_CALLS assertEqualsMon "_mount_dir arg" "/home/test-dir" MOUNTDIR_CALL1_ARG1 assertEqualsMon "_mount_dir arg" "test-pot" MOUNTDIR_CALL1_ARG2 assertEqualsMon "_mount_dir arg" "/test-mnt" MOUNTDIR_CALL1_ARG3 assertEqualsMon "_mount_dir arg" "" MOUNTDIR_CALL1_ARG4 } test_pot_mount_in_061() { pot-mount-in -p test-pot -d test-dir -m /test-mnt -r assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS assertEqualsMon "_mount_dir calls" "1" MOUNTDIR_CALLS assertEqualsMon "_mount_dir arg" "/home/test-dir" MOUNTDIR_CALL1_ARG1 assertEqualsMon "_mount_dir arg" "test-pot" MOUNTDIR_CALL1_ARG2 assertEqualsMon "_mount_dir arg" "/test-mnt" MOUNTDIR_CALL1_ARG3 assertEqualsMon "_mount_dir arg" "ro" MOUNTDIR_CALL1_ARG4 } test_pot_mount_in_062() { pot-mount-in -p test-pot -d test-dir -m /test-mnt -w assertEquals "Exit rc" "1" "$?" assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_mount_dataset calls" "0" MOUNTDSET_CALLS assertEqualsMon "_mount_dir calls" "0" MOUNTDIR_CALLS } setUp() { common_setUp POT_FS_ROOT=/tmp POT_ZFS_ROOT=zpot } . shunit/shunit2 ================================================ FILE: tests/mount-out1.sh ================================================ #!/bin/sh # system utilities stubs if [ "$(uname)" = "Linux" ]; then TEST=/usr/bin/[ else TEST=/bin/[ fi [() { if ${TEST} "$1" = "!" ]; then if ${TEST} "$2" = "-d" ]; then if ${TEST} "$3" = "test-dir" ]; then return 1 # false fi fi fi ${TEST} "$@" return $? } realpath() { __monitor REALPATH "$@" if [ "$2" = "test-dir" ]; then echo "/home/test-dir" return 0 # true fi return 1 # false } logger() { : } # UUT . ../share/pot/mount-out.sh # common stubs . common-stub.sh # app specific stubs mount-out-help() { __monitor HELP "$@" return 0 # true } _mountpoint_validation() { __monitor MPVALID "$@" echo "$2" } _umount_mnt_p() { __monitor UMNT_P "$@" } test_pot_mount_in_001() { pot-mount-out assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_umount_mnt_p calls" "0" UMNT_P_CALLS setUp pot-mount-out -vb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_umount_mnt_p calls" "0" UMNT_P_CALLS setUp pot-mount-out -b bb assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_umount_mnt_p calls" "0" UMNT_P_CALLS setUp pot-mount-out -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_umount_mnt_p calls" "0" UMNT_P_CALLS } test_pot_mount_in_002() { pot-mount-out -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_umount_mnt_p calls" "0" UMNT_P_CALLS setUp pot-mount-out -m /test-mnt assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "0" ISUID0_CALLS assertEqualsMon "_umount_mnt_p calls" "0" UMNT_P_CALLS } test_pot_mount_in_020() { pot-mount-out -p test-pot -m /test-mnt assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_uid0 calls" "1" ISUID0_CALLS assertEqualsMon "_umount_mnt_p calls" "1" UMNT_P_CALLS assertEqualsMon "_umount_mnt_p arg" "test-pot" UMNT_P_CALL1_ARG1 assertEqualsMon "_umount_mnt_p arg" "/test-mnt" UMNT_P_CALL1_ARG2 } setUp() { common_setUp POT_FS_ROOT=/tmp POT_ZFS_ROOT=zpot } . shunit/shunit2 ================================================ FILE: tests/network1.sh ================================================ #!/bin/sh # system utilities stubs ifconfig() { if [ -z "$1" ]; then cat << EOF-- em0: flags=8843 metric 0 mtu 1500 options=200080 inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.178.255 ether e4:b3:18:d8:4d:25 hwaddr c8:5b:76:3a:2f:96 nd6 options=29 media: Ethernet autoselect status: no carrier em1: flags=8843 metric 0 mtu 1500 options=200080 inet 10.192.168.2 netmask 0xffffff00 broadcast 10.192.168.255 ether e4:b3:18:d8:4d:45 hwaddr c8:5b:76:3a:2f:a6 nd6 options=29 media: Ethernet autoselect status: no carrier bce0: flags=8843 metric 0 mtu 1500 options=200080 inet 10.192.168.3 netmask 0xffffff00 broadcast 10.192.168.255 ether e4:b3:18:d8:4d:35 hwaddr c8:5b:76:3a:2f:b6 nd6 options=29 media: Ethernet autoselect status: no carrier lo0: flags=8049 metric 0 mtu 16384 options=600003 inet6 ::1 prefixlen 128 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2 inet 127.0.0.1 netmask 0xff000000 nd6 options=21 groups: lo bridge0: flags=8843 metric 0 mtu 1500 ether 02:87:a9:03:d7:00 inet 10.192.0.111 netmask 0xffc00000 broadcast 10.255.255.255 nd6 options=1 groups: bridge id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200 root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0 bridge1: flags=8843 metric 0 mtu 1500 ether 02:87:a9:03:d7:00 inet 10.192.0.11 netmask 0xffc00000 broadcast 10.255.255.255 nd6 options=1 groups: bridge id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200 root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0 bridge2: flags=8843 metric 0 mtu 1500 ether 02:87:a9:03:d7:00 inet 10.192.0.1 netmask 0xffc00000 broadcast 10.255.255.255 nd6 options=1 groups: bridge id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200 root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0 EOF-- return 0 # true elif [ "$1" = "-g" ] && [ "$2" = "bridge" ]; then cat << EOF-- bridge0 bridge1 bridge2 EOF-- return 0 # true elif [ "$1" = "bridge0" ]; then cat << EOF-- bridge0: flags=8843 metric 0 mtu 1500 inet 10.192.0.111 netmask 0xffc00000 broadcast 10.255.255.255 EOF-- return 0 # true elif [ "$1" = "bridge1" ]; then cat << EOF-- bridge1: flags=8843 metric 0 mtu 1500 inet 10.192.0.11 netmask 0xffc00000 broadcast 10.255.255.255 EOF-- return 0 # true elif [ "$1" = "bridge2" ]; then cat << EOF-- bridge2: flags=8843 metric 0 mtu 1500 inet 10.192.0.1 netmask 0xffc00000 broadcast 10.255.255.255 EOF-- return 0 # true elif [ "$1" = "em0" ]; then cat << EOF-- em0: flags=8843 metric 0 mtu 1500 options=200080 inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.178.255 ether e4:b3:18:d8:4d:25 hwaddr c8:5b:76:3a:2f:96 nd6 options=29 media: Ethernet autoselect status: no carrier EOF-- return 0 # true elif [ "$1" = "em1" ]; then cat << EOF-- em1: flags=8843 metric 0 mtu 1500 options=200080 inet 10.192.168.1 netmask 0xffffff00 broadcast 10.192.168.255 ether e4:b3:18:d8:4d:25 hwaddr c8:5b:76:3a:2f:96 nd6 options=29 media: Ethernet autoselect status: no carrier EOF-- return 0 # true elif [ "$1" = "bce0" ]; then cat << EOF-- bce0: flags=8843 metric 0 mtu 1500 options=200080 inet 10.192.168.3 netmask 0xffffff00 broadcast 10.192.168.255 ether e4:b3:18:d8:4d:35 hwaddr c8:5b:76:3a:2f:b6 nd6 options=29 media: Ethernet autoselect status: no carrier EOF-- return 0 # true else return 1 # false fi } # system utilities stubs potnet() { if [ "$1" = "next" ]; then if [ -n "$3" ]; then echo "10.192.123.234" else echo "10.192.123.123" fi return 0 # true fi if [ "$1" = "validate" ] && [ "$2" = "-H" ] ; then if [ "$3" = "10.192.123.123" ] || [ "$3" = "10.192.123.234" ] || [ "$3" = "10.1.10.10" ]; then return 0 # true fi fi if [ "$1" = "ipcheck" ]; then case "$3" in 192.168.200.200|10.192.123.234|10.1.10.10) ;; 2a0a:fade:dead:01e::80|2a0a:fade:dead:01e::443) ;; *) return 1 ;; esac return 0 # true fi if [ "$1" = "ip4check" ]; then case "$3" in 192.168.200.200|10.192.123.234|10.1.10.10) ;; *) return 1 ;; esac return 0 # true fi if [ "$1" = "ip6check" ]; then case "$3" in 2a0a:fade:dead:01e::80|2a0a:fade:dead:01e::443) ;; *) return 1 ;; esac return 0 # true fi return 1 # false } # UUT . ../share/pot/network.sh . ../share/pot/common.sh # add common stub _is_vnet_available() { return 0 # true } _is_potnet_available() { return 0 # true } _get_network_stack() { if [ -z "$STUB_STACK" ]; then echo dual else echo "$STUB_STACK" fi } _get_pot_network_stack() { _get_network_stack } _is_bridge() { case "$1" in test-bridge) return 0 # return true ;; esac return 1 # false } # app specific stubs test_get_pot_rdr_anchor_name_001() { _rc="$(_get_pot_rdr_anchor_name "test-pot" )" assertEquals "test-pot" "$_rc" } test_get_pot_rdr_anchor_name_002() { _rc="$(_get_pot_rdr_anchor_name "0123456789012345678901234567890123456789012345678901234" )" assertEquals "0123456789012345678901234567890123456789012345678901234" "$_rc" } test_get_pot_rdr_anchor_name_003() { _rc="$(_get_pot_rdr_anchor_name "01234567890123456789012345678901234567890123456789012345" )" assertEquals "1234567890123456789012345678901234567890123456789012345" "$_rc" } test_get_pot_rdr_anchor_name_004() { _rc="$(_get_pot_rdr_anchor_name "012345678901234567890123456789012345678901234567890123456789" )" assertEquals "5678901234567890123456789012345678901234567890123456789" "$_rc" } test_get_pot_rdr_anchor_name_005() { _rc="$(_get_pot_rdr_anchor_name "01234_678901234567890123456789012345678901234567890123456789" )" assertEquals "678901234567890123456789012345678901234567890123456789" "$_rc" } test_get_pot_rdr_anchor_name_006() { _rc="$(_get_pot_rdr_anchor_name "01234___8901234567890123456789012345678901234567890123456789" )" assertEquals "8901234567890123456789012345678901234567890123456789" "$_rc" } test_pot_bridge_001() { # shellcheck disable=SC2039 local _rc POT_GATEWAY=10.192.0.111 _rc="$(_pot_bridge )" assertEquals "bridge0" "$_rc" POT_GATEWAY=192.168.0.1 _rc="$(_pot_bridge )" assertEquals "" "$_rc" POT_GATEWAY=10.192.0.1 _rc="$(_pot_bridge )" assertEquals "bridge2" "$_rc" } test_pot_is_valid_netif_001() { _is_valid_netif bridge2 assertTrue "netif not recognized" "$?" } test_pot_is_valid_netif_002() { _is_valid_netif not-netif assertFalse "netif wrongly recognized" "$?" } test_validate_alias_ipaddr_001() { assertTrue "address not recognized" '_validate_alias_ipaddr "192.168.200.200" "dual"' } test_get_alias_ipv4_001() { ipaddr="192.168.200.200" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "bce0|192.168.200.200" "$output" STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "bce0|192.168.200.200" "$output" STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "bce0|192.168.200.200" "$output" STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "" "$output" } test_validate_alias_ipaddr_002() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "em0|192.168.200.200" "dual"' } test_get_alias_ipv4_002() { ipaddr="em0|192.168.200.200" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200" "$output" STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200" "$output" STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200" "$output" STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "" "$output" } test_validate_alias_ipaddr_003() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "em0|192.168.200.200 10.1.10.10" "dual"' } test_get_alias_ipv4_003() { ipaddr="em0|192.168.200.200 10.1.10.10" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200,bce0|10.1.10.10" "$output" STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200,bce0|10.1.10.10" "$output" STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200,bce0|10.1.10.10" "$output" STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "" "$output" } test_validate_alias_ipaddr_004() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "10.1.10.10 em0|192.168.200.200" "dual"' } test_get_alias_ipv4_004() { ipaddr="10.1.10.10 em0|192.168.200.200" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "bce0|10.1.10.10,em0|192.168.200.200" "$output" STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "bce0|10.1.10.10,em0|192.168.200.200" "$output" STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "bce0|10.1.10.10,em0|192.168.200.200" "$output" STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "" "$output" } test_validate_alias_ipaddr_005() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "em0|192.168.200.200 em1|10.1.10.10" "dual"' } test_get_alias_ipv4_005() { ipaddr="em0|192.168.200.200 em1|10.1.10.10" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200,em1|10.1.10.10" "$output" STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200,em1|10.1.10.10" "$output" STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200,em1|10.1.10.10" "$output" STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "" "$output" } test_validate_alias_ipaddr_006() { assertFalse "NIC|address shouldn't be accepted" '_validate_alias_ipaddr "em0|192.168.200.200 em1|10.1.10.10" "ipv6"' } test_validate_alias_ipaddr_010() { assertTrue "address not recognized" '_validate_alias_ipaddr "2a0a:fade:dead:01e::80" "dual"' } test_get_alias_ipv4_010() { ipaddr="2a0a:fade:dead:01e::80" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' } test_validate_alias_ipaddr_011() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "em0|2a0a:fade:dead:01e::80" "dual"' } test_get_alias_ipv4_011() { ipaddr="em0|2a0a:fade:dead:01e::80" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' } test_validate_alias_ipaddr_012() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "em0|2a0a:fade:dead:01e::80 2a0a:fade:dead:01e::443" "dual"' } test_get_alias_ipv4_012() { ipaddr="em0|2a0a:fade:dead:01e::80 2a0a:fade:dead:01e::443" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' } test_validate_alias_ipaddr_013() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "2a0a:fade:dead:01e::443 em0|2a0a:fade:dead:01e::80" "dual"' } test_get_alias_ipv4_013() { ipaddr="2a0a:fade:dead:01e::443 em0|2a0a:fade:dead:01e::80" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' } test_validate_alias_ipaddr_014() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "em0|2a0a:fade:dead:01e::80 em1|2a0a:fade:dead:01e::443" "dual"' } test_get_alias_ipv4_014() { ipaddr="em0|2a0a:fade:dead:01e::80 em1|2a0a:fade:dead:01e::443" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' } test_validate_alias_ipaddr_015() { assertFalse "NIC|address shouldn't be accepted" '_validate_alias_ipaddr "em0|2a0a:fade:dead:01e::80 em1|2a0a:fade:dead:01e::443" "ipv4"' } test_validate_alias_ipaddr_020() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "em0|2a0a:fade:dead:01e::80 em1|192.168.200.200" "dual"' } test_get_alias_ipv4_020() { ipaddr="em0|2a0a:fade:dead:01e::80 em1|192.168.200.200" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em1|192.168.200.200" "$output" STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em1|192.168.200.200" "$output" STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em1|192.168.200.200" "$output" STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' } test_validate_alias_ipaddr_021() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "em0|2a0a:fade:dead:01e::80 em0|192.168.200.200" "dual"' } test_get_alias_ipv4_021() { ipaddr="em0|2a0a:fade:dead:01e::80 em0|192.168.200.200" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200" "$output" STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200" "$output" STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "em0|192.168.200.200" "$output" STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' } test_validate_alias_ipaddr_022() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "2a0a:fade:dead:01e::80 192.168.200.200" "dual"' } test_get_alias_ipv4_022() { ipaddr="2a0a:fade:dead:01e::80 192.168.200.200" output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "bce0|192.168.200.200" "$output" STUB_STACK=ipv4 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "bce0|192.168.200.200" "$output" STUB_STACK=dual output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertEquals "alias_ipv4 is wrong" "bce0|192.168.200.200" "$output" STUB_STACK=ipv6 output="$( _get_alias_ipv4 test-pot "$ipaddr")" assertTrue "alias_ipv4 is wrong" '[ -z "$output"]' } test_validate_alias_ipaddr_023() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "2a0a:fade:dead:01e::80 192.168.200.200" "ipv4"' } test_validate_alias_ipaddr_024() { assertTrue "NIC|address not recognized" '_validate_alias_ipaddr "2a0a:fade:dead:01e::80 192.168.200.200" "ipv6"' } test_validate_network_param_001() { if ipaddr="$(_validate_network_param "no-network")" ; then fail "Invalid network type not recognized" else assertContains "Wrong error message" "$ipaddr" 'no-network' fi } test_validate_network_param_002() { if ipaddr="$(_validate_network_param "no-network" "ignored1" "ignored2")" ; then fail "Invalid network type not recognized" else assertContains "Wrong error message" "$ipaddr" 'no-network' fi } test_validate_network_param_010() { if ipaddr="$(_validate_network_param "inherit" "ignored1" "ignored2")" ; then assertTrue "ip addr should be empty" "[ -z $ipaddr ]" else fail "Valid inherit config not recognized" fi } test_validate_network_param_020() { if ipaddr="$(_validate_network_param "alias" "" "")" ; then fail "Invalid alias config not recognized" else assertContains "Wrong error message" "$ipaddr" 'mandatory' fi } test_validate_network_param_021() { if ipaddr="$(_validate_network_param "alias" "auto" "no-bridge")" ; then fail "Invalid alias config not recognized" else assertContains "Wrong error message" "$ipaddr" 'auto' fi } test_validate_network_param_022() { if ipaddr="$(_validate_network_param "alias" "500.0.0.1" "no-bridge")" ; then fail "Invalid alias config not recognized" else assertContains "Wrong error message" "$ipaddr" "500.0.0.1" fi } test_validate_network_param_023() { if ipaddr="$(_validate_network_param "alias" "192.168.200.200" "no-bridge")" ; then assertEquals "Wrong ip returned " "192.168.200.200" "$ipaddr" else fail "Valid alias config not recognized" fi } test_validate_network_param_024() { if ipaddr="$(_validate_network_param "alias" "em0|192.168.200.200" "no-bridge")" ; then assertEquals "Wrong ip returned " "em0|192.168.200.200" "$ipaddr" else fail "Valid alias config not recognized" fi } test_validate_network_param_025() { if ipaddr="$(_validate_network_param "alias" "em0|192.168.200.200 10.1.10.10" "no-bridge")" ; then assertEquals "Wrong ip returned " "em0|192.168.200.200 10.1.10.10" "$ipaddr" else fail "Valid alias config not recognized" fi } test_validate_network_param_026() { if ipaddr="$(_validate_network_param "alias" "em0|192.168.200.200 em1|10.1.10.10" "no-bridge")" ; then assertEquals "Wrong ip returned " "em0|192.168.200.200 em1|10.1.10.10" "$ipaddr" else fail "Valid alias config not recognized" fi } test_validate_network_param_027() { if ipaddr="$(_validate_network_param "alias" "em0|192.168.200.200 em1|10.1.10.10" "" "dual")" ; then assertEquals "Wrong ip returned " "em0|192.168.200.200 em1|10.1.10.10" "$ipaddr" else fail "Valid alias config not recognized" fi } test_validate_network_param_028() { if ipaddr="$(_validate_network_param "alias" "em0|192.168.200.200 em1|10.1.10.10" "" "ipv4")" ; then assertEquals "Wrong ip returned " "em0|192.168.200.200 em1|10.1.10.10" "$ipaddr" else fail "Valid alias config not recognized" fi } test_validate_network_param_029() { if ipaddr="$(_validate_network_param "alias" "em0|192.168.200.200 em1|10.1.10.10" "" "ipv6")" ; then fail "Invalid alias config not recognized" else assertContains "Wrong error message" "$ipaddr" "ipv6" assertContains "Wrong error message" "$ipaddr" "em0|192.168.200.200 em1|10.1.10.10" fi } test_validate_network_param_040() { if ipaddr="$(_validate_network_param "public-bridge" "500.0.0.1" "no-bridge")" ; then fail "Invalid public-bridge config not recognized" else assertContains "Wrong error message" "$ipaddr" "500.0.0.1" fi } test_validate_network_param_041() { if ipaddr="$(_validate_network_param "public-bridge" "" "")" ; then assertEquals "Wrong ip returned " "10.192.123.123" "$ipaddr" else fail "Valid public-bridge config not recognized - $ipaddr" fi } test_validate_network_param_042() { if ipaddr="$(_validate_network_param "public-bridge" "10.192.123.123" "no-bridge")" ; then assertEquals "Wrong ip returned " "10.192.123.123" "$ipaddr" else fail "Valid public-bridge config not recognized - $ipaddr" fi } test_validate_network_param_043() { if ipaddr="$(_validate_network_param "public-bridge" "auto" "no-bridge")" ; then assertEquals "Wrong ip returned " "10.192.123.123" "$ipaddr" else fail "Valid public-bridge config not recognized - $ipaddr" fi } test_validate_network_param_060() { if ipaddr="$(_validate_network_param "private-bridge" "auto" "")" ; then fail "Valid public-bridge config not recognized" else assertContains "Wrong error message" "$ipaddr" "-B" fi } test_validate_network_param_061() { if ipaddr="$(_validate_network_param "private-bridge" "auto" "no-bridge")" ; then fail "Valid public-bridge config not recognized" else assertContains "Wrong error message" "$ipaddr" "no-bridge" fi } test_validate_network_param_062() { STUB_STACK="ipv6" if ipaddr="$(_validate_network_param "private-bridge" "auto" "test-bridge")" ; then fail "Valid public-bridge config not recognized" else assertContains "Wrong error message" "$ipaddr" "ipv6" fi } test_validate_network_param_063() { if ipaddr="$(_validate_network_param "private-bridge" "500.0.0.1" "test-bridge")" ; then fail "Valid public-bridge config not recognized" else assertContains "Wrong error message" "$ipaddr" "500.0.0.1" fi } test_validate_network_param_070() { if ipaddr="$(_validate_network_param "private-bridge" "auto" "test-bridge")" ; then assertEquals "Wrong ip returned " "10.192.123.234" "$ipaddr" else fail "Valid private-bridge config not recognized - $ipaddr" fi } test_validate_network_param_071() { if ipaddr="$(_validate_network_param "private-bridge" "" "test-bridge")" ; then assertEquals "Wrong ip returned " "10.192.123.234" "$ipaddr" else fail "Valid private-bridge config not recognized - $ipaddr" fi } test_validate_network_param_072() { if ipaddr="$(_validate_network_param "private-bridge" "10.192.123.234" "test-bridge")" ; then assertEquals "Wrong ip returned " "10.192.123.234" "$ipaddr" else fail "Valid private-bridge config not recognized - $ipaddr" fi } test_is_export_port_valid_001() { _is_export_port_valid assertFalse "empty argument not recognized" "$?" } test_is_export_port_valid_002() { _is_export_port_valid ssh assertFalse "port as a name should cause an error" "$?" _is_export_port_valid ssh:8080 assertFalse "port as a name should cause an error" "$?" _is_export_port_valid 8080:ssh assertFalse "port as a name should cause an error" "$?" } test_is_export_port_valid_003() { _is_export_port_valid 80000 assertFalse "invalid port number should cause an error" "$?" _is_export_port_valid 80000:8080 assertFalse "invalid port number should cause an error" "$?" _is_export_port_valid 8080:80000 assertFalse "invalid port number should cause an error" "$?" _is_export_port_valid -22 assertFalse "negative port number should cause an error" "$?" _is_export_port_valid -22:8080 assertFalse "negative port number should cause an error" "$?" _is_export_port_valid 8080:-22 assertFalse "negative port number should cause an error" "$?" } test_is_export_port_valid_004() { _is_export_port_valid udp:80000 assertFalse "invalid port number should cause an error" "$?" _is_export_port_valid udp:80000:8080 assertFalse "invalid port number should cause an error" "$?" _is_export_port_valid udp:8080:80000 assertFalse "invalid port number should cause an error" "$?" _is_export_port_valid udp:-22 assertFalse "negative port number should cause an error" "$?" _is_export_port_valid udp:-22:8080 assertFalse "negative port number should cause an error" "$?" _is_export_port_valid udp:8080:-22 assertFalse "negative port number should cause an error" "$?" } test_is_export_port_valid_005() { _is_export_port_valid tcp:80000 assertFalse "invalid port number should cause an error" "$?" _is_export_port_valid tcp:80000:8080 assertFalse "invalid port number should cause an error" "$?" _is_export_port_valid tcp:8080:80000 assertFalse "invalid port number should cause an error" "$?" _is_export_port_valid tcp:-22 assertFalse "negative port number should cause an error" "$?" _is_export_port_valid tcp:-22:8080 assertFalse "negative port number should cause an error" "$?" _is_export_port_valid tcp:8080:-22 assertFalse "negative port number should cause an error" "$?" } test_is_export_port_valid_010() { _is_export_port_valid 8080 assertTrue "valid port should be accepted" "$?" _is_export_port_valid 8080:8080 assertTrue "valid port should be accepted" "$?" } test_is_export_port_valid_011() { _is_export_port_valid udp:8080 assertTrue "valid port should be accepted" "$?" _is_export_port_valid udp:8080:8080 assertTrue "valid port should be accepted" "$?" } test_is_export_port_valid_012() { _is_export_port_valid tcp:8080 assertTrue "valid port should be accepted" "$?" _is_export_port_valid tcp:8080:8080 assertTrue "valid port should be accepted" "$?" } setUp() { _POT_VERBOSITY=1 POT_EXTIF="bce0" STUB_STACK= } . shunit/shunit2 ================================================ FILE: tests/pipefail-stub.sh ================================================ #!/bin/sh _set_pipefail() { local _major _version if [ "$(uname)" = "Linux" ]; then set -o pipefail return fi _major="$(sysctl -n kern.osrelease | cut -f 1 -d '.')" _version="$(sysctl -n kern.osrelease | cut -f 1 -d '-')" if [ "$_major" -ge "13" ]; then set -o pipefail return fi case "$_version" in "12.1") set -o pipefail ;; esac } ================================================ FILE: tests/ps1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/ps.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs ps-help() { __monitor HELP "$@" } _ps_pots() { __monitor PSPOTS "$@" } _is_vnet_up() { return 0 # true } test_pot_ps_001() { pot-ps -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "ps_pots calls" "0" PSPOTS_CALLS setUp pot-ps -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "ps_pots calls" "0" PSPOTS_CALLS } test_pot_ps_020() { pot-ps -q assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "ps_pots calls" "1" PSPOTS_CALLS assertEqualsMon "ps_pots arg1" "quiet" PSPOTS_CALL1_ARG1 } test_pot_ps_021() { pot-ps assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "ps_pots calls" "1" PSPOTS_CALLS assertEqualsMon "ps_pots arg1" "" PSPOTS_CALL1_ARG1 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/rename1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/rename.sh # common stubs . common-stub.sh # app specific stubs rename-help() { __monitor HELP "$@" } _rn_conf() { __monitor RNCONF "$@" } _rn_zfs() { __monitor RNZFS "$@" } _rn_recursive() { __monitor RNRECURSIVE "$@" } test_pot_rename_001() { pot-rename assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS setUp pot-rename -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS setUp pot-rename -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS setUp pot-rename -va assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS } test_pot_rename_002() { pot-rename -p test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS setUp pot-rename -n test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS } test_pot_rename_003() { pot-rename -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS setUp pot-rename -n test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS } test_pot_rename_004() { pot-rename -p test-pot -n test-pot-2 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS } test_pot_rename_005() { pot-rename -p no-test-pot -n no-test-pot-2 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS } test_pot_rename_006() { pot-rename -p test-pot-run -n test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_rn_conf calls" "0" RNCONF_CALLS assertEqualsMon "_rn_zfs calls" "0" RNZFS_CALLS assertEqualsMon "_rn_recursive calls" "0" RNRECURSIVE_CALLS } test_pot_rename_020() { pot-rename -p test-pot -n test-no-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_rn_conf calls" "1" RNCONF_CALLS assertEqualsMon "_rn_conf args" "test-pot" RNCONF_CALL1_ARG1 assertEqualsMon "_rn_conf args" "test-no-pot" RNCONF_CALL1_ARG2 assertEqualsMon "_rn_zfs calls" "1" RNZFS_CALLS assertEqualsMon "_rn_zfs args" "test-pot" RNZFS_CALL1_ARG1 assertEqualsMon "_rn_zfs args" "test-no-pot" RNZFS_CALL1_ARG2 assertEqualsMon "_rn_recursive calls" "1" RNRECURSIVE_CALLS assertEqualsMon "_rn_recursive args" "test-pot" RNRECURSIVE_CALL1_ARG1 assertEqualsMon "_rn_recursive args" "test-no-pot" RNRECURSIVE_CALL1_ARG2 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/rename2.sh ================================================ #!/bin/sh # system utilities stubs SED=sed_stub sed_stub() { if [ "$(uname)" = "Linux" ]; then sed -i'' "$3" "$4" "$5" else sed "$@" fi } # UUT . ../share/pot/rename.sh # common stubs . common-stub.sh . conf-stub.sh # app specific stubs hostname() { echo "test" } test_rn_conf_001() { _rn_conf test-pot new-pot assertEquals "fscomp args1" "zpot/bases/11.1 /tmp/jails/new-pot/m ro" "$(sed '1!d' /tmp/jails/test-pot/conf/fscomp.conf)" assertEquals "fscomp args2" "zpot/jails/new-pot/usr.local /tmp/jails/new-pot/m/usr/local zfs-remount" "$(sed '2!d' /tmp/jails/test-pot/conf/fscomp.conf)" assertEquals "fscomp args3" "zpot/jails/new-pot/custom /tmp/jails/new-pot/m/opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/test-pot/conf/fscomp.conf)" assertEquals "host.hostname" "host.hostname=\"new-pot.test\"" "$(grep ^host.hostname /tmp/jails/test-pot/conf/pot.conf)" } setUp() { common_setUp conf_setUp } tearDown() { common_tearDown conf_tearDown } . shunit/shunit2 ================================================ FILE: tests/rename3.sh ================================================ #!/bin/sh # system utilities stubs zfs() { __monitor ZFS "$@" } # UUT . ../share/pot/rename.sh # common stubs . common-stub.sh _zfs_dataset_valid() { __monitor ZDVALID "$@" case "$1" in ${POT_ZFS_ROOT}/jails/test-pot|\ ${POT_ZFS_ROOT}/jails/test-pot/usr.local|\ ${POT_ZFS_ROOT}/jails/test-pot/custom|\ ${POT_ZFS_ROOT}/jails/test-pot-2|\ ${POT_ZFS_ROOT}/jails/test-pot-2/custom|\ ${POT_ZFS_ROOT}/jails/new-pot/usr.local|\ ${POT_ZFS_ROOT}/jails/test-pot-single|\ ${POT_ZFS_ROOT}/jails/test-pot-single/m|\ ${POT_ZFS_ROOT}/jails/new-pot-single/m) return 0 # true ;; esac return 1 # false } # app specific stubs test_rn_zfs_001() { _rn_zfs test-pot new-pot assertEqualsMon "_zfs_dataset_valid calls" "4" ZDVALID_CALLS assertEqualsMon "zfs calls" "9" ZFS_CALLS assertEqualsMon "zfs c1 arg1" "umount" ZFS_CALL1_ARG1 assertEqualsMon "zfs c1 arg2" "-f" ZFS_CALL1_ARG2 assertEqualsMon "zfs c1 arg3" "${POT_ZFS_ROOT}/jails/test-pot/usr.local" ZFS_CALL1_ARG3 assertEqualsMon "zfs c2 arg1" "set" ZFS_CALL2_ARG1 assertEqualsMon "zfs c2 arg2" "mountpoint=/jails/new-pot/usr.local" ZFS_CALL2_ARG2 assertEqualsMon "zfs c2 arg3" "${POT_ZFS_ROOT}/jails/test-pot/usr.local" ZFS_CALL2_ARG3 assertEqualsMon "zfs c3 arg1" "umount" ZFS_CALL3_ARG1 assertEqualsMon "zfs c3 arg2" "-f" ZFS_CALL3_ARG2 assertEqualsMon "zfs c3 arg3" "${POT_ZFS_ROOT}/jails/test-pot/custom" ZFS_CALL3_ARG3 assertEqualsMon "zfs c4 arg1" "set" ZFS_CALL4_ARG1 assertEqualsMon "zfs c4 arg2" "mountpoint=/jails/new-pot/custom" ZFS_CALL4_ARG2 assertEqualsMon "zfs c4 arg3" "${POT_ZFS_ROOT}/jails/test-pot/custom" ZFS_CALL4_ARG3 assertEqualsMon "zfs c5 arg1" "umount" ZFS_CALL5_ARG1 assertEqualsMon "zfs c5 arg2" "-f" ZFS_CALL5_ARG2 assertEqualsMon "zfs c5 arg3" "${POT_ZFS_ROOT}/jails/test-pot" ZFS_CALL5_ARG3 assertEqualsMon "zfs c6 arg1" "rename" ZFS_CALL6_ARG1 assertEqualsMon "zfs c6 arg2" "${POT_ZFS_ROOT}/jails/test-pot" ZFS_CALL6_ARG2 assertEqualsMon "zfs c6 arg3" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL6_ARG3 assertEqualsMon "zfs c7 arg1" "mount" ZFS_CALL7_ARG1 assertEqualsMon "zfs c7 arg2" "${POT_ZFS_ROOT}/jails/new-pot" ZFS_CALL7_ARG2 assertEqualsMon "zfs c8 arg1" "mount" ZFS_CALL8_ARG1 assertEqualsMon "zfs c8 arg2" "${POT_ZFS_ROOT}/jails/new-pot/custom" ZFS_CALL8_ARG2 assertEqualsMon "zfs c9 arg1" "mount" ZFS_CALL9_ARG1 assertEqualsMon "zfs c9 arg2" "${POT_ZFS_ROOT}/jails/new-pot/usr.local" ZFS_CALL9_ARG2 } test_rn_zfs_002() { _rn_zfs test-pot-2 new-pot-2 assertEqualsMon "_zfs_dataset_valid calls" "4" ZDVALID_CALLS assertEqualsMon "zfs calls" "6" ZFS_CALLS assertEqualsMon "zfs c1 arg1" "umount" ZFS_CALL1_ARG1 assertEqualsMon "zfs c1 arg2" "-f" ZFS_CALL1_ARG2 assertEqualsMon "zfs c1 arg3" "${POT_ZFS_ROOT}/jails/test-pot-2/custom" ZFS_CALL1_ARG3 assertEqualsMon "zfs c2 arg1" "set" ZFS_CALL2_ARG1 assertEqualsMon "zfs c2 arg2" "mountpoint=/jails/new-pot-2/custom" ZFS_CALL2_ARG2 assertEqualsMon "zfs c2 arg3" "${POT_ZFS_ROOT}/jails/test-pot-2/custom" ZFS_CALL2_ARG3 assertEqualsMon "zfs c3 arg1" "umount" ZFS_CALL3_ARG1 assertEqualsMon "zfs c3 arg2" "-f" ZFS_CALL3_ARG2 assertEqualsMon "zfs c3 arg3" "${POT_ZFS_ROOT}/jails/test-pot-2" ZFS_CALL3_ARG3 assertEqualsMon "zfs c4 arg1" "rename" ZFS_CALL4_ARG1 assertEqualsMon "zfs c4 arg2" "${POT_ZFS_ROOT}/jails/test-pot-2" ZFS_CALL4_ARG2 assertEqualsMon "zfs c4 arg3" "${POT_ZFS_ROOT}/jails/new-pot-2" ZFS_CALL4_ARG3 assertEqualsMon "zfs c5 arg1" "mount" ZFS_CALL5_ARG1 assertEqualsMon "zfs c5 arg2" "${POT_ZFS_ROOT}/jails/new-pot-2" ZFS_CALL5_ARG2 assertEqualsMon "zfs c6 arg1" "mount" ZFS_CALL6_ARG1 assertEqualsMon "zfs c6 arg2" "${POT_ZFS_ROOT}/jails/new-pot-2/custom" ZFS_CALL6_ARG2 } test_rn_zfs_003() { _rn_zfs test-pot-single new-pot-single assertEqualsMon "_zfs_dataset_valid calls" "3" ZDVALID_CALLS assertEqualsMon "zfs calls" "6" ZFS_CALLS assertEqualsMon "zfs c1 arg1" "umount" ZFS_CALL1_ARG1 assertEqualsMon "zfs c1 arg2" "-f" ZFS_CALL1_ARG2 assertEqualsMon "zfs c1 arg3" "${POT_ZFS_ROOT}/jails/test-pot-single/m" ZFS_CALL1_ARG3 assertEqualsMon "zfs c2 arg1" "set" ZFS_CALL2_ARG1 assertEqualsMon "zfs c2 arg2" "mountpoint=/jails/new-pot-single/m" ZFS_CALL2_ARG2 assertEqualsMon "zfs c2 arg3" "${POT_ZFS_ROOT}/jails/test-pot-single/m" ZFS_CALL2_ARG3 assertEqualsMon "zfs c3 arg1" "umount" ZFS_CALL3_ARG1 assertEqualsMon "zfs c3 arg2" "-f" ZFS_CALL3_ARG2 assertEqualsMon "zfs c3 arg3" "${POT_ZFS_ROOT}/jails/test-pot-single" ZFS_CALL3_ARG3 assertEqualsMon "zfs c4 arg1" "rename" ZFS_CALL4_ARG1 assertEqualsMon "zfs c4 arg2" "${POT_ZFS_ROOT}/jails/test-pot-single" ZFS_CALL4_ARG2 assertEqualsMon "zfs c4 arg3" "${POT_ZFS_ROOT}/jails/new-pot-single" ZFS_CALL4_ARG3 assertEqualsMon "zfs c5 arg1" "mount" ZFS_CALL5_ARG1 assertEqualsMon "zfs c5 arg2" "${POT_ZFS_ROOT}/jails/new-pot-single" ZFS_CALL5_ARG2 assertEqualsMon "zfs c6 arg1" "mount" ZFS_CALL6_ARG1 assertEqualsMon "zfs c6 arg2" "${POT_ZFS_ROOT}/jails/new-pot-single/m" ZFS_CALL6_ARG2 } setUp() { common_setUp POT_ZFS_ROOT=zpot } . shunit/shunit2 ================================================ FILE: tests/rename4.sh ================================================ #!/bin/sh # system utilities stubs ls() { cat << LS_EOL /opt/pot/jails/test-pot/ /opt/pot/jails/test-pot-2/ /opt/pot/jails/test-pot-nosnap/ LS_EOL } SED=sed_stub sed_stub() { if [ "$(uname)" = "Linux" ]; then sed -i'' "$3" "$4" "$5" else sed "$@" fi } # UUT . ../share/pot/rename.sh # common stubs . common-stub.sh . conf-stub.sh # app specific stubs test_rn_recursive_001() { _rn_recursive test-pot new-pot assertEquals "fscomp base" "zpot/bases/11.1 /tmp/jails/test-pot-2/m ro" "$(sed '1!d' /tmp/jails/test-pot-2/conf/fscomp.conf)" assertEquals "fscomp usr.local" "zpot/jails/new-pot/usr.local /tmp/jails/test-pot-2/m/usr/local ro" "$(sed '2!d' /tmp/jails/test-pot-2/conf/fscomp.conf)" assertEquals "fscomp custom" "zpot/jails/test-pot-2/custom /tmp/jails/test-pot-2/m/opt/custom zfs-remount" "$(sed '3!d' /tmp/jails/test-pot-2/conf/fscomp.conf)" assertEquals "pot.conf potbase" "pot.potbase=new-pot" "$(grep ^pot.potbase= /tmp/jails/test-pot-2/conf/pot.conf)" assertEquals "pot.conf depende" "pot.depend=new-pot" "$(grep ^pot.depend= /tmp/jails/test-pot-nosnap/conf/pot.conf)" } setUp() { common_setUp conf_setUp } tearDown() { common_tearDown conf_tearDown } . shunit/shunit2 ================================================ FILE: tests/revert1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/revert.sh # common stubs . common-stub.sh # app specific stubs revert-help() { __monitor HELP "$@" } _pot_zfs_rollback() { __monitor POTZFSROLL "$@" } _pot_zfs_rollback_full() { __monitor POTZFSROLLFULL "$@" } _fscomp_zfs_rollback() { __monitor FSCOMPZFSROLL "$@" } test_pot_revert_001() { pot-revert assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS setUp pot-revert -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS setUp pot-revert -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS setUp pot-revert -va assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS } test_pot_revert_002() { pot-revert -f test-fscomp -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_zfs_exist calls" "0" ZFSEXIST_CALLS assertEqualsMon "Info calls" "0" INFO_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS setUp pot-revert -p test-pot -f test-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_zfs_exist calls" "0" ZFSEXIST_CALLS assertEqualsMon "Info calls" "0" INFO_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS } test_pot_revert_020() { pot-revert -p assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS setUp pot-revert -p not-a-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS setUp pot-revert -p test-pot-run assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS } test_pot_revert_021() { pot-revert -p test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_rollback calls" "1" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback arg" "test-pot" POTZFSROLL_CALL1_ARG1 assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS } test_pot_revert_022() { pot-revert -p test-pot -a assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_pot_zfs_rollback_full arg" "" POTZFSROLLFULL_CALL1_ARG1 } test_pot_revert_040() { pot-revert -f assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS setUp pot-revert -f not-a-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_zfs_exist calls" "1" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS } test_pot_revert_041() { pot-revert -f test-fscomp assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_zfs_exist calls" "1" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "1" FSCOMPZFSROLL_CALLS assertEqualsMon "_fscomp_zfs_rollback arg" "test-fscomp" FSCOMPZFSROLL_CALL1_ARG1 assertEqualsMon "Info calls" "0" INFO_CALLS } test_pot_revert_042() { pot-revert -f test-fscomp -a assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_rollback calls" "0" POTZFSROLL_CALLS assertEqualsMon "_pot_zfs_rollback_full calls" "0" POTZFSROLLFULL_CALLS assertEqualsMon "_zfs_exist calls" "0" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_rollback calls" "0" FSCOMPZFSROLL_CALLS assertEqualsMon "_fscomp_zfs_rollback arg" "" FSCOMPZFSROLL_CALL1_ARG1 assertEqualsMon "Info calls" "0" INFO_CALLS } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/set-attr1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/set-attribute.sh # common stubs . common-stub.sh # app specific stubs set-attribute-help() { __monitor HELP "$@" } _set_boolean_attribute() { __monitor SETATTR "$@" } test_pot_set_attr_001() { pot-set-attribute assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS setUp pot-set-attribute -bv assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS setUp pot-set-attribute -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS setUp pot-set-attribute -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS } test_pot_set_attr_002() { pot-set-attribute -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS setUp pot-set-attribute -A start-at-boot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS setUp pot-set-attribute -V ON assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS } test_pot_set_attr_003() { pot-set-attribute -A start-at-boot -V ON assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS setUp pot-set-attribute -p test-pot -A start-at-boot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS setUp pot-set-attribute -p test-pot -V ON assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS } test_pot_set_attr_004() { pot-set-attribute -p test-no-pot -A start-at-boot -V ON assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS } test_pot_set_attr_005() { pot-set-attribute -p test-pot -A not-an-attribute -V ON assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr calls" "0" SETATTR_CALLS } test_pot_set_attr_020() { pot-set-attribute -p test-pot -A start-at-boot -V ON assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr calls" "1" SETATTR_CALLS assertEqualsMon "_set_attr arg1" "test-pot" SETATTR_CALL1_ARG1 assertEqualsMon "_set_attr arg2" "start-at-boot" SETATTR_CALL1_ARG2 assertEqualsMon "_set_attr arg3" "ON" SETATTR_CALL1_ARG3 } test_pot_set_attr_021() { pot-set-attribute -p test-pot -A persistent -V ON assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr arg1" "test-pot" SETATTR_CALL1_ARG1 assertEqualsMon "_set_attr arg2" "persistent" SETATTR_CALL1_ARG2 assertEqualsMon "_set_attr arg3" "ON" SETATTR_CALL1_ARG3 } test_pot_set_attr_022() { pot-set-attribute -p test-pot -A no-rc-script -V ON assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr arg1" "test-pot" SETATTR_CALL1_ARG1 assertEqualsMon "_set_attr arg2" "no-rc-script" SETATTR_CALL1_ARG2 assertEqualsMon "_set_attr arg3" "ON" SETATTR_CALL1_ARG3 } test_pot_set_attr_023() { pot-set-attribute -p test-pot -A fdescfs -V ON assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr arg1" "test-pot" SETATTR_CALL1_ARG1 assertEqualsMon "_set_attr arg2" "fdescfs" SETATTR_CALL1_ARG2 assertEqualsMon "_set_attr arg3" "ON" SETATTR_CALL1_ARG3 } test_pot_set_attr_024() { pot-set-attribute -p test-pot -A procfs -V ON assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr arg1" "test-pot" SETATTR_CALL1_ARG1 assertEqualsMon "_set_attr arg2" "procfs" SETATTR_CALL1_ARG2 assertEqualsMon "_set_attr arg3" "ON" SETATTR_CALL1_ARG3 } test_pot_set_attr_025() { pot-set-attribute -p test-pot -A prunable -V ON assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr arg1" "test-pot" SETATTR_CALL1_ARG1 assertEqualsMon "_set_attr arg2" "prunable" SETATTR_CALL1_ARG2 assertEqualsMon "_set_attr arg3" "ON" SETATTR_CALL1_ARG3 } test_pot_set_attr_026() { pot-set-attribute -p test-pot -A localhost-tunnel -V ON assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr arg1" "test-pot" SETATTR_CALL1_ARG1 assertEqualsMon "_set_attr arg2" "localhost-tunnel" SETATTR_CALL1_ARG2 assertEqualsMon "_set_attr arg3" "ON" SETATTR_CALL1_ARG3 } test_pot_set_attr_027() { pot-set-attribute -p test-pot -A early-start-at-boot -V ON assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_attr arg1" "test-pot" SETATTR_CALL1_ARG1 assertEqualsMon "_set_attr arg2" "early-start-at-boot" SETATTR_CALL1_ARG2 assertEqualsMon "_set_attr arg3" "ON" SETATTR_CALL1_ARG3 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/set-attr2.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/set-attribute.sh # common stubs . common-stub.sh # app specific stubs set-attribute-help() { __monitor HELP "$@" } test_normalize_true_false_1() { local rc if rc=$(_normalize_true_false YES) ; then assertEquals "YES" "$rc" else fail "it shouldn't be here" fi } test_normalize_true_false_2() { local rc if rc=$(_normalize_true_false NO) ; then assertEquals "NO" "$rc" else fail "it shouldn't be here" fi } test_normalize_true_false_3() { local rc if rc=$(_normalize_true_false asdfasdf) ; then fail "it shouldn't be here" else assertEquals "" "$rc" fi } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/set-cmd1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/set-cmd.sh # common stubs . common-stub.sh # app specific stubs set-cmd-help() { __monitor HELP "$@" } _set_command() { __monitor SETCMD "$@" } test_pot_set_cmd_001() { pot-set-cmd assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_command calls" "0" SETCMD_CALLS setUp pot-set-cmd -bv assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_command calls" "0" SETCMD_CALLS setUp pot-set-cmd -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_command calls" "0" SETCMD_CALLS setUp pot-set-cmd -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_command calls" "0" SETCMD_CALLS } test_pot_set_cmd_002() { pot-set-cmd -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_command calls" "0" SETCMD_CALLS setUp pot-set-cmd -c sh assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_command calls" "0" SETCMD_CALLS } test_pot_set_cmd_020() { pot-set-cmd -p test-no-pot -c "sh /etc/rc" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_command calls" "0" SETCMD_CALLS } test_pot_set_cmd_040() { pot-set-cmd -p test-pot -c "/echo Hello World" assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_command calls" "1" SETCMD_CALLS assertEqualsMon "_set_command arg1" "test-pot" SETCMD_CALL1_ARG1 assertEqualsMon "_set_command arg2" "/echo Hello World" SETCMD_CALL1_ARG2 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/set-env1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/set-env.sh # common stubs . common-stub.sh # app specific stubs set-env-help() { __monitor HELP "$@" } rm() { __monitor RM "$@" } mktemp() { echo /tmp/pot-set-env } _set_environment() { __monitor SETENV "$@" } test_pot_set_env_001() { pot-set-env assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_environment calls" "0" SETENV_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS setUp pot-set-env -bv assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_environment calls" "0" SETENV_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS setUp pot-set-env -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_environment calls" "0" SETENV_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS setUp pot-set-env -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_environment calls" "0" SETENV_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_002() { pot-set-env -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_environment calls" "0" SETENV_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS setUp pot-set-env -E VAR=value assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_environment calls" "0" SETENV_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_020() { pot-set-env -p test-no-pot -E VAR=value assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "0" SETENV_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_021() { pot-set-env -p test-pot -E NOVAR assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "2" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_environment calls" "0" SETENV_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_040() { pot-set-env -p test-pot -E VAR=value assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=value"' "$(sed '1!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_041() { pot-set-env -p test-pot -E VAR=value -E VAR2=value2 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEquals "_tmpfile length" "2" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=value"' "$(sed '1!d' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR2=value2"' "$(sed '2!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_042() { pot-set-env -p test-pot -E VAR="value1 value2" assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=value1 value2"' "$(sed '1!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_043() { pot-set-env -p test-pot -E VAR="value1 value2" -E VAR2=value3 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "2" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=value1 value2"' "$(sed '1!d' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR2=value3"' "$(sed '2!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_044() { pot-set-env -p test-pot -E EMPTYVAR= assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"EMPTYVAR="' "$(sed '1!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_045() { pot-set-env -p test-pot -E VAR="12*" assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=12*"' "$(sed '1!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_046() { pot-set-env -p test-pot -E VAR='12*' -E 'VAR2=?h* ' assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "2" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=12*"' "$(sed '1!d' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR2=?h* "' "$(sed '2!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_027() { pot-set-env -p test-pot -E VAR='value1 "value2"' assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=value1 \"value2\""' "$(sed '1!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_060() { pot-set-env -p test-pot -E "VAR=value1 value2" assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=value1 value2"' "$(sed '1!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_061() { pot-set-env -p test-pot -E VAR="value1 value2" assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=value1 value2"' "$(sed '1!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_062() { pot-set-env -p test-pot -E 'VAR=value1 value2' assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=value1 value2"' "$(sed '1!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_env_063() { pot-set-env -p test-pot -E VAR='value1 value2' assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_environment calls" "1" SETENV_CALLS assertEqualsMon "_set_environment arg1" "test-pot" SETENV_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-env)" assertEquals "_tmpfile" '"VAR=value1 value2"' "$(sed '1!d' /tmp/pot-set-env)" assertEqualsMon "_rm calls" "1" RM_CALLS } setUp() { common_setUp /bin/rm -f /tmp/pot-set-env } tearDown() { common_tearDown /bin/rm -f /tmp/pot-set-env } . shunit/shunit2 ================================================ FILE: tests/set-env2.sh ================================================ #!/bin/sh # system utilities stubs SED=sed_stub sed_stub() { if [ "$(uname)" = "Linux" ]; then sed -i'' "$3" "$4" else sed "$@" fi } # UUT . ../share/pot/set-env.sh . ../share/pot/common.sh # common stubs . conf-stub.sh test_set_environment_000() { cat > /tmp/pot-set-env << EOF_SETENV "VAR=value" EOF_SETENV _set_environment test-pot /tmp/pot-set-env assertEquals "pot.env lines" "1" "$(grep -c "^pot.env=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR=value"' "$(grep ^pot.env /tmp/jails/test-pot/conf/pot.conf)" } test_set_environment_001() { cat > /tmp/pot-set-env << EOF_SETENV "VAR=value" "VAR2=value2" EOF_SETENV _set_environment test-pot /tmp/pot-set-env assertEquals "pot.env lines" "2" "$(grep -c "^pot.env=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR=value"' "$(grep "^pot.env=\"VAR=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR2=value2"' "$(grep "^pot.env=\"VAR2=" /tmp/jails/test-pot/conf/pot.conf)" } test_set_environment_002() { cat > /tmp/pot-set-env << EOF_SETENV "VAR=value1 value2" EOF_SETENV _set_environment test-pot /tmp/pot-set-env assertEquals "pot.env lines" "1" "$(grep -c "^pot.env=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR=value1 value2"' "$(grep ^pot.env /tmp/jails/test-pot/conf/pot.conf)" } test_set_environment_003() { cat > /tmp/pot-set-env << EOF_SETENV "VAR=value1 value2" "VAR2=value3" EOF_SETENV _set_environment test-pot /tmp/pot-set-env assertEquals "pot.env lines" "2" "$(grep -c "^pot.env=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR=value1 value2"' "$(grep "^pot.env=\"VAR=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR2=value3"' "$(grep "^pot.env=\"VAR2=" /tmp/jails/test-pot/conf/pot.conf)" } test_set_environment_004() { cat > /tmp/pot-set-env << EOF_SETENV "EMPTYVAR=" EOF_SETENV _set_environment test-pot /tmp/pot-set-env assertEquals "pot.env lines" "1" "$(grep -c "^pot.env=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="EMPTYVAR="' "$(grep ^pot.env /tmp/jails/test-pot/conf/pot.conf)" } test_set_environment_005() { cat > /tmp/pot-set-env << EOF_SETENV "VAR=12*" EOF_SETENV _set_environment test-pot /tmp/pot-set-env assertEquals "pot.env lines" "1" "$(grep -c "^pot.env=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR=12*"' "$(grep ^pot.env /tmp/jails/test-pot/conf/pot.conf)" } test_set_environment_006() { cat > /tmp/pot-set-env << EOF_SETENV "VAR=12*" "VAR2=?h* " EOF_SETENV _set_environment test-pot /tmp/pot-set-env assertEquals "pot.env lines" "2" "$(grep -c "^pot.env=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR=12*"' "$(grep "^pot.env=\"VAR=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR2=?h* "' "$(grep "^pot.env=\"VAR2=" /tmp/jails/test-pot/conf/pot.conf)" } test_set_environment_007() { cat > /tmp/pot-set-env << EOF_SETENV "VAR=value1 \"value2\"" EOF_SETENV _set_environment test-pot /tmp/pot-set-env assertEquals "pot.env lines" "1" "$(grep -c "^pot.env=" /tmp/jails/test-pot/conf/pot.conf)" assertEquals "pot.env args" 'pot.env="VAR=value1 \"value2\""' "$(grep "^pot.env=\"VAR=" /tmp/jails/test-pot/conf/pot.conf)" } setUp() { conf_setUp } tearDown() { conf_tearDown /bin/rm -f /tmp/pot-set-env } . shunit/shunit2 ================================================ FILE: tests/set-hook1.sh ================================================ #!/bin/sh # system utilities stubs potnet() { case "$4" in "10.1.2.3"|"10.1.2.4"|\ "fe00::2"|"::1") return 0 # true esac } # UUT . ../share/pot/set-hook.sh # common stubs . common-stub.sh # app specific stubs set-hook-help() { __monitor HELP "$@" } _set_hook() { __monitor SETHOOK "$@" } _is_valid_hook() { __monitor VALIDHOOK "$@" if [ "$1" != "valid_script" ]; then return 1 # false fi return 0 # true } test_pot_set_hook_001() { pot-set-hook assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS setUp pot-set-hook -bv assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS setUp pot-set-hook -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS setUp pot-set-hook -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS } test_pot_set_hook_002() { pot-set-hook -s valid_script assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS } test_pot_set_hook_003() { pot-set-hook -p test-pot -s assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS } test_pot_set_hook_020() { pot-set-hook -p test-no-pot -s valid_script assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS } test_pot_set_hook_021() { pot-set-hook -p test-pot -s not_valid_script assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS } test_pot_set_hook_022() { pot-set-hook -p test-pot -S not_valid_script assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS } test_pot_set_hook_023() { pot-set-hook -p test-pot -t not_valid_script assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS } test_pot_set_hook_024() { pot-set-hook -p test-pot -T not_valid_script assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_set_hook calls" "0" SETHOOK_CALLS } test_pot_set_hook_040() { pot-set-hook -p test-pot -s valid_script assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hook calls" "1" SETHOOK_CALLS assertEqualsMon "_set_hook arg1" "test-pot" SETHOOK_CALL1_ARG1 assertEqualsMon "_set_hook arg2" "valid_script" SETHOOK_CALL1_ARG2 assertEqualsMon "_set_hook arg3" "prestart" SETHOOK_CALL1_ARG3 } test_pot_set_hook_041() { pot-set-hook -p test-pot -s valid_script -S valid_script assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hook calls" "2" SETHOOK_CALLS assertEqualsMon "_set_hook arg1" "test-pot" SETHOOK_CALL1_ARG1 assertEqualsMon "_set_hook arg2" "valid_script" SETHOOK_CALL1_ARG2 assertEqualsMon "_set_hook arg3" "prestart" SETHOOK_CALL1_ARG3 assertEqualsMon "_set_hook arg1" "test-pot" SETHOOK_CALL2_ARG1 assertEqualsMon "_set_hook arg2" "valid_script" SETHOOK_CALL2_ARG2 assertEqualsMon "_set_hook arg3" "poststart" SETHOOK_CALL2_ARG3 } test_pot_set_hook_042() { pot-set-hook -p test-pot -t valid_script -T valid_script assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hook calls" "2" SETHOOK_CALLS assertEqualsMon "_set_hook arg1" "test-pot" SETHOOK_CALL1_ARG1 assertEqualsMon "_set_hook arg2" "valid_script" SETHOOK_CALL1_ARG2 assertEqualsMon "_set_hook arg3" "prestop" SETHOOK_CALL1_ARG3 assertEqualsMon "_set_hook arg1" "test-pot" SETHOOK_CALL2_ARG1 assertEqualsMon "_set_hook arg2" "valid_script" SETHOOK_CALL2_ARG2 assertEqualsMon "_set_hook arg3" "poststop" SETHOOK_CALL2_ARG3 } test_pot_set_hook_043() { pot-set-hook -p test-pot -t valid_script -T valid_script -s valid_script -S valid_script assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hook calls" "4" SETHOOK_CALLS assertEqualsMon "_set_hook arg1" "test-pot" SETHOOK_CALL1_ARG1 assertEqualsMon "_set_hook arg2" "valid_script" SETHOOK_CALL1_ARG2 assertEqualsMon "_set_hook arg3" "prestart" SETHOOK_CALL1_ARG3 assertEqualsMon "_set_hook arg1" "test-pot" SETHOOK_CALL2_ARG1 assertEqualsMon "_set_hook arg2" "valid_script" SETHOOK_CALL2_ARG2 assertEqualsMon "_set_hook arg3" "poststart" SETHOOK_CALL2_ARG3 assertEqualsMon "_set_hook arg1" "test-pot" SETHOOK_CALL3_ARG1 assertEqualsMon "_set_hook arg2" "valid_script" SETHOOK_CALL3_ARG2 assertEqualsMon "_set_hook arg3" "prestop" SETHOOK_CALL3_ARG3 assertEqualsMon "_set_hook arg1" "test-pot" SETHOOK_CALL4_ARG1 assertEqualsMon "_set_hook arg2" "valid_script" SETHOOK_CALL4_ARG2 assertEqualsMon "_set_hook arg3" "poststop" SETHOOK_CALL4_ARG3 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/set-hosts1.sh ================================================ #!/bin/sh # system utilities stubs potnet() { case "$4" in "10.1.2.3"|"10.1.2.4"|\ "fe00::2"|"::1") return 0 # true esac } # UUT . ../share/pot/set-hosts.sh # common stubs . common-stub.sh # app specific stubs set-hosts-help() { __monitor HELP "$@" } rm() { __monitor RM "$@" } mktemp() { echo "/tmp/pot-set-hosts" } _set_hosts() { __monitor SETHOSTS "$@" } test_pot_set_hosts_001() { pot-set-hosts assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS setUp pot-set-hosts -bv assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS setUp pot-set-hosts -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS setUp pot-set-hosts -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_002() { pot-set-hosts -H test-pot-2:10.1.2.3 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_003() { pot-set-hosts -p test-pot -H assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_020() { pot-set-hosts -p test-no-pot -H test-pot-2:10.1.2.3 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_021() { pot-set-hosts -p test-pot -H test-pot-2 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "2" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_022() { pot-set-hosts -p test-pot -H test-pot-2: assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_023() { pot-set-hosts -p test-pot -H :10.1.2.3 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "0" SETHOSTS_CALLS assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_040() { pot-set-hosts -p test-pot -H test-pot-2:10.1.2.3 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "1" SETHOSTS_CALLS assertEqualsMon "_set_hosts arg1" "test-pot" SETHOSTS_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-hosts)" assertEquals "_tmpfile" '10.1.2.3 test-pot-2' "$(sed '1!d' /tmp/pot-set-hosts)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_041() { pot-set-hosts -p test-pot -H test-pot-2:10.1.2.3 -H test-pot-3:10.1.2.4 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "1" SETHOSTS_CALLS assertEquals "_tmpfile length" "2" "$( awk 'END {print NR}' /tmp/pot-set-hosts)" assertEquals "_tmpfile" '10.1.2.3 test-pot-2' "$(sed '1!d' /tmp/pot-set-hosts)" assertEquals "_tmpfile" '10.1.2.4 test-pot-3' "$(sed '2!d' /tmp/pot-set-hosts)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_042() { pot-set-hosts -p test-pot -H test-pot-2:fe00::2 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "1" SETHOSTS_CALLS assertEqualsMon "_set_hosts arg1" "test-pot" SETHOSTS_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-hosts)" assertEquals "_tmpfile" 'fe00::2 test-pot-2' "$(sed '1!d' /tmp/pot-set-hosts)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_043() { pot-set-hosts -p test-pot -H test-pot-2:::1 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "1" SETHOSTS_CALLS assertEqualsMon "_set_hosts arg1" "test-pot" SETHOSTS_CALL1_ARG1 assertEquals "_tmpfile length" "1" "$( awk 'END {print NR}' /tmp/pot-set-hosts)" assertEquals "_tmpfile" '::1 test-pot-2' "$(sed '1!d' /tmp/pot-set-hosts)" assertEqualsMon "_rm calls" "1" RM_CALLS } test_pot_set_hosts_044() { pot-set-hosts -p test-pot -H test-pot-2:10.1.2.3 -H test-pot-3:10.1.2.4 -H test-pot-4:::1 -H test-pot-5:fe00::2 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_hosts calls" "1" SETHOSTS_CALLS assertEqualsMon "_set_hosts arg1" "test-pot" SETHOSTS_CALL1_ARG1 assertEquals "_tmpfile length" "4" "$( awk 'END {print NR}' /tmp/pot-set-hosts)" assertEquals "_tmpfile" '10.1.2.3 test-pot-2' "$(sed '1!d' /tmp/pot-set-hosts)" assertEquals "_tmpfile" '10.1.2.4 test-pot-3' "$(sed '2!d' /tmp/pot-set-hosts)" assertEquals "_tmpfile" '::1 test-pot-4' "$(sed '3!d' /tmp/pot-set-hosts)" assertEquals "_tmpfile" 'fe00::2 test-pot-5' "$(sed '4!d' /tmp/pot-set-hosts)" assertEqualsMon "_rm calls" "1" RM_CALLS } setUp() { common_setUp /bin/rm -f /tmp/pot-set-hosts } tearDown() { common_tearDown /bin/rm -f /tmp/pot-set-hosts } . shunit/shunit2 ================================================ FILE: tests/set-rss1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/set-rss.sh # common stubs . common-stub.sh # app specific stubs set-rss-help() { __monitor HELP "$@" } _set_rss() { __monitor ADDRSS "$@" } test_pot_set_rss_001() { pot-set-rss assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -bv assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS } test_pot_set_rss_002() { pot-set-rss -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -C 1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -M 200M assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -M 200M -C 1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS } test_pot_set_rss_003() { pot-set-rss -p test-pot -M 200Megabyte assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -p test-pot -M 10000000T assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -p test-pot -M 00M assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -p test-pot -M 1.5G assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS } test_pot_set_rss_020() { pot-set-rss -p test-no-pot -C 1 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -p test-no-pot -M 200M assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS setUp pot-set-rss -p test-pot -M 200M -C 0 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_rss calls" "0" ADDRSS_CALLS } test_pot_set_rss_021() { pot-set-rss -p test-pot -M 200M assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_rss calls" "1" ADDRSS_CALLS setUp pot-set-rss -p test-pot -C 1 assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_rss calls" "1" ADDRSS_CALLS setUp pot-set-rss -p test-pot -C 2 -M 200M assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_set_rss calls" "2" ADDRSS_CALLS } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/show1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/show.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs show-help() { __monitor HELP "$@" } _show_pot() { __monitor SHOWPOT "$@" } _show_all_pots() { __monitor SHOWALLPOTS "$@" } _show_running_pots() { __monitor SHOWRUNPOTS "$@" } test_pot_show_001() { pot-show -k bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS setUp pot-show -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS } test_pot_show_002() { pot-show -a -r assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS } test_pot_show_003() { pot-show -a -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "is_pot calls" "0" ISPOT_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS } test_pot_show_004() { pot-show -a -p test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "is_pot calls" "0" ISPOT_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS } test_pot_show_005() { pot-show -r -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "is_pot calls" "0" ISPOT_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS } test_pot_show_006() { pot-show -r -p test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "is_pot calls" "0" ISPOT_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS } test_pot_show_010() { pot-show -p test-no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS } test_pot_show_020() { pot-show assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "1" SHOWRUNPOTS_CALLS } test_pot_show_021() { pot-show -r assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "1" SHOWRUNPOTS_CALLS } test_pot_show_022() { pot-show -a assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "show_pot calls" "0" SHOWPOT_CALLS assertEqualsMon "show_all_pots calls" "1" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS } test_pot_show_023() { pot-show -p test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "is_pot calls" "1" ISPOT_CALLS assertEqualsMon "show_pot calls" "1" SHOWPOT_CALLS assertEqualsMon "show_pot arg" "test-pot" SHOWPOT_CALL1_ARG1 assertEqualsMon "show_all_pots calls" "0" SHOWALLPOTS_CALLS assertEqualsMon "show_running_pots calls" "0" SHOWRUNPOTS_CALLS } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/shunit/.gitignore ================================================ # Hidden files generated by macOS. .DS_Store ._* ================================================ FILE: tests/shunit/.travis.yml ================================================ language: bash env: - SHUNIT_COLOR='always' script: # Execute the unit tests. - ./test_runner os: - linux - osx addons: apt: packages: - ksh - zsh matrix: include: - os: linux script: # Run the source through ShellCheck (http://www.shellcheck.net). - shellcheck shunit2 *_test.sh - shellcheck -s sh shunit2_test_helpers - os: linux # Support Ubuntu Trusty through Apr 2019. dist: trusty ================================================ FILE: tests/shunit/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at kate.ward@forestent.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: tests/shunit/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: tests/shunit/README.md ================================================ # shUnit2 shUnit2 is a [xUnit](http://en.wikipedia.org/wiki/XUnit) unit test framework for Bourne based shell scripts, and it is designed to work in a similar manner to [JUnit](http://www.junit.org), [PyUnit](http://pyunit.sourceforge.net), etc.. If you have ever had the desire to write a unit test for a shell script, shUnit2 can do the job. [![Travis CI](https://img.shields.io/travis/kward/shunit2.svg)](https://travis-ci.org/kward/shunit2) ## Table of Contents * [Introduction](#introduction) * [Credits / Contributors](#credits-contributors) * [Feedback](#feedback) * [Quickstart](#quickstart) * [Function Reference](#function-reference) * [General Info](#general-info) * [Asserts](#asserts) * [Failures](#failures) * [Setup/Teardown](#setup-teardown) * [Skipping](#skipping) * [Suites](#suites) * [Advanced Usage](#advanced-usage) * [Some constants you can use](#some-constants-you-can-use) * [Error Handling](#error-handling) * [Including Line Numbers in Asserts (Macros)](#including-line-numbers-in-asserts-macros) * [Test Skipping](#test-skipping) * [Running specific tests from the command line](#cmd-line-args) * [Appendix](#appendix) * [Getting help](#getting-help) * [Zsh](#zsh) --- ## Introduction shUnit2 was originally developed to provide a consistent testing solution for [log4sh][log4sh], a shell based logging framework similar to [log4j](http://logging.apache.org). During the development of that product, a repeated problem of having things work just fine under one shell (`/bin/bash` on Linux to be specific), and then not working under another shell (`/bin/sh` on Solaris) kept coming up. Although several simple tests were run, they were not adequate and did not catch some corner cases. The decision was finally made to write a proper unit test framework after multiple brown-bag releases were made. _Research was done to look for an existing product that met the testing requirements, but no adequate product was found._ ### Tested software **Tested Operating Systems** (varies over time) OS | Support | Verified ----------------------------------- | --------- | -------- Ubuntu Linux (14.04.05 LTS) | Travis CI | continuous macOS High Sierra (10.13.3) | Travis CI | continuous FreeBSD | user | unknown Solaris 8, 9, 10 (inc. OpenSolaris) | user | unknown Cygwin | user | unknown **Tested Shells** * Bourne Shell (__sh__) * BASH - GNU Bourne Again SHell (__bash__) * DASH (__dash__) * Korn Shell (__ksh__) * pdksh - Public Domain Korn Shell (__pdksh__) * zsh - Zsh (__zsh__) (since 2.1.2) _please see the Zsh shell errata for more information_ See the appropriate Release Notes for this release (`doc/RELEASE_NOTES-X.X.X.txt`) for the list of actual versions tested. ### Credits / Contributors A list of contributors to shUnit2 can be found in `doc/contributors.md`. Many thanks go out to all those who have contributed to make this a better tool. shUnit2 is the original product of many hours of work by Kate Ward, the primary author of the code. For related software, check out https://github.com/kward. ### Feedback Feedback is most certainly welcome for this document. Send your questions, comments, and criticisms via the [shunit2-users](https://groups.google.com/a/forestent.com/forum/#!forum/shunit2-users/new) forum (created 2018-12-09), or file an issue via https://github.com/kward/shunit2/issues. --- ## Quickstart This section will give a very quick start to running unit tests with shUnit2. More information is located in later sections. Here is a quick sample script to show how easy it is to write a unit test in shell. _Note: the script as it stands expects that you are running it from the "examples" directory._ ```sh #! /bin/sh # file: examples/equality_test.sh testEquality() { assertEquals 1 1 } # Load shUnit2. . ./shunit2 ``` Running the unit test should give results similar to the following. ```console $ cd examples $ ./equality_test.sh testEquality Ran 1 test. OK ``` W00t! You've just run your first successful unit test. So, what just happened? Quite a bit really, and it all happened simply by sourcing the `shunit2` library. The basic functionality for the script above goes like this: * When shUnit2 is sourced, it will walk through any functions defined whose name starts with the string `test`, and add those to an internal list of tests to execute. Once a list of test functions to be run has been determined, shunit2 will go to work. * Before any tests are executed, shUnit2 again looks for a function, this time one named `oneTimeSetUp()`. If it exists, it will be run. This function is normally used to setup the environment for all tests to be run. Things like creating directories for output or setting environment variables are good to place here. Just so you know, you can also declare a corresponding function named `oneTimeTearDown()` function that does the same thing, but once all the tests have been completed. It is good for removing temporary directories, etc. * shUnit2 is now ready to run tests. Before doing so though, it again looks for another function that might be declared, one named `setUp()`. If the function exists, it will be run before each test. It is good for resetting the environment so that each test starts with a clean slate. **At this stage, the first test is finally run.** The success of the test is recorded for a report that will be generated later. After the test is run, shUnit2 looks for a final function that might be declared, one named `tearDown()`. If it exists, it will be run after each test. It is a good place for cleaning up after each test, maybe doing things like removing files that were created, or removing directories. This set of steps, `setUp() > test() > tearDown()`, is repeated for all of the available tests. * Once all the work is done, shUnit2 will generate the nice report you saw above. A summary of all the successes and failures will be given so that you know how well your code is doing. We should now try adding a test that fails. Change your unit test to look like this. ```sh #! /bin/sh # file: examples/party_test.sh testEquality() { assertEquals 1 1 } testPartyLikeItIs1999() { year=`date '+%Y'` assertEquals "It's not 1999 :-(" '1999' "${year}" } # Load shUnit2. . ./shunit2 ``` So, what did you get? I guess it told you that this isn't 1999. Bummer, eh? Hopefully, you noticed a couple of things that were different about the second test. First, we added an optional message that the user will see if the assert fails. Second, we did comparisons of strings instead of integers as in the first test. It doesn't matter whether you are testing for equality of strings or integers. Both work equally well with shUnit2. Hopefully, this is enough to get you started with unit testing. If you want a ton more examples, take a look at the tests provided with [log4sh][log4sh] or [shFlags][shflags]. Both provide excellent examples of more advanced usage. shUnit2 was after all written to meet the unit testing need that [log4sh][log4sh] had. --- ## Function Reference ### General Info Any string values passed should be properly quoted -- they should must be surrounded by single-quote (`'`) or double-quote (`"`) characters -- so that the shell will properly parse them. ### Asserts `assertEquals [message] expected actual` Asserts that _expected_ and _actual_ are equal to one another. The _expected_ and _actual_ values can be either strings or integer values as both will be treated as strings. The _message_ is optional, and must be quoted. `assertNotEquals [message] unexpected actual` Asserts that _unexpected_ and _actual_ are not equal to one another. The _unexpected_ and _actual_ values can be either strings or integer values as both will be treaded as strings. The _message_ is optional, and must be quoted. `assertSame [message] expected actual` This function is functionally equivalent to `assertEquals`. `assertNotSame [message] unexpected actual` This function is functionally equivalent to `assertNotEquals`. `assertContains [message] container content` Asserts that _container_ contains _content_. The _container_ and _content_ values can be either strings or integer values as both will be treated as strings. The _message_ is optional, and must be quoted. `assertNotContains [message] container content` Asserts that _container_ does not contain _content_. The _container_ and _content_ values can be either strings or integer values as both will be treaded as strings. The _message_ is optional, and must be quoted. `assertNull [message] value` Asserts that _value_ is _null_, or in shell terms, a zero-length string. The _value_ must be a string as an integer value does not translate into a zero- length string. The _message_ is optional, and must be quoted. `assertNotNull [message] value` Asserts that _value_ is _not null_, or in shell terms, a non-empty string. The _value_ may be a string or an integer as the later will be parsed as a non-empty string value. The _message_ is optional, and must be quoted. `assertTrue [message] condition` Asserts that a given shell test _condition_ is _true_. The condition can be as simple as a shell _true_ value (the value `0` -- equivalent to `${SHUNIT_TRUE}`), or a more sophisticated shell conditional expression. The _message_ is optional, and must be quoted. A sophisticated shell conditional expression is equivalent to what the __if__ or __while__ shell built-ins would use (more specifically, what the __test__ command would use). Testing for example whether some value is greater than another value can be done this way. `assertTrue "[ 34 -gt 23 ]"` Testing for the ability to read a file can also be done. This particular test will fail. `assertTrue 'test failed' "[ -r /some/non-existant/file' ]"` As the expressions are standard shell __test__ expressions, it is possible to string multiple expressions together with `-a` and `-o` in the standard fashion. This test will succeed as the entire expression evaluates to _true_. `assertTrue 'test failed' '[ 1 -eq 1 -a 2 -eq 2 ]'` One word of warning: be very careful with your quoting as shell is not the most forgiving of bad quoting, and things will fail in strange ways. `assertFalse [message] condition` Asserts that a given shell test _condition_ is _false_. The condition can be as simple as a shell _false_ value (the value `1` -- equivalent to `${SHUNIT_FALSE}`), or a more sophisticated shell conditional expression. The _message_ is optional, and must be quoted. _For examples of more sophisticated expressions, see `assertTrue`._ ### Failures Just to clarify, failures __do not__ test the various arguments against one another. Failures simply fail, optionally with a message, and that is all they do. If you need to test arguments against one another, use asserts. If all failures do is fail, why might one use them? There are times when you may have some very complicated logic that you need to test, and the simple asserts provided are simply not adequate. You can do your own validation of the code, use an `assertTrue ${SHUNIT_TRUE}` if your own tests succeeded, and use a failure to record a failure. `fail [message]` Fails the test immediately. The _message_ is optional, and must be quoted. `failNotEquals [message] unexpected actual` Fails the test immediately, reporting that the _unexpected_ and _actual_ values are not equal to one another. The _message_ is optional, and must be quoted. _Note: no actual comparison of unexpected and actual is done._ `failSame [message] expected actual` Fails the test immediately, reporting that the _expected_ and _actual_ values are the same. The _message_ is optional, and must be quoted. _Note: no actual comparison of expected and actual is done._ `failNotSame [message] expected actual` Fails the test immediately, reporting that the _expected_ and _actual_ values are not the same. The _message_ is optional, and must be quoted. _Note: no actual comparison of expected and actual is done._ `failFound [message] content` Fails the test immediately, reporting that the _content_ was found. The _message_ is optional, and must be quoted. _Note: no actual search of content is done._ `failNotFound [message] content` Fails the test immediately, reporting that the _content_ was not found. The _message_ is optional, and must be quoted. _Note: no actual search of content is done._ ### Setup/Teardown `oneTimeSetUp` This function can be be optionally overridden by the user in their test suite. If this function exists, it will be called once before any tests are run. It is useful to prepare a common environment for all tests. `oneTimeTearDown` This function can be be optionally overridden by the user in their test suite. If this function exists, it will be called once after all tests are completed. It is useful to clean up the environment after all tests. `setUp` This function can be be optionally overridden by the user in their test suite. If this function exists, it will be called before each test is run. It is useful to reset the environment before each test. `tearDown` This function can be be optionally overridden by the user in their test suite. If this function exists, it will be called after each test completes. It is useful to clean up the environment after each test. ### Skipping `startSkipping` This function forces the remaining _assert_ and _fail_ functions to be "skipped", i.e. they will have no effect. Each function skipped will be recorded so that the total of asserts and fails will not be altered. `endSkipping` This function returns calls to the _assert_ and _fail_ functions to their default behavior, i.e. they will be called. `isSkipping` This function returns the current state of skipping. It can be compared against `${SHUNIT_TRUE}` or `${SHUNIT_FALSE}` if desired. ### Suites The default behavior of shUnit2 is that all tests will be found dynamically. If you have a specific set of tests you want to run, or you don't want to use the standard naming scheme of prefixing your tests with `test`, these functions are for you. Most users will never use them though. `suite` This function can be optionally overridden by the user in their test suite. If this function exists, it will be called when `shunit2` is sourced. If it does not exist, shUnit2 will search the parent script for all functions beginning with the word `test`, and they will be added dynamically to the test suite. `suite_addTest name` This function adds a function named _name_ to the list of tests scheduled for execution as part of this test suite. This function should only be called from within the `suite()` function. --- ## Advanced Usage ### Some constants you can use There are several constants provided by shUnit2 as variables that might be of use to you. *Predefined* | Constant | Value | | --------------- | ----- | | SHUNIT\_TRUE | Standard shell `true` value (the integer value 0). | | SHUNIT\_FALSE | Standard shell `false` value (the integer value 1). | | SHUNIT\_ERROR | The integer value 2. | | SHUNIT\_TMPDIR | Path to temporary directory that will be automatically cleaned up upon exit of shUnit2. | | SHUNIT\_VERSION | The version of shUnit2 you are running. | *User defined* | Constant | Value | | ----------------- | ----- | | SHUNIT\_CMD\_EXPR | Override which `expr` command is used. By default `expr` is used, except on BSD systems where `gexpr` is used. | | SHUNIT\_COLOR | Enable colorized output. Options are 'auto', 'always', or 'none', with 'auto' being the default. | | SHUNIT\_PARENT | The filename of the shell script containing the tests. This is needed specifically for Zsh support. | | SHUNIT\_TEST\_PREFIX | Define this variable to add a prefix in front of each test name that is output in the test report. | ### Error handling The constants values `SHUNIT_TRUE`, `SHUNIT_FALSE`, and `SHUNIT_ERROR` are returned from nearly every function to indicate the success or failure of the function. Additionally the variable `flags_error` is filled with a detailed error message if any function returns with a `SHUNIT_ERROR` value. ### Including Line Numbers in Asserts (Macros) If you include lots of assert statements in an individual test function, it can become difficult to determine exactly which assert was thrown unless your messages are unique. To help somewhat, line numbers can be included in the assert messages. To enable this, a special shell "macro" must be used rather than the standard assert calls. _Shell doesn't actually have macros; the name is used here as the operation is similar to a standard macro._ For example, to include line numbers for a `assertEquals()` function call, replace the `assertEquals()` with `${_ASSERT_EQUALS_}`. _**Example** -- Asserts with and without line numbers_ ```sh #! /bin/sh # file: examples/lineno_test.sh testLineNo() { # This assert will have line numbers included (e.g. "ASSERT:[123] ..."). echo "ae: ${_ASSERT_EQUALS_}" ${_ASSERT_EQUALS_} 'not equal' 1 2 # This assert will not have line numbers included (e.g. "ASSERT: ..."). assertEquals 'not equal' 1 2 } # Load shUnit2. . ./shunit2 ``` Notes: 1. Due to how shell parses command-line arguments, all strings used with macros should be quoted twice. Namely, single-quotes must be converted to single- double-quotes, and vice-versa. If the string being passed is absolutely for sure not empty, the extra quoting is not necessary.

Normal `assertEquals` call.
`assertEquals 'some message' 'x' ''`

Macro `_ASSERT_EQUALS_` call. Note the extra quoting around the _message_ and the _null_ value.
`_ASSERT_EQUALS_ '"some message"' 'x' '""'` 1. Line numbers are not supported in all shells. If a shell does not support them, no errors will be thrown. Supported shells include: __bash__ (>=3.0), __ksh__, __pdksh__, and __zsh__. ### Test Skipping There are times where the test code you have written is just not applicable to the system you are running on. This section describes how to skip these tests but maintain the total test count. Probably the easiest example would be shell code that is meant to run under the __bash__ shell, but the unit test is running under the Bourne shell. There are things that just won't work. The following test code demonstrates two sample functions, one that will be run under any shell, and the another that will run only under the __bash__ shell. _**Example** -- math include_ ```sh # file: examples/math.inc. add_generic() { num_a=$1 num_b=$2 expr $1 + $2 } add_bash() { num_a=$1 num_b=$2 echo $(($1 + $2)) } ``` And here is a corresponding unit test that correctly skips the `add_bash()` function when the unit test is not running under the __bash__ shell. _**Example** -- math unit test_ ```sh #! /bin/sh # file: examples/math_test.sh testAdding() { result=`add_generic 1 2` assertEquals \ "the result of '${result}' was wrong" \ 3 "${result}" # Disable non-generic tests. [ -z "${BASH_VERSION:-}" ] && startSkipping result=`add_bash 1 2` assertEquals \ "the result of '${result}' was wrong" \ 3 "${result}" } oneTimeSetUp() { # Load include to test. . ./math.inc } # Load and run shUnit2. . ./shunit2 ``` Running the above test under the __bash__ shell will result in the following output. ```console $ /bin/bash math_test.sh testAdding Ran 1 test. OK ``` But, running the test under any other Unix shell will result in the following output. ```console $ /bin/ksh math_test.sh testAdding Ran 1 test. OK (skipped=1) ``` As you can see, the total number of tests has not changed, but the report indicates that some tests were skipped. Skipping can be controlled with the following functions: `startSkipping()`, `endSkipping()`, and `isSkipping()`. Once skipping is enabled, it will remain enabled until the end of the current test function call, after which skipping is disabled. ### Running specific tests from the command line. When running a test script, you may override the default set of tests, or the suite-specified set of tests, by providing additional arguments on the command line. Each additional argument after the `--` marker is assumed to be the name of a test function to be run in the order specified. e.g. ```console test-script.sh -- testOne testTwo otherFunction ``` or ```console shunit2 test-script.sh testOne testTwo otherFunction ``` In either case, three functions will be run as tests, `testOne`, `testTwo`, and `otherFunction`. Note that the function `otherFunction` would not normally be run by `shunit2` as part of the implicit collection of tests as it's function name does not match the test function name pattern `test*`. If a specified test function does not exist, `shunit2` will still attempt to run that function and thereby cause a failure which `shunit2` will catch and mark as a failed test. All other tests will run normally. The specification of tests does not affect how `shunit2` looks for and executes the setup and tear down functions, which will still run as expected. --- ## Appendix ### Getting Help For help, please send requests to either the shunit2-users@forestent.com mailing list (archives available on the web at https://groups.google.com/a/forestent.com/forum/#!forum/shunit2-users) or directly to Kate Ward . ### Zsh For compatibility with Zsh, there is one requirement that must be met -- the `shwordsplit` option must be set. There are three ways to accomplish this. 1. In the unit-test script, add the following shell code snippet before sourcing the `shunit2` library. ```sh setopt shwordsplit ``` 2. When invoking __zsh__ from either the command-line or as a script with `#!`, add the `-y` parameter. ```sh #! /bin/zsh -y ``` 3. When invoking __zsh__ from the command-line, add `-o shwordsplit --` as parameters before the script name. ```console $ zsh -o shwordsplit -- some_script ``` [log4sh]: https://github.com/kward/log4sh [shflags]: https://github.com/kward/shflags ================================================ FILE: tests/shunit/doc/CHANGES-2.1.md ================================================ # shUnit2 2.1.x Changes ## Changes with 2.1.8 ### New Issue #29. Add support for user defined prefix for test names. A prefix can be added by defining the `SHUNIT_TEST_PREFIX` variable. ### Improvements Issue #78. Added an example for using suite tests. Run continuous integration additionally against Ubuntu Trusty. ### Fixed Issue #94. Removed the `gen_test_report.sh` script as the Travis CI output can be used instead. Reports were used before Travis CI was used. Issue #84. Treat syntax errors in functions as test failures. Issue #77. Fail tests when the environment functions (e.g. `setup()` or `tearDown()`) fail. ## Changes with 2.1.7 ### Bug fixes Issue #69. shUnit2 should not exit with 0 when it has (syntax) errors. ### Enhancements Issue #54. Shell commands prefixed with '\' so that they can be stubbed in tests. Issue #68. Ran all code through [ShellCheck](http://www.shellcheck.net/). Issue #60. Continuous integration tests now run with [Travis CI](https://travis-ci.org/kward/shunit2). Issue #56. Added color support. Color is enabled automatically when supported, but can be disabled by defining the SHUNIT_COLOR environment variable before sourcing shunit2. Accepted values are `always`, `auto` (the default), and `none`. Issue #35. Add colored output. ### Other Moved code to GitHub (https://github.com/kward/shunit2), and restructured to be more GitHub like. Changed to the Apache 2.0 license. ## Changes with 2.1.6 Removed all references to the DocBook documentation. Simplified the 'src' structure. Fixed error message in fail() that stated wrong number of required arguments. Updated lib/versions. Fixed bug in `_shunit_mktempDir()` where a failure occurred when the 'od' command was not present in `/usr/bin`. Renamed `shunit_tmpDir` variable to `SHUNIT_TMPDIR` to closer match the standard `TMPDIR` variable. Added support for calling shunit2 as an executable, in addition to the existing method of sourcing it in as a library. This allows users to keep tests working despite the location of the shunit2 executable being different for each OS distribution. Issue #14: Improved handling of some strange chars (e.g. single and double quotes) in messages. Issue# 27: Fixed error message for `assertSame()`. Issue# 25: Added check and error message to user when phantom functions are written to a partition mounted with `noexec`. Issue# 11: Added support for defining functions like `function someFunction()`. ## Changes with 2.1.5 Issue# 1: Fixed bug pointed out by R Bernstein in the trap code where certain types of exit conditions did not generate the ending report. Issue# 2: Added `assertNotEquals()` assert. Issue# 3: Moved check for unset variables out of shUnit2 into the unit tests. Testing poorly written software blows up if this check is in, but it is only interesting for shUnit2 itself. Added `shunit_test_output.sh` unit test for this. Some shells still do not catch such errors properly (e.g. Bourne shell and BASH 2.x). Added new custom assert in test_helpers to check for output to STDOUT, and none to STDERR. Replaced fatal message in the temp directory creation with a `_shunit_fatal()` function call. Fixed test_output unit test so it works now that the 'set -u' stuff was removed for Issue# 3. Flushed out the coding standards in the `README.txt` a bit more, and brought the shunit2 code up to par with the documented standards. Issue# 4: Completely changed the reporting output to be a closer match for JUnit and PyUnit. As a result, tests are counted separately from assertions. Provide public `shunit_tmpDir` variable that can be used by unit test scripts that need automated and guaranteed cleanup. Issue# 7: Fixed duplicated printing of messages passed to asserts. Per code review, fixed wording of `failSame()` and `failNotSame()` messages. Replaced `version_info.sh` with versions library and made appropriate changes in other scripts to use it. Added `gen_test_results.sh` to make releases easier. Fixed bugs in `shlib_relToAbsPath()` in shlib. Converted DocBook documentation to reStructuredText for easier maintenance. The DocBook documentation is now considered obsolete, and will be removed in a future release. Issue# 5: Fixed the documentation around the usage of failures. Issue# 9: Added unit tests and updated documentation to demonstrate the requirement of quoting values twice when macros are used. This is due to how shell parses arguments. When an invalid number of arguments is passed to a function, the invalid number is returned to the user so they are more aware of what the cause might be. ## Changes with 2.1.4 Removed the `_shunit_functionExists()` function as it was dead code. Fixed zsh version number check in version_info. Fixed bug in last resort temporary directory creation. Fixed off-by-one in exit value for scripts caught by the trap handler. Added argument count error checking to all functions. Added mkdir_test.sh example. Moved src/test into src/shell to better match structure used with shFlags. Fixed problem where null values were not handled properly under ksh. Added support for outputting line numbers as part of assert messages. Started documenting the coding standards, and changed some variable names as a result. Improved zsh version and option checks. Renamed the `__SHUNIT_VERSION` variable to `SHUNIT_VERSION`. ## Changes with 2.1.3 Added some explicit variable defaults, even though the variables are set, as they sometimes behave strange when the script is canceled. Additional workarounds for zsh compatibility. shUnit2 now exits with a non-zero exit code if any of the tests failed. This was done for automated testing frameworks. Tests that were skipped are not considered failures, and do not affect the exit code. Changed detection of STDERR output in unit tests. ## Changes with 2.1.2 Unset additional variables that were missed. Added checks and workarounds to improve zsh compatibility. Added some argument count checks `assertEquals()`, `assertNull()`, and `assertSame()`. ## Changes with 2.1.1 Fixed bug where `fail()` was not honoring skipping. Fixed problem with `docs-docbook-prep` target that prevented it from working. (Thanks to Bryan Larsen for pointing this out.) Changed the test in `assertFalse()` so that any non-zero value registers as false. (Credits to Bryan Larsen) Major fiddling to bring more in line with [JUnit](http://junit.org/). Asserts give better output when no message is given, and failures now just fail. It was pointed out that the simple 'failed' message for a failed assert was not only insufficient, it was nonstandard (when compared to JUnit) and didn't provide the user with an expected vs actual result. The code was revised somewhat to bring closer into alignment with JUnit (v4.3.1 specifically) so that it feels more "normal". (Credits to Richard Jensen) As part of the JUnit realignment, it was noticed that `fail*()` functions in JUnit don't actually do any comparisons themselves. They only generate a failure message. Updated the code to match. Added self-testing unit tests. Kinda horkey, but they did find bugs during the JUnit realignment. Fixed the code for returning from asserts as the return was being called before the unsetting of variables occurred. (Credits to Mathias Goldau) The assert(True|False)() functions now accept an integer value for a conditional test. A value of '0' is considered 'true', while any non-zero value is considered 'false'. All public functions now fill use default values to work properly with the '-x' shell debugging flag. Fixed the method of percent calculation for the report to get achieve better accuracy. ## Changes with 2.1.0 (since 2.0.1) This release is a branch of the 2.0.1 release. Moving to [reStructured Text](http://docutils.sourceforge.net/rst.html) for the documentation. Fixed problem with `fail()`. The failure message was not properly printed. Fixed the `Makefile` so that the DocBook XML and XSLT files would be downloaded before parsing can continue. Renamed the internal `__SHUNIT_TRUE` and `__SHUNIT_FALSE` variables to `SHUNIT_TRUE` and `SHUNIT_FALSE` so that unit tests can "use" them. Added support for test "skipping". If skipping is turned on with the `startSkip()` function, `assert` and `fail` functions will return immediately, and the skip will be recorded. The report output format was changed to include the percentage for each test result, rather than just those successful. [travis_ci]: https://travis-ci.org/kward/shunit2 ================================================ FILE: tests/shunit/doc/RELEASE_NOTES-2.1.0.txt ================================================ Release Notes for shUnit2 2.1.0 =============================== This release was branched from shUnit2 2.0.1. It mostly adds new functionality, but there are couple of bugs fixed from the previous release. See the ``CHANGES-2.1.rst`` file for a full list of changes. Tested Platforms ---------------- This list of platforms comes from the latest version of log4sh as shUnit2 is used in the testing of log4sh on each of these platforms. Cygwin - bash 3.2.9(10) - pdksh 5.2.14 Linux - bash 3.1.17(1), 3.2.10(1) - dash 0.5.3 - ksh 1993-12-28 - pdksh 5.2.14 - zsh 4.3.2 (does not work) Mac OS X 10.4.8 (Darwin 8.8) - bash 2.05b.0(1) - ksh 1993-12-28 Solaris 8 U3 (x86) - /bin/sh - bash 2.03.0(1) - ksh M-11/16/88i Solaris 10 U2 (sparc) - /bin/sh - bash 3.00.16(1) - ksh M-11/16/88i Solaris 10 U2 (x86) - /bin/sh - bash 3.00.16(1) - ksh M-11/16/88i New Features ------------ Test skipping Support added for test "skipping". A skip mode can be enabled so that subsequent ``assert`` and ``fail`` functions that are called will be recorded as "skipped" rather than as "passed" or "failed". This functionality can be used such that when a set of tests makes sense on one platform but not on another, they can be effectively disabled without altering the total number of tests. One example might be when something is supported under ``bash``, but not under a standard Bourne shell. New functions: ``startSkipping()``, ``endSkipping``, ``isSkipping`` Changes and Enhancements ------------------------ Moving to the use of `reStructured Text `_ for documentation. It is easy to read and edit in textual form, but converts nicely to HTML. The report format has changed. Rather than including a simple "success" percentage at the end, a percentage is given for each type of test. Bug Fixes --------- The ``fail()`` function did not output the optional failure message. Fixed the ``Makefile`` so that the DocBook XML and XSLT files would be downloaded before documentation parsing will continue. Deprecated Features ------------------- None. Known Bugs and Issues --------------------- None. .. $Revision$ .. vim:fileencoding=latin1:spell:syntax=rst:textwidth=80 ================================================ FILE: tests/shunit/doc/RELEASE_NOTES-2.1.1.txt ================================================ Release Notes for shUnit2 2.1.1 =============================== This is mainly a bug fix release, but it also incorporates a realignment with the JUnit 4 code. Asserts now provide better failure messages, and the failure functions no longer perform tests. See the ``CHANGES-2.1.txt`` file for a full list of changes. Tested Platforms ---------------- This list of platforms comes from the latest version of log4sh as shUnit2 is used in the testing of log4sh on each of these platforms. Cygwin - bash 3.2.15(13) - pdksh 5.2.14 Linux - bash 3.1.17(1), 3.2.10(1) - dash 0.5.3 - ksh 1993-12-28 - pdksh 5.2.14 - zsh 4.3.2 (does not work) Mac OS X 10.4.9 (Darwin 8.9.1) - bash 2.05b.0(1) - ksh 1993-12-28 Solaris 8 U3 (x86) - /bin/sh - bash 2.03.0(1) - ksh M-11/16/88i Solaris 10 U2 (sparc, x86) - /bin/sh - bash 3.00.16(1) - ksh M-11/16/88i New Features ------------ None. Changes and Enhancements ------------------------ The internal test in ``assertFalse()`` now accepts any non-zero value as false. The ``assertTrue()`` and ``assertFalse()`` functions now accept an integer value for a conditional test. A value of '0' is considered 'true', while any non-zero value is considered 'false'. Self-testing unit tests were added. Bug Fixes --------- The ``fail()`` assert now honors skipping. The ``docs-docbook-prep`` target now works properly. All asserts now properly unset their variables. Deprecated Features ------------------- None. Known Bugs and Issues --------------------- Functions do not properly test for an invalid number of arguments. .. vim:fileencoding=latin1:ft=rst:spell:textwidth=80 ================================================ FILE: tests/shunit/doc/RELEASE_NOTES-2.1.2.txt ================================================ Release Notes for shUnit2 2.1.2 =============================== This release adds initial support for the zsh shell. Due to some differences with this shell as compared with others, some special checks have been added, and there are some extra requirements necessary when this shell is to be used. To use zsh with shUnit2, the following two requirements must be met: * The ``shwordsplit`` option must be set. * The ``function_argzero`` option must be unset. Please read the Shell Errata section of the documentation for guidance on how to meet these requirements. See the ``CHANGES-2.1.txt`` file for a full list of changes. Tested Platforms ---------------- This list of platforms comes from the latest version of log4sh as shUnit2 is used in the testing of log4sh on each of these platforms. Linux - bash 3.1.17(1), 3.2.25(1) - dash 0.5.4 - ksh 1993-12-28 - pdksh 5.2.14 - zsh 4.2.5, 4.3.4 Mac OS X 10.4.11 (Darwin 8.11.1) - bash 2.05b.0(1) - ksh 1993-12-28 - zsh 4.2.3 Solaris 10 U3 (x86) - /bin/sh - bash 3.00.16(1) - ksh M-11/16/88i - zsh 4.2.1 New Features ------------ Support for the zsh shell. Changes and Enhancements ------------------------ Added some argument count checks. Bug Fixes --------- None. Deprecated Features ------------------- None. Known Bugs and Issues --------------------- Functions do not properly test for an invalid number of arguments. ksh and pdksh do not pass null arguments (i.e. empty strings as '') properly, and as such checks do not work properly. zsh requires the ``shwordsplit`` option to be set, and the ``function_argzero`` option to be unset for proper operation. .. vim:fileencoding=latin1:ft=rst:spell:textwidth=80 ================================================ FILE: tests/shunit/doc/RELEASE_NOTES-2.1.3.txt ================================================ Release Notes for shUnit2 2.1.3 =============================== This release is minor feature release. It improves support for zsh (although it still isn't what it could be) and adds automated testing framework support by returning a non-zero exit when tests fail. To use zsh with shUnit2, the following two requirements must be met: * The ``shwordsplit`` option must be set. * The ``function_argzero`` option must be unset. Please read the Shell Errata section of the documentation for guidance on how to meet these requirements. See the ``CHANGES-2.1.txt`` file for a full list of changes. Tested Platforms ---------------- Cygwin - bash 3.2.33(18) - pdksh 5.2.14 Linux - bash 3.2.33(1) - dash 0.5.4 - ksh 1993-12-28 - pdksh 5.2.14 - zsh 4.3.4 Mac OS X 10.5.2 (Darwin 9.2.2) - bash 3.2.17(1) - ksh 1993-12-28 - zsh 4.3.4 Solaris 11 x86 (Nevada 77) - /bin/sh - bash 3.2.25(1) - ksh M-11/16/88i - zsh 4.3.4 New Features ------------ None. Changes and Enhancements ------------------------ Support for automated testing frameworks. Bug Fixes --------- Fixed some issues with zsh support. Deprecated Features ------------------- None. Known Bugs and Issues --------------------- Functions do not properly test for an invalid number of arguments. ksh and pdksh do not pass null arguments (i.e. empty strings as '') properly, and as such checks do not work properly. zsh requires the ``shwordsplit`` option to be set, and the ``function_argzero`` option to be unset for proper operation. .. vim:fileencoding=latin1:ft=rst:spell:textwidth=80 ================================================ FILE: tests/shunit/doc/RELEASE_NOTES-2.1.4.txt ================================================ Release Notes for shUnit2 2.1.4 =============================== This release contains lots of bug fixes and changes. Mostly, it fixes zsh support in zsh 3.0, and the handling of null values in ksh. To use zsh with shUnit2, the following requirement must be met: - The ``shwordsplit`` option must be set. Please read the Shell Errata section of the documentation for guidance on how to meet these requirements. See the ``CHANGES-2.1.txt`` file for a full list of changes. Tested Platforms ---------------- Cygwin - bash 3.2.39(19) - pdksh 5.2.14 - zsh 4.3.4 Linux (Ubuntu Dapper 6.06) - bash 3.1.17(1) - pdksh 5.2.14 - zsh 4.2.5 Linux (Ubuntu Hardy 8.04) - bash 3.2.39(1) - dash 0.5.4 - ksh 1993-12-28 - pdksh 5.2.14 - zsh 4.3.4 Mac OS X 10.5.4 (Darwin 9.4.0) - bash 3.2.17(1) - ksh 1993-12-28 - zsh 4.3.4 Solaris 9 U6 x86 - /bin/sh - bash 2.05.0(1) - ksh M-11/16/88i - zsh 3.0.8 Solaris 11 x86 (Nevada 77) - /bin/sh - bash 3.2.25(1) - ksh M-11/16/88i - zsh 4.3.4 New Features ------------ Support added to output assert source line number as part of assert messages. Changes and Enhancements ------------------------ Support for automated testing frameworks. Added argument count error checking to all functions. Bug Fixes --------- Fixed some issues with ksh and zsh support. Fixed off-by-one of exit value in trap handler. Fixed handling of null values under ksh. Fixed bug in last resort temporary directory creation. Deprecated Features ------------------- None. Known Bugs and Issues --------------------- zsh requires the ``shwordsplit`` option to be set. Line numbers in assert messages do not work properly with Bash 2.x. .. vim:fileencoding=latin1:ft=rst:spell:tw=80 ================================================ FILE: tests/shunit/doc/RELEASE_NOTES-2.1.5.txt ================================================ Release Notes for shUnit2 2.1.5 =============================== This release contains several bug fixes and changes. Additionally, it includes a rewrite of the test output to better match JUnit and PyUnit. This version also includes a slightly expanded set of coding standards by which shUnit2 is coded. It should help anyone reading the code to better understand it. Please read the Shell Errata section of the documentation for guidance on how to meet these requirements. See the ``CHANGES-2.1.txt`` file for a full list of changes. Tested Platforms ---------------- Cygwin - bash 3.2.39(20) - ksh (sym-link to pdksh) - pdksh 5.2.14 - zsh 4.3.4 Linux (Ubuntu Dapper 6.06) - bash 3.1.17(1) - ksh M-1993-12-28 - pdksh 5.2.14-99/07/13.2 - zsh 4.2.5 Linux (Ubuntu Hardy 8.04) - bash 3.2.39(1) - dash 0.5.4 - ksh M-1993-12-28 - pdksh 5.2.14-99/07/13.2 - zsh 4.3.4 Mac OS X 10.5.4 (Darwin 9.4.0) - bash 3.2.17(1) - ksh M-1993-12-28 - zsh 4.3.4 Solaris 9 U6 x86 - /bin/sh - bash 2.05.0(1) - ksh M-11/16/88i - zsh 3.0.8 Solaris 11 x86 (Nevada 77) - /bin/sh - bash 3.2.25(1) - ksh M-11/16/88i - zsh 4.3.4 New Features ------------ Support added for output assert source line number as part of assert messages. Issue #2: Added assertNotEquals() assert. Provided a public ``shunit_tmpDir`` variable that can be used by unit test scripts that need automated and guaranteed cleanup. Changes and Enhancements ------------------------ Issue #3: Removed the check for unset variables as shUnit2 should not expect scripts being tested to be clean. Issue #4: Rewrote the test summary. It is now greatly simplified and much more script friendly. Issue #5: Fixed the documentation around the usage of failures. Issue #9: Added unit tests and improved documentation around the use of macros. Code updated to meet documented coding standards. Improved code reuse of ``_shunit_exit()`` and ``_shunit_fatal()`` functions. All output except shUnit2 error messages now goes to STDOUT. Converted DocBook documentation to reStructuredText for easier maintenance. Bug Fixes --------- Issue #1: Fixed bug in rap code where certain types of exit conditions did not generate the ending report. Issue #7: Fixed duplicated printing of messages passed to asserts. Fixed bugs in ``shlib_relToAbsPath()`` in ``shlib``. Deprecated Features ------------------- None. Known Bugs and Issues --------------------- Zsh requires the ``shwordsplit`` option to be set. See the documentation for examples of how to do this. Line numbers in assert messages do not work properly with BASH 2.x. The Bourne shell of Solaris, BASH 2.x, and Zsh 3.0.x do not properly catch the SIGTERM signal. As such, shell interpreter failures due to such things as unbound variables cannot be caught. (See ``shunit_test_misc.sh``) .. vim:fileencoding=latin1:ft=rst:spell:tw=80 ================================================ FILE: tests/shunit/doc/RELEASE_NOTES-2.1.6.txt ================================================ Release Notes for shUnit2 2.1.6 =============================== This release contains bug fixes and changes. It is also the first release to support running shunit2 as a standalone program. Please read the Shell Errata section of the documentation for guidance on how to meet these requirements. See the ``CHANGES-2.1.txt`` file for a full list of changes. New Features ------------ Support for running shUnit2 as a standalone program. This makes it possible for users to execute their unit tests in a manner that is not dependent on the location an OS distribution maintainer chose to place shUnit2 in the file system. Added support for functions defined like 'function someFunction()'. Changes and Enhancements ------------------------ Renamed the public ``shunit_tmpDir`` variable to ``SHUNIT_TMPDIR`` to be more consistent with the ``TMPDIR`` variable. Bug Fixes --------- Fixed issue where shunit2 would fail on some distributions when creating a temporary directory because the **od** command was not present. Deprecated Features ------------------- None. Known Bugs and Issues --------------------- Zsh requires the ``shwordsplit`` option to be set. See the documentation for examples of how to do this. Line numbers in assert messages do not work properly with BASH 2.x. The Bourne shell of Solaris, BASH 2.x, and Zsh 3.0.x do not properly catch the SIGTERM signal. As such, shell interpreter failures due to such things as unbound variables cannot be caught. (See ``shunit_test_misc.sh``) Tested Platforms ---------------- Cygwin 1.7.9 (Windows XP SP2) - bash 4.1.10(4) - dash 0.5.6.1 - ksh (sym-link to pdksh) - pdksh 5.2.14 - zsh 4.3.11 Linux (Ubuntu Dapper 6.06.2 LTS) - bash 3.1.17(1) - dash 0.5.3 - ksh (sym-link to pdksh) - pdksh 5.2.14-99/07/13.2 - zsh 4.2.5 Linux (Ubuntu Hardy 8.04.4 LTS) - bash 3.2.39(1) - dash 0.5.4 - ksh M-1993-12-28 - pdksh 5.2.14-99/07/13.2 - zsh 4.3.4 Linux (Ubuntu Lucid 10.04.2 LTS) - bash 4.1.5(1) - dash 0.5.5.1 - ksh JM-93t+-2009-05-01 - pdksh 5.2.14-99/07/13.2 - zsh 4.3.10 Mac OS X 10.6.7 - bash 3.2.48(1) - ksh M-1993-12-28 - zsh 4.3.9 Solaris 8 U7 x86 - /bin/sh - bash 2.03.0(1) - ksh M-11/16/88i - zsh 3.0.6 Solaris 9 U6 x86 - /bin/sh - bash 2.05.0(1) - ksh M-11/16/88i - zsh 3.0.8 OpenSolaris 2009.06(snv_111b) x86 - /bin/sh - bash 3.2.25(1) - ksh 2008-11-04 .. vim:fileencoding=latin1:ft=rst:spell:tw=80 ================================================ FILE: tests/shunit/doc/RELEASE_NOTES-2.1.7.md ================================================ # shUnit2 2.1.7 Release Notes https://github.com/kward/shunit2 This release contains bug fixes and enhancements. It is the first release since moving to GitHub. Users can now clone the latest version at any time. See the `CHANGES-2.1.md` file for a full list of changes. ## New Features Colorized output, based on popular demand. shUnit2 output is now colorized based on the result of the asserts. ## Changes and Enhancements With the move to GitHub, the shUnit2 unit tests are run on every commit using the [Travis CI][TravisCI] continuous integration framework. Additionally, all code is run through [ShellCheck](http:/www.shellcheck.net/) on every commit. [TravisCI]: https://travis-ci.org/kward/shunit2 Shell commands in shUnit2 are prefixed with '\' so that they can be stubbed in tests. ## Bug Fixes shUnit2 no longer exits with an 'OK' result if there were syntax errors due to incorrect usage of the assert commands. ## Deprecated Features None. ## Known Bugs and Issues Zsh requires the `shwordsplit` option to be set. See the documentation for examples of how to do this. Line numbers in assert messages do not work properly with BASH 2.x. The Bourne shell of Solaris, BASH 2.x, and Zsh 3.0.x do not properly catch the SIGTERM signal. As such, shell interpreter failures due to such things as unbound variables cannot be caught. (See `shunit_test_misc.sh`) ## Tested Platforms Continuous integration testing is provided by [Travis CI][TravisCI]. Tested OSes: - Linux - macOS Tested shells: - /bin/sh - ash - bash - dash - ksh - pdksh - zsh ================================================ FILE: tests/shunit/doc/TODO.txt ================================================ Make it possible to execute a single test by passing the name of the test on the command line Add support for '--randomize-order' so that the test order is randomized to check for dependencies (which shouldn't be there) between tests. --debug option to display point in source code (line number and such) where the problem showed up. assertTrue() just gives 'ASSERT:', nothing else :-(. others too? upd: assertNull() will give message passed, but nothing else useful :-( $Revision$ ================================================ FILE: tests/shunit/doc/contributors.md ================================================ The original author of shunit2 is Kate Ward. The following people have contributed in some way or another to shunit2. - [Alex Harvey](https://github.com/alexharv074) - Bryan Larsen - [David Acacio](https://github.com/dacacioa) - Kevin Van Horn - [Maciej Bliziński](https://github.com/automatthias) - Mario Sparada - Mathias Goldau - Richard Jensen - Rob Holland - Rocky Bernstein - [rugk](https://github.com/rugk) - wood4321 (of code.google.com) ================================================ FILE: tests/shunit/doc/design_doc.txt ================================================ Design Doc for shUnit shUnit is based upon JUnit. The initial ideas for the script came from the book "Pragmatic Unit Testing - In Java with JUnit" by Andrew Hunt and David Thomas. The script was written to perform unit testing for log4sh. log4sh had grown enough that it was becoming difficult to easily test and and verify that the tests passed for the many different operating systems on which it was being used. The functions in shUnit are meant to match those in JUnit as much as possible where shell allows. In the initial version, there will be no concept of exceptions (as normal POSIX shell has no concept of them) but attempts to trap problems will be done. Programatic Standards: * SHUNIT_TRUE - public global constant * __SHUNIT_SHELL_FLAGS - private global constant * __shunit_oldShellFlags - private global variable * assertEquals - public unit test function * shunit_publicFunc - public shUnit function; can be called from parent unit test script * _shunit_privateFunc - private shUnit function; should not be called from parent script. meant for internal use by shUnit * _su_myVar - variable inside a public function. prefixing with '_su_' to reduce the chances that a variable outside of shUnit will be overridden. * _su__myVar - variable inside a private function. prefixing with '_su__' to reduce the chances that a variable in a shUnit public function, or a variable outside of shUnit will be overridden. $Revision$ ================================================ FILE: tests/shunit/examples/equality_test.sh ================================================ #! /bin/sh # file: examples/equality_test.sh testEquality() { assertEquals 1 1 } # Load and run shUnit2. . ../shunit2 ================================================ FILE: tests/shunit/examples/lineno_test.sh ================================================ #! /bin/sh # file: examples/lineno_test.sh testLineNo() { # This assert will have line numbers included (e.g. "ASSERT:[123] ...") if # they are supported. echo "_ASSERT_EQUALS_ macro value: ${_ASSERT_EQUALS_}" ${_ASSERT_EQUALS_} '"not equal"' 1 2 # This assert will not have line numbers included (e.g. "ASSERT: ..."). assertEquals 'not equal' 1 2 } # Load and run shUnit2. . ../shunit2 ================================================ FILE: tests/shunit/examples/math.inc ================================================ # available as examples/math.inc add_generic() { num_a=$1 num_b=$2 expr $1 + $2 } add_bash() { num_a=$1 num_b=$2 echo $(($1 + $2)) } ================================================ FILE: tests/shunit/examples/math_test.sh ================================================ #! /bin/sh # file: examples/math_test.sh testAdding() { result=`add_generic 1 2` assertEquals \ "the result of '${result}' was wrong" \ 3 "${result}" # Disable non-generic tests. [ -z "${BASH_VERSION:-}" ] && startSkipping result=`add_bash 1 2` assertEquals \ "the result of '${result}' was wrong" \ 3 "${result}" } oneTimeSetUp() { # Load include to test. . ./math.inc } # Load and run shUnit2. . ../shunit2 ================================================ FILE: tests/shunit/examples/mkdir_test.sh ================================================ #!/bin/sh # vim:et:ft=sh:sts=2:sw=2 # # Copyright 2008-2019 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 license. # http://www.apache.org/licenses/LICENSE-2.0 # # shUnit2 -- Unit testing framework for Unix shell scripts. # https://github.com/kward/shunit2 # # Author: kate.ward@forestent.com (Kate Ward) # # Example unit test for the mkdir command. # # There are times when an existing shell script needs to be tested. In this # example, we will test several aspects of the the mkdir command, but the # techniques could be used for any existing shell script. testMissingDirectoryCreation() { ${mkdirCmd} "${testDir}" >${stdoutF} 2>${stderrF} rtrn=$? th_assertTrueWithNoOutput ${rtrn} "${stdoutF}" "${stderrF}" assertTrue 'directory missing' "[ -d '${testDir}' ]" } testExistingDirectoryCreationFails() { # Create a directory to test against. ${mkdirCmd} "${testDir}" # Test for expected failure while trying to create directory that exists. ${mkdirCmd} "${testDir}" >${stdoutF} 2>${stderrF} rtrn=$? assertFalse 'expecting return code of 1 (false)' ${rtrn} assertNull 'unexpected output to stdout' "`cat ${stdoutF}`" assertNotNull 'expected error message to stderr' "`cat ${stderrF}`" assertTrue 'directory missing' "[ -d '${testDir}' ]" } testRecursiveDirectoryCreation() { testDir2="${testDir}/test2" ${mkdirCmd} -p "${testDir2}" >${stdoutF} 2>${stderrF} rtrn=$? th_assertTrueWithNoOutput ${rtrn} "${stdoutF}" "${stderrF}" assertTrue 'first directory missing' "[ -d '${testDir}' ]" assertTrue 'second directory missing' "[ -d '${testDir2}' ]" } th_assertTrueWithNoOutput() { th_return_=$1 th_stdout_=$2 th_stderr_=$3 assertFalse 'unexpected output to STDOUT' "[ -s '${th_stdout_}' ]" assertFalse 'unexpected output to STDERR' "[ -s '${th_stderr_}' ]" unset th_return_ th_stdout_ th_stderr_ } oneTimeSetUp() { outputDir="${SHUNIT_TMPDIR}/output" mkdir "${outputDir}" stdoutF="${outputDir}/stdout" stderrF="${outputDir}/stderr" mkdirCmd='mkdir' # save command name in variable to make future changes easy testDir="${SHUNIT_TMPDIR}/some_test_dir" } tearDown() { rm -fr "${testDir}" } # Load and run shUnit2. [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 . ../shunit2 ================================================ FILE: tests/shunit/examples/mock_file.sh ================================================ #!/bin/sh # # shUnit2 example for mocking files. # # This example demonstrates two different mechanisms for mocking files on the # system. The first method is preferred for testing specific aspects of a file, # and the second method is preferred when multiple tests need access to the # same mock data. # # When mocking files, the key thing of importance is providing the code under # test with the correct file to read. The best practice for writing code where # files need to be mocked is either: # - Pass the filename to be tested into a function and test that function, or # - Provide a function that returns the name of the filename to be read. # # The first case is preferred whenever possible as it allows the unit test to # be explicit about what is being tested. The second case is useful when the # first case is not achievable. # # For the second case, there are two common methods to mock the filename # returned by the function: # - Provide a special value (e.g. a mock variable) that is only available # during testing, or # - Override something (e.g. the constant) in the test script. # # The first case is preferred as it doesn't require the unit test to alter code # in any way. Yes, it means that the code itself knows that it is under test, # and it behaves slightly differently than under normal conditions, but a # visual inspection of the code by the developer should be sufficient to # validate proper functionality of such a simple function. # Treat unset variables as an error. set -u PASSWD='/etc/passwd' # Read the root UID from the passwd filename provided as the first argument. root_uid_from_passed_filename() { filename=$1 root_uid "${filename}" unset filename } # Read the root UID from the passwd filename derived by call to the # passwd_filename() function. root_uid_from_derived_filename() { root_uid "$(passwd_filename)" } passwd_filename() { if [ -n "${MOCK_PASSWD:-}" ]; then echo "${MOCK_PASSWD}" # Mock file for testing. return fi echo "${PASSWD}" } # Extract the root UID. root_uid() { awk -F: 'u==$1{print $3}' u=root "$1"; } main() { echo "root_uid_from_passed_filename:" root_uid_from_passed_filename "${PASSWD}" echo echo "root_uid_from_derived_filename:" root_uid_from_derived_filename } # Execute main() if this is run in standalone mode (i.e. not in a unit test). ARGV0="$(basename "$0")" argv0="$(echo "${ARGV0}" |sed 's/_test$//;s/_test\.sh$//')" if [ "${ARGV0}" = "${argv0}" ]; then main "$@" fi ================================================ FILE: tests/shunit/examples/mock_file_test.sh ================================================ #!/bin/sh # # shUnit2 example for mocking files. MOCK_PASSWD='' # This will be overridden in oneTimeSetUp(). test_root_uid_from_passed_filename() { result="$(root_uid_from_passed_filename "${MOCK_PASSWD}")" assertEquals 'unexpected root uid' '0' "${result}" } test_root_uid_from_derived_filename() { result="$(root_uid_from_derived_filename)" assertEquals 'unexpected root uid' '0' "${result}" } oneTimeSetUp() { # Provide a mock passwd file for testing. This will be cleaned up # automatically by shUnit2. MOCK_PASSWD="${SHUNIT_TMPDIR}/passwd" cat <"${MOCK_PASSWD}" nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false root:*:0:0:System Administrator:/var/root:/bin/sh daemon:*:1:1:System Services:/var/root:/usr/bin/false EOF # Load script under test. . './mock_file.sh' } # Load and run shUnit2. [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 . ../shunit2 ================================================ FILE: tests/shunit/examples/party_test.sh ================================================ #! /bin/sh # file: examples/party_test.sh # # This test is mostly for fun. Technically, it is a bad example of a unit test # because of the temporal requirement, namely that the year be 1999. A better # test would have been to pass in both a known-bad and known-good year into a # function, and test for the expected result. testPartyLikeItIs1999() { year=`date '+%Y'` assertEquals "It's not 1999 :-(" \ '1999' "${year}" } # Load and run shUnit2. . ../shunit2 ================================================ FILE: tests/shunit/examples/suite_test.sh ================================================ #!/bin/sh # file: examples/suite_test.sh # # This test demonstrates the use of suites. Note: the suite functionality is # deprecated as of v2.1.0, and will be removed in a future major release. # suite is a special function called by shUnit2 to setup a suite of tests. It # enables a developer to call a set of functions that contain tests without # needing to rename the functions to start with "test". # # Tests that are to be called from within `suite()` are added to the list of # executable tests by means of the `suite_addTest()` function. suite() { # Add the suite_test_one() function to the list of executable tests. suite_addTest suite_test_one # Call the suite_test_two() function, but note that the test results will not # be added to the global stats, and therefore not reported at the end of the # unit test execution. suite_test_two } suite_test_one() { assertEquals 1 1 } suite_test_two() { assertNotEquals 1 2 } # Load and run shUnit2. . ../shunit2 ================================================ FILE: tests/shunit/lib/shflags ================================================ # vim:et:ft=sh:sts=2:sw=2 # # Copyright 2008-2017 Kate Ward. All Rights Reserved. # Released under the Apache License 2.0 license. # http://www.apache.org/licenses/LICENSE-2.0 # # shFlags -- Advanced command-line flag library for Unix shell scripts. # https://github.com/kward/shflags # # Author: kate.ward@forestent.com (Kate Ward) # # This module implements something like the gflags library available # from https://github.com/gflags/gflags. # # FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take # a name, default value, help-string, and optional 'short' name (one-letter # name). Some flags have other arguments, which are described with the flag. # # DEFINE_string: takes any input, and interprets it as a string. # # DEFINE_boolean: does not take any arguments. Say --myflag to set # FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false. For short # flags, passing the flag on the command-line negates the default value, i.e. # if the default is true, passing the flag sets the value to false. # # DEFINE_float: takes an input and interprets it as a floating point number. As # shell does not support floats per-se, the input is merely validated as # being a valid floating point value. # # DEFINE_integer: takes an input and interprets it as an integer. # # SPECIAL FLAGS: There are a few flags that have special meaning: # --help (or -?) prints a list of all the flags in a human-readable fashion # --flagfile=foo read flags from foo. (not implemented yet) # -- as in getopt(), terminates flag-processing # # EXAMPLE USAGE: # # -- begin hello.sh -- # #! /bin/sh # . ./shflags # DEFINE_string name 'world' "somebody's name" n # FLAGS "$@" || exit $? # eval set -- "${FLAGS_ARGV}" # echo "Hello, ${FLAGS_name}." # -- end hello.sh -- # # $ ./hello.sh -n Kate # Hello, Kate. # # CUSTOMIZABLE BEHAVIOR: # # A script can override the default 'getopt' command by providing the path to # an alternate implementation by defining the FLAGS_GETOPT_CMD variable. # # NOTES: # # * Not all systems include a getopt version that supports long flags. On these # systems, only short flags are recognized. #============================================================================== # shFlags # # Shared attributes: # flags_error: last error message # flags_output: last function output (rarely valid) # flags_return: last return value # # __flags_longNames: list of long names for all flags # __flags_shortNames: list of short names for all flags # __flags_boolNames: list of boolean flag names # # __flags_opts: options parsed by getopt # # Per-flag attributes: # FLAGS_: contains value of flag named 'flag_name' # __flags__default: the default flag value # __flags__help: the flag help string # __flags__short: the flag short name # __flags__type: the flag type # # Notes: # - lists of strings are space separated, and a null value is the '~' char. # ### ShellCheck (http://www.shellcheck.net/) # $() are not fully portable (POSIX != portable). # shellcheck disable=SC2006 # [ p -a q ] are well defined enough (vs [ p ] && [ q ]). # shellcheck disable=SC2166 # Return if FLAGS already loaded. [ -n "${FLAGS_VERSION:-}" ] && return 0 FLAGS_VERSION='1.2.3pre' # Return values that scripts can use. FLAGS_TRUE=0 FLAGS_FALSE=1 FLAGS_ERROR=2 # Logging levels. FLAGS_LEVEL_DEBUG=0 FLAGS_LEVEL_INFO=1 FLAGS_LEVEL_WARN=2 FLAGS_LEVEL_ERROR=3 FLAGS_LEVEL_FATAL=4 __FLAGS_LEVEL_DEFAULT=${FLAGS_LEVEL_WARN} # Determine some reasonable command defaults. __FLAGS_EXPR_CMD='expr --' __FLAGS_UNAME_S=`uname -s` if [ "${__FLAGS_UNAME_S}" = 'BSD' ]; then __FLAGS_EXPR_CMD='gexpr --' else _flags_output_=`${__FLAGS_EXPR_CMD} 2>&1` if [ $? -eq ${FLAGS_TRUE} -a "${_flags_output_}" = '--' ]; then # We are likely running inside BusyBox. __FLAGS_EXPR_CMD='expr' fi unset _flags_output_ fi # Commands a user can override if desired. FLAGS_EXPR_CMD=${FLAGS_EXPR_CMD:-${__FLAGS_EXPR_CMD}} FLAGS_GETOPT_CMD=${FLAGS_GETOPT_CMD:-getopt} # Specific shell checks. if [ -n "${ZSH_VERSION:-}" ]; then setopt |grep "^shwordsplit$" >/dev/null if [ $? -ne ${FLAGS_TRUE} ]; then _flags_fatal 'zsh shwordsplit option is required for proper zsh operation' fi if [ -z "${FLAGS_PARENT:-}" ]; then _flags_fatal "zsh does not pass \$0 through properly. please declare' \ \"FLAGS_PARENT=\$0\" before calling shFlags" fi fi # Can we use built-ins? ( echo "${FLAGS_TRUE#0}"; ) >/dev/null 2>&1 if [ $? -eq ${FLAGS_TRUE} ]; then __FLAGS_USE_BUILTIN=${FLAGS_TRUE} else __FLAGS_USE_BUILTIN=${FLAGS_FALSE} fi # # Constants. # # Reserved flag names. __FLAGS_RESERVED_LIST=' ARGC ARGV ERROR FALSE GETOPT_CMD HELP PARENT TRUE ' __FLAGS_RESERVED_LIST="${__FLAGS_RESERVED_LIST} VERSION " # Determined getopt version (standard or enhanced). __FLAGS_GETOPT_VERS_STD=0 __FLAGS_GETOPT_VERS_ENH=1 # shellcheck disable=SC2120 _flags_getopt_vers() { _flags_getopt_cmd_=${1:-${FLAGS_GETOPT_CMD}} case "`${_flags_getopt_cmd_} -lfoo '' --foo 2>&1`" in ' -- --foo') echo ${__FLAGS_GETOPT_VERS_STD} ;; ' --foo --') echo ${__FLAGS_GETOPT_VERS_ENH} ;; # Unrecognized output. Assuming standard getopt version. *) echo ${__FLAGS_GETOPT_VERS_STD} ;; esac unset _flags_getopt_cmd_ } # shellcheck disable=SC2119 __FLAGS_GETOPT_VERS=`_flags_getopt_vers` # getopt optstring lengths __FLAGS_OPTSTR_SHORT=0 __FLAGS_OPTSTR_LONG=1 __FLAGS_NULL='~' # Flag info strings. __FLAGS_INFO_DEFAULT='default' __FLAGS_INFO_HELP='help' __FLAGS_INFO_SHORT='short' __FLAGS_INFO_TYPE='type' # Flag lengths. __FLAGS_LEN_SHORT=0 __FLAGS_LEN_LONG=1 # Flag types. __FLAGS_TYPE_NONE=0 __FLAGS_TYPE_BOOLEAN=1 __FLAGS_TYPE_FLOAT=2 __FLAGS_TYPE_INTEGER=3 __FLAGS_TYPE_STRING=4 # Set the constants readonly. __flags_constants=`set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'` for __flags_const in ${__flags_constants}; do # Skip certain flags. case ${__flags_const} in FLAGS_HELP) continue ;; FLAGS_PARENT) continue ;; esac # Set flag readonly. if [ -z "${ZSH_VERSION:-}" ]; then readonly "${__flags_const}" continue fi case ${ZSH_VERSION} in [123].*) readonly "${__flags_const}" ;; *) readonly -g "${__flags_const}" ;; # Declare readonly constants globally. esac done unset __flags_const __flags_constants # # Internal variables. # # Space separated lists. __flags_boolNames=' ' # Boolean flag names. __flags_longNames=' ' # Long flag names. __flags_shortNames=' ' # Short flag names. __flags_definedNames=' ' # Defined flag names (used for validation). __flags_columns='' # Screen width in columns. __flags_level=0 # Default logging level. __flags_opts='' # Temporary storage for parsed getopt flags. #------------------------------------------------------------------------------ # Private functions. # # Logging functions. _flags_debug() { [ ${__flags_level} -le ${FLAGS_LEVEL_DEBUG} ] || return echo "flags:DEBUG $*" >&2 } _flags_info() { [ ${__flags_level} -le ${FLAGS_LEVEL_INFO} ] || return echo "flags:INFO $*" >&2 } _flags_warn() { [ ${__flags_level} -le ${FLAGS_LEVEL_WARN} ] || return echo "flags:WARN $*" >&2 } _flags_error() { [ ${__flags_level} -le ${FLAGS_LEVEL_ERROR} ] || return echo "flags:ERROR $*" >&2 } _flags_fatal() { [ ${__flags_level} -le ${FLAGS_LEVEL_FATAL} ] || return echo "flags:FATAL $*" >&2 exit ${FLAGS_ERROR} } # Get the logging level. flags_loggingLevel() { echo ${__flags_level}; } # Set the logging level. # # Args: # _flags_level_: integer: new logging level # Returns: # nothing flags_setLoggingLevel() { [ $# -ne 1 ] && _flags_fatal "flags_setLevel(): logging level missing" _flags_level_=$1 [ "${_flags_level_}" -ge "${FLAGS_LEVEL_DEBUG}" \ -a "${_flags_level_}" -le "${FLAGS_LEVEL_FATAL}" ] \ || _flags_fatal "Invalid logging level '${_flags_level_}' specified." __flags_level=$1 unset _flags_level_ } # Define a flag. # # Calling this function will define the following info variables for the # specified flag: # FLAGS_flagname - the name for this flag (based upon the long flag name) # __flags__default - the default value # __flags_flagname_help - the help string # __flags_flagname_short - the single letter alias # __flags_flagname_type - the type of flag (one of __FLAGS_TYPE_*) # # Args: # _flags_type_: integer: internal type of flag (__FLAGS_TYPE_*) # _flags_name_: string: long flag name # _flags_default_: default flag value # _flags_help_: string: help string # _flags_short_: string: (optional) short flag name # Returns: # integer: success of operation, or error _flags_define() { if [ $# -lt 4 ]; then flags_error='DEFINE error: too few arguments' flags_return=${FLAGS_ERROR} _flags_error "${flags_error}" return ${flags_return} fi _flags_type_=$1 _flags_name_=$2 _flags_default_=$3 _flags_help_=${4:-§} # Special value '§' indicates no help string provided. _flags_short_=${5:-${__FLAGS_NULL}} _flags_debug "type:${_flags_type_} name:${_flags_name_}" \ "default:'${_flags_default_}' help:'${_flags_help_}'" \ "short:${_flags_short_}" _flags_return_=${FLAGS_TRUE} _flags_usName_="`_flags_underscoreName "${_flags_name_}"`" # Check whether the flag name is reserved. _flags_itemInList "${_flags_usName_}" "${__FLAGS_RESERVED_LIST}" if [ $? -eq ${FLAGS_TRUE} ]; then flags_error="flag name (${_flags_name_}) is reserved" _flags_return_=${FLAGS_ERROR} fi # Require short option for getopt that don't support long options. if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ -a "${__FLAGS_GETOPT_VERS}" -ne "${__FLAGS_GETOPT_VERS_ENH}" \ -a "${_flags_short_}" = "${__FLAGS_NULL}" ] then flags_error="short flag required for (${_flags_name_}) on this platform" _flags_return_=${FLAGS_ERROR} fi # Check for existing long name definition. if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then if _flags_itemInList "${_flags_usName_}" "${__flags_definedNames}"; then flags_error="definition for ([no]${_flags_name_}) already exists" _flags_warn "${flags_error}" _flags_return_=${FLAGS_FALSE} fi fi # Check for existing short name definition. if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ -a "${_flags_short_}" != "${__FLAGS_NULL}" ] then if _flags_itemInList "${_flags_short_}" "${__flags_shortNames}"; then flags_error="flag short name (${_flags_short_}) already defined" _flags_warn "${flags_error}" _flags_return_=${FLAGS_FALSE} fi fi # Handle default value. Note, on several occasions the 'if' portion of an # if/then/else contains just a ':' which does nothing. A binary reversal via # '!' is not done because it does not work on all shells. if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then case ${_flags_type_} in ${__FLAGS_TYPE_BOOLEAN}) if _flags_validBool "${_flags_default_}"; then case ${_flags_default_} in true|t|0) _flags_default_=${FLAGS_TRUE} ;; false|f|1) _flags_default_=${FLAGS_FALSE} ;; esac else flags_error="invalid default flag value '${_flags_default_}'" _flags_return_=${FLAGS_ERROR} fi ;; ${__FLAGS_TYPE_FLOAT}) if _flags_validFloat "${_flags_default_}"; then : else flags_error="invalid default flag value '${_flags_default_}'" _flags_return_=${FLAGS_ERROR} fi ;; ${__FLAGS_TYPE_INTEGER}) if _flags_validInt "${_flags_default_}"; then : else flags_error="invalid default flag value '${_flags_default_}'" _flags_return_=${FLAGS_ERROR} fi ;; ${__FLAGS_TYPE_STRING}) ;; # Everything in shell is a valid string. *) flags_error="unrecognized flag type '${_flags_type_}'" _flags_return_=${FLAGS_ERROR} ;; esac fi if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then # Store flag information. eval "FLAGS_${_flags_usName_}='${_flags_default_}'" eval "__flags_${_flags_usName_}_${__FLAGS_INFO_TYPE}=${_flags_type_}" eval "__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}=\ \"${_flags_default_}\"" eval "__flags_${_flags_usName_}_${__FLAGS_INFO_HELP}=\"${_flags_help_}\"" eval "__flags_${_flags_usName_}_${__FLAGS_INFO_SHORT}='${_flags_short_}'" # append flag names to name lists __flags_shortNames="${__flags_shortNames}${_flags_short_} " __flags_longNames="${__flags_longNames}${_flags_name_} " [ "${_flags_type_}" -eq "${__FLAGS_TYPE_BOOLEAN}" ] && \ __flags_boolNames="${__flags_boolNames}no${_flags_name_} " # Append flag names to defined names for later validation checks. __flags_definedNames="${__flags_definedNames}${_flags_usName_} " [ "${_flags_type_}" -eq "${__FLAGS_TYPE_BOOLEAN}" ] && \ __flags_definedNames="${__flags_definedNames}no${_flags_usName_} " fi flags_return=${_flags_return_} unset _flags_default_ _flags_help_ _flags_name_ _flags_return_ \ _flags_short_ _flags_type_ _flags_usName_ [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" return ${flags_return} } # Underscore a flag name by replacing dashes with underscores. # # Args: # unnamed: string: log flag name # Output: # string: underscored name _flags_underscoreName() { echo "$1" |tr '-' '_' } # Return valid getopt options using currently defined list of long options. # # This function builds a proper getopt option string for short (and long) # options, using the current list of long options for reference. # # Args: # _flags_optStr: integer: option string type (__FLAGS_OPTSTR_*) # Output: # string: generated option string for getopt # Returns: # boolean: success of operation (always returns True) _flags_genOptStr() { _flags_optStrType_=$1 _flags_opts_='' for _flags_name_ in ${__flags_longNames}; do _flags_usName_="`_flags_underscoreName "${_flags_name_}"`" _flags_type_="`_flags_getFlagInfo "${_flags_usName_}" "${__FLAGS_INFO_TYPE}"`" [ $? -eq ${FLAGS_TRUE} ] || _flags_fatal 'call to _flags_type_ failed' case ${_flags_optStrType_} in ${__FLAGS_OPTSTR_SHORT}) _flags_shortName_="`_flags_getFlagInfo \ "${_flags_usName_}" "${__FLAGS_INFO_SHORT}"`" if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then _flags_opts_="${_flags_opts_}${_flags_shortName_}" # getopt needs a trailing ':' to indicate a required argument. [ "${_flags_type_}" -ne "${__FLAGS_TYPE_BOOLEAN}" ] && \ _flags_opts_="${_flags_opts_}:" fi ;; ${__FLAGS_OPTSTR_LONG}) _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_name_}" # getopt needs a trailing ':' to indicate a required argument [ "${_flags_type_}" -ne "${__FLAGS_TYPE_BOOLEAN}" ] && \ _flags_opts_="${_flags_opts_}:" ;; esac done echo "${_flags_opts_}" unset _flags_name_ _flags_opts_ _flags_optStrType_ _flags_shortName_ \ _flags_type_ _flags_usName_ return ${FLAGS_TRUE} } # Returns flag details based on a flag name and flag info. # # Args: # string: underscored flag name # string: flag info (see the _flags_define function for valid info types) # Output: # string: value of dereferenced flag variable # Returns: # integer: one of FLAGS_{TRUE|FALSE|ERROR} _flags_getFlagInfo() { # Note: adding gFI to variable names to prevent naming conflicts with calling # functions _flags_gFI_usName_=$1 _flags_gFI_info_=$2 # Example: given argument usName (underscored flag name) of 'my_flag', and # argument info of 'help', set the _flags_infoValue_ variable to the value of # ${__flags_my_flag_help}, and see if it is non-empty. _flags_infoVar_="__flags_${_flags_gFI_usName_}_${_flags_gFI_info_}" _flags_strToEval_="_flags_infoValue_=\"\${${_flags_infoVar_}:-}\"" eval "${_flags_strToEval_}" if [ -n "${_flags_infoValue_}" ]; then # Special value '§' indicates no help string provided. [ "${_flags_gFI_info_}" = ${__FLAGS_INFO_HELP} \ -a "${_flags_infoValue_}" = '§' ] && _flags_infoValue_='' flags_return=${FLAGS_TRUE} else # See if the _flags_gFI_usName_ variable is a string as strings can be # empty... # Note: the DRY principle would say to have this function call itself for # the next three lines, but doing so results in an infinite loop as an # invalid _flags_name_ will also not have the associated _type variable. # Because it doesn't (it will evaluate to an empty string) the logic will # try to find the _type variable of the _type variable, and so on. Not so # good ;-) # # Example cont.: set the _flags_typeValue_ variable to the value of # ${__flags_my_flag_type}, and see if it equals '4'. _flags_typeVar_="__flags_${_flags_gFI_usName_}_${__FLAGS_INFO_TYPE}" _flags_strToEval_="_flags_typeValue_=\"\${${_flags_typeVar_}:-}\"" eval "${_flags_strToEval_}" # shellcheck disable=SC2154 if [ "${_flags_typeValue_}" = "${__FLAGS_TYPE_STRING}" ]; then flags_return=${FLAGS_TRUE} else flags_return=${FLAGS_ERROR} flags_error="missing flag info variable (${_flags_infoVar_})" fi fi echo "${_flags_infoValue_}" unset _flags_gFI_usName_ _flags_gfI_info_ _flags_infoValue_ _flags_infoVar_ \ _flags_strToEval_ _flags_typeValue_ _flags_typeVar_ [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" return ${flags_return} } # Check for presence of item in a list. # # Passed a string (e.g. 'abc'), this function will determine if the string is # present in the list of strings (e.g. ' foo bar abc '). # # Args: # _flags_str_: string: string to search for in a list of strings # unnamed: list: list of strings # Returns: # boolean: true if item is in the list _flags_itemInList() { _flags_str_=$1 shift case " ${*:-} " in *\ ${_flags_str_}\ *) flags_return=${FLAGS_TRUE} ;; *) flags_return=${FLAGS_FALSE} ;; esac unset _flags_str_ return ${flags_return} } # Returns the width of the current screen. # # Output: # integer: width in columns of the current screen. _flags_columns() { if [ -z "${__flags_columns}" ]; then if eval stty size >/dev/null 2>&1; then # stty size worked :-) # shellcheck disable=SC2046 set -- `stty size` __flags_columns="${2:-}" fi fi if [ -z "${__flags_columns}" ]; then if eval tput cols >/dev/null 2>&1; then # shellcheck disable=SC2046 set -- `tput cols` __flags_columns="${1:-}" fi fi echo "${__flags_columns:-80}" } # Validate a boolean. # # Args: # _flags__bool: boolean: value to validate # Returns: # bool: true if the value is a valid boolean _flags_validBool() { _flags_bool_=$1 flags_return=${FLAGS_TRUE} case "${_flags_bool_}" in true|t|0) ;; false|f|1) ;; *) flags_return=${FLAGS_FALSE} ;; esac unset _flags_bool_ return ${flags_return} } # Validate a float. # # Args: # _flags_float_: float: value to validate # Returns: # bool: true if the value is a valid integer _flags_validFloat() { flags_return=${FLAGS_FALSE} [ -n "$1" ] || return ${flags_return} _flags_float_=$1 if _flags_validInt "${_flags_float_}"; then flags_return=${FLAGS_TRUE} elif _flags_useBuiltin; then _flags_float_whole_=${_flags_float_%.*} _flags_float_fraction_=${_flags_float_#*.} if _flags_validInt "${_flags_float_whole_:-0}" -a \ _flags_validInt "${_flags_float_fraction_}"; then flags_return=${FLAGS_TRUE} fi unset _flags_float_whole_ _flags_float_fraction_ else flags_return=${FLAGS_TRUE} case ${_flags_float_} in -*) # Negative floats. _flags_test_=`${FLAGS_EXPR_CMD} "${_flags_float_}" :\ '\(-[0-9]*\.[0-9]*\)'` ;; *) # Positive floats. _flags_test_=`${FLAGS_EXPR_CMD} "${_flags_float_}" :\ '\([0-9]*\.[0-9]*\)'` ;; esac [ "${_flags_test_}" != "${_flags_float_}" ] && flags_return=${FLAGS_FALSE} unset _flags_test_ fi unset _flags_float_ _flags_float_whole_ _flags_float_fraction_ return ${flags_return} } # Validate an integer. # # Args: # _flags_int_: integer: value to validate # Returns: # bool: true if the value is a valid integer _flags_validInt() { flags_return=${FLAGS_FALSE} [ -n "$1" ] || return ${flags_return} _flags_int_=$1 case ${_flags_int_} in -*.*) ;; # Ignore negative floats (we'll invalidate them later). -*) # Strip possible leading negative sign. if _flags_useBuiltin; then _flags_int_=${_flags_int_#-} else _flags_int_=`${FLAGS_EXPR_CMD} "${_flags_int_}" : '-\([0-9][0-9]*\)'` fi ;; esac case ${_flags_int_} in *[!0-9]*) flags_return=${FLAGS_FALSE} ;; *) flags_return=${FLAGS_TRUE} ;; esac unset _flags_int_ return ${flags_return} } # Parse command-line options using the standard getopt. # # Note: the flag options are passed around in the global __flags_opts so that # the formatting is not lost due to shell parsing and such. # # Args: # @: varies: command-line options to parse # Returns: # integer: a FLAGS success condition _flags_getoptStandard() { flags_return=${FLAGS_TRUE} _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` # Check for spaces in passed options. for _flags_opt_ in "$@"; do # Note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06. _flags_match_=`echo "x${_flags_opt_}x" |sed 's/ //g'` if [ "${_flags_match_}" != "x${_flags_opt_}x" ]; then flags_error='the available getopt does not support spaces in options' flags_return=${FLAGS_ERROR} break fi done if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then __flags_opts=`getopt "${_flags_shortOpts_}" "$@" 2>&1` _flags_rtrn_=$? if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then _flags_warn "${__flags_opts}" flags_error='unable to parse provided options with getopt.' flags_return=${FLAGS_ERROR} fi fi unset _flags_match_ _flags_opt_ _flags_rtrn_ _flags_shortOpts_ return ${flags_return} } # Parse command-line options using the enhanced getopt. # # Note: the flag options are passed around in the global __flags_opts so that # the formatting is not lost due to shell parsing and such. # # Args: # @: varies: command-line options to parse # Returns: # integer: a FLAGS success condition _flags_getoptEnhanced() { flags_return=${FLAGS_TRUE} _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` _flags_boolOpts_=`echo "${__flags_boolNames}" \ |sed 's/^ *//;s/ *$//;s/ /,/g'` _flags_longOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_LONG}` __flags_opts=`${FLAGS_GETOPT_CMD} \ -o "${_flags_shortOpts_}" \ -l "${_flags_longOpts_},${_flags_boolOpts_}" \ -- "$@" 2>&1` _flags_rtrn_=$? if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then _flags_warn "${__flags_opts}" flags_error='unable to parse provided options with getopt.' flags_return=${FLAGS_ERROR} fi unset _flags_boolOpts_ _flags_longOpts_ _flags_rtrn_ _flags_shortOpts_ return ${flags_return} } # Dynamically parse a getopt result and set appropriate variables. # # This function does the actual conversion of getopt output and runs it through # the standard case structure for parsing. The case structure is actually quite # dynamic to support any number of flags. # # Args: # argc: int: original command-line argument count # @: varies: output from getopt parsing # Returns: # integer: a FLAGS success condition _flags_parseGetopt() { _flags_argc_=$1 shift flags_return=${FLAGS_TRUE} if [ "${__FLAGS_GETOPT_VERS}" -ne "${__FLAGS_GETOPT_VERS_ENH}" ]; then # The @$ must be unquoted as it needs to be re-split. # shellcheck disable=SC2068 set -- $@ else # Note the quotes around the `$@' -- they are essential! eval set -- "$@" fi # Provide user with the number of arguments to shift by later. # NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not # properly give user access to non-flag arguments mixed in between flag # arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only # for backwards compatibility reasons. FLAGS_ARGC=`_flags_math "$# - 1 - ${_flags_argc_}"` export FLAGS_ARGC # Handle options. note options with values must do an additional shift. while true; do _flags_opt_=$1 _flags_arg_=${2:-} _flags_type_=${__FLAGS_TYPE_NONE} _flags_name_='' # Determine long flag name. case "${_flags_opt_}" in --) shift; break ;; # Discontinue option parsing. --*) # Long option. if _flags_useBuiltin; then _flags_opt_=${_flags_opt_#*--} else _flags_opt_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : '--\(.*\)'` fi _flags_len_=${__FLAGS_LEN_LONG} if _flags_itemInList "${_flags_opt_}" "${__flags_longNames}"; then _flags_name_=${_flags_opt_} else # Check for negated long boolean version. if _flags_itemInList "${_flags_opt_}" "${__flags_boolNames}"; then if _flags_useBuiltin; then _flags_name_=${_flags_opt_#*no} else _flags_name_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : 'no\(.*\)'` fi _flags_type_=${__FLAGS_TYPE_BOOLEAN} _flags_arg_=${__FLAGS_NULL} fi fi ;; -*) # Short option. if _flags_useBuiltin; then _flags_opt_=${_flags_opt_#*-} else _flags_opt_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : '-\(.*\)'` fi _flags_len_=${__FLAGS_LEN_SHORT} if _flags_itemInList "${_flags_opt_}" "${__flags_shortNames}"; then # Yes. Match short name to long name. Note purposeful off-by-one # (too high) with awk calculations. _flags_pos_=`echo "${__flags_shortNames}" \ |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \ e="${_flags_opt_}"` _flags_name_=`echo "${__flags_longNames}" \ |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"` fi ;; esac # Die if the flag was unrecognized. if [ -z "${_flags_name_}" ]; then flags_error="unrecognized option (${_flags_opt_})" flags_return=${FLAGS_ERROR} break fi # Set new flag value. _flags_usName_=`_flags_underscoreName "${_flags_name_}"` [ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \ _flags_type_=`_flags_getFlagInfo \ "${_flags_usName_}" ${__FLAGS_INFO_TYPE}` case ${_flags_type_} in ${__FLAGS_TYPE_BOOLEAN}) if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}" else eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}" fi else _flags_strToEval_="_flags_val_=\ \${__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}}" eval "${_flags_strToEval_}" # shellcheck disable=SC2154 if [ "${_flags_val_}" -eq ${FLAGS_FALSE} ]; then eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}" else eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}" fi fi ;; ${__FLAGS_TYPE_FLOAT}) if _flags_validFloat "${_flags_arg_}"; then eval "FLAGS_${_flags_usName_}='${_flags_arg_}'" else flags_error="invalid float value (${_flags_arg_})" flags_return=${FLAGS_ERROR} break fi ;; ${__FLAGS_TYPE_INTEGER}) if _flags_validInt "${_flags_arg_}"; then eval "FLAGS_${_flags_usName_}='${_flags_arg_}'" else flags_error="invalid integer value (${_flags_arg_})" flags_return=${FLAGS_ERROR} break fi ;; ${__FLAGS_TYPE_STRING}) eval "FLAGS_${_flags_usName_}='${_flags_arg_}'" ;; esac # Handle special case help flag. if [ "${_flags_usName_}" = 'help' ]; then # shellcheck disable=SC2154 if [ "${FLAGS_help}" -eq ${FLAGS_TRUE} ]; then flags_help flags_error='help requested' flags_return=${FLAGS_FALSE} break fi fi # Shift the option and non-boolean arguments out. shift [ "${_flags_type_}" != ${__FLAGS_TYPE_BOOLEAN} ] && shift done # Give user back non-flag arguments. FLAGS_ARGV='' while [ $# -gt 0 ]; do FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'" shift done unset _flags_arg_ _flags_len_ _flags_name_ _flags_opt_ _flags_pos_ \ _flags_strToEval_ _flags_type_ _flags_usName_ _flags_val_ return ${flags_return} } # Perform some path using built-ins. # # Args: # $@: string: math expression to evaluate # Output: # integer: the result # Returns: # bool: success of math evaluation _flags_math() { if [ $# -eq 0 ]; then flags_return=${FLAGS_FALSE} elif _flags_useBuiltin; then # Variable assignment is needed as workaround for Solaris Bourne shell, # which cannot parse a bare $((expression)). # shellcheck disable=SC2016 _flags_expr_='$(($@))' eval echo ${_flags_expr_} flags_return=$? unset _flags_expr_ else eval expr "$@" flags_return=$? fi return ${flags_return} } # Cross-platform strlen() implementation. # # Args: # _flags_str: string: to determine length of # Output: # integer: length of string # Returns: # bool: success of strlen evaluation _flags_strlen() { _flags_str_=${1:-} if [ -z "${_flags_str_}" ]; then flags_output=0 elif _flags_useBuiltin; then flags_output=${#_flags_str_} else flags_output=`${FLAGS_EXPR_CMD} "${_flags_str_}" : '.*'` fi flags_return=$? unset _flags_str_ echo "${flags_output}" return ${flags_return} } # Use built-in helper function to enable unit testing. # # Args: # None # Returns: # bool: true if built-ins should be used _flags_useBuiltin() { return ${__FLAGS_USE_BUILTIN}; } #------------------------------------------------------------------------------ # public functions # # A basic boolean flag. Boolean flags do not take any arguments, and their # value is either 1 (false) or 0 (true). For long flags, the false value is # specified on the command line by prepending the word 'no'. With short flags, # the presence of the flag toggles the current value between true and false. # Specifying a short boolean flag twice on the command results in returning the # value back to the default value. # # A default value is required for boolean flags. # # For example, lets say a Boolean flag was created whose long name was 'update' # and whose short name was 'x', and the default value was 'false'. This flag # could be explicitly set to 'true' with '--update' or by '-x', and it could be # explicitly set to 'false' with '--noupdate'. DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; } # Other basic flags. DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@"; } DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; } DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@"; } # Parse the flags. # # Args: # unnamed: list: command-line flags to parse # Returns: # integer: success of operation, or error FLAGS() { # Define a standard 'help' flag if one isn't already defined. [ -z "${__flags_help_type:-}" ] && \ DEFINE_boolean 'help' false 'show this help' 'h' # Parse options. if [ $# -gt 0 ]; then if [ "${__FLAGS_GETOPT_VERS}" -ne "${__FLAGS_GETOPT_VERS_ENH}" ]; then _flags_getoptStandard "$@" else _flags_getoptEnhanced "$@" fi flags_return=$? else # Nothing passed; won't bother running getopt. __flags_opts='--' flags_return=${FLAGS_TRUE} fi if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then _flags_parseGetopt $# "${__flags_opts}" flags_return=$? fi [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}" return ${flags_return} } # This is a helper function for determining the 'getopt' version for platforms # where the detection isn't working. It simply outputs debug information that # can be included in a bug report. # # Args: # none # Output: # debug info that can be included in a bug report # Returns: # nothing flags_getoptInfo() { # Platform info. _flags_debug "uname -a: `uname -a`" _flags_debug "PATH: ${PATH}" # Shell info. if [ -n "${BASH_VERSION:-}" ]; then _flags_debug 'shell: bash' _flags_debug "BASH_VERSION: ${BASH_VERSION}" elif [ -n "${ZSH_VERSION:-}" ]; then _flags_debug 'shell: zsh' _flags_debug "ZSH_VERSION: ${ZSH_VERSION}" fi # getopt info. ${FLAGS_GETOPT_CMD} >/dev/null _flags_getoptReturn=$? _flags_debug "getopt return: ${_flags_getoptReturn}" _flags_debug "getopt --version: `${FLAGS_GETOPT_CMD} --version 2>&1`" unset _flags_getoptReturn } # Returns whether the detected getopt version is the enhanced version. # # Args: # none # Output: # none # Returns: # bool: true if getopt is the enhanced version flags_getoptIsEnh() { test "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_ENH}" } # Returns whether the detected getopt version is the standard version. # # Args: # none # Returns: # bool: true if getopt is the standard version flags_getoptIsStd() { test "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_STD}" } # This is effectively a 'usage()' function. It prints usage information and # exits the program with ${FLAGS_FALSE} if it is ever found in the command line # arguments. Note this function can be overridden so other apps can define # their own --help flag, replacing this one, if they want. # # Args: # none # Returns: # integer: success of operation (always returns true) flags_help() { if [ -n "${FLAGS_HELP:-}" ]; then echo "${FLAGS_HELP}" >&2 else echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2 fi if [ -n "${__flags_longNames}" ]; then echo 'flags:' >&2 for flags_name_ in ${__flags_longNames}; do flags_flagStr_='' flags_boolStr_='' flags_usName_=`_flags_underscoreName "${flags_name_}"` flags_default_=`_flags_getFlagInfo \ "${flags_usName_}" ${__FLAGS_INFO_DEFAULT}` flags_help_=`_flags_getFlagInfo \ "${flags_usName_}" ${__FLAGS_INFO_HELP}` flags_short_=`_flags_getFlagInfo \ "${flags_usName_}" ${__FLAGS_INFO_SHORT}` flags_type_=`_flags_getFlagInfo \ "${flags_usName_}" ${__FLAGS_INFO_TYPE}` [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \ flags_flagStr_="-${flags_short_}" if [ "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_ENH}" ]; then [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \ flags_flagStr_="${flags_flagStr_}," # Add [no] to long boolean flag names, except the 'help' flag. [ "${flags_type_}" -eq ${__FLAGS_TYPE_BOOLEAN} \ -a "${flags_usName_}" != 'help' ] && \ flags_boolStr_='[no]' flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:" fi case ${flags_type_} in ${__FLAGS_TYPE_BOOLEAN}) if [ "${flags_default_}" -eq ${FLAGS_TRUE} ]; then flags_defaultStr_='true' else flags_defaultStr_='false' fi ;; ${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER}) flags_defaultStr_=${flags_default_} ;; ${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;; esac flags_defaultStr_="(default: ${flags_defaultStr_})" flags_helpStr_=" ${flags_flagStr_} ${flags_help_:+${flags_help_} }${flags_defaultStr_}" _flags_strlen "${flags_helpStr_}" >/dev/null flags_helpStrLen_=${flags_output} flags_columns_=`_flags_columns` if [ "${flags_helpStrLen_}" -lt "${flags_columns_}" ]; then echo "${flags_helpStr_}" >&2 else echo " ${flags_flagStr_} ${flags_help_}" >&2 # Note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06 # because it doesn't like empty strings when used in this manner. flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \ |awk '{printf "%"length($0)-2"s", ""}'`" flags_helpStr_=" ${flags_emptyStr_} ${flags_defaultStr_}" _flags_strlen "${flags_helpStr_}" >/dev/null flags_helpStrLen_=${flags_output} if [ "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_STD}" \ -o "${flags_helpStrLen_}" -lt "${flags_columns_}" ]; then # Indented to match help string. echo "${flags_helpStr_}" >&2 else # Indented four from left to allow for longer defaults as long flag # names might be used too, making things too long. echo " ${flags_defaultStr_}" >&2 fi fi done fi unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_ \ flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \ flags_columns_ flags_short_ flags_type_ flags_usName_ return ${FLAGS_TRUE} } # Reset shflags back to an uninitialized state. # # Args: # none # Returns: # nothing flags_reset() { for flags_name_ in ${__flags_longNames}; do flags_usName_=`_flags_underscoreName "${flags_name_}"` flags_strToEval_="unset FLAGS_${flags_usName_}" for flags_type_ in \ ${__FLAGS_INFO_DEFAULT} \ ${__FLAGS_INFO_HELP} \ ${__FLAGS_INFO_SHORT} \ ${__FLAGS_INFO_TYPE} do flags_strToEval_=\ "${flags_strToEval_} __flags_${flags_usName_}_${flags_type_}" done eval "${flags_strToEval_}" done # Reset internal variables. __flags_boolNames=' ' __flags_longNames=' ' __flags_shortNames=' ' __flags_definedNames=' ' # Reset logging level back to default. flags_setLoggingLevel ${__FLAGS_LEVEL_DEFAULT} unset flags_name_ flags_type_ flags_strToEval_ flags_usName_ } # # Initialization # # Set the default logging level. flags_setLoggingLevel ${__FLAGS_LEVEL_DEFAULT} ================================================ FILE: tests/shunit/lib/versions ================================================ #! /bin/sh # vim:et:ft=sh:sts=2:sw=2 # # Versions determines the versions of all installed shells. # # Copyright 2008-2018 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 License. # # Author: kate.ward@forestent.com (Kate Ward) # https://github.com/kward/shlib # # This library provides reusable functions that determine actual names and # versions of installed shells and the OS. The library can also be run as a # script if set executable. # # Disable checks that aren't fully portable (POSIX != portable). # shellcheck disable=SC2006 ARGV0=`basename "$0"` LSB_RELEASE='/etc/lsb-release' VERSIONS_SHELLS='ash /bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/zsh /bin/sh /usr/xpg4/bin/sh /sbin/sh' true; TRUE=$? false; FALSE=$? ERROR=2 UNAME_R=`uname -r` UNAME_S=`uname -s` __versions_haveStrings=${ERROR} versions_osName() { os_name_='unrecognized' os_system_=${UNAME_S} os_release_=${UNAME_R} case ${os_system_} in CYGWIN_NT-*) os_name_='Cygwin' ;; Darwin) os_name_=`/usr/bin/sw_vers -productName` os_version_=`versions_osVersion` case ${os_version_} in 10.4|10.4.[0-9]*) os_name_='Mac OS X Tiger' ;; 10.5|10.5.[0-9]*) os_name_='Mac OS X Leopard' ;; 10.6|10.6.[0-9]*) os_name_='Mac OS X Snow Leopard' ;; 10.7|10.7.[0-9]*) os_name_='Mac OS X Lion' ;; 10.8|10.8.[0-9]*) os_name_='Mac OS X Mountain Lion' ;; 10.9|10.9.[0-9]*) os_name_='Mac OS X Mavericks' ;; 10.10|10.10.[0-9]*) os_name_='Mac OS X Yosemite' ;; 10.11|10.11.[0-9]*) os_name_='Mac OS X El Capitan' ;; 10.12|10.12.[0-9]*) os_name_='macOS Sierra' ;; 10.13|10.13.[0-9]*) os_name_='macOS High Sierra' ;; 10.14|10.14.[0-9]*) os_name_='macOS Mojave' ;; *) os_name_='macOS' ;; esac ;; FreeBSD) os_name_='FreeBSD' ;; Linux) os_name_='Linux' ;; SunOS) os_name_='SunOS' if [ -r '/etc/release' ]; then if grep 'OpenSolaris' /etc/release >/dev/null; then os_name_='OpenSolaris' else os_name_='Solaris' fi fi ;; esac echo ${os_name_} unset os_name_ os_system_ os_release_ os_version_ } versions_osVersion() { os_version_='unrecognized' os_system_=${UNAME_S} os_release_=${UNAME_R} case ${os_system_} in CYGWIN_NT-*) os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]\.[0-9]*\).*'` ;; Darwin) os_version_=`/usr/bin/sw_vers -productVersion` ;; FreeBSD) os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]*\)-.*'` ;; Linux) if [ -r '/etc/os-release' ]; then os_version_=`awk -F= '$1~/PRETTY_NAME/{print $2}' /etc/os-release \ |sed 's/"//g'` elif [ -r '/etc/redhat-release' ]; then os_version_=`cat /etc/redhat-release` elif [ -r '/etc/SuSE-release' ]; then os_version_=`head -n 1 /etc/SuSE-release` elif [ -r "${LSB_RELEASE}" ]; then if grep -q 'DISTRIB_ID=Ubuntu' "${LSB_RELEASE}"; then # shellcheck disable=SC2002 os_version_=`cat "${LSB_RELEASE}" \ |awk -F= '$1~/DISTRIB_DESCRIPTION/{print $2}' \ |sed 's/"//g;s/ /-/g'` fi fi ;; SunOS) if [ -r '/etc/release' ]; then if grep 'OpenSolaris' /etc/release >/dev/null; then # OpenSolaris os_version_=`grep 'OpenSolaris' /etc/release |awk '{print $2"("$3")"}'` else # Solaris major_=`echo "${os_release_}" |sed 's/[0-9]*\.\([0-9]*\)/\1/'` minor_=`grep Solaris /etc/release |sed 's/[^u]*\(u[0-9]*\).*/\1/'` os_version_="${major_}${minor_}" fi fi ;; esac echo "${os_version_}" unset os_release_ os_system_ os_version_ major_ minor_ } versions_shellVersion() { shell_=$1 shell_present_=${FALSE} case "${shell_}" in ash) [ -x '/bin/busybox' ] && shell_present_=${TRUE} ;; *) [ -x "${shell_}" ] && shell_present_=${TRUE} ;; esac if [ ${shell_present_} -eq ${FALSE} ]; then echo 'not installed' return ${FALSE} fi version_='' case ${shell_} in /sbin/sh) ;; # SunOS /usr/xpg4/bin/sh) version_=`versions_shell_xpg4 "${shell_}"` ;; # SunOS */sh) # This could be one of any number of shells. Try until one fits. version_='' [ -z "${version_}" ] && version_=`versions_shell_bash "${shell_}"` # dash cannot be self determined yet [ -z "${version_}" ] && version_=`versions_shell_ksh "${shell_}"` # pdksh is covered in versions_shell_ksh() [ -z "${version_}" ] && version_=`versions_shell_xpg4 "${shell_}"` [ -z "${version_}" ] && version_=`versions_shell_zsh "${shell_}"` ;; ash) version_=`versions_shell_ash "${shell_}"` ;; */bash) version_=`versions_shell_bash "${shell_}"` ;; */dash) # Assuming Ubuntu Linux until somebody comes up with a better test. The # following test will return an empty string if dash is not installed. version_=`versions_shell_dash` ;; */ksh) version_=`versions_shell_ksh "${shell_}"` ;; */pdksh) version_=`versions_shell_pdksh "${shell_}"` ;; */zsh) version_=`versions_shell_zsh "${shell_}"` ;; *) version_='invalid' esac echo "${version_:-unknown}" unset shell_ version_ } # The ash shell is included in BusyBox. versions_shell_ash() { busybox --help |head -1 |sed 's/BusyBox v\([0-9.]*\) .*/\1/' } versions_shell_bash() { $1 --version : 2>&1 |grep 'GNU bash' |sed 's/.*version \([^ ]*\).*/\1/' } versions_shell_dash() { eval dpkg >/dev/null 2>&1 [ $? -eq 127 ] && return # Return if dpkg not found. dpkg -l |grep ' dash ' |awk '{print $3}' } versions_shell_ksh() { versions_shell_=$1 versions_version_='' # Try a few different ways to figure out the version. versions_version_=`${versions_shell_} --version : 2>&1` # shellcheck disable=SC2181 if [ $? -eq 0 ]; then versions_version_=`echo "${versions_version_}" \ |sed 's/.*\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\).*/\1/'` else versions_version_='' fi if [ -z "${versions_version_}" ]; then _versions_have_strings versions_version_=`strings "${versions_shell_}" 2>&1 \ |grep Version \ |sed 's/^.*Version \(.*\)$/\1/;s/ s+ \$$//;s/ /-/g'` fi if [ -z "${versions_version_}" ]; then versions_version_=`versions_shell_pdksh "${versions_shell_}"` fi echo "${versions_version_}" unset versions_shell_ versions_version_ } versions_shell_pdksh() { _versions_have_strings strings "$1" 2>&1 \ |grep 'PD KSH' \ |sed -e 's/.*PD KSH \(.*\)/\1/;s/ /-/g' } versions_shell_xpg4() { _versions_have_strings strings "$1" 2>&1 \ |grep 'Version' \ |sed -e 's/^@(#)Version //' } versions_shell_zsh() { versions_shell_=$1 # Try a few different ways to figure out the version. # shellcheck disable=SC2016 versions_version_=`echo 'echo ${ZSH_VERSION}' |${versions_shell_}` if [ -z "${versions_version_}" ]; then versions_version_=`${versions_shell_} --version : 2>&1` # shellcheck disable=SC2181 if [ $? -eq 0 ]; then versions_version_=`echo "${versions_version_}" |awk '{print $2}'` else versions_version_='' fi fi echo "${versions_version_}" unset versions_shell_ versions_version_ } # Determine if the 'strings' binary installed. _versions_have_strings() { [ ${__versions_haveStrings} -ne ${ERROR} ] && return if eval strings /dev/null >/dev/null 2>&1; then __versions_haveStrings=${TRUE} return fi echo 'WARN: strings not installed. try installing binutils?' >&2 __versions_haveStrings=${FALSE} } versions_main() { # Treat unset variables as an error. set -u os_name=`versions_osName` os_version=`versions_osVersion` echo "os: ${os_name} version: ${os_version}" for shell in ${VERSIONS_SHELLS}; do shell_version=`versions_shellVersion "${shell}"` echo "shell: ${shell} version: ${shell_version}" done } if [ "${ARGV0}" = 'versions' ]; then versions_main "$@" fi ================================================ FILE: tests/shunit/shunit2 ================================================ #! /bin/sh # vim:et:ft=sh:sts=2:sw=2 # # Copyright 2008-2019 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 license. # http://www.apache.org/licenses/LICENSE-2.0 # # shUnit2 -- Unit testing framework for Unix shell scripts. # https://github.com/kward/shunit2 # # Author: kate.ward@forestent.com (Kate Ward) # # shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is # based on the popular JUnit unit testing framework for Java. # # $() are not fully portable (POSIX != portable). # shellcheck disable=SC2006 # expr may be antiquated, but it is the only solution in some cases. # shellcheck disable=SC2003 # Return if shunit2 already loaded. command [ -n "${SHUNIT_VERSION:-}" ] && exit 0 SHUNIT_VERSION='2.1.8pre' # Return values that scripts can use. SHUNIT_TRUE=0 SHUNIT_FALSE=1 SHUNIT_ERROR=2 # Logging functions. _shunit_warn() { ${__SHUNIT_CMD_ECHO_ESC} \ "${__shunit_ansi_yellow}shunit2:WARN${__shunit_ansi_none} $*" >&2 } _shunit_error() { ${__SHUNIT_CMD_ECHO_ESC} \ "${__shunit_ansi_red}shunit2:ERROR${__shunit_ansi_none} $*" >&2 } _shunit_fatal() { ${__SHUNIT_CMD_ECHO_ESC} \ "${__shunit_ansi_red}shunit2:FATAL${__shunit_ansi_none} $*" >&2 exit ${SHUNIT_ERROR} } # Determine some reasonable command defaults. __SHUNIT_CMD_ECHO_ESC='echo -e' # shellcheck disable=SC2039 command [ "`echo -e test`" = '-e test' ] && __SHUNIT_CMD_ECHO_ESC='echo' __SHUNIT_UNAME_S=`uname -s` case "${__SHUNIT_UNAME_S}" in BSD) __SHUNIT_CMD_EXPR='gexpr' ;; *) __SHUNIT_CMD_EXPR='expr' ;; esac __SHUNIT_CMD_TPUT='tput' # Commands a user can override if needed. SHUNIT_CMD_EXPR=${SHUNIT_CMD_EXPR:-${__SHUNIT_CMD_EXPR}} SHUNIT_CMD_TPUT=${SHUNIT_CMD_TPUT:-${__SHUNIT_CMD_TPUT}} # Enable color output. Options are 'never', 'always', or 'auto'. SHUNIT_COLOR=${SHUNIT_COLOR:-auto} # Specific shell checks. if command [ -n "${ZSH_VERSION:-}" ]; then setopt |grep "^shwordsplit$" >/dev/null if command [ $? -ne ${SHUNIT_TRUE} ]; then _shunit_fatal 'zsh shwordsplit option is required for proper operation' fi if command [ -z "${SHUNIT_PARENT:-}" ]; then _shunit_fatal "zsh does not pass \$0 through properly. please declare \ \"SHUNIT_PARENT=\$0\" before calling shUnit2" fi fi # # Constants # __SHUNIT_MODE_SOURCED='sourced' __SHUNIT_MODE_STANDALONE='standalone' __SHUNIT_PARENT=${SHUNIT_PARENT:-$0} # User provided test prefix to display in front of the name of the test being # executed. Define by setting the SHUNIT_TEST_PREFIX variable. __SHUNIT_TEST_PREFIX=${SHUNIT_TEST_PREFIX:-} # ANSI colors. __SHUNIT_ANSI_NONE='\033[0m' __SHUNIT_ANSI_RED='\033[1;31m' __SHUNIT_ANSI_GREEN='\033[1;32m' __SHUNIT_ANSI_YELLOW='\033[1;33m' __SHUNIT_ANSI_CYAN='\033[1;36m' # Set the constants readonly. __shunit_constants=`set |grep '^__SHUNIT_' |cut -d= -f1` echo "${__shunit_constants}" |grep '^Binary file' >/dev/null && \ __shunit_constants=`set |grep -a '^__SHUNIT_' |cut -d= -f1` for __shunit_const in ${__shunit_constants}; do if command [ -z "${ZSH_VERSION:-}" ]; then readonly "${__shunit_const}" else case ${ZSH_VERSION} in [123].*) readonly "${__shunit_const}" ;; *) readonly -g "${__shunit_const}" # Declare readonly constants globally. esac fi done unset __shunit_const __shunit_constants # # Internal variables. # # Variables. __shunit_lineno='' # Line number of executed test. __shunit_mode=${__SHUNIT_MODE_SOURCED} # Operating mode. __shunit_reportGenerated=${SHUNIT_FALSE} # Is report generated. __shunit_script='' # Filename of unittest script (standalone mode). __shunit_skip=${SHUNIT_FALSE} # Is skipping enabled. __shunit_suite='' # Suite of tests to execute. __shunit_clean=${SHUNIT_FALSE} # _shunit_cleanup() was already called. # ANSI colors (populated by _shunit_configureColor()). __shunit_ansi_none='' __shunit_ansi_red='' __shunit_ansi_green='' __shunit_ansi_yellow='' __shunit_ansi_cyan='' # Counts of tests. __shunit_testSuccess=${SHUNIT_TRUE} __shunit_testsTotal=0 __shunit_testsPassed=0 __shunit_testsFailed=0 # Counts of asserts. __shunit_assertsTotal=0 __shunit_assertsPassed=0 __shunit_assertsFailed=0 __shunit_assertsSkipped=0 # # Macros. # # shellcheck disable=SC2016,SC2089 _SHUNIT_LINENO_='eval __shunit_lineno=""; if command [ "${1:-}" = "--lineno" ]; then command [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' #----------------------------------------------------------------------------- # Assertion functions. # # Assert that two values are equal to one another. # # Args: # message: string: failure message [optional] # expected: string: expected value # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertEquals() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertEquals() requires two or three arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_expected_=$1 shunit_actual_=$2 shunit_return=${SHUNIT_TRUE} if command [ "${shunit_expected_}" = "${shunit_actual_}" ]; then _shunit_assertPass else failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" shunit_return=${SHUNIT_FALSE} fi unset shunit_message_ shunit_expected_ shunit_actual_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' # Assert that two values are not equal to one another. # # Args: # message: string: failure message [optional] # expected: string: expected value # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertNotEquals() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertNotEquals() requires two or three arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_expected_=$1 shunit_actual_=$2 shunit_return=${SHUNIT_TRUE} if command [ "${shunit_expected_}" != "${shunit_actual_}" ]; then _shunit_assertPass else failSame "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" shunit_return=${SHUNIT_FALSE} fi unset shunit_message_ shunit_expected_ shunit_actual_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' # Assert that a container contains a content. # # Args: # message: string: failure message [optional] # container: string: container to analyze # content: string: content to find # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertContains() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertContains() requires two or three arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_container_=$1 shunit_content_=$2 shunit_return=${SHUNIT_TRUE} if echo "$shunit_container_" | grep -F -- "$shunit_content_" > /dev/null; then _shunit_assertPass else failNotFound "${shunit_message_}" "${shunit_content_}" shunit_return=${SHUNIT_FALSE} fi unset shunit_message_ shunit_container_ shunit_content_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _ASSERT_CONTAINS_='eval assertContains --lineno "${LINENO:-}"' # Assert that a container does not contain a content. # # Args: # message: string: failure message [optional] # container: string: container to analyze # content: string: content to look for # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertNotContains() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertNotContains() requires two or three arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_container_=$1 shunit_content_=$2 shunit_return=${SHUNIT_TRUE} if echo "$shunit_container_" | grep -F -- "$shunit_content_" > /dev/null; then failFound "${shunit_message_}" "${shunit_content_}" shunit_return=${SHUNIT_FALSE} else _shunit_assertPass fi unset shunit_message_ shunit_container_ shunit_content_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _ASSERT_NOT_CONTAINS_='eval assertNotContains --lineno "${LINENO:-}"' # Assert that a value is null (i.e. an empty string) # # Args: # message: string: failure message [optional] # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertNull() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 1 -o $# -gt 2 ]; then _shunit_error "assertNull() requires one or two arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi assertTrue "${shunit_message_}" "[ -z '$1' ]" shunit_return=$? unset shunit_message_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' # Assert that a value is not null (i.e. a non-empty string) # # Args: # message: string: failure message [optional] # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertNotNull() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null _shunit_error "assertNotNull() requires one or two arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` test -n "${shunit_actual_}" assertTrue "${shunit_message_}" $? shunit_return=$? unset shunit_actual_ shunit_message_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' # Assert that two values are the same (i.e. equal to one another). # # Args: # message: string: failure message [optional] # expected: string: expected value # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertSame() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertSame() requires two or three arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi assertEquals "${shunit_message_}" "$1" "$2" shunit_return=$? unset shunit_message_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' # Assert that two values are not the same (i.e. not equal to one another). # # Args: # message: string: failure message [optional] # expected: string: expected value # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertNotSame() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertNotSame() requires two or three arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 3 ]; then shunit_message_="${shunit_message_:-}$1" shift fi assertNotEquals "${shunit_message_}" "$1" "$2" shunit_return=$? unset shunit_message_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' # Assert that a value or shell test condition is true. # # In shell, a value of 0 is true and a non-zero value is false. Any integer # value passed can thereby be tested. # # Shell supports much more complicated tests though, and a means to support # them was needed. As such, this function tests that conditions are true or # false through evaluation rather than just looking for a true or false. # # The following test will succeed: # assertTrue 0 # assertTrue "[ 34 -gt 23 ]" # The following test will fail with a message: # assertTrue 123 # assertTrue "test failed" "[ -r '/non/existent/file' ]" # # Args: # message: string: failure message [optional] # condition: string: integer value or shell conditional statement # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertTrue() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 1 -o $# -gt 2 ]; then _shunit_error "assertTrue() takes one or two arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_condition_=$1 # See if condition is an integer, i.e. a return value. shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` shunit_return=${SHUNIT_TRUE} if command [ -z "${shunit_condition_}" ]; then # Null condition. shunit_return=${SHUNIT_FALSE} elif command [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] then # Possible return value. Treating 0 as true, and non-zero as false. command [ "${shunit_condition_}" -ne 0 ] && shunit_return=${SHUNIT_FALSE} else # Hopefully... a condition. ( eval "${shunit_condition_}" ) >/dev/null 2>&1 command [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} fi # Record the test. if command [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then _shunit_assertPass else _shunit_assertFail "${shunit_message_}" fi unset shunit_message_ shunit_condition_ shunit_match_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' # Assert that a value or shell test condition is false. # # In shell, a value of 0 is true and a non-zero value is false. Any integer # value passed can thereby be tested. # # Shell supports much more complicated tests though, and a means to support # them was needed. As such, this function tests that conditions are true or # false through evaluation rather than just looking for a true or false. # # The following test will succeed: # assertFalse 1 # assertFalse "[ 'apples' = 'oranges' ]" # The following test will fail with a message: # assertFalse 0 # assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" # # Args: # message: string: failure message [optional] # condition: string: integer value or shell conditional statement # Returns: # integer: success (TRUE/FALSE/ERROR constant) assertFalse() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 1 -o $# -gt 2 ]; then _shunit_error "assertFalse() requires one or two arguments; $# given" _shunit_assertFail return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_condition_=$1 # See if condition is an integer, i.e. a return value. shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` shunit_return=${SHUNIT_TRUE} if command [ -z "${shunit_condition_}" ]; then # Null condition. shunit_return=${SHUNIT_FALSE} elif command [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] then # Possible return value. Treating 0 as true, and non-zero as false. command [ "${shunit_condition_}" -eq 0 ] && shunit_return=${SHUNIT_FALSE} else # Hopefully... a condition. ( eval "${shunit_condition_}" ) >/dev/null 2>&1 command [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} fi # Record the test. if command [ "${shunit_return}" -eq "${SHUNIT_TRUE}" ]; then _shunit_assertPass else _shunit_assertFail "${shunit_message_}" fi unset shunit_message_ shunit_condition_ shunit_match_ return "${shunit_return}" } # shellcheck disable=SC2016,SC2034 _ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' #----------------------------------------------------------------------------- # Failure functions. # # Records a test failure. # # Args: # message: string: failure message [optional] # Returns: # integer: success (TRUE/FALSE/ERROR constant) fail() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -gt 1 ]; then _shunit_error "fail() requires zero or one arguments; $# given" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 1 ]; then shunit_message_="${shunit_message_}$1" shift fi _shunit_assertFail "${shunit_message_}" unset shunit_message_ return ${SHUNIT_FALSE} } # shellcheck disable=SC2016,SC2034 _FAIL_='eval fail --lineno "${LINENO:-}"' # Records a test failure, stating two values were not equal. # # Args: # message: string: failure message [optional] # expected: string: expected value # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) failNotEquals() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "failNotEquals() requires one or two arguments; $# given" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_expected_=$1 shunit_actual_=$2 shunit_message_=${shunit_message_%% } _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" unset shunit_message_ shunit_expected_ shunit_actual_ return ${SHUNIT_FALSE} } # shellcheck disable=SC2016,SC2034 _FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' # Records a test failure, stating a value was found. # # Args: # message: string: failure message [optional] # content: string: found value # Returns: # integer: success (TRUE/FALSE/ERROR constant) failFound() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 1 -o $# -gt 2 ]; then _shunit_error "failFound() requires one or two arguments; $# given" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_message_=${shunit_message_%% } _shunit_assertFail "${shunit_message_:+${shunit_message_} }Found" unset shunit_message_ return ${SHUNIT_FALSE} } # shellcheck disable=SC2016,SC2034 _FAIL_FOUND_='eval failFound --lineno "${LINENO:-}"' # Records a test failure, stating a content was not found. # # Args: # message: string: failure message [optional] # content: string: content not found # Returns: # integer: success (TRUE/FALSE/ERROR constant) failNotFound() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 1 -o $# -gt 2 ]; then _shunit_error "failNotFound() requires one or two arguments; $# given" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_content_=$1 shunit_message_=${shunit_message_%% } _shunit_assertFail "${shunit_message_:+${shunit_message_} }Not found:<${shunit_content_}>" unset shunit_message_ shunit_content_ return ${SHUNIT_FALSE} } # shellcheck disable=SC2016,SC2034 _FAIL_NOT_FOUND_='eval failNotFound --lineno "${LINENO:-}"' # Records a test failure, stating two values should have been the same. # # Args: # message: string: failure message [optional] # expected: string: expected value # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) failSame() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "failSame() requires two or three arguments; $# given" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_message_=${shunit_message_%% } _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" unset shunit_message_ return ${SHUNIT_FALSE} } # shellcheck disable=SC2016,SC2034 _FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' # Records a test failure, stating two values were not equal. # # This is functionally equivalent to calling failNotEquals(). # # Args: # message: string: failure message [optional] # expected: string: expected value # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) failNotSame() { # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} if command [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "failNotSame() requires one or two arguments; $# given" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} shunit_message_=${__shunit_lineno} if command [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi failNotEquals "${shunit_message_}" "$1" "$2" shunit_return=$? unset shunit_message_ return ${shunit_return} } # shellcheck disable=SC2016,SC2034 _FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' #----------------------------------------------------------------------------- # Skipping functions. # # Force remaining assert and fail functions to be "skipped". # # This function forces the remaining assert and fail functions to be "skipped", # i.e. they will have no effect. Each function skipped will be recorded so that # the total of asserts and fails will not be altered. # # Args: # None startSkipping() { __shunit_skip=${SHUNIT_TRUE}; } # Resume the normal recording behavior of assert and fail calls. # # Args: # None endSkipping() { __shunit_skip=${SHUNIT_FALSE}; } # Returns the state of assert and fail call skipping. # # Args: # None # Returns: # boolean: (TRUE/FALSE constant) isSkipping() { return ${__shunit_skip}; } #----------------------------------------------------------------------------- # Suite functions. # # Stub. This function should contains all unit test calls to be made. # # DEPRECATED (as of 2.1.0) # # This function can be optionally overridden by the user in their test suite. # # If this function exists, it will be called when shunit2 is sourced. If it # does not exist, shunit2 will search the parent script for all functions # beginning with the word 'test', and they will be added dynamically to the # test suite. # # This function should be overridden by the user in their unit test suite. # Note: see _shunit_mktempFunc() for actual implementation # # Args: # None #suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION # Adds a function name to the list of tests schedule for execution. # # This function should only be called from within the suite() function. # # Args: # function: string: name of a function to add to current unit test suite suite_addTest() { shunit_func_=${1:-} __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` unset shunit_func_ } # Stub. This function will be called once before any tests are run. # # Common one-time environment preparation tasks shared by all tests can be # defined here. # # This function should be overridden by the user in their unit test suite. # Note: see _shunit_mktempFunc() for actual implementation # # Args: # None #oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION # Stub. This function will be called once after all tests are finished. # # Common one-time environment cleanup tasks shared by all tests can be defined # here. # # This function should be overridden by the user in their unit test suite. # Note: see _shunit_mktempFunc() for actual implementation # # Args: # None #oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION # Stub. This function will be called before each test is run. # # Common environment preparation tasks shared by all tests can be defined here. # # This function should be overridden by the user in their unit test suite. # Note: see _shunit_mktempFunc() for actual implementation # # Args: # None #setUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION # Note: see _shunit_mktempFunc() for actual implementation # Stub. This function will be called after each test is run. # # Common environment cleanup tasks shared by all tests can be defined here. # # This function should be overridden by the user in their unit test suite. # Note: see _shunit_mktempFunc() for actual implementation # # Args: # None #tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION #------------------------------------------------------------------------------ # Internal shUnit2 functions. # # Create a temporary directory to store various run-time files in. # # This function is a cross-platform temporary directory creation tool. Not all # OSes have the `mktemp` function, so one is included here. # # Args: # None # Outputs: # string: the temporary directory that was created _shunit_mktempDir() { # Try the standard `mktemp` function. ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return # The standard `mktemp` didn't work. Use our own. # shellcheck disable=SC2039 if command [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 "${_shunit_file_}" #! /bin/sh exit ${SHUNIT_TRUE} EOF command chmod +x "${_shunit_file_}" done unset _shunit_file_ } # Final cleanup function to leave things as we found them. # # Besides removing the temporary directory, this function is in charge of the # final exit code of the unit test. The exit code is based on how the script # was ended (e.g. normal exit, or via Ctrl-C). # # Args: # name: string: name of the trap called (specified when trap defined) _shunit_cleanup() { _shunit_name_=$1 case "${_shunit_name_}" in EXIT) ;; INT) _shunit_signal_=130 ;; # 2+128 TERM) _shunit_signal_=143 ;; # 15+128 *) _shunit_error "unrecognized trap value (${_shunit_name_})" _shunit_signal_=0 ;; esac if command [ "${_shunit_name_}" != 'EXIT' ]; then _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" fi # Do our work. if command [ ${__shunit_clean} -eq ${SHUNIT_FALSE} ]; then # Ensure tear downs are only called once. __shunit_clean=${SHUNIT_TRUE} tearDown command [ $? -eq ${SHUNIT_TRUE} ] \ || _shunit_warn "tearDown() returned non-zero return code." oneTimeTearDown command [ $? -eq ${SHUNIT_TRUE} ] \ || _shunit_warn "oneTimeTearDown() returned non-zero return code." command rm -fr "${__shunit_tmpDir}" fi if command [ "${_shunit_name_}" != 'EXIT' ]; then # Handle all non-EXIT signals. trap - 0 # Disable EXIT trap. exit ${_shunit_signal_} elif command [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ]; then _shunit_assertFail 'unknown failure encountered running a test' _shunit_generateReport exit ${SHUNIT_ERROR} fi unset _shunit_name_ _shunit_signal_ } # configureColor based on user color preference. # # Args: # color: string: color mode (one of `always`, `auto`, or `none`). _shunit_configureColor() { _shunit_color_=${SHUNIT_FALSE} # By default, no color. case $1 in 'always') _shunit_color_=${SHUNIT_TRUE} ;; 'auto') command [ "`_shunit_colors`" -ge 8 ] && _shunit_color_=${SHUNIT_TRUE} ;; 'none') ;; *) _shunit_fatal "unrecognized color option '$1'" ;; esac case ${_shunit_color_} in ${SHUNIT_TRUE}) __shunit_ansi_none=${__SHUNIT_ANSI_NONE} __shunit_ansi_red=${__SHUNIT_ANSI_RED} __shunit_ansi_green=${__SHUNIT_ANSI_GREEN} __shunit_ansi_yellow=${__SHUNIT_ANSI_YELLOW} __shunit_ansi_cyan=${__SHUNIT_ANSI_CYAN} ;; ${SHUNIT_FALSE}) __shunit_ansi_none='' __shunit_ansi_red='' __shunit_ansi_green='' __shunit_ansi_yellow='' __shunit_ansi_cyan='' ;; esac unset _shunit_color_ _shunit_tput_ } # colors returns the number of supported colors for the TERM. _shunit_colors() { _shunit_tput_=`${SHUNIT_CMD_TPUT} colors 2>/dev/null` if command [ $? -eq 0 ]; then echo "${_shunit_tput_}" else echo 16 fi unset _shunit_tput_ } # The actual running of the tests happens here. # # Args: # None _shunit_execSuite() { for _shunit_test_ in ${__shunit_suite}; do __shunit_testSuccess=${SHUNIT_TRUE} # Disable skipping. endSkipping # Execute the per-test setup function. setUp command [ $? -eq ${SHUNIT_TRUE} ] \ || _shunit_fatal "setup() returned non-zero return code." # Execute the test. echo "${__SHUNIT_TEST_PREFIX}${_shunit_test_}" eval "${_shunit_test_}" if command [ $? -ne ${SHUNIT_TRUE} ]; then _shunit_error "${_shunit_test_}() returned non-zero return code." __shunit_testSuccess=${SHUNIT_ERROR} _shunit_incFailedCount fi # Execute the per-test tear-down function. tearDown command [ $? -eq ${SHUNIT_TRUE} ] \ || _shunit_fatal "tearDown() returned non-zero return code." # Update stats. if command [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` else __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` fi done unset _shunit_test_ } # Generates the user friendly report with appropriate OK/FAILED message. # # Args: # None # Output: # string: the report of successful and failed tests, as well as totals. _shunit_generateReport() { command [ "${__shunit_reportGenerated}" -eq ${SHUNIT_TRUE} ] && return _shunit_ok_=${SHUNIT_TRUE} # If no exit code was provided, determine an appropriate one. command [ "${__shunit_testsFailed}" -gt 0 \ -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ && _shunit_ok_=${SHUNIT_FALSE} echo _shunit_msg_="Ran ${__shunit_ansi_cyan}${__shunit_testsTotal}${__shunit_ansi_none}" if command [ "${__shunit_testsTotal}" -eq 1 ]; then ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_} test." else ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_} tests." fi if command [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then _shunit_msg_="${__shunit_ansi_green}OK${__shunit_ansi_none}" command [ "${__shunit_assertsSkipped}" -gt 0 ] \ && _shunit_msg_="${_shunit_msg_} (${__shunit_ansi_yellow}skipped=${__shunit_assertsSkipped}${__shunit_ansi_none})" else _shunit_msg_="${__shunit_ansi_red}FAILED${__shunit_ansi_none}" _shunit_msg_="${_shunit_msg_} (${__shunit_ansi_red}failures=${__shunit_assertsFailed}${__shunit_ansi_none}" command [ "${__shunit_assertsSkipped}" -gt 0 ] \ && _shunit_msg_="${_shunit_msg_},${__shunit_ansi_yellow}skipped=${__shunit_assertsSkipped}${__shunit_ansi_none}" _shunit_msg_="${_shunit_msg_})" fi echo ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_}" __shunit_reportGenerated=${SHUNIT_TRUE} unset _shunit_msg_ _shunit_ok_ } # Test for whether a function should be skipped. # # Args: # None # Returns: # boolean: whether the test should be skipped (TRUE/FALSE constant) _shunit_shouldSkip() { command [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} _shunit_assertSkip } # Records a successful test. # # Args: # None _shunit_assertPass() { __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` } # Records a test failure. # # Args: # message: string: failure message to provide user _shunit_assertFail() { __shunit_testSuccess=${SHUNIT_FALSE} _shunit_incFailedCount \[ $# -gt 0 ] && ${__SHUNIT_CMD_ECHO_ESC} \ "${__shunit_ansi_red}ASSERT:${__shunit_ansi_none}$*" } # Increment the count of failed asserts. # # Args: # none _shunit_incFailedCount() { __shunit_assertsFailed=`expr "${__shunit_assertsFailed}" + 1` __shunit_assertsTotal=`expr "${__shunit_assertsTotal}" + 1` } # Records a skipped test. # # Args: # None _shunit_assertSkip() { __shunit_assertsSkipped=`expr "${__shunit_assertsSkipped}" + 1` __shunit_assertsTotal=`expr "${__shunit_assertsTotal}" + 1` } # Prepare a script filename for sourcing. # # Args: # script: string: path to a script to source # Returns: # string: filename prefixed with ./ (if necessary) _shunit_prepForSourcing() { _shunit_script_=$1 case "${_shunit_script_}" in /*|./*) echo "${_shunit_script_}" ;; *) echo "./${_shunit_script_}" ;; esac unset _shunit_script_ } # Escape a character in a string. # # Args: # c: string: unescaped character # s: string: to escape character in # Returns: # string: with escaped character(s) _shunit_escapeCharInStr() { command [ -n "$2" ] || return # No point in doing work on an empty string. # Note: using shorter variable names to prevent conflicts with # _shunit_escapeCharactersInString(). _shunit_c_=$1 _shunit_s_=$2 # Escape the character. # shellcheck disable=SC1003,SC2086 echo ''${_shunit_s_}'' |command sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' unset _shunit_c_ _shunit_s_ } # Escape a character in a string. # # Args: # str: string: to escape characters in # Returns: # string: with escaped character(s) _shunit_escapeCharactersInString() { command [ -n "$1" ] || return # No point in doing work on an empty string. _shunit_str_=$1 # Note: using longer variable names to prevent conflicts with # _shunit_escapeCharInStr(). for _shunit_char_ in '"' '$' "'" '`'; do _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` done echo "${_shunit_str_}" unset _shunit_char_ _shunit_str_ } # Extract list of functions to run tests against. # # Args: # script: string: name of script to extract functions from # Returns: # string: of function names _shunit_extractTestFunctions() { _shunit_script_=$1 # Extract the lines with test function names, strip of anything besides the # function name, and output everything on a single line. _shunit_regex_='^\s*((function test[A-Za-z0-9_-]*)|(test[A-Za-z0-9_-]* *\(\)))' # shellcheck disable=SC2196 egrep "${_shunit_regex_}" "${_shunit_script_}" \ |command sed 's/^[^A-Za-z0-9_-]*//;s/^function //;s/\([A-Za-z0-9_-]*\).*/\1/g' \ |xargs unset _shunit_regex_ _shunit_script_ } #------------------------------------------------------------------------------ # Main. # # Determine the operating mode. if command [ $# -eq 0 -o "${1:-}" = '--' ]; then __shunit_script=${__SHUNIT_PARENT} __shunit_mode=${__SHUNIT_MODE_SOURCED} else __shunit_script=$1 command [ -r "${__shunit_script}" ] || \ _shunit_fatal "unable to read from ${__shunit_script}" __shunit_mode=${__SHUNIT_MODE_STANDALONE} fi # Create a temporary storage location. __shunit_tmpDir=`_shunit_mktempDir` # Provide a public temporary directory for unit test scripts. # TODO(kward): document this. SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" command mkdir "${SHUNIT_TMPDIR}" # Setup traps to clean up after ourselves. trap '_shunit_cleanup EXIT' 0 trap '_shunit_cleanup INT' 2 trap '_shunit_cleanup TERM' 15 # Create phantom functions to work around issues with Cygwin. _shunit_mktempFunc PATH="${__shunit_tmpDir}:${PATH}" # Make sure phantom functions are executable. This will bite if `/tmp` (or the # current `$TMPDIR`) points to a path on a partition that was mounted with the # 'noexec' option. The noexec command was created with `_shunit_mktempFunc()`. noexec 2>/dev/null || _shunit_fatal \ 'Please declare TMPDIR with path on partition with exec permission.' # We must manually source the tests in standalone mode. if command [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then # shellcheck disable=SC1090 command . "`_shunit_prepForSourcing \"${__shunit_script}\"`" fi # Configure default output coloring behavior. _shunit_configureColor "${SHUNIT_COLOR}" # Execute the oneTimeSetUp function (if it exists). oneTimeSetUp command [ $? -eq ${SHUNIT_TRUE} ] \ || _shunit_fatal "oneTimeSetUp() returned non-zero return code." # Command line selected tests or suite selected tests if command [ "$#" -ge 2 ]; then # Argument $1 is either the filename of tests or '--'; either way, skip it. shift # Remaining arguments ($2 .. $#) are assumed to be test function names. # Interate through all remaining args in "$@" in a POSIX (likely portable) way. # Helpful tip: https://unix.stackexchange.com/questions/314032/how-to-use-arguments-like-1-2-in-a-for-loop for _shunit_arg_ do suite_addTest "${_shunit_arg_}" done unset _shunit_arg_ else # Execute the suite function defined in the parent test script. # DEPRECATED as of 2.1.0. suite fi # If no tests or suite specified, dynamically build a list of functions. if command [ -z "${__shunit_suite}" ]; then shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` for shunit_func_ in ${shunit_funcs_}; do suite_addTest "${shunit_func_}" done fi unset shunit_func_ shunit_funcs_ # Execute the suite of unit tests. _shunit_execSuite # Execute the oneTimeTearDown function (if it exists). oneTimeTearDown command [ $? -eq ${SHUNIT_TRUE} ] \ || _shunit_fatal "oneTimeTearDown() returned non-zero return code." # Generate a report summary. _shunit_generateReport # That's it folks. command [ "${__shunit_testsFailed}" -eq 0 ] exit $? ================================================ FILE: tests/shunit/shunit2_args_test.sh ================================================ #!/bin/sh # # shunit2 unit test for running subset(s) of tests based upon command line arguments. # Also shows how non-default tests or a arbitrary subset of tests can be run. # # Disable source following. # shellcheck disable=SC1090,SC1091 # Load test helpers. . ./shunit2_test_helpers # This test does not nomrally run because it does not begin "test*" # Will be run by settting the arguments to the script to include the name of this test. non_default_test() { # arbitrary assert assertTrue 0 # true intent is to set this variable, which will be tested below NON_DEFAULT_TEST_RAN="yup, we ran" } # Test that the "non_default_test" ran, otherwise fail test_non_default_ran() { assertNotNull "'non_default_test' did not run" "$NON_DEFAULT_TEST_RAN" } # fail if this test runs, which is shouldn't if args are set correctly. test_will_fail() { fail "test_will_fail should not be run if arg-parsing works" } oneTimeSetUp() { th_oneTimeSetUp # prime with "null" value NON_DEFAULT_TEST_RAN="" } # Load and run shunit2. # shellcheck disable=SC2034 [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 # If zero/one argument(s) are provided, this test is being run in it's # entirety, and therefore we want to set the arguments to the script # to (simulate and) test the processing of command-line specified # tests. If we don't, then the "test_will_fail" test will run (by # default) and the overall test will fail. # # However, if two or more arguments are provided, then assume this # test script is being run by hand to experiment with command-line # test specification, and then don't override the user provided # arguments. if command [ "$#" -le 1 ]; then # We set the arguments in a POSIX way, inasmuch as we can; # helpful tip: # https://unix.stackexchange.com/questions/258512/how-to-remove-a-positional-parameter-from set -- "--" "non_default_test" "test_non_default_ran" fi # Load and run tests, but only if running as a script, not if being sourced by shunit2 command [ -z "${SHUNIT_VERSION:-}" ] && . "${TH_SHUNIT}" ================================================ FILE: tests/shunit/shunit2_asserts_test.sh ================================================ #! /bin/sh # vim:et:ft=sh:sts=2:sw=2 # # shunit2 unit test for assert functions. # # Copyright 2008-2017 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 license. # # Author: kate.ward@forestent.com (Kate Ward) # https://github.com/kward/shunit2 # # Disable source following. # shellcheck disable=SC1090,SC1091 # These variables will be overridden by the test helpers. stdoutF="${TMPDIR:-/tmp}/STDOUT" stderrF="${TMPDIR:-/tmp}/STDERR" # Load test helpers. . ./shunit2_test_helpers commonEqualsSame() { fn=$1 ( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'equal' $? "${stdoutF}" "${stderrF}" ( ${fn} "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'equal; with msg' $? "${stdoutF}" "${stderrF}" ( ${fn} 'abc def' 'abc def' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'equal with spaces' $? "${stdoutF}" "${stderrF}" ( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'not equal' $? "${stdoutF}" "${stderrF}" ( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'null values' $? "${stdoutF}" "${stderrF}" ( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" ( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } commonNotEqualsSame() { fn=$1 ( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not same' $? "${stdoutF}" "${stderrF}" ( ${fn} "${MSG}" 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not same, with msg' $? "${stdoutF}" "${stderrF}" ( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" ( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" ( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" ( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } testAssertEquals() { commonEqualsSame 'assertEquals' } testAssertNotEquals() { commonNotEqualsSame 'assertNotEquals' } testAssertSame() { commonEqualsSame 'assertSame' } testAssertNotSame() { commonNotEqualsSame 'assertNotSame' } testAssertContains() { ( assertContains 'abcdef' 'abc' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'found' $? "${stdoutF}" "${stderrF}" ( assertContains 'abcdef' 'bcd' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'found' $? "${stdoutF}" "${stderrF}" ( assertContains 'abcdef' 'def' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'found' $? "${stdoutF}" "${stderrF}" ( assertContains 'abc -Xabc def' '-Xabc' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'content starts with "-"' $? "${stdoutF}" "${stderrF}" ( assertContains "${MSG}" 'abcdef' 'abc' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'found, with msg' $? "${stdoutF}" "${stderrF}" ( assertContains 'abcdef' 'xyz' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'not found' $? "${stdoutF}" "${stderrF}" ( assertContains 'abcdef' 'zab' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'not found' $? "${stdoutF}" "${stderrF}" ( assertContains 'abcdef' 'efg' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'not found' $? "${stdoutF}" "${stderrF}" ( assertContains 'abcdef' 'acf' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'not found' $? "${stdoutF}" "${stderrF}" ( assertContains 'abcdef' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" ( assertContains arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } testAssertNotContains() { ( assertNotContains 'abcdef' 'xyz' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not found' $? "${stdoutF}" "${stderrF}" ( assertNotContains 'abcdef' 'zab' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not found' $? "${stdoutF}" "${stderrF}" ( assertNotContains 'abcdef' 'efg' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not found' $? "${stdoutF}" "${stderrF}" ( assertNotContains 'abcdef' 'acf' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not found' $? "${stdoutF}" "${stderrF}" ( assertNotContains "${MSG}" 'abcdef' 'xyz' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not found, with msg' $? "${stdoutF}" "${stderrF}" ( assertNotContains 'abcdef' 'abc' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'found' $? "${stdoutF}" "${stderrF}" ( assertNotContains 'abcdef' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" ( assertNotContains arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } testAssertNull() { ( assertNull '' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'null' $? "${stdoutF}" "${stderrF}" ( assertNull "${MSG}" '' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'null, with msg' $? "${stdoutF}" "${stderrF}" ( assertNull 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'not null' $? "${stdoutF}" "${stderrF}" ( assertNull >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" ( assertNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } testAssertNotNull() { ( assertNotNull 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not null' $? "${stdoutF}" "${stderrF}" ( assertNotNull "${MSG}" 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not null, with msg' $? "${stdoutF}" "${stderrF}" ( assertNotNull 'x"b' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not null, with double-quote' $? \ "${stdoutF}" "${stderrF}" ( assertNotNull "x'b" >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not null, with single-quote' $? \ "${stdoutF}" "${stderrF}" # shellcheck disable=SC2016 ( assertNotNull 'x$b' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not null, with dollar' $? \ "${stdoutF}" "${stderrF}" ( assertNotNull 'x`b' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'not null, with backtick' $? \ "${stdoutF}" "${stderrF}" ( assertNotNull '' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}" # There is no test for too few arguments as $1 might actually be null. ( assertNotNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } testAssertTrue() { ( assertTrue 0 >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'true' $? "${stdoutF}" "${stderrF}" ( assertTrue "${MSG}" 0 >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'true, with msg' $? "${stdoutF}" "${stderrF}" ( assertTrue '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'true condition' $? "${stdoutF}" "${stderrF}" ( assertTrue 1 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'false' $? "${stdoutF}" "${stderrF}" ( assertTrue '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'false condition' $? "${stdoutF}" "${stderrF}" ( assertTrue '' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}" ( assertTrue >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" ( assertTrue arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } testAssertFalse() { ( assertFalse 1 >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'false' $? "${stdoutF}" "${stderrF}" ( assertFalse "${MSG}" 1 >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'false, with msg' $? "${stdoutF}" "${stderrF}" ( assertFalse '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" ) th_assertTrueWithNoOutput 'false condition' $? "${stdoutF}" "${stderrF}" ( assertFalse 0 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'true' $? "${stdoutF}" "${stderrF}" ( assertFalse '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}" ( assertFalse '' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}" ( assertFalse >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" ( assertFalse arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } oneTimeSetUp() { th_oneTimeSetUp MSG='This is a test message' } # Load and run shunit2. # shellcheck disable=SC2034 [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 . "${TH_SHUNIT}" ================================================ FILE: tests/shunit/shunit2_failures_test.sh ================================================ #! /bin/sh # vim:et:ft=sh:sts=2:sw=2 # # Copyright 2008-2019 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 license. # http://www.apache.org/licenses/LICENSE-2.0 # # shUnit2 -- Unit testing framework for Unix shell scripts. # https://github.com/kward/shunit2 # # Author: kate.ward@forestent.com (Kate Ward) # # shUnit2 unit test for failure functions # # Disable source following. # shellcheck disable=SC1090,SC1091 # These variables will be overridden by the test helpers. stdoutF="${TMPDIR:-/tmp}/STDOUT" stderrF="${TMPDIR:-/tmp}/STDERR" # Load test helpers. . ./shunit2_test_helpers testFail() { ( fail >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'fail' $? "${stdoutF}" "${stderrF}" ( fail "${MSG}" >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'fail with msg' $? "${stdoutF}" "${stderrF}" ( fail arg1 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'too many arguments' $? "${stdoutF}" "${stderrF}" } testFailNotEquals() { ( failNotEquals 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" ( failNotEquals "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}" ( failNotEquals 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}" ( failNotEquals '' '' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" ( failNotEquals >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" ( failNotEquals arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } testFailSame() { ( failSame 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" ( failSame "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}" ( failSame 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}" ( failSame '' '' >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" ( failSame >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" ( failSame arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" } oneTimeSetUp() { th_oneTimeSetUp MSG='This is a test message' } # Load and run shUnit2. # shellcheck disable=SC2034 [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 . "${TH_SHUNIT}" ================================================ FILE: tests/shunit/shunit2_macros_test.sh ================================================ #! /bin/sh # vim:et:ft=sh:sts=2:sw=2 # # shunit2 unit test for macros. # # Copyright 2008-2017 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 license. # # Author: kate.ward@forestent.com (Kate Ward) # https://github.com/kward/shunit2 # ### ShellCheck http://www.shellcheck.net/ # Disable source following. # shellcheck disable=SC1090,SC1091 # Presence of LINENO variable is checked. # shellcheck disable=SC2039 # These variables will be overridden by the test helpers. stdoutF="${TMPDIR:-/tmp}/STDOUT" stderrF="${TMPDIR:-/tmp}/STDERR" # Load test helpers. . ./shunit2_test_helpers testAssertEquals() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_ASSERT_EQUALS_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_EQUALS_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_ASSERT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_EQUALS_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testAssertNotEquals() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_ASSERT_NOT_EQUALS_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_NOT_EQUALS_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_ASSERT_NOT_EQUALS_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_NOT_EQUALS_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testSame() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_ASSERT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_SAME_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_ASSERT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_SAME_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testNotSame() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_ASSERT_NOT_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_NOT_SAME_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_ASSERT_NOT_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_NOT_SAME_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testNull() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_ASSERT_NULL_} 'x' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_NULL_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_ASSERT_NULL_} '"some msg"' 'x' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_NULL_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testNotNull() { # start skipping if LINENO not available [ -z "${LINENO:-}" ] && startSkipping ( ${_ASSERT_NOT_NULL_} '' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_NOT_NULL_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_ASSERT_NOT_NULL_} '"some msg"' '""' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_NOT_NULL_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stdoutF}" "${stderrF}" >&2 return 0 } testAssertTrue() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_ASSERT_TRUE_} "${SHUNIT_FALSE}" >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_TRUE_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_ASSERT_TRUE_} '"some msg"' "${SHUNIT_FALSE}" >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_TRUE_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testAssertFalse() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_ASSERT_FALSE_} "${SHUNIT_TRUE}" >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_FALSE_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_ASSERT_FALSE_} '"some msg"' "${SHUNIT_TRUE}" >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_ASSERT_FALSE_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testFail() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_FAIL_} >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_FAIL_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_FAIL_} '"some msg"' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_FAIL_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testFailNotEquals() { # start skipping if LINENO not available [ -z "${LINENO:-}" ] && startSkipping ( ${_FAIL_NOT_EQUALS_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_FAIL_NOT_EQUALS_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_FAIL_NOT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_FAIL_NOT_EQUALS_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testFailSame() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_FAIL_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_FAIL_SAME_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_FAIL_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_FAIL_SAME_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } testFailNotSame() { # Start skipping if LINENO not available. [ -z "${LINENO:-}" ] && startSkipping ( ${_FAIL_NOT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_FAIL_NOT_SAME_ failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 ( ${_FAIL_NOT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null rtrn=$? assertTrue '_FAIL_NOT_SAME_ w/ msg failure' ${rtrn} [ "${rtrn}" -ne "${SHUNIT_TRUE}" ] && cat "${stderrF}" >&2 return 0 } oneTimeSetUp() { th_oneTimeSetUp } # Disable output coloring as it breaks the tests. SHUNIT_COLOR='none'; export SHUNIT_COLOR # Load and run shUnit2. # shellcheck disable=SC2034 [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT="$0" . "${TH_SHUNIT}" ================================================ FILE: tests/shunit/shunit2_misc_test.sh ================================================ #! /bin/sh # vim:et:ft=sh:sts=2:sw=2 # # shUnit2 unit tests of miscellaneous things # # Copyright 2008-2018 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 license. # # Author: kate.ward@forestent.com (Kate Ward) # https://github.com/kward/shunit2 # ### ShellCheck http://www.shellcheck.net/ # $() are not fully portable (POSIX != portable). # shellcheck disable=SC2006 # Disable source following. # shellcheck disable=SC1090,SC1091 # Not wanting to escape single quotes. # shellcheck disable=SC1003 # These variables will be overridden by the test helpers. stdoutF="${TMPDIR:-/tmp}/STDOUT" stderrF="${TMPDIR:-/tmp}/STDERR" # Load test helpers. . ./shunit2_test_helpers # Note: the test script is prefixed with '#' chars so that shUnit2 does not # incorrectly interpret the embedded functions as real functions. testUnboundVariable() { unittestF="${SHUNIT_TMPDIR}/unittest" sed 's/^#//' >"${unittestF}" <"${stdoutF}" 2>"${stderrF}" ) assertFalse 'expected a non-zero exit value' $? grep '^ASSERT:unknown failure' "${stdoutF}" >/dev/null assertTrue 'assert message was not generated' $? grep '^Ran [0-9]* test' "${stdoutF}" >/dev/null assertTrue 'test count message was not generated' $? grep '^FAILED' "${stdoutF}" >/dev/null assertTrue 'failure message was not generated' $? } # assertEquals repeats message argument. # https://github.com/kward/shunit2/issues/7 testIssue7() { # Disable coloring so 'ASSERT:' lines can be matched correctly. _shunit_configureColor 'none' ( assertEquals 'Some message.' 1 2 >"${stdoutF}" 2>"${stderrF}" ) diff "${stdoutF}" - >/dev/null < but was:<2> EOF rtrn=$? assertEquals "${SHUNIT_TRUE}" "${rtrn}" [ "${rtrn}" -eq "${SHUNIT_TRUE}" ] || cat "${stderrF}" >&2 } # Support prefixes on test output. # https://github.com/kward/shunit2/issues/29 testIssue29() { unittestF="${SHUNIT_TMPDIR}/unittest" sed 's/^#//' >"${unittestF}" <"${stdoutF}" 2>"${stderrF}" ) grep '^--- test_assert' "${stdoutF}" >/dev/null rtrn=$? assertEquals "${SHUNIT_TRUE}" "${rtrn}" [ "${rtrn}" -eq "${SHUNIT_TRUE}" ] || cat "${stdoutF}" >&2 } # shUnit2 should not exit with 0 when it has syntax errors. # https://github.com/kward/shunit2/issues/69 testIssue69() { unittestF="${SHUNIT_TMPDIR}/unittest" for t in Equals NotEquals Null NotNull Same NotSame True False; do assert="assert${t}" sed 's/^#//' >"${unittestF}" <"${stdoutF}" 2>"${stderrF}" ) grep '^FAILED' "${stdoutF}" >/dev/null assertTrue "failure message for ${assert} was not generated" $? done } # Ensure that test fails if setup/teardown functions fail. testIssue77() { unittestF="${SHUNIT_TMPDIR}/unittest" for func in oneTimeSetUp setUp tearDown oneTimeTearDown; do sed 's/^#//' >"${unittestF}" <"${stdoutF}" 2>"${stderrF}" grep '^FAILED' "${stdoutF}" >/dev/null assertTrue "failure of ${func}() did not end test" $? done } # Ensure a test failure is recorded for code containing syntax errors. # https://github.com/kward/shunit2/issues/84 testIssue84() { unittestF="${SHUNIT_TMPDIR}/unittest" sed 's/^#//' >"${unittestF}" <<\EOF ## Function with syntax error. #syntax_error() { ${!#3442} -334 a$@2[1]; } #test_syntax_error() { # syntax_error # assertTrue ${SHUNIT_TRUE} #} #SHUNIT_COLOR='none' #SHUNIT_TEST_PREFIX='--- ' #. ${TH_SHUNIT} EOF ( exec "${SHELL:-sh}" "${unittestF}" >"${stdoutF}" 2>"${stderrF}" ) grep '^FAILED' "${stdoutF}" >/dev/null assertTrue "failure message for ${assert} was not generated" $? } testPrepForSourcing() { assertEquals '/abc' "`_shunit_prepForSourcing '/abc'`" assertEquals './abc' "`_shunit_prepForSourcing './abc'`" assertEquals './abc' "`_shunit_prepForSourcing 'abc'`" } testEscapeCharInStr() { while read -r desc char str want; do got=`_shunit_escapeCharInStr "${char}" "${str}"` assertEquals "${desc}" "${want}" "${got}" done <<'EOF' backslash \ '' '' backslash_pre \ \def \\def backslash_mid \ abc\def abc\\def backslash_post \ abc\ abc\\ quote " '' '' quote_pre " "def \"def quote_mid " abc"def abc\"def quote_post " abc" abc\" string $ '' '' string_pre $ $def \$def string_mid $ abc$def abc\$def string_post $ abc$ abc\$ EOF # TODO(20170924:kward) fix or remove. # actual=`_shunit_escapeCharInStr "'" ''` # assertEquals '' "${actual}" # assertEquals "abc\\'" `_shunit_escapeCharInStr "'" "abc'"` # assertEquals "abc\\'def" `_shunit_escapeCharInStr "'" "abc'def"` # assertEquals "\\'def" `_shunit_escapeCharInStr "'" "'def"` # # Must put the backtick in a variable so the shell doesn't misinterpret it # # while inside a backticked sequence (e.g. `echo '`'` would fail). # backtick='`' # actual=`_shunit_escapeCharInStr ${backtick} ''` # assertEquals '' "${actual}" # assertEquals '\`abc' \ # `_shunit_escapeCharInStr "${backtick}" ${backtick}'abc'` # assertEquals 'abc\`' \ # `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}` # assertEquals 'abc\`def' \ # `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}'def'` } testEscapeCharInStr_specialChars() { # Make sure our forward slash doesn't upset sed. assertEquals '/' "`_shunit_escapeCharInStr '\' '/'`" # Some shells escape these differently. # TODO(20170924:kward) fix or remove. #assertEquals '\\a' `_shunit_escapeCharInStr '\' '\a'` #assertEquals '\\b' `_shunit_escapeCharInStr '\' '\b'` } # Test the various ways of declaring functions. # # Prefixing (then stripping) with comment symbol so these functions aren't # treated as real functions by shUnit2. testExtractTestFunctions() { f="${SHUNIT_TMPDIR}/extract_test_functions" sed 's/^#//' <"${f}" ## Function on a single line. #testABC() { echo 'ABC'; } ## Multi-line function with '{' on next line. #test_def() # { # echo 'def' #} ## Multi-line function with '{' on first line. #testG3 () { # echo 'G3' #} ## Function with numerical values in name. #function test4() { echo '4'; } ## Leading space in front of function. # test5() { echo '5'; } ## Function with '_' chars in name. #some_test_function() { echo 'some func'; } ## Function that sets variables. #func_with_test_vars() { # testVariable=1234 #} ## Function with keyword but no parenthesis #function test6 { echo '6'; } ## Function with keyword but no parenthesis, multi-line #function test7 { # echo '7'; #} ## Function with no parenthesis, '{' on next line #function test8 #{ # echo '8' #} ## Function with hyphenated name #test-9() { # echo '9'; #} ## Function without parenthesis or keyword #test_foobar { echo 'hello world'; } ## Function with multiple function keywords #function function test_test_test() { echo 'lorem'; } EOF actual=`_shunit_extractTestFunctions "${f}"` assertEquals 'testABC test_def testG3 test4 test5 test6 test7 test8 test-9' "${actual}" } # Test that certain external commands sometimes "stubbed" by users are escaped. testIssue54() { for c in mkdir rm cat chmod sed; do grep "^[^#]*${c} " "${TH_SHUNIT}" | grep -qv "command ${c}" assertFalse "external call to ${c} not protected somewhere" $? done grep '^[^#]*[^ ] *\[' "${TH_SHUNIT}" | grep -qv 'command \[' assertFalse "call to [ ... ] not protected somewhere" $? grep '^[^#]* *\.' "${TH_SHUNIT}" | grep -qv 'command \.' assertFalse "call to . not protected somewhere" $? } mock_tput() { if [ -z "${TERM}" ]; then # shellcheck disable=SC2016 echo 'tput: No value for $TERM and no -T specified' return 2 fi if [ "$1" = 'colors' ]; then echo 256 return 0 fi return 1 } testColors() { while read -r desc cmd colors; do SHUNIT_CMD_TPUT=${cmd} got=`_shunit_colors` want=${colors} assertEquals "${got}" "${want}" done <<'EOF' missing missing_tput 16 mock mock_tput 256 EOF } testColorsWitoutTERM() { SHUNIT_CMD_TPUT='mock_tput' got=`TERM='' _shunit_colors` want=16 assertEquals "${got}" "${want}" } setUp() { for f in "${stdoutF}" "${stderrF}"; do cp /dev/null "${f}" done # Reconfigure coloring as some tests override default behavior. _shunit_configureColor "${SHUNIT_COLOR_DEFAULT}" # shellcheck disable=SC2034,SC2153 SHUNIT_CMD_TPUT=${__SHUNIT_CMD_TPUT} } oneTimeSetUp() { SHUNIT_COLOR_DEFAULT="${SHUNIT_COLOR}" th_oneTimeSetUp } # Load and run shUnit2. # shellcheck disable=SC2034 [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 . "${TH_SHUNIT}" ================================================ FILE: tests/shunit/shunit2_standalone_test.sh ================================================ #! /bin/sh # vim:et:ft=sh:sts=2:sw=2 # # shUnit2 unit test for standalone operation. # # Copyright 2010-2017 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 license. # # Author: kate.ward@forestent.com (Kate Ward) # https://github.com/kward/shunit2 # # This unit test is purely to test that calling shunit2 directly, while passing # the name of a unit test script, works. When run, this script determines if it # is running as a standalone program, and calls main() if it is. # ### ShellCheck http://www.shellcheck.net/ # $() are not fully portable (POSIX != portable). # shellcheck disable=SC2006 # Disable source following. # shellcheck disable=SC1090,SC1091 ARGV0="`basename "$0"`" # Load test helpers. . ./shunit2_test_helpers testStandalone() { assertTrue "${SHUNIT_TRUE}" } main() { ${TH_SHUNIT} "${ARGV0}" } # Are we running as a standalone? if [ "${ARGV0}" = 'shunit2_test_standalone.sh' ]; then if [ $# -gt 0 ]; then main "$@"; else main; fi fi ================================================ FILE: tests/shunit/shunit2_test_helpers ================================================ # vim:et:ft=sh:sts=2:sw=2 # # shUnit2 unit test common functions # # Copyright 2008 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 license. # # Author: kate.ward@forestent.com (Kate Ward) # https://github.com/kward/shunit2 # ### ShellCheck (http://www.shellcheck.net/) # Commands are purposely escaped so they can be mocked outside shUnit2. # shellcheck disable=SC1001,SC1012 # expr may be antiquated, but it is the only solution in some cases. # shellcheck disable=SC2003 # $() are not fully portable (POSIX != portable). # shellcheck disable=SC2006 # Treat unset variables as an error when performing parameter expansion. set -u # Set shwordsplit for zsh. \[ -n "${ZSH_VERSION:-}" ] && setopt shwordsplit # # Constants. # # Path to shUnit2 library. Can be overridden by setting SHUNIT_INC. TH_SHUNIT=${SHUNIT_INC:-./shunit2}; export TH_SHUNIT # Configure debugging. Set the DEBUG environment variable to any # non-empty value to enable debug output, or TRACE to enable trace # output. TRACE=${TRACE:+'th_trace '} \[ -n "${TRACE}" ] && DEBUG=1 \[ -z "${TRACE}" ] && TRACE=':' DEBUG=${DEBUG:+'th_debug '} \[ -z "${DEBUG}" ] && DEBUG=':' # # Variables. # th_RANDOM=0 # # Functions. # # Logging functions. th_trace() { echo "${MY_NAME}:TRACE $*" >&2; } th_debug() { echo "${MY_NAME}:DEBUG $*" >&2; } th_info() { echo "${MY_NAME}:INFO $*" >&2; } th_warn() { echo "${MY_NAME}:WARN $*" >&2; } th_error() { echo "${MY_NAME}:ERROR $*" >&2; } th_fatal() { echo "${MY_NAME}:FATAL $*" >&2; } # Output subtest name. th_subtest() { echo " $*" >&2; } th_oneTimeSetUp() { # These files will be cleaned up automatically by shUnit2. stdoutF="${SHUNIT_TMPDIR}/stdout" stderrF="${SHUNIT_TMPDIR}/stderr" returnF="${SHUNIT_TMPDIR}/return" expectedF="${SHUNIT_TMPDIR}/expected" export stdoutF stderrF returnF expectedF } # Generate a random number. th_generateRandom() { tfgr_random=${th_RANDOM} while \[ "${tfgr_random}" = "${th_RANDOM}" ]; do # shellcheck disable=SC2039 if \[ -n "${RANDOM:-}" ]; then # $RANDOM works # shellcheck disable=SC2039 tfgr_random=${RANDOM}${RANDOM}${RANDOM}$$ elif \[ -r '/dev/urandom' ]; then tfgr_random=`od -vAn -N4 -tu4 >> STDOUT' >&2 \cat "${_th_stdout_}" >&2 fi if \[ -n "${_th_stderr_}" -a -s "${_th_stderr_}" ]; then echo '>>> STDERR' >&2 \cat "${_th_stderr_}" >&2 fi if \[ -n "${_th_stdout_}" -o -n "${_th_stderr_}" ]; then echo '<<< end output' >&2 fi fi unset _th_return_ _th_stdout_ _th_stderr_ } # # Main. # ${TRACE} 'trace output enabled' ${DEBUG} 'debug output enabled' ================================================ FILE: tests/shunit/test_runner ================================================ #! /bin/sh # vim:et:ft=sh:sts=2:sw=2 # # Unit test suite runner. # # Copyright 2008-2018 Kate Ward. All Rights Reserved. # Released under the Apache 2.0 license. # # Author: kate.ward@forestent.com (Kate Ward) # https://github.com/kward/shlib # # This script runs all the unit tests that can be found, and generates a nice # report of the tests. # ### ShellCheck (http://www.shellcheck.net/) # Disable source following. # shellcheck disable=SC1090,SC1091 # expr may be antiquated, but it is the only solution in some cases. # shellcheck disable=SC2003 # $() are not fully portable (POSIX != portable). # shellcheck disable=SC2006 # Return if test_runner already loaded. [ -z "${RUNNER_LOADED:-}" ] || return 0 RUNNER_LOADED=0 RUNNER_ARGV0=`basename "$0"` RUNNER_SHELLS='/bin/sh ash /bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/zsh' RUNNER_TEST_SUFFIX='_test.sh' true; RUNNER_TRUE=$? false; RUNNER_FALSE=$? runner_warn() { echo "runner:WARN $*" >&2; } runner_error() { echo "runner:ERROR $*" >&2; } runner_fatal() { echo "runner:FATAL $*" >&2; exit 1; } runner_usage() { echo "usage: ${RUNNER_ARGV0} [-e key=val ...] [-s shell(s)] [-t test(s)]" } _runner_tests() { echo ./*${RUNNER_TEST_SUFFIX} |sed 's#./##g'; } _runner_testName() { # shellcheck disable=SC1117 _runner_testName_=`expr "${1:-}" : "\(.*\)${RUNNER_TEST_SUFFIX}"` if [ -n "${_runner_testName_}" ]; then echo "${_runner_testName_}" else echo 'unknown' fi unset _runner_testName_ } main() { # Find and load versions library. for _runner_dir_ in . ${LIB_DIR:-lib}; do if [ -r "${_runner_dir_}/versions" ]; then _runner_lib_dir_="${_runner_dir_}" break fi done [ -n "${_runner_lib_dir_}" ] || runner_fatal 'Unable to find versions library.' . "${_runner_lib_dir_}/versions" || runner_fatal 'Unable to load versions library.' unset _runner_dir_ _runner_lib_dir_ # Process command line flags. env='' while getopts 'e:hs:t:' opt; do case ${opt} in e) # set an environment variable key=`expr "${OPTARG}" : '\([^=]*\)='` val=`expr "${OPTARG}" : '[^=]*=\(.*\)'` # shellcheck disable=SC2166 if [ -z "${key}" -o -z "${val}" ]; then runner_usage exit 1 fi eval "${key}='${val}'" eval "export ${key}" env="${env:+${env} }${key}" ;; h) runner_usage; exit 0 ;; # help output s) shells=${OPTARG} ;; # list of shells to run t) tests=${OPTARG} ;; # list of tests to run *) runner_usage; exit 1 ;; esac done shift "`expr ${OPTIND} - 1`" # Fill shells and/or tests. shells=${shells:-${RUNNER_SHELLS}} [ -z "${tests}" ] && tests=`_runner_tests` # Error checking. if [ -z "${tests}" ]; then runner_error 'no tests found to run; exiting' exit 1 fi cat <&1; ) test "${runner_passing_}" -eq ${RUNNER_TRUE} -a $? -eq ${RUNNER_TRUE} runner_passing_=$? done done return ${runner_passing_} } # Execute main() if this is run in standalone mode (i.e. not from a unit test). [ -z "${SHUNIT_VERSION}" ] && main "$@" ================================================ FILE: tests/signal1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/signal.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs signal-help() { __monitor HELP "$@" } _get_signal_names() { __monitor GETSIGNALNAMES "$@" } _validate_signal_name() { __monitor VALIDATESIGNALNAME "$@" if [ "$1" = "SIGINFO" ] || [ "$1" = "SIGHUP" ]; then return 0 # true fi return 1 # false } _validate_pid() { __monitor VALIDATEPID "$@" if [ "$1" = "1234" ]; then return 0 # true fi return 1 # false } _send_signal() { __monitor SENDSIGNAL "$@" } test_pot_signal_001() { pot-signal assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "Send signal calls" "0" SENDSIGNAL_CALLS setUp pot-signal -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Send signal calls" "0" SENDSIGNAL_CALLS setUp pot-signal -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Send signal calls" "0" SENDSIGNAL_CALLS setUp pot-signal -v assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "Send signal calls" "0" SENDSIGNAL_CALLS } test_pot_signal_002() { pot-signal -p test-pot -s SIGBAD assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "Validate signal calls" "1" VALIDATESIGNALNAME_CALLS assertEqualsMon "Validate signal arg" "SIGBAD" VALIDATESIGNALNAME_CALL1_ARG1 assertEqualsMon "Send signal calls" "0" SENDSIGNAL_CALLS setUp pot-signal -p test-pot -P 1234 -m cmd assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "Validate pid calls" "0" VALIDATEPID_CALLS assertEqualsMon "Send signal calls" "0" SENDSIGNAL_CALLS setUp pot-signal -p test-pot -P cmd assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "Validate pid calls" "1" VALIDATEPID_CALLS assertEqualsMon "Validate pid calls" "cmd" VALIDATEPID_CALL1_ARG1 assertEqualsMon "Send signal calls" "0" SENDSIGNAL_CALLS } test_pot_signal_003() { pot-signal -p test-pot -P 1234 assertEquals "Exit rc" "1" "$?" assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "Validate pid calls" "1" VALIDATEPID_CALLS assertEqualsMon "Validate pid calls" "1234" VALIDATEPID_CALL1_ARG1 assertEqualsMon "Validate signal calls" "1" VALIDATESIGNALNAME_CALLS assertEqualsMon "Validate signal arg" "SIGINFO" VALIDATESIGNALNAME_CALL1_ARG1 assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "Send signal calls" "0" SENDSIGNAL_CALLS } test_pot_signal_020() { pot-signal -p test-pot-run assertEquals "Exit rc" "0" "$?" assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Send signal calls" "1" SENDSIGNAL_CALLS assertEqualsMon "Send signal arg1" "test-pot-run" SENDSIGNAL_CALL1_ARG1 assertEqualsMon "Send signal arg2" "SIGINFO" SENDSIGNAL_CALL1_ARG2 assertEqualsMon "Send signal arg3" "" SENDSIGNAL_CALL1_ARG3 assertEqualsMon "Send signal arg4" "" SENDSIGNAL_CALL1_ARG4 assertEqualsMon "Send signal arg5" "NO" SENDSIGNAL_CALL1_ARG5 assertEqualsMon "Send signal arg6" "NO" SENDSIGNAL_CALL1_ARG6 setUp pot-signal -p test-pot-run -s SIGHUP assertEquals "Exit rc" "0" "$?" assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Send signal calls" "1" SENDSIGNAL_CALLS assertEqualsMon "Send signal arg1" "test-pot-run" SENDSIGNAL_CALL1_ARG1 assertEqualsMon "Send signal arg2" "SIGHUP" SENDSIGNAL_CALL1_ARG2 assertEqualsMon "Send signal arg3" "" SENDSIGNAL_CALL1_ARG3 assertEqualsMon "Send signal arg4" "" SENDSIGNAL_CALL1_ARG4 assertEqualsMon "Send signal arg5" "NO" SENDSIGNAL_CALL1_ARG5 assertEqualsMon "Send signal arg6" "NO" SENDSIGNAL_CALL1_ARG6 } test_pot_signal_021() { pot-signal -p test-pot-run -s SIGHUP -P 1234 -f -C assertEquals "Exit rc" "0" "$?" assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Send signal calls" "1" SENDSIGNAL_CALLS assertEqualsMon "Send signal arg1" "test-pot-run" SENDSIGNAL_CALL1_ARG1 assertEqualsMon "Send signal arg2" "SIGHUP" SENDSIGNAL_CALL1_ARG2 assertEqualsMon "Send signal arg3" "1234" SENDSIGNAL_CALL1_ARG3 assertEqualsMon "Send signal arg4" "" SENDSIGNAL_CALL1_ARG4 assertEqualsMon "Send signal arg5" "YES" SENDSIGNAL_CALL1_ARG5 assertEqualsMon "Send signal arg6" "YES" SENDSIGNAL_CALL1_ARG6 } test_pot_signal_022() { pot-signal -p test-pot-run -s SIGINFO -m grep -f -C assertEquals "Exit rc" "0" "$?" assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Send signal calls" "1" SENDSIGNAL_CALLS assertEqualsMon "Send signal arg1" "test-pot-run" SENDSIGNAL_CALL1_ARG1 assertEqualsMon "Send signal arg2" "SIGINFO" SENDSIGNAL_CALL1_ARG2 assertEqualsMon "Send signal arg3" "" SENDSIGNAL_CALL1_ARG3 assertEqualsMon "Send signal arg4" "grep" SENDSIGNAL_CALL1_ARG4 assertEqualsMon "Send signal arg5" "YES" SENDSIGNAL_CALL1_ARG5 assertEqualsMon "Send signal arg6" "YES" SENDSIGNAL_CALL1_ARG6 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/signal2.sh ================================================ #!/bin/sh # system utilities stubs pkill() { __monitor PKILL "$@" } pgrep() { __monitor PGREP "$@" } mktemp() { __monitor MKTEMP "$@" echo /dev/null } rm() { __monitor RM "$@" } # UUT . ../share/pot/signal.sh . ../share/pot/common.sh # common stubs . common-stub.sh _get_conf_var() { __monitor GETCONFVAR "$@" if [ "$1" = "test-pot-presist" ]; then echo "YES" return fi echo "NO" } # app specific stubs test_send_signal_001() { _send_signal test-pot SIGINFO "" "" "NO" "NO" assertEqualsMon "pgrep calls" "0" PGREP_CALLS assertEqualsMon "pkill calls" "1" PKILL_CALLS assertEqualsMon "pkill arg1" "-SIGINFO" PKILL_CALL1_ARG1 assertEqualsMon "pkill arg2" "-j" PKILL_CALL1_ARG2 assertEqualsMon "pkill arg3" "test-pot" PKILL_CALL1_ARG3 assertEqualsMon "pkill arg4" "-F" PKILL_CALL1_ARG4 assertEqualsMon "pkill arg5" "/tmp/pot_main_pid_test-pot" PKILL_CALL1_ARG5 assertEqualsMon "rm calls" "0" RM_CALLS } test_send_signal_002() { _send_signal test-pot-presist SIGINFO "" "" "NO" "NO" rc=$? assertEquals "return code" "1" "$rc" assertEqualsMon "pgrep calls" "0" PGREP_CALLS assertEqualsMon "pkill calls" "0" PKILL_CALLS } test_send_signal_003() { _send_signal test-pot-presist SIGINFO "" "" "YES" "NO" rc=$? assertEquals "return code" "0" "$rc" assertEqualsMon "pgrep calls" "0" PGREP_CALLS assertEqualsMon "pkill calls" "0" PKILL_CALLS } test_send_signal_010() { _send_signal test-pot SIGINFO "" "command" "NO" "NO" assertEqualsMon "pgrep calls" "0" PGREP_CALLS assertEqualsMon "pkill calls" "1" PKILL_CALLS assertEqualsMon "pkill arg1" "-SIGINFO" PKILL_CALL1_ARG1 assertEqualsMon "pkill arg2" "-j" PKILL_CALL1_ARG2 assertEqualsMon "pkill arg3" "test-pot" PKILL_CALL1_ARG3 assertEqualsMon "pkill arg4" "command" PKILL_CALL1_ARG4 assertEqualsMon "rm calls" "0" RM_CALLS } test_send_signal_011() { _send_signal test-pot SIGINFO "1234" "" "NO" "NO" assertEqualsMon "pgrep calls" "0" PGREP_CALLS assertEqualsMon "pkill calls" "1" PKILL_CALLS assertEqualsMon "pkill arg1" "-SIGINFO" PKILL_CALL1_ARG1 assertEqualsMon "pkill arg2" "-j" PKILL_CALL1_ARG2 assertEqualsMon "pkill arg3" "test-pot" PKILL_CALL1_ARG3 assertEqualsMon "pkill arg4" "-F" PKILL_CALL1_ARG4 assertEqualsMon "pkill arg5" "/dev/null" PKILL_CALL1_ARG5 assertEqualsMon "rm calls" "1" RM_CALLS } test_send_signal_020() { _send_signal test-pot SIGINFO "" "" "NO" "YES" assertEqualsMon "pgrep calls" "1" PGREP_CALLS assertEqualsMon "pkill arg1" "-j" PGREP_CALL1_ARG1 assertEqualsMon "pkill arg2" "test-pot" PGREP_CALL1_ARG2 assertEqualsMon "pkill arg4" "/tmp/pot_main_pid_test-pot" PGREP_CALL1_ARG4 assertEqualsMon "pkill calls" "0" PKILL_CALLS } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/snapshot1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/snapshot.sh # common stubs . common-stub.sh # app specific stubs snapshot-help() { __monitor HELP "$@" } test_pot_snapshot_001() { pot-snapshot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS setUp pot-snapshot -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS setUp pot-snapshot -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS setUp pot-snapshot -va assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS } test_pot_snapshot_002() { pot-snapshot -f test-fscomp -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_zfs_exist calls" "0" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS assertEqualsMon "Info calls" "0" INFO_CALLS } test_pot_snapshot_003() { pot-snapshot -p test-pot -f test-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_zfs_exist calls" "0" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS assertEqualsMon "Info calls" "0" INFO_CALLS } test_pot_snapshot_004() { pot-snapshot -p test-pot -n backup assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_zfs_exist calls" "0" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS assertEqualsMon "Info calls" "0" INFO_CALLS } test_pot_snapshot_020() { pot-snapshot -p assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS setUp pot-snapshot -p not-a-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS setUp pot-snapshot -p test-pot-run assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS } test_pot_snapshot_021() { pot-snapshot -p test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "1" POTZFSSNAP_CALLS assertEqualsMon "_pot_zfs_snap arg" "test-pot" POTZFSSNAP_CALL1_ARG1 assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS } test_pot_snapshot_022() { pot-snapshot -p test-pot -a assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_zfs_exist calls" "0" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS assertEqualsMon "Info calls" "0" INFO_CALLS } test_pot_snapshot_023() { pot-snapshot -p test-pot -r assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "1" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "1" RMVPOTSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap arg" "test-pot" RMVPOTSNAP_CALL1_ARG1 assertEqualsMon "_pot_zfs_snap calls" "1" POTZFSSNAP_CALLS assertEqualsMon "_pot_zfs_snap arg" "test-pot" POTZFSSNAP_CALL1_ARG1 assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS } test_pot_snapshot_040() { pot-snapshot -f assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS setUp pot-snapshot -f not-a-fscomp assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_zfs_exist calls" "1" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS } test_pot_snapshot_041() { pot-snapshot -f test-fscomp assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_zfs_exist calls" "1" ZFSEXIST_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "1" FSCOMPZFSSNAP_CALLS assertEqualsMon "_fscomp_zfs_snap arg" "test-fscomp" FSCOMPZFSSNAP_CALL1_ARG1 assertEqualsMon "_fscomp_zfs_snap arg" "" FSCOMPZFSSNAP_CALL1_ARG2 assertEqualsMon "Info calls" "0" INFO_CALLS } test_pot_snapshot_042() { pot-snapshot -f test-fscomp -a assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_zfs_exist calls" "0" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS assertEqualsMon "Info calls" "0" INFO_CALLS } test_pot_snapshot_043() { pot-snapshot -f test-fscomp -n backup assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_zfs_exist calls" "0" ZFSEXIST_CALLS assertEqualsMon "_fscomp_zfs_snap calls" "0" FSCOMPZFSSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "0" RMVFSCOMPSNAP_CALLS assertEqualsMon "Info calls" "0" INFO_CALLS } test_pot_snapshot_044() { pot-snapshot -f test-fscomp -r assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot calls" "0" ISPOT_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_pot_zfs_snap calls" "0" POTZFSSNAP_CALLS assertEqualsMon "_remove_oldest_pot_snap calls" "0" RMVPOTSNAP_CALLS assertEqualsMon "_pot_zfs_snap_full calls" "0" POTZFSSNAPFULL_CALLS assertEqualsMon "_zfs_exist calls" "1" ZFSEXIST_CALLS assertEqualsMon "_remove_oldest_fscomp_snap calls" "1" RMVFSCOMPSNAP_CALLS assertEqualsMon "_remove_oldest_fscomp_snap arg" "test-fscomp" RMVFSCOMPSNAP_CALL1_ARG1 assertEqualsMon "_fscomp_zfs_snap calls" "1" FSCOMPZFSSNAP_CALLS assertEqualsMon "_fscomp_zfs_snap arg" "test-fscomp" FSCOMPZFSSNAP_CALL1_ARG1 assertEqualsMon "_fscomp_zfs_snap arg" "" FSCOMPZFSSNAP_CALL1_ARG2 assertEqualsMon "Info calls" "0" INFO_CALLS } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/start2.sh ================================================ #!/bin/sh : ${MKTEMP_FILE:=/tmp/pot_pfrules_test} # system utilities stubs pfctl() { __monitor PFCTL "$@" } mktemp() { touch $MKTEMP_FILE echo $MKTEMP_FILE } rm() { : } # UUT . ../share/pot/start.sh POT_MKTEMP_SUFFIX=XXX # common stubs . common-stub.sh _get_pot_export_ports() { __monitor GETEXPORTPORTS "$@" } _js_get_free_rnd_port() { __monitor RNDPORT "$@" echo 3333 } _get_ip_var() { echo 1.2.3.4 } _get_pot_export_ports() { case $1 in "test-pot80") echo 80 ;; "test-pot80s3000") echo 80:3000 ;; "test-pot80433") echo 80 433:3000 ;; "test-pot53udp80433tcp") echo udp:53:53 tcp:80 tcp:433:3000 ;; *) ;; esac } test_js_export_ports_001() { _js_export_ports test-pot80 assertEqualsMon "pfctl calls" "1" PFCTL_CALLS assertEquals "pfrules lines" "1" "$( wc -l $MKTEMP_FILE | awk '{print $1}')" assertEquals "rdr rule" "rdr pass on em2 proto tcp from any to (em2) port 3333 -> 1.2.3.4 port 80" "$(sed '1!d' $MKTEMP_FILE)" } test_js_export_ports_002() { _js_export_ports test-pot80s3000 assertEqualsMon "pfctl calls" "1" PFCTL_CALLS assertEquals "pfrules lines" "1" "$( wc -l $MKTEMP_FILE | awk '{print $1}')" assertEquals "rdr rule" "rdr pass on em2 proto tcp from any to (em2) port 3000 -> 1.2.3.4 port 80" "$(sed '1!d' $MKTEMP_FILE)" } test_js_export_ports_003() { _js_export_ports test-pot80433 assertEqualsMon "pfctl calls" "1" PFCTL_CALLS assertEquals "pfrules lines" "2" "$( wc -l $MKTEMP_FILE | awk '{print $1}')" assertEquals "rdr rule" "rdr pass on em2 proto tcp from any to (em2) port 3333 -> 1.2.3.4 port 80" "$(sed '1!d' $MKTEMP_FILE)" assertEquals "rdr rule" "rdr pass on em2 proto tcp from any to (em2) port 3000 -> 1.2.3.4 port 433" "$(sed '2!d' $MKTEMP_FILE)" } test_js_export_ports_004() { _js_export_ports test-pot53udp80433tcp assertEqualsMon "pfctl calls" "1" PFCTL_CALLS assertEquals "pfrules lines" "3" "$( wc -l $MKTEMP_FILE | awk '{print $1}')" assertEquals "rdr rule" "rdr pass on em2 proto udp from any to (em2) port 53 -> 1.2.3.4 port 53" "$(sed '1!d' $MKTEMP_FILE)" assertEquals "rdr rule" "rdr pass on em2 proto tcp from any to (em2) port 3333 -> 1.2.3.4 port 80" "$(sed '2!d' $MKTEMP_FILE)" assertEquals "rdr rule" "rdr pass on em2 proto tcp from any to (em2) port 3000 -> 1.2.3.4 port 433" "$(sed '3!d' $MKTEMP_FILE)" } setUp() { common_setUp POT_FS_ROOT=/tmp POT_ZFS_ROOT=zpot POT_EXTIF="em2" } tearDown() { common_tearDown /bin/rm -f $MKTEMP_FILE } . shunit/shunit2 ================================================ FILE: tests/start3.sh ================================================ #!/bin/sh # system utilities stubs pfctl() { __monitor PFCTL "$@" } SED=sed_stub sed_stub() { if [ "$(uname)" = "Linux" ]; then shift 2 sed -i'' "$@" else sed "$@" fi } POT_MKTEMP_SUFFIX=XXX # UUT . ../share/pot/start.sh # common stubs . ../share/pot/common.sh . ../share/pot/set-env.sh . common-stub.sh . conf-stub.sh cp() { : } pot-cmd() { echo _POT_NAME=test-pot } test_js_env_001() { _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "1" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" } test_js_env_020() { pot-set-env -p test-pot -E VAR=value _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "2" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR=value"' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line2" "0" "$( grep -F -c 'export "VAR2=' /tmp/pot_environment_test-pot.sh)" # . /tmp/pot_environment_test-pot.sh # assertEquals "export validation" "$VAR" "value" # assertEquals "export validation" "$_POT_NAME" "test-pot" } test_js_env_021() { pot-set-env -p test-pot -E VAR=value -E VAR2=value2 _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "3" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR=value"' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR2=value2"' /tmp/pot_environment_test-pot.sh)" # . /tmp/pot_environment_test-pot.sh # assertEquals "export validation" "$VAR" "value" # assertEquals "export validation" "$VAR2" "value2" } test_js_env_022() { pot-set-env -p test-pot -E VAR="value1 value2" _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "2" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR=value1 value2"' /tmp/pot_environment_test-pot.sh)" # . /tmp/pot_environment_test-pot.sh # assertEquals "export validation" "$VAR" "value1 value2" } test_js_env_023() { pot-set-env -p test-pot -E "VAR=value1 value2" -E VAR2=value3 _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "3" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR=value1 value2"' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR2=value3"' /tmp/pot_environment_test-pot.sh)" # . /tmp/pot_environment_test-pot.sh # assertEquals "export validation" "$VAR" "value1 value2" # assertEquals "export validation" "$VAR2" "value3" } test_js_env_024() { pot-set-env -p test-pot -E "EMPTYVAR=" _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "2" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "EMPTYVAR="' /tmp/pot_environment_test-pot.sh)" # # . /tmp/pot_environment_test-pot.sh # assertEquals "export validation" "$EMPTYVAR" "" } test_js_env_025() { pot-set-env -p test-pot -E "VAR=12*" _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "2" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR=12*"' /tmp/pot_environment_test-pot.sh)" # # . /tmp/pot_environment_test-pot.sh # assertEquals "export validation" "$VAR" "12*" } test_js_env_026() { pot-set-env -p test-pot -E "VAR=12*" -E "VAR2=?h* " _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "3" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR=12*"' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR2=?h* "' /tmp/pot_environment_test-pot.sh)" # . /tmp/pot_environment_test-pot.sh # assertEquals "export validation" "$VAR" "12*" # assertEquals "export validation" "$VAR2" "?h* " } test_js_env_027() { pot-set-env -p test-pot -E 'VAR=value1 "value2"' _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "2" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR=value1 \"value2\""' /tmp/pot_environment_test-pot.sh)" # # . /tmp/pot_environment_test-pot.sh # assertEquals "export validation" 'value1 "value2"' "$VAR" } test_js_env_040() { pot-set-env -p test-pot -E VAR1=value1 -E "VAR2=value1 value2" -E 'VAR3=value1 value2 value3' -E VAR4=value4 _js_env test-pot # assertTrue "env script exists" "[ -e /tmp/pot_environment_test-pot.sh ]" # assertEquals "env script length" "5" "$( awk 'END {print NR}' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR1=value1"' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR2=value1 value2"' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR3=value1 value2 value3"' /tmp/pot_environment_test-pot.sh)" # assertEquals "export line" "1" "$( grep -F -c 'export "VAR4=value4"' /tmp/pot_environment_test-pot.sh)" } setUp() { common_setUp conf_setUp } tearDown() { common_tearDown conf_tearDown } . shunit/shunit2 ================================================ FILE: tests/start4.sh ================================================ #!/bin/sh # system utilities stubs potnet() { if [ -z "$3" ]; then # public bridge echo "10.1.2.3 test-pot-2" echo "10.1.2.4 test-single" fi if [ "$3" = "test-bridge" ]; then # private-bridge echo "10.1.3.3 test-pot-multi-private" fi } # UUT . ../share/pot/start.sh # common stubs . common-stub.sh test_js_etc_hosts_000() { _js_etc_hosts test-pot-2 assertTrue "/etc/hosts" "[ -r /tmp/jails/test-pot-2/m/etc ]" assertEquals "/etc/hosts length" "4" "$( awk 'END {print NR}' /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "127.0.0.1" "127.0.0.1 localhost test-pot-2.test-domain" "$( grep "^127.0.0.1" /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "::1" "::1 localhost test-pot-2.test-domain" "$( grep "^::1" /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "test-pot-2" "10.1.2.3 test-pot-2" "$( grep "^10.1.2.3 " /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "test-single" "10.1.2.4 test-single" "$( grep "^10.1.2.4 " /tmp/jails/test-pot-2/m/etc/hosts)" } test_js_etc_hosts_001() { _js_etc_hosts test-pot-multi-private assertTrue "/etc/hosts" "[ -r /tmp/jails/test-pot-multi-private/m/etc ]" assertEquals "/etc/hosts length" "3" "$( awk 'END {print NR}' /tmp/jails/test-pot-multi-private/m/etc/hosts)" assertEquals "127.0.0.1" "127.0.0.1 localhost test-pot-multi-private.test-domain" "$( grep "^127.0.0.1" /tmp/jails/test-pot-multi-private/m/etc/hosts)" assertEquals "::1" "::1 localhost test-pot-multi-private.test-domain" "$( grep "^::1" /tmp/jails/test-pot-multi-private/m/etc/hosts)" assertEquals "test-pot-multi-private" "10.1.3.3 test-pot-multi-private" "$( grep "^10.1.3.3 " /tmp/jails/test-pot-multi-private/m/etc/hosts)" } test_js_etc_hosts_020() { echo "pot.hosts=10.10.10.1 test-pot-custom" > /tmp/jails/test-pot-2/conf/pot.conf echo "pot.hosts=10.10.10.2 test-pot-custom-2" >> /tmp/jails/test-pot-2/conf/pot.conf _js_etc_hosts test-pot-2 assertTrue "/etc/hosts" "[ -r /tmp/jails/test-pot-2/m/etc ]" assertEquals "/etc/hosts length" "6" "$( awk 'END {print NR}' /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "127.0.0.1" "127.0.0.1 localhost test-pot-2.test-domain" "$( grep "^127.0.0.1" /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "::1" "::1 localhost test-pot-2.test-domain" "$( grep "^::1" /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "test-pot-2" "10.1.2.3 test-pot-2" "$( grep "^10.1.2.3 " /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "test-single" "10.1.2.4 test-single" "$( grep "^10.1.2.4 " /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "test-pot-custom" "10.10.10.1 test-pot-custom" "$( grep "^10.10.10.1 " /tmp/jails/test-pot-2/m/etc/hosts)" assertEquals "test-pot-custom-2" "10.10.10.2 test-pot-custom-2" "$( grep "^10.10.10.2 " /tmp/jails/test-pot-2/m/etc/hosts)" } test_js_etc_hosts_021() { echo "pot.hosts=10.10.10.1 test-pot-custom" > /tmp/jails/test-pot-multi-private/conf/pot.conf echo "pot.hosts=10.10.10.2 test-pot-custom-2" >> /tmp/jails/test-pot-multi-private/conf/pot.conf _js_etc_hosts test-pot-multi-private assertTrue "/etc/hosts" "[ -r /tmp/jails/test-pot-multi-private/m/etc/hosts ]" assertEquals "/etc/hosts length" "5" "$( awk 'END {print NR}' /tmp/jails/test-pot-multi-private/m/etc/hosts)" assertEquals "127.0.0.1" "127.0.0.1 localhost test-pot-multi-private.test-domain" "$( grep "^127.0.0.1" /tmp/jails/test-pot-multi-private/m/etc/hosts)" assertEquals "::1" "::1 localhost test-pot-multi-private.test-domain" "$( grep "^::1" /tmp/jails/test-pot-multi-private/m/etc/hosts)" assertEquals "test-pot-multi-private" "10.1.3.3 test-pot-multi-private" "$( grep "^10.1.3.3 " /tmp/jails/test-pot-multi-private/m/etc/hosts)" assertEquals "test-pot-custom" "10.10.10.1 test-pot-custom" "$( grep "^10.10.10.1 " /tmp/jails/test-pot-multi-private/m/etc/hosts)" assertEquals "test-pot-custom-2" "10.10.10.2 test-pot-custom-2" "$( grep "^10.10.10.2 " /tmp/jails/test-pot-multi-private/m/etc/hosts)" } test_js_resolv_001() { _js_resolv test-pot-dns-off assertFalse "off created a resolv.conf" "[ -r /tmp/jails/test-pot-dns-off/m/etc/resolv.conf ]" } test_js_resolv_002() { _js_resolv test-pot-dns-inherit assertTrue "not created a resolv.conf" "[ -r /tmp/jails/test-pot-dns-inherit/m/etc/resolv.conf ]" assertTrue "wrong resolv.conf" "diff /tmp/jails/test-pot-dns-inherit/m/etc/resolv.conf /etc/resolv.conf" } test_js_resolv_003() { _js_resolv test-pot-dns-custom assertTrue "off created a resolv.conf" "[ -r /tmp/jails/test-pot-dns-custom/m/etc/resolv.conf ]" assertTrue "wrong resolv.conf" "diff /tmp/jails/test-pot-dns-custom/m/etc/resolv.conf /tmp/jails/test-pot-dns-custom/conf/resolv.conf" } test_js_resolv_004() { _js_resolv test-pot-dns-pot assertTrue "off created a resolv.conf" "[ -r /tmp/jails/test-pot-dns-pot/m/etc/resolv.conf ]" assertEquals "test-js-resolv-search" "search test-domain" "$( grep "^search " /tmp/jails/test-pot-dns-pot/m/etc/resolv.conf)" assertEquals "test-js-resolv-server" "nameserver 10.2.3.4" "$( grep "^nameserver " /tmp/jails/test-pot-dns-pot/m/etc/resolv.conf)" } setUp() { common_setUp POT_FS_ROOT=/tmp POT_ZFS_ROOT=zpot POT_EXTIF="em2" POT_DNS_IP="10.2.3.4" mkdir -p /tmp/jails/test-pot-2/m/etc mkdir -p /tmp/jails/test-pot-2/conf touch /tmp/jails/test-pot-2/conf/pot.conf mkdir -p /tmp/jails/test-pot-multi-private/m/etc mkdir -p /tmp/jails/test-pot-multi-private/conf touch /tmp/jails/test-pot-multi-private/conf/pot.conf mkdir -p /tmp/jails/test-pot-dns-inherit/m/etc mkdir -p /tmp/jails/test-pot-dns-pot/m/etc mkdir -p /tmp/jails/test-pot-dns-custom/m/etc mkdir -p /tmp/jails/test-pot-dns-custom/conf touch /tmp/jails/test-pot-dns-custom/conf/resolv.conf } tearDown() { common_tearDown rm -rf /tmp/jails } . shunit/shunit2 ================================================ FILE: tests/stop1.sh ================================================ #!/bin/sh # system utilities stubs lockf() { return 0 } # UUT . ../share/pot/stop.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs _js_rm_resolv() { return 0 # true } _pot_umount() { return 0 # true } _epair_cleanup() { return 0 # true } _js_stop() { __monitor STOPPED "$@" } stop-help() { __monitor HELP "$@" } test_pot_stop_001() { pot-stop assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "Stop calls" "0" STOPPED_CALLS setUp pot-stop -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Stop calls" "0" STOPPED_CALLS setUp pot-stop -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Stop calls" "0" STOPPED_CALLS } test_pot_stop_002() { pot-stop non-existent-test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "Stop calls" "0" STOPPED_CALLS } test_pot_stop_020() { pot-stop test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Stop calls" "1" STOPPED_CALLS assertEqualsMon "stop args" "test-pot" STOPPED_CALL1_ARG1 assertEqualsMon "stop args" "NO" STOPPED_CALL1_ARG2 assertEqualsMon "stop args" "" STOPPED_CALL1_ARG3 } test_pot_stop_021() { pot-stop -p test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Stop calls" "1" STOPPED_CALLS assertEqualsMon "stop args" "test-pot" STOPPED_CALL1_ARG1 assertEqualsMon "stop args" "NO" STOPPED_CALL1_ARG2 assertEqualsMon "stop args" "" STOPPED_CALL1_ARG3 } test_pot_stop_022() { pot-stop -p test-pot -s assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Stop calls" "1" STOPPED_CALLS assertEqualsMon "stop args" "test-pot" STOPPED_CALL1_ARG1 assertEqualsMon "stop args" "YES" STOPPED_CALL1_ARG2 assertEqualsMon "stop args" "" STOPPED_CALL1_ARG3 } test_pot_stop_023() { pot-stop -p test-pot -s -i epair4a assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "Stop calls" "1" STOPPED_CALLS assertEqualsMon "stop args" "test-pot" STOPPED_CALL1_ARG1 assertEqualsMon "stop args" "YES" STOPPED_CALL1_ARG2 assertEqualsMon "stop args" "epair4a" STOPPED_CALL1_ARG3 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/term1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/term.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs pot-cmd() { __monitor POTCMD "$@" if [ "$POTCMD_SHOULD_START_POT" = "yes" ]; then _pname="test-pot-run" fi } _term() { __monitor TERM "$@" } term-help() { __monitor HELP "$@" } test_pot_term_001() { pot-term assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_term calls" "0" TERM_CALLS assertEqualsMon "pot-cmd calls" "0" POTCMD_CALLS setUp pot-term -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "_term calls" "0" TERM_CALLS assertEqualsMon "pot-cmd calls" "0" POTCMD_CALLS setUp pot-term -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot_running calls" "0" ISPOTRUN_CALLS assertEqualsMon "_term calls" "0" TERM_CALLS assertEqualsMon "pot-cmd calls" "0" POTCMD_CALLS } test_pot_term_020() { pot-term test-pot-run assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "_term calls" "1" TERM_CALLS assertEqualsMon "pot-cmd calls" "0" POTCMD_CALLS } test_pot_term_030() { pot-term test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot_running calls" "1" ISPOTRUN_CALLS assertEqualsMon "_term calls" "0" TERM_CALLS assertEqualsMon "pot-cmd calls" "0" POTCMD_CALLS } test_pot_term_031() { pot-term -f test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "_is_pot_running calls" "2" ISPOTRUN_CALLS assertEqualsMon "_term calls" "0" TERM_CALLS assertEqualsMon "pot-cmd calls" "1" POTCMD_CALLS } test_pot_term_032() { # In this test "pot-cmd start" is changing pot name from # test-pot to test-pot-run. POTCMD_SHOULD_START_POT=yes pot-term -f test-pot assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "_is_pot_running calls" "2" ISPOTRUN_CALLS assertEqualsMon "_term calls" "1" TERM_CALLS assertEqualsMon "pot-cmd calls" "1" POTCMD_CALLS } setUp() { common_setUp POTCMD_SHOULD_START_POT=no } . shunit/shunit2 ================================================ FILE: tests/test-suite.sh ================================================ #!/bin/sh DOIT= SHL="sh" if [ "$(uname)" = "Linux" ]; then # using bash explicitely because of travis unkowns about /bin/sh DOIT=bash SHL=bash fi if ! $SHL -n ../bin/pot ../share/pot/*.sh ; then exit 1 else echo "Syntax check passed" echo fi if ! command -v flock >/dev/null; then echo "flock not found." 1>&2 if [ "$(uname)" = "FreeBSD" ]; then echo "Consider installing sysutils/flock" 1>&2 echo "(pkg install flock)" 1>&2 fi exit 1 fi suites=$(ls ./*.sh) rc=0 for s in $suites ; do if [ "$s" = "./test-suite.sh" ]; then continue elif [ "$s" = "./common-stub.sh" ]; then continue elif [ "$s" = "./conf-stub.sh" ]; then continue elif [ "$s" = "./pipefail-stub.sh" ]; then continue elif [ "$s" = "./monitor.sh" ]; then continue else echo "Running $( basename $s ) ..." $DOIT "./$s" || rc=1 fi done exit $rc ================================================ FILE: tests/top1.sh ================================================ #!/bin/sh # system utilities stubs top() { __monitor TOP "$@" } # UUT . ../share/pot/top.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs top-help() { __monitor HELP "$@" } test_pot_top_001() { pot-top -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "top calls" "0" TOP_CALLS setUp pot-top -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "top calls" "0" TOP_CALLS } test_pot_top_020() { pot-top -p assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "top calls" "0" TOP_CALLS assertEqualsMon "top arg1" "" TOP_CALL1_ARG1 } test_pot_top_021() { pot-top -p "" assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "top calls" "0" TOP_CALLS assertEqualsMon "top arg1" "" TOP_CALL1_ARG1 } test_pot_top_022() { pot-top -p no-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "top calls" "0" TOP_CALLS assertEqualsMon "top arg1" "" TOP_CALL1_ARG1 } test_pot_top_023() { pot-top -p test-pot assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS assertEqualsMon "Error calls" "1" ERROR_CALLS assertEqualsMon "top calls" "0" TOP_CALLS assertEqualsMon "top arg1" "" TOP_CALL1_ARG1 } test_pot_top_040() { pot-top -p test-pot-run assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "0" HELP_CALLS assertEqualsMon "Error calls" "0" ERROR_CALLS assertEqualsMon "top calls" "1" TOP_CALLS assertEqualsMon "top arg1" "-J" TOP_CALL1_ARG1 assertEqualsMon "top arg2" "test-pot-run" TOP_CALL1_ARG2 } setUp() { common_setUp } . shunit/shunit2 ================================================ FILE: tests/version1.sh ================================================ #!/bin/sh # system utilities stubs # UUT . ../share/pot/version.sh . ../share/pot/common.sh # common stubs . common-stub.sh # app specific stubs version-help() { __monitor HELP "$@" } test_pot_version_001() { pot-version -b bb assertEquals "Exit rc" "1" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS setUp pot-version -h assertEquals "Exit rc" "0" "$?" assertEqualsMon "Help calls" "1" HELP_CALLS } test_pot_version_020() { result=$(pot-version) assertEquals "Exit rc" "0" "$?" assertEquals "Incorrect version" "pot version: $_POT_VERSION" "$result" } test_pot_version_021() { result=$(pot-version -v) assertEquals "Exit rc" "0" "$?" assertEquals "Incorrect version" "pot version: $_POT_VERSION" "$result" } test_pot_version_022() { result=$(pot-version -q) assertEquals "Exit rc" "0" "$?" assertEquals "Incorrect version" "$_POT_VERSION" "$result" } setUp() { common_setUp _POT_VERSION="5.4.3" _POT_VERBOSITY="1" } . shunit/shunit2