git-push-for-backups

git-syncing
This commit is contained in:
Nemo 2019-08-14 15:10:07 +05:30 committed by GitHub
commit 425d55e30f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 32 deletions

View File

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## 0.2.1 - 2019-08-14
- Adds a `push` command (See #2)
## 0.2.0 - 2019-08-12
- Adds export command (See [#1013](https://github.com/outline/outline/pull/1013) for corresponding Outline PR)

View File

@ -4,6 +4,9 @@ WORKDIR /outliner
COPY . /outliner/
RUN gem install bundler && \
bundle install
bundle install && \
apk add --no-cache git openssh-client && \
echo -e "StrictHostKeyChecking no" >> /etc/ssh/ssh_config && \
mkdir /root/.ssh
ENTRYPOINT ["/outliner/entrypoint.sh"]

View File

@ -81,10 +81,27 @@ docker run --env OUTLINE_BASE_URI="https://kb.example.com" \
import "/data" "Archive"
```
### Push
Note: Push is currently only available as a Docker Command
```bash
docker run --env OUTLINE_BASE_URI="https://kb.example.com" \
--env OUTLINE_TOKEN="PUT YOUR TOKEN HERE" \
--env OUTLINE_TOKEN="PUT YOUR TOKEN HERE" \
--env GIT_BRANCH=outline \
--env GIT_REMOTE_URL=git@example.com:org/outline.backup.git
--volume /etc/ssh/private.key:/root/.ssh/id_rsa
captn3m0/outliner \
push
```
#### Limitations
- Images are currently not imported. Host them externally for this to work.
- Only `.md` files are currently supported
- `push` doesn't sync file-history, but is meant to push a one-time backup to Git.
- `StrictHostKeyChecking` is currently disabled for `push`, please only run this in trusted networks.
## Development

View File

@ -1,19 +1,63 @@
#!/bin/sh
set -eu
if [ $# -eq 0 ]; then
echo "Please run with outliner [export|import] arguments"
echo "Please run with outliner [export|import|sync] arguments"
exit
fi
setup_git() {
if [ -f "$HOME/.ssh/id_rsa" ]; then
# This is required because Kubernetes secret mounts can't
# have file permissions set
chmod 0400 "$HOME/.ssh/id_rsa"
if [ ! -d "$HOME/.ssh/id_rsa.pub" ]; then
ssh-keygen -y -f "$HOME/.ssh/id_rsa" > "$HOME/.ssh/id_rsa.pub"
fi
echo "[+] Using SSH key for git pushes"
else
echo "[E] Git credentials not available, quitting"
exit 1
fi
eval $(ssh-agent)
ssh-add "$HOME/.ssh/id_rsa"
}
update_git_config() {
EMAIL=${GIT_EMAIL:-outliner@example.invalid}
git config --global user.email "$EMAIL"
git config --global user.name "Outliner Backup"
git remote add origin "$GIT_REMOTE_URL"
}
case $1 in
export)
shift
bundle exec outliner-export $@
bundle exec outliner-export "$@"
;;
import)
shift
bundle exec outliner-import $@
break
bundle exec outliner-import "$@"
;;
sync)
tmp_dir=$(mktemp -d)
if [ -z "$GIT_REMOTE_URL" ]; then
echo "[E] GIT_REMOTE_URL not set"
exit 1
else
setup_git
bundle exec outliner-export "$tmp_dir"
cd "$tmp_dir"
git init
update_git_config
git add .
git commit --message "Backup: $(date)" > /dev/null
BRANCH=${GIT_BRANCH:-master}
git checkout -b "$BRANCH"
git status
git push origin --force "HEAD:$BRANCH"
fi
;;
*)
echo "Invalid command, please check README"

View File

@ -1,16 +1,15 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require "bundler/setup"
require "outliner"
require 'bundler/setup'
require 'outliner'
require 'tempfile'
def validate
unless (ARGV.size == 1) and Dir.exists?(ARGV[0]) and ENV.key?('OUTLINE_BASE_URI') and ENV.key?('OUTLINE_TOKEN')
puts "[E] Please call as `outliner-export directory`"
puts "[E] Please export OUTLINE_BASE_URI and OUTLINE_TOKEN environment variables"
puts "[E] OUTLINE_BASE_URI should not include /api"
exit 1
end
raise 'Missing arguments' if ARGV.size != 1
raise 'Invalid directory' unless Dir.exist?(ARGV[0])
raise 'OUTLINE_BASE_URI not set' unless ENV.key?('OUTLINE_BASE_URI')
raise 'OUTLINE_TOKEN not set' unless ENV.key?('OUTLINE_TOKEN')
end
# Run validations
@ -25,7 +24,7 @@ response = CLIENT.collections_exportAll(download: true)
# Extract it to a tempfle
file = Tempfile.new('download.zip')
File.open(file.path, 'w') { |file| file.write(response.body) }
File.open(file.path, 'w') { |f| f.write(response.body) }
`unzip -o "#{file.path}" -d "#{local_directory}"`

View File

@ -1,25 +1,28 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require "bundler/setup"
require "outliner"
require 'bundler/setup'
require 'outliner'
def validate
unless (ARGV.size == 2) and Dir.exists?(ARGV[0]) and ARGV[1].match(/\w+/) and ENV.key?('OUTLINE_BASE_URI') and ENV.key?('OUTLINE_TOKEN')
puts "[E] Please call as `outliner-import local_directory remote_collection_name`"
puts "[E] Please export OUTLINE_BASE_URI and OUTLINE_TOKEN environment variables"
puts "[E] OUTLINE_BASE_URI should not include /api"
exit 1
end
raise 'Missing arguments' if ARGV.size != 2
raise 'Invalid directory' unless Dir.exist?(ARGV[0])
raise 'Invalid collection' unless ARGV[1].match(/\w+/)
raise 'OUTLINE_BASE_URI not set' unless ENV.key?('OUTLINE_BASE_URI')
raise 'OUTLINE_TOKEN not set' unless ENV.key?('OUTLINE_TOKEN')
end
def create_documents_recursively(directory, collection_id, parent_document_id=nil)
def create_documents_recursively(directory, collection_id, parent_document_id = nil)
cwd = Dir.pwd
Dir.chdir directory
# Create all documents for this directory
Dir["*.md"].each do |file|
Dir['*.md'].each do |file|
params = {
title: file[0...-3],
text: file[0...-3] + "\n" + File.read(file) + "\n\n---\nImported at #{Time.now}",
text: file[0...-3] +
"\n" +
File.read(file) +
"\n\n---\nImported at #{Time.now}",
collectionId: collection_id,
publish: true
}
@ -30,11 +33,11 @@ def create_documents_recursively(directory, collection_id, parent_document_id=ni
end
# Create child documents for each sub-directory
Dir.glob('*').select {|f| File.directory? f}.each do |dir|
Dir.glob('*').select { |f| File.directory? f }.each do |dir|
puts "[-] #{dir}"
params = {
title: dir,
text: dir +"\nImported at #{Time.now}",
text: dir + "\nImported at #{Time.now}",
collectionId: collection_id,
publish: true,
parentDocumentId: parent_document_id
@ -58,12 +61,11 @@ root_collection_id = CLIENT.find_or_create_collection(remote_collection_name)
begin
create_documents_recursively(local_directory, root_collection_id)
puts "[S] Import successful"
rescue Exception => e
puts '[S] Import successful'
rescue StandardError? => e
# If we fail, print an error, and delete the collection
puts "[E] Import failed with error: #{e.message}"
CLIENT.collections_delete(id: root_collection_id)
puts "[E] Deleted collection, please report the issue or retry"
puts '[E] Deleted collection, please report the issue or retry'
exit 1
end