Compare commits

...

7 Commits

Author SHA1 Message Date
Christian Schwarz 30057d4e59 build: fix warning for cached builds with Go 1.10 2018-04-01 17:53:51 +02:00
Christian Schwarz 75fd21e454 make generate: stringer was updated and now uses strconv instead of fmt
https://github.com/golang/tools/commit/bd4635fd25596cdd56c1fb399c53b351d1a81f2d#diff-0415b5286e4cf3e373f349d917e5e039
2018-04-01 15:30:04 +02:00
Christian Schwarz 0d2f73d728 docs: tutorial: minor refinements 2018-04-01 14:58:12 +02:00
Christian Schwarz 9b803aad2d docs: tutorial: document known_hosts file setup
fixes #64
2018-04-01 14:58:04 +02:00
Christian Schwarz fb74addc1e bump go-rwccmd to support ssh error messages
this is a follow-up to ccd062e

fixes #65
2018-04-01 14:34:05 +02:00
Christian Schwarz 7f89372cfa docs: fix enumeration in ssh+stdinserver docs 2018-03-04 17:20:08 +01:00
Christian Schwarz 26b436463d ssh+stdinserver: connect: dial_timeout
This  is a follow-up to ccd062e
2018-03-04 17:19:41 +01:00
11 changed files with 55 additions and 18 deletions
Generated
+1 -1
View File
@@ -83,7 +83,7 @@
branch = "master" branch = "master"
name = "github.com/problame/go-netssh" name = "github.com/problame/go-netssh"
packages = ["."] packages = ["."]
revision = "ffa145d2506e222977205e7666a9722d6b9959ac" revision = "53a2e445f8ace7ec678f2d8cdd9c1428dfef4562"
[[projects]] [[projects]]
branch = "master" branch = "master"
+1
View File
@@ -11,6 +11,7 @@ RUN /tmp/lazy.sh devsetup
# prepare volume mount of git checkout to /zrepl # prepare volume mount of git checkout to /zrepl
RUN mkdir -p /go/src/github.com/zrepl/zrepl RUN mkdir -p /go/src/github.com/zrepl/zrepl
RUN chmod -R 0777 /go RUN chmod -R 0777 /go
RUN mkdir -p /.cache && chmod -R 0777 /.cache
WORKDIR /go/src/github.com/zrepl/zrepl WORKDIR /go/src/github.com/zrepl/zrepl
+20 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/problame/go-netssh" "github.com/problame/go-netssh"
"time"
) )
type SSHStdinserverConnecter struct { type SSHStdinserverConnecter struct {
@@ -19,6 +20,8 @@ type SSHStdinserverConnecter struct {
TransportOpenCommand []string `mapstructure:"transport_open_command"` TransportOpenCommand []string `mapstructure:"transport_open_command"`
SSHCommand string `mapstructure:"ssh_command"` SSHCommand string `mapstructure:"ssh_command"`
Options []string Options []string
DialTimeout string `mapstructure:"dial_timeout"`
dialTimeout time.Duration
} }
func parseSSHStdinserverConnecter(i map[string]interface{}) (c *SSHStdinserverConnecter, err error) { func parseSSHStdinserverConnecter(i map[string]interface{}) (c *SSHStdinserverConnecter, err error) {
@@ -29,6 +32,15 @@ func parseSSHStdinserverConnecter(i map[string]interface{}) (c *SSHStdinserverCo
return nil, err return nil, err
} }
if c.DialTimeout != "" {
c.dialTimeout, err = time.ParseDuration(c.DialTimeout)
if err != nil {
return nil, errors.Wrap(err, "cannot parse dial_timeout")
}
} else {
c.dialTimeout = 10 * time.Second
}
// TODO assert fields are filled // TODO assert fields are filled
return return
@@ -38,9 +50,15 @@ func (c *SSHStdinserverConnecter) Connect() (rwc io.ReadWriteCloser, err error)
var endpoint netssh.Endpoint var endpoint netssh.Endpoint
if err = copier.Copy(&endpoint, c); err != nil { if err = copier.Copy(&endpoint, c); err != nil {
return return nil, errors.WithStack(err)
}
var dialCtx context.Context
dialCtx, dialCancel := context.WithTimeout(context.TODO(), c.dialTimeout) // context.TODO tied to error handling below
defer dialCancel()
if rwc, err = netssh.Dial(dialCtx, endpoint); err != nil {
if err == context.DeadlineExceeded {
err = errors.Errorf("dial_timeout of %s exceeded", c.dialTimeout)
} }
if rwc, err = netssh.Dial(context.TODO(), endpoint); err != nil {
err = errors.WithStack(err) err = errors.WithStack(err)
return return
} }
+9 -1
View File
@@ -1,6 +1,7 @@
.. |break_config| replace:: **[BREAK]** .. |break_config| replace:: **[BREAK]**
.. |break| replace:: **[BREAK]** .. |break| replace:: **[BREAK]**
.. |bugfix| replace:: [BUG] .. |bugfix| replace:: [BUG]
.. |docs| replace:: [DOCS]
.. |feature| replace:: [FEATURE] .. |feature| replace:: [FEATURE]
Changelog Changelog
@@ -19,7 +20,13 @@ Developers should consult the git commit log or GitHub issue tracker.
* Make sure to understand the meaning bookmarks have for :ref:`maximum replication downtime <replication-downtime>`. * Make sure to understand the meaning bookmarks have for :ref:`maximum replication downtime <replication-downtime>`.
* Example: :sampleconf:`pullbackup/productionhost.yml` * Example: :sampleconf:`pullbackup/productionhost.yml`
* |break| :commit:`ccd062e`: both sides of a replication setup must be updated and restarted. Otherwise the connecting side will hang and not time out. * |break| :commit:`ccd062e`: ``ssh+stdinserver`` transport: changed protocol requires daemon restart on both sides
* The delicate procedure of talking to the serving-side zrepl daemon via the stdinserver proxy command now has better error handling.
* This includes handshakes between client+proxy and client + remote daemo, which is not implemented in previous versions of zrepl.
* The connecting side will therefore time out, with the message ``dial_timeout of 10s exceeded``.
* Both sides of a replication setup must be updated and restarted. Otherwise the connecting side will hang and not time out.
* |break_config| :commit:`2bfcfa5`: first outlet in ``global.logging`` is now used for logging meta-errors, for example problems encountered when writing to other outlets. * |break_config| :commit:`2bfcfa5`: first outlet in ``global.logging`` is now used for logging meta-errors, for example problems encountered when writing to other outlets.
* |feature| :issue:`10`: ``zrepl control status`` subcommand * |feature| :issue:`10`: ``zrepl control status`` subcommand
@@ -34,6 +41,7 @@ Developers should consult the git commit log or GitHub issue tracker.
* |bugfix| :issue:`8` and :issue:`56`: ``ssh+stdinserver`` transport properly reaps SSH child processes * |bugfix| :issue:`8` and :issue:`56`: ``ssh+stdinserver`` transport properly reaps SSH child processes
* |bugfix| :commit:`cef63ac`: ``human`` format now prints non-string values correctly * |bugfix| :commit:`cef63ac`: ``human`` format now prints non-string values correctly
* |bugfix| :issue:`26`: slow TCP outlets no longer block the daemon * |bugfix| :issue:`26`: slow TCP outlets no longer block the daemon
* |docs| :issue:`64`: tutorial: document ``known_host`` file entry
0.0.2 0.0.2
----- -----
+6 -2
View File
@@ -85,8 +85,9 @@ Connect Mode
user: root user: root
port: 22 port: 22
identity_file: /etc/zrepl/ssh/identity identity_file: /etc/zrepl/ssh/identity
options: # optional options: # optional, default [], `-o` arguments passed to ssh
- "Compression=on" - "Compression=on"
dial_timeout: # optional, default 10s, max time.Duration until initial handshake is completed
The connecting zrepl daemon The connecting zrepl daemon
@@ -101,10 +102,13 @@ The connecting zrepl daemon
#. The remote user, host and port correspond to those configured. #. The remote user, host and port correspond to those configured.
#. Further options can be specified using the ``options`` field, which appends each entry in the list to the command line using ``-o $entry``. #. Further options can be specified using the ``options`` field, which appends each entry in the list to the command line using ``-o $entry``.
1. Wraps the pipe ends in an ``io.ReadWriteCloser`` and uses it for RPC. #. Wraps the pipe ends in an ``io.ReadWriteCloser`` and uses it for RPC.
As discussed in the section above, the connecting zrepl daemon expects that ``zrepl stdinserver $client_identity`` is executed automatically via an ``authorized_keys`` file entry. As discussed in the section above, the connecting zrepl daemon expects that ``zrepl stdinserver $client_identity`` is executed automatically via an ``authorized_keys`` file entry.
The ``known_hosts`` file used by the ssh command must contain an entry for the serving host, e.g., ``app-srv.example.com`` in the example above.
.. NOTE:: .. NOTE::
The environment variables of the underlying SSH process are cleared. ``$SSH_AUTH_SOCK`` will not be available. The environment variables of the underlying SSH process are cleared. ``$SSH_AUTH_SOCK`` will not be available.
+1 -1
View File
@@ -16,7 +16,7 @@ zrepl - ZFS replication
Getting started Getting started
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
The :ref:`5 minute tutorial setup <tutorial>` gives you a first impression. The :ref:`10 minutes tutorial setup <tutorial>` gives you a first impression.
Main Features Main Features
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
+9 -2
View File
@@ -60,7 +60,7 @@ Follow the :ref:`OS-specific installation instructions <installation>` and come
Configure ``backup-srv`` Configure ``backup-srv``
------------------------ ------------------------
We define a **pull job** named ``pull_app-srv`` in the |mainconfig|: :: We define a **pull job** named ``pull_app-srv`` in the |mainconfig| on host ``backup-srv``: ::
jobs: jobs:
- name: pull_app-srv - name: pull_app-srv
@@ -94,6 +94,13 @@ It uses the private key specified at ``connect.identity_file`` which we still ne
Note that most use cases do not benefit from separate keypairs per remote endpoint. Note that most use cases do not benefit from separate keypairs per remote endpoint.
Thus, it is sufficient to create one keypair and use it for all ``connect`` directives on one host. Thus, it is sufficient to create one keypair and use it for all ``connect`` directives on one host.
zrepl uses ssh's default ``known_hosts`` file, which must contain a host identification entry for ``app-srv.example.com``.
If that entry does not already exist, we need to generate it.
Run the following command, compare the host fingerprints, and confirm with yes if they match.
You will not be able to get a shell with the identity file we just generated, which is fine. ::
ssh -i /etc/zrepl/ssh/identity root@app-srv.example.com
Learn more about :ref:`transport-ssh+stdinserver` transport and the :ref:`pull job <job-pull>` format. Learn more about :ref:`transport-ssh+stdinserver` transport and the :ref:`pull job <job-pull>` format.
.. _tutorial-configure-app-srv: .. _tutorial-configure-app-srv:
@@ -101,7 +108,7 @@ Learn more about :ref:`transport-ssh+stdinserver` transport and the :ref:`pull j
Configure ``app-srv`` Configure ``app-srv``
--------------------- ---------------------
We define a corresponding **source job** named ``pull_backup`` in the |mainconfig|: :: We define a corresponding **source job** named ``pull_backup`` in the |mainconfig| on host ``app-srv``: ::
jobs: jobs:
- name: pull_backup - name: pull_backup
+2 -2
View File
@@ -2,7 +2,7 @@
package rpc package rpc
import "fmt" import "strconv"
const _DataType_name = "DataTypeNoneDataTypeControlDataTypeMarshaledJSONDataTypeOctets" const _DataType_name = "DataTypeNoneDataTypeControlDataTypeMarshaledJSONDataTypeOctets"
@@ -11,7 +11,7 @@ var _DataType_index = [...]uint8{0, 12, 27, 48, 62}
func (i DataType) String() string { func (i DataType) String() string {
i -= 1 i -= 1
if i >= DataType(len(_DataType_index)-1) { if i >= DataType(len(_DataType_index)-1) {
return fmt.Sprintf("DataType(%d)", i+1) return "DataType(" + strconv.FormatInt(int64(i+1), 10) + ")"
} }
return _DataType_name[_DataType_index[i]:_DataType_index[i+1]] return _DataType_name[_DataType_index[i]:_DataType_index[i+1]]
} }
+2 -3
View File
@@ -2,7 +2,7 @@
package rpc package rpc
import "fmt" import "strconv"
const ( const (
_FrameType_name_0 = "FrameTypeHeaderFrameTypeDataFrameTypeTrailer" _FrameType_name_0 = "FrameTypeHeaderFrameTypeDataFrameTypeTrailer"
@@ -11,7 +11,6 @@ const (
var ( var (
_FrameType_index_0 = [...]uint8{0, 15, 28, 44} _FrameType_index_0 = [...]uint8{0, 15, 28, 44}
_FrameType_index_1 = [...]uint8{0, 12}
) )
func (i FrameType) String() string { func (i FrameType) String() string {
@@ -22,6 +21,6 @@ func (i FrameType) String() string {
case i == 255: case i == 255:
return _FrameType_name_1 return _FrameType_name_1
default: default:
return fmt.Sprintf("FrameType(%d)", i) return "FrameType(" + strconv.FormatInt(int64(i), 10) + ")"
} }
} }
+2 -2
View File
@@ -2,7 +2,7 @@
package rpc package rpc
import "fmt" import "strconv"
const _Status_name = "StatusOKStatusRequestErrorStatusServerErrorStatusError" const _Status_name = "StatusOKStatusRequestErrorStatusServerErrorStatusError"
@@ -11,7 +11,7 @@ var _Status_index = [...]uint8{0, 8, 26, 43, 54}
func (i Status) String() string { func (i Status) String() string {
i -= 1 i -= 1
if i >= Status(len(_Status_index)-1) { if i >= Status(len(_Status_index)-1) {
return fmt.Sprintf("Status(%d)", i+1) return "Status(" + strconv.FormatInt(int64(i+1), 10) + ")"
} }
return _Status_name[_Status_index[i]:_Status_index[i+1]] return _Status_name[_Status_index[i]:_Status_index[i+1]]
} }
+2 -2
View File
@@ -2,7 +2,7 @@
package zfs package zfs
import "fmt" import "strconv"
const _Conflict_name = "ConflictIncrementalConflictAllRightConflictNoCommonAncestorConflictDiverged" const _Conflict_name = "ConflictIncrementalConflictAllRightConflictNoCommonAncestorConflictDiverged"
@@ -10,7 +10,7 @@ var _Conflict_index = [...]uint8{0, 19, 35, 59, 75}
func (i Conflict) String() string { func (i Conflict) String() string {
if i < 0 || i >= Conflict(len(_Conflict_index)-1) { if i < 0 || i >= Conflict(len(_Conflict_index)-1) {
return fmt.Sprintf("Conflict(%d)", i) return "Conflict(" + strconv.FormatInt(int64(i), 10) + ")"
} }
return _Conflict_name[_Conflict_index[i]:_Conflict_index[i+1]] return _Conflict_name[_Conflict_index[i]:_Conflict_index[i+1]]
} }