├── .devcontainer └── devcontainer.json ├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── project_backlog.yml ├── PULL_REQUEST_TEMPLATE.md ├── actionlint.yaml ├── dependabot.yml └── workflows │ ├── actionlint.yaml │ ├── build.yaml │ ├── buildenvs.yaml │ ├── check-pr.yaml │ ├── check-static.yaml │ ├── chore-expire-action-caches.yml │ ├── myself-full.yaml │ ├── notarization.yaml │ ├── release-stable.yaml │ ├── release-staging.yaml │ ├── tests.yaml │ ├── tools-dockerfile-llb-frontend.yaml │ ├── tools-go-generate-qemu-device.yaml │ ├── tools-protoc-gen-go-netconn.yaml │ └── tools-webinstall.yaml ├── .gitignore ├── .golangci.yaml ├── .goreleaser-stable.yaml ├── .goreleaser-staging.yaml ├── .vscode ├── extensions.json └── settings.json ├── LICENSE.md ├── Makefile ├── README.md ├── action.yml ├── api ├── api.go ├── compose │ └── v1 │ │ └── compose.zip.go ├── machine │ ├── machine.go │ └── v1alpha1 │ │ ├── machine.zip.go │ │ ├── port.go │ │ └── register.go ├── network │ ├── network.go │ └── v1alpha1 │ │ ├── interface.zip.go │ │ ├── network.zip.go │ │ └── register.go └── volume │ ├── v1alpha1 │ ├── register.go │ └── volume.zip.go │ └── volume.go ├── archive ├── archive.go ├── archive_options.go ├── options.go └── unarchive.go ├── buf.gen.machine.yaml ├── buildenvs ├── Makefile ├── base-golang.Dockerfile ├── base.Dockerfile ├── devcontainer.Dockerfile ├── github-action.Dockerfile ├── myself.Dockerfile ├── qemu.Dockerfile └── xen.Dockerfile ├── cmd ├── kraft │ └── main.go └── runu │ ├── init.go │ └── main.go ├── cmdfactory ├── args.go ├── builder.go ├── builder_test.go ├── errors.go ├── flags.go ├── flags_bool.go ├── flags_enum.go ├── flags_int.go ├── flags_string.go ├── flags_string_array.go └── help.go ├── compose ├── project.go └── v1.go ├── config ├── config.go ├── config_file.go ├── context.go ├── defaults.go ├── feeder.go ├── feeder_yaml.go ├── kraftcloud.go └── manager.go ├── cpio ├── LICENSE ├── doc.go ├── example_test.go ├── fileinfo.go ├── hash.go ├── header.go ├── reader.go ├── svr4.go ├── svr4_test.go ├── testdata │ ├── Makefile │ ├── checklist.txt │ ├── etc │ │ └── hosts │ ├── gophers.txt │ ├── readme.txt │ ├── test_odc.cpio │ ├── test_svr4.cpio │ ├── test_svr4_crc.cpio │ └── todo.txt ├── writer.go └── writer_test.go ├── docs └── demo.gif ├── exec ├── executable.go ├── options.go ├── process.go ├── process_darwin.go ├── process_freebsd.go ├── process_linux.go ├── process_netbsd.go ├── process_openbsd.go ├── process_windows.go └── sequential.go ├── go.mod ├── go.sum ├── hack └── tools.go ├── initrd ├── detect.go ├── directory.go ├── directory_test.go ├── doc.go ├── dockerfile.go ├── dockerfile_test.go ├── file.go ├── initrd.go ├── initrd_test.go ├── ociimage.go ├── ociimage_netbsd.go ├── ociimage_openbsd.go ├── ociimage_test.go ├── options.go ├── tarball.go ├── tarball_test.go ├── testdata │ ├── rootfs.Dockerfile │ └── rootfs.tar.gz ├── utils.go ├── utils_unix.go └── utils_windows.go ├── internal ├── bootstrap │ └── init.go ├── cli │ ├── kraft │ │ ├── build │ │ │ ├── build.go │ │ │ ├── builder.go │ │ │ ├── builder_dockerfile.go │ │ │ ├── builder_kraftfile_runtime.go │ │ │ ├── builder_kraftfile_unikraft.go │ │ │ └── utils.go │ │ ├── clean │ │ │ └── clean.go │ │ ├── cloud │ │ │ ├── certificate │ │ │ │ ├── certificate.go │ │ │ │ ├── create │ │ │ │ │ └── create.go │ │ │ │ ├── get │ │ │ │ │ └── get.go │ │ │ │ ├── list │ │ │ │ │ └── list.go │ │ │ │ └── remove │ │ │ │ │ └── remove.go │ │ │ ├── cloud.go │ │ │ ├── compose │ │ │ │ ├── build │ │ │ │ │ └── build.go │ │ │ │ ├── compose.go │ │ │ │ ├── create │ │ │ │ │ └── create.go │ │ │ │ ├── down │ │ │ │ │ └── down.go │ │ │ │ ├── list │ │ │ │ │ └── list.go │ │ │ │ ├── logs │ │ │ │ │ └── logs.go │ │ │ │ ├── ps │ │ │ │ │ └── ps.go │ │ │ │ ├── push │ │ │ │ │ └── push.go │ │ │ │ ├── start │ │ │ │ │ └── start.go │ │ │ │ ├── stop │ │ │ │ │ └── stop.go │ │ │ │ └── up │ │ │ │ │ └── up.go │ │ │ ├── deploy │ │ │ │ ├── deploy.go │ │ │ │ ├── deployer.go │ │ │ │ ├── deployer_image_name.go │ │ │ │ ├── deployer_kraftfile_runtime.go │ │ │ │ ├── deployer_kraftfile_unikraft.go │ │ │ │ ├── deployer_rootfs.go │ │ │ │ └── utils.go │ │ │ ├── image │ │ │ │ ├── image.go │ │ │ │ ├── list │ │ │ │ │ └── list.go │ │ │ │ └── remove │ │ │ │ │ └── remove.go │ │ │ ├── instance │ │ │ │ ├── create │ │ │ │ │ ├── create.go │ │ │ │ │ ├── rollout_qualifier.go │ │ │ │ │ └── rollout_strategy.go │ │ │ │ ├── get │ │ │ │ │ └── get.go │ │ │ │ ├── instance.go │ │ │ │ ├── list │ │ │ │ │ └── list.go │ │ │ │ ├── logs │ │ │ │ │ └── logs.go │ │ │ │ ├── remove │ │ │ │ │ └── remove.go │ │ │ │ ├── restart │ │ │ │ │ └── restart.go │ │ │ │ ├── start │ │ │ │ │ └── start.go │ │ │ │ ├── stop │ │ │ │ │ └── stop.go │ │ │ │ └── template │ │ │ │ │ ├── create │ │ │ │ │ └── create.go │ │ │ │ │ ├── get │ │ │ │ │ └── get.go │ │ │ │ │ ├── list │ │ │ │ │ └── list.go │ │ │ │ │ ├── remove │ │ │ │ │ └── remove.go │ │ │ │ │ └── template.go │ │ │ ├── metro │ │ │ │ ├── list │ │ │ │ │ └── list.go │ │ │ │ └── metro.go │ │ │ ├── quota │ │ │ │ └── quota.go │ │ │ ├── scale │ │ │ │ ├── add │ │ │ │ │ └── add.go │ │ │ │ ├── get │ │ │ │ │ └── get.go │ │ │ │ ├── initialize │ │ │ │ │ └── initialize.go │ │ │ │ ├── remove │ │ │ │ │ └── remove.go │ │ │ │ ├── reset │ │ │ │ │ └── reset.go │ │ │ │ └── scale.go │ │ │ ├── service │ │ │ │ ├── create │ │ │ │ │ └── create.go │ │ │ │ ├── drain │ │ │ │ │ └── drain.go │ │ │ │ ├── get │ │ │ │ │ └── get.go │ │ │ │ ├── list │ │ │ │ │ └── list.go │ │ │ │ ├── logs │ │ │ │ │ └── logs.go │ │ │ │ ├── remove │ │ │ │ │ └── remove.go │ │ │ │ └── service.go │ │ │ ├── tunnel │ │ │ │ ├── relay.go │ │ │ │ └── tunnel.go │ │ │ ├── utils │ │ │ │ ├── is_uuid.go │ │ │ │ ├── populate_flags.go │ │ │ │ ├── print.go │ │ │ │ └── rand.go │ │ │ └── volume │ │ │ │ ├── attach │ │ │ │ └── attach.go │ │ │ │ ├── create │ │ │ │ └── create.go │ │ │ │ ├── detach │ │ │ │ └── detach.go │ │ │ │ ├── get │ │ │ │ └── get.go │ │ │ │ ├── import │ │ │ │ ├── cpio.go │ │ │ │ ├── errors.go │ │ │ │ ├── errors_test.go │ │ │ │ ├── import.go │ │ │ │ └── volimport.go │ │ │ │ ├── list │ │ │ │ └── list.go │ │ │ │ ├── remove │ │ │ │ └── remove.go │ │ │ │ ├── template │ │ │ │ ├── create │ │ │ │ │ └── create.go │ │ │ │ ├── get │ │ │ │ │ └── get.go │ │ │ │ ├── list │ │ │ │ │ └── list.go │ │ │ │ ├── remove │ │ │ │ │ └── remove.go │ │ │ │ └── template.go │ │ │ │ └── volume.go │ │ ├── compose │ │ │ ├── build │ │ │ │ └── build.go │ │ │ ├── compose.go │ │ │ ├── create │ │ │ │ └── create.go │ │ │ ├── down │ │ │ │ └── down.go │ │ │ ├── logs │ │ │ │ └── logs.go │ │ │ ├── ls │ │ │ │ └── ls.go │ │ │ ├── pause │ │ │ │ └── pause.go │ │ │ ├── ps │ │ │ │ └── ps.go │ │ │ ├── pull │ │ │ │ └── pull.go │ │ │ ├── push │ │ │ │ └── push.go │ │ │ ├── start │ │ │ │ └── start.go │ │ │ ├── stop │ │ │ │ └── stop.go │ │ │ ├── unpause │ │ │ │ └── unpause.go │ │ │ ├── up │ │ │ │ └── up.go │ │ │ └── utils │ │ │ │ └── utils.go │ │ ├── events │ │ │ └── events.go │ │ ├── fetch │ │ │ └── fetch.go │ │ ├── kraft.go │ │ ├── lib │ │ │ ├── add │ │ │ │ └── add.go │ │ │ ├── create │ │ │ │ └── create.go │ │ │ ├── lib.go │ │ │ └── remove │ │ │ │ └── remove.go │ │ ├── login │ │ │ └── login.go │ │ ├── logs │ │ │ ├── colorful_consumer.go │ │ │ └── logs.go │ │ ├── menu │ │ │ └── menu.go │ │ ├── net │ │ │ ├── create │ │ │ │ └── create.go │ │ │ ├── down │ │ │ │ └── down.go │ │ │ ├── inspect │ │ │ │ └── inspect.go │ │ │ ├── list │ │ │ │ └── list.go │ │ │ ├── net.go │ │ │ ├── remove │ │ │ │ └── remove.go │ │ │ └── up │ │ │ │ └── up.go │ │ ├── pause │ │ │ └── pause.go │ │ ├── pkg │ │ │ ├── info │ │ │ │ └── info.go │ │ │ ├── list │ │ │ │ └── list.go │ │ │ ├── packager.go │ │ │ ├── packager_cli_kernel.go │ │ │ ├── packager_dockerfile.go │ │ │ ├── packager_kraftfile_runtime.go │ │ │ ├── packager_kraftfile_unikraft.go │ │ │ ├── pkg.go │ │ │ ├── pull │ │ │ │ └── pull.go │ │ │ ├── push │ │ │ │ └── push.go │ │ │ ├── remove │ │ │ │ └── remove.go │ │ │ ├── source │ │ │ │ └── source.go │ │ │ ├── unsource │ │ │ │ └── unsource.go │ │ │ ├── update │ │ │ │ └── update.go │ │ │ ├── utils.go │ │ │ └── utils │ │ │ │ └── print.go │ │ ├── ps │ │ │ └── ps.go │ │ ├── remove │ │ │ └── remove.go │ │ ├── run │ │ │ ├── run.go │ │ │ ├── runner.go │ │ │ ├── runner_kernel.go │ │ │ ├── runner_kraftfile_runtime.go │ │ │ ├── runner_kraftfile_unikraft.go │ │ │ ├── runner_linuxu.go │ │ │ ├── runner_package.go │ │ │ └── utils.go │ │ ├── set │ │ │ └── set.go │ │ ├── start │ │ │ └── start.go │ │ ├── stop │ │ │ └── stop.go │ │ ├── system │ │ │ ├── set │ │ │ │ └── set.go │ │ │ └── system.go │ │ ├── unset │ │ │ └── unset.go │ │ ├── utils │ │ │ ├── kraftcloud.go │ │ │ ├── ports.go │ │ │ └── rootfs.go │ │ ├── version │ │ │ └── version.go │ │ ├── volume │ │ │ ├── create │ │ │ │ └── create.go │ │ │ ├── inspect │ │ │ │ └── inspect.go │ │ │ ├── list │ │ │ │ └── list.go │ │ │ ├── remove │ │ │ │ └── remove.go │ │ │ └── volume.go │ │ └── x │ │ │ ├── exp.go │ │ │ └── probe │ │ │ └── probe.go │ ├── options.go │ └── runu │ │ ├── create │ │ └── create.go │ │ ├── delete │ │ └── delete.go │ │ ├── kill │ │ └── kill.go │ │ ├── ps │ │ └── ps.go │ │ ├── runu.go │ │ ├── start │ │ └── start.go │ │ └── state │ │ └── state.go ├── errs │ ├── defs.go │ └── exits.go ├── fancymap │ └── print.go ├── filelock │ ├── filelock.go │ ├── filelock_fcntl.go │ ├── filelock_other.go │ ├── filelock_test.go │ ├── filelock_unix.go │ └── filelock_windows.go ├── findsh │ ├── find.go │ └── find_windows.go ├── ghrepo │ └── repo.go ├── httpclient │ ├── cache.go │ └── httpclient.go ├── httpunix │ └── transport.go ├── lockedfile │ ├── lockedfile.go │ ├── lockedfile_filelock.go │ ├── lockedfile_plan9.go │ ├── lockedfile_test.go │ ├── mutex.go │ └── transform_test.go ├── logtail │ └── logtail.go ├── rainbowprint │ └── colors.go ├── retrytimeout │ └── retrytimeout.go ├── run │ ├── run.go │ ├── stub.go │ └── utils.go ├── set │ └── string_set.go ├── tableprinter │ ├── column.go │ ├── render_json.go │ ├── render_list.go │ ├── render_table.go │ ├── render_yaml.go │ ├── tableprinter.go │ ├── tableprinter_options.go │ └── tableprinter_test.go ├── text │ ├── indent.go │ ├── indent_test.go │ ├── sanitize.go │ ├── sanitize_test.go │ ├── truncate.go │ └── truncate_test.go ├── update │ └── update.go ├── version │ └── version.go ├── waitgroup │ ├── doc.go │ └── waitgroup.go └── yamlmerger │ └── yamlmerger.go ├── iostreams ├── color.go ├── color_test.go ├── context.go ├── epipe_other.go ├── epipe_windows.go └── iostreams.go ├── kconfig ├── config.go ├── expr.go ├── kconfig.go └── parser.go ├── libmocktainer ├── README.md ├── configs │ ├── config.go │ ├── namespaces.go │ ├── namespaces_linux.go │ ├── namespaces_syscall.go │ ├── network.go │ └── validate │ │ └── validator.go ├── container.go ├── container_linux.go ├── error.go ├── factory_linux.go ├── init_linux.go ├── message_linux.go ├── network_linux.go ├── process.go ├── process_linux.go ├── restored_process.go ├── rootfs_linux.go ├── specconv │ └── spec_linux.go ├── standard_init_linux.go ├── state_linux.go ├── sync.go ├── unikraft │ ├── doc.go │ └── net_qemu.go └── utils │ └── cmsg.go ├── log ├── context.go ├── formatter.go ├── levels.go ├── logger.go └── type.go ├── machine ├── firecracker │ ├── config.go │ ├── execconfig.go │ ├── init.go │ ├── v1alpha1.go │ └── v1alpha1_options.go ├── name │ ├── id.go │ └── name.go ├── network │ ├── bridge │ │ ├── bridge.go │ │ ├── utils.go │ │ └── v1alpha1.go │ ├── iputils │ │ └── iputils.go │ ├── iterator_v1alpha1.go │ ├── macaddr │ │ └── macaddr.go │ ├── pool.go │ ├── register_darwin.go │ ├── register_freebsd.go │ ├── register_linux.go │ ├── register_netbsd.go │ ├── register_openbsd.go │ ├── register_windows.go │ ├── service.go │ └── utils.go ├── platform │ ├── detect.go │ ├── detect_windows.go │ ├── filter.go │ ├── iterator_v1alpha1.go │ ├── platform.go │ ├── register_darwin.go │ ├── register_freebsd.go │ ├── register_linux.go │ ├── register_netbsd.go │ ├── register_openbsd.go │ ├── register_unix.go │ ├── register_windows.go │ └── strategy.go ├── qemu │ ├── buf.lock │ ├── buf.yaml │ ├── config.go │ ├── init.go │ ├── qemu_chardev.go │ ├── qemu_cpus.go │ ├── qemu_devices.go │ ├── qemu_displays.go │ ├── qemu_fsdev.go │ ├── qemu_hostchardev.go │ ├── qemu_machine.go │ ├── qemu_memory.go │ ├── qemu_netdev.go │ ├── qemu_rtc.go │ ├── qemu_smp.go │ ├── qemu_system.go │ ├── qemu_version.go │ ├── qemu_vga.go │ ├── qmp │ │ ├── events.go │ │ └── v7alpha2 │ │ │ ├── control.pb.netconn.go │ │ │ ├── control.proto │ │ │ ├── descriptor.proto │ │ │ ├── error.pb.netconn.go │ │ │ ├── error.proto │ │ │ ├── event.pb.netconn.go │ │ │ ├── event.proto │ │ │ ├── greeting.pb.netconn.go │ │ │ ├── greeting.proto │ │ │ ├── machine.pb.netconn.go │ │ │ ├── machine.proto │ │ │ ├── misc.pb.netconn.go │ │ │ ├── misc.proto │ │ │ ├── net.pb.netconn.go │ │ │ ├── net.proto │ │ │ ├── run_state.pb.netconn.go │ │ │ ├── run_state.proto │ │ │ ├── service.pb.netconn.go │ │ │ ├── service.proto │ │ │ ├── sockets.pb.netconn.go │ │ │ └── sockets.proto │ ├── v1alpha1.go │ └── v1alpha1_options.go ├── volume │ ├── 9pfs │ │ └── v1alpha1.go │ ├── iterator_v1alpha1.go │ ├── register_unix.go │ └── strategy.go └── xen │ ├── README.md │ ├── init.go │ ├── stub.go │ ├── v1alpha1.go │ └── xenstore_client.go ├── make ├── make.go ├── options.go ├── progress.go └── value.go ├── manifest ├── channel.go ├── init.go ├── manager.go ├── manager_options.go ├── manifest.go ├── manifest_options.go ├── pack.go ├── pack_pull_archive.go ├── pack_pull_git.go ├── provider.go ├── provider_directory.go ├── provider_git.go ├── provider_github.go ├── provider_index.go ├── provider_manifest.go ├── provider_tarball.go └── version.go ├── oci ├── README.md ├── annotations.go ├── blob.go ├── blob_options.go ├── cache │ ├── image.go │ └── index.go ├── compatible.go ├── google_go_containerregistry.go ├── handler │ ├── containerd.go │ ├── containerd_netbsd.go │ ├── containerd_openbsd.go │ ├── directory.go │ ├── directory_image.go │ ├── handler.go │ └── jobs.go ├── index.go ├── init.go ├── layer.go ├── layer_options.go ├── manager.go ├── manager_options.go ├── manifest.go ├── mediatypes.go ├── oci.go ├── pack.go ├── simpleauth │ └── simpleauth.go ├── utils │ ├── platform.go │ └── tarball.go └── wellknown.go ├── pack ├── context.go ├── package.go ├── pull_options.go └── push_option.go ├── packmanager ├── context.go ├── manager.go ├── pack_options.go ├── query.go ├── strategy.go ├── umbrella.go └── unpack_options.go ├── schema ├── schema.go ├── v0.5.json └── v0.6.json ├── scripts └── kraftld ├── store └── embedded.go ├── test └── e2e │ ├── cli │ ├── cli_suite_test.go │ ├── net_create_test.go │ ├── net_down_test.go │ ├── net_inspect_test.go │ ├── net_ls_test.go │ ├── net_rm_test.go │ ├── net_up_test.go │ ├── pkg_source_test.go │ ├── pkg_unsource_test.go │ ├── pkg_update_test.go │ └── version_test.go │ ├── cloud │ ├── cloud_suite_test.go │ ├── img_list_test.go │ └── instance_create_test.go │ └── framework │ ├── cmd │ └── cmd.go │ ├── config │ ├── config.go │ ├── config_suite_test.go │ └── config_test.go │ └── matchers │ ├── be_empty_dir.go │ ├── be_empty_dir_test.go │ ├── contain_dirs.go │ ├── contain_dirs_test.go │ ├── contain_files.go │ ├── contain_files_test.go │ └── matchers.go ├── tools ├── dockerfile-llb-frontend │ ├── .dockerignore │ ├── Dockerfile │ ├── README.md │ ├── build │ │ ├── build.go │ │ ├── build_test.go │ │ └── mocks │ │ │ └── Client.go │ ├── go.mod │ ├── go.sum │ ├── image │ │ └── image.go │ ├── main.go │ └── test │ │ ├── buildkit │ │ └── buildkit_test.go │ │ ├── docker │ │ └── docker_test.go │ │ └── e2e_util.go ├── gendocs │ └── main.go ├── genman │ └── main.go ├── github-action │ ├── build.go │ ├── execute.go │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── pack.go │ └── pull.go ├── go-generate-qemu-devices │ ├── devices.gotmpl │ ├── go.mod │ ├── go.sum │ └── main.go ├── protoc-gen-go-netconn │ ├── apply.go │ ├── go.mod │ ├── go.sum │ └── main.go └── webinstall │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ ├── install.sh │ └── main.go ├── tui ├── confirm │ └── confirm.go ├── multiselect │ └── multiselect.go ├── paraprogress │ ├── options.go │ ├── paraprogress.go │ └── process.go ├── processtree │ ├── options.go │ ├── processtree.go │ ├── update.go │ └── view.go ├── selection │ └── select.go ├── textinput │ └── text.go └── tui.go ├── unikraft ├── app │ ├── application.go │ ├── application_options.go │ ├── build_options.go │ ├── kernel.go │ ├── loader.go │ ├── normalize.go │ ├── project.go │ ├── project_options.go │ ├── transform.go │ └── volume │ │ ├── transform.go │ │ └── volumes.go ├── arch │ ├── architecture.go │ ├── host.go │ ├── options.go │ └── transform.go ├── component │ ├── component.go │ └── extensions.go ├── context.go ├── core │ ├── args.go │ ├── core.go │ ├── options.go │ └── transform.go ├── export │ ├── README.md │ └── v0 │ │ ├── posixenviron │ │ ├── library.go │ │ └── params.go │ │ ├── ukargparse │ │ ├── params.go │ │ ├── params_strmap.go │ │ ├── params_strslice.go │ │ └── parse.go │ │ ├── uknetdev │ │ ├── library.go │ │ └── params.go │ │ ├── ukrandom │ │ ├── library.go │ │ └── params.go │ │ └── vfscore │ │ ├── library.go │ │ └── params.go ├── lib │ ├── library.go │ ├── match.go │ ├── options.go │ ├── template │ │ ├── CODING_STYLE.md.tmpl │ │ ├── CONTRIBUTING.md.tmpl │ │ ├── COPYING.md.tmpl │ │ ├── Config.uk.tmpl │ │ ├── Makefile.uk.tmpl │ │ ├── README.md.tmpl │ │ ├── main.c.tmpl │ │ ├── options.go │ │ └── template.go │ └── transform.go ├── plat │ ├── options.go │ ├── platform.go │ └── transform.go ├── runtime │ ├── runtime.go │ ├── runtime_options.go │ ├── runtime_pack.go │ └── transform.go ├── syscall.go ├── target │ ├── command.go │ ├── env.go │ ├── options.go │ ├── select.go │ ├── target.go │ └── transform.go ├── template │ ├── options.go │ ├── template.go │ └── transform.go ├── type.go ├── unikraft.go └── utils.go └── utils ├── comparable_stringer.go ├── terminal.go ├── utils.go └── utils_test.go /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Kraftkit development environment", 3 | "build": { "dockerfile": "../buildenvs/devcontainer.Dockerfile" }, 4 | "remoteUser": "root", 5 | "hostRequirements": { 6 | "cpus": 2, 7 | "memory": "8gb", 8 | "storage": "32gb" 9 | }, 10 | "customizations": { 11 | "vscode": { 12 | "extensions": [ 13 | "golang.go", 14 | "Gruntfuggly.todo-tree", 15 | "shardulm94.trailing-spaces" 16 | ], 17 | "settings": { 18 | "files.eol": "\n", 19 | "editor.formatOnSave": true, 20 | "go.lintOnSave": "package", 21 | "files.insertFinalNewline": true, 22 | "go.toolsEnvVars": { 23 | "CGO_ENABLED": "0" 24 | }, 25 | "gopls": { 26 | "usePlaceholders": false, 27 | "staticcheck": true, 28 | "vulncheck": "Imports" 29 | }, 30 | "[go]": { 31 | "editor.codeActionsOnSave": { 32 | "source.organizeImports": true 33 | } 34 | }, 35 | "go.useLanguageServer": true 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org/ 2 | 3 | [*.{go,proto}] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = tab 8 | indent_size = 2 9 | 10 | # Tab indentation (no size specified) 11 | [Makefile] 12 | indent_style = tab 13 | 14 | # Track the line length of commit messages 15 | [.git/**] 16 | max_line_length = 75 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | machine/qemu/qemu_devices.go linguist-generated=true 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # General maintainers if nothing else matches 2 | * @nderjung @craciunoiuc 3 | 4 | # Maintainers for specific file types 5 | *.yml @nderjung @craciunoiuc 6 | *.yaml @nderjung @craciunoiuc 7 | 8 | # Maintainers for tools and other non-core files 9 | tools/webinstall @nderjung @craciunoiuc 10 | tools/gendocs @nderjung @craciunoiuc 11 | tools/genman @nderjung @craciunoiuc 12 | 13 | # Maintainers for specific file paths 14 | machine/xen @nderjung @andreistan26 @craciunoiuc 15 | internal/cli/kraft/compose @LucaSeri @nderjung 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | contact_links: 4 | - name: 💡 Discuss an idea 5 | url: https://github.com/unikraft/unikraft/discussions/new 6 | about: Discuss a feature or usecase which Kraftkit could support. 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 13 | 14 | ### Prerequisite checklist 15 | 16 | 19 | 20 | - [ ] Read the [contribution guidelines](https://unikraft.org/docs/contributing/) regarding submitting new changes to the project; 21 | - [ ] Tested your changes against relevant architectures and platforms; 22 | - [ ] Ran `make fmt` on your commit series before opening this PR; 23 | - [ ] Updated relevant documentation. 24 | 25 | ### Description of changes 26 | 27 | 30 | -------------------------------------------------------------------------------- /.github/actionlint.yaml: -------------------------------------------------------------------------------- 1 | self-hosted-runner: 2 | labels: 3 | - mac-m2-14 4 | config-variables: null 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | 5 | - package-ecosystem: gomod 6 | directory: / 7 | target-branch: staging 8 | schedule: 9 | interval: weekly 10 | day: sunday 11 | time: '09:00' 12 | commit-message: 13 | prefix: gomod # Prefix messages with 14 | include: scope # List all updated dependencies 15 | - package-ecosystem: gomod 16 | directory: /tools/go-generate-qemu-devices 17 | target-branch: staging 18 | schedule: 19 | interval: weekly 20 | day: sunday 21 | time: '09:00' 22 | commit-message: 23 | prefix: gomod # Prefix messages with 24 | include: scope # List all updated dependencies 25 | - package-ecosystem: gomod 26 | directory: /tools/protoc-gen-go-netconn 27 | target-branch: staging 28 | schedule: 29 | interval: weekly 30 | day: sunday 31 | time: '09:00' 32 | commit-message: 33 | prefix: gomod # Prefix messages with 34 | include: scope # List all updated dependencies 35 | 36 | - package-ecosystem: github-actions 37 | directory: / 38 | schedule: 39 | interval: weekly 40 | day: sunday 41 | time: '09:00' 42 | -------------------------------------------------------------------------------- /.github/workflows/actionlint.yaml: -------------------------------------------------------------------------------- 1 | name: actionlint 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, reopened] 6 | branches: [staging] 7 | paths: 8 | - '.github/workflows/**' 9 | 10 | jobs: 11 | actionlint: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Install action linter 17 | run: | 18 | mkdir -p "$HOME"/.local/bin 19 | curl -sL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash | bash -s -- latest "$HOME"/.local/bin 20 | 21 | - name: Check that all workflows are valid 22 | run: actionlint -verbose 23 | -------------------------------------------------------------------------------- /.github/workflows/release-staging.yaml: -------------------------------------------------------------------------------- 1 | name: release/staging 2 | 3 | on: 4 | push: 5 | branches: [staging] 6 | 7 | permissions: 8 | contents: write 9 | packages: write 10 | 11 | jobs: 12 | goreleaser: 13 | runs-on: ubuntu-latest 14 | container: kraftkit.sh/myself-full:latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | submodules: recursive 21 | 22 | - name: Fetch all tags 23 | run: | 24 | git config --global --add safe.directory /__w/kraftkit/kraftkit 25 | git fetch --force --tags 26 | 27 | - name: Generate GoReleaser configuration 28 | run: | 29 | ytt -f .goreleaser-staging.yaml > goreleaser-staging.yaml 30 | 31 | - name: Run GoReleaser 32 | run: | 33 | git tag -d "$(git describe)" || true 34 | git config user.name "Unikraft Bot" 35 | git config user.email "monkey@unikraft.io" 36 | git tag -a "$(git describe)" -m "Pre-release: $(git describe)" 37 | echo "$GOOGLE_APPLICATION_JSON" > /tmp/gs.json 38 | goreleaser build \ 39 | --config goreleaser-staging.yaml \ 40 | --skip=validate 41 | goreleaser release \ 42 | --config goreleaser-staging.yaml \ 43 | --clean \ 44 | --skip=validate 45 | env: 46 | GITHUB_TOKEN: ${{ secrets.GH_PAT }} 47 | SENTRY_DSN: ${{ secrets.SENTRY_DSN }} 48 | -------------------------------------------------------------------------------- /.github/workflows/tools-dockerfile-llb-frontend.yaml: -------------------------------------------------------------------------------- 1 | name: tools/dockerfile-llb-frontend 2 | 3 | on: 4 | push: 5 | branches: [stable] 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | branches: [staging] 9 | paths: 10 | - 'tools/dockerfile-llb-frontend/**' 11 | - '.github/workflows/dockerfile-llb-frontend.yaml' 12 | 13 | jobs: 14 | plugin-push: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v4 19 | 20 | - name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v3 22 | 23 | - name: Login to Registry 24 | if: ${{ github.event_name == 'push' }} 25 | uses: docker/login-action@v3 26 | with: 27 | registry: index.unikraft.io 28 | username: ${{ secrets.REG_USERNAME }} 29 | password: ${{ secrets.REG_TOKEN }} 30 | 31 | - name: Build OCI image for the LLB plugin 32 | uses: docker/build-push-action@v6 33 | with: 34 | context: ./tools/dockerfile-llb-frontend 35 | file: ./tools/dockerfile-llb-frontend/Dockerfile 36 | tags: index.unikraft.io/kraftkit.sh/llb:latest 37 | push: ${{ github.event_name == 'push' }} 38 | platforms: linux/amd64 39 | cache-from: type=gha 40 | cache-to: type=gha,mode=max 41 | -------------------------------------------------------------------------------- /.github/workflows/tools-webinstall.yaml: -------------------------------------------------------------------------------- 1 | name: tools/webinstall 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | myself-push: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Set up Docker Buildx 12 | uses: docker/setup-buildx-action@v3 13 | 14 | - name: Login to Registry 15 | uses: docker/login-action@v3 16 | with: 17 | registry: ghcr.io 18 | username: ${{github.actor}} 19 | password: ${{secrets.GITHUB_TOKEN}} 20 | 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 1 25 | 26 | - name: Build & Push OCI Image 27 | uses: docker/build-push-action@v6 28 | with: 29 | push: true 30 | tags: ghcr.io/unikraft/kraftkit/webinstall:latest 31 | platforms: linux/amd64 32 | context: ./tools/webinstall 33 | file: ./tools/webinstall/Dockerfile 34 | secrets: | 35 | GIT_AUTH_TOKEN=${{ secrets.GITHUB_TOKEN }} 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore distributables folder 2 | dist/ 3 | goreleaser-*.yaml 4 | 5 | # Ignore vscode folder 6 | .vscode/ 7 | !.vscode/settings.json 8 | 9 | # Ignore idea (GoLand) folder 10 | .idea/ 11 | 12 | # Ignore tool binaries 13 | tools/go-generate-qemu-devices/go-generate-qemu-devices 14 | tools/protoc-gen-go-netconn/protoc-gen-go-netconn 15 | 16 | # Ignore swap files 17 | *.swp 18 | *.swo 19 | *~ 20 | .*~ 21 | 22 | # Go workspace 23 | go.work 24 | go.work.sum 25 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | run: 3 | issues-exit-code: 2 4 | linters: 5 | default: none 6 | enable: 7 | - misspell 8 | - unparam 9 | exclusions: 10 | generated: lax 11 | presets: 12 | - comments 13 | - common-false-positives 14 | - legacy 15 | - std-error-handling 16 | paths: 17 | - tmp/ 18 | - dist/ 19 | - third_party$ 20 | - builtin$ 21 | - examples$ 22 | formatters: 23 | enable: 24 | - gofumpt 25 | exclusions: 26 | generated: lax 27 | paths: 28 | - tmp/ 29 | - dist/ 30 | - third_party$ 31 | - builtin$ 32 | - examples$ 33 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "golang.go", 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "Kraftfile": "yaml", 4 | }, 5 | "editor.rulers": [80], 6 | "editor.wordWrapColumn": 80, 7 | "go.formatTool": "goimports", 8 | "go.useLanguageServer": true, 9 | "[go]": { 10 | "editor.insertSpaces": false, 11 | "editor.formatOnSave": true, 12 | "editor.codeActionsOnSave": { 13 | "source.organizeImports": "explicit" 14 | }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Unikraft GmbH & The KraftKit Authors. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /api/api.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package api 6 | 7 | import ( 8 | "encoding/gob" 9 | 10 | zip "api.zip" 11 | "k8s.io/apimachinery/pkg/api/resource" 12 | 13 | machinev1alpha1 "kraftkit.sh/api/machine/v1alpha1" 14 | networkv1alpha1 "kraftkit.sh/api/network/v1alpha1" 15 | volumev1alpha1 "kraftkit.sh/api/volume/v1alpha1" 16 | ) 17 | 18 | func init() { 19 | gob.Register(resource.Quantity{}) 20 | } 21 | 22 | func RegisterSchemes() error { 23 | return zip.Register( 24 | machinev1alpha1.AddToScheme, 25 | networkv1alpha1.AddToScheme, 26 | volumev1alpha1.AddToScheme, 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /api/machine/machine.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package machine 6 | 7 | // GroupName is the name of the API group. 8 | var GroupName = "machine.unikraft.io" 9 | -------------------------------------------------------------------------------- /api/machine/v1alpha1/port.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package v1alpha1 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | 11 | "github.com/containerd/nerdctl/pkg/portutil" 12 | 13 | corev1 "k8s.io/api/core/v1" 14 | ) 15 | 16 | const DefaultProtocol = corev1.ProtocolTCP 17 | 18 | // ParsePort parses a string representation of a MachinePort and returns the 19 | // instantiated structure. The input structure uses nerdctl's implementation 20 | // which in itself follows the traditional "docker-like" syntax often used in a 21 | // CLI-context with the `-p` flag. 22 | func ParsePort(s string) ([]MachinePort, error) { 23 | mappings, err := portutil.ParseFlagP(s) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | ports := make([]MachinePort, len(mappings)) 29 | for i, port := range mappings { 30 | ports[i] = MachinePort{ 31 | HostIP: port.HostIP, 32 | HostPort: port.HostPort, 33 | MachinePort: port.ContainerPort, 34 | Protocol: corev1.Protocol(port.Protocol), 35 | } 36 | } 37 | 38 | return ports, nil 39 | } 40 | 41 | // String implements fmt.Stringer and outputs MachinePorts in human-readable 42 | // format. 43 | func (ports MachinePorts) String() string { 44 | strs := make([]string, len(ports)) 45 | 46 | for i, p := range ports { 47 | strs[i] = fmt.Sprintf("%s:%d->%d/%s", p.HostIP, p.HostPort, p.MachinePort, p.Protocol) 48 | } 49 | 50 | return strings.Join(strs, ", ") 51 | } 52 | -------------------------------------------------------------------------------- /api/machine/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package v1alpha1 6 | 7 | import ( 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | "k8s.io/apimachinery/pkg/runtime" 10 | "k8s.io/apimachinery/pkg/runtime/schema" 11 | 12 | "kraftkit.sh/api/machine" 13 | ) 14 | 15 | const Version = "v1alpha1" 16 | 17 | var SchemeGroupVersion = schema.GroupVersion{ 18 | Group: machine.GroupName, 19 | Version: Version, 20 | } 21 | 22 | func AddToScheme(scheme *runtime.Scheme) error { 23 | return AddToSchemeWithGV(scheme, SchemeGroupVersion) 24 | } 25 | 26 | func AddToSchemeWithGV(scheme *runtime.Scheme, schemeGroupVersion schema.GroupVersion) error { 27 | scheme.AddKnownTypes(schemeGroupVersion, 28 | &Machine{}, 29 | &MachineList{}, 30 | ) 31 | 32 | // Add common types 33 | scheme.AddKnownTypes(schemeGroupVersion, 34 | &metav1.Status{}, 35 | ) 36 | 37 | if schemeGroupVersion == SchemeGroupVersion { 38 | // Add the watch version that applies 39 | metav1.AddToGroupVersion(scheme, schemeGroupVersion) 40 | } 41 | 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /api/network/network.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package network 6 | 7 | // GroupName is the name of the API group. 8 | var GroupName = "network.unikraft.io" 9 | -------------------------------------------------------------------------------- /api/network/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package v1alpha1 6 | 7 | import ( 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | "k8s.io/apimachinery/pkg/runtime" 10 | "k8s.io/apimachinery/pkg/runtime/schema" 11 | 12 | "kraftkit.sh/api/network" 13 | ) 14 | 15 | const Version = "v1alpha1" 16 | 17 | var SchemeGroupVersion = schema.GroupVersion{ 18 | Group: network.GroupName, 19 | Version: Version, 20 | } 21 | 22 | func AddToScheme(scheme *runtime.Scheme) error { 23 | return AddToSchemeWithGV(scheme, SchemeGroupVersion) 24 | } 25 | 26 | func AddToSchemeWithGV(scheme *runtime.Scheme, schemeGroupVersion schema.GroupVersion) error { 27 | scheme.AddKnownTypes(schemeGroupVersion, 28 | &Network{}, 29 | &NetworkList{}, 30 | ) 31 | 32 | // Add common types 33 | scheme.AddKnownTypes(schemeGroupVersion, 34 | &metav1.Status{}, 35 | ) 36 | 37 | if schemeGroupVersion == SchemeGroupVersion { 38 | // Add the watch version that applies 39 | metav1.AddToGroupVersion(scheme, schemeGroupVersion) 40 | } 41 | 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /api/volume/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package v1alpha1 6 | 7 | import ( 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | "k8s.io/apimachinery/pkg/runtime" 10 | "k8s.io/apimachinery/pkg/runtime/schema" 11 | 12 | "kraftkit.sh/api/volume" 13 | ) 14 | 15 | const Version = "v1alpha1" 16 | 17 | var SchemeGroupVersion = schema.GroupVersion{ 18 | Group: volume.GroupName, 19 | Version: Version, 20 | } 21 | 22 | func AddToScheme(scheme *runtime.Scheme) error { 23 | return AddToSchemeWithGV(scheme, SchemeGroupVersion) 24 | } 25 | 26 | func AddToSchemeWithGV(scheme *runtime.Scheme, schemeGroupVersion schema.GroupVersion) error { 27 | scheme.AddKnownTypes(schemeGroupVersion, 28 | &Volume{}, 29 | &VolumeList{}, 30 | ) 31 | 32 | // Add common types 33 | scheme.AddKnownTypes(schemeGroupVersion, 34 | &metav1.Status{}, 35 | ) 36 | 37 | if schemeGroupVersion == SchemeGroupVersion { 38 | // Add the watch version that applies 39 | metav1.AddToGroupVersion(scheme, schemeGroupVersion) 40 | } 41 | 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /api/volume/volume.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package volume 6 | 7 | // GroupName is the name of the API group. 8 | var GroupName = "volume.unikraft.io" 9 | -------------------------------------------------------------------------------- /archive/archive_options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package archive 6 | 7 | type ArchiveOptions struct { 8 | stripTimes bool 9 | gzip bool 10 | } 11 | 12 | type ArchiveOption func(*ArchiveOptions) error 13 | 14 | // WithStripTimes indicates that during the archival process that any file times 15 | // should be removed. 16 | func WithStripTimes(stripTimes bool) ArchiveOption { 17 | return func(ao *ArchiveOptions) error { 18 | ao.stripTimes = stripTimes 19 | return nil 20 | } 21 | } 22 | 23 | // WithGzip indicates that when archiving occurs that the resulting artifact 24 | // should be gzip compressed. 25 | func WithGzip(gzip bool) ArchiveOption { 26 | return func(ao *ArchiveOptions) error { 27 | ao.gzip = gzip 28 | return nil 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /archive/options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package archive 6 | 7 | type UnarchiveOptions struct { 8 | stripComponents int 9 | stripIfOnlyDir bool 10 | } 11 | 12 | type UnarchiveOption func(uo *UnarchiveOptions) error 13 | 14 | func StripComponents(sc int) UnarchiveOption { 15 | return func(uo *UnarchiveOptions) error { 16 | if sc < 0 { 17 | sc = 0 18 | } 19 | 20 | uo.stripComponents = sc 21 | return nil 22 | } 23 | } 24 | 25 | // If there exists only one top-level directory, strip it. 26 | func StripIfSingleTopLevelDir() UnarchiveOption { 27 | return func(uo *UnarchiveOptions) error { 28 | uo.stripIfOnlyDir = true 29 | return nil 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /buf.gen.machine.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | managed: 3 | enabled: true 4 | go_package_prefix: 5 | default: kraftkit.sh 6 | plugins: 7 | - name: go-netconn 8 | out: . 9 | opt: 10 | - paths=source_relative 11 | - logtostderr=true 12 | - emit_empty=false 13 | - emit_any_as_generic=true 14 | - emit_message_options=true 15 | - map_enum_to_message=true 16 | - remap_enum_via_json_name=true 17 | -------------------------------------------------------------------------------- /buildenvs/base-golang.Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (c) 2022, NEC Europe Ltd., Unikraft GmbH, and The KraftKit Authors. 3 | # Licensed under the BSD-3-Clause License (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | ARG REGISTRY=kraftkit.sh 6 | ARG GO_VERSION=1.24.0 7 | 8 | FROM golang:${GO_VERSION}-bookworm AS golang 9 | FROM ${REGISTRY}/base:latest 10 | 11 | COPY --from=golang /usr/local/go /usr/local/go 12 | 13 | ENV PATH=$PATH:/usr/local/go/bin 14 | -------------------------------------------------------------------------------- /buildenvs/devcontainer.Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | # Licensed under the BSD-3-Clause License (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | FROM kraftkit.sh/base-golang:latest 6 | 7 | RUN set -xe; \ 8 | apt-get update; \ 9 | apt-get install -y --no-install-recommends \ 10 | cmake \ 11 | libssh2-1-dev \ 12 | libssl-dev \ 13 | pkg-config; \ 14 | apt-get clean; \ 15 | git config --global --add safe.directory /go/src/kraftkit.sh; 16 | 17 | WORKDIR /go/src/kraftkit.sh 18 | 19 | COPY . . 20 | 21 | ENV DOCKER= 22 | ENV GOROOT=/usr/local/go 23 | ENV KRAFTKIT_LOG_LEVEL=debug 24 | ENV KRAFTKIT_LOG_TYPE=basic 25 | ENV PAGER=cat 26 | ENV PATH=$PATH:/go/src/kraftkit.sh/dist 27 | -------------------------------------------------------------------------------- /cmd/kraft/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package main 7 | 8 | import ( 9 | "os" 10 | "path/filepath" 11 | 12 | "kraftkit.sh/internal/cli/kraft" 13 | ) 14 | 15 | func main() { 16 | // Make args[0] just the name of the executable since it is used in logs. 17 | os.Args[0] = filepath.Base(os.Args[0]) 18 | 19 | os.Exit(kraft.Main(os.Args)) 20 | } 21 | -------------------------------------------------------------------------------- /cmd/runu/init.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package main 6 | 7 | import ( 8 | "os" 9 | 10 | _ "github.com/opencontainers/runc/libcontainer/nsenter" 11 | 12 | libcontainer "kraftkit.sh/libmocktainer" 13 | ) 14 | 15 | func init() { 16 | if len(os.Args) > 1 && os.Args[1] == "init" { 17 | // This is the golang entry point for runc init, executed 18 | // before main() but after libcontainer/nsenter's nsexec(). 19 | libcontainer.Init() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cmd/runu/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package main 7 | 8 | import ( 9 | "os" 10 | "path/filepath" 11 | 12 | "kraftkit.sh/internal/cli/runu" 13 | ) 14 | 15 | func main() { 16 | // Make args[0] just the name of the executable since it is used in logs. 17 | os.Args[0] = filepath.Base(os.Args[0]) 18 | 19 | os.Exit(runu.Main(os.Args)) 20 | } 21 | -------------------------------------------------------------------------------- /cmdfactory/errors.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Copyright (c) 2019 GitHub Inc. 3 | // Copyright (c) 2022 Unikraft GmbH. 4 | package cmdfactory 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | 10 | "github.com/AlecAivazis/survey/v2/terminal" 11 | ) 12 | 13 | // FlagErrorf returns a new FlagError that wraps an error produced by 14 | // fmt.Errorf(format, args...). 15 | func FlagErrorf(format string, args ...interface{}) error { 16 | return FlagErrorWrap(fmt.Errorf(format, args...)) 17 | } 18 | 19 | // FlagError returns a new FlagError that wraps the specified error. 20 | func FlagErrorWrap(err error) error { return &FlagError{err} } 21 | 22 | // A *FlagError indicates an error processing command-line flags or other 23 | // arguments. Such errors cause the application to display the usage message. 24 | type FlagError struct { 25 | // Note: not struct{error}: only *FlagError should satisfy error. 26 | err error 27 | } 28 | 29 | func (fe *FlagError) Error() string { 30 | return fe.err.Error() 31 | } 32 | 33 | func (fe *FlagError) Unwrap() error { 34 | return fe.err 35 | } 36 | 37 | // ErrSilent is an error that triggers exit code 1 without any error messaging 38 | var ErrSilent = errors.New("ErrSilent") 39 | 40 | // ErrCancel signals user-initiated cancellation 41 | var ErrCancel = errors.New("ErrCancel") 42 | 43 | func IsUserCancellation(err error) bool { 44 | return errors.Is(err, ErrCancel) || errors.Is(err, terminal.InterruptErr) 45 | } 46 | 47 | func MutuallyExclusive(message string, conditions ...bool) error { 48 | numTrue := 0 49 | for _, ok := range conditions { 50 | if ok { 51 | numTrue++ 52 | } 53 | } 54 | if numTrue > 1 { 55 | return FlagErrorf("%s", message) 56 | } 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /cmdfactory/flags.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2012 Alex Ogier. 3 | // Copyright (c) 2012 The Go Authors. 4 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 5 | // Licensed under the BSD-3-Clause License (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | package cmdfactory 8 | 9 | import ( 10 | "github.com/spf13/pflag" 11 | ) 12 | 13 | // VarF returns and instantiated flag based on a pointer value, a name and 14 | // usage line. 15 | func VarF(value pflag.Value, name, usage string) *pflag.Flag { 16 | flag := &pflag.Flag{ 17 | Name: name, 18 | Usage: usage, 19 | Value: value, 20 | DefValue: value.String(), 21 | } 22 | 23 | return flag 24 | } 25 | 26 | // VarPF is like VarP, but returns the flag created 27 | func VarPF(value pflag.Value, name, shorthand, usage string) *pflag.Flag { 28 | flag := &pflag.Flag{ 29 | Name: name, 30 | Shorthand: shorthand, 31 | Usage: usage, 32 | Value: value, 33 | DefValue: value.String(), 34 | } 35 | 36 | return flag 37 | } 38 | -------------------------------------------------------------------------------- /cmdfactory/flags_bool.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2012 Alex Ogier. 3 | // Copyright (c) 2012 The Go Authors. 4 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 5 | // Licensed under the BSD-3-Clause License (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | package cmdfactory 8 | 9 | import ( 10 | "strconv" 11 | 12 | "github.com/spf13/pflag" 13 | ) 14 | 15 | type boolValue bool 16 | 17 | func newBoolValue(val bool, p *bool) *boolValue { 18 | *p = val 19 | return (*boolValue)(p) 20 | } 21 | 22 | func (b *boolValue) Set(val string) error { 23 | v, err := strconv.ParseBool(val) 24 | *b = boolValue(v) 25 | return err 26 | } 27 | 28 | func (b *boolValue) Type() string { 29 | return "bool" 30 | } 31 | 32 | func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) } 33 | 34 | // BoolVar returns an instantiated flag for to an associated pointer boolean 35 | // value with a given name, default value and usage line. 36 | func BoolVar(p *bool, name string, value bool, usage string) *pflag.Flag { 37 | flag := VarF(newBoolValue(value, p), name, usage) 38 | flag.NoOptDefVal = "true" 39 | return flag 40 | } 41 | 42 | // BoolVarP is like BoolVar, but accepts a shorthand letter that can be used 43 | // after a single dash. 44 | func BoolVarP(p *bool, name, shorthand string, value bool, usage string) *pflag.Flag { 45 | flag := VarPF(newBoolValue(value, p), name, shorthand, usage) 46 | flag.NoOptDefVal = "true" 47 | return flag 48 | } 49 | -------------------------------------------------------------------------------- /cmdfactory/flags_enum.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package cmdfactory 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | ) 11 | 12 | type EnumFlag[T fmt.Stringer] struct { 13 | Allowed []T 14 | Value T 15 | } 16 | 17 | // NewEnumFlag give a list of allowed flag parameters, where the second argument 18 | // is the default 19 | func NewEnumFlag[T fmt.Stringer](allowed []T, d T) *EnumFlag[T] { 20 | return &EnumFlag[T]{ 21 | Allowed: allowed, 22 | Value: d, 23 | } 24 | } 25 | 26 | func (a *EnumFlag[T]) String() string { 27 | return a.Value.String() 28 | } 29 | 30 | func (a *EnumFlag[T]) Set(p string) error { 31 | isIncluded := func(opts []T, val string) (bool, *T) { 32 | for _, opt := range opts { 33 | if val == opt.String() { 34 | return true, &opt 35 | } 36 | } 37 | 38 | return false, nil 39 | } 40 | 41 | ok, t := isIncluded(a.Allowed, p) 42 | if !ok { 43 | allowed := make([]string, len(a.Allowed)) 44 | for i := range a.Allowed { 45 | allowed[i] = a.Allowed[i].String() 46 | } 47 | return fmt.Errorf("%s is not included in: %s", p, strings.Join(allowed, ", ")) 48 | } 49 | 50 | a.Value = *t 51 | return nil 52 | } 53 | 54 | func (a *EnumFlag[T]) Type() string { 55 | return "string" 56 | } 57 | -------------------------------------------------------------------------------- /cmdfactory/flags_int.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2012 Alex Ogier. 3 | // Copyright (c) 2012 The Go Authors. 4 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 5 | // Licensed under the BSD-3-Clause License (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | package cmdfactory 8 | 9 | import ( 10 | "strconv" 11 | 12 | "github.com/spf13/pflag" 13 | ) 14 | 15 | type intValue int 16 | 17 | func newIntValue(val int, p *int) *intValue { 18 | *p = val 19 | return (*intValue)(p) 20 | } 21 | 22 | func (s *intValue) Set(val string) error { 23 | i, err := strconv.Atoi(val) 24 | if err != nil { 25 | return err 26 | } 27 | *s = intValue(i) 28 | return nil 29 | } 30 | 31 | func (s *intValue) Type() string { 32 | return "int" 33 | } 34 | 35 | func (s *intValue) String() string { 36 | return strconv.Itoa(int(*s)) 37 | } 38 | 39 | // IntVar returns an instantiated flag for to an associated pointer string 40 | // value with a given name, default value and usage line. 41 | func IntVar(p *int, name string, value int, usage string) *pflag.Flag { 42 | return VarF(newIntValue(value, p), name, usage) 43 | } 44 | 45 | // IntVarP is like IntVar, but accepts a shorthand letter that can be used 46 | // after a single dash. 47 | func IntVarP(p *int, name, shorthand string, value int, usage string) *pflag.Flag { 48 | return VarPF(newIntValue(value, p), name, shorthand, usage) 49 | } 50 | -------------------------------------------------------------------------------- /cmdfactory/flags_string.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2012 Alex Ogier. 3 | // Copyright (c) 2012 The Go Authors. 4 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 5 | // Licensed under the BSD-3-Clause License (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | package cmdfactory 8 | 9 | import ( 10 | "github.com/spf13/pflag" 11 | ) 12 | 13 | type stringValue string 14 | 15 | func newStringValue(val string, p *string) *stringValue { 16 | *p = val 17 | return (*stringValue)(p) 18 | } 19 | 20 | func (s *stringValue) Set(val string) error { 21 | *s = stringValue(val) 22 | return nil 23 | } 24 | 25 | func (s *stringValue) Type() string { 26 | return "string" 27 | } 28 | 29 | func (s *stringValue) String() string { return string(*s) } 30 | 31 | // StringVar returns an instantiated flag for to an associated pointer string 32 | // value with a given name, default value and usage line. 33 | func StringVar(p *string, name string, value string, usage string) *pflag.Flag { 34 | return VarF(newStringValue(value, p), name, usage) 35 | } 36 | 37 | // StringVarP is like StringVar, but accepts a shorthand letter that can be used 38 | // after a single dash. 39 | func StringVarP(p *string, name, shorthand string, value string, usage string) *pflag.Flag { 40 | return VarPF(newStringValue(value, p), name, shorthand, usage) 41 | } 42 | -------------------------------------------------------------------------------- /config/context.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package config 6 | 7 | import ( 8 | "context" 9 | ) 10 | 11 | // contextKey is used to retrieve the logger from the context. 12 | type contextKey struct{} 13 | 14 | // WithConfigManager returns a new context with the provided logger. Use in 15 | // combination with logger.WithField(s) for great effect. 16 | func WithConfigManager[C any](ctx context.Context, cfgm *ConfigManager[C]) context.Context { 17 | return context.WithValue(ctx, contextKey{}, cfgm) 18 | } 19 | 20 | // FromContext returns the Config Manager for kraftkit in the context, or an 21 | // inert configuration that results in default values. 22 | func M[T any](ctx context.Context) *ConfigManager[T] { 23 | l := ctx.Value(contextKey{}) 24 | 25 | if l == nil { 26 | l, _ := NewConfigManager(new(T)) 27 | return l 28 | } 29 | 30 | return l.(*ConfigManager[T]) 31 | } 32 | 33 | // ConfigFromContext returns the config for kraftkit in the context, or an inert 34 | // configuration that results in default values. 35 | func G[T any](ctx context.Context) *T { 36 | return M[T](ctx).Config 37 | } 38 | -------------------------------------------------------------------------------- /cpio/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Ryan Armstrong. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /cpio/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2017, Ryan Armstrong. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | /* 7 | Package cpio providers readers and writers for CPIO archives. Currently, only 8 | the SVR4 (New ASCII) format is supported, both with and without checksums. 9 | 10 | This package aims to be feel like Go's archive/tar package. 11 | 12 | See the CPIO man page: https://www.freebsd.org/cgi/man.cgi?query=cpio&sektion=5 13 | */ 14 | package cpio 15 | -------------------------------------------------------------------------------- /cpio/fileinfo.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2017, Ryan Armstrong. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package cpio 7 | 8 | import ( 9 | "os" 10 | "path" 11 | "time" 12 | ) 13 | 14 | // fileInfo implements fs.FileInfo. 15 | type fileInfo struct { 16 | h *Header 17 | } 18 | 19 | // Name returns the base name of the file. 20 | func (fi fileInfo) Name() string { 21 | if fi.IsDir() { 22 | return path.Base(path.Clean(fi.h.Name)) 23 | } 24 | return path.Base(fi.h.Name) 25 | } 26 | 27 | func (fi fileInfo) Size() int64 { return fi.h.Size } 28 | func (fi fileInfo) IsDir() bool { return fi.Mode().IsDir() } 29 | func (fi fileInfo) ModTime() time.Time { return fi.h.ModTime } 30 | func (fi fileInfo) Sys() interface{} { return fi.h } 31 | 32 | func (fi fileInfo) Mode() (mode os.FileMode) { 33 | mode = os.FileMode(fi.h.Mode).Perm() 34 | if fi.h.Mode&ModeSetuid != 0 { 35 | mode |= os.ModeSetuid 36 | } 37 | if fi.h.Mode&ModeSetgid != 0 { 38 | mode |= os.ModeSetgid 39 | } 40 | if fi.h.Mode&ModeSticky != 0 { 41 | mode |= os.ModeSticky 42 | } 43 | m := os.FileMode(fi.h.Mode) & ModeType 44 | if m == TypeDir { 45 | mode |= os.ModeDir 46 | } 47 | if m == TypeFifo { 48 | mode |= os.ModeNamedPipe 49 | } 50 | if m == TypeSymlink { 51 | mode |= os.ModeSymlink 52 | } 53 | if m == TypeBlock { 54 | mode |= os.ModeDevice 55 | } 56 | if m == TypeChar { 57 | mode |= os.ModeDevice | os.ModeCharDevice 58 | } 59 | if m == TypeSocket { 60 | mode |= os.ModeSocket 61 | } 62 | return mode 63 | } 64 | -------------------------------------------------------------------------------- /cpio/hash.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2017, Ryan Armstrong. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package cpio 7 | 8 | import ( 9 | "encoding/binary" 10 | "hash" 11 | ) 12 | 13 | type digest struct { 14 | sum uint32 15 | } 16 | 17 | // NewHash returns a new hash.Hash32 for computing SVR4 checksums. 18 | func NewHash() hash.Hash32 { 19 | return &digest{} 20 | } 21 | 22 | func (d *digest) Write(p []byte) (n int, err error) { 23 | for _, b := range p { 24 | d.sum += uint32(b & 0xFF) 25 | } 26 | 27 | return len(p), nil 28 | } 29 | 30 | func (d *digest) Sum(b []byte) []byte { 31 | out := [4]byte{} 32 | binary.LittleEndian.PutUint32(out[:], d.sum) 33 | return append(b, out[:]...) 34 | } 35 | 36 | func (d *digest) Sum32() uint32 { 37 | return d.sum 38 | } 39 | 40 | func (d *digest) Reset() { 41 | d.sum = 0 42 | } 43 | 44 | func (d *digest) Size() int { 45 | return 4 46 | } 47 | 48 | func (d *digest) BlockSize() int { 49 | return 1 50 | } 51 | -------------------------------------------------------------------------------- /cpio/testdata/Makefile: -------------------------------------------------------------------------------- 1 | SOURCES = \ 2 | gophers.txt \ 3 | readme.txt \ 4 | todo.txt \ 5 | checklist.txt 6 | 7 | ARCHIVES = \ 8 | test_odc.cpio \ 9 | test_svr4.cpio \ 10 | test_svr4_crc.cpio 11 | 12 | all: $(ARCHIVES) 13 | 14 | test_odc.cpio: $(SOURCES) 15 | echo $(SOURCES) | tr " " "\n" | cpio -o --owner=0:0 --format=odc > $@ 16 | 17 | test_svr4.cpio: $(SOURCES) 18 | echo $(SOURCES) | tr " " "\n" | cpio -o --owner=0:0 --format=newc > $@ 19 | 20 | test_svr4_crc.cpio: $(SOURCES) 21 | echo $(SOURCES) | tr " " "\n" | cpio -o --owner=0:0 --format=crc > $@ 22 | 23 | clean: 24 | rm -f $(ARCHIVES) version.txt 25 | 26 | .PHONY: all clean 27 | -------------------------------------------------------------------------------- /cpio/testdata/checklist.txt: -------------------------------------------------------------------------------- 1 | todo.txt -------------------------------------------------------------------------------- /cpio/testdata/etc/hosts: -------------------------------------------------------------------------------- 1 | 127.0.0.1 localhost 2 | ::1 localhost 3 | -------------------------------------------------------------------------------- /cpio/testdata/gophers.txt: -------------------------------------------------------------------------------- 1 | Gopher names: 2 | George 3 | Geoffrey 4 | Gonzo 5 | -------------------------------------------------------------------------------- /cpio/testdata/readme.txt: -------------------------------------------------------------------------------- 1 | This archive contains some text files. 2 | -------------------------------------------------------------------------------- /cpio/testdata/test_odc.cpio: -------------------------------------------------------------------------------- 1 | 0707070000540525321006440000000000000000010000001313263532500001400000000044gophers.txtGopher names: 2 | George 3 | Geoffrey 4 | Gonzo 5 | 0707070000540522411006440000000000000000010000001313263515400001300000000047readme.txtThis archive contains some text files. 6 | 0707070000540523201006440000000000000000010000001313263520500001100000000035todo.txtGet animal handling license. 7 | 0707070000543142571207550000000000000000010000001313763605600001600000000010checklist.txttodo.txt0707070000000000000000000000000000000000010000000000000000000001300000000000TRAILER!!! -------------------------------------------------------------------------------- /cpio/testdata/test_svr4.cpio: -------------------------------------------------------------------------------- 1 | 07070100E8555A000081A4000000000000000000000001596B3AD500000024000000000000002C00000000000000000000000C00000000gophers.txtGopher names: 2 | George 3 | Geoffrey 4 | Gonzo 5 | 07070100E854A1000081A4000000000000000000000001596B3A6C00000027000000000000002C00000000000000000000000B00000000readme.txtThis archive contains some text files. 6 | 07070100E854D0000081A4000000000000000000000001596B3A850000001D000000000000002C00000000000000000000000900000000todo.txtGet animal handling license. 7 | 07070100F998AF0000A1ED000000000000000000000001597F3C2E00000008000000000000002C00000000000000000000000E00000000checklist.txttodo.txt07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!! -------------------------------------------------------------------------------- /cpio/testdata/test_svr4_crc.cpio: -------------------------------------------------------------------------------- 1 | 07070200E8555A000081A4000000000000000000000001596B3AD500000024000000000000002C00000000000000000000000C00000C98gophers.txtGopher names: 2 | George 3 | Geoffrey 4 | Gonzo 5 | 07070200E854A1000081A4000000000000000000000001596B3A6C00000027000000000000002C00000000000000000000000B00000E3Dreadme.txtThis archive contains some text files. 6 | 07070200E854D0000081A4000000000000000000000001596B3A850000001D000000000000002C00000000000000000000000900000A52todo.txtGet animal handling license. 7 | 07070200F998AF0000A1ED000000000000000000000001597F3C2E00000008000000000000002C00000000000000000000000E00000000checklist.txttodo.txt07070200000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!! -------------------------------------------------------------------------------- /cpio/testdata/todo.txt: -------------------------------------------------------------------------------- 1 | Get animal handling license. 2 | -------------------------------------------------------------------------------- /cpio/writer_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2017, Ryan Armstrong. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package cpio_test 7 | 8 | import ( 9 | "bytes" 10 | "io" 11 | "os" 12 | "testing" 13 | 14 | "kraftkit.sh/cpio" 15 | ) 16 | 17 | func store(w *cpio.Writer, fn string) error { 18 | f, err := os.Open(fn) 19 | if err != nil { 20 | return err 21 | } 22 | defer f.Close() 23 | fi, err := f.Stat() 24 | if err != nil { 25 | return err 26 | } 27 | hdr, err := cpio.FileInfoHeader(fi, "") 28 | if err != nil { 29 | return err 30 | } 31 | if err := w.WriteHeader(hdr); err != nil { 32 | return err 33 | } 34 | if !fi.IsDir() { 35 | if _, err := io.Copy(w, f); err != nil { 36 | return err 37 | } 38 | } 39 | return err 40 | } 41 | 42 | func TestWriter(t *testing.T) { 43 | var buf bytes.Buffer 44 | w := cpio.NewWriter(&buf) 45 | if err := store(w, "testdata/etc"); err != nil { 46 | t.Fatalf("store: %v", err) 47 | } 48 | if err := store(w, "testdata/etc/hosts"); err != nil { 49 | t.Fatalf("store: %v", err) 50 | } 51 | if err := w.Close(); err != nil { 52 | t.Fatalf("Close: %v", err) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /docs/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unikraft/kraftkit/d94aeb139d1c27911ec1a89afdbfea6471fdb32a/docs/demo.gif -------------------------------------------------------------------------------- /exec/process_darwin.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package exec 6 | 7 | import ( 8 | "syscall" 9 | ) 10 | 11 | func hostAttributes() *syscall.SysProcAttr { 12 | // the Setpgid flag is used to prevent the child process from exiting when 13 | // the parent is killed 14 | return &syscall.SysProcAttr{ 15 | Setpgid: true, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exec/process_freebsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package exec 6 | 7 | import ( 8 | "syscall" 9 | ) 10 | 11 | func hostAttributes() *syscall.SysProcAttr { 12 | // the Setpgid flag is used to prevent the child process from exiting when 13 | // the parent is killed 14 | return &syscall.SysProcAttr{ 15 | Setpgid: true, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exec/process_linux.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package exec 6 | 7 | import ( 8 | "syscall" 9 | ) 10 | 11 | func hostAttributes() *syscall.SysProcAttr { 12 | // the Setpgid flag is used to prevent the child process from exiting when 13 | // the parent is killed 14 | return &syscall.SysProcAttr{ 15 | Setpgid: true, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exec/process_netbsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package exec 6 | 7 | import ( 8 | "syscall" 9 | ) 10 | 11 | func hostAttributes() *syscall.SysProcAttr { 12 | // the Setpgid flag is used to prevent the child process from exiting when 13 | // the parent is killed 14 | return &syscall.SysProcAttr{ 15 | Setpgid: true, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exec/process_openbsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package exec 6 | 7 | import ( 8 | "syscall" 9 | ) 10 | 11 | func hostAttributes() *syscall.SysProcAttr { 12 | // the Setpgid flag is used to prevent the child process from exiting when 13 | // the parent is killed 14 | return &syscall.SysProcAttr{ 15 | Setpgid: true, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exec/process_windows.go: -------------------------------------------------------------------------------- 1 | // process_windows.go 2 | //go:build windows 3 | 4 | // SPDX-License-Identifier: BSD-3-Clause 5 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 6 | // Licensed under the BSD-3-Clause License (the "License"). 7 | // You may not use this file expect in compliance with the License. 8 | package exec 9 | 10 | import ( 11 | "syscall" 12 | ) 13 | 14 | func hostAttributes() *syscall.SysProcAttr { 15 | // the CREATE_NEW_PROCESS_GROUP flag is used to prevent the child process from exiting when 16 | // the parent is killed 17 | return &syscall.SysProcAttr{ 18 | CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /exec/sequential.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package exec 6 | 7 | import "context" 8 | 9 | type SequentialProcesses struct { 10 | sequence []*Process 11 | } 12 | 13 | // NewSequential returns a newly generated SequentialProcesses structure with 14 | // the provided processes 15 | func NewSequential(sequence ...*Process) (*SequentialProcesses, error) { 16 | sp := &SequentialProcesses{ 17 | sequence: sequence, 18 | } 19 | 20 | return sp, nil 21 | } 22 | 23 | // StartAndWait sequentially starts the list of processes and waits for it to 24 | // complete before starting the next. 25 | func (sq *SequentialProcesses) StartAndWait(ctx context.Context) error { 26 | for _, process := range sq.sequence { 27 | if err := process.StartAndWait(ctx); err != nil { 28 | return err 29 | } 30 | } 31 | 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /hack/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 5 | // Licensed under the BSD-3-Clause License (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | 8 | package hack 9 | 10 | // These imports ensure that build tools are included in Go modules so that we 11 | // can `go install` them in module-aware mode. 12 | // See https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module 13 | import _ "github.com/onsi/ginkgo/v2/ginkgo" 14 | -------------------------------------------------------------------------------- /initrd/detect.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package initrd 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | ) 11 | 12 | // New attempts to return the builder for a supplied path which 13 | // will allow the provided ... 14 | func New(ctx context.Context, path string, opts ...InitrdOption) (Initrd, error) { 15 | if builder, err := NewFromDockerfile(ctx, path, opts...); err == nil { 16 | return builder, nil 17 | } else if builder, err := NewFromTarball(ctx, path, opts...); err == nil { 18 | return builder, nil 19 | } else if builder, err := NewFromFile(ctx, path, opts...); err == nil { 20 | return builder, nil 21 | } else if builder, err := NewFromDirectory(ctx, path, opts...); err == nil { 22 | return builder, nil 23 | } else if builder, err := NewFromOCIImage(ctx, path, opts...); err == nil { 24 | return builder, nil 25 | } 26 | 27 | return nil, fmt.Errorf("could not determine how to build initrd from: %s", path) 28 | } 29 | -------------------------------------------------------------------------------- /initrd/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | // Package initrd is a package that is used for the dynamic construction of CPIO 7 | // archives which are used as initramfs for a unikernel instance. 8 | package initrd 9 | -------------------------------------------------------------------------------- /initrd/initrd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package initrd 6 | 7 | import "context" 8 | 9 | const ( 10 | // DefaultInitramfsFileName is the default filename used when creating or 11 | // serializing a CPIO archive. 12 | DefaultInitramfsFileName = "initramfs.cpio" 13 | 14 | // DefaultInitramfsArchFileName is the default filename used when creating 15 | // or serializing a CPIO archive based on a specific architecture 16 | DefaultInitramfsArchFileName = "initramfs-%s.cpio" 17 | ) 18 | 19 | // Initrd is an interface that is used to allow for different underlying 20 | // implementations to construct a CPIO archive. 21 | type Initrd interface { 22 | // Name of the initramfs builder. 23 | Name() string 24 | 25 | // Build the rootfs and return the location of the result or error. 26 | Build(context.Context) (string, error) 27 | 28 | // All environment variables that are set within. 29 | Env() []string 30 | 31 | // All arguments that are passed to the initramfs. 32 | Args() []string 33 | } 34 | -------------------------------------------------------------------------------- /initrd/initrd_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package initrd_test 7 | 8 | import ( 9 | "io" 10 | "os" 11 | "testing" 12 | 13 | "kraftkit.sh/cpio" 14 | ) 15 | 16 | var expectHeaders = map[string]cpio.Header{ 17 | "./a": { 18 | Mode: cpio.TypeDir, 19 | }, 20 | "./a/b": { 21 | Mode: cpio.TypeDir, 22 | }, 23 | "./a/b/c": { 24 | Mode: cpio.TypeDir, 25 | }, 26 | "./a/b/c/d": { 27 | Mode: cpio.TypeReg, 28 | Size: 13, 29 | }, 30 | "./a/b/c/e-symlink": { 31 | Mode: cpio.TypeSymlink, 32 | Linkname: "./d", 33 | }, 34 | "./a/b/c/f-hardlink": { 35 | Mode: cpio.TypeReg, 36 | Size: 0, 37 | }, 38 | "./a/b/c/g-recursive-symlink": { 39 | Mode: cpio.TypeSymlink, 40 | Linkname: ".", 41 | }, 42 | } 43 | 44 | // openFile opens a file for reading, and closes it when the test completes. 45 | func openFile(t *testing.T, path string) io.Reader { 46 | t.Helper() 47 | 48 | f, err := os.Open(path) 49 | if err != nil { 50 | t.Fatal("Failed to open file for reading:", err) 51 | } 52 | t.Cleanup(func() { 53 | if err := f.Close(); err != nil { 54 | t.Error("Failed to close file:", err) 55 | } 56 | }) 57 | 58 | return f 59 | } 60 | -------------------------------------------------------------------------------- /initrd/ociimage_netbsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package initrd 6 | 7 | import ( 8 | "context" 9 | ) 10 | 11 | type ociimage struct{} 12 | 13 | // NewFromOCIImage creates a new initrd from a remote container image. 14 | func NewFromOCIImage(ctx context.Context, path string, opts ...InitrdOption) (Initrd, error) { 15 | return nil, nil 16 | } 17 | 18 | // Build implements Initrd. 19 | func (initrd *ociimage) Name() string { 20 | return "OCI image" 21 | } 22 | 23 | // Build implements Initrd. 24 | func (initrd *ociimage) Build(ctx context.Context) (string, error) { 25 | return "", nil 26 | } 27 | 28 | // Env implements Initrd. 29 | func (initrd *ociimage) Env() []string { 30 | return nil 31 | } 32 | 33 | // Args implements Initrd. 34 | func (initrd *ociimage) Args() []string { 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /initrd/ociimage_openbsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package initrd 6 | 7 | import ( 8 | "context" 9 | ) 10 | 11 | type ociimage struct{} 12 | 13 | // NewFromOCIImage creates a new initrd from a remote container image. 14 | func NewFromOCIImage(ctx context.Context, path string, opts ...InitrdOption) (Initrd, error) { 15 | return nil, nil 16 | } 17 | 18 | // Build implements Initrd. 19 | func (initrd *ociimage) Name() string { 20 | return "OCI image" 21 | } 22 | 23 | // Build implements Initrd. 24 | func (initrd *ociimage) Build(ctx context.Context) (string, error) { 25 | return "", nil 26 | } 27 | 28 | // Env implements Initrd. 29 | func (initrd *ociimage) Env() []string { 30 | return nil 31 | } 32 | 33 | // Args implements Initrd. 34 | func (initrd *ociimage) Args() []string { 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /initrd/testdata/rootfs.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:latest 2 | 3 | # Create a directory 4 | RUN mkdir -p /out/a/b/c 5 | 6 | # Set the working directory 7 | WORKDIR /out/a/b/c 8 | 9 | # Create a file 10 | RUN echo "Hello, World" > ./d 11 | 12 | # Create a symbolic linked file 13 | RUN ln -s ./d ./e-symlink 14 | 15 | # Create a hard linked file 16 | RUN ln ./d ./f-hardlink 17 | 18 | # Create a recursive symolic link 19 | RUN ln -s . ./g-recursive-symlink 20 | 21 | # Create a blank file system 22 | FROM scratch 23 | 24 | # Copy the directory from the previous stage 25 | COPY --from=0 /out / 26 | -------------------------------------------------------------------------------- /initrd/testdata/rootfs.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unikraft/kraftkit/d94aeb139d1c27911ec1a89afdbfea6471fdb32a/initrd/testdata/rootfs.tar.gz -------------------------------------------------------------------------------- /initrd/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package initrd 6 | 7 | import ( 8 | "compress/gzip" 9 | "fmt" 10 | "io" 11 | "os" 12 | 13 | "kraftkit.sh/cpio" 14 | ) 15 | 16 | func compressFiles(output string, writer *cpio.Writer, reader *os.File) error { 17 | err := writer.Close() 18 | if err != nil { 19 | return fmt.Errorf("could not close CPIO writer: %w", err) 20 | } 21 | 22 | _, err = reader.Seek(0, io.SeekStart) 23 | if err != nil { 24 | return fmt.Errorf("could not seek to start of file: %w", err) 25 | } 26 | 27 | fw, err := os.OpenFile(output+".gz", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) 28 | if err != nil { 29 | return fmt.Errorf("could not open initramfs file: %w", err) 30 | } 31 | 32 | gw := gzip.NewWriter(fw) 33 | 34 | if _, err := io.Copy(gw, reader); err != nil { 35 | return fmt.Errorf("could not compress initramfs file: %w", err) 36 | } 37 | 38 | err = gw.Close() 39 | if err != nil { 40 | return fmt.Errorf("could not close gzip writer: %w", err) 41 | } 42 | 43 | err = fw.Close() 44 | if err != nil { 45 | return fmt.Errorf("could not close compressed initramfs file: %w", err) 46 | } 47 | 48 | if err := os.Remove(output); err != nil { 49 | return fmt.Errorf("could not remove uncompressed initramfs: %w", err) 50 | } 51 | 52 | if err := os.Rename(output+".gz", output); err != nil { 53 | return fmt.Errorf("could not rename compressed initramfs: %w", err) 54 | } 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /initrd/utils_unix.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | // SPDX-License-Identifier: BSD-3-Clause 5 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 6 | // Licensed under the BSD-3-Clause License (the "License"). 7 | // You may not use this file except in compliance with the License. 8 | package initrd 9 | 10 | import ( 11 | "io/fs" 12 | "syscall" 13 | 14 | "kraftkit.sh/cpio" 15 | ) 16 | 17 | func FileInfoToCPIOHeader(info fs.FileInfo, header *cpio.Header) { 18 | if sysInfo := info.Sys(); sysInfo != nil { 19 | if stat, ok := sysInfo.(*syscall.Stat_t); ok { 20 | header.Uid = int(stat.Uid) 21 | header.Guid = int(stat.Gid) 22 | header.Inode = int64(stat.Ino) 23 | header.Links = int(stat.Nlink) 24 | header.DeviceID = int(stat.Dev) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /initrd/utils_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | // SPDX-License-Identifier: BSD-3-Clause 5 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 6 | // Licensed under the BSD-3-Clause License (the "License"). 7 | // You may not use this file except in compliance with the License. 8 | package initrd 9 | 10 | import ( 11 | "io/fs" 12 | 13 | "kraftkit.sh/cpio" 14 | ) 15 | 16 | func FileInfoToCPIOHeader(info fs.FileInfo, header *cpio.Header) {} 17 | -------------------------------------------------------------------------------- /internal/bootstrap/init.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | // Package bootstrap lets us keep kraftkit initialization logic in one place. 7 | package bootstrap 8 | 9 | import ( 10 | "context" 11 | 12 | "kraftkit.sh/api" 13 | "kraftkit.sh/machine/qemu" 14 | "kraftkit.sh/manifest" 15 | "kraftkit.sh/oci" 16 | "kraftkit.sh/packmanager" 17 | ) 18 | 19 | // InitKraftkit performs a set of kraftkit setup steps. 20 | // It allows us to move away from in-package init() magic. 21 | // It also allows us to propagate initialization errors easily. 22 | func InitKraftkit(ctx context.Context) error { 23 | registerAdditionalFlags() 24 | 25 | if err := registerSchemes(); err != nil { 26 | return err 27 | } 28 | 29 | return registerPackageManagers(ctx) 30 | } 31 | 32 | func registerAdditionalFlags() { 33 | manifest.RegisterFlags() 34 | qemu.RegisterFlags() 35 | } 36 | 37 | func registerSchemes() error { 38 | return api.RegisterSchemes() 39 | } 40 | 41 | func registerPackageManagers(ctx context.Context) error { 42 | managerConstructors := []func(u *packmanager.UmbrellaManager) error{ 43 | oci.RegisterPackageManager(), 44 | manifest.RegisterPackageManager(), 45 | } 46 | 47 | return packmanager.InitUmbrellaManager(ctx, managerConstructors) 48 | } 49 | -------------------------------------------------------------------------------- /internal/cli/kraft/build/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package build 7 | 8 | import ( 9 | "context" 10 | 11 | "kraftkit.sh/unikraft/app" 12 | ) 13 | 14 | // initProject sets up the project based on the provided context and 15 | // options. 16 | func (opts *BuildOptions) initProject(ctx context.Context) error { 17 | var err error 18 | 19 | popts := []app.ProjectOption{ 20 | app.WithProjectWorkdir(opts.Workdir), 21 | } 22 | 23 | if len(opts.Kraftfile) > 0 { 24 | popts = append(popts, app.WithProjectKraftfile(opts.Kraftfile)) 25 | } else { 26 | popts = append(popts, app.WithProjectDefaultKraftfiles()) 27 | } 28 | 29 | if opts.Output != "" { 30 | popts = append(popts, app.WithProjectOutDir(opts.Output)) 31 | } 32 | 33 | // Interpret the project directory 34 | opts.Project, err = app.NewProjectFromOptions(ctx, popts...) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /internal/cli/kraft/cloud/certificate/certificate.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package certificate 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/spf13/pflag" 13 | 14 | "kraftkit.sh/cmdfactory" 15 | 16 | "kraftkit.sh/internal/cli/kraft/cloud/certificate/create" 17 | "kraftkit.sh/internal/cli/kraft/cloud/certificate/get" 18 | "kraftkit.sh/internal/cli/kraft/cloud/certificate/list" 19 | "kraftkit.sh/internal/cli/kraft/cloud/certificate/remove" 20 | ) 21 | 22 | type CertificateOptions struct{} 23 | 24 | func NewCmd() *cobra.Command { 25 | cmd, err := cmdfactory.New(&CertificateOptions{}, cobra.Command{ 26 | Short: "Manage TLS certificates", 27 | Use: "cert SUBCOMMAND", 28 | Aliases: []string{"certificate", "certificates", "certs", "crt", "crts"}, 29 | Annotations: map[string]string{ 30 | cmdfactory.AnnotationHelpGroup: "kraftcloud-certificate", 31 | cmdfactory.AnnotationHelpHidden: "true", 32 | }, 33 | }) 34 | if err != nil { 35 | panic(err) 36 | } 37 | 38 | cmd.AddCommand(create.NewCmd()) 39 | cmd.AddCommand(list.NewCmd()) 40 | cmd.AddCommand(remove.NewCmd()) 41 | cmd.AddCommand(get.NewCmd()) 42 | 43 | return cmd 44 | } 45 | 46 | func (opts *CertificateOptions) Run(_ context.Context, _ []string) error { 47 | return pflag.ErrHelp 48 | } 49 | -------------------------------------------------------------------------------- /internal/cli/kraft/cloud/deploy/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package deploy 7 | 8 | import ( 9 | "context" 10 | 11 | "kraftkit.sh/unikraft/app" 12 | ) 13 | 14 | // initProject sets up the project based on the provided context and 15 | // options. 16 | func (opts *DeployOptions) initProject(ctx context.Context) error { 17 | var err error 18 | 19 | popts := []app.ProjectOption{ 20 | app.WithProjectWorkdir(opts.Workdir), 21 | } 22 | 23 | if len(opts.Kraftfile) > 0 { 24 | popts = append(popts, app.WithProjectKraftfile(opts.Kraftfile)) 25 | } else { 26 | popts = append(popts, app.WithProjectDefaultKraftfiles()) 27 | } 28 | 29 | // Interpret the project directory 30 | opts.Project, err = app.NewProjectFromOptions(ctx, popts...) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /internal/cli/kraft/cloud/image/image.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package image 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/MakeNowJust/heredoc" 12 | "github.com/spf13/cobra" 13 | "github.com/spf13/pflag" 14 | 15 | "kraftkit.sh/internal/cli/kraft/cloud/image/list" 16 | "kraftkit.sh/internal/cli/kraft/cloud/image/remove" 17 | 18 | "kraftkit.sh/cmdfactory" 19 | ) 20 | 21 | type ImageOptions struct{} 22 | 23 | func NewCmd() *cobra.Command { 24 | cmd, err := cmdfactory.New(&ImageOptions{}, cobra.Command{ 25 | Short: "Manage images", 26 | Use: "image SUBCOMMAND", 27 | Aliases: []string{"img", "images"}, 28 | Example: heredoc.Doc(` 29 | # List images in your account. 30 | $ kraft cloud image list 31 | 32 | # Delete an image from your account. 33 | $ kraft cloud image remove caddy@sha256:2ba5324141... 34 | `), 35 | Annotations: map[string]string{ 36 | cmdfactory.AnnotationHelpGroup: "kraftcloud-image", 37 | cmdfactory.AnnotationHelpHidden: "true", 38 | }, 39 | }) 40 | if err != nil { 41 | panic(err) 42 | } 43 | 44 | cmd.AddCommand(list.NewCmd()) 45 | cmd.AddCommand(remove.NewCmd()) 46 | 47 | return cmd 48 | } 49 | 50 | func (opts *ImageOptions) Run(_ context.Context, _ []string) error { 51 | return pflag.ErrHelp 52 | } 53 | -------------------------------------------------------------------------------- /internal/cli/kraft/cloud/metro/metro.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package metro 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/MakeNowJust/heredoc" 12 | "github.com/spf13/cobra" 13 | "github.com/spf13/pflag" 14 | 15 | "kraftkit.sh/internal/cli/kraft/cloud/metro/list" 16 | 17 | "kraftkit.sh/cmdfactory" 18 | ) 19 | 20 | type MetroOptions struct{} 21 | 22 | func NewCmd() *cobra.Command { 23 | cmd, err := cmdfactory.New(&MetroOptions{}, cobra.Command{ 24 | Short: "Inspect Unikraft Cloud metros and regions", 25 | Use: "metro", 26 | Aliases: []string{"metros", "m"}, 27 | Example: heredoc.Doc(` 28 | # List metros available. 29 | $ kraft cloud metro list 30 | 31 | # List metros available in JSON format. 32 | $ kraft cloud metro list -o json 33 | 34 | # List metros available and their status. 35 | $ kraft cloud metro list --status 36 | `), 37 | Annotations: map[string]string{ 38 | cmdfactory.AnnotationHelpGroup: "kraftcloud-metro", 39 | cmdfactory.AnnotationHelpHidden: "true", 40 | }, 41 | }) 42 | if err != nil { 43 | panic(err) 44 | } 45 | 46 | cmd.AddCommand(list.NewCmd()) 47 | 48 | return cmd 49 | } 50 | 51 | func (opts *MetroOptions) Run(_ context.Context, _ []string) error { 52 | return pflag.ErrHelp 53 | } 54 | -------------------------------------------------------------------------------- /internal/cli/kraft/cloud/utils/is_uuid.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package utils 7 | 8 | import "github.com/google/uuid" 9 | 10 | // IsUUID returns whether the provided the string is a UUID or not. 11 | func IsUUID(arg string) bool { 12 | _, uuidErr := uuid.Parse(arg) 13 | return uuidErr == nil 14 | } 15 | -------------------------------------------------------------------------------- /internal/cli/kraft/cloud/utils/rand.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package utils 7 | 8 | import ( 9 | "crypto/rand" 10 | "math/big" 11 | "strings" 12 | ) 13 | 14 | // GenRandAuth generates a random authentication string. 15 | func GenRandAuth() (string, error) { 16 | rndChars := []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") 17 | maxIdx := big.NewInt(int64(len(rndChars))) 18 | 19 | const authLen = 32 20 | var auth strings.Builder 21 | auth.Grow(authLen) 22 | 23 | var i *big.Int 24 | var err error 25 | for range authLen { 26 | if i, err = rand.Int(rand.Reader, maxIdx); err != nil { 27 | return "", err 28 | } 29 | if err = auth.WriteByte(rndChars[i.Int64()]); err != nil { 30 | return "", err 31 | } 32 | } 33 | 34 | return auth.String(), nil 35 | } 36 | -------------------------------------------------------------------------------- /internal/cli/kraft/cloud/volume/import/errors.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package vimport 7 | 8 | import "errors" 9 | 10 | // Loggable is a type of error that can be asserted for behaviour, and signals 11 | // whether an error should be logged when handled. 12 | // It is particularly useful for communicating to a caller that the error was 13 | // already reported (e.g. logged) in a callee. 14 | type Loggable interface { 15 | error 16 | Loggable() bool 17 | } 18 | 19 | // NotLoggable marks an error as not loggable. 20 | func NotLoggable(err error) error { 21 | return noLogError{e: err} 22 | } 23 | 24 | // IsLoggable returns whether err should be logged when handled. 25 | // All errors are considered loggable unless explicitly marked otherwise. 26 | func IsLoggable(err error) bool { 27 | lerr := (Loggable)(nil) 28 | if impl := errors.As(err, &lerr); !impl { 29 | return true 30 | } 31 | return lerr.Loggable() 32 | } 33 | 34 | // noLogError is an error type that should not be logged when handled. 35 | type noLogError struct { 36 | e error 37 | } 38 | 39 | var _ Loggable = (*noLogError)(nil) 40 | 41 | // Loggable implements Loggable. 42 | func (noLogError) Loggable() bool { 43 | return false 44 | } 45 | 46 | // Error implements the error interface. 47 | func (e noLogError) Error() string { 48 | return e.e.Error() 49 | } 50 | 51 | // Unwrap implements the Unwrap part of the error interface. 52 | func (e noLogError) Unwrap() error { 53 | return e.e 54 | } 55 | -------------------------------------------------------------------------------- /internal/cli/kraft/cloud/volume/import/errors_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package vimport_test 7 | 8 | import ( 9 | "errors" 10 | "fmt" 11 | "testing" 12 | 13 | vimport "kraftkit.sh/internal/cli/kraft/cloud/volume/import" 14 | ) 15 | 16 | func TestLoggableError(t *testing.T) { 17 | genericErr := errors.New("an error") 18 | nologErr := vimport.NotLoggable(genericErr) 19 | 20 | // generic 21 | if !vimport.IsLoggable(genericErr) { 22 | t.Error("Expected generic error to be loggable") 23 | } 24 | if !vimport.IsLoggable(fmt.Errorf("wrapped: %w", genericErr)) { 25 | t.Error("Expected wrapped generic error to be loggable") 26 | } 27 | 28 | // nolog 29 | if vimport.IsLoggable(nologErr) { 30 | t.Error("Expected nolog error to not be loggable") 31 | } 32 | if vimport.IsLoggable(fmt.Errorf("wrapped: %w", nologErr)) { 33 | t.Error("Expected wrapped nolog error to not be loggable") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /internal/cli/kraft/lib/lib.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package lib 6 | 7 | import ( 8 | "context" 9 | 10 | "github.com/MakeNowJust/heredoc" 11 | "github.com/spf13/cobra" 12 | "github.com/spf13/pflag" 13 | "kraftkit.sh/cmdfactory" 14 | "kraftkit.sh/internal/cli/kraft/lib/add" 15 | "kraftkit.sh/internal/cli/kraft/lib/create" 16 | "kraftkit.sh/internal/cli/kraft/lib/remove" 17 | ) 18 | 19 | type LibOptions struct{} 20 | 21 | func NewCmd() *cobra.Command { 22 | cmd, err := cmdfactory.New(&LibOptions{}, cobra.Command{ 23 | Short: "Manage and maintain Unikraft microlibraries", 24 | Use: "lib SUBCOMMAND", 25 | Aliases: []string{"library"}, 26 | Long: "Manage and maintain Unikraft microlibraries.", 27 | Example: heredoc.Doc(` 28 | # Add a new microlibrary to your project. 29 | $ kraft lib add 30 | `), 31 | Annotations: map[string]string{ 32 | cmdfactory.AnnotationHelpGroup: "lib", 33 | cmdfactory.AnnotationHelpHidden: "true", 34 | }, 35 | }) 36 | if err != nil { 37 | panic(err) 38 | } 39 | 40 | cmd.AddCommand(remove.NewCmd()) 41 | cmd.AddCommand(add.NewCmd()) 42 | cmd.AddCommand(create.NewCmd()) 43 | 44 | return cmd 45 | } 46 | 47 | func (opts *LibOptions) Run(_ context.Context, _ []string) error { 48 | return pflag.ErrHelp 49 | } 50 | -------------------------------------------------------------------------------- /internal/cli/kraft/logs/colorful_consumer.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package logs 6 | 7 | import ( 8 | "fmt" 9 | 10 | rainbow "kraftkit.sh/internal/rainbowprint" 11 | 12 | "kraftkit.sh/iostreams" 13 | ) 14 | 15 | type LogConsumer interface { 16 | Consume(line ...string) 17 | } 18 | 19 | type ColorfulConsumer struct { 20 | streams *iostreams.IOStreams 21 | color rainbow.ColorFunc 22 | prefix string 23 | } 24 | 25 | // NewColorfulConsumer creates a new log consumer which prefixes each line with a colorful prefix. 26 | func NewColorfulConsumer(streams *iostreams.IOStreams, color bool, prefix string) (*ColorfulConsumer, error) { 27 | if streams == nil { 28 | return nil, fmt.Errorf("cannot create a colorful consumer with nil IOStreams") 29 | } 30 | 31 | var colorFunc rainbow.ColorFunc 32 | if color { 33 | rainbow.SetANSIMode(streams, rainbow.Auto) 34 | } else { 35 | rainbow.SetANSIMode(streams, rainbow.Never) 36 | } 37 | 38 | colorFunc = rainbow.NextColor() 39 | return &ColorfulConsumer{streams: streams, color: colorFunc, prefix: prefix}, nil 40 | } 41 | 42 | // Consume implements logConsumer 43 | func (c *ColorfulConsumer) Consume(strs ...string) { 44 | for _, s := range strs { 45 | if c.prefix != "" { 46 | s = fmt.Sprintf("%s | %s", c.color(c.prefix), s) 47 | } 48 | 49 | fmt.Fprintf(c.streams.Out, "%s\n", s) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /internal/cli/kraft/pkg/packager.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package pkg 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | 12 | "kraftkit.sh/pack" 13 | ) 14 | 15 | // packager is an interface for defining different mechanisms to perform a 16 | // packaging of a unikernel. Standardizing first the check, Packagable, 17 | // to determine whether the provided input is capable of executing, and 18 | // Pack, actually performing the packaging. 19 | type packager interface { 20 | // String implements fmt.Stringer and returns the name of the implementing 21 | // builder. 22 | fmt.Stringer 23 | 24 | // Packagable determines whether the provided input is packagable by the 25 | // current implementation. 26 | Packagable(context.Context, *PkgOptions, ...string) (bool, error) 27 | 28 | // Pack performs the packaging based on the determined implementation. 29 | Pack(context.Context, *PkgOptions, ...string) ([]pack.Package, error) 30 | } 31 | 32 | // packagers is the list of built-in packagers which are checked 33 | // sequentially for capability. The first to test positive via Packagable 34 | // is used with the controller. 35 | func packagers() []packager { 36 | return []packager{ 37 | &packagerCliKernel{}, 38 | &packagerKraftfileUnikraft{}, 39 | &packagerKraftfileRuntime{}, 40 | &packagerDockerfile{}, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /internal/cli/kraft/system/system.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2025, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package system 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/spf13/pflag" 13 | 14 | "kraftkit.sh/cmdfactory" 15 | 16 | "kraftkit.sh/internal/cli/kraft/system/set" 17 | ) 18 | 19 | type System struct{} 20 | 21 | func NewCmd() *cobra.Command { 22 | cmd, err := cmdfactory.New(&System{}, cobra.Command{ 23 | Short: "Manage KraftKit and host system", 24 | Use: "system SUBCOMMAND", 25 | Aliases: []string{"sys", "self"}, 26 | Annotations: map[string]string{ 27 | cmdfactory.AnnotationHelpGroup: "misc", 28 | cmdfactory.AnnotationHelpHidden: "true", 29 | }, 30 | }) 31 | if err != nil { 32 | panic(err) 33 | } 34 | 35 | cmd.AddCommand(set.NewCmd()) 36 | 37 | return cmd 38 | } 39 | 40 | func (opts *System) Run(ctx context.Context, args []string) error { 41 | return pflag.ErrHelp 42 | } 43 | -------------------------------------------------------------------------------- /internal/cli/kraft/utils/kraftcloud.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // RewrapAsKraftCloudPackage returns the equivalent package name as a 8 | // KraftCloud package. 9 | func RewrapAsKraftCloudPackage(name string) string { 10 | name = strings.Replace(name, "unikarft.org/", "index.unikraft.io/", 1) 11 | 12 | if strings.HasPrefix(name, "unikraft.io") { 13 | name = "index." + name 14 | } else if strings.Contains(name, "/") && !strings.Contains(name, "unikraft.io") { 15 | name = "index.unikraft.io/" + name 16 | } else if !strings.HasPrefix(name, "index.unikraft.io") { 17 | name = "index.unikraft.io/official/" + name 18 | } 19 | 20 | return name 21 | } 22 | -------------------------------------------------------------------------------- /internal/cli/kraft/utils/ports.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package utils 7 | 8 | import ( 9 | "context" 10 | "fmt" 11 | 12 | machineapi "kraftkit.sh/api/machine/v1alpha1" 13 | ) 14 | 15 | // CheckPorts is a utility method used to throw an error if the supplied machine 16 | // has assigned ports which are already used by an existing, running machine, 17 | // which is accessible through the supplied machine controller. 18 | func CheckPorts(ctx context.Context, controller machineapi.MachineService, machine *machineapi.Machine) error { 19 | existingMachines, err := controller.List(ctx, &machineapi.MachineList{}) 20 | if err != nil { 21 | return fmt.Errorf("getting list of existing machines: %w", err) 22 | } 23 | 24 | for _, existingMachine := range existingMachines.Items { 25 | for _, existingPort := range existingMachine.Spec.Ports { 26 | for _, newPort := range machine.Spec.Ports { 27 | if existingPort.HostIP == newPort.HostIP && existingPort.HostPort == newPort.HostPort && existingMachine.Status.State == machineapi.MachineStateRunning { 28 | return fmt.Errorf("port %s:%d is already in use by %s", existingPort.HostIP, existingPort.HostPort, existingMachine.Name) 29 | } 30 | } 31 | } 32 | } 33 | 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /internal/cli/kraft/version/version.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package version 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | "github.com/MakeNowJust/heredoc" 12 | "github.com/spf13/cobra" 13 | 14 | "kraftkit.sh/cmdfactory" 15 | "kraftkit.sh/internal/version" 16 | "kraftkit.sh/iostreams" 17 | ) 18 | 19 | type VersionOptions struct{} 20 | 21 | func NewCmd() *cobra.Command { 22 | cmd, err := cmdfactory.New(&VersionOptions{}, cobra.Command{ 23 | Short: "Show kraft version information", 24 | Use: "version", 25 | Aliases: []string{"v"}, 26 | Args: cobra.NoArgs, 27 | Long: "Show kraft version information.", 28 | Example: heredoc.Doc(` 29 | # Show kraft version information 30 | $ kraft version 31 | `), 32 | Annotations: map[string]string{ 33 | cmdfactory.AnnotationHelpGroup: "misc", 34 | }, 35 | }) 36 | if err != nil { 37 | panic(err) 38 | } 39 | 40 | return cmd 41 | } 42 | 43 | func (opts *VersionOptions) Run(ctx context.Context, _ []string) error { 44 | fmt.Fprintf(iostreams.G(ctx).Out, "kraft %s", version.String()) 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /internal/cli/kraft/x/exp.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package x 6 | 7 | import ( 8 | "context" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/spf13/pflag" 12 | 13 | "kraftkit.sh/cmdfactory" 14 | 15 | "kraftkit.sh/internal/cli/kraft/x/probe" 16 | ) 17 | 18 | type Exp struct{} 19 | 20 | func NewCmd() *cobra.Command { 21 | cmd, err := cmdfactory.New(&Exp{}, cobra.Command{ 22 | Short: "Experimental commands", 23 | Use: "x [SUBCOMMAND]", 24 | Hidden: true, 25 | Annotations: map[string]string{ 26 | cmdfactory.AnnotationHelpGroup: "misc", 27 | cmdfactory.AnnotationHelpHidden: "true", 28 | }, 29 | }) 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | cmd.AddCommand(probe.NewCmd()) 35 | 36 | return cmd 37 | } 38 | 39 | func (opts *Exp) Pre(_ *cobra.Command, _ []string) error { 40 | return nil 41 | } 42 | 43 | func (opts *Exp) Run(_ context.Context, _ []string) error { 44 | return pflag.ErrHelp 45 | } 46 | -------------------------------------------------------------------------------- /internal/errs/defs.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package errs 6 | 7 | import "errors" 8 | 9 | var ( 10 | // ErrNotFound is returned when an object is not found 11 | ErrNotFound = errors.New("not found") 12 | 13 | // ErrInvalid is returned when a compose project is invalid 14 | ErrInvalid = errors.New("invalid") 15 | 16 | // ErrUnsupported is returned when a compose project uses an unsupported attribute 17 | ErrUnsupported = errors.New("unsupported") 18 | 19 | // ErrIncompatible is returned when a compose project uses an incompatible attribute 20 | ErrIncompatible = errors.New("incompatible") 21 | ) 22 | 23 | // IsNotFoundError returns true if the unwrapped error is ErrNotFound 24 | func IsNotFoundError(err error) bool { 25 | return errors.Is(err, ErrNotFound) 26 | } 27 | 28 | // IsInvalidError returns true if the unwrapped error is ErrInvalid 29 | func IsInvalidError(err error) bool { 30 | return errors.Is(err, ErrInvalid) 31 | } 32 | 33 | // IsUnsupportedError returns true if the unwrapped error is ErrUnsupported 34 | func IsUnsupportedError(err error) bool { 35 | return errors.Is(err, ErrUnsupported) 36 | } 37 | 38 | // IsUnsupportedError returns true if the unwrapped error is ErrIncompatible 39 | func IsIncompatibleError(err error) bool { 40 | return errors.Is(err, ErrIncompatible) 41 | } 42 | -------------------------------------------------------------------------------- /internal/filelock/filelock_other.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build !unix && !windows 6 | 7 | package filelock 8 | 9 | import ( 10 | "errors" 11 | "io/fs" 12 | ) 13 | 14 | type lockType int8 15 | 16 | const ( 17 | readLock = iota + 1 18 | writeLock 19 | ) 20 | 21 | func lock(f File, lt lockType) error { 22 | return &fs.PathError{ 23 | Op: lt.String(), 24 | Path: f.Name(), 25 | Err: errors.ErrUnsupported, 26 | } 27 | } 28 | 29 | func unlock(f File) error { 30 | return &fs.PathError{ 31 | Op: "Unlock", 32 | Path: f.Name(), 33 | Err: errors.ErrUnsupported, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /internal/filelock/filelock_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd 6 | 7 | package filelock 8 | 9 | import ( 10 | "io/fs" 11 | "syscall" 12 | ) 13 | 14 | type lockType int16 15 | 16 | const ( 17 | readLock lockType = syscall.LOCK_SH 18 | writeLock lockType = syscall.LOCK_EX 19 | ) 20 | 21 | func lock(f File, lt lockType) (err error) { 22 | for { 23 | err = syscall.Flock(int(f.Fd()), int(lt)) 24 | if err != syscall.EINTR { 25 | break 26 | } 27 | } 28 | if err != nil { 29 | return &fs.PathError{ 30 | Op: lt.String(), 31 | Path: f.Name(), 32 | Err: err, 33 | } 34 | } 35 | return nil 36 | } 37 | 38 | func unlock(f File) error { 39 | return lock(f, syscall.LOCK_UN) 40 | } 41 | -------------------------------------------------------------------------------- /internal/filelock/filelock_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build windows 6 | 7 | package filelock 8 | 9 | import ( 10 | "io/fs" 11 | 12 | "golang.org/x/sys/windows" 13 | ) 14 | 15 | type lockType uint32 16 | 17 | const ( 18 | readLock lockType = 0 19 | writeLock lockType = windows.LOCKFILE_EXCLUSIVE_LOCK 20 | ) 21 | 22 | const ( 23 | reserved = 0 24 | allBytes = ^uint32(0) 25 | ) 26 | 27 | func lock(f File, lt lockType) error { 28 | // Per https://golang.org/issue/19098, “Programs currently expect the Fd 29 | // method to return a handle that uses ordinary synchronous I/O.” 30 | // However, LockFileEx still requires an OVERLAPPED structure, 31 | // which contains the file offset of the beginning of the lock range. 32 | // We want to lock the entire file, so we leave the offset as zero. 33 | ol := new(windows.Overlapped) 34 | 35 | err := windows.LockFileEx(windows.Handle(f.Fd()), uint32(lt), reserved, allBytes, allBytes, ol) 36 | if err != nil { 37 | return &fs.PathError{ 38 | Op: lt.String(), 39 | Path: f.Name(), 40 | Err: err, 41 | } 42 | } 43 | return nil 44 | } 45 | 46 | func unlock(f File) error { 47 | ol := new(windows.Overlapped) 48 | err := windows.UnlockFileEx(windows.Handle(f.Fd()), reserved, allBytes, allBytes, ol) 49 | if err != nil { 50 | return &fs.PathError{ 51 | Op: "Unlock", 52 | Path: f.Name(), 53 | Err: err, 54 | } 55 | } 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /internal/findsh/find.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | // SPDX-License-Identifier: MIT 5 | // 6 | // Copyright (c) 2019 GitHub Inc. 7 | // 2022 Unikraft GmbH. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | // SOFTWARE. 26 | 27 | package findsh 28 | 29 | import "os/exec" 30 | 31 | // Find locates the `sh` interpreter on the system. 32 | func Find() (string, error) { 33 | return exec.LookPath("sh") 34 | } 35 | -------------------------------------------------------------------------------- /internal/findsh/find_windows.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // 3 | // Copyright (c) 2019 GitHub Inc. 4 | // 2022 Unikraft GmbH. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | package findsh 25 | 26 | import ( 27 | "github.com/cli/safeexec" 28 | ) 29 | 30 | func Find() (string, error) { 31 | shPath, err := safeexec.LookPath("cmd") 32 | if err != nil { 33 | return "", err 34 | } 35 | 36 | return shPath, nil 37 | } 38 | -------------------------------------------------------------------------------- /internal/run/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package run 6 | 7 | import "strings" 8 | 9 | // BootArgsPrepare prepares the boot arguments for the unikernel. 10 | // Because of double parsing we need to be careful to escape each argument 11 | // with either single or double quotes before merging them together. 12 | func BootArgsPrepare(args ...string) string { 13 | var sb strings.Builder 14 | for _, arg := range args { 15 | if strings.Count(arg, "'") != strings.Count(arg, "\\'") { 16 | sb.WriteByte('"') 17 | sb.Write([]byte(arg)) 18 | sb.WriteByte('"') 19 | sb.WriteByte(' ') 20 | } else { 21 | sb.Write([]byte(arg)) 22 | sb.WriteByte(' ') 23 | } 24 | } 25 | 26 | return sb.String() 27 | } 28 | -------------------------------------------------------------------------------- /internal/tableprinter/column.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | 6 | package tableprinter 7 | 8 | // Column represents a column name in a table. 9 | type Column struct { 10 | Name string 11 | Value string 12 | } 13 | -------------------------------------------------------------------------------- /internal/tableprinter/render_json.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package tableprinter 6 | 7 | import ( 8 | "encoding/json" 9 | "fmt" 10 | "io" 11 | "strings" 12 | ) 13 | 14 | func (printer *TablePrinter) renderJSON(w io.Writer) error { 15 | header := printer.rows[0] 16 | var rows []map[string]string 17 | 18 | for i, row := range printer.rows { 19 | if i == 0 { 20 | continue 21 | } 22 | m := make(map[string]string) 23 | 24 | for j, column := range row { 25 | m[strings.ReplaceAll(strings.ToLower(header[j].text), " ", "_")] = column.text 26 | } 27 | 28 | if len(m) > 0 { 29 | rows = append(rows, m) 30 | } 31 | } 32 | 33 | b, err := json.Marshal(rows) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | if _, err = fmt.Fprint(w, string(b)); err != nil { 39 | return err 40 | } 41 | 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /internal/tableprinter/render_table.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package tableprinter 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | "strings" 11 | ) 12 | 13 | func (printer *TablePrinter) renderTable(w io.Writer) error { 14 | numCols := len(printer.rows[0]) 15 | colWidths := printer.calculateColumnWidths(len(printer.delimeter)) 16 | 17 | for _, row := range printer.rows { 18 | for col, field := range row { 19 | if col > 0 { 20 | _, err := fmt.Fprint(w, printer.delimeter) 21 | if err != nil { 22 | return err 23 | } 24 | } 25 | 26 | truncVal := printer.truncateFunc(colWidths[col], field.text) 27 | 28 | if col < numCols-1 { 29 | // pad value with spaces on the right 30 | if padWidth := colWidths[col] - field.DisplayWidth(); padWidth > 0 { 31 | truncVal += strings.Repeat(" ", padWidth) 32 | } 33 | } 34 | 35 | if field.color != nil { 36 | truncVal = field.color(truncVal) 37 | } 38 | 39 | _, err := fmt.Fprint(w, truncVal) 40 | if err != nil { 41 | return err 42 | } 43 | } 44 | 45 | if len(row) > 0 { 46 | _, err := fmt.Fprint(w, "\n") 47 | if err != nil { 48 | return err 49 | } 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /internal/tableprinter/render_yaml.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package tableprinter 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | "strings" 11 | 12 | "gopkg.in/yaml.v2" 13 | ) 14 | 15 | func (printer *TablePrinter) renderYAML(w io.Writer) error { 16 | header := printer.rows[0] 17 | var rows []map[string]string 18 | 19 | for i, row := range printer.rows { 20 | if i == 0 { 21 | continue 22 | } 23 | m := make(map[string]string) 24 | 25 | for j, column := range row { 26 | m[strings.ReplaceAll(strings.ToLower(header[j].text), " ", "_")] = column.text 27 | } 28 | 29 | if len(m) > 0 { 30 | rows = append(rows, m) 31 | } 32 | } 33 | 34 | b, err := yaml.Marshal(rows) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | if _, err = fmt.Fprint(w, string(b)); err != nil { 40 | return err 41 | } 42 | 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /internal/text/indent.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // 3 | // Copyright (c) 2019 GitHub Inc. 4 | // 2022 Unikraft GmbH. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | package text 25 | 26 | import ( 27 | "regexp" 28 | "strings" 29 | ) 30 | 31 | var lineRE = regexp.MustCompile(`(?m)^`) 32 | 33 | func Indent(s, indent string) string { 34 | if len(strings.TrimSpace(s)) == 0 { 35 | return s 36 | } 37 | return lineRE.ReplaceAllLiteralString(s, indent) 38 | } 39 | -------------------------------------------------------------------------------- /internal/text/sanitize.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // 3 | // Copyright (c) 2019 GitHub Inc. 4 | // 2022 Unikraft GmbH. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | package text 25 | 26 | import ( 27 | "regexp" 28 | "strings" 29 | ) 30 | 31 | var ws = regexp.MustCompile(`\s+`) 32 | 33 | func ReplaceExcessiveWhitespace(s string) string { 34 | return ws.ReplaceAllString(strings.TrimSpace(s), " ") 35 | } 36 | -------------------------------------------------------------------------------- /internal/version/version.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package version 6 | 7 | import ( 8 | "fmt" 9 | "runtime" 10 | ) 11 | 12 | var ( 13 | version = "No version provided" 14 | commit = "No commit provided" 15 | buildTime = "No build timestamp provided" 16 | agentName = "kraftkit" 17 | ) 18 | 19 | // Version returns KraftKit's version string. 20 | func Version() string { 21 | return version 22 | } 23 | 24 | // Commit return KraftKit's HEAD Git commit SHA. 25 | func Commit() string { 26 | return commit 27 | } 28 | 29 | // BuildTime returns the time in which the package or binary was built. 30 | func BuildTime() string { 31 | return buildTime 32 | } 33 | 34 | // String returns all version information. 35 | func String() string { 36 | return fmt.Sprintf("%s (%s) %s %s\n", 37 | version, 38 | commit, 39 | runtime.Version(), 40 | buildTime, 41 | ) 42 | } 43 | 44 | // UserAgent returns KraftKit's agent name and the version to be used when 45 | // making HTTP requests. 46 | func UserAgent() string { 47 | if version != "No version provided" { 48 | return fmt.Sprintf("%s/%s", agentName, version) 49 | } 50 | 51 | return agentName 52 | } 53 | -------------------------------------------------------------------------------- /internal/waitgroup/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | /* 7 | The internal `waitgroup` package is a generic which provides a synchronization 8 | lock to read observe a list of provided entities. 9 | */ 10 | package waitgroup 11 | -------------------------------------------------------------------------------- /internal/waitgroup/waitgroup.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package waitgroup 7 | 8 | import "sync" 9 | 10 | type WaitGroup[T comparable] struct { 11 | lsz sync.WaitGroup 12 | mu sync.RWMutex 13 | li []T 14 | } 15 | 16 | // Add to the wait group. 17 | func (wg *WaitGroup[T]) Add(k T) { 18 | wg.mu.Lock() 19 | defer wg.mu.Unlock() 20 | 21 | if wg.Contains(k) { 22 | return 23 | } 24 | 25 | wg.li = append(wg.li, k) 26 | wg.lsz.Add(1) 27 | } 28 | 29 | // Done signals that the provided entity can be removed from the wait group. 30 | func (wg *WaitGroup[T]) Done(needle T) { 31 | wg.mu.Lock() 32 | defer wg.mu.Unlock() 33 | 34 | if !wg.Contains(needle) { 35 | return 36 | } 37 | 38 | for i, k := range wg.li { 39 | if k == needle { 40 | wg.li = append(wg.li[:i], wg.li[i+1:]...) 41 | wg.lsz.Done() 42 | return 43 | } 44 | } 45 | } 46 | 47 | // Wait for all items in the wait group to be removed. 48 | func (wg *WaitGroup[T]) Wait() { 49 | wg.lsz.Wait() 50 | } 51 | 52 | // Contains checks if the provided entity is still in the wait group. 53 | func (wg *WaitGroup[T]) Contains(needle T) bool { 54 | for _, mid := range wg.li { 55 | if mid == needle { 56 | return true 57 | } 58 | } 59 | 60 | return false 61 | } 62 | 63 | // Items returns the list of items in the wait group. 64 | func (wg *WaitGroup[T]) Items() []T { 65 | return wg.li 66 | } 67 | -------------------------------------------------------------------------------- /iostreams/context.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package iostreams 6 | 7 | import ( 8 | "context" 9 | ) 10 | 11 | var ( 12 | // G is an alias for FromContext. 13 | // 14 | // We may want to define this locally to a package to get package tagged 15 | // iostreams. 16 | G = FromContext 17 | 18 | // L is the system IO stream. 19 | IO = System() 20 | ) 21 | 22 | // contextKey is used to retrieve the logger from the context. 23 | type contextKey struct{} 24 | 25 | // WithIOStreams returns a new context with the provided logger. Use in 26 | // combination with logger.WithField(s) for great effect. 27 | func WithIOStreams(ctx context.Context, iostreams *IOStreams) context.Context { 28 | return context.WithValue(ctx, contextKey{}, iostreams) 29 | } 30 | 31 | // FromContext returns the logger kraftkit in the context, or an inert logger 32 | // that will not log anything. 33 | func FromContext(ctx context.Context) *IOStreams { 34 | if ctx == nil { 35 | return IO 36 | } 37 | 38 | l := ctx.Value(contextKey{}) 39 | 40 | if l == nil { 41 | return IO 42 | } 43 | 44 | return l.(*IOStreams) 45 | } 46 | -------------------------------------------------------------------------------- /iostreams/epipe_other.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | // SPDX-License-Identifier: MIT 5 | // 6 | // Copyright (c) 2019 GitHub Inc. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | package iostreams 27 | 28 | import ( 29 | "errors" 30 | "syscall" 31 | ) 32 | 33 | func isEpipeError(err error) bool { 34 | return errors.Is(err, syscall.EPIPE) 35 | } 36 | -------------------------------------------------------------------------------- /iostreams/epipe_windows.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // 3 | // Copyright (c) 2019 GitHub Inc. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package iostreams 24 | 25 | import ( 26 | "errors" 27 | "syscall" 28 | ) 29 | 30 | func isEpipeError(err error) bool { 31 | // 232 is Windows error code ERROR_NO_DATA, "The pipe is being closed". 32 | return errors.Is(err, syscall.Errno(232)) 33 | } 34 | -------------------------------------------------------------------------------- /libmocktainer/README.md: -------------------------------------------------------------------------------- 1 | # libmocktainer 2 | 3 | A stripped down version of [libcontainer][1], with the bare minimum 4 | functionalities preserved for running Linux VMMs (QEMU, Firecracker) while 5 | remaining compliant with the [OCI runtime][2] flow. 6 | 7 | Its main purpose is to back Unikraft's [`runu`](../cmd/runu) OCI runtime CLI. 8 | 9 | ## Maintenance 10 | 11 | To facilitate the maintenance of this library, please be mindful and keep it as 12 | close as possible to the upstream libcontainer code. 13 | 14 | ## Copyright and license 15 | 16 | The source code of libcontainer is distributed under the terms of the [Apache 17 | 2.0 license][3], copyright 2014 Docker, inc. 18 | 19 | [1]: https://github.com/opencontainers/runc/tree/1f25724a/libcontainer#readme 20 | [2]: https://github.com/opencontainers/runtime-spec/blob/v1.1.0/runtime.md 21 | [3]: https://github.com/opencontainers/runc/blob/1f25724a/LICENSE 22 | -------------------------------------------------------------------------------- /libmocktainer/configs/namespaces.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2014 Docker, Inc. 3 | // Copyright 2023 Unikraft GmbH and The KraftKit Authors 4 | 5 | package configs 6 | 7 | type NamespaceType string 8 | 9 | type Namespaces []Namespace 10 | -------------------------------------------------------------------------------- /libmocktainer/configs/namespaces_syscall.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | // SPDX-License-Identifier: Apache-2.0 5 | // Copyright 2014 Docker, Inc. 6 | // Copyright 2023 Unikraft GmbH and The KraftKit Authors 7 | 8 | package configs 9 | 10 | import "golang.org/x/sys/unix" 11 | 12 | var namespaceInfo = map[NamespaceType]int{ 13 | NEWNET: unix.CLONE_NEWNET, 14 | } 15 | 16 | // CloneFlags parses the container's Namespaces options to set the correct 17 | // flags on clone, unshare. This function returns flags only for new namespaces. 18 | func (n *Namespaces) CloneFlags() uintptr { 19 | var flag int 20 | for _, v := range *n { 21 | if v.Path != "" { 22 | continue 23 | } 24 | flag |= namespaceInfo[v.Type] 25 | } 26 | return uintptr(flag) 27 | } 28 | -------------------------------------------------------------------------------- /libmocktainer/configs/validate/validator.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2014 Docker, Inc. 3 | // Copyright 2023 Unikraft GmbH and The KraftKit Authors 4 | 5 | package validate 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "os" 11 | "path/filepath" 12 | 13 | "kraftkit.sh/libmocktainer/configs" 14 | ) 15 | 16 | type check func(config *configs.Config) error 17 | 18 | func Validate(config *configs.Config) error { 19 | checks := []check{ 20 | rootfs, 21 | } 22 | for _, c := range checks { 23 | if err := c(config); err != nil { 24 | return err 25 | } 26 | } 27 | return nil 28 | } 29 | 30 | // rootfs validates if the rootfs is an absolute path and is not a symlink 31 | // to the container's root filesystem. 32 | func rootfs(config *configs.Config) error { 33 | if _, err := os.Stat(config.Rootfs); err != nil { 34 | return fmt.Errorf("invalid rootfs: %w", err) 35 | } 36 | cleaned, err := filepath.Abs(config.Rootfs) 37 | if err != nil { 38 | return fmt.Errorf("invalid rootfs: %w", err) 39 | } 40 | if cleaned, err = filepath.EvalSymlinks(cleaned); err != nil { 41 | return fmt.Errorf("invalid rootfs: %w", err) 42 | } 43 | if filepath.Clean(config.Rootfs) != cleaned { 44 | return errors.New("invalid rootfs: not an absolute path, or a symlink") 45 | } 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /libmocktainer/container.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2014 Docker, Inc. 3 | // Copyright 2023 Unikraft GmbH and The KraftKit Authors 4 | 5 | package libmocktainer 6 | 7 | import ( 8 | "time" 9 | 10 | "kraftkit.sh/libmocktainer/configs" 11 | ) 12 | 13 | // Status is the status of a container. 14 | type Status int 15 | 16 | const ( 17 | // Created is the status that denotes the container exists but has not been run yet. 18 | Created Status = iota 19 | // Running is the status that denotes the container exists and is running. 20 | Running 21 | // Stopped is the status that denotes the container does not have a created or running process. 22 | Stopped 23 | ) 24 | 25 | func (s Status) String() string { 26 | switch s { 27 | case Created: 28 | return "created" 29 | case Running: 30 | return "running" 31 | case Stopped: 32 | return "stopped" 33 | default: 34 | return "unknown" 35 | } 36 | } 37 | 38 | // BaseState represents the platform agnostic pieces relating to a 39 | // running container's state 40 | type BaseState struct { 41 | // ID is the container ID. 42 | ID string `json:"id"` 43 | 44 | // InitProcessPid is the init process id in the parent namespace. 45 | InitProcessPid int `json:"init_process_pid"` 46 | 47 | // InitProcessStartTime is the init process start time in clock cycles since boot time. 48 | InitProcessStartTime uint64 `json:"init_process_start"` 49 | 50 | // Created is the unix timestamp for the creation time of the container in UTC 51 | Created time.Time `json:"created"` 52 | 53 | // Config is the container's configuration. 54 | Config configs.Config `json:"config"` 55 | } 56 | -------------------------------------------------------------------------------- /libmocktainer/error.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2014 Docker, Inc. 3 | // Copyright 2023 Unikraft GmbH and The KraftKit Authors 4 | 5 | package libmocktainer 6 | 7 | import "errors" 8 | 9 | var ( 10 | ErrExist = errors.New("container with given ID already exists") 11 | ErrInvalidID = errors.New("invalid container ID format") 12 | ErrNotExist = errors.New("container does not exist") 13 | ErrRunning = errors.New("container still running") 14 | ErrNotRunning = errors.New("container not running") 15 | ) 16 | -------------------------------------------------------------------------------- /libmocktainer/network_linux.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2014 Docker, Inc. 3 | // Copyright 2023 Unikraft GmbH and The KraftKit Authors 4 | 5 | package libmocktainer 6 | 7 | import ( 8 | "fmt" 9 | 10 | "github.com/vishvananda/netlink" 11 | 12 | "kraftkit.sh/libmocktainer/configs" 13 | ) 14 | 15 | var strategies = map[string]networkStrategy{ 16 | "loopback": &loopback{}, 17 | } 18 | 19 | // networkStrategy represents a specific network configuration for 20 | // a container's networking stack 21 | type networkStrategy interface { 22 | create(*network, int) error 23 | initialize(*network) error 24 | detach(*configs.Network) error 25 | attach(*configs.Network) error 26 | } 27 | 28 | // getStrategy returns the specific network strategy for the 29 | // provided type. 30 | func getStrategy(tpe string) (networkStrategy, error) { 31 | s, exists := strategies[tpe] 32 | if !exists { 33 | return nil, fmt.Errorf("unknown strategy type %q", tpe) 34 | } 35 | return s, nil 36 | } 37 | 38 | // loopback is a network strategy that provides a basic loopback device 39 | type loopback struct{} 40 | 41 | func (l *loopback) create(n *network, nspid int) error { 42 | return nil 43 | } 44 | 45 | func (l *loopback) initialize(config *network) error { 46 | return netlink.LinkSetUp(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: "lo"}}) 47 | } 48 | 49 | func (l *loopback) attach(n *configs.Network) (err error) { 50 | return nil 51 | } 52 | 53 | func (l *loopback) detach(n *configs.Network) (err error) { 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /libmocktainer/restored_process.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2014 Docker, Inc. 3 | // Copyright 2023 Unikraft GmbH and The KraftKit Authors 4 | 5 | package libmocktainer 6 | 7 | import ( 8 | "errors" 9 | "os" 10 | ) 11 | 12 | // nonChildProcess represents a process where the calling process is not 13 | // the parent process. This process is created when Load loads a container 14 | // from a persisted state. 15 | type nonChildProcess struct { 16 | processPid int 17 | processStartTime uint64 18 | } 19 | 20 | func (p *nonChildProcess) start() error { 21 | return errors.New("restored process cannot be started") 22 | } 23 | 24 | func (p *nonChildProcess) pid() int { 25 | return p.processPid 26 | } 27 | 28 | func (p *nonChildProcess) terminate() error { 29 | return errors.New("restored process cannot be terminated") 30 | } 31 | 32 | func (p *nonChildProcess) wait() (*os.ProcessState, error) { 33 | return nil, errors.New("restored process cannot be waited on") 34 | } 35 | 36 | func (p *nonChildProcess) startTime() (uint64, error) { 37 | return p.processStartTime, nil 38 | } 39 | 40 | func (p *nonChildProcess) signal(s os.Signal) error { 41 | proc, err := os.FindProcess(p.processPid) 42 | if err != nil { 43 | return err 44 | } 45 | return proc.Signal(s) 46 | } 47 | 48 | func (p *nonChildProcess) externalDescriptors() []string { 49 | return nil 50 | } 51 | 52 | func (p *nonChildProcess) setExternalDescriptors([]string) { 53 | } 54 | 55 | func (p *nonChildProcess) forwardChildLogs() chan error { 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /libmocktainer/unikraft/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | // Package unikraft contains libmocktainer code that is not in upstream libcontainer. 7 | package unikraft 8 | -------------------------------------------------------------------------------- /log/context.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package log 6 | 7 | import ( 8 | "context" 9 | 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | var ( 14 | // G is an alias for FromContext. 15 | // 16 | // We may want to define this locally to a package to get package tagged log 17 | // messages. 18 | G = FromContext 19 | 20 | // L is the global logger. 21 | L = logrus.StandardLogger() 22 | ) 23 | 24 | // contextKey is used to retrieve the logger from the context. 25 | type contextKey struct{} 26 | 27 | // WithLogger returns a new context with the provided logger. Use in 28 | // combination with logger.WithField(s) for great effect. 29 | func WithLogger(ctx context.Context, logger *logrus.Logger) context.Context { 30 | return context.WithValue(ctx, contextKey{}, logger) 31 | } 32 | 33 | // FromContext returns the logger kraftkit in the context, or an inert logger 34 | // that will not log anything. 35 | func FromContext(ctx context.Context) *logrus.Logger { 36 | l, ok := ctx.Value(contextKey{}).(*logrus.Logger) 37 | if !ok || l == nil { 38 | return L 39 | } 40 | 41 | return l 42 | } 43 | -------------------------------------------------------------------------------- /log/levels.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package log 6 | 7 | import "github.com/sirupsen/logrus" 8 | 9 | // Levels returns a map of log level string names to their constant equivalent. 10 | func Levels() map[string]logrus.Level { 11 | return map[string]logrus.Level{ 12 | "panic": logrus.PanicLevel, 13 | "fatal": logrus.FatalLevel, 14 | "error": logrus.ErrorLevel, 15 | "warning": logrus.WarnLevel, 16 | "warn": logrus.WarnLevel, 17 | "info": logrus.InfoLevel, 18 | "debug": logrus.DebugLevel, 19 | "trace": logrus.TraceLevel, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /log/type.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package log 6 | 7 | import "strings" 8 | 9 | // LoggerType controls how log statements are output 10 | type LoggerType uint 11 | 12 | // Logger types 13 | const ( 14 | QUIET LoggerType = iota 15 | BASIC 16 | FANCY 17 | JSON 18 | ) 19 | 20 | func LoggerTypeFromString(name string) LoggerType { 21 | name = strings.ToLower(name) 22 | switch name { 23 | case "quiet": 24 | return QUIET 25 | case "basic": 26 | return BASIC 27 | case "fancy": 28 | return FANCY 29 | case "json": 30 | return JSON 31 | default: 32 | return BASIC 33 | } 34 | } 35 | 36 | func LoggerTypeToString(t LoggerType) string { 37 | switch t { 38 | case QUIET: 39 | return "quiet" 40 | case BASIC: 41 | return "basic" 42 | case FANCY: 43 | return "fancy" 44 | case JSON: 45 | return "json" 46 | default: 47 | return "basic" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /machine/firecracker/config.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package firecracker 6 | 7 | // FirecrackerConfig is a subset of the Firecracker's Go SDK structure of the 8 | // same format. We use this subset because these are the only attribute 9 | // necessary and additionally, gob cannot register some of the embedded types. 10 | type FirecrackerConfig struct { 11 | SocketPath string `json:"socketPath,omitempty"` 12 | BootArgs string `json:"bootArgs,omitempty"` 13 | LogPath string `json:"logPath,omitempty"` 14 | 15 | // TODO(craciunouc): This is a temporary solution until we have proper 16 | // un/marshalling of the resources (and all structures). 17 | Memory string `json:"memory,omitempty"` 18 | } 19 | -------------------------------------------------------------------------------- /machine/firecracker/init.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package firecracker 6 | 7 | import "encoding/gob" 8 | 9 | func init() { 10 | gob.Register(FirecrackerConfig{}) 11 | } 12 | -------------------------------------------------------------------------------- /machine/firecracker/v1alpha1_options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package firecracker 6 | 7 | import "time" 8 | 9 | // MachineServiceV1alpha1Option represents an option-method handler for the 10 | // machinev1alpha1 service. 11 | type MachineServiceV1alpha1Option func(*machineV1alpha1Service) error 12 | 13 | // WithTimeout sets the time out when communicating with the firecracker socket 14 | // API. 15 | func WithTimeout(timeout time.Duration) MachineServiceV1alpha1Option { 16 | return func(service *machineV1alpha1Service) error { 17 | service.timeout = timeout 18 | return nil 19 | } 20 | } 21 | 22 | // WithDebug enables firecracker's internal debugging. 23 | func WithDebug(debug bool) MachineServiceV1alpha1Option { 24 | return func(service *machineV1alpha1Service) error { 25 | service.debug = debug 26 | return nil 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /machine/network/bridge/bridge.go: -------------------------------------------------------------------------------- 1 | package bridge 2 | 3 | import ( 4 | "encoding/gob" 5 | 6 | "github.com/vishvananda/netlink" 7 | ) 8 | 9 | const ( 10 | // DefaultMTU is the default MTU for new bridge interfaces. 11 | DefaultMTU = 1500 12 | ) 13 | 14 | func init() { 15 | gob.Register(&netlink.Bridge{}) 16 | } 17 | -------------------------------------------------------------------------------- /machine/network/iputils/iputils.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package iputils 7 | 8 | import ( 9 | "encoding/binary" 10 | "math/big" 11 | "net" 12 | ) 13 | 14 | // IpToBigInt converts a 4 bytes IP into a 128 bit integer. 15 | func IPToBigInt(ip net.IP) *big.Int { 16 | x := big.NewInt(0) 17 | if ip4 := ip.To4(); ip4 != nil { 18 | return x.SetBytes(ip4) 19 | } 20 | if ip6 := ip.To16(); ip6 != nil { 21 | return x.SetBytes(ip6) 22 | } 23 | return nil 24 | } 25 | 26 | // BigIntToIP converts 128 bit integer into a 4 bytes IP address. 27 | func BigIntToIP(v *big.Int) net.IP { 28 | return net.IP(v.Bytes()) 29 | } 30 | 31 | // Increases IP address numeric value by 1. 32 | func IncreaseIP(ip net.IP) net.IP { 33 | rawip := IPToBigInt(ip) 34 | rawip.Add(rawip, big.NewInt(1)) 35 | return BigIntToIP(rawip) 36 | } 37 | 38 | // IsUnicastIP returns true if the provided IP address and network mask is a 39 | // unicast address. 40 | func IsUnicastIP(ip net.IP, mask net.IPMask) bool { 41 | // broadcast v4 ip 42 | if len(ip) == net.IPv4len && binary.BigEndian.Uint32(ip)&^binary.BigEndian.Uint32(mask) == ^binary.BigEndian.Uint32(mask) { 43 | return false 44 | } 45 | 46 | // global unicast 47 | return ip.IsGlobalUnicast() 48 | } 49 | -------------------------------------------------------------------------------- /machine/network/register_darwin.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package network 6 | 7 | import ( 8 | "context" 9 | "errors" 10 | 11 | networkv1alpha1 "kraftkit.sh/api/network/v1alpha1" 12 | ) 13 | 14 | var defaultStrategyName = "bridge" 15 | 16 | // hostSupportedStrategies returns the map of known supported drivers for the 17 | // given host. 18 | func hostSupportedStrategies() map[string]*Strategy { 19 | return map[string]*Strategy{ 20 | "bridge": { 21 | NewNetworkV1alpha1: func(ctx context.Context, opts ...any) (networkv1alpha1.NetworkService, error) { 22 | return nil, errors.New("network service is not supported on MacOS") 23 | }, 24 | }, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /machine/network/register_freebsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package network 6 | 7 | import ( 8 | "context" 9 | "errors" 10 | 11 | networkv1alpha1 "kraftkit.sh/api/network/v1alpha1" 12 | ) 13 | 14 | var defaultStrategyName = "bridge" 15 | 16 | // hostSupportedStrategies returns the map of known supported drivers for the 17 | // given host. 18 | func hostSupportedStrategies() map[string]*Strategy { 19 | return map[string]*Strategy{ 20 | "bridge": { 21 | NewNetworkV1alpha1: func(ctx context.Context, opts ...any) (networkv1alpha1.NetworkService, error) { 22 | return nil, errors.New("network service is not supported on freeBSD") 23 | }, 24 | }, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /machine/network/register_linux.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package network 6 | 7 | import ( 8 | "context" 9 | "path/filepath" 10 | 11 | zip "api.zip" 12 | 13 | networkv1alpha1 "kraftkit.sh/api/network/v1alpha1" 14 | "kraftkit.sh/config" 15 | "kraftkit.sh/machine/network/bridge" 16 | "kraftkit.sh/store" 17 | ) 18 | 19 | var defaultStrategyName = "bridge" 20 | 21 | // hostSupportedStrategies returns the map of known supported drivers for the 22 | // given host. 23 | func hostSupportedStrategies() map[string]*Strategy { 24 | return map[string]*Strategy{ 25 | "bridge": { 26 | NewNetworkV1alpha1: func(ctx context.Context, opts ...any) (networkv1alpha1.NetworkService, error) { 27 | service, err := bridge.NewNetworkServiceV1alpha1(ctx, opts...) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | embeddedStore, err := store.NewEmbeddedStore[networkv1alpha1.NetworkSpec, networkv1alpha1.NetworkStatus]( 33 | filepath.Join( 34 | config.G[config.KraftKit](ctx).RuntimeDir, 35 | "networkv1alpha1", 36 | ), 37 | ) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | return networkv1alpha1.NewNetworkServiceHandler( 43 | ctx, 44 | service, 45 | zip.WithStore[networkv1alpha1.NetworkSpec, networkv1alpha1.NetworkStatus](embeddedStore, zip.StoreRehydrationSpecNil), 46 | ) 47 | }, 48 | }, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /machine/network/register_netbsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package network 6 | 7 | import ( 8 | "context" 9 | "errors" 10 | 11 | networkv1alpha1 "kraftkit.sh/api/network/v1alpha1" 12 | ) 13 | 14 | var defaultStrategyName = "bridge" 15 | 16 | // hostSupportedStrategies returns the map of known supported drivers for the 17 | // given host. 18 | func hostSupportedStrategies() map[string]*Strategy { 19 | return map[string]*Strategy{ 20 | "bridge": { 21 | NewNetworkV1alpha1: func(ctx context.Context, opts ...any) (networkv1alpha1.NetworkService, error) { 22 | return nil, errors.New("network service is not supported on netBSD") 23 | }, 24 | }, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /machine/network/register_openbsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package network 6 | 7 | import ( 8 | "context" 9 | "errors" 10 | 11 | networkv1alpha1 "kraftkit.sh/api/network/v1alpha1" 12 | ) 13 | 14 | var defaultStrategyName = "bridge" 15 | 16 | // hostSupportedStrategies returns the map of known supported drivers for the 17 | // given host. 18 | func hostSupportedStrategies() map[string]*Strategy { 19 | return map[string]*Strategy{ 20 | "bridge": { 21 | NewNetworkV1alpha1: func(ctx context.Context, opts ...any) (networkv1alpha1.NetworkService, error) { 22 | return nil, errors.New("network service is not supported on openBSD") 23 | }, 24 | }, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /machine/network/register_windows.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package network 6 | 7 | import ( 8 | "context" 9 | "errors" 10 | 11 | networkv1alpha1 "kraftkit.sh/api/network/v1alpha1" 12 | ) 13 | 14 | var defaultStrategyName = "bridge" 15 | 16 | // hostSupportedStrategies returns the map of known supported drivers for the 17 | // given host. 18 | func hostSupportedStrategies() map[string]*Strategy { 19 | return map[string]*Strategy{ 20 | "bridge": { 21 | NewNetworkV1alpha1: func(ctx context.Context, opts ...any) (networkv1alpha1.NetworkService, error) { 22 | return nil, errors.New("network service is not supported on Windows") 23 | }, 24 | }, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /machine/network/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package network 7 | 8 | import "net" 9 | 10 | // NetworksIntersect returns whether two networks have any common IP addresses. 11 | func NetworksIntersect(a, b net.IPNet) bool { 12 | return a.Contains(b.IP) || b.Contains(a.IP) 13 | } 14 | -------------------------------------------------------------------------------- /machine/platform/detect_windows.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package platform 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | ) 11 | 12 | type SystemMode string 13 | 14 | const ( 15 | SystemUnknown = SystemMode("unknown") 16 | SystemGuest = SystemMode("guest") 17 | SystemHost = SystemMode("host") 18 | ) 19 | 20 | // Detect returns the hypervisor and system mode in the context to the 21 | // determined hypervisor or an error if not detectable. 22 | func Detect(ctx context.Context) (Platform, SystemMode, error) { 23 | return PlatformUnknown, SystemUnknown, fmt.Errorf("Hypervisor detection is not supported on Windows") 24 | } 25 | -------------------------------------------------------------------------------- /machine/platform/register_darwin.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package platform 6 | 7 | func unixVariantStrategies() map[Platform]*Strategy { 8 | // Nothing added for Darwin 9 | return map[Platform]*Strategy{} 10 | } 11 | -------------------------------------------------------------------------------- /machine/platform/register_freebsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package platform 6 | 7 | func unixVariantStrategies() map[Platform]*Strategy { 8 | return map[Platform]*Strategy{} 9 | } 10 | -------------------------------------------------------------------------------- /machine/platform/register_netbsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package platform 6 | 7 | func unixVariantStrategies() map[Platform]*Strategy { 8 | return map[Platform]*Strategy{} 9 | } 10 | -------------------------------------------------------------------------------- /machine/platform/register_openbsd.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package platform 6 | 7 | func unixVariantStrategies() map[Platform]*Strategy { 8 | return map[Platform]*Strategy{} 9 | } 10 | -------------------------------------------------------------------------------- /machine/platform/register_windows.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package platform 6 | 7 | // hostSupportedStrategies returns the map of known supported drivers for the 8 | // given host. 9 | // No drivers are supported on Windows currently. Future HyperV support is possible. 10 | func hostSupportedStrategies() map[Platform]*Strategy { 11 | s := map[Platform]*Strategy{} 12 | 13 | return s 14 | } 15 | -------------------------------------------------------------------------------- /machine/qemu/buf.lock: -------------------------------------------------------------------------------- 1 | # Generated by buf. DO NOT EDIT. 2 | version: v1 3 | -------------------------------------------------------------------------------- /machine/qemu/buf.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | name: buf.build/krafkit/qemu 3 | breaking: 4 | use: 5 | - FILE 6 | lint: 7 | use: 8 | - DEFAULT 9 | -------------------------------------------------------------------------------- /machine/qemu/qemu_memory.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package qemu 6 | 7 | import ( 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | type QemuMemoryUnit string 13 | 14 | const ( 15 | QemuMemoryUnitMB = QemuMemoryUnit("M") 16 | QemuMemoryUnitGB = QemuMemoryUnit("G") 17 | ) 18 | 19 | type QemuMemory struct { 20 | Size uint64 `json:"size,omitempty"` 21 | Unit QemuMemoryUnit `json:"unit,omitempty"` 22 | Slots uint64 `json:"slots,omitempty"` 23 | MaxMem string `json:"max_mem,omitempty"` 24 | } 25 | 26 | const ( 27 | QemuMemoryDefault = 64 28 | QemuMemoryScale = 1024 * 1024 29 | ) 30 | 31 | func (qm QemuMemory) String() string { 32 | if qm.Size == 0 && len(qm.Unit) == 0 { 33 | return "" 34 | } 35 | 36 | var ret strings.Builder 37 | 38 | if qm.Size == 0 { 39 | qm.Size = QemuMemoryDefault 40 | } 41 | if len(qm.Unit) == 0 { 42 | qm.Unit = QemuMemoryUnitMB 43 | } 44 | 45 | ret.WriteString("size=") 46 | ret.WriteString(strconv.FormatUint(qm.Size, 10)) 47 | ret.WriteString(string(qm.Unit)) 48 | 49 | if qm.Slots > 0 { 50 | ret.WriteString("slots=") 51 | ret.WriteString(strconv.FormatUint(qm.Slots, 10)) 52 | } 53 | 54 | if len(qm.MaxMem) > 0 { 55 | ret.WriteString("maxmem=") 56 | ret.WriteString(qm.MaxMem) 57 | } 58 | 59 | return ret.String() 60 | } 61 | -------------------------------------------------------------------------------- /machine/qemu/qemu_system.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package qemu 6 | 7 | const ( 8 | QemuSystemX86 = "qemu-system-x86_64" 9 | QemuSystemArm = "qemu-system-arm" 10 | QemuSystemAarch64 = "qemu-system-aarch64" 11 | ) 12 | -------------------------------------------------------------------------------- /machine/qemu/qemu_vga.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package qemu 6 | 7 | type QemuVGA string 8 | 9 | const ( 10 | QemuVGAStd = QemuVGA("std") 11 | QemuVGACirrus = QemuVGA("cirrus") 12 | QemuVGAVMWare = QemuVGA("vmware") 13 | QemuVGAQxl = QemuVGA("qxl") 14 | QemuVGAXenFb = QemuVGA("xenfb") 15 | QemuVGATCX = QemuVGA("tcx") 16 | QemuVGACG3 = QemuVGA("cg3") 17 | QemuVGAVirtio = QemuVGA("virtio") 18 | QemuVGANone = QemuVGA("none") 19 | ) 20 | 21 | func (qa QemuVGA) String() string { 22 | return string(qa) 23 | } 24 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/control.pb.netconn.go: -------------------------------------------------------------------------------- 1 | // Code generated by kraftkit.sh/tools/protoc-gen-go-netconn. DO NOT EDIT. 2 | // source: machine/qemu/qmp/v7alpha2/control.proto 3 | 4 | package qmpv7alpha2 5 | 6 | type Capability string 7 | 8 | const ( 9 | oob = Capability("oob") 10 | ) 11 | 12 | func (e Capability) String() string { 13 | return string(e) 14 | } 15 | 16 | func Capabilitys() []Capability { 17 | return []Capability{ 18 | oob, 19 | } 20 | } 21 | 22 | type CapabilitiesRequest struct { 23 | Execute string `json:"execute" default:"qmp_capabilities"` 24 | 25 | Arguments CapabilitiesRequestArguments `json:"arguments,omitempty"` 26 | } 27 | 28 | type CapabilitiesRequestArguments struct { 29 | Enable []Capability `json:"enable"` 30 | } 31 | 32 | type QuitRequest struct { 33 | Execute string `json:"execute" default:"quit"` 34 | } 35 | 36 | type QuitResponse struct { 37 | } 38 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/control.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | syntax = "proto3"; 6 | 7 | package qmp.v1alpha; 8 | 9 | import "machine/qemu/qmp/v7alpha2/descriptor.proto"; 10 | 11 | option go_package = "kraftkit.sh/machine/qemu/qmp/v7alpha2;qmpv7alpha2"; 12 | 13 | enum Capability { 14 | oob = 0; 15 | } 16 | 17 | message CapabilitiesRequest { 18 | option (execute) = "qmp_capabilities"; 19 | message Arguments { 20 | repeated Capability enable = 1 [ json_name = "enable" ]; 21 | } 22 | Arguments arguments = 1 [ json_name = "arguments,omitempty" ]; 23 | } 24 | 25 | message QuitRequest { 26 | option (execute) = "quit"; 27 | } 28 | 29 | message QuitResponse {} 30 | 31 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/descriptor.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | syntax = "proto3"; 6 | 7 | package qmp.v1alpha; 8 | 9 | import "google/protobuf/any.proto"; 10 | import "google/protobuf/descriptor.proto"; 11 | 12 | option go_package = "kraftkit.sh/machine/qemu/qmp/v7alpha2;qmpv7alpha2"; 13 | 14 | extend google.protobuf.MessageOptions { 15 | string execute = 51000; 16 | } 17 | 18 | extend google.protobuf.EnumValueOptions { 19 | string json_name = 51001; 20 | string map_message = 51002; 21 | } 22 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/error.pb.netconn.go: -------------------------------------------------------------------------------- 1 | // Code generated by kraftkit.sh/tools/protoc-gen-go-netconn. DO NOT EDIT. 2 | // source: machine/qemu/qmp/v7alpha2/error.proto 3 | 4 | package qmpv7alpha2 5 | 6 | type ErrorResponse struct { 7 | Class string `json:"class"` 8 | Cescription string `json:"desc"` 9 | } 10 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/error.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | syntax = "proto3"; 6 | 7 | package qmp.v1alpha; 8 | 9 | option go_package = "kraftkit.sh/machine/qemu/qmp/v7alpha2;qmpv7alpha2"; 10 | 11 | message ErrorResponse { 12 | string class = 1 [ json_name = "class" ]; 13 | string cescription = 2 [ json_name = "desc" ]; 14 | } 15 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/greeting.pb.netconn.go: -------------------------------------------------------------------------------- 1 | // Code generated by kraftkit.sh/tools/protoc-gen-go-netconn. DO NOT EDIT. 2 | // source: machine/qemu/qmp/v7alpha2/greeting.proto 3 | 4 | package qmpv7alpha2 5 | 6 | type GreetingVersionTriple struct { 7 | Major uint32 `json:"major"` 8 | Minor uint32 `json:"minor"` 9 | Micro uint32 `json:"micro"` 10 | } 11 | 12 | type GreetingVersion struct { 13 | Qemu GreetingVersionTriple `json:"qemu"` 14 | Package string `json:"package"` 15 | } 16 | 17 | type Greeting struct { 18 | Version GreetingVersion `json:"version"` 19 | Capabilities []Capability `json:"capabilities"` 20 | } 21 | 22 | type GreetingResponse struct { 23 | Qmp Greeting `json:"QMP"` 24 | } 25 | 26 | type GreetingRequest struct { 27 | } 28 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/greeting.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | syntax = "proto3"; 6 | 7 | package qmp.v1alpha; 8 | 9 | import "machine/qemu/qmp/v7alpha2/control.proto"; 10 | 11 | option go_package = "kraftkit.sh/machine/qemu/qmp/v7alpha2;qmpv7alpha2"; 12 | 13 | message GreetingVersionTriple { 14 | uint32 major = 1 [ json_name = "major" ]; 15 | uint32 minor = 2 [ json_name = "minor" ]; 16 | uint32 micro = 3 [ json_name = "micro" ]; 17 | } 18 | 19 | message GreetingVersion { 20 | GreetingVersionTriple qemu = 1 [ json_name = "qemu" ]; 21 | string package = 2 [ json_name = "package" ]; 22 | } 23 | 24 | message Greeting { 25 | GreetingVersion version = 1 [ json_name = "version" ]; 26 | repeated Capability capabilities = 2 [ json_name = "capabilities" ]; 27 | } 28 | 29 | message GreetingResponse { 30 | Greeting qmp = 1 [ json_name = "QMP" ]; 31 | } 32 | 33 | message GreetingRequest {} 34 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/machine.pb.netconn.go: -------------------------------------------------------------------------------- 1 | // Code generated by kraftkit.sh/tools/protoc-gen-go-netconn. DO NOT EDIT. 2 | // source: machine/qemu/qmp/v7alpha2/machine.proto 3 | 4 | package qmpv7alpha2 5 | 6 | type QueryKvmRequest struct { 7 | Execute string `json:"execute" default:"query-kvm"` 8 | } 9 | 10 | type KvmInfo struct { 11 | Enabled bool `json:"enabled"` 12 | Present bool `json:"present"` 13 | } 14 | 15 | type QueryKvmResponse struct { 16 | Return KvmInfo `json:"return"` 17 | } 18 | 19 | type SystemResetRequest struct { 20 | Execute string `json:"execute" default:"system_reset"` 21 | } 22 | 23 | type SystemPowerdownRequest struct { 24 | Execute string `json:"execute" default:"system_powerdown"` 25 | } 26 | 27 | type SystemWakeupRequest struct { 28 | Execute string `json:"execute" default:"system_Wakeup"` 29 | } 30 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/machine.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | syntax = "proto3"; 6 | 7 | package qmp.v1alpha; 8 | 9 | import "machine/qemu/qmp/v7alpha2/descriptor.proto"; 10 | 11 | option go_package = "kraftkit.sh/machine/qemu/qmp/v7alpha2;qmpv7alpha2"; 12 | 13 | message QueryKvmRequest { 14 | option (execute) = "query-kvm"; 15 | } 16 | 17 | message KvmInfo { 18 | bool enabled = 1 [ json_name = "enabled" ]; 19 | bool present = 2 [ json_name = "present" ]; 20 | } 21 | 22 | message QueryKvmResponse { 23 | KvmInfo return = 1 [ json_name = "return" ]; 24 | } 25 | 26 | message SystemResetRequest { 27 | option (execute) = "system_reset"; 28 | } 29 | 30 | message SystemPowerdownRequest { 31 | option (execute) = "system_powerdown"; 32 | } 33 | 34 | message SystemWakeupRequest { 35 | option (execute) = "system_Wakeup"; 36 | } 37 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/misc.pb.netconn.go: -------------------------------------------------------------------------------- 1 | // Code generated by kraftkit.sh/tools/protoc-gen-go-netconn. DO NOT EDIT. 2 | // source: machine/qemu/qmp/v7alpha2/misc.proto 3 | 4 | package qmpv7alpha2 5 | 6 | type StopRequest struct { 7 | Execute string `json:"execute" default:"stop"` 8 | } 9 | 10 | type StopResponse struct { 11 | } 12 | 13 | type ContRequest struct { 14 | Execute string `json:"execute" default:"cont"` 15 | } 16 | 17 | type ContResponse struct { 18 | } 19 | -------------------------------------------------------------------------------- /machine/qemu/qmp/v7alpha2/misc.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | syntax = "proto3"; 6 | 7 | package qmp.v1alpha; 8 | 9 | import "machine/qemu/qmp/v7alpha2/descriptor.proto"; 10 | 11 | option go_package = "kraftkit.sh/machine/qemu/qmp/v7alpha2;qmpv7alpha2"; 12 | 13 | message StopRequest { 14 | option (execute) = "stop"; 15 | } 16 | 17 | message StopResponse {} 18 | 19 | message ContRequest { 20 | option (execute) = "cont"; 21 | } 22 | 23 | message ContResponse {} 24 | -------------------------------------------------------------------------------- /machine/qemu/v1alpha1_options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package qemu 6 | 7 | import "kraftkit.sh/exec" 8 | 9 | // MachineServiceV1alpha1Option represents an option-method handler for the 10 | // machinev1alpha1 service. 11 | type MachineServiceV1alpha1Option func(*machineV1alpha1Service) error 12 | 13 | // WithExecOptions passes additional kraftkit.sh/exec options to any sub-process 14 | // invocation called within the machine service. 15 | func WithExecOptions(eopts ...exec.ExecOption) MachineServiceV1alpha1Option { 16 | return func(service *machineV1alpha1Service) error { 17 | service.eopts = eopts 18 | return nil 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /machine/xen/README.md: -------------------------------------------------------------------------------- 1 | ## Xen Integration Versioning 2 | 3 | Xen functionality is broken up into a hypervisor <-> library relationship. 4 | Even if those are decoupled, they need to be within an acceptable version distance of each other. 5 | We currently have confirmed integration with Xen 4.19 and possibly the 4.20-rc versions that are in the works. 6 | 7 | ### Changing Xen versions from 4.19 8 | 9 | In order to make krafkit work with an older version, it must be recompiled for that version. 10 | Fastest way to do this would be to follow this set of commands: 11 | 1. Change the version to an older one: 12 | ```console 13 | $ find . -type f -exec sed -i 's/4.19/4.18/g' {} + 14 | ``` 15 | 16 | 2. Get the library version corresponding to that one: 17 | ```console 18 | $ go get -u xenbits.xenproject.org/git-http/xen.git/tools/golang/xenlight@RELEASE-4.18.0 && go mod tidy 19 | ``` 20 | 21 | 3. Rebuild the KraftKit build environment: 22 | ```console 23 | $ make buildenv-xen buildenv-myself-full buildenv-myself 24 | ``` 25 | 26 | 4. Start the build container: 27 | ```console 28 | $ docker run --rm -it --entrypoint /bin/bash -v .:/tmp/kraftkit kraftkit.sh/myself-full:latest 29 | ``` 30 | 31 | 5. Rebuild KraftKit: 32 | ```console 33 | $ cd /tmp/kraftkit && make kraft 34 | ``` 35 | 36 | That's it! 37 | Your binary is now located at `dist/kraft`. 38 | Remember that you need to use `sudo` in order to interact with Xen. 39 | -------------------------------------------------------------------------------- /machine/xen/init.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | //go:build xen 7 | // +build xen 8 | 9 | package xen 10 | 11 | import ( 12 | "encoding/gob" 13 | 14 | "xenbits.xenproject.org/git-http/xen.git/tools/golang/xenlight" 15 | ) 16 | 17 | func init() { 18 | gob.Register(xenlight.Domid(0)) 19 | } 20 | -------------------------------------------------------------------------------- /machine/xen/stub.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | //go:build !xen 7 | // +build !xen 8 | 9 | package xen 10 | 11 | import ( 12 | "context" 13 | "fmt" 14 | 15 | machinev1alpha1 "kraftkit.sh/api/machine/v1alpha1" 16 | ) 17 | 18 | func NewMachineV1alpha1Service(ctx context.Context) (machinev1alpha1.MachineService, error) { 19 | return nil, fmt.Errorf("xen is not supported") 20 | } 21 | -------------------------------------------------------------------------------- /make/value.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package make 6 | 7 | // ConditionalValue represents an expression in a Makefile in the form of 8 | // `VARIABLE-$(CONDITION) += VALUE`. This is a typical convention in C-based 9 | // projects where the `$(CONDITION)` variable either resolves itself to a 10 | // variable or value, e.g. `y`. 11 | type ConditionalValue struct { 12 | DependsOn *string 13 | Value string 14 | } 15 | -------------------------------------------------------------------------------- /oci/annotations.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package oci 6 | 7 | const ( 8 | AnnotationMediaType = "org.unikraft.mediaType" 9 | AnnotationName = "org.unikraft.image.name" 10 | AnnotationVersion = "org.unikraft.image.version" 11 | AnnotationURL = "org.unikraft.image.url" 12 | AnnotationCreated = "org.unikraft.image.created" 13 | AnnotaitonDescription = "org.unikraft.image.description" 14 | AnnotationKernelPath = "org.unikraft.kernel.image" 15 | AnnotationKernelDbgPath = "org.unikraft.kernel.imagedbg" 16 | AnnotationKernelVersion = "org.unikraft.kernel.version" 17 | AnnotationKernelInitrdPath = "org.unikraft.kernel.initrd" 18 | AnnotationKernelKConfig = "org.unikraft.kernel.kconfig." 19 | AnnotationKernelArch = "org.unikraft.kernel.arch" 20 | AnnotationKernelPlat = "org.unikraft.kernel.plat" 21 | AnnotationFilesystemPath = "org.unikraft.filesystem" 22 | AnnotationDiskIndexPathPattern = "org.unikraft.disk-%d" 23 | AnnotationKraftKitVersion = "sh.kraftkit.version" 24 | ) 25 | -------------------------------------------------------------------------------- /oci/blob_options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package oci 6 | 7 | import ocispec "github.com/opencontainers/image-spec/specs-go/v1" 8 | 9 | type BlobOption func(*Blob) error 10 | 11 | // WithBlobRemoveAfterSave atomizes each operation on the blob. 12 | func WithBlobRemoveAfterSave(removeAfterSave bool) BlobOption { 13 | return func(blob *Blob) error { 14 | blob.removeAfterSave = removeAfterSave 15 | return nil 16 | } 17 | } 18 | 19 | // WithBlobPlatform specifies platform attribution such that the later queries 20 | // to the blob store which include platform specification only return those with 21 | // the set parameters. 22 | func WithBlobPlatform(platform *ocispec.Platform) BlobOption { 23 | return func(blob *Blob) error { 24 | blob.desc.Platform = platform 25 | return nil 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /oci/cache/image.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package cache 6 | 7 | import ( 8 | "sync" 9 | 10 | "github.com/google/go-containerregistry/pkg/name" 11 | v1 "github.com/google/go-containerregistry/pkg/v1" 12 | "github.com/google/go-containerregistry/pkg/v1/remote" 13 | ) 14 | 15 | var ( 16 | imageCache map[string]v1.Image 17 | imageCacheMu sync.Mutex 18 | ) 19 | 20 | // RemoteImage is a wrapper for v1.Image which caches requests in-memory for 21 | // previously requested image. This aids in reducing the number of lookup calls 22 | // to the same images. Since v1.WithPlatform is not respected, a valid lookup 23 | // will have had any additional options, such as WithTransport and WithAuth, 24 | // fully satisfied. 25 | func RemoteImage(ref name.Reference, options ...remote.Option) (v1.Image, error) { 26 | name := ref.Name() 27 | 28 | if imageCache == nil { 29 | imageCache = make(map[string]v1.Image) 30 | goto lookup 31 | } 32 | 33 | imageCacheMu.Lock() 34 | if image, ok := imageCache[name]; ok { 35 | imageCacheMu.Unlock() 36 | return image, nil 37 | } 38 | imageCacheMu.Unlock() 39 | 40 | lookup: 41 | v1Image, err := remote.Image(ref, options...) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | imageCacheMu.Lock() 47 | imageCache[name] = v1Image 48 | imageCacheMu.Unlock() 49 | 50 | return v1Image, nil 51 | } 52 | -------------------------------------------------------------------------------- /oci/cache/index.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package cache 6 | 7 | import ( 8 | "sync" 9 | 10 | "github.com/google/go-containerregistry/pkg/name" 11 | v1 "github.com/google/go-containerregistry/pkg/v1" 12 | "github.com/google/go-containerregistry/pkg/v1/remote" 13 | ) 14 | 15 | var ( 16 | indexCache map[string]v1.ImageIndex 17 | indexCacheMu sync.Mutex 18 | ) 19 | 20 | // RemoteIndex is a wrapper for v1.RemoteIndex which caches requests in-memory 21 | // for previously requested indexes. This aids in reducing the number of lookup 22 | // calls to the same index. Since v1.WithPlatform is not respected, a valid 23 | // lookup will have had any additional options, such as WithTransport and 24 | // WithAuth, fully satisfied. 25 | func RemoteIndex(ref name.Reference, options ...remote.Option) (v1.ImageIndex, error) { 26 | name := ref.Name() 27 | 28 | if indexCache == nil { 29 | indexCacheMu.Lock() 30 | indexCache = make(map[string]v1.ImageIndex) 31 | indexCacheMu.Unlock() 32 | goto lookup 33 | } 34 | 35 | indexCacheMu.Lock() 36 | if index, ok := indexCache[name]; ok { 37 | indexCacheMu.Unlock() 38 | return index, nil 39 | } 40 | indexCacheMu.Unlock() 41 | 42 | lookup: 43 | v1ImageIndex, err := remote.Index(ref, options...) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | indexCacheMu.Lock() 49 | indexCache[name] = v1ImageIndex 50 | indexCacheMu.Unlock() 51 | 52 | return v1ImageIndex, nil 53 | } 54 | -------------------------------------------------------------------------------- /oci/google_go_containerregistry.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package oci 6 | 7 | import ( 8 | v1 "github.com/google/go-containerregistry/pkg/v1" 9 | "github.com/opencontainers/go-digest" 10 | ocispec "github.com/opencontainers/image-spec/specs-go/v1" 11 | ) 12 | 13 | // Convert github.com/google/go-containerregistry/pkg/v1.Descriptor to 14 | // github.com/opencontainers/image-spec/specs-go/v1.Descriptor 15 | func FromGoogleV1DescriptorToOCISpec(from ...v1.Descriptor) []ocispec.Descriptor { 16 | to := make([]ocispec.Descriptor, len(from)) 17 | 18 | for i := range from { 19 | to[i] = ocispec.Descriptor{ 20 | MediaType: string(from[i].MediaType), 21 | Digest: digest.Digest(from[i].Digest.String()), 22 | Size: from[i].Size, 23 | URLs: from[i].URLs, 24 | Annotations: from[i].Annotations, 25 | Data: from[i].Data, 26 | Platform: FromGoogleV1PlatformToOCISpec(from[i].Platform), 27 | } 28 | } 29 | 30 | return to 31 | } 32 | 33 | // Convert github.com/google/go-containerregistry/pkg/v1.Platform to 34 | // github.com/opencontainers/image-spec/specs-go/v1.Platform 35 | func FromGoogleV1PlatformToOCISpec(from *v1.Platform) *ocispec.Platform { 36 | if from == nil { 37 | return nil 38 | } 39 | 40 | return &ocispec.Platform{ 41 | Architecture: from.Architecture, 42 | OS: from.OS, 43 | OSVersion: from.OSVersion, 44 | OSFeatures: from.OSFeatures, 45 | Variant: from.Variant, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /oci/init.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package oci 6 | 7 | import ( 8 | "kraftkit.sh/packmanager" 9 | ) 10 | 11 | func RegisterPackageManager() func(u *packmanager.UmbrellaManager) error { 12 | return func(u *packmanager.UmbrellaManager) error { 13 | return u.RegisterPackageManager( 14 | OCIFormat, 15 | NewPackageManager, 16 | WithDefaultAuth(), 17 | WithDefaultRegistries(), 18 | WithDetectHandler(), 19 | ) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /oci/layer_options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package oci 6 | 7 | import "fmt" 8 | 9 | type LayerOption func(*Layer) error 10 | 11 | // WithLayerAnnotation sets an annotation for a particular layer 12 | func WithLayerAnnotation(key, val string) LayerOption { 13 | return func(layer *Layer) error { 14 | if layer.blob == nil { 15 | return fmt.Errorf("cannot apply layer annotation without creating blob") 16 | } 17 | 18 | if layer.blob.desc.Annotations == nil { 19 | layer.blob.desc.Annotations = make(map[string]string) 20 | } 21 | 22 | layer.blob.desc.Annotations[key] = val 23 | 24 | return nil 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /oci/mediatypes.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package oci 6 | 7 | const ( 8 | MediaTypeLayer = "application/vnd.unikraft.rootfs.diff" 9 | MediaTypeImageKernel = "application/vnd.unikraft.image.v1" 10 | MediaTypeInitrdCpio = "application/vnd.unikraft.initrd.v1" 11 | MediaTypeConfig = "application/vnd.unikraft.config.v1" 12 | 13 | MediaTypeLayerGzip = MediaTypeLayer + "+gzip" 14 | MediaTypeImageKernelGzip = MediaTypeImageKernel + "+gzip" 15 | MediaTypeInitrdCpioGzip = MediaTypeInitrdCpio + "+gzip" 16 | MediaTypeConfigGzip = MediaTypeConfig + "+gzip" 17 | ) 18 | -------------------------------------------------------------------------------- /oci/oci.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package oci 6 | 7 | const ( 8 | DefaultRegistry = "unikraft.org" 9 | DefaultNamespace = "default" 10 | DefaultTag = "latest" 11 | ) 12 | -------------------------------------------------------------------------------- /oci/simpleauth/simpleauth.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | // Package simpleauth implements a basic pass-by-reference of credentials for 7 | // the authn.Authenticator interface. 8 | package simpleauth 9 | 10 | import "github.com/google/go-containerregistry/pkg/authn" 11 | 12 | // SimpleAuthenticator is used to handle looking up the already populated 13 | // user configuration that is used when speaking with the remote registry. 14 | type SimpleAuthenticator struct { 15 | Auth *authn.AuthConfig 16 | } 17 | 18 | // Authorization implements authn.Authenticator. 19 | func (auth *SimpleAuthenticator) Authorization() (*authn.AuthConfig, error) { 20 | return auth.Auth, nil 21 | } 22 | -------------------------------------------------------------------------------- /oci/utils/platform.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package utils 7 | 8 | import ( 9 | "crypto/sha256" 10 | "encoding/json" 11 | "fmt" 12 | 13 | ocispec "github.com/opencontainers/image-spec/specs-go/v1" 14 | ) 15 | 16 | // PlatformChecksum accepts an input manifest and generates a 17 | // checksum based on the platform 18 | func PlatformChecksum(seed string, manifest *ocispec.Platform) (string, error) { 19 | b, err := json.Marshal(manifest) 20 | if err != nil { 21 | return "", err 22 | } 23 | 24 | h := sha256.New() 25 | h.Write([]byte(seed)) 26 | h.Write(b) 27 | return fmt.Sprintf("%x", h.Sum(nil)), nil 28 | } 29 | -------------------------------------------------------------------------------- /oci/utils/tarball.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2025, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package utils 6 | 7 | import ( 8 | "archive/tar" 9 | "fmt" 10 | "io" 11 | "io/fs" 12 | "path/filepath" 13 | ) 14 | 15 | // OpenFromTarOCILayer returns a reader for the given file from the provided 16 | // tarball reader. 17 | func OpenFromTarOCILayer(r io.Reader, path string) (io.Reader, error) { 18 | tarPath, err := filepath.Rel("/", path) 19 | if err != nil { 20 | return nil, fmt.Errorf("could not trim leading separator from path %q: %w", path, err) 21 | } 22 | 23 | tr := tar.NewReader(r) 24 | for { 25 | h, err := tr.Next() 26 | if err != nil { 27 | if err == io.EOF { 28 | break 29 | } 30 | return nil, fmt.Errorf("could not advance to the next entry in the OCI image layer: %w", err) 31 | } 32 | 33 | if h.Name != tarPath { 34 | continue 35 | } 36 | 37 | if t := h.Typeflag; t != tar.TypeReg { 38 | return nil, fmt.Errorf("path is not a regular file") 39 | } 40 | 41 | return tr, nil 42 | } 43 | 44 | return nil, &fs.PathError{Op: "open", Path: path, Err: fs.ErrNotExist} 45 | } 46 | -------------------------------------------------------------------------------- /oci/wellknown.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package oci 6 | 7 | const ( 8 | WellKnownKernelPath = "/unikraft/bin/kernel" 9 | WellKnownKernelDbgPath = "/unikraft/bin/kernel.dbg" 10 | WellKnownInitrdPath = "/unikraft/bin/initrd" 11 | WellKnownConfigPath = "/unikraft/bin/config" 12 | WellKnownKernelSourceDir = "/unikraft/src" 13 | WellKnownAppSourceDir = "/unikraft/app" 14 | ) 15 | -------------------------------------------------------------------------------- /pack/context.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package pack 6 | 7 | type ContextKey string 8 | -------------------------------------------------------------------------------- /pack/push_option.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package pack 6 | 7 | // PushOptions contains the list of options which can be set whilst pushing a 8 | // package. 9 | type PushOptions struct { 10 | onProgress func(progress float64) 11 | } 12 | 13 | // PushOption is an option function which is used to modify PushOptions. 14 | type PushOption func(*PushOptions) error 15 | 16 | // NewPushOptions creates PushOptions 17 | func NewPushOptions(opts ...PushOption) (*PushOptions, error) { 18 | options := &PushOptions{} 19 | 20 | for _, o := range opts { 21 | err := o(options) 22 | if err != nil { 23 | return nil, err 24 | } 25 | } 26 | 27 | return options, nil 28 | } 29 | 30 | // WithPushProgressFunc set an optional progress function which is used as a 31 | // callback during the transmission of the package and the host. 32 | func WithPushProgressFunc(onProgress func(progress float64)) PushOption { 33 | return func(opts *PushOptions) error { 34 | opts.onProgress = onProgress 35 | return nil 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packmanager/context.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package packmanager 6 | 7 | import ( 8 | "context" 9 | ) 10 | 11 | var ( 12 | // G is an alias for FromContext. 13 | // 14 | // We may want to define this locally to a package to get package tagged 15 | // package manager. 16 | G = FromContext 17 | 18 | // PM is the system-access umbrella package manager. 19 | PM = UmbrellaManager{} 20 | ) 21 | 22 | // contextKey is used to retrieve the package manager from the context. 23 | type contextKey struct{} 24 | 25 | // WithPackageManager returns a new context with the provided package manager. 26 | func WithPackageManager(ctx context.Context, pm PackageManager) context.Context { 27 | return context.WithValue(ctx, contextKey{}, pm) 28 | } 29 | 30 | // FromContext returns the package manager in the context, or access to the 31 | // umbrella package manager which iterates over all registered package managers. 32 | func FromContext(ctx context.Context) PackageManager { 33 | l := ctx.Value(contextKey{}) 34 | 35 | if l == nil { 36 | return PM 37 | } 38 | 39 | return l.(PackageManager) 40 | } 41 | -------------------------------------------------------------------------------- /packmanager/unpack_options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package packmanager 6 | 7 | // UnpackOptions contains the list of options which can be used to unpackage an 8 | // a component. 9 | type UnpackOptions struct { 10 | workdir string 11 | } 12 | 13 | // UnpackOption is an option function which is used to modify UnpackOptions. 14 | type UnpackOption func(*UnpackOptions) error 15 | 16 | // WithUnpackWorkdir sets the directory to unpack the package to 17 | func WithUnpackWorkdir(workdir string) UnpackOption { 18 | return func(uopts *UnpackOptions) error { 19 | uopts.workdir = workdir 20 | return nil 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/e2e/cli/cli_suite_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package cli_test 7 | 8 | import ( 9 | "testing" 10 | 11 | . "github.com/onsi/ginkgo/v2" //nolint:stylecheck 12 | . "github.com/onsi/gomega" //nolint:stylecheck 13 | ) 14 | 15 | func TestCli(t *testing.T) { 16 | RegisterFailHandler(Fail) 17 | RunSpecs(t, "CLI Suite") 18 | } 19 | -------------------------------------------------------------------------------- /test/e2e/cloud/cloud_suite_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package cli_test 7 | 8 | import ( 9 | "testing" 10 | 11 | . "github.com/onsi/ginkgo/v2" //nolint:stylecheck 12 | . "github.com/onsi/gomega" //nolint:stylecheck 13 | ) 14 | 15 | func TestCloud(t *testing.T) { 16 | RegisterFailHandler(Fail) 17 | RunSpecs(t, "Cloud Suite") 18 | } 19 | -------------------------------------------------------------------------------- /test/e2e/framework/config/config_suite_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package config_test 7 | 8 | import ( 9 | "testing" 10 | 11 | . "github.com/onsi/ginkgo/v2" //nolint:stylecheck 12 | . "github.com/onsi/gomega" //nolint:stylecheck 13 | ) 14 | 15 | func TestConfig(t *testing.T) { 16 | RegisterFailHandler(Fail) 17 | RunSpecs(t, "Config") 18 | } 19 | -------------------------------------------------------------------------------- /test/e2e/framework/matchers/be_empty_dir.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package matchers 7 | 8 | import ( 9 | "fmt" 10 | "os" 11 | 12 | "github.com/onsi/gomega/format" 13 | "github.com/onsi/gomega/types" 14 | ) 15 | 16 | // beAnEmptyDirectoryMatcher asserts that an existing directory is empty. 17 | type beAnEmptyDirectoryMatcher struct { 18 | err error 19 | } 20 | 21 | var _ types.GomegaMatcher = (*beAnEmptyDirectoryMatcher)(nil) 22 | 23 | func (matcher *beAnEmptyDirectoryMatcher) Match(actual any) (success bool, err error) { 24 | actualDirName, ok := actual.(string) 25 | if !ok { 26 | return false, fmt.Errorf("BeAnEmptyDirectory matcher expects a directory path") 27 | } 28 | 29 | dirEntries, err := os.ReadDir(actualDirName) 30 | if err != nil { 31 | matcher.err = fmt.Errorf("reading directory entries: %w", err) 32 | return false, nil 33 | } 34 | 35 | n := len(dirEntries) 36 | hasEntries := n > 0 37 | 38 | if hasEntries { 39 | matcher.err = fmt.Errorf("directory contains %d entries", n) 40 | } 41 | 42 | return !hasEntries, nil 43 | } 44 | 45 | func (matcher *beAnEmptyDirectoryMatcher) FailureMessage(actual any) string { 46 | return format.Message(actual, fmt.Sprintf("to be an empty directory: %s", matcher.err)) 47 | } 48 | 49 | func (*beAnEmptyDirectoryMatcher) NegatedFailureMessage(actual any) string { 50 | return format.Message(actual, "not be an empty directory") 51 | } 52 | -------------------------------------------------------------------------------- /test/e2e/framework/matchers/matchers.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2023, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | // Package matchers contains additional Gomega matchers. 7 | package matchers 8 | 9 | import "github.com/onsi/gomega/types" 10 | 11 | // BeAnEmptyDirectory succeeds if a file exists and is a directory that does 12 | // not contain any file. 13 | // Actual must be a string representing the absolute path to the directory 14 | // being checked. 15 | func BeAnEmptyDirectory() types.GomegaMatcher { 16 | return &beAnEmptyDirectoryMatcher{} 17 | } 18 | 19 | // ContainFiles succeeds if a directory exists and contains files with the 20 | // provided names. 21 | // Actual must be a string representing the absolute path to the directory 22 | // containing these files. 23 | func ContainFiles(files ...string) types.GomegaMatcher { 24 | return &containFilesMatcher{fileNames: files} 25 | } 26 | 27 | // ContainDirectories succeeds if a directory exists and contains 28 | // sub-directories with the provided names. 29 | // Actual must be a string representing the absolute path to the directory 30 | // containing these sub-directories. 31 | func ContainDirectories(dirs ...string) types.GomegaMatcher { 32 | return &containDirectoriesMatcher{dirNames: dirs} 33 | } 34 | -------------------------------------------------------------------------------- /tools/dockerfile-llb-frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | */.vscode* 2 | test/ 3 | *_test.go 4 | *.bak 5 | *.swp 6 | *.idea 7 | *.orig 8 | .DS_Store 9 | *.md 10 | .git/ 11 | .gitignore 12 | Dockerfile 13 | -------------------------------------------------------------------------------- /tools/dockerfile-llb-frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (c) 2022, NEC Europe Ltd., Unikraft GmbH, and The KraftKit Authors. 3 | # Licensed under the BSD-3-Clause License (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | 6 | FROM golang:1.24 AS builder 7 | 8 | WORKDIR /src 9 | COPY . ./ 10 | RUN CGO_ENABLED=0 go build -o /kraft-llb-plugin -tags "containers_image_storage_stub,containers_image_openpgp" --ldflags "-s -w" 11 | 12 | FROM scratch 13 | COPY --from=builder /kraft-llb-plugin /bin/kraft-llb-plugin 14 | ENTRYPOINT ["/bin/kraft-llb-plugin"] 15 | -------------------------------------------------------------------------------- /tools/dockerfile-llb-frontend/image/image.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | // Package image handles setting metadata on resulting container images. 7 | package image 8 | 9 | import ( 10 | "runtime" 11 | 12 | specs "github.com/opencontainers/image-spec/specs-go/v1" 13 | "kraftkit.sh/oci" 14 | ) 15 | 16 | // UnikraftImageConfig provided metadata enables running unikraft images through docker run. 17 | func UnikraftImageConfig() *specs.Image { 18 | return &specs.Image{ 19 | Platform: specs.Platform{ 20 | Architecture: runtime.GOARCH, 21 | OS: runtime.GOOS, 22 | }, 23 | RootFS: specs.RootFS{ 24 | Type: "layers", 25 | }, 26 | Config: specs.ImageConfig{ 27 | WorkingDir: "/", 28 | Entrypoint: []string{oci.WellKnownKernelPath}, 29 | }, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tools/protoc-gen-go-netconn/go.mod: -------------------------------------------------------------------------------- 1 | module kraftkit.sh/tools/protoc-gen-go-netconn 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/Masterminds/sprig/v3 v3.3.0 7 | github.com/golang/glog v1.2.5 8 | github.com/iancoleman/strcase v0.3.0 9 | google.golang.org/protobuf v1.36.6 10 | ) 11 | 12 | require ( 13 | dario.cat/mergo v1.0.1 // indirect 14 | github.com/Masterminds/goutils v1.1.1 // indirect 15 | github.com/Masterminds/semver/v3 v3.3.0 // indirect 16 | github.com/google/uuid v1.6.0 // indirect 17 | github.com/huandu/xstrings v1.5.0 // indirect 18 | github.com/mitchellh/copystructure v1.2.0 // indirect 19 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 20 | github.com/shopspring/decimal v1.4.0 // indirect 21 | github.com/spf13/cast v1.7.0 // indirect 22 | golang.org/x/crypto v0.35.0 // indirect 23 | ) 24 | -------------------------------------------------------------------------------- /tools/webinstall/Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | # Licensed under the BSD-3-Clause License (the "License"). 4 | # You may not use this file expect in compliance with the License. 5 | 6 | ARG GO_VERSION=1.24 7 | 8 | FROM golang:${GO_VERSION}-bullseye AS base 9 | 10 | ARG ORG=unikraft 11 | ARG BIN=webinstall 12 | ARG GO_VERSION=${GO_VERSION} 13 | 14 | WORKDIR /go/src/webinstall 15 | 16 | ENV GOROOT=/usr/local/go 17 | ENV PATH=$PATH:/go/src/webinstall 18 | ENV CGO_ENABLED=0 19 | 20 | COPY . /go/src/webinstall 21 | 22 | RUN set -xe; \ 23 | go build -tags static -a -ldflags='-s -w' -ldflags '-extldflags "-static"' . 24 | 25 | FROM gcr.io/distroless/static:nonroot AS prod 26 | 27 | COPY --from=base /go/src/webinstall/webinstall /webinstall 28 | 29 | EXPOSE 8080 30 | 31 | ENTRYPOINT ["/webinstall"] 32 | -------------------------------------------------------------------------------- /tui/confirm/confirm.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Acorn Labs, Inc; All rights reserved. 3 | // Copyright 2022 Unikraft GmbH; All rights reserved. 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | 7 | package confirm 8 | 9 | import ( 10 | "github.com/erikgeiser/promptkit/confirmation" 11 | "kraftkit.sh/tui" 12 | ) 13 | 14 | // NewConfirm is a utility method used in a CLI context to prompt the user with 15 | // a yes/no question. 16 | func NewConfirm(question string) (bool, error) { 17 | input := confirmation.New( 18 | tui.TextWhiteBgBlue("[?]")+" "+ 19 | question, 20 | confirmation.NewValue(true), 21 | ) 22 | input.Template = confirmation.TemplateYN 23 | input.ResultTemplate = confirmation.ResultTemplateYN 24 | input.KeyMap.SelectYes = append(input.KeyMap.SelectYes, "+") 25 | input.KeyMap.SelectNo = append(input.KeyMap.SelectNo, "-") 26 | 27 | return input.RunPrompt() 28 | } 29 | -------------------------------------------------------------------------------- /tui/paraprogress/options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package paraprogress 6 | 7 | import "time" 8 | 9 | type ParaProgressOption func(md *ParaProgress) error 10 | 11 | func WithRenderer(norender bool) ParaProgressOption { 12 | return func(md *ParaProgress) error { 13 | md.norender = norender 14 | return nil 15 | } 16 | } 17 | 18 | func IsParallel(parallel bool) ParaProgressOption { 19 | return func(md *ParaProgress) error { 20 | md.parallel = parallel 21 | return nil 22 | } 23 | } 24 | 25 | func WithFailFast(failFast bool) ParaProgressOption { 26 | return func(pp *ParaProgress) error { 27 | pp.failFast = failFast 28 | return nil 29 | } 30 | } 31 | 32 | func WithNameWidth(width int) ParaProgressOption { 33 | return func(pp *ParaProgress) error { 34 | pp.nameWidth = width 35 | return nil 36 | } 37 | } 38 | 39 | func WithTimeout(timeout time.Duration) ParaProgressOption { 40 | return func(pp *ParaProgress) error { 41 | pp.timeout = timeout 42 | return nil 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tui/processtree/options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file expect in compliance with the License. 5 | package processtree 6 | 7 | import "time" 8 | 9 | type ProcessTreeOption func(pt *ProcessTree) error 10 | 11 | func WithVerb(verb string) ProcessTreeOption { 12 | return func(pt *ProcessTree) error { 13 | pt.verb = verb 14 | return nil 15 | } 16 | } 17 | 18 | func WithRenderer(norender bool) ProcessTreeOption { 19 | return func(pt *ProcessTree) error { 20 | pt.norender = norender 21 | return nil 22 | } 23 | } 24 | 25 | func IsParallel(parallel bool) ProcessTreeOption { 26 | return func(pt *ProcessTree) error { 27 | pt.parallel = parallel 28 | return nil 29 | } 30 | } 31 | 32 | func WithFailFast(failFast bool) ProcessTreeOption { 33 | return func(pt *ProcessTree) error { 34 | pt.failFast = failFast 35 | return nil 36 | } 37 | } 38 | 39 | func WithHideOnSuccess(hide bool) ProcessTreeOption { 40 | return func(pt *ProcessTree) error { 41 | pt.hide = hide 42 | return nil 43 | } 44 | } 45 | 46 | func WithTimeout(timeout time.Duration) ProcessTreeOption { 47 | return func(pt *ProcessTree) error { 48 | pt.timeout = timeout 49 | return nil 50 | } 51 | } 52 | 53 | func WithHideError(hide bool) ProcessTreeOption { 54 | return func(pt *ProcessTree) error { 55 | pt.hideError = hide 56 | return nil 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tui/selection/select.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package selection 7 | 8 | import ( 9 | "fmt" 10 | "sort" 11 | 12 | "github.com/erikgeiser/promptkit/selection" 13 | "kraftkit.sh/tui" 14 | ) 15 | 16 | // Select is a utility method used in a CLI context to prompt the user 17 | // given a slice of options based on the generic type. 18 | func Select[T fmt.Stringer](question string, options ...T) (*T, error) { 19 | if len(options) == 1 { 20 | return &options[0], nil 21 | } 22 | 23 | strings := make([]string, 0, len(options)) 24 | for _, option := range options { 25 | strings = append(strings, option.String()) 26 | } 27 | 28 | sort.Strings(strings) 29 | 30 | sp := selection.New(tui.TextWhiteBgBlue("[?]")+" "+question, strings) 31 | sp.Filter = nil 32 | 33 | result, err := sp.RunPrompt() 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | for _, t := range options { 39 | if t.String() == result { 40 | return &t, nil 41 | } 42 | } 43 | 44 | return nil, fmt.Errorf("could not perform selection") 45 | } 46 | -------------------------------------------------------------------------------- /tui/textinput/text.go: -------------------------------------------------------------------------------- 1 | package textinput 2 | 3 | import ( 4 | "github.com/charmbracelet/lipgloss" 5 | "github.com/erikgeiser/promptkit/textinput" 6 | ) 7 | 8 | var queryMark = lipgloss.NewStyle(). 9 | Background(lipgloss.Color("12")). 10 | Foreground(lipgloss.AdaptiveColor{ 11 | Light: "0", 12 | Dark: "15", 13 | }). 14 | Render 15 | 16 | // NewSpecify is a utility method used in a CLI context to prompt the user with 17 | // a question to specify answer as string. 18 | func NewTextInput(question, placeholder, defaultAns string) (string, error) { 19 | input := textinput.New(queryMark("[?] ") + question) 20 | input.Placeholder = placeholder 21 | input.InitialValue = defaultAns 22 | return input.RunPrompt() 23 | } 24 | -------------------------------------------------------------------------------- /tui/tui.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package tui 6 | 7 | import "github.com/charmbracelet/lipgloss" 8 | 9 | var ( 10 | TextTitle = lipgloss.NewStyle(). 11 | Bold(true). 12 | Render 13 | 14 | TextRed = lipgloss.NewStyle(). 15 | Foreground(lipgloss.Color("9")). 16 | Render 17 | 18 | TextWhiteBgRed = lipgloss.NewStyle(). 19 | Background(lipgloss.Color("9")). 20 | Foreground(lipgloss.AdaptiveColor{ 21 | Light: "15", 22 | Dark: "0", 23 | }). 24 | Render 25 | 26 | TextGreen = lipgloss.NewStyle(). 27 | Foreground(lipgloss.Color("10")). 28 | Render 29 | 30 | TextWhiteBgGreen = lipgloss.NewStyle(). 31 | Background(lipgloss.Color("10")). 32 | Foreground(lipgloss.AdaptiveColor{ 33 | Light: "15", 34 | Dark: "0", 35 | }). 36 | Render 37 | 38 | TextBlue = lipgloss.NewStyle(). 39 | Foreground(lipgloss.Color("12")). 40 | Render 41 | 42 | TextLightBlue = lipgloss.NewStyle(). 43 | Foreground(lipgloss.Color("14")). 44 | Render 45 | 46 | TextWhiteBgBlue = lipgloss.NewStyle(). 47 | Background(lipgloss.Color("12")). 48 | Foreground(lipgloss.AdaptiveColor{ 49 | Light: "15", 50 | Dark: "0", 51 | }). 52 | Render 53 | 54 | TextLightGray = lipgloss.NewStyle(). 55 | Foreground(lipgloss.Color("245")). 56 | Render 57 | 58 | TextYellow = lipgloss.NewStyle(). 59 | Foreground(lipgloss.Color("11")). 60 | Render 61 | ) 62 | -------------------------------------------------------------------------------- /unikraft/app/volume/transform.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package volume 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "strings" 11 | ) 12 | 13 | // TransformFromSchema parses an input schema and returns an instantiated 14 | // VolumeConfig 15 | func TransformFromSchema(ctx context.Context, data interface{}) (interface{}, error) { 16 | volume := VolumeConfig{} 17 | 18 | switch entry := data.(type) { 19 | case string: 20 | var split []string 21 | if strings.Contains(entry, ":") { 22 | split = strings.Split(entry, ":") 23 | if len(split) > 2 { 24 | return nil, fmt.Errorf("expected format template value to be @") 25 | } 26 | 27 | volume.source = split[0] 28 | if len(split) == 2 { 29 | volume.destination = split[1] 30 | } 31 | } else { 32 | // When no colon is specified, assume the root file system 33 | volume.source = entry 34 | volume.destination = "/" 35 | } 36 | 37 | case map[string]interface{}: 38 | for key, prop := range entry { 39 | switch key { 40 | case "driver": 41 | volume.driver = prop.(string) 42 | 43 | case "source": 44 | volume.source = prop.(string) 45 | 46 | case "destination": 47 | volume.destination = prop.(string) 48 | 49 | case "readonly": 50 | volume.readOnly = prop.(bool) 51 | 52 | } 53 | } 54 | } 55 | 56 | return volume, nil 57 | } 58 | -------------------------------------------------------------------------------- /unikraft/arch/host.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package arch 6 | 7 | import ( 8 | "fmt" 9 | "runtime" 10 | ) 11 | 12 | // HostArchitecture returns the architecture of the host or an error if 13 | // unsupported by Unikraft. 14 | func HostArchitecture() (string, error) { 15 | arch := runtime.GOARCH 16 | switch arch { 17 | case "amd64": 18 | return "x86_64", nil 19 | case "arm", "arm64": 20 | return arch, nil 21 | default: 22 | return "", fmt.Errorf("unsupported architecture: %v", arch) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /unikraft/arch/options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package arch 6 | 7 | import ( 8 | "kraftkit.sh/kconfig" 9 | ) 10 | 11 | // ArchitectureOption is a function that modifies a ArchitectureConfig. 12 | type ArchitectureOption func(*ArchitectureConfig) 13 | 14 | // WithName sets the name of the architecture. 15 | func WithName(name string) ArchitectureOption { 16 | return func(ac *ArchitectureConfig) { 17 | ac.name = name 18 | } 19 | } 20 | 21 | // WithKConfig sets the kconfig of the architecture. 22 | func WithKConfig(kconfig kconfig.KeyValueMap) ArchitectureOption { 23 | return func(ac *ArchitectureConfig) { 24 | ac.kconfig = kconfig 25 | } 26 | } 27 | 28 | // WithVersion sets the version of the architecture. 29 | func WithVersion(version string) ArchitectureOption { 30 | return func(ac *ArchitectureConfig) { 31 | ac.version = version 32 | } 33 | } 34 | 35 | // WithSource sets the source of the architecture. 36 | func WithSource(source string) ArchitectureOption { 37 | return func(ac *ArchitectureConfig) { 38 | ac.source = source 39 | } 40 | } 41 | 42 | // WithPath sets the path of the architecture. 43 | func WithPath(path string) ArchitectureOption { 44 | return func(ac *ArchitectureConfig) { 45 | ac.path = path 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /unikraft/arch/transform.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package arch 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | "kraftkit.sh/unikraft" 12 | ) 13 | 14 | // TransformFromSchema parses an input schema and returns an instantiated 15 | // ArchitectureConfig 16 | func TransformFromSchema(ctx context.Context, data interface{}) (interface{}, error) { 17 | uk := unikraft.FromContext(ctx) 18 | architecture := ArchitectureConfig{} 19 | 20 | switch value := data.(type) { 21 | case string: 22 | architecture.name = value 23 | default: 24 | return nil, fmt.Errorf("invalid type %T for architecture", data) 25 | } 26 | 27 | if uk != nil && uk.UK_BASE != "" { 28 | architecture.path, _ = unikraft.PlaceComponent( 29 | uk.UK_BASE, 30 | unikraft.ComponentTypeArch, 31 | architecture.name, 32 | ) 33 | } 34 | 35 | return architecture, nil 36 | } 37 | -------------------------------------------------------------------------------- /unikraft/context.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package unikraft 6 | 7 | import "context" 8 | 9 | // contextKey is used to retrieve the logger from the context. 10 | type contextKey struct{} 11 | 12 | // Context is a general-purpose context container for use within the Unikraft 13 | // package. It mimics the environmental variables within Unikraft's main build 14 | // system. 15 | type Context struct { 16 | UK_NAME string 17 | UK_BASE string 18 | BUILD_DIR string 19 | } 20 | 21 | // WithContext 22 | func WithContext(ctx context.Context, val *Context) context.Context { 23 | return context.WithValue(ctx, contextKey{}, val) 24 | } 25 | 26 | func FromContext(ctx context.Context) *Context { 27 | uk, ok := ctx.Value(contextKey{}).(*Context) 28 | if !ok { 29 | return nil 30 | } 31 | 32 | return uk 33 | } 34 | -------------------------------------------------------------------------------- /unikraft/export/README.md: -------------------------------------------------------------------------------- 1 | # Unikraft C-Go bindings 2 | 3 | This package contains C-bindings for Unikraft to be used within the context of 4 | Go applications which are built on top of Unikraft. The purpose of this package 5 | is twofold: 6 | 7 | 1. to allow KraftKit internals to reference Unikraft internal structures during 8 | the manifestation of a unikernel (either during compile-time or runtime); 9 | and, 10 | 2. to enable developers programming in Go to directly reference Unikraft 11 | internals and bypass general-purpose syscall boundaries. 12 | 13 | This package is work-in-progress, and as such the enumerated libraries exposed 14 | (or "exported") by this package are delivered through the `v0` suffix. This 15 | serves to indicate that the exported constants, variables, methods and utilities 16 | offered by KraftKit representing Unikraft internals are incomplete, subject to 17 | change and therefore considered unstable. Thus, usage of the exported methods 18 | are delivered via: 19 | 20 | ```go 21 | import "kraftkit.sh/unikraft/export/v0" 22 | ``` 23 | 24 | Towards [the release of Unikraft v1.0 25 | itself](https://github.com/orgs/unikraft/projects/24/views/38), the exported 26 | libraries, symbols, methods and utility methods will reflect both stable APIs 27 | both in terms of Unikraft's internals but also with regard to how this package 28 | can be used. 29 | -------------------------------------------------------------------------------- /unikraft/export/v0/posixenviron/library.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package posixenviron 6 | 7 | const LibraryName = "posix-environ" 8 | 9 | const DefaultCompiledInLimit = 15 10 | -------------------------------------------------------------------------------- /unikraft/export/v0/posixenviron/params.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package posixenviron 6 | 7 | import ( 8 | "strings" 9 | 10 | "kraftkit.sh/unikraft/export/v0/ukargparse" 11 | ) 12 | 13 | var ParamEnvVars = ukargparse.NewParamStrSlice("env", "vars", nil) 14 | 15 | // ExportedParams returns the parameters available by this exported library. 16 | func ExportedParams() []ukargparse.Param { 17 | return []ukargparse.Param{ 18 | ParamEnvVars, 19 | } 20 | } 21 | 22 | // EnvVarEntry is an environment variable entry. 23 | type EnvVarEntry struct { 24 | name string 25 | value string 26 | } 27 | 28 | // NewEnvVarEntry generates a structure that is representative of one of 29 | // Unikraft's posix-environ variables. 30 | func NewEnvVarEntry(name, value string) EnvVarEntry { 31 | return EnvVarEntry{ 32 | name, 33 | value, 34 | } 35 | } 36 | 37 | // String implements fmt.Stringer and returns a valid posix-environ environment 38 | // variable. 39 | func (entry EnvVarEntry) String() string { 40 | return strings.Join([]string{ 41 | entry.name, 42 | entry.value, 43 | }, "=") 44 | } 45 | -------------------------------------------------------------------------------- /unikraft/export/v0/uknetdev/library.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package uknetdev 6 | 7 | const ( 8 | LibraryName = "uknetdev" 9 | ) 10 | -------------------------------------------------------------------------------- /unikraft/export/v0/uknetdev/params.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package uknetdev 6 | 7 | import ( 8 | "strings" 9 | 10 | "kraftkit.sh/unikraft/export/v0/ukargparse" 11 | ) 12 | 13 | // The netdev.ip parameter can be used to override IPv4 address information 14 | // for multiple devices. For each device the following colon-separated format 15 | // is introduced: 16 | // 17 | // cidr[:gw[:dns0[:dns1[:hostname[:domain]]]]] 18 | func NewParamIp() ukargparse.Param { 19 | return ukargparse.ParamStr("netdev", "ip", nil) 20 | } 21 | 22 | // NetdevIp represents the attributes of the network device which is understood 23 | // by uknetdev and uklibparam. 24 | type NetdevIp struct { 25 | CIDR string 26 | Gateway string 27 | DNS0 string 28 | DNS1 string 29 | Hostname string 30 | Domain string 31 | } 32 | 33 | // String implements fmt.Stringer and returns a valid netdev.ip-formatted entry. 34 | func (entry NetdevIp) String() string { 35 | return strings.Join([]string{ 36 | entry.CIDR, 37 | entry.Gateway, 38 | entry.DNS0, 39 | entry.DNS1, 40 | entry.Hostname, 41 | entry.Domain, 42 | }, ":") 43 | } 44 | 45 | // ExportedParams returns the parameters available by this exported library. 46 | func ExportedParams() []ukargparse.Param { 47 | return []ukargparse.Param{ 48 | NewParamIp(), 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /unikraft/export/v0/ukrandom/library.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package ukrandom 6 | 7 | const LibraryName = "ukrandom" 8 | -------------------------------------------------------------------------------- /unikraft/export/v0/ukrandom/params.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package ukrandom 6 | 7 | import ( 8 | "crypto/rand" 9 | "fmt" 10 | "math" 11 | "math/big" 12 | "strings" 13 | 14 | "kraftkit.sh/unikraft/export/v0/ukargparse" 15 | ) 16 | 17 | var ParamRandomSeed = ukargparse.ParamStr("random", "seed", nil) 18 | 19 | // ExportedParams returns the parameters available by this exported library. 20 | func ExportedParams() []ukargparse.Param { 21 | return []ukargparse.Param{ 22 | ParamRandomSeed, 23 | } 24 | } 25 | 26 | // RandomSeed are the 8 ints that are required by the ukrandom library. 27 | type RandomSeed [8]uint32 28 | 29 | // NewRandomSeed generates a new set of true random integers or nothing if error. 30 | func NewRandomSeed() (random RandomSeed) { 31 | maxUint32 := big.NewInt(math.MaxUint32) 32 | for i := 0; i < 8; i++ { 33 | val, err := rand.Int(rand.Reader, maxUint32) 34 | if err != nil { 35 | return RandomSeed{} 36 | } 37 | random[i] = uint32(val.Uint64()) 38 | } 39 | 40 | return random 41 | } 42 | 43 | // String implements fmt.Stringer and returns a valid set of random bytes. 44 | func (rng RandomSeed) String() string { 45 | var sb strings.Builder 46 | 47 | sb.WriteString("[ ") 48 | for i := 0; i < 8; i++ { 49 | sb.WriteString(fmt.Sprintf("0x%04x ", rng[i])) 50 | } 51 | sb.WriteString("]") 52 | 53 | return sb.String() 54 | } 55 | -------------------------------------------------------------------------------- /unikraft/export/v0/vfscore/library.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package vfscore 6 | 7 | const LibraryName = "vfscore" 8 | -------------------------------------------------------------------------------- /unikraft/export/v0/vfscore/params.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package vfscore 6 | 7 | import ( 8 | "strings" 9 | 10 | "kraftkit.sh/unikraft/export/v0/ukargparse" 11 | ) 12 | 13 | var ParamVfsFstab = ukargparse.NewParamStrSlice("vfs", "fstab", nil) 14 | 15 | // ExportedParams returns the parameters available by this exported library. 16 | func ExportedParams() []ukargparse.Param { 17 | return []ukargparse.Param{ 18 | ParamVfsFstab, 19 | } 20 | } 21 | 22 | // FstabEntry is a vfscore mount entry. 23 | type FstabEntry struct { 24 | sourceDevice string 25 | mountTarget string 26 | fsDriver string 27 | flags string 28 | opts string 29 | ukopts string 30 | } 31 | 32 | // NewFstabEntry generates a structure that is representative of one of 33 | // Unikraft's vfscore automounts. 34 | func NewFstabEntry(sourceDevice, mountTarget, fsDriver, flags, opts, ukopts string) FstabEntry { 35 | return FstabEntry{ 36 | sourceDevice, 37 | mountTarget, 38 | fsDriver, 39 | flags, 40 | opts, 41 | ukopts, 42 | } 43 | } 44 | 45 | // String implements fmt.Stringer and returns a valid vfs.automount-formatted 46 | // entry. 47 | func (entry FstabEntry) String() string { 48 | return strings.Join([]string{ 49 | entry.sourceDevice, 50 | entry.mountTarget, 51 | entry.fsDriver, 52 | entry.flags, 53 | entry.opts, 54 | entry.ukopts, 55 | }, ":") 56 | } 57 | -------------------------------------------------------------------------------- /unikraft/lib/template/CODING_STYLE.md.tmpl: -------------------------------------------------------------------------------- 1 | # Coding Style 2 | 3 | Please refer to the [`CODING_STYLE.md`](https://github.com/unikraft/unikraft/tree/staging/CODING_STYLE.md) file in the main Unikraft repository. 4 | -------------------------------------------------------------------------------- /unikraft/lib/template/CONTRIBUTING.md.tmpl: -------------------------------------------------------------------------------- 1 | # Contributing to Unikraft 2 | 3 | Please refer to the [`CONTRIBUTING.md`](https://github.com/unikraft/unikraft/tree/staging/CONTRIBUTING.md) file in the main Unikraft repository. 4 | -------------------------------------------------------------------------------- /unikraft/lib/template/Config.uk.tmpl: -------------------------------------------------------------------------------- 1 | menuconfig {{ .LibKNameUpperCase }} 2 | {{if .Description }} bool "{{ .Description }}" 3 | {{else }} bool "{{ .ProjectName }} Unikraft library" 4 | {{end}} default n 5 | {{range $index, $dependency := .KconfigDependencies }} 6 | select {{ $dependency }} 7 | {{end}} 8 | {{if .LibKName -}} 9 | {{if .ProvideCMain -}} 10 | config {{ .LibKNameUpperCase }}_MAIN_FUNCTION 11 | bool "Provide main function" 12 | default n 13 | {{end -}} 14 | {{end -}} 15 | -------------------------------------------------------------------------------- /unikraft/lib/template/README.md.tmpl: -------------------------------------------------------------------------------- 1 | # {{ .ProjectName }} for Unikraft 2 | 3 | This is the port of {{ .ProjectName }} for Unikraft as external library. 4 | 5 | Please refer to the [`README.md`](https://github.com/unikraft/unikraft/tree/staging/README.md) 6 | as well as the documentation in the [`doc/`](https://github.com/unikraft/unikraft/tree/staging/doc/) 7 | subdirectory of the main unikraft repository. 8 | -------------------------------------------------------------------------------- /unikraft/plat/options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package plat 6 | 7 | import "kraftkit.sh/kconfig" 8 | 9 | // PlatformOption is a function that modifies a PlatformConfig. 10 | type PlatformOption func(*PlatformConfig) 11 | 12 | // WithName sets the name of the platform. 13 | func WithName(name string) PlatformOption { 14 | return func(pc *PlatformConfig) { 15 | pc.name = name 16 | } 17 | } 18 | 19 | // WithVersion sets the version of the platform. 20 | func WithVersion(version string) PlatformOption { 21 | return func(pc *PlatformConfig) { 22 | pc.version = version 23 | } 24 | } 25 | 26 | // WithSource sets the source of the platform. 27 | func WithSource(source string) PlatformOption { 28 | return func(pc *PlatformConfig) { 29 | pc.source = source 30 | } 31 | } 32 | 33 | // WithPath sets the path of the platform. 34 | func WithPath(path string) PlatformOption { 35 | return func(pc *PlatformConfig) { 36 | pc.path = path 37 | } 38 | } 39 | 40 | // WithInternal sets the internal flag of the platform. 41 | func WithInternal(internal bool) PlatformOption { 42 | return func(pc *PlatformConfig) { 43 | pc.internal = internal 44 | } 45 | } 46 | 47 | // WithKConfig sets the kconfig of the platform. 48 | func WithKConfig(kconfig kconfig.KeyValueMap) PlatformOption { 49 | return func(pc *PlatformConfig) { 50 | pc.kconfig = kconfig 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /unikraft/plat/transform.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package plat 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | 11 | mplatform "kraftkit.sh/machine/platform" 12 | "kraftkit.sh/unikraft" 13 | ) 14 | 15 | // TransformFromSchema parses an input schema and returns an instantiated 16 | // PlatformConfig 17 | func TransformFromSchema(ctx context.Context, data interface{}) (interface{}, error) { 18 | uk := unikraft.FromContext(ctx) 19 | platform := PlatformConfig{} 20 | 21 | switch value := data.(type) { 22 | case string: 23 | platform.name = value 24 | default: 25 | return nil, fmt.Errorf("invalid type %T for platform", data) 26 | } 27 | 28 | // If the user has provided an alias for a known internal platform name, 29 | // rewrite it to the correct name. 30 | if alias, ok := mplatform.PlatformsByName()[platform.name]; ok { 31 | platform.name = alias.String() 32 | } 33 | 34 | if uk != nil && uk.UK_BASE != "" { 35 | platform.path, _ = unikraft.PlaceComponent( 36 | uk.UK_BASE, 37 | unikraft.ComponentTypePlat, 38 | platform.name, 39 | ) 40 | } 41 | 42 | return platform, nil 43 | } 44 | -------------------------------------------------------------------------------- /unikraft/syscall.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package unikraft 6 | 7 | import ( 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | // ProvidedSyscall is a simple structure which contains the syscall name and the 13 | // number of arguments which are accepted. 14 | type ProvidedSyscall struct { 15 | Name string 16 | Nargs uint 17 | } 18 | 19 | // NewProvidedSyscall converts an exported `UK_PROVIDED_SYSCALL` entry into a 20 | // standard `ProvidedSyscall` structure. 21 | func NewProvidedSyscall(export string) *ProvidedSyscall { 22 | syscall, snargs, found := strings.Cut(export, "-") 23 | if !found { 24 | return nil 25 | } 26 | 27 | nargs, _ := strconv.ParseUint(snargs, 10, 64) 28 | 29 | return &ProvidedSyscall{ 30 | Name: syscall, 31 | Nargs: uint(nargs), 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /unikraft/target/env.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | 6 | package target 7 | 8 | type Env map[string]string 9 | -------------------------------------------------------------------------------- /unikraft/template/options.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package template 6 | 7 | // TemplateOption is a function that modifies a TemplateConfig. 8 | type TemplateOption func(*TemplateConfig) error 9 | 10 | // WithName sets the name of the template. 11 | func WithName(name string) TemplateOption { 12 | return func(tc *TemplateConfig) error { 13 | tc.name = name 14 | return nil 15 | } 16 | } 17 | 18 | // WithVersion sets the version of the template. 19 | func WithVersion(version string) TemplateOption { 20 | return func(tc *TemplateConfig) error { 21 | tc.version = version 22 | return nil 23 | } 24 | } 25 | 26 | // WithSource sets the source of the template. 27 | func WithSource(source string) TemplateOption { 28 | return func(tc *TemplateConfig) error { 29 | tc.source = source 30 | return nil 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /unikraft/unikraft.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | // Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. 3 | // Licensed under the BSD-3-Clause License (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | package unikraft 6 | 7 | const ( 8 | // Environmental variables recognized by Unikraft's build system. 9 | UK_NAME = "CONFIG_UK_NAME" 10 | UK_DEFNAME = "CONFIG_UK_DEFNAME" 11 | UK_CONFIG = "CONFIG_UK_CONFIG" 12 | UK_FULLVERSION = "CONFIG_UK_FULLVERSION" 13 | UK_CODENAME = "CONFIG_UK_CODENAME" 14 | UK_ARCH = "CONFIG_UK_ARCH" 15 | UK_BASE = "CONFIG_UK_BASE" 16 | UK_APP = "CONFIG_UK_APP" 17 | UK_DEFCONFIG = "UK_DEFCONFIG" 18 | KCONFIG_APP_DIR = "KCONFIG_APP_DIR" 19 | KCONFIG_LIB_DIR = "KCONFIG_LIB_DIR" 20 | KCONFIG_LIB_IN = "KCONFIG_LIB_IN" 21 | KCONFIG_PLAT_DIR = "KCONFIG_PLAT_DIR" 22 | KCONFIG_PLAT_IN = "KCONFIG_PLAT_IN" 23 | 24 | // Filenames which represent ecosystem files 25 | Config_uk = "Config.uk" 26 | Exportsyms_uk = "exportsyms.uk" 27 | Linker_uk = "Linker.uk" 28 | Localsyms_uk = "localsyms.uk" 29 | Makefile_uk = "Makefile.uk" 30 | 31 | // Standard Makefile.uk variables 32 | UK_PROVIDED_SYSCALLS = "UK_PROVIDED_SYSCALLS" 33 | 34 | // Built-in paths 35 | VendorDir = ".unikraft" 36 | BuildDir = ".unikraft/build" 37 | LibsDir = ".unikraft/libs" 38 | ) 39 | --------------------------------------------------------------------------------