Skip to content

Commit 6bc3c3b

Browse files
Resolve DEV-46 "Implement lbnl sftp handler"
1 parent 5621877 commit 6bc3c3b

25 files changed

Lines changed: 554 additions & 295 deletions

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# secrets file
22
.env
33

4+
# rubocop creates this
5+
.cache
6+
7+
.*_history
8+
49
vendor
510
.bundle
611

.rubocop.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ AllCops:
55
- 'bin/**/*'
66
- 'db/**/*'
77
- 'out/**/*'
8+
- 'spec/**/*'
89

910
# Allow one line around block body (Layout/EmptyLines will still disallow two or more)
1011
Layout/EmptyLinesAroundBlockBody:
@@ -34,6 +35,9 @@ Lint/SuppressedException:
3435
Layout:
3536
Max: 150
3637

38+
Metrics/MethodLength:
39+
Max: 50
40+
3741
# Confusing and weird
3842
Naming/VariableNumber:
3943
Enabled: False

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ USER $APP_USER
3636

3737
# Uses the get_gobi script as the entrypoint, so any arguments passed to `docker run`
3838
# at invocation are passed directly to this script.
39-
ENTRYPOINT ["ruby","/opt/app/lib/get_gobi.rb"]
39+
ENTRYPOINT ["/opt/app/bin/berkeley_library-sftp_handler.rb"]
4040

4141
# =============================================================================
4242
# Target: development

Gemfile

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
source 'https://rubygems.org'
22

3-
gem 'colorize'
4-
gem 'erb'
5-
gem 'getoptlong'
3+
gem 'chronic', '~> 0.10.2'
64
gem 'net-sftp'
7-
gem 'rspec'
8-
gem 'rspec_junit_formatter'
9-
gem 'rubocop', require: false
10-
gem 'rubocop-checkstyle_formatter', require: false
115
gem 'thor', '~> 1.1'
12-
gem 'uri'
13-
gem 'webmock'
6+
7+
group :test do
8+
gem 'colorize'
9+
gem 'rspec'
10+
gem 'rspec-its', '~> 1.3'
11+
gem 'rspec_junit_formatter'
12+
gem 'rubocop', require: false
13+
gem 'rubocop-checkstyle_formatter', require: false
14+
gem 'timecop', '~> 0.9.5'
15+
gem 'webmock'
16+
end

Gemfile.lock

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@ GEM
44
addressable (2.8.0)
55
public_suffix (>= 2.0.2, < 5.0)
66
ast (2.4.2)
7-
cgi (0.3.2)
7+
chronic (0.10.2)
88
colorize (0.8.1)
99
crack (0.4.5)
1010
rexml
1111
diff-lcs (1.5.0)
12-
erb (2.2.3)
13-
cgi
14-
getoptlong (0.1.1)
1512
hashdiff (1.0.1)
1613
net-sftp (3.0.0)
1714
net-ssh (>= 5.0.0, < 7.0.0)
@@ -32,6 +29,9 @@ GEM
3229
rspec-expectations (3.11.0)
3330
diff-lcs (>= 1.2.0, < 2.0)
3431
rspec-support (~> 3.11.0)
32+
rspec-its (1.3.0)
33+
rspec-core (>= 3.0.0)
34+
rspec-expectations (>= 3.0.0)
3535
rspec-mocks (3.11.0)
3636
diff-lcs (>= 1.2.0, < 2.0)
3737
rspec-support (~> 3.11.0)
@@ -53,8 +53,8 @@ GEM
5353
rubocop (>= 1.14.0)
5454
ruby-progressbar (1.11.0)
5555
thor (1.2.1)
56+
timecop (0.9.5)
5657
unicode-display_width (2.1.0)
57-
uri (0.11.0)
5858
webmock (3.14.0)
5959
addressable (>= 2.8.0)
6060
crack (>= 0.3.2)
@@ -64,16 +64,16 @@ PLATFORMS
6464
x86_64-linux
6565

6666
DEPENDENCIES
67+
chronic (~> 0.10.2)
6768
colorize
68-
erb
69-
getoptlong
7069
net-sftp
7170
rspec
71+
rspec-its (~> 1.3)
7272
rspec_junit_formatter
7373
rubocop
7474
rubocop-checkstyle_formatter
7575
thor (~> 1.1)
76-
uri
76+
timecop (~> 0.9.5)
7777
webmock
7878

7979
BUNDLED WITH

Jenkinsfile

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ dockerComposePipeline(
22
commands: [
33
[
44
[run: 'rspec', entrypoint: '/bin/sh -c'],
5-
[run: 'rubocop', entrypoint: '/bin/sh -c'],
5+
[run: 'rubocop', entrypoint: '/bin/sh -c'],
66
]
77
],
88
artifacts: [
9-
junit : 'artifacts/rspec/*.xml',
10-
html : [
11-
'RuboCop' : 'artifacts/rubocop',
9+
junit: 'artifacts/rspec/*.xml',
10+
html: [
11+
Rubocop: 'artifacts/rubocop',
1212
],
1313
]
1414
)
15-

README.md

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,58 @@
1-
# GOBI Processor
1+
# SFTP Handler
22

3-
A command-line tool for retrieving GOBI order marc files (.ord) via sftp.
3+
A command-line tool for SFTP-ing files from different providers. Currently supports LBNL patron files and Gobi E-Order files.
44

5-
## Running it locally
5+
## Getting started
66

7-
To run the application for real, you'll need to configure a local `.env` file with the GOBI password, which you can obtain from LastPass (search for "gobi"). Don't worry: this file is git-ignored.
8-
9-
```ini
10-
# ./.env (in the directory you cloned this from GitLab)
11-
GOBI_PASS=password-from-lastpass
12-
```
13-
14-
---
15-
16-
> **Additional Configuration:** The app accepts a few other configuration options, which you can see in `config/connections.yml`. The default values should work fine, however, so you probably don't need to change them. Also note that everything is mocked in the rspec tests, where you're not actually hitting the GOBI server.
17-
18-
---
19-
20-
With that configured, you can run the application like so:
21-
22-
```sh
23-
docker compose build # as always, you need to build it first
24-
docker compose run --rm app ebook0413.ord
25-
```
26-
27-
Today's GOBI order file will be at `/gobiord/eboo{mmdd}.ord` on their server. By default, the app copies it into the `/opt/app/data` directory within the container (mapped to `./data` in development), but this can be overwritten by the `--local_dir` flag:
7+
The application is dockerized, so for starters, just build it:
288

299
```sh
30-
docker compose run --rm app --local_dir /path/in/container
10+
docker compose build
3111
```
3212

33-
Look for a specific file by passing its name as an argument:
34-
35-
```sh
36-
docker-compose run --rm app ebook0413.ord
37-
```
13+
Besides that, it's a fairly standard Ruby library:
14+
- [Thor](https://github.com/rails/thor) for the CLI
15+
- RSpec for testing (along with a few RSpec plugins)
3816

39-
You can also pass additional arguments when looking for a specific file:
17+
The `bin/berkeley_library-sftp_handler.rb` script is the container's entrypoint, so you can run it ad-hoc like so:
4018

4119
```sh
42-
docker-compose run --rm app ebook0413.ord \
43-
--remote_dir gobiord-staging \
44-
--local_dir path_to_local_dir
20+
# view help docs
21+
docker compose run --rm app help
22+
docker compose run --rm app help gobi
23+
docker compose run --rm app help lbnl
24+
25+
# run the gobi loader
26+
docker compose run --rm app gobi
27+
docker compose run --rm app gobi --filename specific-file.ord
28+
29+
# run the lbnl loader
30+
docker compose run --rm app lbnl
31+
docker compose run --rm app lbnl --filename specific-file.zip
4532
```
4633

47-
## Testing
34+
By default, files are downloaded to `./data`. You can override this with the `--local-dir` option. See the specific help output or the [CLI class](lib/berkeley_library/sftp_handler/cli.rb) for details.
4835

49-
The app includes a number of RSpec tests integrated into its Jenkins pipeline. You can run the tests locally via:
36+
Open a shell (e.g. to run tests) by overriding the entrypoint:
5037

5138
```sh
52-
docker compose run --rm --entrypoint=rspec app
39+
docker compose run --rm --entrypoint bash app
5340
```
5441

55-
Or by shelling into the container and running RSpec from there:
42+
### Secrets and .env
5643

57-
```sh
58-
docker compose run --rm --entrypoint=sh app
59-
rspec
60-
```
44+
SSH passwords and key data should be stored in the .env file. This file is git-ignored, so don't worry about it being committed. The contents of different secrets will be shared with you via LastPass; just ask for it in Slack.
6145

62-
---
46+
```ini
47+
LIT_GOBI_PASSWORD="the-password"
48+
LIT_LBNL_KEY_DATA="-----BEGIN RSA PRIVATE KEY-----
49+
...
50+
-----END RSA PRIVATE KEY-----"
51+
```
6352

64-
> **Insecure KEX:** As of 04/28/22, Gobi's server only supports outdated Diffie-Hellman key exchange algorithms, which you local sftp client will probably (and correctly) refuse. If you want to test manually, then for now you must explicitly allow the old algorithm by passing the following option to your sftp client: `-oKexAlgorithms=+diffie-hellman-group1-sha1`.
53+
## Adding new downloaders
6554

66-
---
55+
To add a new downloader, create a class under BerkeleyLibrary::SftpHandler::Downloader, inherit from Downloader::Base, and implement the `download!` method. Then, integrate it into the CLI by adding a new method to BerkeleyLibrary::SftpHandler::Cli. See the existing examples for Lbnl and Gobi for more guidance.
6756

6857
## Production configuration
6958

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env ruby
2+
3+
File.join(File.expand_path('..', __dir__), 'lib').tap do |lib|
4+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5+
end
6+
7+
require 'docker'
8+
Docker::Secret.setup_environment!
9+
10+
require 'berkeley_library/sftp_handler'
11+
12+
BerkeleyLibrary::SftpHandler::Cli.start(ARGV)

config/connections.yml

Lines changed: 0 additions & 4 deletions
This file was deleted.

docker-compose.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ services:
44
context: .
55
target: development
66
environment:
7-
GOBI_PASS: "${GOBI_PASS}"
7+
LIT_GOBI_PASSWORD: "${LIT_GOBI_PASSWORD}"
8+
LIT_LBNL_KEY_DATA: "${LIT_LBNL_KEY_DATA}"
89
image: containers.lib.berkeley.edu/lap/gobi_sftp/development:latest
910
init: yes
1011
volumes:

0 commit comments

Comments
 (0)