-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* The project has switched from gRPC to REST API. This change isn't compatible with old job configurations. Instead of configuring `serv:` for every job, it configures in one place: ```yaml # Include file with keys for accessing remote jobs and authenticate remote # clients. The filename is relative to filename of this configuration file. include_keys: "keys.yaml" listen: # Serve "sink" and "source" jobs for network access. - addr: ":8888" tls_cert: "/usr/local/etc/ssl/cert.pem" tls_key: "/usr/local/etc/ssl/key.pem" zfs: true ``` This configuration serves http and https API requests. `tls_cert` and `tls_key` are optional and needed for serving https requests. `keys.yaml` contains authentication keys of remote clients: ```yaml # Clients with defined authentication keys have network access to "sink" and # "source" jobs. The key name is their client identity name. # Authentication token and client_identity for me. - name: "a.domain.com" # client_identity key: "long and secret token" ``` * All transports has been replaced by `local` and `http` transports. `local` transport configuration looks almost the same: ```yaml jobs: - name: "zroot-to-zdisk" type: "push" connect: type: "local" listener_name: "zdisk" client_identity: "localhost" ``` with one exception. `listener_name` now is a remote job name actually. The new `http` transport replaced all network transports. Its configuration look like: ```yaml jobs: - name: "zroot-to-server" type: "push" connect: type: "http" server: "https://server:8888" listener_name: "zdisk" client_identity: "serverkey" - name: "server-to-zdisk" type: "pull" connect: type: "http" server: "https://server:8888" listener_name: "zroot-to-client" client_identity: "serverkey" ``` `listener_name` is a job name on the server with type of `sink` or `source`. `client_identity` is a key name from `keys.yaml`. That key will be sent to the server for authentication and the server must have a key with the same `key` content in `keys.yaml`. `name` can be different, because `sink` and `source` jobs use key name as `client_identity`.
- Loading branch information
Showing
63 changed files
with
2,239 additions
and
900 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Clients with defined authentication keys have network access to "sink" and | ||
# "source" jobs. The key name is their client identity name. | ||
|
||
# - name: "localhost" # client identity name | ||
# key: "long long and secret key" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package jsonclient | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"slices" | ||
"strconv" | ||
) | ||
|
||
const jsonLenHeader = "X-Zrepl-Json-Length" | ||
|
||
func (self *Client) PostStream(ctx context.Context, endpoint string, | ||
in, out any, r io.Reader, reqEditors ...RequestEditorFn, | ||
) error { | ||
var b bytes.Buffer | ||
if err := json.NewEncoder(&b).Encode(in); err != nil { | ||
return fmt.Errorf("jsonclient: marshaling json payload: %w", err) | ||
} | ||
b.WriteString("\n") | ||
|
||
body := io.MultiReader(&b, r) | ||
editors := slices.Concat([]RequestEditorFn{ | ||
func(ctx context.Context, req *http.Request) error { | ||
req.Header.Set("Content-Type", "application/octet-stream") | ||
req.Header.Set(jsonLenHeader, strconv.Itoa(b.Len())) | ||
return nil | ||
}, | ||
}, reqEditors) | ||
|
||
req, err := self.NewRequest(ctx, http.MethodPost, endpoint, body, editors...) | ||
if err != nil { | ||
return err | ||
} | ||
return self.Do(req, out) | ||
} | ||
|
||
func (self *Client) PostResponseStream(ctx context.Context, endpoint string, | ||
in, out any, reqEditors ...RequestEditorFn, | ||
) (io.ReadCloser, error) { | ||
req, err := self.postRequest(ctx, endpoint, in, reqEditors...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
resp, err := self.Client.Do(req) | ||
if err != nil { | ||
return nil, fmt.Errorf("http do: %w", err) | ||
} | ||
|
||
if err := parseJsonPayload(resp, out); err != nil { | ||
_, _ = io.Copy(io.Discard, resp.Body) | ||
resp.Body.Close() | ||
return nil, fmt.Errorf("unexpected response from %q: %w", req.URL, err) | ||
} | ||
return resp.Body, nil | ||
} | ||
|
||
func parseJsonPayload(resp *http.Response, out any) error { | ||
if err := checkStatusCode(resp); err != nil { | ||
return err | ||
} else if !canUnmarshal(out) { | ||
return nil | ||
} | ||
return ReadJsonPayload(resp.Header, resp.Body, out) | ||
} | ||
|
||
func ReadJsonPayload(h http.Header, r io.Reader, out any) error { | ||
lenStr := h.Get(jsonLenHeader) | ||
if lenStr == "" { | ||
return nil | ||
} | ||
|
||
jsonLen, err := strconv.Atoi(lenStr) | ||
if err != nil { | ||
return fmt.Errorf( | ||
"jsonclient: parsing json payload length %q: %w", lenStr, err) | ||
} else if jsonLen == 0 { | ||
return nil | ||
} | ||
|
||
lr := io.LimitReader(r, int64(jsonLen)) | ||
if err = json.NewDecoder(lr).Decode(out); err != nil { | ||
return fmt.Errorf("jsonclient: decoding json payload %w", err) | ||
} | ||
return nil | ||
} | ||
|
||
func WriteJsonPayload(h http.Header, w io.Writer, in any) error { | ||
var b bytes.Buffer | ||
if err := json.NewEncoder(&b).Encode(in); err != nil { | ||
return fmt.Errorf("jsonclient: marshaling json payload: %w", err) | ||
} | ||
b.WriteString("\n") | ||
|
||
h.Set(jsonLenHeader, strconv.Itoa(b.Len())) | ||
if _, err := io.Copy(w, &b); err != nil { | ||
return fmt.Errorf("jsonclient: writing json payload: %w", err) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.