Compare commits

..

4 Commits

Author SHA1 Message Date
668fcca581 Remove Python package components 2024-08-09 16:27:43 +01:00
1b8e170fd9 Update links to point at new URL & branch 2024-08-09 16:24:18 +01:00
5b629fc5b4 Update bootstrap-Windows.ps1 script
* Add 1Password install step
* Add Scoop install step
* Remove SSH key generation step
* Make 1Password, Hyper-V, Containers, and SSH Server steps optional
* Refactor to run Scoop install as unelevated then relaunch as elevated
  for remaining tasks
2024-08-09 15:37:24 +01:00
3606f4bbb9 Update Windows bootstrap scripts
* Add `bootstrap-Windows.ps1` sets up the bare minimum required to start
  Debian in WSL2 sharing SSH keys with the Windows host and enable SSH
  server for remote access.
* Add `bootstrap-Windows.sh` copies Windows host SSH keys, upgrades
  Debian to unstable, then installs Ansible and dependencies.
* Remove `bootstrap-Windows.cmd`.
2022-06-11 15:45:58 +01:00
7 changed files with 120 additions and 417 deletions

View File

@@ -7,39 +7,29 @@ Bootstrap an OS instance with bare essentials.
To bootstrap a macOS instance:
```console
$ curl -O https://code.infektor.net/config/bootstrap/raw/master/bootstrap-macOS.sh && chmod +x bootstrap-macOS.sh && ./bootstrap-macOS.sh
$ curl -O https://git.infektor.net/config/bootstrap/raw/main/bootstrap-macOS.sh && chmod +x bootstrap-macOS.sh && ./bootstrap-macOS.sh
```
To bootstrap a Debian based Linux instance:
```console
$ wget https://code.infektor.net/config/bootstrap/raw/master/bootstrap-Debian.sh && chmod +x bootstrap-Debian.sh && ./bootstrap-Debian.sh
$ wget https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Debian.sh && chmod +x bootstrap-Debian.sh && ./bootstrap-Debian.sh
```
To bootstrap a Arch Linux based instance:
```console
$ curl -O https://code.infektor.net/config/bootstrap/raw/master/bootstrap-Arch.sh && chmod +x bootstrap-Arch.sh && ./bootstrap-Arch.sh
$ curl -O https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Arch.sh && chmod +x bootstrap-Arch.sh && ./bootstrap-Arch.sh
```
To bootstrap a Fedora Linux instance:
```console
$ curl -O https://code.infektor.net/config/bootstrap/raw/master/bootstrap-Fedora.sh && chmod +x bootstrap-Fedora.sh && ./bootstrap-Fedora.sh
$ curl -O https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Fedora.sh && chmod +x bootstrap-Fedora.sh && ./bootstrap-Fedora.sh
```
To bootstrap a Windows instance:
```console
$ bitsadmin /transfer bootstrap-Windows.cmd https://code.infektor.net/config/bootstrap/raw/master/bootstrap-Windows.cmd %cd%\bootstrap-Windows.cmd & %cd%\bootstrap-Windows.cmd
```
## Package
Install as a pip package to set SSH keys on any of GitHub, GitLab, BitBucket
Cloud, or Gogs servers:
```console
$ pip install git+https://code.infektor.net/config/bootstrap.git
$ python -c 'import bootstrap; bootstrap.set_ssh_keys()'
$ Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-WebRequest -Uri "https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Windows.ps1" -OutFile "./bootstrap-Windows.ps1"; ./bootstrap-Windows.ps1
```

View File

@@ -59,37 +59,46 @@ agree() {
}
apt_install() {
sudo apt-get install --yes --install-recommends $1 > /dev/null
sudo apt install --yes --install-recommends $1 > /dev/null
}
pip_install() {
pip3 install --user $1 > /dev/null
pip install --user $1 > /dev/null
}
export PATH=~/.local/bin:$PATH
agree "Update apt cache" && sudo apt update > /dev/null
agree "Upgrade apt packages" "N" && sudo apt upgrade > /dev/null
missing git && agree "Install git" && apt_install git
if missing python; then
agree "Intsall python-is-python3" && apt_install python-is-python3
if missing pip; then
agree "Install python-pip" && apt_install python-pip
agree "Upgrade pip with pip" && \
sudo -H pip_install --upgrade pip > /dev/null
fi
if missing pip3; then
agree "Install python-pip" && apt_install python3-pip
fi
if missing virtualenv; then
agree "Install python3-virtualenv" && apt_install python3-virtualenv
fi
missing virtualenv && agree "Install virtualenv" && pip_install virtualenv
if [ ! -f ~/.ssh/id_rsa ] && agree "Generate SSH key"; then
read -rp "SSH email: " email
[ ! -d ~/.ssh ] && mkdir -p ~/.ssh
ssh-keygen -t ed25519 -C "$email" -N "" -f ~/.ssh/id_rsa
ssh-keygen -t rsa -b 4096 -C "$email" -N "" -f ~/.ssh/id_rsa
fi
missing conduit && agree "Install ansible" && \
pip_install ansible
if ! missing virtualenv && agree "Set SSH keys on remote Git servers"; then
env=$(mktemp -d)
virtualenv $env > /dev/null
source $env/bin/activate
pip install git+https://code.infektor.net/config/bootstrap.git > /dev/null
python -c 'import bootstrap; bootstrap.set_ssh_keys()'
deactivate
rm -r $env
fi
missing conduit && agree "Install conduit" && \
pip_install git+ssh://git@github.com/kbenzie/conduit.git
echo "To use installed pip packages update your PATH:"
echo 'export PATH=~/.local/bin:$PATH'

View File

@@ -1,193 +0,0 @@
@echo off
setlocal
if [%1]==[/?] goto :help
echo %* | find "/?" > nul
if errorlevel 1 goto :main
:help
echo usage: %0 [/?]
echo
echo Bootstrap a macOS instance with:
echo
echo * Windows SDK - from MSDN
echo * Chocolatey - package manager
echo * Cmder, including Git - from Chocolatey
echo * Python - from Chocolatey
echo * virtualenv - from pip
echo * SSH key - from ssh-keygen
echo * GitHub public key - with SSH key
echo * GitLab public key - with SSH key
echo * BitBucket Cloud public key - with SSH key
echo * Gogs Cloud public key - with SSH key
echo * conduit - configuration manager
echo
echo optional arguments:
echo /? show this help message and exit
goto end
:main
:: Check for admin permissions
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
if errorlevel 1 (
echo Administrator privilages required!
exit /B 1
)
:: Install Windows SDK
:windows_sdk
set choice=
set /p choice="Install Windows SDK [Y/n]? "
if "%choice%"=="" goto windows_sdk_yes
if "%choice%"=="Y" goto windows_sdk_yes
if "%choice%"=="y" goto windows_sdk_yes
if "%choice%"=="N" goto windows_sdk_no
if "%choice%"=="n" goto windows_sdk_no
echo invalid value: %choice%
goto windows_sdk
:windows_sdk_yes
bitsadmin.exe /transfer "Download Windows SDK" https://go.microsoft.com/fwlink/p/?linkid=845298 %~dp0\winsdksetup.exe
if errorlevel 1 exit /B 1
echo Installing Windows SDK...
%~dp0\winsdksetup.exe /features + /q
if errorlevel 1 exit /B 1
del %~dp0\winsdksetup.exe
:windows_sdk_no
:: Install Chocolatey
:choco
set choice=
set /p choice="Install Chocolatey [Y/n]? "
if "%choice%"=="" goto choco_yes
if "%choice%"=="Y" goto choco_yes
if "%choice%"=="y" goto choco_yes
if "%choice%"=="N" goto choco_no
if "%choice%"=="n" goto choco_no
echo invalid value: %choice%
goto choco
:choco_yes
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
if errorlevel 1 exit /B 1
:choco_no
:: Install Cmder, including Git
:git
set choice=
set /p choice="Install Cmder, including Git [Y/n]? "
if "%choice%"=="" goto git_yes
if "%choice%"=="Y" goto git_yes
if "%choice%"=="y" goto git_yes
if "%choice%"=="N" goto git_no
if "%choice%"=="n" goto git_no
echo invalid value: %choice%
goto git
:git_yes
choco install cmder --yes
if errorlevel 1 exit /B 1
:git_no
:: Install Python
:python
set choice=
set /p choice="Install Python [Y/n]? "
if "%choice%"=="" goto python_yes
if "%choice%"=="Y" goto python_yes
if "%choice%"=="y" goto python_yes
if "%choice%"=="N" goto python_no
if "%choice%"=="n" goto python_no
echo invalid value: %choice%
goto python
:python_yes
choco install python2 --yes
if errorlevel 1 exit /B 1
:python_no
:: Install virtualenv
:virtualenv
set choice=
set /p choice="Install virtualenv [Y/n]? "
if "%choice%"=="" goto virtualenv_yes
if "%choice%"=="Y" goto virtualenv_yes
if "%choice%"=="y" goto virtualenv_yes
if "%choice%"=="N" goto virtualenv_no
if "%choice%"=="n" goto virtualenv_no
echo invalid value: %choice%
goto virtualenv
:virtualenv_yes
"C:\Python27\Scripts\pip.exe" install virtualenv
if errorlevel 1 exit /B 1
:virtualenv_no
:: Generate SSH key
:ssh_key
set choice=
set /p choice="Generate SSH key [Y/n]? "
if "%choice%"=="" goto ssh_key_yes
if "%choice%"=="Y" goto ssh_key_yes
if "%choice%"=="y" goto ssh_key_yes
if "%choice%"=="N" goto ssh_key_no
if "%choice%"=="n" goto ssh_key_no
echo invalid value: %choice%
goto ssh_key
:ssh_key_yes
mkdir %USERPROFILE%\.ssh
set /P email="SSH email: "
"C:\tools\cmder\vendor\git-for-windows\usr\bin\ssh-keygen.exe" -t rsa -b 4096 -C "%email%" -N "" -f %USERPROFILE%\.ssh\id_rsa
if errorlevel 1 exit /B 1
:ssh_key_no
:: Set SSH keys on remote Git servers
:remote_ssh_keys
:: Add git to the PATH to pip can find it
set PATH=C:\tools\cmder\vendor\git-for-windows\bin;%PATH%
set choice=
set /p choice="Set SSH keys on remote Git servers [Y/n]? "
if "%choice%"=="" goto remote_ssh_keys_yes
if "%choice%"=="Y" goto remote_ssh_keys_yes
if "%choice%"=="y" goto remote_ssh_keys_yes
if "%choice%"=="N" goto remote_ssh_keys_no
if "%choice%"=="n" goto remote_ssh_keys_no
echo invalid value: %choice%
goto remote_ssh_keys
:remote_ssh_keys_yes
"C:\Python27\Scripts\virtualenv.exe" %~dp0\bootstrap_env
if errorlevel 1 exit /B 1
"%~dp0\bootstrap_env\Scripts\pip.exe" install git+https://code.infektor.net/config/bootstrap.git
if errorlevel 1 exit /B 1
"%~dp0\bootstrap_env\Scripts\python.exe" -c "import bootstrap; bootstrap.set_ssh_keys()"
if errorlevel 1 exit /B 1
:remote_ssh_keys_no
:: Install conduit
:conduit
set choice=
set /p choice="Install conduit [Y/n]? "
if "%choice%"=="" goto conduit_yes
if "%choice%"=="Y" goto conduit_yes
if "%choice%"=="y" goto conduit_yes
if "%choice%"=="N" goto conduit_no
if "%choice%"=="n" goto conduit_no
echo invalid value: %choice%
goto conduit
:conduit_yes
"C:\Python27\Scripts\pip.exe" install git+ssh://git@github.com/kbenzie/conduit.git
rmdir /Q /S "%~dp0\bootstrap_env"
:conduit_no
:remove_bootstrap
set choice=
set /p choice="Remove bootstrap-Windows.cmd [y/N]? "
if "%choice%"=="" goto remove_bootstrap_no
if "%choice%"=="Y" goto remove_bootstrap_yes
if "%choice%"=="y" goto remove_bootstrap_yes
if "%choice%"=="N" goto remove_bootstrap_no
if "%choice%"=="n" goto remove_bootstrap_no
echo invalid value: %choice%
goto remove_bootstrap
:remove_bootstrap_yes
start /b "" cmd /c del "%~f0"&exit /b
:remove_bootstrap_no
:end
endlocal

65
bootstrap-Windows.ps1 Normal file
View File

@@ -0,0 +1,65 @@
$IsElevated = [bool]([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
$Choices = '&Yes', '&No'
if (-Not $IsElevated) {
Write-Host "Not running as Administrator. Performing unprivileged actions."
# Install Scoop
Write-Host "`nInstall Scoop"
$ScoopInstaller = "$env:USERPROFILE/Downloads/ScoopInstaller.ps1"
Invoke-WebRequest -Uri https://get.scoop.sh -OutFile $ScoopInstaller
&$ScoopInstaller -ScoopDir "$env:LocalAppData/Scoop" -ScoopGlobalDir "$env:ProgramData/Scoop"
$Decision = $Host.UI.PromptForChoice('Relaunch as Administrator', 'Proceed?', $Choices, 0)
if ($Decision -eq 0) {
$Bootstrap = $MyInvocation.MyCommand.Path
Start-Process powershell.exe "-ExecutionPolicy ByPass -NoProfile -File $Bootstrap" -Verb RunAs
}
} else {
Write-Host "Running as Administrator. Performing privileged actions."
# Install 1Password
$Decision = $Host.UI.PromptForChoice('Install 1Password', 'Proceed?', $Choices, 0)
if ($Decision -eq 0) {
$1passwordInstaller = "$env:USERPROFILE/Downloads/1PasswordSetup-latest.exe"
Invoke-WebRequest -Uri "https://downloads.1password.com/win/1PasswordSetup-latest.exe" -OutFile "$1passwordInstaller"
&$1passwordInstaller
Remove-Item $1passwordInstaller
} else {
echo 'Skipping 1Password'
}
# Enable Hyper-V
$Decision = $Host.UI.PromptForChoice('Enable Hyper-V', 'Proceed?', $Choices, 0)
if ($Decision -eq 0) {
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
} else {
echo 'Skipping Hyper-V'
}
# Enable Containters
$Decision = $Host.UI.PromptForChoice('Enable Containers', 'Proceed?', $Choices, 0)
if ($Decision -eq 0) {
Enable-WindowsOptionalFeature -Online -FeatureName Containers -All
} else {
echo 'Skipping Containers'
}
# Install Chocolatey
Write-Host "`nInstall Chocolatey"
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Install SSH Server
$Decision = $Host.UI.PromptForChoice('Install SSH Server', 'Proceed?', $Choices, 0)
if ($Decision -eq 0) {
choco install --yes "--package-parameters=/SSHServerFeature" openssh
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
} else {
echo 'Skipping SSH Server'
}
Write-Host 'Press any key to continue...'
[System.Console]::ReadKey($true)
}

27
bootstrap-Windows.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Copy SSH keys from Windows host.
cp -r /mnt/c/Users/Benie/.ssh ~/.ssh
chown benie:benie ~/.ssh
for file in ~/.ssh/*; do
chmod 0600 $file
done
# Upgrade Debian to unstable
sudo apt-get update
sudo apt-get upgrade --yes
sudo sed 's/stretch/buster/g' -i /etc/apt/sources.list
sudo apt-get update
sudo apt-get full-upgrade --yes
sudo sed 's/buster/bullseye/g' -i /etc/apt/sources.list
sudo apt-get update
sudo apt-get full-upgrade --yes
sudo sed 's/bullseye/unstable/g' -i /etc/apt/sources.list
sudo apt-get update
sudo apt-get full-upgrade --yes
# Install ansible
sudo apt-get install ansible git python3-apt python3-pip

View File

@@ -1,184 +0,0 @@
"""Interactively set SSH keys on remote Git servers."""
from __future__ import print_function
from getpass import getpass
from os import environ
from os.path import join
from platform import node, system
from requests import ConnectionError, get, post
from requests.auth import HTTPBasicAuth
from requests.compat import urlparse
try:
input = raw_input
except NameError:
pass
class BootstrapError(Exception):
"""Bootstrap Exception."""
pass
def bootstrap_error(response):
"""Create a BootstrapError from a Response."""
return BootstrapError('%s %s' % (response.status_code, response.reason))
def agree(question, default='Y'):
"""Prompt user to answer a yes/no question."""
valid = {
'y': True,
'Y': True,
'yes': True,
'n': False,
'N': False,
'no': False,
'': {'Y': True,
'N': False}[default]
}
answer = input('%s [%s]? ' % (question, {'Y': 'Y/n', 'N': 'y/N'}[default]))
try:
return valid[answer]
except KeyError:
print('invalid input: %s' % answer)
return agree(question)
def get_url(service, default):
"""Get URL."""
url = input('%s URL%s: ' % (service, ' (%s)' % default if default else ''))
if url == '':
if default:
return default
else:
print('invalid input: %s' % url)
return get_url(service, default)
return url
def get_username_password(service):
"""Get username/password."""
username = input('%s username: ' % service)
password = getpass('%s password: ' % service)
return (username, password)
def get_local_key():
"""Get local SSH key."""
if system() == 'Windows':
home = environ['userprofile']
else:
home = environ['HOME']
with open(join(home, '.ssh', 'id_rsa.pub'), 'r') as key_file:
return key_file.read().rstrip()
def key_exists(keys, local_key):
"""Check if local SSH key is already set."""
for key in keys:
if local_key.startswith(key['key']):
return True
return False
def set_github_ssh_key():
"""Set GitHub SSH key."""
url = urlparse(get_url('GitHub', 'https://github.com'))
keys_url = '%s://api.%s/user/keys' % (url.scheme, url.netloc)
username, password = get_username_password('GitHub')
auth = HTTPBasicAuth(username, password)
response = get(keys_url, auth=auth)
if response.status_code != 200:
raise bootstrap_error(response)
keys = response.json()
local_key = get_local_key()
if not key_exists(keys, local_key):
response = post(
keys_url, auth=auth, json={'title': node(),
'key': local_key})
if response.status_code != 201:
raise bootstrap_error(response)
def set_gitlab_ssh_key():
"""Set GitLab SSH key."""
api_url = '%s/api/v4' % get_url('GitLab', 'https://gitlab.com')
keys_url = '%s/user/keys' % api_url
username, password = get_username_password('GitLab')
credentials = {'login': username, 'password': password}
response = get(keys_url, credentials)
if response.status_code != 200:
raise bootstrap_error(response)
keys = response.json()
local_key = get_local_key()
if not key_exists(keys, local_key):
response = post(keys_url,
credentials,
json={
'title': node(),
'key': local_key
})
if response.status_code != 201:
raise bootstrap_error(response)
def set_bitbucket_cloud_ssh_key():
"""Set BitBucket Cloud SSH key."""
username, password = get_username_password('BitBucket Cloud')
keys_url = 'https://api.bitbucket.org/1.0/users/%s/ssh-keys' % username
auth = HTTPBasicAuth(username, password)
response = get(keys_url, auth=auth)
if response.status_code != 200:
raise bootstrap_error(response)
keys = response.json()
local_key = get_local_key()
if not key_exists(keys, local_key):
response = post(
keys_url, auth=auth, data={'label': node(),
'key': local_key})
if response.status_code != 200:
raise bootstrap_error(response)
def set_gogs_ssh_key():
"""Set Gogs SSH key."""
keys_url = '%s/api/v1/user/keys' % get_url('Gogs', None)
username, password = get_username_password('Gogs')
auth = HTTPBasicAuth(username, password)
response = get(keys_url, auth=auth)
if response.status_code != 200:
raise bootstrap_error(response)
keys = response.json()
local_key = get_local_key()
if not key_exists(keys, local_key):
response = post(
keys_url, auth=auth, json={'title': node(),
'key': local_key})
if response.status_code != 201:
raise bootstrap_error(response)
def set_ssh_keys():
"""Interactively set SSH keys on remote Git servers."""
try:
for service in ['GitHub', 'GitLab', 'BitBucket Cloud', 'Gogs']:
question = 'Set %s SSH key' % service
default = 'Y'
while agree(question, default):
try:
{
'GitHub': set_github_ssh_key,
'GitLab': set_gitlab_ssh_key,
'BitBucket Cloud': set_bitbucket_cloud_ssh_key,
'Gogs': set_gogs_ssh_key,
}[service]()
if service == 'BitBucket Cloud':
break
question = 'Set another %s SSH key' % service
default = 'N'
except (BootstrapError, ConnectionError) as error:
print('error: %s' % error.message)
except KeyboardInterrupt:
exit(130)

View File

@@ -1,11 +0,0 @@
"""Setup bootstrap package."""
from setuptools import find_packages, setup
setup(
name='bootstrap',
version='0.1.0',
packages=find_packages(),
install_requires=[
'requests',
])