Support windows.

This commit is contained in:
Shuai Lin 2016-12-05 13:41:25 +08:00
parent ec673e1df0
commit 0c609f6b5a
2 changed files with 479 additions and 0 deletions

67
README.windows.md Normal file
View file

@ -0,0 +1,67 @@
# Getting Stared On Windows
## System Requirements
Only Windows 10 is supported.
At this time(2016/12/5) windows server 2016 doesn't support running linux containers yet. We'll add the support for windows server 2016 once it support running linux containers.
## Install the Requirements
### Install Docker for Windows
Follow the instructions on https://docs.docker.com/docker-for-windows/ to install docker on windows.
You need to turn on the Hyper-V feature in your system:
- Open "program and features" from windows start menu
- Click "turn on/off windows features", you'll see a settings window
- If Hyper-V is not checked, check it. You may be asked to reboot your system after that.
Make sure docker daemon is running before continuing.
### Install Git
Download the installer from https://git-scm.com/download/win and install it.
**Important**: During the installation, you must choose "Checkout as is, Commit as is".
### Install Notepad++
Seafile configuration files are using linux-style line-ending, which can't be hanlded by the notepad.exe program. So we need to install notepad++, an lightweight text editor that works better in this case.
Download the installer from https://notepad-plus-plus.org/download/v7.2.2.html and install it. During the installation, you can uncheck all the optional components.
## Getting Started with Seafile Docker
### Decide Which Drive to Store Seafile Data
Choose the larges drive on your system. Assume it's the `C:` Drive. Now right-click on the tray icon of the docker app, and click the "settings" menu item.
You should see a settings dialog now. Click the "Shared Drives" tab, and check the `C:` drive. Then click "**apply**" on the settings dialog.
### Run Seafile Docker
First open a powershell window **as administrator** , and run the following command to set the execution policy to "RemoteSigned":
```sh
Set-ExecutionPolicy RemoteSigned
```
Close the powershell window, and open a new one **as the normal user**.
Now run the following commands:
(Note that if you're using another drive than "C:", say "D:" ,you should change the "/c/seafile" in the following commands to "/d/seafile" instead.)
```sh
git clone https://github.com/haiwen/seafile-docker.git /c/seafile/
cd /c/seafile/
Copy-Item samples/server.conf bootstrap/bootstrap.conf
# Edit the options according to your use case
start notepad++ bootstrap/bootstrap.conf
./launcher.ps1 bootstrap
./launcher.ps1 start
```

412
launcher.ps1 Normal file
View file

@ -0,0 +1,412 @@
# -*- buffer-file-coding-system: utf-8-unix -*-
<#
This is the powershell version of the launcher script to be used on windows.
you should use it instead of the linux 'launcher' script.
#>
Param(
[Parameter(Position=1)]
[string]$action,
[switch]$skipPrereqs,
[switch]$v
)
# Always verbose before we reach a stable release.
$v = $true
$ErrorActionPreference = "Stop"
$version = "6.0.5"
$image = "seafileorg/server:$version"
$local_image = "local_seafile/server:latest"
$dockerdir = $PSScriptRoot.Replace("\", "/")
$sharedir = "$dockerdir/shared"
$installdir = "/opt/seafile/seafile-server-$version"
$bootstrap_conf="$dockerdir/bootstrap/bootstrap.conf"
$version_stamp_file="$sharedir/seafile/seafile-data/current_version"
$bash_history="$sharedir/.bash_history"
$usage = {
Write-Host "Usage: launcher COMMAND [--skip-prereqs] [--docker-args STRING]"
Write-Host "Commands:"
Write-Host " start: Start/initialize the container"
Write-Host " stop: Stop a running container"
Write-Host " restart: Restart the container"
Write-Host " destroy: Stop and remove the container"
Write-Host " enter: Open a shell to run commands inside the container"
Write-Host " logs: View the Docker container logs"
Write-Host " bootstrap: Bootstrap the container based on a template"
Write-Host " rebuild: Rebuild the container (destroy old, bootstrap, start new)"
Write-Host ""
Write-Host "Options:"
Write-Host " --skipPrereqs Don't check launcher prerequisites"
Write-Host " --dockerArgs Extra arguments to pass when running docker"
exit 1
}
function main() {
check_is_system_supported
if (!$action) {
& $usage
}
# loginfo "action = $action"
if (!$skipPrereqs) {
check_prereqs
}
switch ($action) {
"bootstrap" { do_bootstrap }
"start" { do_start }
default { & $usage }
}
}
<# A Powershell version of the following bash code:
[[ $a == "1" ]] || {
# do something else when a != 1
}
Use it like:
do_if_not { where.exe docker } { loginfo "docker program doesn't exist"}
Currently the first branch must be a subprocess call.
#>
function do_if_not([scriptblock]$block_1, [scriptblock]$block_2) {
$failed = $false
try {
& $block_1
} catch [System.Management.Automation.RemoteException] {
$failed = $true
}
if ($failed) {
& $block_2
}
}
function do_if([scriptblock]$block_1, [scriptblock]$block_2) {
$failed = $false
try {
& $block_1
} catch [System.Management.Automation.RemoteException] {
$failed = $true
}
if (!($failed)) {
& $block_2
}
}
<#
Mimics python's `subproess.check_output`: Run the given command, capture the
output, and terminate the script if the command fails. For example:
check_output docker run ...
Code borrowed from http://stackoverflow.com/a/11549817/1467959
#>
function check_output($cmd) {
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $cmd
$pinfo.RedirectStandardError = $false
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.WorkingDirectory = $PSScriptRoot
if ($args) {
$pinfo.Arguments = $args
}
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$stdout = $p.StandardOutput.ReadToEnd()
$p.WaitForExit()
echo "$stdout"
if (!($p.ExitCode -eq 0)) {
err_and_quit "The command $cmd $args failed"
}
}
<#
Mimics python's `subprocess.check_call`: Run the given command, capture the
output, and terminate the script if the command fails. For example:
check_call docker run ...
#>
function check_call($cmd) {
if ($args) {
$process = Start-Process -NoNewWindow -Wait -FilePath "$cmd" -ArgumentList $args -PassThru
} else {
$process = Start-Process -NoNewWindow -Wait -FilePath "$cmd" -PassThru
}
if (!($process.ExitCode -eq 0)) {
err_and_quit "The command $cmd $args failed with code $LASTEXITCODE"
}
}
function get_date_str() {
Get-Date -format "yyyy-MM-dd hh:mm:ss"
}
function err_and_quit($msg) {
Write-Host -BackgroundColor Black -ForegroundColor Yellow -Object "[$(get_date_str)] Error: $msg"
exit 1
}
function loginfo($msg) {
Write-Host -ForegroundColor Green -Object "[$(get_date_str)] $msg"
}
function program_exists($exe) {
cmd.exe /c where.exe "$exe" 2>&1>$null
return $LASTEXITCODE -eq 0
}
function to_unix_path($path) {
$path -replace '^|\\+','/' -replace ':'
}
$sharedir_u = $(to_unix_path $sharedir)
$dockerdir_u = $(to_unix_path $dockerdir)
function check_prereqs() {
if (!(program_exists "git.exe")) {
err_and_quit "You need to install git first. Check https://git-scm.com/download/win".
}
if (!(program_exists "docker.exe")) {
err_and_quit "You need to install docker first. Check https://docs.docker.com/docker-for-windows/."
}
}
function check_is_system_supported() {
$ver = [Environment]::OSVersion
if (!($ver.Version.Major -eq 10)) {
err_and_quit "Only Windows 10 is supported."
}
}
function set_envs() {
$script:envs = @()
if ($v) {
$script:envs += "-e"
$script:envs += "SEAFILE_DOCKER_VERBOSE=true"
}
}
# Call powershell mkdir, but only create the directory when it doesn't exist
function makedir($path) {
if (!(Test-Path $path)) {
New-Item -ItemType "Directory" -Force -Path $path 2>&1>$null
}
}
function touch($path) {
if (!(Test-Path $path)) {
New-Item -ItemType "file" -Path $path 2>&1>$null
}
}
function init_shared() {
makedir "$sharedir/seafile"
makedir "$sharedir/db"
makedir "$sharedir/logs/seafile"
makedir "$sharedir/logs/var-log"
makedir "$sharedir/logs/var-log/nginx"
touch "$sharedir/logs/var-log/syslog"
touch $bash_history
}
function set_bootstrap_volumes() {
init_shared
$mounts = @(
"${sharedir_u}:/shared",
"${sharedir_u}/logs/var-log:/var/log",
"${sharedir_u}/db:/var/lib/mysql",
"${dockerdir_u}/bootstrap:/bootstrap",
"${dockerdir_u}/scripts:/scripts:ro",
"${dockerdir_u}/templates:/templates:ro",
"${dockerdir_u}/scripts/tmp/check_init_admin.py:$installdir/check_init_admin.py:ro",
"${sharedir_u}/.bash_history:/root/.bash_history"
)
$script:volumes = @()
foreach($m in $mounts) {
$script:volumes += "-v"
$script:volumes += "$m"
}
}
function set_volumes() {
init_shared
$mounts = @(
"${sharedir_u}:/shared",
"${sharedir_u}/logs/var-log:/var/log",
"${sharedir_u}/db:/var/lib/mysql",
"${sharedir_u}/.bash_history:/root/.bash_history"
)
$script:volumes=@()
foreach($m in $mounts) {
$script:volumes += "-v"
$script:volumes += "$m"
}
}
function set_ports() {
$ports = $(check_output "docker" "run" "--rm" "-it" `
"-v" "${dockerdir_u}/scripts:/scripts" `
"-v" "${dockerdir_u}/bootstrap:/bootstrap:ro" `
$image `
"/scripts/bootstrap.py" "--parse-ports")
# The output is like "-p 80:80 -p 443:443", we need to split it into an array
$script:ports = $(-split $ports)
}
function set_my_init() {
$script:my_init = @("/sbin/my_init")
if (!($v)) {
$script:my_init += "--quiet"
}
}
function parse_seafile_container([array]$lines) {
foreach($line in $lines) {
$fields = $(-split $line)
if ("seafile".Equals($fields[-1])) {
echo $fields[0]
break
}
}
## We can write it using more elegant "ForEach-Object" using the following
## code, but someone says that "break" works like "continue" in the
## ForEach-Object's script block.
##
## See ## http://stackoverflow.com/a/7763698/1467959
##
## Anway, we use a foreach loop to keep the code
## simple.
##
# $lines | ForEach-Object {
# $fields =$(-split $_)
# if ("seafile".Equals($fields[-1])) {
# echo $fields[0]
# break
# }
# }
}
# Equivalent of `docker ps | awk '{ print $1, $(NF) }' | grep " seafile$" | awk '{ print $1 }' || true`
function set_running_container() {
try {
$script:existing = $(parse_seafile_container $(docker ps))
} catch [System.Management.Automation.RemoteException] {
$script:existing = ""
}
}
# Equivalent of `docker ps -a |awk '{ print $1, $(NF) }' | grep " seafile$" | awk '{ print $1 }' || true`
function set_existing_container() {
try {
$script:existing = $(parse_seafile_container $(docker ps -a))
} catch [System.Management.Automation.RemoteException] {
$script:existing = ""
}
}
function ignore_error($cmd) {
if ($args) {
Start-Process -NoNewWindow -Wait -FilePath "$cmd" -ArgumentList $args
} else {
Start-Process -NoNewWindow -Wait -FilePath "$cmd"
}
}
function remove_container($container) {
do_if { docker inspect $container 2>&1>$null } {
docker rm -f $container 2>&1>$null
}
}
function do_bootstrap() {
if (!(Test-Path $bootstrap_conf)) {
err_and_quit "The file $bootstrap_conf doesn't exist. Have you run seafile-server-setup?"
}
do_if_not { docker history $image 2>&1>$null } {
loginfo "Pulling Seafile server image $version, this may take a while."
check_call docker pull $image
loginfo "Seafile server image $version pulled. Now bootstrapping the server ..."
}
set_envs
set_bootstrap_volumes
set_ports
set_my_init
# loginfo "ports is $script:ports"
remove_container "seafile-bootstrap"
check_call "docker" "run" "--rm" "-it" "--name" "seafile-bootstrap" `
"-e" "SEAFILE_BOOTSRAP=1" `
@script:envs `
@script:volumes `
@script:ports `
$image `
@script:my_init "--" "/scripts/bootstrap.py"
# @script:my_init "--" "/bin/bash"
loginfo "Now building the local docker image."
check_call "docker" "build" "-f" "bootstrap/generated/Dockerfile" "-t" "local_seafile/server:latest" "." 2>$null
loginfo "Image built."
}
function do_start() {
set_running_container
if ($script:running) {
loginfo "Nothing to do, your container has already started!"
exit 0
}
# check_version_match
set_existing_container
if ($script:existing) {
loginfo "starting up existing container"
check_call docker start seafile
exit 0
}
set_envs
set_volumes
set_ports
$attach_on_run = @()
$restart_policy = @()
if ("true".Equals($SUPERVISED)) {
$restart_policy = @("--restart=no")
$attach_on_run = @("-a", "stdout", "-a", "stderr")
} else {
$attach_on_run = @("-d")
}
loginfo "Starting up new seafile server container"
remove_container "seafile"
docker run @attach_on_run @restart_policy --name seafile -h seafile @envs @volumes @ports $local_image
}
. main