diff --git a/dev-env/Readme.md b/dev-env/Readme.md new file mode 100644 index 0000000..bfde9a3 --- /dev/null +++ b/dev-env/Readme.md @@ -0,0 +1,18 @@ +Setting up a New Development Environment +======================================== + +The following instructions use VirtualBox and Vagrant to setup a +VM running Debian, with most of the required tools installed. + +Step 1: Download and install VirtualBox + +Step 2: Download and install vagrant + +Step 3: Update defaults.yaml or create a custom.yaml with the overridden values + +Step 4: "vagrant up" + +Note: + Vagrant only allows you to bring up one environment per vagrant file. +To setup additional development environments (ie: for alternative releases), +you must copy the repo to another location. diff --git a/dev-env/vagrant/Readme.md b/dev-env/vagrant/Readme.md new file mode 100644 index 0000000..547a686 --- /dev/null +++ b/dev-env/vagrant/Readme.md @@ -0,0 +1,31 @@ + +Supported Capabilities: + Disk: + - support bigger VBOX disk + - support relocate the DISK to be on an SSD + - support disk resize within the VM + User: + - support ssh as the new user. + - setup bash env (variables) + Build: + - repo init + - repo sync + - setup git settings + - creates required directories for build env + - minikube setup + - update containers prior to running the downloader + - invoke downloader + - support restart of minikube on reboot + +Setup Time: (approximately 25 min): + - 3 minutes to download and provision the Debian VM + - 6 minutes to clone the source code. + - 7 minutes initialize the build containers + - 9 minutes to run the downloader for the STX build packages + +Future Work Items: + - populate the initial mirror from previous upstream builds + - provide data on how to upload the git certs (for git review, etc..) + - DHCP support (so you can connect to the VM by its name) + verified /etc/machine-id is unique, so DHCP should work for these VMs. + - NIS (home dir) support diff --git a/dev-env/vagrant/Vagrantfile b/dev-env/vagrant/Vagrantfile new file mode 100644 index 0000000..18be31a --- /dev/null +++ b/dev-env/vagrant/Vagrantfile @@ -0,0 +1,397 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# ========================================================= +# Automatically setup required vagrant plugins +# Currently required vagrant plugins: +# - vagrant-disksize +required_plugins = [ 'vagrant-disksize' ] + +if ARGV[0] != 'plugin' + plugins_to_install = required_plugins.select { |plugin| not Vagrant.has_plugin? plugin } + if not plugins_to_install.empty? + puts "Installing plugins: #{plugins_to_install.join(' ')}" + if system "vagrant plugin install #{plugins_to_install.join(' ')}" + exec "vagrant #{ARGV.join(' ')}" + else + abort "Installation of one or more plugins has failed. Aborting." + end + end +end +# ========================================================== +require 'yaml' + +# A file containing all the default variables is provided +VARS = YAML.load_file(File.join(File.dirname(__FILE__), 'defaults.yaml')) + +# A user can create a file called 'custom.yaml' and override values from 'defaults.yaml' +CUSTOM = File.join(File.dirname(__FILE__), 'custom.yaml') +if File.exist?(CUSTOM) + CUSTOM_VARS = YAML.load_file(CUSTOM) + VARS = VARS.merge CUSTOM_VARS +end + +# Print the variables from default.yaml and custom.yaml that are being used +puts "Vagrant variables:" +puts VARS + +# ========================================================== +# Setup the packages +$package_setup = </dev/null || useradd ${DEV_USER} -m -p $(openssl passwd -1 ${DEV_PASSWORD}) -s ${DEV_SHELL} + usermod -s ${DEV_SHELL} ${DEV_USER} + # Add the user to the docker group + sudo usermod -aG docker ${DEV_USER} + # Add the user to the sudoers file + echo "${DEV_USER} ALL=(ALL) NOPASSWD:ALL" | tee /etc/sudoers.d/${DEV_USER} + echo "Git setup" + su - ${DEV_USER} -c "git config --global user.name \"${USER_NAME}\"" + su - ${DEV_USER} -c "git config --global user.email ${USER_EMAIL}" + + # setup the directory for the user under /localdisk + MY_LOCALDISK="/localdisk/${DEV_USER}" + mkdir -p ${MY_LOCALDISK} + chown ${DEV_USER} ${MY_LOCALDISK} + + # setup ssh host keys so that git hosts will not complain for ssh urls + # .ssh must be 700 permissions + # Creating it as root, because "su -" is a pain to deal with + mkdir -m=700 -p /home/${DEV_USER}/.ssh + chown ${DEV_USER}:${DEV_USER} /home/${DEV_USER}/.ssh + + # Setup keys for this host + SSH_KEY="/home/${DEV_USER}/.ssh/id_ed25519" + HOSTNAME=`hostname` + su - ${DEV_USER} -c "ssh-keygen -q -f ${SSH_KEY} -N '' -t ed25519 -C ${DEV_USER}@${HOSTNAME}" + + # Setup known hosts + su - ${DEV_USER} -c "ssh-keyscan -t rsa ${KNOWN_HOSTS} >> /home/${DEV_USER}/.ssh/known_hosts" + # some HOSTS might require an alternative port. ie: ssh://git@nowhere.com:7999 + if [[ ! -z "${ALT_PORT}" ]] + then + echo "Setting up ${ALT_PORT}" + su - ${DEV_USER} -c "ssh-keyscan -t rsa -p ${ALT_PORT} ${ALT_HOSTS} >> /home/${DEV_USER}/.ssh/known_hosts" + else + echo "NOT Setting up ${ALT_PORT}" + fi + + if [[ ! -z "${SSH_URL}" ]] + then + echo "Uploading ssh key to ${SSH_URL} by logging in with git user and password" + SSH_PUB_KEY=`cat ${SSH_KEY}.pub` + su - ${DEV_USER} -c "curl -v -u ${GIT_USER}:${GIT_PASSWORD} POST -H \"Content-Type: application/json\" -d '{\"text\": \"${SSH_PUB_KEY}\"}' ${SSH_URL}" + fi + + # Add additional exports to .bashrc + # https://opendev.org/starlingx/tools/src/branch/master/import-stx.README + PROFILE="/home/${DEV_USER}/.profile" + if grep -q "PROJECT=" ${PROFILE} + then + echo "${PROFILE} already setup" + else + echo "Setting up ${PROFILE}" + + # append all of these to the end of .profile + echo "export PROJECT=${PROJECT}" >> ${PROFILE} + echo "export USER_NAME=\"${USER_NAME}\"" >> ${PROFILE} + echo "export USER_EMAIL=${USER_EMAIL}" >> ${PROFILE} + echo "export MINIKUBENAME=minikube-${DEV_USER}-${PROJECT}" >> ${PROFILE} + + # minikube + MINIKUBE_HOME="${MY_LOCALDISK}/MINIKUBE_HOME" + su - ${DEV_USER} -c "mkdir -p ${MINIKUBE_HOME}" + echo "export MINIKUBE_HOME=${MINIKUBE_HOME}" >> ${PROFILE} + + # patches + PATCHES_DIR="${MY_LOCALDISK}/PATCHES" + su - ${DEV_USER} -c "mkdir -p ${PATCHES_DIR}" + echo "export PATCHES_DIR=${PATCHES_DIR}" >> ${PROFILE} + + + # STX_BUILD_HOME is the same as the project workspace + MY_WORKSPACE="${MY_LOCALDISK}/WORKSPACE/${PROJECT}" + su - ${DEV_USER} -c "mkdir -p ${MY_WORKSPACE}" + echo "export MY_WORKSPACE=${MY_WORKSPACE}" >> ${PROFILE} + echo "export STX_BUILD_HOME=${MY_WORKSPACE}" >> ${PROFILE} + + MY_REPO_ROOT_DIR="${MY_WORKSPACE}/localdisk/designer/${DEV_USER}/${PROJECT}" + su - ${DEV_USER} -c "mkdir -p ${MY_REPO_ROOT_DIR}" + echo "export MY_REPO_ROOT_DIR=${MY_REPO_ROOT_DIR}" >> ${PROFILE} + + echo "export MY_REPO=${MY_REPO_ROOT_DIR}/cgcs-root" >> ${PROFILE} + STX_TOOLS="${MY_REPO_ROOT_DIR}/stx-tools" + echo "export STX_TOOLS=${MY_REPO_ROOT_DIR}/stx-tools" >> ${PROFILE} + # Update the profile so that import-stx is automatically 'sourced' whenever we login + echo " +if [[ -d \${STX_TOOLS} ]]; then + pushd \${STX_TOOLS} > /dev/null + source ./import-stx + popd > /dev/null +fi " >> ${PROFILE} + + fi # setting up profile + +USER_SETUP + + +# ==================================================== +$system_setup = < + mkdir -p /localdisk +SYSTEM_SETUP + +# ==================================================== +# This inline script uses special syntax to prevent ruby from stripping quotes +$repo_setup = <<-'REPO_SETUP' + # Note: You cannot switch users in vagrant + # su - -c is the only way to run commands as another user + # Step 1) repo init + MY_LOCALDISK="/localdisk/${DEV_USER}" + MY_WORKSPACE="${MY_LOCALDISK}/WORKSPACE/${PROJECT}" + MY_REPO_ROOT_DIR="${MY_WORKSPACE}/localdisk/designer/${DEV_USER}/${PROJECT}" + STX_TOOLS="${MY_REPO_ROOT_DIR}/stx-tools" + + date + echo "Initializing repo" + su - ${DEV_USER} -c "cd ${MY_REPO_ROOT_DIR}; + repo init -u ${MANIFEST_URL} -m ${MANIFEST_FILE} -b ${MANIFEST_BRANCH}" + # Step 2) repo sync + date + echo "Synchronizing repo. This can take some time (approximately 8 min)" + su - ${DEV_USER} -c "cd ${MY_REPO_ROOT_DIR}; + repo sync -j $(nproc --all)" + + # Step 3) stx-init-env + date + echo "stx-init-env. This can take some time (approximately 6 min)" + # initialize minikube env + su - ${DEV_USER} -c "cd ${STX_TOOLS}; + source import-stx; + stx config --add builder.myuname $(id -un ${DEV_USER}); + stx config --add builder.uid $(id -u ${DEV_USER}); + stx config --add project.name ${PROJECT}; + stx config --add project.gituser \"${USER_NAME}\"; + stx config --add project.gitemail ${USER_EMAIL}; + # stx-init-env spams stdout, so we will redirect that command to a log + ./stx-init-env > ${MY_WORKSPACE}/stx-init-env.log 2>&1 ; + + # Display the last new lines of the log + tail ${MY_WORKSPACE}/stx-init-env.log; + + # status should indicate success rather than 'ContainerCreating' + stx control status" + + # Step 3) Support minikube auto-start on reboot for this user + date + # override contents of /usr/lib/systemd/system/minikube.service + MINIKUBE_SERVICE="/usr/lib/systemd/system/minikube.service" + MINIKUBENAME="minikube-${DEV_USER}-${PROJECT}" + echo " +[Unit] +Description=minikube +After=network-online.target containerd.service docker.service +Wants=network-online.target docker.service +Requires=docker.socket containerd.service docker.service + +[Service] +Type=oneshot +ExecStart=/bin/bash -l -c \"minikube start -p ${MINIKUBENAME}\" +RemainAfterExit=true +ExecStop=/bin/bash -l -c \"minikube stop -p ${MINIKUBENAME}\" +User=${DEV_USER} +Group=docker + +[Install] +WantedBy=multi-user.target +" > ${MINIKUBE_SERVICE} + # reload minikube systemd service + systemctl daemon-reload + systemctl enable minikube + systemctl start minikube + + # Step 4) Run the downloader + date + echo "Waiting 60 seconds before running the downloader to ensure all containers are running" + sleep 60 + + date + echo "Running the downloader. This can take some time (approximately 10 min)" + su - ${DEV_USER} -c "cd ${STX_TOOLS}; + source import-stx; + stx control status; + echo 'Running apt-get update'; + stx shell -c 'sudo apt-get update'; + echo 'Running downloader'; + stx shell -c 'downloader' > ${MY_WORKSPACE}/downloader.log 2>&1; + # display the last new lines of the downloader log + tail ${MY_WORKSPACE}/downloader.log + " + date + echo "DONE" + + # populate mirrors + # download prebuilt artifacts +REPO_SETUP + +# =================================================================== +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure("2") do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + # Every Vagrant development environment requires a box. You can search for + # boxes at https://vagrantcloud.com/search. + config.vm.box = VARS['base_image'] + + # set the hostname within this VBOX + config.vm.hostname = VARS['hostname'] + + # set the vbox disk size (this uses vagrant-disksize plugin) + # Note: provisioning steps are needed for debian to recognize this + config.disksize.size = VARS['vbox_disk_size'] + + # config.vm.define + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + # NOTE: This will enable public access to the opened port + # config.vm.network "forwarded_port", guest: 80, host: 8080 + config.vm.network "forwarded_port", guest: 22, host: VARS['sshport'] + config.ssh.insert_key = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine and only allow access + # via 127.0.0.1 to disable public access + # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + + # Disable the synched folder in vagrant + config.vm.synced_folder '.', '/vagrant', disabled: true + + # VirtualBox settings: + config.vm.provider "virtualbox" do |vb| + vb.name = VARS['vbox_name'] + vb.gui = VARS['vbox_gui'] + vb.memory = VARS['vbox_memory'] + vb.cpus = VARS['vbox_cpus'] + # Override where vagrant will install the VMs + if !VARS['vbox_vm_location'].nil? + vb.customize "pre-import", ["setproperty", "machinefolder", VARS['vbox_vm_location'] ] + end + vb.customize "pre-boot", ["modifyvm", :id, "--groups", VARS['vbox_group'] ] + end + + # First step of provisioning is to install the required packages + config.vm.provision "shell", inline: $package_setup + + # Make further changes to the system setup + config.vm.provision "shell", inline: $system_setup + + # Set up a new user + config.vm.provision "shell", env: {"DEV_USER" => VARS['dev_user'], + "DEV_PASSWORD" => VARS['dev_password'], + "DEV_SHELL" => VARS['dev_shell'], + "PROJECT" => VARS['PROJECT'], + "KNOWN_HOSTS" => VARS['KNOWN_HOSTS'], + "ALT_PORT" => VARS['ALT_PORT'], + "ALT_HOSTS" => VARS['ALT_HOSTS'], + "SSH_URL" => VARS['SSH_URL'], + "GIT_USER" => VARS['GIT_USER'], + "GIT_PASSWORD" => VARS['GIT_PASSWORD'], + "USER_EMAIL" => VARS['USER_EMAIL'], + "USER_NAME" => VARS['USER_NAME']}, inline: $user_setup + + # Initialize the code using the repo command + config.vm.provision "shell", env: {"DEV_USER" => VARS['dev_user'], + "MANIFEST_URL" => VARS['MANIFEST_URL'], + "MANIFEST_FILE" => VARS['MANIFEST_FILE'], + "MANIFEST_BRANCH" => VARS['MANIFEST_BRANCH'], + "PROJECT" => VARS['PROJECT'], + "USER_EMAIL" => VARS['USER_EMAIL'], + "USER_NAME" => VARS['USER_NAME']}, inline: $repo_setup +end diff --git a/dev-env/vagrant/defaults.yaml b/dev-env/vagrant/defaults.yaml new file mode 100644 index 0000000..b8c82e6 --- /dev/null +++ b/dev-env/vagrant/defaults.yaml @@ -0,0 +1,64 @@ +--- + # =============== vbox settings =============================================== + # Before running vagrant up , update the entries with the comment: "UPDATE_ME" + # =============== login settings =============================================== + dev_user: "sysadmin" # UPDATE_ME + dev_password: "sysadmin" # UPDATE_ME + USER_EMAIL: "somebody@nowhere.com" # UPDATE_ME + USER_NAME: "Some Body" # UPDATE_ME + + # base_image is the starting 'box' downloaded from https://app.vagrantup.com/boxes + # debian bullseye64 includes python 3.9 + base_image: "debian/bullseye64" + + # Create a VBox Group for the VM. Useful when making separate VMs for different branches + vbox_group: "/StarlingX Dev" + + # Assign a name for the development VM as shown in vbox + vbox_name: "stx-dev-vm" + + # Assign a hostname for the development VM + hostname: "stx-dev-vm" + + # Assign a port for port forwarding to ssh (22) + # meaning if you ssh to your :sshport it will connect to :22 + sshport: "2201" + + # Display the VirtualBox GUI when booting the machine + vbox_gui: true + + # 20 GB memory + vbox_memory: "20480" + + # 6 cpus + vbox_cpus: "6" + + # 500 GB disk size + vbox_disk_size: "500GB" + + # Uncomment and update the next line to override the location where VMs and disk are created + # vbox_vm_location: "D:\\SSD-VMS" + + # Note: Changing the shell will likely break many other setup steps. + dev_shell: "/bin/bash" + + # =============== BUILD settings =============================================== + # Warning: DO NOT use extended characters, underscore, or spaces for PROJECT + PROJECT: "stx-env" + + # KNOWN_HOSTS is the list of hosts that may need host key ssh validation for git + KNOWN_HOSTS: "github.com" + ALT_HOSTS: "" + ALT_PORT: "" + + # Internal git repositories and manifests may require additional fields to be setup + SSH_URL: "" + GIT_USER: "" + GIT_PASSWORD: "" + + # =============== SOURCE CODE settings =============================================== + # StarlingX code is checked out using 'repo' command + # ex: repo init -u https://opendev.org/starlingx/manifest -m default.xml -b master + MANIFEST_URL: "https://opendev.org/starlingx/manifest" + MANIFEST_FILE: "default.xml" + MANIFEST_BRANCH: "master"