add support for build tag to allow to disable some features
The following build tags are available: - "nogcs", disable Google Cloud Storage backend - "nos3", disable S3 Compabible Object Storage backends - "nobolt", disable Bolt data provider - "nomysql", disable MySQL data provider - "nopgsql", disable PostgreSQL data provider - "nosqlite", disable SQLite data provider - "noportable", disable portable mode
This commit is contained in:
parent
15298b0409
commit
ad53429cf1
26 changed files with 406 additions and 189 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !noportable
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -14,6 +16,7 @@ import (
|
||||||
"github.com/drakkan/sftpgo/dataprovider"
|
"github.com/drakkan/sftpgo/dataprovider"
|
||||||
"github.com/drakkan/sftpgo/service"
|
"github.com/drakkan/sftpgo/service"
|
||||||
"github.com/drakkan/sftpgo/sftpd"
|
"github.com/drakkan/sftpgo/sftpd"
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
"github.com/drakkan/sftpgo/vfs"
|
"github.com/drakkan/sftpgo/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -138,6 +141,8 @@ Please take a look at the usage below to customize the serving parameters`,
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
utils.AddFeature("+portable")
|
||||||
|
|
||||||
portableCmd.Flags().StringVarP(&directoryToServe, "directory", "d", ".",
|
portableCmd.Flags().StringVarP(&directoryToServe, "directory", "d", ".",
|
||||||
"Path to the directory to serve. This can be an absolute path or a path relative to the current directory")
|
"Path to the directory to serve. This can be an absolute path or a path relative to the current directory")
|
||||||
portableCmd.Flags().IntVarP(&portableSFTPDPort, "sftpd-port", "s", 0, "0 means a random non privileged port")
|
portableCmd.Flags().IntVarP(&portableSFTPDPort, "sftpd-port", "s", 0, "0 means a random non privileged port")
|
||||||
|
|
9
cmd/portable_disabled.go
Normal file
9
cmd/portable_disabled.go
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// +build noportable
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import "github.com/drakkan/sftpgo/utils"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("-portable")
|
||||||
|
}
|
|
@ -63,7 +63,7 @@ func init() {
|
||||||
version := utils.GetAppVersion()
|
version := utils.GetAppVersion()
|
||||||
rootCmd.Flags().BoolP("version", "v", false, "")
|
rootCmd.Flags().BoolP("version", "v", false, "")
|
||||||
rootCmd.Version = version.GetVersionAsString()
|
rootCmd.Version = version.GetVersionAsString()
|
||||||
rootCmd.SetVersionTemplate(`{{printf "SFTPGo version: "}}{{printf "%s" .Version}}
|
rootCmd.SetVersionTemplate(`{{printf "SFTPGo "}}{{printf "%s" .Version}}
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !nobolt
|
||||||
|
|
||||||
package dataprovider
|
package dataprovider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -52,6 +54,10 @@ type compatUserV2 struct {
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("+bolt")
|
||||||
|
}
|
||||||
|
|
||||||
func initializeBoltProvider(basePath string) error {
|
func initializeBoltProvider(basePath string) error {
|
||||||
var err error
|
var err error
|
||||||
logSender = fmt.Sprintf("dataprovider_%v", BoltDataProviderName)
|
logSender = fmt.Sprintf("dataprovider_%v", BoltDataProviderName)
|
||||||
|
|
17
dataprovider/bolt_disabled.go
Normal file
17
dataprovider/bolt_disabled.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// +build nobolt
|
||||||
|
|
||||||
|
package dataprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("-bolt")
|
||||||
|
}
|
||||||
|
|
||||||
|
func initializeBoltProvider(basePath string) error {
|
||||||
|
return errors.New("bolt disabled at build time")
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !nomysql
|
||||||
|
|
||||||
package dataprovider
|
package dataprovider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -6,7 +8,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
// we import go-sql-driver/mysql here to be able to disable MySQL support using a build tag
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
|
||||||
"github.com/drakkan/sftpgo/logger"
|
"github.com/drakkan/sftpgo/logger"
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -28,6 +34,10 @@ type MySQLProvider struct {
|
||||||
dbHandle *sql.DB
|
dbHandle *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("+mysql")
|
||||||
|
}
|
||||||
|
|
||||||
func initializeMySQLProvider() error {
|
func initializeMySQLProvider() error {
|
||||||
var err error
|
var err error
|
||||||
logSender = fmt.Sprintf("dataprovider_%v", MySQLDataProviderName)
|
logSender = fmt.Sprintf("dataprovider_%v", MySQLDataProviderName)
|
||||||
|
|
17
dataprovider/mysql_disabled.go
Normal file
17
dataprovider/mysql_disabled.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// +build nomysql
|
||||||
|
|
||||||
|
package dataprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("-mysql")
|
||||||
|
}
|
||||||
|
|
||||||
|
func initializeMySQLProvider() error {
|
||||||
|
return errors.New("MySQL disabled at build time")
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !nopgsql
|
||||||
|
|
||||||
package dataprovider
|
package dataprovider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -5,7 +7,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
// we import lib/pq here to be able to disable PostgreSQL support using a build tag
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
|
||||||
"github.com/drakkan/sftpgo/logger"
|
"github.com/drakkan/sftpgo/logger"
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -26,6 +32,10 @@ type PGSQLProvider struct {
|
||||||
dbHandle *sql.DB
|
dbHandle *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("+pgsql")
|
||||||
|
}
|
||||||
|
|
||||||
func initializePGSQLProvider() error {
|
func initializePGSQLProvider() error {
|
||||||
var err error
|
var err error
|
||||||
logSender = fmt.Sprintf("dataprovider_%v", PGSQLDataProviderName)
|
logSender = fmt.Sprintf("dataprovider_%v", PGSQLDataProviderName)
|
||||||
|
|
17
dataprovider/pgsql_disabled.go
Normal file
17
dataprovider/pgsql_disabled.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// +build nopgsql
|
||||||
|
|
||||||
|
package dataprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("-pgsql")
|
||||||
|
}
|
||||||
|
|
||||||
|
func initializePGSQLProvider() error {
|
||||||
|
return errors.New("PostgreSQL disabled at build time")
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !nosqlite
|
||||||
|
|
||||||
package dataprovider
|
package dataprovider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -6,6 +8,9 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
// we import go-sqlite3 here to be able to disable SQLite support using a build tag
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
|
||||||
"github.com/drakkan/sftpgo/logger"
|
"github.com/drakkan/sftpgo/logger"
|
||||||
"github.com/drakkan/sftpgo/utils"
|
"github.com/drakkan/sftpgo/utils"
|
||||||
)
|
)
|
||||||
|
@ -41,6 +46,10 @@ type SQLiteProvider struct {
|
||||||
dbHandle *sql.DB
|
dbHandle *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("+sqlite")
|
||||||
|
}
|
||||||
|
|
||||||
func initializeSQLiteProvider(basePath string) error {
|
func initializeSQLiteProvider(basePath string) error {
|
||||||
var err error
|
var err error
|
||||||
var connectionString string
|
var connectionString string
|
||||||
|
|
17
dataprovider/sqlite_disabled.go
Normal file
17
dataprovider/sqlite_disabled.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// +build nosqlite
|
||||||
|
|
||||||
|
package dataprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("-sqlite")
|
||||||
|
}
|
||||||
|
|
||||||
|
func initializeSQLiteProvider(basePath string) error {
|
||||||
|
return errors.New("SQLite disabled at build time")
|
||||||
|
}
|
|
@ -4,19 +4,18 @@ RUN apk add --no-cache git gcc g++ ca-certificates \
|
||||||
&& go get -d github.com/drakkan/sftpgo
|
&& go get -d github.com/drakkan/sftpgo
|
||||||
WORKDIR /go/src/github.com/drakkan/sftpgo
|
WORKDIR /go/src/github.com/drakkan/sftpgo
|
||||||
ARG TAG
|
ARG TAG
|
||||||
|
ARG FEATURES
|
||||||
# Use --build-arg TAG=LATEST for latest tag. Use e.g. --build-arg TAG=0.9.6 for a specific tag/commit. Otherwise HEAD (master) is built.
|
# Use --build-arg TAG=LATEST for latest tag. Use e.g. --build-arg TAG=0.9.6 for a specific tag/commit. Otherwise HEAD (master) is built.
|
||||||
RUN git checkout $(if [ "${TAG}" = LATEST ]; then echo `git rev-list --tags --max-count=1`; elif [ -n "${TAG}" ]; then echo "${TAG}"; else echo HEAD; fi)
|
RUN git checkout $(if [ "${TAG}" = LATEST ]; then echo `git rev-list --tags --max-count=1`; elif [ -n "${TAG}" ]; then echo "${TAG}"; else echo HEAD; fi)
|
||||||
RUN go build -i -ldflags "-s -w -X github.com/drakkan/sftpgo/utils.commit=`git describe --always --dirty` -X github.com/drakkan/sftpgo/utils.date=`date -u +%FT%TZ`" -o /go/bin/sftpgo
|
RUN go build -i $(if [ -n "${FEATURES}" ]; then echo "-tags ${FEATURES}"; fi) -ldflags "-s -w -X github.com/drakkan/sftpgo/utils.commit=`git describe --always --dirty` -X github.com/drakkan/sftpgo/utils.date=`date -u +%FT%TZ`" -o /go/bin/sftpgo
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates su-exec \
|
RUN apk add --no-cache ca-certificates su-exec \
|
||||||
&& mkdir -p /data /etc/sftpgo /srv/sftpgo/config /srv/sftpgo/web /srv/sftpgo/backups
|
&& mkdir -p /data /etc/sftpgo /srv/sftpgo/config /srv/sftpgo/web /srv/sftpgo/backups
|
||||||
|
|
||||||
# ca-certificates is needed for Cloud Storage Support and to expose the REST API over HTTPS.
|
# git and rsync are optional, uncomment the next line to add support for them if needed.
|
||||||
# If you install git then ca-certificates will be automatically installed as dependency.
|
#RUN apk add --no-cache git rsync
|
||||||
# git, rsync and ca-certificates are optional, uncomment the next line to add support for them if needed.
|
|
||||||
#RUN apk add --no-cache git rsync ca-certificates
|
|
||||||
|
|
||||||
COPY --from=builder /go/bin/sftpgo /bin/
|
COPY --from=builder /go/bin/sftpgo /bin/
|
||||||
COPY --from=builder /go/src/github.com/drakkan/sftpgo/sftpgo.json /etc/sftpgo/sftpgo.json
|
COPY --from=builder /go/src/github.com/drakkan/sftpgo/sftpgo.json /etc/sftpgo/sftpgo.json
|
||||||
|
|
|
@ -13,7 +13,10 @@ sudo groupadd -g 1003 sftpgrp && \
|
||||||
|
|
||||||
# Edit sftpgo.json as you need
|
# Edit sftpgo.json as you need
|
||||||
|
|
||||||
# Get and build SFTPGo image (add --build-arg TAG=LATEST to build the latest tag or e.g. TAG=0.9.6 for a specific tag/commit).
|
# Get and build SFTPGo image.
|
||||||
|
# Add --build-arg TAG=LATEST to build the latest tag or e.g. TAG=0.9.6 for a specific tag/commit.
|
||||||
|
# Add --build-arg FEATURES=<features to disable> to disable some feature.
|
||||||
|
# Please take a look at the [build from source](./../../../docs/build-from-source.md) documentation for the complete list of the features that can be disabled.
|
||||||
git clone https://github.com/drakkan/sftpgo.git && \
|
git clone https://github.com/drakkan/sftpgo.git && \
|
||||||
cd sftpgo && \
|
cd sftpgo && \
|
||||||
sudo docker build -t sftpgo docker/sftpgo/alpine/
|
sudo docker build -t sftpgo docker/sftpgo/alpine/
|
||||||
|
|
|
@ -4,16 +4,18 @@ LABEL maintainer="nicola.murino@gmail.com"
|
||||||
RUN go get -d github.com/drakkan/sftpgo
|
RUN go get -d github.com/drakkan/sftpgo
|
||||||
WORKDIR /go/src/github.com/drakkan/sftpgo
|
WORKDIR /go/src/github.com/drakkan/sftpgo
|
||||||
ARG TAG
|
ARG TAG
|
||||||
|
ARG FEATURES
|
||||||
# Use --build-arg TAG=LATEST for latest tag. Use e.g. --build-arg TAG=0.9.6 for a specific tag/commit. Otherwise HEAD (master) is built.
|
# Use --build-arg TAG=LATEST for latest tag. Use e.g. --build-arg TAG=0.9.6 for a specific tag/commit. Otherwise HEAD (master) is built.
|
||||||
RUN git checkout $(if [ "${TAG}" = LATEST ]; then echo `git rev-list --tags --max-count=1`; elif [ -n "${TAG}" ]; then echo "${TAG}"; else echo HEAD; fi)
|
RUN git checkout $(if [ "${TAG}" = LATEST ]; then echo `git rev-list --tags --max-count=1`; elif [ -n "${TAG}" ]; then echo "${TAG}"; else echo HEAD; fi)
|
||||||
RUN go build -i -ldflags "-s -w -X github.com/drakkan/sftpgo/utils.commit=`git describe --always --dirty` -X github.com/drakkan/sftpgo/utils.date=`date -u +%FT%TZ`" -o sftpgo
|
RUN go build -i $(if [ -n "${FEATURES}" ]; then echo "-tags ${FEATURES}"; fi) -ldflags "-s -w -X github.com/drakkan/sftpgo/utils.commit=`git describe --always --dirty` -X github.com/drakkan/sftpgo/utils.date=`date -u +%FT%TZ`" -o sftpgo
|
||||||
|
|
||||||
# now define the run environment
|
# now define the run environment
|
||||||
FROM debian:latest
|
FROM debian:latest
|
||||||
|
|
||||||
# ca-certificates is needed for Cloud Storage Support and to expose the REST API over HTTPS.
|
# ca-certificates is needed for Cloud Storage Support and to expose the REST API over HTTPS.
|
||||||
# If you install git then ca-certificates will be automatically installed as dependency.
|
RUN apt-get update && apt-get install -y ca-certificates
|
||||||
# git, rsync and ca-certificates are optional, uncomment the next line to add support for them if needed.
|
|
||||||
|
# git and rsync are optional, uncomment the next line to add support for them if needed.
|
||||||
#RUN apt-get update && apt-get install -y git rsync ca-certificates
|
#RUN apt-get update && apt-get install -y git rsync ca-certificates
|
||||||
|
|
||||||
ARG BASE_DIR=/app
|
ARG BASE_DIR=/app
|
||||||
|
|
|
@ -8,13 +8,22 @@ You can build the container image using `docker build`, for example:
|
||||||
docker build -t="drakkan/sftpgo" .
|
docker build -t="drakkan/sftpgo" .
|
||||||
```
|
```
|
||||||
|
|
||||||
This will build master of github.com/drakkan/sftpgo. To build the latest tag you can add `--build-arg TAG=LATEST`
|
This will build master of github.com/drakkan/sftpgo.
|
||||||
and to build a specific tag/commit you can use for example `TAG=0.9.6`, like this:
|
|
||||||
|
To build the latest tag you can add `--build-arg TAG=LATEST` and to build a specific tag/commit you can use for example `TAG=0.9.6`, like this:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build -t="drakkan/sftpgo" --build-arg TAG=0.9.6 .
|
docker build -t="drakkan/sftpgo" --build-arg TAG=0.9.6 .
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To disable some features you can add `--build-arg FEATURES=<features to disable>`. For example you can disable SQLite support like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t="drakkan/sftpgo" --build-arg FEATURES=nosqlite .
|
||||||
|
```
|
||||||
|
|
||||||
|
Please take a look at the [build from source](./../../../docs/build-from-source.md) documentation for the complete list of the features that can be disabled.
|
||||||
|
|
||||||
Now create the required folders on the host system, for example:
|
Now create the required folders on the host system, for example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
@ -8,13 +8,23 @@ go get -u github.com/drakkan/sftpgo
|
||||||
|
|
||||||
Make sure [Git](https://git-scm.com/downloads) is installed on your machine and in your system's `PATH`.
|
Make sure [Git](https://git-scm.com/downloads) is installed on your machine and in your system's `PATH`.
|
||||||
|
|
||||||
SFTPGo depends on [go-sqlite3](https://github.com/mattn/go-sqlite3) which is a CGO package and so it requires a `C` compiler at build time.
|
The following build tags are available to disable some features:
|
||||||
|
|
||||||
|
- `nogcs`, disable Google Cloud Storage backend
|
||||||
|
- `nos3`, disable S3 Compabible Object Storage backends
|
||||||
|
- `nobolt`, disable Bolt data provider
|
||||||
|
- `nomysql`, disable MySQL data provider
|
||||||
|
- `nopgsql`, disable PostgreSQL data provider
|
||||||
|
- `nosqlite`, disable SQLite data provider
|
||||||
|
- `noportable`, disable portable mode
|
||||||
|
|
||||||
|
If no build tag is specified all the features will be included.
|
||||||
|
|
||||||
|
The optional [SQLite driver](https://github.com/mattn/go-sqlite3 "go-sqlite3") is a `CGO` package and so it requires a `C` compiler at build time.
|
||||||
On Linux and macOS, a compiler is easy to install or already installed. On Windows, you need to download [MinGW-w64](https://sourceforge.net/projects/mingw-w64/files/) and build SFTPGo from its command prompt.
|
On Linux and macOS, a compiler is easy to install or already installed. On Windows, you need to download [MinGW-w64](https://sourceforge.net/projects/mingw-w64/files/) and build SFTPGo from its command prompt.
|
||||||
|
|
||||||
The compiler is a build time only dependency. It is not required at runtime.
|
The compiler is a build time only dependency. It is not required at runtime.
|
||||||
|
|
||||||
If you don't need SQLite, you can also get/build SFTPGo setting the environment variable `GCO_ENABLED` to 0. This way, SQLite support will be disabled and PostgreSQL, MySQL, bbolt and memory data providers will keep working. In this way, you don't need a `C` compiler for building.
|
|
||||||
|
|
||||||
Version info, such as git commit and build date, can be embedded setting the following string variables at build time:
|
Version info, such as git commit and build date, can be embedded setting the following string variables at build time:
|
||||||
|
|
||||||
- `github.com/drakkan/sftpgo/utils.commit`
|
- `github.com/drakkan/sftpgo/utils.commit`
|
||||||
|
@ -23,12 +33,12 @@ Version info, such as git commit and build date, can be embedded setting the fol
|
||||||
For example, you can build using the following command:
|
For example, you can build using the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go build -i -ldflags "-s -w -X github.com/drakkan/sftpgo/utils.commit=`git describe --always --dirty` -X github.com/drakkan/sftpgo/utils.date=`date -u +%FT%TZ`" -o sftpgo
|
go build -i -tags nogcs,nos3,nosqlite -ldflags "-s -w -X github.com/drakkan/sftpgo/utils.commit=`git describe --always --dirty` -X github.com/drakkan/sftpgo/utils.date=`date -u +%FT%TZ`" -o sftpgo
|
||||||
```
|
```
|
||||||
|
|
||||||
You should get a version that includes git commit and build date like this one:
|
You should get a version that includes git commit, build date and available features like this one:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ sftpgo -v
|
$ ./sftpgo -v
|
||||||
SFTPGo version: 0.9.0-dev-90607d4-dirty-2019-08-08T19:28:36Z
|
SFTPGo 0.9.6-dev-15298b0-dirty-2020-05-22T21:25:51Z -gcs -s3 +bolt +mysql +pgsql -sqlite +portable
|
||||||
```
|
```
|
|
@ -2,7 +2,7 @@ openapi: 3.0.1
|
||||||
info:
|
info:
|
||||||
title: SFTPGo
|
title: SFTPGo
|
||||||
description: 'SFTPGo REST API'
|
description: 'SFTPGo REST API'
|
||||||
version: 1.8.5
|
version: 1.8.6
|
||||||
|
|
||||||
servers:
|
servers:
|
||||||
- url: /api/v1
|
- url: /api/v1
|
||||||
|
@ -1278,6 +1278,11 @@ components:
|
||||||
type: string
|
type: string
|
||||||
commit_hash:
|
commit_hash:
|
||||||
type: string
|
type: string
|
||||||
|
features:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
description: Features for the current build. Available features are "portable", "bolt", "mysql", "sqlite", "pgsql", "s3", "gcs". If a feature is available it has a "+" prefix, otherwise a "-" prefix
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
BasicAuth:
|
BasicAuth:
|
||||||
type: http
|
type: http
|
||||||
|
|
8
main.go
8
main.go
|
@ -3,13 +3,7 @@
|
||||||
// https://github.com/drakkan/sftpgo/blob/master/README.md
|
// https://github.com/drakkan/sftpgo/blob/master/README.md
|
||||||
package main // import "github.com/drakkan/sftpgo"
|
package main // import "github.com/drakkan/sftpgo"
|
||||||
|
|
||||||
import (
|
import "github.com/drakkan/sftpgo/cmd"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
|
||||||
_ "github.com/lib/pq"
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
|
||||||
|
|
||||||
"github.com/drakkan/sftpgo/cmd"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cmd.Execute()
|
cmd.Execute()
|
||||||
|
|
|
@ -2,16 +2,8 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/grandcat/zeroconf"
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
|
||||||
"github.com/drakkan/sftpgo/config"
|
"github.com/drakkan/sftpgo/config"
|
||||||
|
@ -141,107 +133,3 @@ func (s *Service) Stop() {
|
||||||
close(s.Shutdown)
|
close(s.Shutdown)
|
||||||
logger.Debug(logSender, "", "Service stopped")
|
logger.Debug(logSender, "", "Service stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartPortableMode starts the service in portable mode
|
|
||||||
func (s *Service) StartPortableMode(sftpdPort int, enabledSSHCommands []string, advertiseService, advertiseCredentials bool) error {
|
|
||||||
if s.PortableMode != 1 {
|
|
||||||
return fmt.Errorf("service is not configured for portable mode")
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
if len(s.PortableUser.Username) == 0 {
|
|
||||||
s.PortableUser.Username = "user"
|
|
||||||
}
|
|
||||||
if len(s.PortableUser.PublicKeys) == 0 && len(s.PortableUser.Password) == 0 {
|
|
||||||
var b strings.Builder
|
|
||||||
for i := 0; i < 8; i++ {
|
|
||||||
b.WriteRune(chars[rand.Intn(len(chars))])
|
|
||||||
}
|
|
||||||
s.PortableUser.Password = b.String()
|
|
||||||
}
|
|
||||||
dataProviderConf := config.GetProviderConf()
|
|
||||||
dataProviderConf.Driver = dataprovider.MemoryDataProviderName
|
|
||||||
dataProviderConf.Name = ""
|
|
||||||
dataProviderConf.CredentialsPath = filepath.Join(os.TempDir(), "credentials")
|
|
||||||
config.SetProviderConf(dataProviderConf)
|
|
||||||
httpdConf := config.GetHTTPDConfig()
|
|
||||||
httpdConf.BindPort = 0
|
|
||||||
config.SetHTTPDConfig(httpdConf)
|
|
||||||
sftpdConf := config.GetSFTPDConfig()
|
|
||||||
sftpdConf.MaxAuthTries = 12
|
|
||||||
if sftpdPort > 0 {
|
|
||||||
sftpdConf.BindPort = sftpdPort
|
|
||||||
} else {
|
|
||||||
// dynamic ports starts from 49152
|
|
||||||
sftpdConf.BindPort = 49152 + rand.Intn(15000)
|
|
||||||
}
|
|
||||||
if utils.IsStringInSlice("*", enabledSSHCommands) {
|
|
||||||
sftpdConf.EnabledSSHCommands = sftpd.GetSupportedSSHCommands()
|
|
||||||
} else {
|
|
||||||
sftpdConf.EnabledSSHCommands = enabledSSHCommands
|
|
||||||
}
|
|
||||||
config.SetSFTPDConfig(sftpdConf)
|
|
||||||
|
|
||||||
err = s.Start()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var mDNSService *zeroconf.Server
|
|
||||||
if advertiseService {
|
|
||||||
version := utils.GetAppVersion()
|
|
||||||
meta := []string{
|
|
||||||
fmt.Sprintf("version=%v", version.GetVersionAsString()),
|
|
||||||
}
|
|
||||||
if advertiseCredentials {
|
|
||||||
logger.InfoToConsole("Advertising credentials via multicast DNS")
|
|
||||||
meta = append(meta, fmt.Sprintf("user=%v", s.PortableUser.Username))
|
|
||||||
if len(s.PortableUser.Password) > 0 {
|
|
||||||
meta = append(meta, fmt.Sprintf("password=%v", s.PortableUser.Password))
|
|
||||||
} else {
|
|
||||||
logger.InfoToConsole("Unable to advertise key based credentials via multicast DNS, we don't have the private key")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mDNSService, err = zeroconf.Register(
|
|
||||||
fmt.Sprintf("SFTPGo portable %v", sftpdConf.BindPort), // service instance name
|
|
||||||
"_sftp-ssh._tcp", // service type and protocol
|
|
||||||
"local.", // service domain
|
|
||||||
sftpdConf.BindPort, // service port
|
|
||||||
meta, // service metadata
|
|
||||||
nil, // register on all network interfaces
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
mDNSService = nil
|
|
||||||
logger.WarnToConsole("Unable to advertise SFTP service via multicast DNS: %v", err)
|
|
||||||
} else {
|
|
||||||
logger.InfoToConsole("SFTP service advertised via multicast DNS")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sig := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
|
|
||||||
go func() {
|
|
||||||
<-sig
|
|
||||||
if mDNSService != nil {
|
|
||||||
logger.InfoToConsole("unregistering multicast DNS service")
|
|
||||||
mDNSService.Shutdown()
|
|
||||||
}
|
|
||||||
s.Stop()
|
|
||||||
}()
|
|
||||||
|
|
||||||
logger.InfoToConsole("Portable mode ready, SFTP port: %v, user: %#v, password: %#v, public keys: %v, directory: %#v, "+
|
|
||||||
"permissions: %+v, enabled ssh commands: %v file extensions filters: %+v", sftpdConf.BindPort, s.PortableUser.Username,
|
|
||||||
s.PortableUser.Password, s.PortableUser.PublicKeys, s.getPortableDirToServe(), s.PortableUser.Permissions,
|
|
||||||
sftpdConf.EnabledSSHCommands, s.PortableUser.Filters.FileExtensions)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) getPortableDirToServe() string {
|
|
||||||
var dirToServe string
|
|
||||||
if s.PortableUser.FsConfig.Provider == 1 {
|
|
||||||
dirToServe = s.PortableUser.FsConfig.S3Config.KeyPrefix
|
|
||||||
} else if s.PortableUser.FsConfig.Provider == 2 {
|
|
||||||
dirToServe = s.PortableUser.FsConfig.GCSConfig.KeyPrefix
|
|
||||||
} else {
|
|
||||||
dirToServe = s.PortableUser.HomeDir
|
|
||||||
}
|
|
||||||
return dirToServe
|
|
||||||
}
|
|
||||||
|
|
126
service/service_portable.go
Normal file
126
service/service_portable.go
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
// +build !noportable
|
||||||
|
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grandcat/zeroconf"
|
||||||
|
|
||||||
|
"github.com/drakkan/sftpgo/config"
|
||||||
|
"github.com/drakkan/sftpgo/dataprovider"
|
||||||
|
"github.com/drakkan/sftpgo/logger"
|
||||||
|
"github.com/drakkan/sftpgo/sftpd"
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StartPortableMode starts the service in portable mode
|
||||||
|
func (s *Service) StartPortableMode(sftpdPort int, enabledSSHCommands []string, advertiseService, advertiseCredentials bool) error {
|
||||||
|
if s.PortableMode != 1 {
|
||||||
|
return fmt.Errorf("service is not configured for portable mode")
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
if len(s.PortableUser.Username) == 0 {
|
||||||
|
s.PortableUser.Username = "user"
|
||||||
|
}
|
||||||
|
if len(s.PortableUser.PublicKeys) == 0 && len(s.PortableUser.Password) == 0 {
|
||||||
|
var b strings.Builder
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
b.WriteRune(chars[rand.Intn(len(chars))])
|
||||||
|
}
|
||||||
|
s.PortableUser.Password = b.String()
|
||||||
|
}
|
||||||
|
dataProviderConf := config.GetProviderConf()
|
||||||
|
dataProviderConf.Driver = dataprovider.MemoryDataProviderName
|
||||||
|
dataProviderConf.Name = ""
|
||||||
|
dataProviderConf.CredentialsPath = filepath.Join(os.TempDir(), "credentials")
|
||||||
|
config.SetProviderConf(dataProviderConf)
|
||||||
|
httpdConf := config.GetHTTPDConfig()
|
||||||
|
httpdConf.BindPort = 0
|
||||||
|
config.SetHTTPDConfig(httpdConf)
|
||||||
|
sftpdConf := config.GetSFTPDConfig()
|
||||||
|
sftpdConf.MaxAuthTries = 12
|
||||||
|
if sftpdPort > 0 {
|
||||||
|
sftpdConf.BindPort = sftpdPort
|
||||||
|
} else {
|
||||||
|
// dynamic ports starts from 49152
|
||||||
|
sftpdConf.BindPort = 49152 + rand.Intn(15000)
|
||||||
|
}
|
||||||
|
if utils.IsStringInSlice("*", enabledSSHCommands) {
|
||||||
|
sftpdConf.EnabledSSHCommands = sftpd.GetSupportedSSHCommands()
|
||||||
|
} else {
|
||||||
|
sftpdConf.EnabledSSHCommands = enabledSSHCommands
|
||||||
|
}
|
||||||
|
config.SetSFTPDConfig(sftpdConf)
|
||||||
|
|
||||||
|
err = s.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var mDNSService *zeroconf.Server
|
||||||
|
if advertiseService {
|
||||||
|
version := utils.GetAppVersion()
|
||||||
|
meta := []string{
|
||||||
|
fmt.Sprintf("version=%v", version.GetVersionAsString()),
|
||||||
|
}
|
||||||
|
if advertiseCredentials {
|
||||||
|
logger.InfoToConsole("Advertising credentials via multicast DNS")
|
||||||
|
meta = append(meta, fmt.Sprintf("user=%v", s.PortableUser.Username))
|
||||||
|
if len(s.PortableUser.Password) > 0 {
|
||||||
|
meta = append(meta, fmt.Sprintf("password=%v", s.PortableUser.Password))
|
||||||
|
} else {
|
||||||
|
logger.InfoToConsole("Unable to advertise key based credentials via multicast DNS, we don't have the private key")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDNSService, err = zeroconf.Register(
|
||||||
|
fmt.Sprintf("SFTPGo portable %v", sftpdConf.BindPort), // service instance name
|
||||||
|
"_sftp-ssh._tcp", // service type and protocol
|
||||||
|
"local.", // service domain
|
||||||
|
sftpdConf.BindPort, // service port
|
||||||
|
meta, // service metadata
|
||||||
|
nil, // register on all network interfaces
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
mDNSService = nil
|
||||||
|
logger.WarnToConsole("Unable to advertise SFTP service via multicast DNS: %v", err)
|
||||||
|
} else {
|
||||||
|
logger.InfoToConsole("SFTP service advertised via multicast DNS")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sig := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-sig
|
||||||
|
if mDNSService != nil {
|
||||||
|
logger.InfoToConsole("unregistering multicast DNS service")
|
||||||
|
mDNSService.Shutdown()
|
||||||
|
}
|
||||||
|
s.Stop()
|
||||||
|
}()
|
||||||
|
|
||||||
|
logger.InfoToConsole("Portable mode ready, SFTP port: %v, user: %#v, password: %#v, public keys: %v, directory: %#v, "+
|
||||||
|
"permissions: %+v, enabled ssh commands: %v file extensions filters: %+v", sftpdConf.BindPort, s.PortableUser.Username,
|
||||||
|
s.PortableUser.Password, s.PortableUser.PublicKeys, s.getPortableDirToServe(), s.PortableUser.Permissions,
|
||||||
|
sftpdConf.EnabledSSHCommands, s.PortableUser.Filters.FileExtensions)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) getPortableDirToServe() string {
|
||||||
|
var dirToServe string
|
||||||
|
if s.PortableUser.FsConfig.Provider == 1 {
|
||||||
|
dirToServe = s.PortableUser.FsConfig.S3Config.KeyPrefix
|
||||||
|
} else if s.PortableUser.FsConfig.Provider == 2 {
|
||||||
|
dirToServe = s.PortableUser.FsConfig.GCSConfig.KeyPrefix
|
||||||
|
} else {
|
||||||
|
dirToServe = s.PortableUser.HomeDir
|
||||||
|
}
|
||||||
|
return dirToServe
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
const version = "0.9.6-dev"
|
const version = "0.9.6-dev"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -10,21 +12,34 @@ var (
|
||||||
|
|
||||||
// VersionInfo defines version details
|
// VersionInfo defines version details
|
||||||
type VersionInfo struct {
|
type VersionInfo struct {
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
BuildDate string `json:"build_date"`
|
BuildDate string `json:"build_date"`
|
||||||
CommitHash string `json:"commit_hash"`
|
CommitHash string `json:"commit_hash"`
|
||||||
|
Features []string `json:"features"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVersionAsString returns the string representation of the VersionInfo struct
|
// GetVersionAsString returns the string representation of the VersionInfo struct
|
||||||
func (v *VersionInfo) GetVersionAsString() string {
|
func (v *VersionInfo) GetVersionAsString() string {
|
||||||
versionString := v.Version
|
var sb strings.Builder
|
||||||
|
sb.WriteString(v.Version)
|
||||||
if len(v.CommitHash) > 0 {
|
if len(v.CommitHash) > 0 {
|
||||||
versionString += "-" + v.CommitHash
|
sb.WriteString("-")
|
||||||
|
sb.WriteString(v.CommitHash)
|
||||||
}
|
}
|
||||||
if len(v.BuildDate) > 0 {
|
if len(v.BuildDate) > 0 {
|
||||||
versionString += "-" + v.BuildDate
|
sb.WriteString("-")
|
||||||
|
sb.WriteString(v.BuildDate)
|
||||||
}
|
}
|
||||||
return versionString
|
if len(v.Features) > 0 {
|
||||||
|
sb.WriteString(" ")
|
||||||
|
sb.WriteString(strings.Join(v.Features, " "))
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFeature adds a feature description
|
||||||
|
func AddFeature(feature string) {
|
||||||
|
versionInfo.Features = append(versionInfo.Features, feature)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
23
vfs/gcsfs.go
23
vfs/gcsfs.go
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !nogcs
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -19,6 +21,7 @@ import (
|
||||||
|
|
||||||
"github.com/drakkan/sftpgo/logger"
|
"github.com/drakkan/sftpgo/logger"
|
||||||
"github.com/drakkan/sftpgo/metrics"
|
"github.com/drakkan/sftpgo/metrics"
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -27,22 +30,6 @@ var (
|
||||||
gcsDefaultFieldsSelection = []string{"Name", "Size", "Deleted", "Updated"}
|
gcsDefaultFieldsSelection = []string{"Name", "Size", "Deleted", "Updated"}
|
||||||
)
|
)
|
||||||
|
|
||||||
// GCSFsConfig defines the configuration for Google Cloud Storage based filesystem
|
|
||||||
type GCSFsConfig struct {
|
|
||||||
Bucket string `json:"bucket,omitempty"`
|
|
||||||
// KeyPrefix is similar to a chroot directory for local filesystem.
|
|
||||||
// If specified the SFTP user will only see objects that starts with
|
|
||||||
// this prefix and so you can restrict access to a specific virtual
|
|
||||||
// folder. The prefix, if not empty, must not start with "/" and must
|
|
||||||
// end with "/".
|
|
||||||
// If empty the whole bucket contents will be available
|
|
||||||
KeyPrefix string `json:"key_prefix,omitempty"`
|
|
||||||
CredentialFile string `json:"-"`
|
|
||||||
Credentials string `json:"credentials,omitempty"`
|
|
||||||
AutomaticCredentials int `json:"automatic_credentials,omitempty"`
|
|
||||||
StorageClass string `json:"storage_class,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GCSFs is a Fs implementation for Google Cloud Storage.
|
// GCSFs is a Fs implementation for Google Cloud Storage.
|
||||||
type GCSFs struct {
|
type GCSFs struct {
|
||||||
connectionID string
|
connectionID string
|
||||||
|
@ -53,6 +40,10 @@ type GCSFs struct {
|
||||||
ctxLongTimeout time.Duration
|
ctxLongTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("+gcs")
|
||||||
|
}
|
||||||
|
|
||||||
// NewGCSFs returns an GCSFs object that allows to interact with Google Cloud Storage
|
// NewGCSFs returns an GCSFs object that allows to interact with Google Cloud Storage
|
||||||
func NewGCSFs(connectionID, localTempDir string, config GCSFsConfig) (Fs, error) {
|
func NewGCSFs(connectionID, localTempDir string, config GCSFsConfig) (Fs, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
18
vfs/gcsfs_disabled.go
Normal file
18
vfs/gcsfs_disabled.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// +build nogcs
|
||||||
|
|
||||||
|
package vfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("-gcs")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGCSFs returns an error, GCS is disabled
|
||||||
|
func NewGCSFs(connectionID, localTempDir string, config GCSFsConfig) (Fs, error) {
|
||||||
|
return nil, errors.New("Google Cloud Storage disabled at build time")
|
||||||
|
}
|
33
vfs/s3fs.go
33
vfs/s3fs.go
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !nos3
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -22,33 +24,6 @@ import (
|
||||||
"github.com/drakkan/sftpgo/utils"
|
"github.com/drakkan/sftpgo/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// S3FsConfig defines the configuration for S3 based filesystem
|
|
||||||
type S3FsConfig struct {
|
|
||||||
Bucket string `json:"bucket,omitempty"`
|
|
||||||
// KeyPrefix is similar to a chroot directory for local filesystem.
|
|
||||||
// If specified the SFTP user will only see objects that starts with
|
|
||||||
// this prefix and so you can restrict access to a specific virtual
|
|
||||||
// folder. The prefix, if not empty, must not start with "/" and must
|
|
||||||
// end with "/".
|
|
||||||
// If empty the whole bucket contents will be available
|
|
||||||
KeyPrefix string `json:"key_prefix,omitempty"`
|
|
||||||
Region string `json:"region,omitempty"`
|
|
||||||
AccessKey string `json:"access_key,omitempty"`
|
|
||||||
AccessSecret string `json:"access_secret,omitempty"`
|
|
||||||
Endpoint string `json:"endpoint,omitempty"`
|
|
||||||
StorageClass string `json:"storage_class,omitempty"`
|
|
||||||
// The buffer size (in MB) to use for multipart uploads. The minimum allowed part size is 5MB,
|
|
||||||
// and if this value is set to zero, the default value (5MB) for the AWS SDK will be used.
|
|
||||||
// The minimum allowed value is 5.
|
|
||||||
// Please note that if the upload bandwidth between the SFTP client and SFTPGo is greater than
|
|
||||||
// the upload bandwidth between SFTPGo and S3 then the SFTP client have to wait for the upload
|
|
||||||
// of the last parts to S3 after it ends the file upload to SFTPGo, and it may time out.
|
|
||||||
// Keep this in mind if you customize these parameters.
|
|
||||||
UploadPartSize int64 `json:"upload_part_size,omitempty"`
|
|
||||||
// How many parts are uploaded in parallel
|
|
||||||
UploadConcurrency int `json:"upload_concurrency,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// S3Fs is a Fs implementation for Amazon S3 compatible object storage.
|
// S3Fs is a Fs implementation for Amazon S3 compatible object storage.
|
||||||
type S3Fs struct {
|
type S3Fs struct {
|
||||||
connectionID string
|
connectionID string
|
||||||
|
@ -59,6 +34,10 @@ type S3Fs struct {
|
||||||
ctxLongTimeout time.Duration
|
ctxLongTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("+s3")
|
||||||
|
}
|
||||||
|
|
||||||
// NewS3Fs returns an S3Fs object that allows to interact with an s3 compatible
|
// NewS3Fs returns an S3Fs object that allows to interact with an s3 compatible
|
||||||
// object storage
|
// object storage
|
||||||
func NewS3Fs(connectionID, localTempDir string, config S3FsConfig) (Fs, error) {
|
func NewS3Fs(connectionID, localTempDir string, config S3FsConfig) (Fs, error) {
|
||||||
|
|
18
vfs/s3fs_disabled.go
Normal file
18
vfs/s3fs_disabled.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// +build nos3
|
||||||
|
|
||||||
|
package vfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/drakkan/sftpgo/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.AddFeature("-s3")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewS3Fs returns an error, S3 is disabled
|
||||||
|
func NewS3Fs(connectionID, localTempDir string, config S3FsConfig) (Fs, error) {
|
||||||
|
return nil, errors.New("S3 disabled at build time")
|
||||||
|
}
|
43
vfs/vfs.go
43
vfs/vfs.go
|
@ -44,6 +44,49 @@ type Fs interface {
|
||||||
Join(elem ...string) string
|
Join(elem ...string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// S3FsConfig defines the configuration for S3 based filesystem
|
||||||
|
type S3FsConfig struct {
|
||||||
|
Bucket string `json:"bucket,omitempty"`
|
||||||
|
// KeyPrefix is similar to a chroot directory for local filesystem.
|
||||||
|
// If specified the SFTP user will only see objects that starts with
|
||||||
|
// this prefix and so you can restrict access to a specific virtual
|
||||||
|
// folder. The prefix, if not empty, must not start with "/" and must
|
||||||
|
// end with "/".
|
||||||
|
// If empty the whole bucket contents will be available
|
||||||
|
KeyPrefix string `json:"key_prefix,omitempty"`
|
||||||
|
Region string `json:"region,omitempty"`
|
||||||
|
AccessKey string `json:"access_key,omitempty"`
|
||||||
|
AccessSecret string `json:"access_secret,omitempty"`
|
||||||
|
Endpoint string `json:"endpoint,omitempty"`
|
||||||
|
StorageClass string `json:"storage_class,omitempty"`
|
||||||
|
// The buffer size (in MB) to use for multipart uploads. The minimum allowed part size is 5MB,
|
||||||
|
// and if this value is set to zero, the default value (5MB) for the AWS SDK will be used.
|
||||||
|
// The minimum allowed value is 5.
|
||||||
|
// Please note that if the upload bandwidth between the SFTP client and SFTPGo is greater than
|
||||||
|
// the upload bandwidth between SFTPGo and S3 then the SFTP client have to wait for the upload
|
||||||
|
// of the last parts to S3 after it ends the file upload to SFTPGo, and it may time out.
|
||||||
|
// Keep this in mind if you customize these parameters.
|
||||||
|
UploadPartSize int64 `json:"upload_part_size,omitempty"`
|
||||||
|
// How many parts are uploaded in parallel
|
||||||
|
UploadConcurrency int `json:"upload_concurrency,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GCSFsConfig defines the configuration for Google Cloud Storage based filesystem
|
||||||
|
type GCSFsConfig struct {
|
||||||
|
Bucket string `json:"bucket,omitempty"`
|
||||||
|
// KeyPrefix is similar to a chroot directory for local filesystem.
|
||||||
|
// If specified the SFTP user will only see objects that starts with
|
||||||
|
// this prefix and so you can restrict access to a specific virtual
|
||||||
|
// folder. The prefix, if not empty, must not start with "/" and must
|
||||||
|
// end with "/".
|
||||||
|
// If empty the whole bucket contents will be available
|
||||||
|
KeyPrefix string `json:"key_prefix,omitempty"`
|
||||||
|
CredentialFile string `json:"-"`
|
||||||
|
Credentials string `json:"credentials,omitempty"`
|
||||||
|
AutomaticCredentials int `json:"automatic_credentials,omitempty"`
|
||||||
|
StorageClass string `json:"storage_class,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// PipeWriter defines a wrapper for pipeat.PipeWriterAt.
|
// PipeWriter defines a wrapper for pipeat.PipeWriterAt.
|
||||||
type PipeWriter struct {
|
type PipeWriter struct {
|
||||||
writer *pipeat.PipeWriterAt
|
writer *pipeat.PipeWriterAt
|
||||||
|
|
Loading…
Reference in a new issue