├── LICENSE ├── Makefile ├── README.md ├── bases ├── overlay-common │ ├── etc │ │ └── hosts.default │ ├── root │ │ ├── .s3cfg.sample │ │ └── .ssh │ │ │ └── instance_keys │ └── usr │ │ └── local │ │ ├── bin │ │ ├── oc-check-kernel │ │ ├── oc-metadata │ │ ├── oc-metadata-json │ │ ├── scw-check-kernel │ │ ├── scw-metadata │ │ └── scw-metadata-json │ │ └── sbin │ │ ├── oc-fetch-ssh-keys │ │ ├── oc-generate-ssh-keys │ │ ├── oc-image-unit │ │ ├── oc-nbd-disconnect-extra │ │ ├── oc-nbd-disconnect-root │ │ ├── oc-server-tags │ │ ├── oc-swapfile │ │ ├── oc-sync-connect-extra-volumes │ │ ├── oc-sync-kernel-headers │ │ ├── oc-sync-kernel-modules │ │ ├── oc-update-scripts │ │ ├── oc-userdata │ │ ├── scw-fetch-ssh-keys │ │ ├── scw-generate-root-passwd │ │ ├── scw-generate-ssh-keys │ │ ├── scw-image-unit │ │ ├── scw-nbd-disconnect-extra │ │ ├── scw-nbd-disconnect-root │ │ ├── scw-server-tags │ │ ├── scw-signal-state │ │ ├── scw-swapfile │ │ ├── scw-sync-connect-extra-volumes │ │ ├── scw-sync-kernel-headers │ │ ├── scw-sync-kernel-modules │ │ ├── scw-update-scripts │ │ └── scw-userdata ├── overlay-docker-based │ └── usr │ │ └── local │ │ └── sbin │ │ ├── builder-enter │ │ ├── builder-leave │ │ ├── scw-builder-enter │ │ └── scw-builder-leave ├── overlay-feature-motd │ └── etc │ │ ├── motd.head │ │ └── update-motd.d │ │ └── 50-scw ├── overlay-openrc │ ├── etc │ │ ├── conf.d │ │ │ ├── killprocs │ │ │ └── mount-ro │ │ ├── init.d │ │ │ ├── bootmisc │ │ │ ├── scw-gen-machine-id │ │ │ ├── scw-gen-root-passwd │ │ │ ├── scw-generate-net-config │ │ │ ├── scw-initramfs-shutdown │ │ │ ├── scw-net-ipv6 │ │ │ ├── scw-set-hostname │ │ │ ├── scw-signal-booted │ │ │ ├── scw-ssh-keys │ │ │ ├── scw-sshd-keys │ │ │ ├── scw-swapfile │ │ │ ├── scw-sync-kernel-extra │ │ │ └── scw-update-motd │ │ ├── motd.head │ │ └── update-motd.d │ │ │ └── 50-scw-minimal │ └── usr │ │ └── local │ │ └── sbin │ │ └── scw-set-hostname ├── overlay-systemd │ ├── etc │ │ ├── machine-id │ │ ├── scw-kernel-check.conf │ │ ├── sysctl.d │ │ │ └── 99-scaleway.conf │ │ └── systemd │ │ │ ├── system-preset │ │ │ └── 90-scw.preset │ │ │ └── system │ │ │ ├── scw-fetch-ssh-keys.service │ │ │ ├── scw-generate-net-config.service │ │ │ ├── scw-generate-root-passwd.service │ │ │ ├── scw-generate-ssh-keys.service │ │ │ ├── scw-net-ipv6.service │ │ │ ├── scw-set-hostname.service │ │ │ ├── scw-signal-booted.service │ │ │ ├── scw-swapfile.service │ │ │ └── scw-sync-kernel-modules.service │ └── usr │ │ └── local │ │ └── sbin │ │ └── scw-set-hostname ├── overlay-sysvinit │ └── etc │ │ ├── init.d │ │ ├── reboot │ │ ├── scw-force-dhclient │ │ ├── scw-signal-booted │ │ ├── scw-ssh-keys │ │ └── scw-sync-kernel-modules │ │ └── init │ │ ├── tty1.override │ │ ├── tty2.override │ │ ├── tty3.override │ │ ├── tty4.override │ │ ├── tty5.override │ │ └── tty6.override └── overlay-upstart │ └── etc │ ├── init.d │ ├── halt │ └── reboot │ └── init │ ├── scw-preserve-root-nbd-client.conf │ ├── scw-serial.conf │ ├── scw-signal-booted.conf │ ├── scw-ssh-keys.conf │ ├── scw-sync-kernel-modules.conf │ ├── tty1.override │ ├── tty2.override │ ├── tty3.override │ ├── tty4.override │ ├── tty5.override │ └── tty6.override ├── bootscript_ids ├── dockerlint.rules ├── jenkins └── image.groovy └── scripts ├── assets_server.sh ├── create_image_live_from_rootfs.sh ├── scw.sh ├── setup_credentials.sh └── test_image.sh /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Online Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Environment checkup 2 | ifndef IMAGE_DIR 3 | $(error "No image directory specified (IMAGE_DIR)") 4 | endif 5 | include $(IMAGE_DIR)/env.mk 6 | ifndef IMAGE_NAME 7 | $(error "No image base name found (IMAGE_NAME), e.g. 'ubuntu'") 8 | endif 9 | ifndef IMAGE_VERSION 10 | $(error "No image version found (IMAGE_VERSION), e.g. 'xenial'") 11 | endif 12 | ifndef IMAGE_TITLE 13 | $(error "No image title found (IMAGE_TITLE), e.g. 'Ubuntu Xenial (16.04)'") 14 | endif 15 | 16 | # Architecture variables setup 17 | ## Normalize host arch 18 | HOST_ARCH := $(shell uname -m) 19 | ifeq ($(HOST_ARCH), $(filter $(HOST_ARCH),arm armhf armv7l)) 20 | HOST_ARCH = arm 21 | else ifeq ($(HOST_ARCH), $(filter $(HOST_ARCH),arm64 aarch64)) 22 | HOST_ARCH = arm64 23 | else ifeq ($(HOST_ARCH), $(filter $(HOST_ARCH),x86_64 amd64)) 24 | HOST_ARCH = x86_64 25 | endif 26 | ARCH ?= $(HOST_ARCH) 27 | 28 | ## Normalize other arch variables 29 | ifeq ($(ARCH), $(filter $(ARCH),arm armhf armv7l)) 30 | TARGET_QEMU_ARCH=arm 31 | TARGET_SCW_ARCH=arm 32 | TARGET_DOCKER_REPO_ARCH=arm32v7 33 | TARGET_MULTIARCH_ARCH=armhf 34 | TARGET_GOLANG_ARCH=arm 35 | else ifeq ($(ARCH), $(filter $(ARCH),arm64 aarch64)) 36 | TARGET_QEMU_ARCH=aarch64 37 | TARGET_SCW_ARCH=arm64 38 | TARGET_DOCKER_REPO_ARCH=arm64v8 39 | TARGET_MULTIARCH_ARCH=arm64 40 | TARGET_GOLANG_ARCH=arm64 41 | else ifeq ($(ARCH), $(filter $(ARCH),x86_64 amd64)) 42 | TARGET_QEMU_ARCH=x86_64 43 | TARGET_SCW_ARCH=x86_64 44 | TARGET_DOCKER_REPO_ARCH=amd64 45 | TARGET_MULTIARCH_ARCH=amd64 46 | TARGET_GOLANG_ARCH=amd64 47 | endif 48 | 49 | DOCKER_NAMESPACE ?= scaleway 50 | BUILD_OPTS ?= 51 | override BUILD_ARGS += SCW_ARCH=$(TARGET_SCW_ARCH) MULTIARCH_ARCH=$(TARGET_MULTIARCH_ARCH) DOCKER_ARCH=$(TARGET_DOCKER_REPO_ARCH) 52 | REGION ?= par1 53 | export REGION 54 | BUILD_METHOD ?= from-rootfs 55 | SERVE_ASSETS ?= y 56 | EXPORT_DIR ?= $(IMAGE_DIR)/export/$(TARGET_SCW_ARCH) 57 | ASSETS_DIR ?= $(EXPORT_DIR)/assets 58 | OUTPUT_ID_TO ?= $(EXPORT_DIR)/image_id 59 | export OUTPUT_ID_TO 60 | 61 | ifdef IMAGE_BOOTSCRIPT_$(TARGET_SCW_ARCH) 62 | IMAGE_BOOTSCRIPT = $(IMAGE_BOOTSCRIPT_$(TARGET_SCW_ARCH)) 63 | endif 64 | 65 | IMAGE_DISK_SIZE ?= 10G 66 | 67 | ifeq ($(shell which scw-metadata >/dev/null 2>&1; echo $$?), 0) 68 | IS_SCW_HOST := y 69 | LOCAL_SCW_REGION := $(shell scw-metadata --cached LOCATION_ZONE_ID) 70 | export LOCAL_SCW_REGION 71 | ifeq ($(LOCAL_SCW_REGION), $(REGION)) 72 | SERVE_IP := $(shell scw-metadata --cached PRIVATE_IP) 73 | else 74 | SERVE_IP := $(shell scw-metadata --cached PUBLIC_IP_ADDRESS) 75 | endif 76 | SERVE_PORT := $(shell shuf -i 10000-60000 -n 1) 77 | else 78 | IS_SCW_HOST := n 79 | ifeq ($(SERVE_ASSETS), n) 80 | ifndef SERVE_IP 81 | $(error "Not a Scaleway host and no server IP given") 82 | endif 83 | ifndef SERVE_PORT 84 | $(error "Not a Scaleway host and no server port given") 85 | endif 86 | endif 87 | endif 88 | export IS_SCW_HOST 89 | 90 | # Default action: display usage 91 | .PHONY: usage 92 | usage: 93 | @echo 'Usage' 94 | @echo ' image build the Docker image' 95 | @echo ' rootfs.tar export the Docker image to a rootfs.tar' 96 | @echo ' scaleway_image create a Scaleway image, requires a working `scaleway-cli' 97 | @echo ' local_tests run TIM tests against the Docker image' 98 | @echo ' tests run TIM tests against the image on Scaleway' 99 | 100 | .PHONY: fclean 101 | fclean: clean 102 | for tag in latest $(shell docker images | grep "^$(DOCKER_NAMESPACE)/$(IMAGE_NAME) " | awk '{print $$2}'); do\ 103 | echo "Creating a backup of '$(DOCKER_NAMESPACE)/$(IMAGE_NAME):$$tag' for caching"; \ 104 | docker tag $(DOCKER_NAMESPACE)/$(IMAGE_NAME):$$tag old$(DOCKER_NAMESPACE)/$(IMAGE_NAME):$$tag; \ 105 | docker rmi -f $(DOCKER_NAMESPACE)/$(IMAGE_NAME):$$tag; \ 106 | done 107 | 108 | .PHONY: clean 109 | clean: 110 | -rm -f $(ASSETS_DIR) $(EXPORT_DIR)/export.tar 111 | -rm -rf $(EXPORT_DIR)/rootfs 112 | 113 | $(EXPORT_DIR): 114 | mkdir -p $(EXPORT_DIR) 115 | 116 | $(ASSETS_DIR): 117 | mkdir -p $(ASSETS_DIR) 118 | 119 | .PHONY: image 120 | image: $(EXPORT_DIR) 121 | ifneq ($(TARGET_SCW_ARCH), $(HOST_ARCH)) 122 | docker run --rm --privileged multiarch/qemu-user-static:register --reset 123 | endif 124 | ifdef IMAGE_BASE_FLAVORS 125 | $(foreach bf,$(IMAGE_BASE_FLAVORS),rsync -az bases/overlay-$(bf)/ $(IMAGE_DIR)/overlay-base;) 126 | endif 127 | docker build $(BUILD_OPTS) -t $(DOCKER_NAMESPACE)/$(IMAGE_NAME):$(TARGET_SCW_ARCH)-$(IMAGE_VERSION) $(foreach ba,$(BUILD_ARGS),--build-arg $(ba)) $$([ -r Dockerfile.$(TARGET_SCW_ARCH) ] && echo "-f Dockerfile.$(TARGET_SCW_ARCH)") $(IMAGE_DIR) 128 | echo $(DOCKER_NAMESPACE)/$(IMAGE_NAME):$(TARGET_SCW_ARCH)-$(IMAGE_VERSION) >$(EXPORT_DIR)/docker_tags 129 | $(eval IMAGE_VERSION_ALIASES += $(IMAGE_VERSION)-$(shell date +%Y-%m-%d)) 130 | $(foreach v,$(IMAGE_VERSION_ALIASES),\ 131 | docker tag $(DOCKER_NAMESPACE)/$(IMAGE_NAME):$(TARGET_SCW_ARCH)-$(IMAGE_VERSION) $(DOCKER_NAMESPACE)/$(IMAGE_NAME):$(TARGET_SCW_ARCH)-$v;\ 132 | echo $(DOCKER_NAMESPACE)/$(IMAGE_NAME):$(TARGET_SCW_ARCH)-$v >>$(EXPORT_DIR)/docker_tags;) 133 | 134 | $(ASSETS_DIR)/rootfs.tar: image $(ASSETS_DIR) 135 | echo "IMAGE_ID=\"$(IMAGE_TITLE)\"" >> $(EXPORT_DIR)/scw-release 136 | echo "IMAGE_RELEASE=$(shell date +%Y-%m-%d)" >> $(EXPORT_DIR)/scw-release 137 | echo "IMAGE_CODENAME=$(IMAGE_NAME)" >> $(EXPORT_DIR)/scw-release 138 | echo "IMAGE_DESCRIPTION=\"$(IMAGE_DESCRIPTION)\"" >> $(EXPORT_DIR)/scw-release 139 | echo "IMAGE_HELP_URL=\"$(IMAGE_SOURCE_URL)\"" >> $(EXPORT_DIR)/scw-release 140 | echo "IMAGE_SOURCE_URL=\"$(IMAGE_SOURCE_URL)\"" >> $(EXPORT_DIR)/scw-release 141 | echo "IMAGE_DOC_URL=\"$(IMAGE_SOURCE_URL)\"" >> $(EXPORT_DIR)/scw-release 142 | cat $(EXPORT_DIR)/scw-release | docker run --name $(IMAGE_NAME)-$(IMAGE_VERSION)-export -i $(DOCKER_NAMESPACE)/$(IMAGE_NAME):$(TARGET_SCW_ARCH)-$(IMAGE_VERSION) sh -c "rm /.dockerenv; cat >/etc/scw-release" 2>/dev/null || true 143 | docker export -o $@.tmp $(IMAGE_NAME)-$(IMAGE_VERSION)-export 144 | docker rm $(IMAGE_NAME)-$(IMAGE_VERSION)-export 145 | mv $@.tmp $@ 146 | 147 | rootfs.tar: $(ASSETS_DIR)/rootfs.tar 148 | ls -la $< 149 | @echo $< 150 | 151 | from-rootfs-common: rootfs.tar 152 | $(eval ROOTFS_URL := $(SERVE_IP):$(SERVE_PORT)/rootfs.tar) 153 | ifeq ($(SERVE_ASSETS), y) 154 | scripts/assets_server.sh start $(SERVE_PORT) $(ASSETS_DIR) 155 | endif 156 | scripts/create_image_live_from_rootfs.sh "$(ROOTFS_URL)" "$(IMAGE_TITLE)" "$(TARGET_SCW_ARCH)" "$(IMAGE_DISK_SIZE)" "$(IMAGE_BOOTSCRIPT)" "$(BUILD_METHOD)" 157 | ifeq ($(SERVE_ASSETS), y) 158 | scripts/assets_server.sh stop $(SERVE_PORT) 159 | endif 160 | 161 | from-rootfs: from-rootfs-common 162 | 163 | unpartitioned-from-rootfs: from-rootfs-common 164 | 165 | .PHONY: scaleway_image 166 | scaleway_image: $(BUILD_METHOD) 167 | 168 | .PHONY: tests 169 | tests: $(EXPORT_DIR) 170 | scripts/test_image.sh start $(TARGET_SCW_ARCH) $(REGION) $(IMAGE_ID) $(EXPORT_DIR)/$(IMAGE_ID).servers $(IMAGE_DIR)/tim_tests 171 | ifneq ($(NO_CLEANUP), true) 172 | scripts/test_image.sh stop $(EXPORT_DIR)/$(IMAGE_ID).servers 173 | endif 174 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scaleway Image Toolbox 2 | 3 | This repository contains the tools, documentation, examples and content for creating images on [Scaleway](https://www.scaleway.com/). 4 | 5 | 6 | ## Distribution images & Instant Apps 7 | 8 | Official Scaleway images are found as git repositories on Github, in two organizations: 9 | * [scaleway](https://github.com/scaleway), which focuses on bases images and distributions, with names prefixed by "image-" 10 | * [scaleway-community](https://github.com/scaleway-community) is dedicated to Instant Apps and ready-to-use images, where names are prefixed with "scaleway-". 11 | 12 | Your contributions are welcome ! 13 | 14 | Your custom images can be anywhere, though, they don't even need to be in repositories. 15 | 16 | 17 | ## Getting started 18 | 19 | ### Simple images 20 | 21 | On Scaleway, images are created by tagging an existing snapshot appropriately. This can be done with the [`scw` CLI tool](https://github.com/scaleway/scaleway-cli) (or alternatively, using the [console](https://cloud.scaleway.com) or directly through [the API](https://developer.scaleway.com)): 22 | 23 | ``` 24 | # Using the scw tool -- this assumes you've already set it up. 25 | # Create a snapshot first: 26 | $ scw commit -v 1 my-server my-snapshot 27 | f3af311c-53f7-4f5d-9252-0bf69f017269 28 | 29 | # Now make an image out of it: 30 | $ scw tag --arch=x86_64 --bootscript="mainline 4.14" my-snapshot my-image 31 | a601dbac-08cb-4af3-9ff6-73b7e8dfd34f 32 | 33 | $ scw images 34 | REPOSITORY TAG IMAGE ID CREATED REGION ARCH 35 | user/my-image latest a601dbac 5 seconds [ par1] [x86_64] 36 | ---- snipping all stock images 8< ---- 37 | ``` 38 | 39 | ### Docker-based images 40 | 41 | Using the tools contained in this repository, it is possible to create Scaleway images from Docker images. At its core, this process uses the tools we explored above and is pretty straightforward to use: 42 | 1. Clone this repository and the repository of the image (if there is one) on a Scaleway instance 43 | 2. In your terminal, navigate to the image-tools directory, and type `make IMAGE_DIR= scaleway_image` 44 | 3. ??? 45 | 4. Profit ! 46 | 47 | As a first example, let's simply rebuild our Ubuntu Xenial image without changing anything. Note that this is not needed to build your own Docker-based images, and is shown here only for demonstration purposes. 48 | 49 | [![asciicast](https://asciinema.org/a/foiok7e9gWnyqKK6HbWQIaAQz.png)](https://asciinema.org/a/foiok7e9gWnyqKK6HbWQIaAQz) 50 | 51 | Now that we've had a first taste, let's create a custom image based on Scaleway's Ubuntu image: 52 | 53 | [![asciicast](https://asciinema.org/a/qRVW81Ciqd1eeoki3Enyn3X7e.png)](https://asciinema.org/a/qRVW81Ciqd1eeoki3Enyn3X7e) 54 | 55 | To recap, here's what's needed for a custom Docker-based image: 56 | - A Dockerfile with an `ARCH` buildarg, based on any Docker image as long as the `FROM` chain can be traced back to one of Scaleway's official images on the Dockerhub: this is needed so that your custom image will ship with the needed tools, configuration and initialization scripts. 57 | - An env.mk file, containing metadata for the builder tool. It must be valid makefile syntax and will be included at the beginning of the build process. It must at least set the following variables: `IMAGE_NAME`, `IMAGE_VERSION` and `IMAGE_TITLE` but can also set other information, such as authorship, or extra buildargs for Docker with `BUILD_ARGS`. 58 | 59 | All the rest is up to you and your creativity ! You can, for example, upload your images to the Dockerhub and start using them as bases for other images. 60 | 61 | After building, the image and associated snapshots will be available for use with your account. Note that introducing name conflicts will force you to use the ids to interact with the images through the CLI. 62 | 63 | 64 | ## Diving below the surface 65 | 66 | This section mainly deals with explaining with what happens during the build process. Reading it is not required to be able to create images. 67 | 68 | As explained above, images are created by tagging a snapshot. Snapshots capture the state of a server's volume at a certain point in time. The simplicity of this step is what makes it versatile: as long as you can somehow get a server to boot and populate one of its volume with some data, you can create a Scaleway Image. 69 | 70 | From there, images can be built in many ways. An example would be to use a server with two volumes, using the first as a system volume and populating the second one as needed (parted, mkfs, debootstrap, pacstrap, etc...) before taking a snapshot of it. Snapshots can only be created when the server is off, though, so you would need to stop it. This can get a bit complicated when you need to build images repeatedly, and requires you to have a dedicated server for the pupose of image creation, so it might be a bit unpractical. 71 | 72 | ### The build initrd 73 | 74 | To make things easier, we created a lightweight tool for the purpose of image creation in the form of a [special initrd](https://github.com/scaleway/initrd/tree/master/build). An initrd, short for **initial ramdisk**, is a minimal root filesystem that is loaded in memory and mounted from there. In its classic form, an initrd is used to setup the core components of the system and finding the real root filesystem, before surrendering execution to the OS' *init*. 75 | 76 | This build initrd is a bit different, as it does not aim to hook into a complete boot and will never call init. It is a intended to be used via a remote boot through preset bootscripts, which are specifications of a kernel + initrd that we feed into [IPXE](http://ipxe.org), the network boot firmware. A server can be assigned a bootscript at creation. The ids of the build bootscripts for different architectures can be found in the `bootscript_ids` file at the root of this project. It can also be accessed with the name "Image creation bootscript". 77 | 78 | Detailed information can be found in the initrd's repository, but let's recap its features broadly. 79 | 80 | The build initrd offers different methods for building images, which are a collection of scripts. After setting up the network and retrieving metadata, it will use the method specified in the `build_method` parameter given through the metadata environment. Each method requires specific arguments. 81 | 82 | The main method used by the image-tools suite is `from-rootfs`, which will retrieve a tarred rootfs from a given location and will apply it to the volume after setting up partitions (Linux, EFI) and their associated filesystem (ext4, fat32). GRUB EFI will then be installed to the partition. For example: 83 | 84 | ``` 85 | $ scw create --bootscript="image creation" --env="build_method=from-rootfs rootfs_url=" 50G 86 | ``` 87 | 88 | Other build methods also exist: 89 | - `from-qcow2`, which will copy a qcow2 file's content to the device, 90 | - `unpartitioned-from-rootfs` which will skip the partitions and EFI setup and use the raw device with an ext4 filesystem. Obviously, these images can only be booted remotely. 91 | 92 | Finally, the build initrd will signal the completion of its job by opening a port given to it through the `signal_build_done_port` parameter, or 22 by default. 93 | -------------------------------------------------------------------------------- /bases/overlay-common/etc/hosts.default: -------------------------------------------------------------------------------- 1 | 127.0.1.1 server 2 | 127.0.0.1 localhost server 3 | ::1 localhost ip6-localhost ip6-loopback 4 | ff02::1 ip6-allnodes 5 | ff02::2 ip6-allrouters -------------------------------------------------------------------------------- /bases/overlay-common/root/.s3cfg.sample: -------------------------------------------------------------------------------- 1 | [default] 2 | default_mime_type = binary/octet-stream 3 | delete_removed = False 4 | dry_run = False 5 | enable_multipart = True 6 | encoding = UTF-8 7 | encrypt = False 8 | follow_symlinks = False 9 | force = False 10 | get_continue = False 11 | gpg_command = /usr/bin/gpg 12 | gpg_decrypt = %(gpg_command)s -d --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s 13 | gpg_encrypt = %(gpg_command)s -c --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s 14 | gpg_passphrase = 15 | guess_mime_type = True 16 | host_base = s3.%(location)s.scw.cloud 17 | host_bucket = %(bucket)s.s3.%(location)s.scw.cloud 18 | human_readable_sizes = False 19 | invalidate_on_cf = False 20 | list_md5 = False 21 | log_target_prefix = 22 | mime_type = 23 | multipart_chunk_size_mb = 250 24 | preserve_attrs = True 25 | progress_meter = True 26 | recursive = False 27 | recv_chunk = 256000 28 | reduced_redundancy = False 29 | send_chunk = 256000 30 | signature_v2 = False 31 | skip_existing = False 32 | socket_timeout = 300 33 | urlencoding_mode = normal 34 | use_https = True 35 | verbosity = WARNING 36 | website_endpoint = https://%(bucket)s.s3.%(location)s.scw.cloud/ 37 | website_error = 38 | website_index = index.html 39 | check_ssl_certificate = True 40 | check_ssl_hostname = True 41 | 42 | access_key = INSERT_ORGANIZATION_ID 43 | secret_key = INSERT_PRIVATE_TOKEN 44 | bucket_location = INSERT_S3_REGION 45 | location = INSERT_S3_REGION 46 | -------------------------------------------------------------------------------- /bases/overlay-common/root/.ssh/instance_keys: -------------------------------------------------------------------------------- 1 | # Here you can put your custom ssh keys 2 | # They will be concatenated to '/root/.ssh/authorized_keys' 3 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/bin/oc-check-kernel: -------------------------------------------------------------------------------- 1 | scw-check-kernel -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/bin/oc-metadata: -------------------------------------------------------------------------------- 1 | scw-metadata -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/bin/oc-metadata-json: -------------------------------------------------------------------------------- 1 | scw-metadata-json -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/bin/scw-check-kernel: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "checks the version/config of the kernel" 3 | # author "Scaleway " 4 | set -eu 5 | 6 | CONFIG_FILE=/etc/scw-kernel-check.conf 7 | 8 | warn_expect_kernel() { 9 | echo "Warning: this image expects a Linux kernel $*;" \ 10 | "consider using another scaleway bootscript." \ 11 | | tee /dev/stderr /dev/console 12 | } 13 | 14 | warn_version() { 15 | warn_expect_kernel \ 16 | ">= $EXPECT_MAJOR_MIN.${EXPECT_MINOR_MIN:-0}" \ 17 | "(you are using $KERNEL_VERSION)" 18 | } 19 | 20 | warn_config() { 21 | warn_expect_kernel "with $1" 22 | } 23 | 24 | check_version() { 25 | [ "${EXPECT_MAJOR_MIN+}" ] || return 0 26 | [ "$MAJOR" -gt "$EXPECT_MAJOR_MIN" ] && return 0 27 | [ "$MAJOR" -lt "$EXPECT_MAJOR_MIN" ] && return 1 28 | 29 | [ "${EXPECT_MINOR_MIN+}" ] || return 0 30 | [ "$MINOR" -gt "$EXPECT_MINOR_MIN" ] && return 0 31 | [ "$MINOR" -lt "$EXPECT_MINOR_MIN" ] && return 1 32 | 33 | return 0 34 | } 35 | 36 | expect_config() { 37 | if [ "$EXPECT_VALUE" = y ]; then 38 | zcat /proc/config.gz | grep -q "^$EXPECT_CONF=y" || return 1 39 | elif [ "$EXPECT_VALUE" = n ]; then 40 | zcat /proc/config.gz | grep -q "^$EXPECT_CONF=[ym]" && return 1 41 | fi 42 | return 0 43 | } 44 | 45 | [ -f "$CONFIG_FILE" ] || exit 0 46 | . "$CONFIG_FILE" 47 | 48 | FAILED=0 49 | 50 | # check if the current kernel version is >= to the expected one 51 | KERNEL_VERSION=$(uname -r) 52 | # extract number before first dot 53 | MAJOR=${KERNEL_VERSION%%.*} 54 | # two-step substitution to extract second number between dots 55 | MINOR=${KERNEL_VERSION#.*} 56 | MINOR=${MINOR%%.*} 57 | 58 | if ! check_version; then 59 | warn_version 60 | FAILED=1 61 | fi 62 | 63 | # check any additional required configs 64 | for EXPECT_CONFIG in $(set | grep '^EXPECT_CONFIG_'); do 65 | EXPECT_LINE=${EXPECT_CONFIG#EXPECT_} 66 | EXPECT_CONF=${EXPECT_LINE%%=*} 67 | eval "EXPECT_VALUE=\${EXPECT_$EXPECT_CONF}" 68 | 69 | if ! expect_config; then 70 | warn_config "$EXPECT_LINE" 71 | FAILED=1 72 | fi 73 | done 74 | 75 | exit "$FAILED" 76 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/bin/scw-metadata: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "executable which retrieves server metadata (TEXT)" 3 | # author "Scaleway " 4 | 5 | export PATH="${PATH:+$PATH:}/usr/bin:/bin" 6 | 7 | CACHE_FILE=/run/scw-metadata.cache 8 | METADATA_IP=${METADATA_IP:-169.254.42.42} 9 | METADATA_URL=${METADATA_URL:-"http://${METADATA_IP}/conf"} 10 | 11 | if [ "$1" = "--cached" -a -f $CACHE_FILE ]; then 12 | shift 13 | BODY=$(cat $CACHE_FILE) 14 | else 15 | [ "$1" = "--cached" ] && shift 16 | if hash curl 2>/dev/null; then 17 | # Using curl 18 | CODE=0 19 | while [ $CODE -ne 200 ]; do 20 | RESPONSE=$(curl --noproxy '*' --silent --write-out "\n%{http_CODE}\n" $METADATA_URL) 21 | CODE=$(echo "$RESPONSE" | sed -n '$p') 22 | BODY=$(echo "$RESPONSE" | sed '$d') 23 | 24 | if [ $CODE -eq 200 ]; then 25 | echo "$BODY" > /run/scw-metadata.cache 26 | ln -s scw-metadata.cache /run/oc-metadata.cache 2>/dev/null 27 | break 28 | fi 29 | sleep 5 30 | done 31 | else 32 | # Using wget 33 | for i in 1 2 3 4 5; do 34 | BODY=$(wget --no-proxy --quiet -O- $METADATA_URL) 35 | echo "$BODY" | grep PRIVATE_IP >/dev/null 36 | if [ $? -eq 0 ]; then 37 | echo "$BODY" > /run/scw-metadata.cache 38 | ln -s scw-metadata.cache /run/oc-metadata.cache 2>/dev/null 39 | break 40 | fi 41 | sleep 2 42 | done 43 | fi 44 | fi 45 | 46 | if [ "$#" -ne 1 ]; then 47 | echo "$BODY" 48 | else 49 | key="$1" 50 | echo "$BODY" | grep "^$key=" | sed "s/^[^=]*=//;s/^['\"]//;s/['\"]$//" 51 | fi 52 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/bin/scw-metadata-json: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "executable which retrieves server metadata (JSON)" 3 | # author "Scaleway " 4 | 5 | export PATH="${PATH:+$PATH:}/usr/bin:/bin" 6 | 7 | CODE=0 8 | while [ $CODE -ne 200 ] 9 | do 10 | RESPONSE=$(curl --noproxy '*' --silent --write-out "\n%{http_CODE}\n" http://169.254.42.42/conf?format=json) 11 | CODE=$(echo "$RESPONSE" | sed -n '$p') 12 | BODY=$(echo "$RESPONSE" | sed '$d') 13 | test $CODE -eq 200 && break 14 | sleep 5 15 | done 16 | 17 | echo "$BODY" 18 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-fetch-ssh-keys: -------------------------------------------------------------------------------- 1 | scw-fetch-ssh-keys -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-generate-ssh-keys: -------------------------------------------------------------------------------- 1 | scw-generate-ssh-keys -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-image-unit: -------------------------------------------------------------------------------- 1 | scw-image-unit -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-nbd-disconnect-extra: -------------------------------------------------------------------------------- 1 | scw-nbd-disconnect-extra -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-nbd-disconnect-root: -------------------------------------------------------------------------------- 1 | scw-nbd-disconnect-root -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-server-tags: -------------------------------------------------------------------------------- 1 | scw-server-tags -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-swapfile: -------------------------------------------------------------------------------- 1 | scw-swapfile -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-sync-connect-extra-volumes: -------------------------------------------------------------------------------- 1 | scw-sync-connect-extra-volumes -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-sync-kernel-headers: -------------------------------------------------------------------------------- 1 | scw-sync-kernel-headers -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-sync-kernel-modules: -------------------------------------------------------------------------------- 1 | scw-sync-kernel-modules -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-update-scripts: -------------------------------------------------------------------------------- 1 | scw-update-scripts -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/oc-userdata: -------------------------------------------------------------------------------- 1 | scw-userdata -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-fetch-ssh-keys: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "fetch SSH keys" 3 | # author "Scaleway " 4 | # source "https://github.com/scaleway/image-tools/blob/master/skeleton-common/usr/local/sbin/scw-fetch-ssh-keys" 5 | 6 | set -e 7 | 8 | # ensure /root/.ssh exists and has correct permissions 9 | mkdir -p /root/.ssh 10 | chmod 700 /root/.ssh 11 | 12 | # ensure /root has the correct permissions 13 | chown root:root /root 14 | chmod 700 /root 15 | 16 | # `--upgrade` refreshes the metadata cache 17 | if [ "$1" = "--upgrade" ]; then 18 | /usr/local/bin/scw-metadata > /dev/null 19 | fi 20 | 21 | cat << EOF > /root/.ssh/authorized_keys 22 | # 23 | # WARNING: Automatically generated file 24 | # This file will be erased at every boot 25 | # This file was generated with '/usr/local/sbin/scw-fetch-ssh-keys' 26 | # 27 | # To add a new key, you can: 28 | # -- Add keys on your Scaleway account https://cloud.scaleway.com/#/credentials 29 | # -- Add keys using server tags - https://cloud.scaleway.com/#/servers/$(scw-metadata --cached ID) 30 | # - i.e: "AUTHORIZED_KEY=ssh-rsa_XXXXXXXXXXX AUTHORIZED_KEY=ssh-rsa_YYYYYYYYYYYYYYY" 31 | # - Be sure to replace all spaces with underscores 32 | # - $> sed 's/ /_/g' ~/.ssh/id_rsa.pub 33 | # -- Add the keys to '/root/.ssh/instance_keys' which will be imported 34 | # 35 | # And recreate your 'authorized_keys' file with the new keys: 36 | # -- Run 'scw-fetch-ssh-keys --upgrade' 37 | # 38 | EOF 39 | 40 | # add Scaleway account keys 41 | /usr/local/bin/scw-metadata --cached | grep SSH_PUBLIC_KEYS_.*_KEY | cut -d'=' -f 2- | tr -d \' >> /root/.ssh/authorized_keys 42 | 43 | # add Server tags keys 44 | /usr/local/bin/scw-metadata --cached | grep TAGS_.*=AUTHORIZED_KEY | cut -d'=' -f 3- | sed 's/_/\ /g' >> /root/.ssh/authorized_keys 45 | 46 | # Import custom keys 47 | if [ -f /root/.ssh/instance_keys ]; then 48 | cat << EOF >> /root/.ssh/authorized_keys 49 | # Below your custom ssh keys from '/root/.ssh/instance_keys' 50 | EOF 51 | (cat /root/.ssh/instance_keys | grep -v "^#" || true) >> /root/.ssh/authorized_keys 52 | fi 53 | 54 | # authorized_keys should only be readable by the owner and no one else 55 | chmod 0600 /root/.ssh/authorized_keys 56 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-generate-root-passwd: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | rootpasswd=$(tr -dc 'A-Za-z0-9' /root/.pw 5 | (echo $rootpasswd; echo $rootpasswd) | passwd root 6 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-generate-ssh-keys: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "generate SSH keys" 3 | # author "Scaleway " 4 | 5 | # Generate ssh host keys if not present 6 | if test -z "$(find /etc/ssh/ -iname 'ssh_host_*_key*')"; then 7 | ssh-keygen -A 8 | fi 9 | scw-userdata ssh-host-fingerprints "$(find /etc/ssh/ -iname "ssh_host_*_key" -exec ssh-keygen -lf \{\} \;)" 10 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-image-unit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "run image unit tests on current image" 3 | # author "Scaleway " 4 | 5 | set -e 6 | 7 | export PATH="${PATH:+$PATH:}/usr/bin:/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin" 8 | 9 | curl -s https://raw.githubusercontent.com/scaleway/image-tools/master/builder/unit.bash > /tmp/scw-image-unit-suite.bash 10 | bash /tmp/scw-image-unit-suite.bash 11 | rm -f /tmp/scw-image-unit-suite.bash 12 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-nbd-disconnect-extra: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "disconnect extra NBD volumes" 3 | # author "Scaleway " 4 | 5 | XNBD_CLIENT=/run/initramfs/usr/sbin/xnbd-client 6 | 7 | for device in /dev/nbd[!0]* 8 | do 9 | ($XNBD_CLIENT -c $device && $XNBD_CLIENT -d $device > /dev/null 2>&1) || true 10 | done 11 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-nbd-disconnect-root: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "disconnect root NBD volume" 3 | # author "Scaleway " 4 | 5 | XNBD_CLIENT=/run/initramfs/usr/sbin/xnbd-client 6 | $XNBD_CLIENT --version > /dev/null 2>&1 7 | $XNBD_CLIENT -d /dev/nbd0 8 | echo "b" > /proc/sysrq-trigger 9 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-server-tags: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$1" = "" ]; then 4 | scw-metadata --cached | grep "^TAGS_" | cut -d'=' -f2-3 5 | exit 0 6 | fi 7 | 8 | VALUE=$(scw-metadata --cached | grep "^TAGS_" | cut -d'=' -f2-3 | grep "^$1") 9 | VALUE1=$(echo $VALUE | awk -F'=' '{print $1}') 10 | VALUE2=$(echo $VALUE | awk -F'=' '{print $2}') 11 | if [ "$VALUE1" = "" ]; then 12 | echo "0" 13 | exit 1 14 | fi 15 | if [ "$VALUE2" = "" ]; then 16 | echo "1" 17 | else 18 | echo $VALUE2 19 | fi 20 | exit 0 21 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-signal-state: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "signals the hypervisor that the machine is booted" 3 | # author "Scaleway " 4 | 5 | SERVER=169.254.42.42 6 | STATE=$1 7 | 8 | curl -s --fail -XPATCH -H "Content-Type: application/json" "$SERVER"/state \ 9 | -d "{\"state_detail\": \"$STATE\"}" -o /dev/null 10 | 11 | if [ $? -eq 0 ]; then 12 | echo "$STATE signal sent!" 13 | else 14 | echo "Can't send $STATE signal" 15 | exit 1 16 | fi 17 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-swapfile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "enables a swapfile" 3 | # author "Scaleway " 4 | 5 | if ! type fallocate >/dev/null 2>/dev/null; then 6 | echo "No such 'fallocate' binary, please install 'util-linux'." 7 | exit 1 8 | fi 9 | 10 | SWAPFILE_SIZE=4G 11 | SWAPFILE_PATH=/swapfile 12 | 13 | swapfile_off() { 14 | if [ -f $SWAPFILE_PATH ] 15 | then 16 | # this is unfortunate: we have now way of telling NBD that 17 | # this file is actually uneeded and we need not to save it in 18 | # the block device behind (trying to take advantage of 19 | # compression by zero-ing it does not work). 20 | # 21 | # this means that if we swap, swapped data will be uploaded on 22 | # the object storage anyway. 23 | swapoff $SWAPFILE_PATH 24 | rm -f $SWAPFILE_PATH 25 | fi 26 | } 27 | 28 | swapfile_on() { 29 | # we recreate this file even if it already exists: this way we 30 | # handle updates of settings in /etc/scaleway.conf 31 | fallocate -l $SWAPFILE_SIZE $SWAPFILE_PATH 32 | chmod 600 $SWAPFILE_PATH 33 | mkswap $SWAPFILE_PATH 34 | swapon $SWAPFILE_PATH 35 | } 36 | 37 | case $1 in 38 | "start") 39 | swapfile_on > /dev/null 40 | exit $? 41 | ;; 42 | 43 | "stop") 44 | swapfile_off > /dev/null 45 | exit $? 46 | ;; 47 | esac 48 | 49 | echo >&2 "usage: $0 [start|stop]" ; exit 1 50 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-sync-connect-extra-volumes: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "sync connect extra NBD volumes" 3 | # author "Scaleway " 4 | 5 | XNBD_CLIENT=/run/initramfs/usr/sbin/xnbd-client 6 | 7 | get_value() { 8 | /usr/local/bin/scw-metadata --cached "$1" 9 | } 10 | 11 | sync_connect_extra_volumes() { 12 | for nbd_id in $(get_value VOLUMES) 13 | do 14 | # ignore root nbd device, it is handled differently. 15 | test $nbd_id -eq 0 && continue 16 | 17 | export_uri=$(get_value "VOLUMES_${nbd_id}_EXPORT_URI") 18 | nbd_host=$(echo $export_uri | sed 's|nbd://\(.*\):.*|\1|') 19 | nbd_port=$(echo $export_uri | sed 's|nbd://.*:\(.*\)|\1|') 20 | 21 | device="/dev/nbd${nbd_id}" 22 | until $XNBD_CLIENT -c $device > /dev/null 2>&1 23 | do 24 | ($XNBD_CLIENT $nbd_host $nbd_port -b 4096 $device || sleep 1) > /dev/null 2>&1 25 | done 26 | done 27 | } 28 | 29 | sync_connect_extra_volumes 30 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-sync-kernel-headers: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "synchronizes kernel headers" 3 | # author "Scaleway " 4 | 5 | set -e 6 | 7 | DIR=/usr 8 | mkdir -p $DIR 9 | KVERSION=`uname -r` 10 | MACHINE=`uname -m` 11 | export PATH="${PATH:+$PATH:}/usr/bin:/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin" 12 | 13 | wget -q -O - http://mirror.scaleway.com/kernel/${MACHINE}/${KVERSION}/include.tar | tar -C ${DIR} -xf - 14 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-sync-kernel-modules: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # description "synchronizes kernel module" 3 | # author "Scaleway " 4 | 5 | set -e -o pipefail 6 | 7 | DIR=/lib/modules 8 | mkdir -p $DIR 9 | TMP_DIR=`mktemp -d -p $DIR` 10 | KVERSION=`uname -r` 11 | KARCH=`uname -m` 12 | TIMEOUT=10 13 | 14 | export PATH="${PATH:+$PATH:}/usr/bin:/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin" 15 | 16 | clean() { 17 | rm -rf "$TMP_DIR" 2>/dev/null 18 | } 19 | trap 'clean' INT TERM EXIT 20 | 21 | if [ ! -d $DIR/${KVERSION} ]; then 22 | curl -fsSL http://mirror.scaleway.com/kernel/${KARCH}/${KVERSION}/modules.tar | tar -C $TMP_DIR -x --strip-component 1 23 | if [ $? -eq 0 ]; then 24 | mkdir -p $DIR/${KVERSION} 25 | mv $TMP_DIR/${KVERSION} $DIR 26 | fi 27 | fi 28 | 29 | depmod -a 30 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-update-scripts: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$FLAVORS" = "" ]; then 4 | if [ -f /etc/scw-release ]; then 5 | FLAVORS=$(cat /etc/scw-release | grep "^IMAGE_FLAVORS=" | tr -d '"' | tr ' ' ',' | cut -d'=' -f2) 6 | fi 7 | fi 8 | FLAVORS=${FLAVORS:-common} 9 | 10 | echo -n "This script will update (overwrite) scaleway's scripts, continue (y/N)? " 11 | read ANSWER 12 | if [ "$ANSWER" = "y" -o "$ANSWER" = "Y" ]; then 13 | curl -Lq https://j.mp/scw-skeleton | FLAVORS=$FLAVORS sh 14 | fi 15 | -------------------------------------------------------------------------------- /bases/overlay-common/usr/local/sbin/scw-userdata: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # description "executable which retrieves server userdata (TEXT)" 3 | # author "Scaleway " 4 | 5 | export PATH="${PATH:+$PATH:}/usr/bin:/bin" 6 | 7 | USERDATA_IP=${USERDATA_IP:-169.254.42.42} 8 | USERDATA_URL=${USERDATA_URL:-"http://${USERDATA_IP}/user_data"} 9 | 10 | get() { 11 | URL=$1 12 | if type curl >/dev/null 2>/dev/null; then 13 | # Using curl 14 | RESPONSE=$(curl --local-port 1-1024 --noproxy '*' --silent --write-out "\n%{http_CODE}\n" $URL) 15 | CODE=$(echo "$RESPONSE" | sed -n '$p') 16 | BODY=$(echo "$RESPONSE" | sed '$d') 17 | echo "$BODY" 18 | else 19 | echo "'curl' dependency is missing." >&2 20 | fi 21 | } 22 | 23 | patch() { 24 | URL="$1" 25 | DATA="$2" 26 | if type curl >/dev/null 2>/dev/null; then 27 | # Using curl 28 | RESPONSE=$(curl --local-port 1-1024 --noproxy '*' -X PATCH -d "$DATA" -H "Content-Type: text/plain" --silent --write-out "\n%{http_CODE}\n" $URL) 29 | else 30 | echo "'curl' dependency is missing." >&2 31 | fi 32 | } 33 | 34 | if [ "$1" = "" ]; then 35 | get "$USERDATA_URL/" 36 | else 37 | if [ "$2" = "" ]; then 38 | get "$USERDATA_URL/$1" 39 | else 40 | patch "$USERDATA_URL/$1" "$2" 41 | fi 42 | fi 43 | -------------------------------------------------------------------------------- /bases/overlay-docker-based/usr/local/sbin/builder-enter: -------------------------------------------------------------------------------- 1 | scw-builder-enter -------------------------------------------------------------------------------- /bases/overlay-docker-based/usr/local/sbin/builder-leave: -------------------------------------------------------------------------------- 1 | scw-builder-leave -------------------------------------------------------------------------------- /bases/overlay-docker-based/usr/local/sbin/scw-builder-enter: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script will prepare the rootfs for the docker-based image-builder 4 | # toolsuite 5 | 6 | set -e 7 | 8 | lsb_dist="$(lsb_release -si 2>/dev/null || (test -f /etc/lsb-release && . /etc/lsb-release; echo ${DISTRIB_ID:-no_lsb}))" 9 | lsb_release="$(lsb_release -sr 2>/dev/null || (test -f /etc/lsb-release && . /etc/lsb-release; echo ${DISTRIB_RELEASE:-no_lsb}))" 10 | 11 | case "$lsb_dist" in 12 | Ubuntu) 13 | # prevent init scripts from running during install/update 14 | printf '#!/bin/sh\nexit 101\n' > /usr/sbin/policy-rc.d && \ 15 | chmod +x /usr/sbin/policy-rc.d 16 | if [ -f /sbin/initctl.distrib ]; then 17 | mv /sbin/initctl.distrib /sbin/initctl 18 | fi 19 | cp /sbin/initctl /sbin/initctl.orig 20 | printf '#!/bin/sh\nexit 0\n' > /sbin/initctl 21 | dpkg-divert --local --rename --add /sbin/initctl 22 | ;; 23 | Debian) 24 | # prevent init scripts from running during install/update 25 | printf '#!/bin/sh\nexit 101\n' > /usr/sbin/policy-rc.d && \ 26 | chmod +x /usr/sbin/policy-rc.d 27 | ;; 28 | *) 29 | echo "Warning: unsupported distribution $lsb_dist ($lsb_release)" >&2 30 | ;; 31 | esac 32 | 33 | 34 | # Ensure /dev as the minimum devices set 35 | test -c /dev/null || mknod -m 0666 /dev/null c 1 3 36 | test -c /dev/zero || mknod -m 0666 /dev/zero c 1 5 37 | test -c /dev/full || mknod -m 0666 /dev/full c 1 7 38 | test -c /dev/tty || mknod -m 0666 /dev/tty c 5 0 39 | test -c /dev/tty0 || mknod -m 0640 /dev/tty0 c 4 0 40 | test -c /dev/urandom || mknod -m 0666 /dev/urandom c 1 9 41 | test -c /dev/random || mknod -m 0666 /dev/random c 1 8 42 | test -c /dev/console || mknod -m 0600 /dev/console c 5 1 43 | -------------------------------------------------------------------------------- /bases/overlay-docker-based/usr/local/sbin/scw-builder-leave: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script will clean the rootfs for a normal usage. 4 | # Globally, it will cancel effects of the builder-enter script. 5 | # It also clean rootfs to make image "forkable" 6 | 7 | set -e 8 | 9 | # unprevent init scripts from running during install/update 10 | lsb_dist="$(lsb_release -si 2>/dev/null || (test -f /etc/lsb-release && . /etc/lsb-release; echo ${DISTRIB_ID:-no_lsb}))" 11 | lsb_release="$(lsb_release -sr 2>/dev/null || (test -f /etc/lsb-release && . /etc/lsb-release; echo ${DISTRIB_RELEASE:-no_lsb}))" 12 | 13 | case "$lsb_dist" in 14 | Ubuntu) 15 | dpkg-divert --remove /sbin/initctl 16 | rm -f /usr/sbin/policy-rc.d /sbin/initctl /sbin/initctl.distrib 17 | mv /sbin/initctl.orig /sbin/initctl 18 | chmod 755 /sbin/initctl 19 | ;; 20 | Debian) 21 | dpkg-divert --remove /sbin/initctl 22 | rm -f /usr/sbin/policy-rc.d /sbin/initctl /sbin/initctl.distrib 23 | ;; 24 | *) 25 | echo "Warning: unsupported distribution $lsb_dist ($lsb_release)" >&2 26 | ;; 27 | esac 28 | 29 | 30 | # remove potentially existing docker aptitude tuning 31 | rm -f /etc/apt/apt.conf.d/docker-* 32 | #rm -f /.dockerenv /.dockerinit 33 | 34 | # remove ssh host keys so they are regenerated on first boot 35 | rm -f /etc/ssh/*_key* 36 | 37 | # clean history 38 | rm -f /root/.history /root/.bash_history 39 | 40 | # clean aptitude 41 | rm -f /var/cache/apt/*.bin /var/cache/apt/archives/partial/*.deb \ 42 | /var/cache/apt/archives/*.deb 43 | 44 | # clean debootstrap 45 | rm -f /var/log/bootstrap.log 46 | 47 | # clean systemd 48 | rm -f /var/log/journal/* 49 | 50 | # Update locate cache 51 | updatedb 2>/dev/null || true 52 | -------------------------------------------------------------------------------- /bases/overlay-feature-motd/etc/motd.head: -------------------------------------------------------------------------------- 1 | _ 2 | ___ ___ __ _| | _____ ____ _ _ _ 3 | / __|/ __/ _` | |/ _ \ \ /\ / / _` | | | | 4 | \__ \ (_| (_| | | __/\ V V / (_| | |_| | 5 | |___/\___\__,_|_|\___| \_/\_/ \__,_|\__, | 6 | |___/ 7 | -------------------------------------------------------------------------------- /bases/overlay-feature-motd/etc/update-motd.d/50-scw: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export PATH="${PATH:+$PATH:}/bin:/usr/bin:/usr/local/bin" 4 | 5 | [ -r /etc/lsb-release ] && . /etc/lsb-release 6 | [ -r /etc/scw-release ] && . /etc/scw-release 7 | if [ -z "$DISTRIB_DESCRIPTION" ] && [ -x /usr/bin/lsb_release ]; then 8 | # Fall back to using the very slow lsb_release utility 9 | DISTRIB_DESCRIPTION=$(lsb_release -s -d) 10 | fi 11 | 12 | date=`date` 13 | load=`cat /proc/loadavg | awk '{print $1}'` 14 | root_usage=`df -h / | awk '/\// {print $(NF-1)}'` 15 | memory_usage=`free -m | awk '/Mem:/ { total=$2 } /buffers\/cache/ { used=$3 } END { printf("%3.1f%%", used/total*100)}'` 16 | swap_usage=`free -m | awk '/Swap/ { printf("%3.1f%%", "exit !$2;$3/$2*100") }'` 17 | users=`users | wc -w` 18 | time=`uptime | grep -ohe 'up .*' | sed 's/,/\ hours/g' | awk '{ printf $2" "$3 }'` 19 | processes=`ps aux | wc -l` 20 | ip=$(scw-metadata --cached PRIVATE_IP) 21 | public_ip=$(scw-metadata --cached PUBLIC_IP_ADDRESS) 22 | 23 | metadata() { 24 | scw-metadata --cached "$1" 25 | } 26 | 27 | volume_metadata() { 28 | device=$1 29 | key=$2 30 | scw-metadata --cached "VOLUMES_${device}_${key}" 31 | } 32 | 33 | 34 | KERNEL_VERSION=$(uname -r) 35 | if [[ $KERNEL_VERSION =~ ^3\.2\.[35][24].* ]]; then 36 | KERNEL_TITLE="- Marvell" 37 | fi 38 | 39 | [ -f /etc/motd.head ] && cat /etc/motd.head || true 40 | printf "\n" 41 | printf "Welcome on %s (%s %s %s %s)\n" "${IMAGE_DESCRIPTION}" "$(uname -o)" "${KERNEL_VERSION}" "$(uname -m)" "$KERNEL_TITLE" 42 | printf "\n" 43 | printf "System information as of: %s\n" "$date" 44 | printf "\n" 45 | printf "System load:\t%s\t\tInt IP Address:\t%s %s\n" $load $ip 46 | printf "Memory usage:\t%s\t\tPub IP Address:\t%s\n" $memory_usage $public_ip 47 | printf "Usage on /:\t%s\t\tSwap usage:\t%s\n" $root_usage $swap_usage 48 | printf "Local Users:\t%s\t\tProcesses:\t%s\n" $users $processes 49 | printf "Image build:\t%s\tSystem uptime:\t%s\n" "${IMAGE_RELEASE}" "$time" 50 | for i in {0..16}; do 51 | metadata VOLUMES_${i} | grep " " >/dev/null || continue 52 | 53 | SIZE=$(( $(volume_metadata $i SIZE) / 1000 / 1000 / 1000 ))G 54 | 55 | volume_export_uri="$(volume_metadata $i EXPORT_URI)" 56 | if [ "$(echo "$volume_export_uri" | cut -d: -f1)" = "nbd" ]; then 57 | device_name="nbd$i" 58 | else 59 | device_name="$(echo "$volume_export_uri" | sed s@device://dev/@@)" 60 | fi 61 | printf "Disk %s:\t%s\n" "$device_name" "$(volume_metadata $i VOLUME_TYPE) ${SIZE}" 62 | done 63 | printf "\n" 64 | printf "Documentation:\t%s\n" "$IMAGE_DOC_URL" 65 | printf "Community:\t%s\n" "$IMAGE_HELP_URL" 66 | printf "Image source:\t%s\n" "$IMAGE_SOURCE_URL" 67 | printf "\n" 68 | [ -f /etc/motd.tail ] && cat /etc/motd.tail || true 69 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/conf.d/killprocs: -------------------------------------------------------------------------------- 1 | # If you wish to pass any options to killall5 during shutdown, 2 | # you should do so here. 3 | 4 | # Kill all processes except the one matching @xnbd. 5 | killall5_opts="-o $(pgrep -f '@xnbd-client.*/dev/nbd0')" 6 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/conf.d/mount-ro: -------------------------------------------------------------------------------- 1 | RC_NO_UMOUNTS="/run" 2 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/bootmisc: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2007-2009 Roy Marples 3 | # Released under the 2-clause BSD license. 4 | 5 | depend() 6 | { 7 | need localmount 8 | before logger 9 | after clock root sysctl 10 | keyword -prefix -timeout 11 | } 12 | 13 | : ${wipe_tmp:=${WIPE_TMP:-yes}} 14 | : ${log_dmesg:=${LOG_DMESG:-yes}} 15 | 16 | cleanup_tmp_dir() 17 | { 18 | local dir="$1" 19 | 20 | if ! [ -d "$dir" ]; then 21 | mkdir -p "$dir" || return $? 22 | fi 23 | checkpath -W "$dir" || return 1 24 | chmod a+rwt "$dir" 2> /dev/null 25 | cd "$dir" || return 1 26 | if yesno $wipe_tmp; then 27 | ebegin "Wiping $dir directory" 28 | 29 | # Faster than raw find 30 | if ! rm -rf -- [!ajlq\.]* 2>/dev/null ; then 31 | # Blah, too many files 32 | find . -maxdepth 1 -name '[!ajlq\.]*' -exec rm -rf -- {} + 33 | fi 34 | 35 | # pam_mktemp creates a .private directory within which 36 | # each user gets a private directory with immutable 37 | # bit set; remove the immutable bit before trying to 38 | # remove it. 39 | [ -d /tmp/.private ] && chattr -R -a /tmp/.private 2> /dev/null 40 | 41 | # Prune the paths that are left 42 | find . -maxdepth 1 \ 43 | ! -name . \ 44 | ! -name lost+found \ 45 | ! -name quota.user \ 46 | ! -name aquota.user \ 47 | ! -name quota.group \ 48 | ! -name aquota.group \ 49 | ! -name journal \ 50 | -exec rm -rf -- {} + 51 | eend 0 52 | else 53 | ebegin "Cleaning $dir directory" 54 | rm -rf -- .X*-lock esrv* kio* \ 55 | jpsock.* .fam* .esd* \ 56 | orbit-* ssh-* ksocket-* \ 57 | .*-unix 58 | eend 0 59 | fi 60 | } 61 | 62 | cleanup_var_run_dir() 63 | { 64 | ebegin "Cleaning /var/run" 65 | for x in $(find /var/run ! -type d ! -name utmp \ 66 | ! -name random-seed ! -name dev.db \ 67 | ! -name ld-elf.so.hints ! -name ld.so.hints); 68 | do 69 | # Clean stale sockets 70 | if [ -S "$x" ]; then 71 | if command -v fuser >/dev/null 2>&1; then 72 | fuser "$x" >/dev/null 2>&1 || rm -- "$x" 73 | else 74 | rm -- "$x" 75 | fi 76 | fi 77 | [ ! -f "$x" ] && continue 78 | # Do not remove pidfiles of already running daemons 79 | case "$x" in 80 | *.pid) 81 | start-stop-daemon --test --quiet \ 82 | --stop --pidfile "$x" && continue 83 | ;; 84 | esac 85 | rm -f -- "$x" 86 | done 87 | eend 0 88 | } 89 | 90 | mkutmp() 91 | { 92 | : >"$1" 93 | # Not all systems have the utmp group 94 | chgrp utmp "$1" 2>/dev/null 95 | chmod 0664 "$1" 96 | } 97 | 98 | migrate_to_run() 99 | { 100 | src="$1" 101 | dst="$2" 102 | if [ -L $src -a "$(readlink -f $src)" != $dst ]; then 103 | ewarn "$src does not point to $dst." 104 | ewarn "Setting $src to point to $dst." 105 | rm $src 106 | elif [ ! -L $src -a -d $src ]; then 107 | ebegin "Migrating $src to $dst" 108 | cp -a $src/* $dst/ 109 | rm -rf $src 110 | eend $? 111 | fi 112 | # If $src doesn't exist at all, just run this 113 | if [ ! -e $src ]; then 114 | ln -s $dst $src 115 | fi 116 | } 117 | 118 | clean_run() 119 | { 120 | [ "$RC_SYS" = VSERVER -o "$RC_SYS" = LXC ] && return 0 121 | local dir 122 | # If / is still read-only due to a problem, this will fail! 123 | if ! checkpath -W /; then 124 | eerror "/ is not writable; unable to clean up underlying /run" 125 | return 1 126 | fi 127 | if ! checkpath -W /tmp; then 128 | eerror "/tmp is not writable; unable to clean up underlying /run" 129 | return 1 130 | fi 131 | # Now we know that we can modify /tmp and / 132 | # if mktemp -d fails, it returns an EMPTY string 133 | # STDERR: mktemp: failed to create directory via template ‘/tmp/tmp.XXXXXXXXXX’: Read-only file system 134 | # STDOUT: '' 135 | rc=0 136 | dir=$(mktemp -d) 137 | if [ -n "$dir" -a -d $dir -a -w $dir ]; then 138 | mount --bind / $dir && rm -rf $dir/run/* || rc=1 139 | umount $dir 140 | rm -rf $dir 141 | else 142 | rc=1 143 | fi 144 | if [ $rc -ne 0 ]; then 145 | eerror "Could not clean up underlying /run on /" 146 | return 1 147 | fi 148 | } 149 | 150 | start() 151 | { 152 | # Remove any added console dirs 153 | if checkpath -W "$RC_LIBEXECDIR"; then 154 | rm -rf "$RC_LIBEXECDIR"/console/* 155 | fi 156 | 157 | local logw=false runw=false extra= 158 | # Ensure that our basic dirs exist 159 | if [ "$RC_UNAME" = Linux ]; then 160 | # Satisfy Linux FHS 161 | extra=/var/lib/misc 162 | if [ ! -d /run ]; then 163 | extra="/var/run $extra" 164 | fi 165 | else 166 | extra=/var/run 167 | fi 168 | for x in /var/log /tmp $extra; do 169 | if ! [ -d $x ]; then 170 | if ! mkdir -p $x; then 171 | eend 1 "failed to create needed directory $x" 172 | return 1 173 | fi 174 | fi 175 | done 176 | 177 | if [ "$RC_UNAME" = Linux -a -d /run ]; then 178 | migrate_to_run /var/lock /run/lock 179 | migrate_to_run /var/run /run 180 | clean_run 181 | fi 182 | 183 | if checkpath -W /var/run; then 184 | ebegin "Creating user login records" 185 | local xtra= 186 | [ "$RC_UNAME" = NetBSD ] && xtra=x 187 | for x in "" $xtra; do 188 | mkutmp /var/run/utmp$x 189 | done 190 | [ -e /var/log/wtmp ] || mkutmp /var/log/wtmp 191 | eend 0 192 | 193 | mountinfo -q -f tmpfs /var/run || cleanup_var_run_dir 194 | fi 195 | 196 | # Clean up /tmp directories 197 | local tmp= 198 | for tmp in ${clean_tmp_dirs:-${wipe_tmp_dirs-/tmp}}; do 199 | mountinfo -q -f tmpfs "$tmp" || cleanup_tmp_dir "$tmp" 200 | done 201 | 202 | if checkpath -W /tmp; then 203 | # Make sure our X11 stuff have the correct permissions 204 | # Omit the chown as bootmisc is run before network is up 205 | # and users may be using lame LDAP auth #139411 206 | rm -rf /tmp/.ICE-unix /tmp/.X11-unix 207 | mkdir -p /tmp/.ICE-unix /tmp/.X11-unix 208 | chmod 1777 /tmp/.ICE-unix /tmp/.X11-unix 209 | if [ -x /sbin/restorecon ]; then 210 | restorecon /tmp/.ICE-unix /tmp/.X11-unix 211 | fi 212 | fi 213 | 214 | if yesno $log_dmesg; then 215 | if $logw || checkpath -W /var/log; then 216 | # Create an 'after-boot' dmesg log 217 | if [ "$RC_SYS" != VSERVER -a "$RC_SYS" != OPENVZ -a "$RC_SYS" != LXC ]; then 218 | dmesg > /var/log/dmesg 219 | chmod 640 /var/log/dmesg 220 | fi 221 | fi 222 | fi 223 | 224 | return 0 225 | } 226 | 227 | stop() 228 | { 229 | # Write a halt record if we're shutting down 230 | if [ "$RC_RUNLEVEL" = shutdown ]; then 231 | [ "$RC_UNAME" = Linux ] && halt -w 232 | if [ "$RC_SYS" = OPENVZ ]; then 233 | yesno $RC_REBOOT && printf "" >/reboot 234 | fi 235 | fi 236 | 237 | return 0 238 | } 239 | 240 | # vim: ft=sh 241 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-gen-machine-id: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2018 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Generate VM UUID" 6 | 7 | depend() { 8 | need root 9 | after net 10 | } 11 | 12 | start() { 13 | if ! [ -f /etc/machine-id ]; then 14 | ebegin "Generating machine UUID" 15 | uuidgen >/etc/machine-id 16 | eend $? 17 | fi 18 | } 19 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-gen-root-passwd: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2018 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Generate root password" 6 | 7 | depend() { 8 | need root 9 | before net 10 | } 11 | 12 | start() { 13 | # only run the service if there is no root password defined in shadow 14 | if [ $(grep root /etc/shadow | awk -F':' '{print $2}' | wc -c) -eq 1 ]; then 15 | ebegin "Generating root password" 16 | /usr/local/sbin/scw-generate-root-passwd 17 | res=$? 18 | eend $res 19 | # if we successfully set the root password, disable this service 20 | if [ $res -eq 0 ]; then 21 | rc-update del scw-gen-root-passwd default 22 | fi 23 | fi 24 | } 25 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-generate-net-config: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2018 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Generate network configuration" 6 | 7 | depend() { 8 | need root 9 | after bootmisc hwdrivers modules 10 | before net 11 | } 12 | 13 | start() { 14 | ebegin "Generating network configuration" 15 | /usr/local/sbin/scw-generate-net-config 16 | eend $? 17 | } 18 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-initramfs-shutdown: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2015 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Run the initramfs shutdown script." 6 | 7 | 8 | depend() { 9 | #after * 10 | after killprocs savecache mount-ro 11 | } 12 | 13 | start() { 14 | DO_PIVOT=1 /run/initramfs/shutdown reboot 15 | return 0 16 | } 17 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-net-ipv6: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2018 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Configure IPv6 networking" 6 | 7 | depend() { 8 | need root 9 | after net 10 | } 11 | 12 | start() { 13 | ebegin "Configuring IPv6 networking" 14 | /usr/local/sbin/scw-net-ipv6 15 | eend $? 16 | } 17 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-set-hostname: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2015-2018 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Set SCW hostname" 6 | 7 | depend() { 8 | need root 9 | after net 10 | } 11 | 12 | start() { 13 | ebegin "Setting SCW hostname" 14 | /usr/local/sbin/scw-set-hostname 15 | echo "hostname=\"$(cat /etc/hostname)\"" > /etc/conf.d/hostname 16 | eend $? 17 | } 18 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-signal-booted: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2015 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Signals the control pane the vm booted" 6 | 7 | depend() { 8 | need net 9 | } 10 | 11 | start() { 12 | ebegin "Sending Signal booted" 13 | /usr/local/sbin/scw-signal-state booted 14 | eend $? 15 | } 16 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-ssh-keys: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2015 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="SSH keys" 6 | 7 | depend() { 8 | need root 9 | before sshd 10 | } 11 | 12 | start() { 13 | ebegin "Fetching SSH keys" 14 | /usr/local/sbin/scw-fetch-ssh-keys 15 | eend $? 16 | } 17 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-sshd-keys: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2015 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="SSHD keys" 6 | 7 | depend() { 8 | need root 9 | after sshd 10 | } 11 | 12 | start() { 13 | ebegin "Generating SSH host keys" 14 | /usr/local/sbin/scw-generate-ssh-keys 15 | eend $? 16 | } 17 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-swapfile: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2015 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Enables a swapfile" 6 | 7 | depend() { 8 | need root 9 | before kmod-static-nodes 10 | } 11 | 12 | start() { 13 | ebegin "Starting swapfile" 14 | /usr/local/sbin/scw-swapfile start 15 | eend $? 16 | } 17 | 18 | stop() { 19 | ebegin "Stopping swapfile" 20 | /usr/local/sbin/scw-swapfile stop 21 | eend $? 22 | } 23 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-sync-kernel-extra: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2015 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Downloads kernel modules/headers from SCW' mirror" 6 | 7 | depend() { 8 | need root 9 | before kmod-static-nodes 10 | } 11 | 12 | start() { 13 | ebegin "Syncing kernel modules/headers" 14 | /usr/local/sbin/scw-sync-kernel-modules 15 | eend $? 16 | } 17 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/init.d/scw-update-motd: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | # Copyright (c) 2015-2018 Scaleway 3 | # Released under the MIT license. 4 | 5 | description="Update /etc/motd" 6 | 7 | depend() { 8 | need net root 9 | use dns 10 | } 11 | 12 | start() { 13 | ebegin "Generating /etc/motd" 14 | run-parts /etc/update-motd.d/ > /etc/motd 15 | eend $? 16 | } 17 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/motd.head: -------------------------------------------------------------------------------- 1 | _ 2 | ___ ___ __ _| | _____ ____ _ _ _ 3 | / __|/ __/ _` | |/ _ \ \ /\ / / _` | | | | 4 | \__ \ (_| (_| | | __/\ V V / (_| | |_| | 5 | |___/\___\__,_|_|\___| \_/\_/ \__,_|\__, | 6 | |___/ 7 | -------------------------------------------------------------------------------- /bases/overlay-openrc/etc/update-motd.d/50-scw-minimal: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ash 2 | 3 | export PATH="${PATH:+$PATH:}/bin:/usr/bin:/usr/local/bin" 4 | 5 | [ -r /etc/lsb-release ] && . /etc/lsb-release 6 | [ -r /etc/scw-release ] && . /etc/scw-release 7 | if [ -z "$DISTRIB_DESCRIPTION" ] && [ -x /usr/bin/lsb_release ]; then 8 | # Fall back to using the very slow lsb_release utility 9 | DISTRIB_DESCRIPTION=$(lsb_release -s -d) 10 | fi 11 | 12 | date=`date` 13 | ip=`ifconfig $(route | grep default | awk '{ print $8 }') | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}'` 14 | public_ip=$(scw-metadata --cached PUBLIC_IP_ADDRESS) 15 | 16 | metadata() { 17 | scw-metadata --cached "$1" 18 | } 19 | 20 | volume_metadata() { 21 | device=$1 22 | key=$2 23 | scw-metadata --cached "VOLUMES_${device}_${key}" 24 | } 25 | 26 | 27 | KERNEL_VERSION=$(uname -r) 28 | 29 | [ -f /etc/motd.head ] && cat /etc/motd.head || true 30 | printf "\n" 31 | printf "Welcome on %s (%s %s %s %s)\n" "${IMAGE_DESCRIPTION}" "$(uname -o)" "${KERNEL_VERSION}" "$(uname -m)" "$KERNEL_TITLE" 32 | printf "\n" 33 | printf "System information as of: %s (boot time)\n" "$date" 34 | printf "\n" 35 | printf "Int IP Address:\t%s\tPub IP Address:\t%s\n" $ip $public_ip 36 | printf "Image build:\t%s\n" "${IMAGE_RELEASE}" 37 | 38 | for i in {0..16}; do 39 | metadata VOLUMES_${i} | grep " " >/dev/null || continue 40 | 41 | SIZE=$(( $(volume_metadata $i SIZE) / 1000 / 1000 / 1000 ))G 42 | 43 | volume_export_uri="$(volume_metadata $i EXPORT_URI)" 44 | if [ "$(echo "$volume_export_uri" | cut -d: -f1)" = "nbd" ]; then 45 | device_name="nbd$i" 46 | else 47 | device_name="$(echo "$volume_export_uri" | sed s@device://dev/@@)" 48 | fi 49 | printf "Disk %s:\t%s\n" "$device_name" "$(volume_metadata $i VOLUME_TYPE) ${SIZE}" 50 | done 51 | printf "\n" 52 | 53 | printf "Documentation:\t%s\n" "$IMAGE_DOC_URL" 54 | printf "Community:\t%s\n" "$IMAGE_HELP_URL" 55 | printf "Image source:\t%s\n" "$IMAGE_SOURCE_URL" 56 | printf "\n" 57 | [ -f /etc/motd.tail ] && cat /etc/motd.tail || true 58 | -------------------------------------------------------------------------------- /bases/overlay-openrc/usr/local/sbin/scw-set-hostname: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ash 2 | 3 | old_hostname=$(hostname) 4 | new_hostname=$(scw-metadata --cached HOSTNAME) 5 | 6 | if [ ! -z "$new_hostname" ]; then 7 | echo $new_hostname > /etc/hostname 8 | if grep -q "$old_hostname" /etc/hosts; then 9 | sed -i "/$old_hostname/s/.*/127.0.0.1\t$new_hostname/" /etc/hosts 10 | else 11 | echo -e "127.0.0.1\t$new_hostname" >> /etc/hosts 12 | fi 13 | fi 14 | 15 | # activate the new hostname 16 | hostname -F /etc/hostname 17 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/machine-id: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scaleway/image-tools/8d224da40fca3df75215109a98e17cbc4e16c7ae/bases/overlay-systemd/etc/machine-id -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/scw-kernel-check.conf: -------------------------------------------------------------------------------- 1 | # I provide variables used to check if the running kernel is compatible with the Scaleway image. 2 | 3 | # kernel version requirements for systemd ( http://cgit.freedesktop.org/systemd/systemd/tree/README#n38 ) 4 | export EXPECT_MAJOR_MIN=3 5 | export EXPECT_MINOR_MIN=7 6 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/sysctl.d/99-scaleway.conf: -------------------------------------------------------------------------------- 1 | # Fix NBD stability issue 2 | vm.min_free_kbytes=65536 3 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system-preset/90-scw.preset: -------------------------------------------------------------------------------- 1 | enable scw-generate-net-config.service 2 | enable scw-net-ipv6.service 3 | enable scw-fetch-ssh-keys.service 4 | enable scw-generate-ssh-keys.service 5 | enable scw-sync-kernel-modules.service 6 | enable scw-signal-booted.service 7 | enable scw-set-hostname.service 8 | enable scw-generate-root-passwd.service 9 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system/scw-fetch-ssh-keys.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SCW fetch ssh keys from metadata 3 | Before=sshd.service 4 | Requires=network-online.target 5 | After=network.target network-online.target 6 | 7 | [Service] 8 | Type=oneshot 9 | ExecStart=/usr/local/sbin/scw-fetch-ssh-keys 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system/scw-generate-net-config.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Generate network configuration 3 | Before=network-pre.target 4 | Wants=network-pre.target 5 | 6 | [Service] 7 | Type=oneshot 8 | ExecStart=/usr/local/sbin/scw-generate-net-config 9 | 10 | [Install] 11 | WantedBy=network.target 12 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system/scw-generate-root-passwd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SCW generate root password if empty 3 | ConditionPathExists=!/root/.pw 4 | 5 | [Service] 6 | Type=oneshot 7 | ExecStart=/usr/local/sbin/scw-generate-root-passwd 8 | 9 | [Install] 10 | WantedBy=basic.target 11 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system/scw-generate-ssh-keys.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Generate ssh host keys 3 | ConditionPathExists=|!/etc/ssh/ssh_host_dsa_key 4 | ConditionPathExists=|!/etc/ssh/ssh_host_dsa_key.pub 5 | ConditionPathExists=|!/etc/ssh/ssh_host_ecdsa_key 6 | ConditionPathExists=|!/etc/ssh/ssh_host_ecdsa_key.pub 7 | ConditionPathExists=|!/etc/ssh/ssh_host_ed25519_key 8 | ConditionPathExists=|!/etc/ssh/ssh_host_ed25519_key.pub 9 | ConditionPathExists=|!/etc/ssh/ssh_host_rsa_key 10 | ConditionPathExists=|!/etc/ssh/ssh_host_rsa_key.pub 11 | Before=ssh.service 12 | After=network-online.target scw-set-hostname.service 13 | 14 | [Service] 15 | Type=oneshot 16 | ExecStart=/usr/local/sbin/scw-generate-ssh-keys 17 | 18 | [Install] 19 | WantedBy=multi-user.target 20 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system/scw-net-ipv6.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Configure IPv6 networking 3 | After=network-online.target 4 | 5 | [Service] 6 | Type=oneshot 7 | ExecStart=/usr/local/sbin/scw-net-ipv6 8 | 9 | [Install] 10 | WantedBy=multi-user.target 11 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system/scw-set-hostname.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SCW set hostname from metadata on first boot 3 | Requires=network-online.target 4 | After=network.target network-online.target 5 | 6 | [Service] 7 | Type=oneshot 8 | ExecStart=/usr/local/sbin/scw-set-hostname 9 | 10 | [Install] 11 | WantedBy=basic.target 12 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system/scw-signal-booted.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SCW signal successful boot 3 | Requires=network-online.target 4 | After=network.target network-online.target 5 | 6 | [Service] 7 | Type=oneshot 8 | ExecStart=/usr/local/sbin/scw-signal-state booted 9 | 10 | [Install] 11 | WantedBy=basic.target 12 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system/scw-swapfile.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SCW swapfile 3 | DefaultDependencies=no 4 | Before=sysinit.target 5 | 6 | [Service] 7 | Type=oneshot 8 | ExecStart=/usr/local/sbin/scw-swapfile start 9 | ExecStop=-/usr/local/sbin/scw-swapfile stop 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /bases/overlay-systemd/etc/systemd/system/scw-sync-kernel-modules.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SCW fetch kernel modules from Scaleway mirror 3 | Requires=network-online.target 4 | After=network.target network-online.target 5 | ConditionPathExists=/run/scaleway/remote-boot 6 | 7 | [Service] 8 | Type=oneshot 9 | ExecStart=/usr/local/sbin/scw-sync-kernel-modules 10 | 11 | [Install] 12 | WantedBy=basic.target 13 | -------------------------------------------------------------------------------- /bases/overlay-systemd/usr/local/sbin/scw-set-hostname: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | old_hostname=$(hostnamectl status | grep 'hostname' | cut -d ":" -f2 | tr -d " ") 4 | new_hostname=$(scw-metadata HOSTNAME) 5 | 6 | if ! [ -s /etc/hosts ]; then 7 | cp /etc/hosts.default /etc/hosts 8 | sed -i "s/\bserver\b/$new_hostname/g" /etc/hosts 9 | fi 10 | 11 | hostnamectl set-hostname $new_hostname 12 | if grep -q "$old_hostname" /etc/hosts; then 13 | sed -i "/$old_hostname/s/\b$old_hostname\b/$new_hostname/g" /etc/hosts 14 | else 15 | echo -e "127.0.0.1\t$new_hostname" >> /etc/hosts 16 | fi 17 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init.d/reboot: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: reboot 4 | # Required-Start: 5 | # Required-Stop: 6 | # Default-Start: 7 | # Default-Stop: 6 8 | # Short-Description: Execute the reboot command. 9 | # Description: 10 | ### END INIT INFO 11 | 12 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 13 | 14 | . /lib/lsb/init-functions 15 | 16 | do_stop () { 17 | DO_PIVOT=1 /run/initramfs/shutdown reboot 18 | } 19 | 20 | case "$1" in 21 | start) 22 | # No-op 23 | ;; 24 | restart|reload|force-reload) 25 | echo "Error: argument '$1' not supported" >&2 26 | exit 3 27 | ;; 28 | stop) 29 | do_stop 30 | ;; 31 | *) 32 | echo "Usage: $0 start|stop" >&2 33 | exit 3 34 | ;; 35 | esac 36 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init.d/scw-force-dhclient: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: scw-force-dhclient 5 | # Required-Start: $remote_fs $local_fs 6 | # Required-Stop: 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 9 | # Short-Description: Ensure dhclient is running 10 | ### END INIT INFO 11 | 12 | . /lib/lsb/init-functions 13 | 14 | set -e 15 | 16 | forcedhclient_start() { 17 | log_action_begin_msg "Ensuring dhclient is running on eth0" 18 | pgrep dhclient >/dev/null || dhclient eth0 19 | log_action_end_msg 0 20 | } 21 | 22 | export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" 23 | 24 | case "$1" in 25 | start|reload|force-reload|restart) 26 | forcedhclient_start 27 | ;; 28 | *) 29 | log_action_msg "Usage: /etc/init.d/scw-force-dhclient {start|restart|reload|force-reload}" || true 30 | exit 1 31 | esac 32 | 33 | exit 0 34 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init.d/scw-signal-booted: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: scw-signal-booted 5 | # Required-Start: $network 6 | # Required-Stop: 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 9 | # Short-Description: Send signal booted to control plane 10 | ### END INIT INFO 11 | 12 | . /lib/lsb/init-functions 13 | 14 | export PATH="${PATH:+$PATH:}/bin:/usr/bin:/usr/local/bin:/usr/sbin:/usr/local/sbin:/sbin" 15 | 16 | signal() { 17 | log_action_begin_msg "Sending BOOTED Signal" 18 | 19 | /usr/local/sbin/scw-signal-state booted 20 | 21 | log_action_end_msg 0 22 | } 23 | 24 | signal 25 | 26 | exit 0 27 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init.d/scw-ssh-keys: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: scw-ssh-keys 5 | # Required-Start: $remote_fs $sshd 6 | # Required-Stop: $remote_fs $sshd 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 9 | # Short-Description: SSH Keys 10 | ### END INIT INFO 11 | 12 | . /lib/lsb/init-functions 13 | 14 | set -e 15 | 16 | export PATH="${PATH:+$PATH:}/bin:/usr/bin:/usr/local/bin:/usr/sbin:/usr/local/sbin:/sbin" 17 | 18 | sshkeys_start() { 19 | ( 20 | log_action_begin_msg "Fetching SSH keys from the web console" 21 | # Fetching /root/.ssh/authorized_keys from metadata 22 | /usr/local/sbin/scw-fetch-ssh-keys & 23 | 24 | # Generate ssh host keys 25 | if [ ! -f /etc/ssh/ssh_host_rsa_key ] 26 | then 27 | ssh-keygen -t rsa -b 2048 -N '' -f /etc/ssh/ssh_host_rsa_key & 28 | ssh-keygen -t dsa -N '' -f /etc/ssh/ssh_host_dsa_key & 29 | ssh-keygen -t ecdsa -N '' -f /etc/ssh/ssh_host_ecdsa_key & 30 | ssh-keygen -t ed25519 -N '' -f /etc/ssh/ssh_host_ed25519_key || true & 31 | fi 32 | 33 | # Wait for all jobs to finish 34 | wait `jobs -p` || true 35 | log_action_end_msg 0 36 | ) 37 | } 38 | 39 | 40 | 41 | case "$1" in 42 | start|reload|force-reload|restart) 43 | sshkeys_start 44 | ;; 45 | *) 46 | log_action_msg "Usage: /etc/init.d/scw-ssh-keys {start|restart}" || true 47 | exit 1 48 | esac 49 | 50 | exit 0 51 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init.d/scw-sync-kernel-modules: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: scw-sync-kernel-modules 5 | # Required-Start: $remote_fs scw-force-dhclient 6 | # Required-Stop: $remote_fs 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 9 | # Short-Description: Sync kernel modules 10 | ### END INIT INFO 11 | 12 | . /lib/lsb/init-functions 13 | 14 | set -e 15 | 16 | synckernelmodules_start() { 17 | log_action_begin_msg "Starting to mount Scaleway extra volumes" 18 | /usr/local/sbin/scw-sync-kernel-modules 19 | log_action_end_msg 0 20 | } 21 | 22 | export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" 23 | 24 | case "$1" in 25 | start) 26 | synckernelmodules_start 27 | ;; 28 | reload|force-reload) 29 | synckernelmodules_start 30 | ;; 31 | restart) 32 | synckernelmodules_start 33 | ;; 34 | *) 35 | log_action_msg "Usage: /etc/init.d/scw-sync-kernel-modules {start|restart}" || true 36 | exit 1 37 | esac 38 | 39 | exit 0 40 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init/tty1.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init/tty2.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init/tty3.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init/tty4.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init/tty5.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-sysvinit/etc/init/tty6.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init.d/halt: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: halt 4 | # Required-Start: 5 | # Required-Stop: 6 | # Default-Start: 7 | # Default-Stop: 0 8 | # Short-Description: Execute the halt command. 9 | # Description: 10 | ### END INIT INFO 11 | 12 | NETDOWN=yes 13 | 14 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 15 | [ -f /etc/default/halt ] && . /etc/default/halt 16 | 17 | . /lib/lsb/init-functions 18 | 19 | do_stop () { 20 | if [ "$INIT_HALT" = "" ] 21 | then 22 | case "$HALT" in 23 | [Pp]*) 24 | INIT_HALT=POWEROFF 25 | ;; 26 | [Hh]*) 27 | INIT_HALT=HALT 28 | ;; 29 | *) 30 | INIT_HALT=POWEROFF 31 | ;; 32 | esac 33 | fi 34 | 35 | if [ "$INIT_HALT" = "HALT" ] 36 | then 37 | log_action_msg "Will now halt" 38 | DO_PIVOT=1 /run/initramfs/shutdown halt 39 | fi 40 | 41 | log_action_msg "Will now poweroff" 42 | DO_PIVOT=1 /run/initramfs/shutdown poweroff 43 | } 44 | 45 | case "$1" in 46 | start) 47 | # No-op 48 | ;; 49 | restart|reload|force-reload) 50 | echo "Error: argument '$1' not supported" >&2 51 | exit 3 52 | ;; 53 | stop) 54 | do_stop 55 | ;; 56 | *) 57 | echo "Usage: $0 start|stop" >&2 58 | exit 3 59 | ;; 60 | esac 61 | 62 | : 63 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init.d/reboot: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: reboot 4 | # Required-Start: 5 | # Required-Stop: 6 | # Default-Start: 7 | # Default-Stop: 6 8 | # Short-Description: Execute the reboot command. 9 | # Description: 10 | ### END INIT INFO 11 | 12 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 13 | 14 | . /lib/lsb/init-functions 15 | 16 | do_stop () { 17 | # Message should end with a newline since kFreeBSD may 18 | # print more stuff (see #323749) 19 | log_action_msg "Will now restart" 20 | DO_PIVOT=1 /run/initramfs/shutdown reboot 21 | } 22 | 23 | case "$1" in 24 | start) 25 | # No-op 26 | ;; 27 | restart|reload|force-reload) 28 | echo "Error: argument '$1' not supported" >&2 29 | exit 3 30 | ;; 31 | stop) 32 | do_stop 33 | ;; 34 | *) 35 | echo "Usage: $0 start|stop" >&2 36 | exit 3 37 | ;; 38 | esac 39 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/scw-preserve-root-nbd-client.conf: -------------------------------------------------------------------------------- 1 | # nbd-root-preserve-client.conf 2 | description "preserve the nbd-client process on shutdown" 3 | author "Scaleway " 4 | 5 | start on local-filesystems 6 | kill timeout 300 7 | 8 | task 9 | 10 | script 11 | ps x | grep @xnbd-client | grep nbd0 | grep -v grep | awk '{print $1}' > /run/sendsigs.omit.d/nbd-client 12 | end script 13 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/scw-serial.conf: -------------------------------------------------------------------------------- 1 | # tty support on Scaleway 2 | # 3 | # This service maintains a getty on ttyS0,ttyS1 from the point the system is 4 | # started until it is shut down again. 5 | 6 | start on stopped rc RUNLEVEL=[2345] and ( 7 | not-container or 8 | container CONTAINER=lxc or 9 | container CONTAINER=lxc-libvirt) 10 | 11 | stop on runlevel [!2345] 12 | 13 | respawn 14 | 15 | script 16 | # getting variables from /proc/cmdline 17 | consoles=$(cat /proc/cmdline | tr " " "\n" | grep ^console= | cut -d= -f2) 18 | echo "$consoles" | while read console; do 19 | tty=$(echo $console | cut -d, -f1) 20 | attrs=$(echo $console | cut -d, -f2) 21 | baud=$(echo $attrs | cut -dn -f1) 22 | 23 | # start getty for the first console= entry 24 | exec /sbin/getty -L ${tty:-ttyS0} ${baud:-9600} vt220 25 | done 26 | end script 27 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/scw-signal-booted.conf: -------------------------------------------------------------------------------- 1 | # testservice - test service job file 2 | 3 | description "SCW Signal Booted" 4 | 5 | # Stanzas control when and how a process is started and stopped 6 | 7 | # When to start the service 8 | # We obviously need network 9 | start on runlevel [345] 10 | 11 | # Run script 12 | exec /usr/local/sbin/scw-signal-state booted 13 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/scw-ssh-keys.conf: -------------------------------------------------------------------------------- 1 | # ssh-keys 2 | description "generate and fetch needed ssh keys" 3 | author "Scaleway " 4 | 5 | start on starting ssh 6 | 7 | task 8 | 9 | script 10 | 11 | ( 12 | /usr/local/sbin/scw-fetch-ssh-keys & 13 | /usr/local/sbin/scw-generate-ssh-keys & 14 | wait `jobs -p` || true 15 | ) 16 | 17 | end script 18 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/scw-sync-kernel-modules.conf: -------------------------------------------------------------------------------- 1 | # sync kernel modules 2 | description "synchronizes kernel modules" 3 | author "Scaleway " 4 | 5 | start on (startup or runlevel [2345]) 6 | kill timeout 300 7 | 8 | task 9 | 10 | script 11 | /usr/local/sbin/scw-sync-kernel-modules 12 | end script 13 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/tty1.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/tty2.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/tty3.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/tty4.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/tty5.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bases/overlay-upstart/etc/init/tty6.override: -------------------------------------------------------------------------------- 1 | manual 2 | -------------------------------------------------------------------------------- /bootscript_ids: -------------------------------------------------------------------------------- 1 | ams1|x86_64|914eabd4-90c2-432f-b54c-87dc373561b2 2 | ams1|arm|49ac4938-3385-4e06-b20b-dd52fbfaf2f5 3 | ams1|arm64|0100cae3-eef2-48ca-bd73-c2f395d78a11 4 | par1|x86_64|c9ae8463-370d-4c83-8f71-b8282e7f6f81 5 | par1|arm|eda986e2-1de5-419e-8c0b-7abe4fb7dca3 6 | par1|arm64|5bd4bbce-7260-4dd0-b2f6-b9e946e7cd3d 7 | -------------------------------------------------------------------------------- /dockerlint.rules: -------------------------------------------------------------------------------- 1 | profile: 2 | name: Default 3 | description: Default Profile. Checks basic syntax. 4 | includes: null 5 | general: 6 | ref_url_base: "https://docs.docker.com/engine/reference/builder/" 7 | valid_instructions: 8 | - FROM 9 | - MAINTAINER 10 | - RUN 11 | - CMD 12 | - LABEL 13 | - EXPOSE 14 | - ENV 15 | - ADD 16 | - COPY 17 | - ENTRYPOINT 18 | - VOLUME 19 | - USER 20 | - WORKDIR 21 | - ONBUILD 22 | - ARG 23 | - STOPSIGNAL 24 | - HEALTHCHECK 25 | - SHELL 26 | ignore_regex: "/^#/" 27 | multiline_regex: "/\\\\$/" 28 | line_rules: 29 | ARG: 30 | paramSyntaxRegex: /.+/ 31 | rules: [] 32 | FROM: 33 | paramSyntaxRegex: "/^[\\w./\\-:]+(:[\\w.]+)?(-[\\w.]+)?$/" 34 | rules: 35 | - label: is_latest_tag 36 | regex: /latest/ 37 | level: error 38 | message: "base image uses 'latest' tag" 39 | description: "using the 'latest' tag may cause unpredictable builds. It is recommended that a specific tag is used in the FROM line or *-released which is the latest supported release." 40 | reference_url: 41 | - "https://docs.docker.com/engine/reference/builder/" 42 | - "#from" 43 | - label: no_tag 44 | regex: "/^[:]/" 45 | level: error 46 | message: No tag is used 47 | description: lorem ipsum tar 48 | reference_url: 49 | - "https://docs.docker.com/engine/reference/builder/" 50 | - "#from" 51 | HEALTHCHECK: 52 | paramSyntaxRegex: /.+/ 53 | rules: [] 54 | MAINTAINER: 55 | paramSyntaxRegex: /.+/ 56 | rules: [] 57 | RUN: 58 | paramSyntaxRegex: /.+/ 59 | rules: 60 | - label: no_yum_clean_all 61 | regex: "/yum(?!.+clean all|.+\\.repo|-config|\\.conf)/" 62 | level: warn 63 | message: yum clean all is not used 64 | description: the yum cache will remain in this layer making the layer unnecessarily large 65 | reference_url: 66 | - "http://docs.projectatomic.io/container-best-practices/#" 67 | - _clear_packaging_caches_and_temporary_package_downloads 68 | - label: yum_update_all 69 | regex: "/yum(.+update all|.+upgrade|.+update)/" 70 | level: info 71 | message: updating the entire base image may add unnecessary size to the container 72 | description: update the entire base image may add unnecessary size to the container 73 | reference_url: 74 | - "http://docs.projectatomic.io/container-best-practices/#" 75 | - _clear_packaging_caches_and_temporary_package_downloads 76 | - label: no_dnf_clean_all 77 | regex: "/dnf(?!.+clean all|.+\\.repo)/g" 78 | level: warn 79 | message: dnf clean all is not used 80 | description: the dnf cache will remain in this layer making the layer unnecessarily large 81 | reference_url: 82 | - "http://docs.projectatomic.io/container-best-practices/#" 83 | - _clear_packaging_caches_and_temporary_package_downloads 84 | - label: no_rvm_cleanup_all 85 | regex: "/rvm install(?!.+cleanup all)/g" 86 | level: warn 87 | message: rvm cleanup is not used 88 | description: the rvm cache will remain in this layer making the layer unnecessarily large 89 | reference_url: 90 | - "http://docs.projectatomic.io/container-best-practices/#" 91 | - _clear_packaging_caches_and_temporary_package_downloads 92 | - label: no_gem_clean_all 93 | regex: "/gem install(?!.+cleanup|.+\\rvm cleanup all)/g" 94 | level: warn 95 | message: gem cleanup all is not used 96 | description: the gem cache will remain in this layer making the layer unnecessarily large 97 | reference_url: 98 | - "http://docs.projectatomic.io/container-best-practices/#" 99 | - _clear_packaging_caches_and_temporary_package_downloads 100 | - label: no_apt-get_clean 101 | regex: "/apt-get install(?!.+clean)/g" 102 | level: info 103 | message: apt-get clean is not used 104 | description: the apt-get cache will remain in this layer making the layer unnecessarily large 105 | reference_url: 106 | - "http://docs.projectatomic.io/container-best-practices/#" 107 | - _clear_packaging_caches_and_temporary_package_downloads 108 | - label: privileged_run_container 109 | regex: /privileged/ 110 | level: warn 111 | message: a privileged run container is allowed access to host devices 112 | description: Does this run need to be privileged? 113 | reference_url: 114 | - "http://docs.docker.com/engine/reference/run/#" 115 | - runtime-privilege-and-linux-capabilities 116 | - label: installing_ssh 117 | regex: /openssh-server/ 118 | level: warn 119 | message: installing SSH in a container is not recommended 120 | description: Do you really need SSH in this image? 121 | reference_url: "https://github.com/jpetazzo/nsenter" 122 | - label: no_ampersand_usage 123 | regex: / ; / 124 | level: info 125 | message: "using ; instead of &&" 126 | description: "RUN do_1 && do_2: The ampersands change the resulting evaluation into do_1 and then do_2 only if do_1 was successful." 127 | reference_url: 128 | - "http://docs.projectatomic.io/container-best-practices/#" 129 | - "#_using_semi_colons_vs_double_ampersands" 130 | SHELL: 131 | paramSyntaxRegex: /.+/ 132 | rules: [] 133 | CMD: 134 | paramSyntaxRegex: /.+/ 135 | rules: [] 136 | LABEL: 137 | paramSyntaxRegex: /.+/ 138 | rules: [] 139 | defined_namevals: 140 | Name: 141 | valueRegex: "/[\\w]+/" 142 | message: "Label 'Name' is missing or has invalid format" 143 | level: warn 144 | required: false 145 | reference_url: 146 | - "http://docs.projectatomic.io/container-best-practices/#" 147 | - _recommended_labels_for_your_project 148 | Version: 149 | valueRegex: "/[\\w.${}()\"'\\\\\\/~<>\\-?\\%:]+/" 150 | message: "Label 'Version' is missing or has invalid format" 151 | level: warn 152 | required: false 153 | reference_url: 154 | - "http://docs.projectatomic.io/container-best-practices/#" 155 | - _recommended_labels_for_your_project 156 | Release: 157 | valueRegex: "/[\\w.${}()\"'\\\\\\/~<>\\-?\\%:]+/" 158 | message: "Label 'Release' is missing or has invalid format" 159 | level: warn 160 | required: false 161 | reference_url: 162 | - "http://docs.projectatomic.io/container-best-practices/#" 163 | - _recommended_labels_for_your_project 164 | Architecture: 165 | valueRegex: "/[\\w]*[6,8][4,6]|[.]*86[.]*64/" 166 | message: "Label 'Architecture' is missing or has invalid format: x86, i386, x86_64" 167 | level: info 168 | required: false 169 | reference_url: 170 | - "http://docs.projectatomic.io/container-best-practices/#" 171 | - _recommended_labels_for_your_project 172 | Vendor: 173 | valueRegex: "/([\\w]+).+/" 174 | message: "Label 'Vendor' is missing or has invalid format" 175 | level: warn 176 | required: false 177 | reference_url: 178 | - "http://docs.projectatomic.io/container-best-practices/#" 179 | - _recommended_labels_for_your_project 180 | Url: 181 | valueRegex: "/([\\w]+).+/" 182 | message: "Label 'Url' is missing or has invalid format" 183 | level: warn 184 | required: false 185 | reference_url: 186 | - "http://docs.projectatomic.io/container-best-practices/#" 187 | - _recommended_labels_for_your_project 188 | Help: 189 | valueRegex: "/([\\w]+).+/" 190 | message: "Label 'Help' is missing or has invalid format" 191 | level: warn 192 | required: false 193 | reference_url: 194 | - "http://docs.projectatomic.io/container-best-practices/#" 195 | - _recommended_labels_for_your_project 196 | EXPOSE: 197 | paramSyntaxRegex: "/^[\\d-\\s\\w/\\\\]+$/" 198 | rules: [] 199 | ENV: 200 | paramSyntaxRegex: "/^[\\w-$/\\\\=\\\"[\\]{}@:,'`\\t. ]+$/" 201 | rules: [] 202 | ADD: 203 | paramSyntaxRegex: "/^~?([\\w-.~:/?#\\[\\]\\\\\\/*@!$&'()*+,;=.{}\"]+[\\s]*)+$/" 204 | COPY: 205 | paramSyntaxRegex: /.+/ 206 | rules: [] 207 | ENTRYPOINT: 208 | paramSyntaxRegex: /.+/ 209 | rules: [] 210 | VOLUME: 211 | paramSyntaxRegex: /.+/ 212 | rules: [] 213 | USER: 214 | paramSyntaxRegex: "/^[a-z0-9_][a-z0-9_-]{0,40}$/" 215 | rules: [] 216 | WORKDIR: 217 | paramSyntaxRegex: "/^~?[\\w\\d-\\/.{}$\\/:]+[\\s]*$/" 218 | rules: [] 219 | ONBUILD: 220 | paramSyntaxRegex: /.+/ 221 | rules: [] 222 | discouraged_instructions: [] 223 | mutually_exclusive_instructions: [] 224 | 225 | -------------------------------------------------------------------------------- /jenkins/image.groovy: -------------------------------------------------------------------------------- 1 | return { 2 | properties([ 3 | [$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', numToKeepStr: '1']], 4 | disableConcurrentBuilds(), 5 | pipelineTriggers([ 6 | cron('H H H * *'), 7 | pollSCM('H */2 * * *') 8 | ]), 9 | parameters([ 10 | booleanParam(name: 'test', defaultValue: true, description: 'Test the image'), 11 | booleanParam(name: 'needAdminApproval', defaultValue: false, description: 'Wait for admin approval after testing'), 12 | booleanParam(name: 'release', defaultValue: false, description: 'Release the image'), 13 | string(name: 'logLevel', defaultValue: '3', description: 'Log level'), 14 | string(name: 'buildOpts', defaultValue: '--pull', description: 'Image build options') 15 | ]) 16 | ]) 17 | 18 | def compute_images = [] 19 | def image_version = [:] 20 | 21 | node { 22 | stage('Pull image source') { 23 | dir('image') { 24 | deleteDir() 25 | checkout scm 26 | } 27 | } 28 | stage('Set environment') { 29 | env.IMAGE_VERSION = env.JOB_NAME.split('-').drop(2).join('-') 30 | manifest = readFile("${env.WORKSPACE}/image/manifest.json") 31 | manifest_data = new groovy.json.JsonSlurperClassic().parseText(manifest) 32 | image_version = manifest_data['images'][env.IMAGE_VERSION] 33 | try { 34 | env.MARKETPLACE_IMAGE_NAME = image_version['marketplace-name'] 35 | } 36 | catch (Exception e) { 37 | throw new hudson.AbortException("Error: does version '${env.IMAGE_VERSION}' exist in manifest?") 38 | } 39 | // All of this is a hack, it needs to be fixed properly. Notably, images need to be per-product 40 | env.IMAGE_DISK_SIZE = "10G" 41 | if (image_version.containsKey('options')) { 42 | if (image_version['options'].containsKey('disk-size')) { 43 | env.IMAGE_DISK_SIZE = image_version['options']['disk-size'] 44 | // This part especially, is a quickfix to be reverted soon for something cleaner 45 | if (env.IMAGE_DISK_SIZE == "25G") { 46 | env.TEST_SERVER_TYPES = "START1-XS" 47 | } 48 | } 49 | } 50 | env.BUILD_OPTS = params.buildOpts 51 | env.LOG_LEVEL = params.logLevel 52 | } 53 | stash 'image-source' 54 | deleteDir() 55 | } 56 | 57 | def image_builders = [:] 58 | for (String arch in image_version['architectures']) { 59 | def tmp_arch = arch 60 | image_builders[tmp_arch] = { 61 | stage("Create image for ${tmp_arch} on Scaleway") { 62 | node("${tmp_arch}&&docker&&scw-cli") { 63 | deleteDir() 64 | unstash 'image-source' 65 | withCredentials([usernamePassword(credentialsId: 'scw-test-orga-token', usernameVariable: 'SCW_ORGANIZATION', passwordVariable: 'SCW_TOKEN')]) { 66 | sh 'scw login -o "$SCW_ORGANIZATION" -t "$SCW_TOKEN" -s >/dev/null 2>&1' 67 | } 68 | echo "Creating image for $tmp_arch" 69 | withEnv(["SSH_KEY_FILE=${env.HOME}/.ssh/id_worker"]) { 70 | sh "make ARCH=${tmp_arch} IMAGE_DIR=${env.WORKSPACE}/image/${image_version['directory']} EXPORT_DIR=${env.WORKSPACE}/export/$tmp_arch BUILD_OPTS='${env.BUILD_OPTS}' scaleway_image" 71 | } 72 | def imageId = readFile("${env.WORKSPACE}/export/${tmp_arch}/image_id").trim() 73 | def docker_tags = readFile("${env.WORKSPACE}/export/${tmp_arch}/docker_tags").trim().split('\n') 74 | def docker_image = docker_tags[0].split(':')[0] 75 | compute_images.add([ 76 | arch: tmp_arch, 77 | id: imageId, 78 | ]) 79 | dir("${env.WORKSPACE}/export/${tmp_arch}") { 80 | sh "docker image rm ${docker_tags[-1]} && docker system prune -f" 81 | } 82 | deleteDir() 83 | } 84 | } 85 | } 86 | } 87 | parallel image_builders 88 | 89 | node("scw-cli") { 90 | if(params.test) { 91 | deleteDir() 92 | unstash 'image-source' 93 | stage('Test the images') { 94 | try { 95 | for (Map image : compute_images) { 96 | withEnv(["SSH_KEY_FILE=${env.HOME}/.ssh/id_worker", "IMAGE_DIR=${env.WORKSPACE}/image/${image_version['directory']}"]) { 97 | sh "make tests IMAGE_DIR=${env.IMAGE_DIR} EXPORT_DIR=${env.WORKSPACE}/export/${image['arch']} ARCH=${image['arch']} IMAGE_ID=${image['id']} TESTS_DIR=${env.IMAGE_DIR}/tests NO_CLEANUP=${params.needAdminApproval}" 98 | } 99 | } 100 | if (env.needsAdminApproval) { 101 | input "Confirm that the images are stable ?" 102 | } 103 | } 104 | finally { 105 | if (env.needsAdminApproval) { 106 | for (Map image : compute_images) { 107 | withEnv(["SSH_KEY_FILE=${env.HOME}/.ssh/id_worker"]) { 108 | sh "scripts/test_images.sh stop ${env.WORKSPACE}/export/${image['arch']}/${image['id']}.servers" 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | 117 | node("docker") { 118 | if(params.release) { 119 | deleteDir() 120 | stage('Release the image') { 121 | message = groovy.json.JsonOutput.toJson([ 122 | type: "image", 123 | data: [ 124 | marketplace_id: image_version['marketplace-id'], 125 | versions: compute_images 126 | ] 127 | ]) 128 | versionId = input( 129 | message: "${message}", 130 | parameters: [string(name: 'image_id', description: 'ID of the new image version')] 131 | ) 132 | echo "Created new marketplace version of image ${image_version['marketplace-id']}: ${versionId}" 133 | } 134 | deleteDir() 135 | } 136 | } 137 | } 138 | 139 | -------------------------------------------------------------------------------- /scripts/assets_server.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | exec >/dev/null 2>&1 4 | 5 | if [ "$1" = "start" ]; then 6 | cd $3 && python3 -m http.server $2 & 7 | else 8 | kill $(lsof -i :$2 -t | tr '\n' ' ') 9 | fi 10 | -------------------------------------------------------------------------------- /scripts/create_image_live_from_rootfs.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | SRC_DIR=$(dirname $(readlink -f $0)) 4 | source $SRC_DIR/scw.sh 5 | source $SRC_DIR/setup_credentials.sh 6 | 7 | if [ -z "$OUTPUT_ID_TO" ]; then 8 | OUTPUT_ID_TO="image_id.txt" 9 | fi 10 | 11 | rootfs_url=$1 12 | image_name=$2 13 | arch=$3 14 | image_disk_size=$4 15 | image_bootscript=$5 16 | build_method=$6 17 | 18 | wait_port_timeout=900 19 | 20 | key=$(cat ${SSH_KEY_FILE}.pub | cut -d' ' -f1,2 | tr ' ' '_') 21 | 22 | bootscript_id=$(grep -E "$REGION\|$arch\>" bootscript_ids | cut -d'|' -f3) 23 | if [ "$arch" = "arm" ]; then 24 | logwarn "Local boot is not supported on C1, defaulting to unpartitioned image creation" 25 | build_method="unpartitioned-from-rootfs" 26 | bootscript_id=$(grep -E "$REGION\|x86_64\>" bootscript_ids | cut -d'|' -f3) 27 | server_type="START1-M" 28 | minimum_total_volume_size=100 29 | server_creation_opts="" 30 | elif [ "$arch" = "x86_64" ]; then 31 | server_type="START1-M" 32 | minimum_total_volume_size=100 33 | server_creation_opts="" 34 | elif [ "$arch" = "arm64" ]; then 35 | server_type="ARM64-4GB" 36 | minimum_total_volume_size=100 37 | server_creation_opts="" 38 | fi 39 | 40 | server_creation_opts="$server_creation_opts --volume='$(( $minimum_total_volume_size - ${image_disk_size%?} ))G'" 41 | 42 | server_name="image-writer-$(date +%Y-%m-%d_%H:%M)" 43 | signal_port=$(shuf -i 10000-60000 -n 1) 44 | server_env="build_method=$build_method rootfs_url=$rootfs_url signal_build_done_port=$signal_port AUTHORIZED_KEY=$key $SERVER_ENV" 45 | 46 | server_id=$(create_server "$server_type" "$server_creation_opts" "$server_name" "$image_disk_size" "$server_env" "$bootscript_id") 47 | [ $? -eq 0 ] || exiterr 48 | 49 | curl --fail -s -X PATCH -H "X-Auth-Token: ${SCW_TOKEN}" -H "Content-type: application/json" -d '{"boot_type":"bootscript"}' "https://cp-${REGION}.scaleway.com/servers/${server_id}" >/dev/null || exiterr 50 | 51 | boot_server $server_id || exiterr 52 | 53 | wait_for_port $server_id $signal_port $wait_port_timeout || exiterr 54 | 55 | stop_server $server_id 56 | 57 | _scw wait $server_id 58 | 59 | image_from_volume $server_id $arch "$image_name" "$image_bootscript" >$OUTPUT_ID_TO || exiterr 60 | 61 | rm_server $server_id 62 | -------------------------------------------------------------------------------- /scripts/scw.sh: -------------------------------------------------------------------------------- 1 | log() { 2 | echo "$@" >&2 3 | } 4 | 5 | if [ -z "$LOG_LEVEL" ]; then 6 | LOG_LEVEL=3 7 | fi 8 | 9 | logerr() { 10 | [ $LOG_LEVEL -gt 0 ] && log "[ERROR]" "$@" 11 | true 12 | } 13 | 14 | logwarn() { 15 | [ $LOG_LEVEL -gt 1 ] && log "[WARNING]" "$@" 16 | true 17 | } 18 | 19 | loginfo() { 20 | [ $LOG_LEVEL -gt 2 ] && log "[INFO]" "$@" 21 | true 22 | } 23 | 24 | logdebug() { 25 | [ $LOG_LEVEL -gt 3 ] && log "[DEBUG]" "$@" 26 | true 27 | } 28 | 29 | exiterr() { 30 | logerr "Exiting on previous errors." 31 | if [ -n "$1" ]; then 32 | exit $1 33 | else 34 | exit 1 35 | fi 36 | } 37 | 38 | test_dependency() { 39 | which "$1" > /dev/null 2>&1 40 | if [ $? -ne 0 ]; then 41 | logerr "$1 not found in \$PATH" 42 | exit 1 43 | fi 44 | } 45 | 46 | test_dependency curl 47 | test_dependency ssh 48 | test_dependency ping 49 | test_dependency jq 50 | test_dependency nc 51 | test_dependency scw 52 | 53 | 54 | __scw() { 55 | scw --region=$REGION "$@" 56 | } 57 | 58 | _scw() { 59 | __scw "$@" >/dev/null 2>&1 60 | } 61 | 62 | _ssh_get_options() { 63 | options="StrictHostKeyChecking=no\nUserKnownHostsFile=/dev/null\nIdentityFile=$SSH_KEY_FILE" 64 | if [ -n "$SSH_GATEWAY" ]; then 65 | options="${options}\nProxyJump=$SSH_GATEWAY" 66 | fi 67 | echo -e $options 68 | } 69 | 70 | _ssh() { 71 | cmd_options="" 72 | while read option; do 73 | cmd_options="${cmd_options}-o ${option} " 74 | done < <(_ssh_get_options) 75 | logdebug "ssh $cmd_options $@" 76 | ssh $cmd_options "$@" 77 | } 78 | 79 | get_server() { 80 | server_id=$1 81 | 82 | res=$(curl --fail -s https://cp-${REGION}.scaleway.com/servers/$server_id -H "x-auth-token: $SCW_TOKEN") 83 | if [ $? -ne 0 ]; then 84 | return 1 85 | else 86 | echo $res 87 | fi 88 | } 89 | 90 | get_server_ip() { 91 | server_id=$1 92 | if [ "$IS_SCW_HOST" = "y" ] && [ "$LOCAL_SCW_REGION" = "$REGION" ]; then 93 | get_server $server_id | jq -r '.server.private_ip' 94 | elif [ -n "$SSH_GATEWAY" ]; then 95 | get_server $server_id | jq -r '.server.private_ip' 96 | else 97 | get_server $server_id | jq -r '.server.public_ip.address // empty' 98 | fi 99 | } 100 | 101 | create_server() { 102 | server_type=$1 103 | server_creation_opts=$2 104 | server_name=$3 105 | image=$4 106 | server_env=$5 107 | bootscript=$6 108 | 109 | if [ -n "$SSH_GATEWAY" ] || ([ "$IS_SCW_HOST" = y ] && [ "$LOCAL_SCW_REGION" = "$REGION" ]); then 110 | ipaddress="--ip-address=none" 111 | fi 112 | 113 | # Try to create the server 114 | loginfo "Creating $server_type server $server_name..." 115 | maximum_create_tries=5 116 | for try in `seq 1 $maximum_create_tries`; do 117 | server_id=$(__scw create $ipaddress --commercial-type="$server_type" --bootscript="$bootscript" --name="$server_name" --env="$server_env" $server_creation_opts $image) 118 | logdebug "$server_id" 119 | if [ -z "$server_id" ]; then 120 | continue 121 | fi 122 | sleep 1 123 | server_info=$(get_server $server_id) 124 | if [ $? -eq 0 ]; then 125 | loginfo "Created server $server_name, id: $server_id" 126 | echo $server_info | jq '.' | while IFS="\n" read line; do 127 | logdebug "$line" 128 | done 129 | echo "$server_id" 130 | return 0 131 | fi 132 | backoff=$(echo "(2^($try-1))*60" | bc) 133 | sleep $backoff 134 | done 135 | logerr "Could not create server" 136 | return 1 137 | } 138 | 139 | boot_server() { 140 | server_id=$1 141 | 142 | # Try to boot the server 143 | loginfo "Booting server..." 144 | maximum_boot_tries=3 145 | boot_timeout=600 146 | failed=true 147 | for try in `seq 1 $maximum_boot_tries`; do 148 | if (get_server $server_id | jq -r '.server.state' | grep -qxE 'stopped'); then 149 | _scw start -w -T $boot_timeout $server_id 150 | fi 151 | sleep 1 152 | if (get_server $server_id | jq -r '.server.state' | grep -qxE 'starting'); then 153 | time_begin=$(date +%s) 154 | while (get_server $server_id | jq -r '.server.state' | grep -qxE 'starting') ; do 155 | time_now=$(date +%s) 156 | time_diff=$(echo "$time_now-$time_begin" | bc) 157 | if [ $time_diff -gt $boot_timeout ]; then 158 | break 159 | fi 160 | sleep 5 161 | done 162 | fi 163 | sleep 1 164 | if (get_server $server_id | jq -r '.server.state' | grep -qxE 'running'); then 165 | failed=false 166 | break 167 | fi 168 | backoff=$(echo "($try-1)*60" | bc) 169 | sleep $backoff 170 | done 171 | if $failed; then 172 | logerr "Could not boot server" 173 | return 2 174 | fi 175 | loginfo "Server booted" 176 | } 177 | 178 | wait_for_port() { 179 | local server_id=$1 180 | local signal_port=$2 181 | local timeout=$3 182 | if [ -z "$timeout" ]; then 183 | timeout=300 184 | fi 185 | 186 | local time_begin=$(date +%s) 187 | local time_now 188 | local time_diff 189 | local failed 190 | 191 | while true; do 192 | local server_ip=$(get_server_ip $server_id) 193 | if [ -n "$SSH_GATEWAY" ]; then 194 | server_ip=$(get_server $server_id | jq -r '.server.private_ip') 195 | cmd_prefix="ssh $SSH_GATEWAY" 196 | fi 197 | time_now=$(date +%s) 198 | time_diff=$(echo "$time_now-$time_begin" | bc) 199 | if [ -n "$server_ip" ]; then 200 | failed=false 201 | break 202 | elif [ $time_diff -gt 120 ]; then 203 | failed=true 204 | break 205 | else 206 | sleep 5 207 | fi 208 | done 209 | if $failed; then 210 | logerr "Could not get a reachable ip for the server" 211 | return 1 212 | fi 213 | 214 | loginfo "Waiting for host to be up and port $signal_port to be open on $server_ip..." 215 | time_begin=$(date +%s) 216 | local host_up=false 217 | local port_open=false 218 | while true; do 219 | if ! $host_up; then 220 | $cmd_prefix ping $server_ip -c 3 >/dev/null 2>&1 && host_up=true 221 | if $host_up; then 222 | logdebug "Host is now up" 223 | continue 224 | fi 225 | else 226 | $cmd_prefix nc -zv $server_ip $signal_port >/dev/null 2>&1 && port_open=true 227 | if $port_open; then 228 | logdebug "Port $signal_port is now open" 229 | break 230 | fi 231 | fi 232 | time_now=$(date +%s) 233 | time_diff=$(echo "$time_now-$time_begin" | bc) 234 | if [ $time_diff -gt $timeout ]; then 235 | logerr "Port $signal_port never opened on $server_ip" 236 | return 2 237 | fi 238 | sleep 1 239 | done 240 | loginfo "Host is up and signaled on port $signal_port" 241 | } 242 | 243 | stop_server() { 244 | server_id=$1 245 | 246 | # Try to stop server 247 | read server_name server_type < <(get_server $server_id | jq -r '.server | "\(.name) \(.commercial_type)"') 248 | loginfo "Stopping $server_type server $server_name..." 249 | maximum_stop_tries=3 250 | failed=true 251 | for try in `seq 1 $maximum_stop_tries`; do 252 | if (get_server $server_id | jq -r '.server.state' | grep -qxE 'running'); then 253 | _scw stop $server_id 254 | fi 255 | sleep 1 256 | if (get_server $server_id | jq -r '.server.state' | grep -qxE 'stopping|stopped'); then 257 | failed=false 258 | break 259 | fi 260 | backoff=$(echo "($try-1)*60" | bc) 261 | sleep $backoff 262 | done 263 | if $failed; then 264 | logerr "Could not stop server $server_name" 265 | return 1 266 | fi 267 | loginfo "Server $server_name stopped" 268 | } 269 | 270 | rm_server() { 271 | server_id=$1 272 | 273 | # Try to stop server 274 | read server_name server_type < <(get_server $server_id | jq -r '.server | "\(.name) \(.commercial_type)"') 275 | loginfo "Removing $server_type server $server_name..." 276 | maximum_rm_tries=3 277 | failed=true 278 | for try in `seq 1 $maximum_rm_tries`; do 279 | if (get_server $server_id | jq -r '.server.state' | grep -qxE 'running'); then 280 | _scw stop -t $server_id 281 | fi 282 | sleep 1 283 | if (get_server $server_id | jq -r '.server.state' | grep -qxE 'stopping'); then 284 | _scw wait $server_id 285 | fi 286 | sleep 1 287 | if (get_server $server_id | jq -r '.server.state' | grep -qxE 'stopped'); then 288 | _scw rm $server_id 289 | fi 290 | if ! (get_server $server_id); then 291 | failed=false 292 | break 293 | fi 294 | backoff=$(echo "($try-1)*60" | bc) 295 | sleep $backoff 296 | done 297 | if (get_server $server_id); then 298 | logerr "Could not stop and remove server $server_name" 299 | return 1 300 | fi 301 | loginfo "Server $server_name removed" 302 | } 303 | 304 | image_from_volume() { 305 | server_id=$1 306 | image_arch=$2 307 | image_name=$3 308 | image_bootscript=$4 309 | 310 | loginfo "Creating snapshot of server" 311 | snapshot_id="" 312 | maximum_snapshot_tries=3 313 | failed=true 314 | for try in `seq 1 $maximum_snapshot_tries`; do 315 | snapshot_id_tmp=$(__scw commit --volume=0 $server_id "snapshot-${server_id}-$(date +%Y-%m-%d_%H:%M)") 316 | if [ $? = 0 ]; then 317 | snapshot_id=$snapshot_id_tmp 318 | failed=false 319 | break 320 | fi 321 | backoff=$(echo "(2^($try-1))*60" | bc) 322 | sleep $backoff 323 | done 324 | if $failed; then 325 | logerr "Could not create snapshot" 326 | return 1 327 | fi 328 | 329 | loginfo "Creating image from snapshot" 330 | image_id="" 331 | maximum_mkimage_tries=3 332 | failed=true 333 | for try in `seq 1 $maximum_mkimage_tries`; do 334 | image_id_tmp=$(__scw tag --arch="$image_arch" --bootscript="$image_bootscript" $snapshot_id "$image_name") 335 | if [ $? = 0 ]; then 336 | image_id=$image_id_tmp 337 | failed=false 338 | break 339 | fi 340 | backoff=$(echo "(2^($try-1))*60" | bc) 341 | sleep $backoff 342 | done 343 | if $failed; then 344 | logerr "Could not create image" 345 | return 2 346 | fi 347 | loginfo "Image $image_name on $image_arch created, id: $image_id" 348 | echo $image_id 349 | } 350 | -------------------------------------------------------------------------------- /scripts/setup_credentials.sh: -------------------------------------------------------------------------------- 1 | # Find a default identity for SSH 2 | if [ -z "$SSH_KEY_FILE" ]; then 3 | for candidate in "id_rsa" "id_dsa" "id_ecdsa" "id_ed25519"; do 4 | candidate_file="$HOME/.ssh/$candidate" 5 | if [ -f $candidate_file ]; then 6 | export SSH_KEY_FILE=$candidate_file 7 | break 8 | fi 9 | done 10 | if [ -z "$SSH_KEY_FILE" ]; then 11 | logerr "Could not find any ssh identity to use" 12 | exit 1 13 | fi 14 | fi 15 | 16 | # Retrieve scw api credentials 17 | if ! [ -f $HOME/.scwrc ]; then 18 | logerr "Please log into Scaleway first : scw login" 19 | exit 1 20 | fi 21 | read SCW_ORGANIZATION SCW_TOKEN < <(jq -r '"\(.organization) \(.token)"' $HOME/.scwrc) 22 | if [ -z "$SCW_ORGANIZATION" ] || [ -z "$SCW_TOKEN" ]; then 23 | logerr "Could not get authentication information from $HOME/.scwrc" 24 | exit 1 25 | fi 26 | -------------------------------------------------------------------------------- /scripts/test_image.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | SRC_DIR=$(dirname $(readlink -f $0)) 4 | source $SRC_DIR/scw.sh 5 | source $SRC_DIR/setup_credentials.sh 6 | 7 | test_start() { 8 | arch=$1 9 | REGION=$2 10 | image_id=$3 11 | servers_list_file=$4 12 | tests_dir=$5 13 | 14 | key=$(cat ${SSH_KEY_FILE}.pub | cut -d' ' -f1,2 | tr ' ' '_') 15 | if [ -n "$TEST_SERVER_TYPES" ]; then 16 | server_types="$TEST_SERVER_TYPES" 17 | elif [ "$arch" = "arm" ]; then 18 | server_types="C1" 19 | elif [ "$arch" = "x86_64" ]; then 20 | server_types="START1-S C2S" 21 | elif [ "$arch" = "arm64" ]; then 22 | server_types="ARM64-2GB" 23 | fi 24 | : >$servers_list_file 25 | 26 | for server_type in $server_types; do 27 | server_name="image-test-$(uuidgen -r)" 28 | server_id=$(create_server "$server_type" "" "$server_name" "$image_id" "AUTHORIZED_KEY=$key" "") 29 | [ $? -eq 0 ] || exiterr 30 | 31 | curl --fail -s -X PATCH -H "Content-Type: application/json" -H "x-auth-token: $SCW_TOKEN" -d '{"boot_type":"local"}' https://cp-$REGION.scaleway.com/servers/$server_id >/dev/null || logwarn "Could not set server boot type to local" 32 | 33 | boot_server $server_id || exiterr 34 | 35 | server_ip=$(get_server_ip $server_id) 36 | [ $? -eq 0 ] || exiterr 37 | echo "$server_id $REGION $server_type $server_name $server_ip" >>$servers_list_file 38 | 39 | wait_for_port $server_id 22 600 || exiterr 40 | 41 | if [ -n "$tests_dir" ] && [ -d "$tests_dir" ]; then 42 | loginfo "Running tests in $tests_dir" 43 | ssh_tmp_config=$(mktemp) 44 | _ssh_get_options >$ssh_tmp_config 45 | ssh -G $server_ip >>$ssh_tmp_config 46 | yamltest --timdir $tests_dir --pytestarg="--connection=ssh" --pytestarg="--ssh-config=$ssh_tmp_config" root@$server_ip || exiterr 47 | rm $ssh_tmp_config 48 | elif ! (_ssh root@$server_ip "uname -a; lsmod"); then 49 | logerr "Command 'uname -a; lsmod' failed to execute" 50 | exiterr 51 | fi 52 | done 53 | loginfo "Tested image $image_id on server(s):" 54 | cat $servers_list_file | while read server_id REGION server_type server_name server_ip; do 55 | loginfo "Name ${server_name}, type $server_type (id ${server_id}, ip ${server_ip})" 56 | done 57 | } 58 | 59 | test_stop() { 60 | servers_list_file=$1 61 | 62 | cat $servers_list_file | while read server_id REGION server_type server_name server_ip; do 63 | rm_server $server_id 64 | done 65 | } 66 | 67 | action=$1 68 | shift 69 | test_$action "$@" 70 | --------------------------------------------------------------------------------