{"id":20044930,"url":"https://github.com/gryf/boxpy","last_synced_at":"2025-09-20T10:32:15.295Z","repository":{"id":63257459,"uuid":"356010051","full_name":"gryf/boxpy","owner":"gryf","description":"Run Linux cloud image on top of VirtualBox using commandline tool","archived":false,"fork":false,"pushed_at":"2024-11-17T18:28:48.000Z","size":295,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-20T11:57:08.024Z","etag":null,"topics":["automation","python","virtualbox","wrapper"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gryf.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-08T18:23:28.000Z","updated_at":"2024-11-17T18:28:51.000Z","dependencies_parsed_at":"2024-04-30T14:35:22.112Z","dependency_job_id":"c8ab00e4-a936-4c13-8080-90735b3a9a5e","html_url":"https://github.com/gryf/boxpy","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gryf%2Fboxpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gryf%2Fboxpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gryf%2Fboxpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gryf%2Fboxpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gryf","download_url":"https://codeload.github.com/gryf/boxpy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233655316,"owners_count":18709257,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","python","virtualbox","wrapper"],"created_at":"2024-11-13T11:02:53.134Z","updated_at":"2025-09-20T10:32:15.285Z","avatar_url":"https://github.com/gryf.png","language":"Python","readme":"======\nbox.py\n======\n\nBox.py is a simple automation tool meant to run Ubuntu, Fedora, Centos Stream\nor Debian cloud images on top of VirtualBox.\n\nWhat it does is simply download official cloud image, set up VM, tweak it up\nand do the initial pre-configuration using generated config drive.\n\nI've wrote this little tool just to not click myself to death using web browser\nfor downloading cloud images, and going through VirtualBox GUI (or figuring out\nweird named options for ``vboxmanage`` ;P)\n\n\nRequirements\n------------\n\n- Python \u003e=3.8\n\n  - `pyyaml`_\n  - `requests`_\n\n- Virtualbox (obviously)\n- ``mkisofs`` or ``genisoimage`` command for generating ISO image\n- ``wget`` command for fetching images\n- ``sha256sum`` and ``sha512sum`` commands for checksum check\n- ``qemu-img`` from *qemu-utils* package command for converting between images\n  formats\n\n\nTested distros\n--------------\n\n- Ubuntu\n  - 18.04\n  - 20.04\n  - 22.04\n  - 24.04\n  - 25.04\n- Fedora\n  - 37\n  - 38\n  - 39\n  - 40\n  - 41\n  - 42\n- Centos Stream\n  - 8\n  - 9\n- Debian\n  - 10 (buster)\n  - 11 (bullseye)\n  - 12 (bookworm)\n  - 13 (trixie) - prerelease\n\nThere is possibility to use whatever OS image which supports cloud-init. Use\nthe ``--image`` param for ``create`` command to pass image filename, although\nit's wise to at least discover (or not, but it may be easier in certain\ndistributions) what username is supposed to be used as a default user and pass\nit with ``--username`` param.\n\n\nHow to run it\n-------------\n\nFirst, make sure you fulfill the requirements; either by using packages from\nyour operating system, or by using virtualenv, i.e.:\n\n.. code:: shell-session\n\n   $ python -m virtualenv .venv\n   $ . .venv/bin/activate\n   (.venv) $ pip install .\n\nYou'll have ``boxpy`` command created for you as well.\n\n.. code:: shell-session\n\n   $ boxpy -V\n   boxpy 1.9.2\n\nOther option is simply link it somewhere in the path:\n\n.. code:: shell-session\n\n   $ ln -s /path/to/box.py ~/bin/boxpy\n   $ chmod +x ~/bin/boxpy\n\nand now you can issue some command. For example, to spin up a VM with Ubuntu\n20.04 with one CPU, 1GB of memory and 6GB of disk:\n\n.. code:: shell-session\n\n   $ boxpy create --version 20.04 myvm\n\nnote, that Ubuntu is default distribution you don't need to specify\n``--distro`` nor ``--version`` it will pick up latest LTS version. Now, let's\nrecreate it with 22.04:\n\n.. code:: shell-session\n\n   $ boxpy rebuild --version 22.04 myvm\n\nor recreate it with Fedora and add additional CPU:\n\n.. code:: shell-session\n\n   $ boxpy rebuild --distro fedora --version 39 --cpu 2 myvm\n\nnow, let's connect to the VM using either ssh command, which is printed out at\nas last ``boxpy`` output line, or simply by using ssh boxpy command:\n\n.. code:: shell-session\n\n   $ boxpy ssh myvm\n\nFor your convenience there is a bash completion for each command, so you can\nuse it ad-hoc, or place on your ``.bashrc`` or whatever:\n\n.. code:: shell-session\n\n   $ source \u003c(boxpy completion bash)\n\nCurrently, following commands are available:\n\n- ``completion`` - as described above\n- ``create`` - create new VM\n- ``destroy`` - that is probably obvious one\n- ``info`` - to get summary about VM\n- ``list`` - for quickly listing all/running VMs\n- ``rebuild`` - recreate specified VM\n- ``ssh`` - connect to the VM using ssh\n- ``start`` - stop the running VM\n- ``stop`` - start stopped VM\n\nAll of the commands have a range of options, and can be examined by using\n``--help`` option.\n\n\nYAML Configuration\n------------------\n\nWhat is more interesting though, is the fact, that you can pass your own\n`cloud-init`_ yaml file, so that VM can be provisioned in easy way.\n\nDefault user-script looks as follows:\n\n.. code:: yaml\n\n   users:\n     - default\n     - name: ubuntu\n       ssh_authorized_keys:\n         - $ssh_key\n       chpasswd: { expire: False }\n       gecos: ubuntu\n       sudo: ALL=(ALL) NOPASSWD:ALL\n       groups: users, admin\n\nIt is really simple, and use ``string.Template`` for exchanging token\n``$ssh_key`` with default, or provided public key, so that you will be able to\nlog in into the VM using that key.\n\nNote, that you need to be extra careful regarding ``$`` sign. As explained\nabove ``$ssh_key`` will be used as a \"variable\" for the template to substitute\nwith the real value of public key. Every ``$`` sign, especially in\n``write_files.contents``, should be escaped with another dollar, so the ``$``\nwill become a ``$$``. Perhaps I'll change the approach for writing ssh key,\nsince that's a little bit annoying.\n\nFor that reason, a little improvement has been done, so now its possible to\npass filenames to the custom config, instead of filling up\n``write_files.contents``:\n\n.. code:: yaml\n\n   write_files:\n     - path: /opt/somefile.txt\n       permissions: '0644'\n       filename: /path/to/local/file.txt\n\nor\n\n.. code:: yaml\n\n   write_files:\n     - path: /opt/somefile.txt\n       permissions: '0644'\n       url: https://some.url/content\n\nduring processing this file, boxpy will look for ``filename`` or ``url`` keys\nin the yaml file for the ``write_files`` sections, and it will remove that key,\nread the file and put its contents under ``content`` key. What is more\nimportant, that will be done after template processing, so there will be no\ninterference for possible ``$`` characters.\n\nWhat is more interesting is the fact, that you could use whatever cloud-init\naccepts, and a special section, for keeping configuration, so that you don't\nneed to provide all the option every time you boot up similar VM. For example:\n\n.. code:: yaml\n\n   packages:\n     - jq\n     - silversearcher-ag\n     - tmux\n     - vim-nox\n   runcmd:\n     - [su, -, ubuntu, -c, \"echo 'set nocompatible' \u003e .vimrc\"]\n   boxpy_data:\n     key: vm\n     cpus: 4\n     memory: 4GB\n     disk_size: 20GB\n\nContents of the user script will be merged with the default one, so expect,\nthat user ``ubuntu`` will be there, and magically you'll be able to connect to\nthe machine using ssh.\n\nProviding file with this content using ``--cloud-config``, will build a VM with\n4 CPUs, 4GB of RAM, expand Ubuntu-server image to 20GB (it'll be dynamically\nallocated VDI image, so it will not swallow all 20 gigs of space) and pass the\n``vm`` ssh key, which will be looked in ``~/.ssh`` directory, if path to the\nkey is not provided.\n\nMoreover, there will be some tools installed and simple vim config\ninitialized, just to make you an idea, what could be done with it.\n\nYou can find some real world examples of the yaml cloud-init files that I use\nin examples directory.\n\nThere is special section ``boxpy_data``, where you can place all the\nconfiguration for the VM. Keys are the same as in ``create`` command options.\nThere is one additional key ``advanced`` which for now can be used for\nconfiguration additional NIC for virtual machine, i.e:\n\n.. code:: yaml\n\n   …\n   boxpy_data:\n     advanced:\n       nic2: intnet\n\nTo select image from local file system, it is possible to set one by providing\nit under ``boxpy_data.image`` key:\n\n.. code:: yaml\n\n   …\n   boxpy_data:\n     image: /path/to/the/qcow2/image\n     default_user: cloud-user\n\nNote, that default_user is also needed to be provided, as there is no guess,\nwhat is the default username for cloud-init configured within provided image.\n\n\nLicense\n-------\n\nThis work is licensed under GPL-3.\n\n\n.. _pyyaml: https://github.com/yaml/pyyaml\n.. _cloud-init: https://cloudinit.readthedocs.io\n.. _requests: https://docs.python-requests.org\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgryf%2Fboxpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgryf%2Fboxpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgryf%2Fboxpy/lists"}