Compare commits

...

100 commits

Author SHA1 Message Date
5d62cef27e [#98] Fix linter issues
Signed-off-by: Alex Vanin <a.vanin@yadro.com>
2023-06-28 12:13:02 +00:00
c0c0c588b5 [#98] Add forgejo workflows
Signed-off-by: Alex Vanin <a.vanin@yadro.com>
2023-06-28 12:13:02 +00:00
2f88460172 [#83] Allow to split objects in the client
Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
2023-06-28 12:12:37 +00:00
66cb5dcf34 [#83] Update .gitignore
Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
2023-06-28 12:12:37 +00:00
91e80ba743 [#73] pool/tree: Fix index in retry loop
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-06-28 13:06:23 +03:00
c243b443bc [#80] objectwriter: Allow custimize maxChunkLen
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-06-26 18:13:04 +03:00
aa8ffebc63 [#95] transformer: Set parent version
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-06-23 13:48:02 +03:00
9d40228cec [#73] pool/tree: Fix client healthy status
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-06-08 17:01:55 +03:00
af40dc68f0 [#84] pool/tree: Allow to pass gRPC dial options
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-06-08 15:55:07 +03:00
981d24a493 [#84] pool: Allow to pass gRPC dial options
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-06-08 15:54:48 +03:00
19adb4dffa [#73] pool/tree: Add tests
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-06-08 14:37:57 +03:00
51e022ab8c [#73] pool/tree: Add tree pool
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-06-08 14:37:57 +03:00
0d3dacb515 [#73] pool: Add getters for NodeParam
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-06-08 14:37:57 +03:00
b2e302624d [#73] pool/tree: Add proto tree service client
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-06-08 14:37:57 +03:00
fcbf96add6 [#76] Add UNIQUE keyword
Signed-off-by: Alejandro Lopez <a.lopez@yadro.com>
2023-06-06 13:54:07 +03:00
4f48f6c9e0 [#78] netmap: Add new keywords NOT and UNIQUE
* Add the rule for NOT operation to the policy parser grammar
* Regenerate query parse
* Implement NOT in filter
* Add unit-tests

Signed-off-by: Airat Arifullin a.arifullin@yadro.com
2023-06-02 17:47:20 +03:00
ec59ebfd88 [#87] go.mod: Update hrw
```
                                                              │      old      │                 new                  │
                                                              │    sec/op     │    sec/op     vs base                │
Netmap_ContainerNodes/REP_2-8                                    13.07µ ± 12%   11.03µ ± 12%  -15.63% (p=0.003 n=10)
Netmap_ContainerNodes/REP_2_IN_X_CBF_2_SELECT_2_FROM_*_AS_X-8   11.383µ ±  9%   9.970µ ± 19%  -12.42% (p=0.005 n=10)
geomean                                                          12.20µ         10.49µ        -14.04%

                                                              │      old      │                 new                  │
                                                              │     B/op      │     B/op      vs base                │
Netmap_ContainerNodes/REP_2-8                                   10.203Ki ± 0%   7.711Ki ± 0%  -24.43% (p=0.000 n=10)
Netmap_ContainerNodes/REP_2_IN_X_CBF_2_SELECT_2_FROM_*_AS_X-8    9.641Ki ± 0%   7.148Ki ± 0%  -25.85% (p=0.000 n=10)
geomean                                                          9.918Ki        7.424Ki       -25.14%

                                                              │    old     │                new                 │
                                                              │ allocs/op  │ allocs/op   vs base                │
Netmap_ContainerNodes/REP_2-8                                   216.0 ± 0%   131.0 ± 0%  -39.35% (p=0.000 n=10)
Netmap_ContainerNodes/REP_2_IN_X_CBF_2_SELECT_2_FROM_*_AS_X-8   215.0 ± 0%   130.0 ± 0%  -39.53% (p=0.000 n=10)
geomean                                                         215.5        130.5       -39.44%
```

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-06-02 14:54:40 +03:00
030ff2f122 [#87] netmap: Add benchmark for ContainerNodes()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-06-02 14:54:40 +03:00
0f7455ff7a [#75] Update antlr4 version to 4.13.0
Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
2023-06-01 13:15:11 +00:00
e6b662cfa6 [#75] Add make targets policy and docker/%
Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
2023-06-01 13:15:11 +00:00
406c2324d4 [#85] go.mod: Tidy
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-06-01 10:02:23 +03:00
10482ffbed [#82] client: Allow to pass gRPC dial options
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-05-30 16:51:22 +03:00
f5b23eb225 [#74] netmap/parser: Update antlr4 generator
Also, add -no-listener option, as we use visitor only.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-05-19 17:47:24 +03:00
70f23dd1ea [#74] pre-commit: Exclude auto-generated files
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-05-19 17:47:24 +03:00
57f874048b [#74] go.mod: Update antlr4 dependency
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-05-19 17:47:24 +03:00
a397d1fd15 [#74] go.mod: Update dependencies
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-05-19 17:47:23 +03:00
9803c2816a [#74] pool: move to sync/atomic
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-05-19 14:58:30 +03:00
d04d96b42e [#74] go.mod: Move to go1.19
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-05-19 14:53:47 +03:00
9a072a8f49 [#68] Replace interface{} with any
Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
2023-05-15 17:21:49 +03:00
15b4287092 [#49] bearer: Allow empty eacl if token is impersonated
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-05-05 12:45:39 +03:00
d4fe9a193d [#66] transformer: Accept constructor in NextTarget
The code of frostfs-node is not yet ready to reuse egress target for
multiple objects, let's postpone until #64.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-05-03 11:22:09 +03:00
c42a6119ff [#66] transformer: Extend tests
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-05-03 11:22:09 +03:00
29b188db57 [#52] Remove storage groups and audit
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-05-03 08:20:37 +00:00
38b03ff28b [#63] transformer: Resolve funlen linter
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-25 13:29:42 +03:00
0fa23a9b14 [#63] transformer: Add context to methods
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-25 13:29:42 +03:00
d0762d037d [#44] pool: Add copies number vector when putting object
Signed-off-by: Artem Tataurov <a.tataurov@yadro.com>
2023-04-20 13:41:05 +03:00
db5b89496d [#49] bearer: Consider impersonate in fillBody
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-04-18 14:54:05 +00:00
7c75db2f2d [#59] netmap: Remove unused param from getSelection()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-18 14:11:04 +00:00
dce55a436a [#9999] sdk: Up api-go version
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-04-18 09:59:52 +00:00
cae2f37cdd client: rename formRequest() to buildRequest()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-18 09:58:34 +00:00
f60bea4be5 [#48] client: Refactor SessionCreate()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-18 09:58:34 +00:00
a16fc40c39 [#48] client: Refactor EndpointInfo()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-18 09:58:34 +00:00
40d966bec2 [#48] client: Refactor NetworkInfo()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-18 09:58:34 +00:00
Pavel Karpy
d0c5d837d2 [#56] *: Drop reputation system
Signed-off-by: Pavel Karpy <p.karpy@yadro.com>
2023-04-18 07:52:16 +00:00
237b90f744 [#49] bearer: Add impersonate flag
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-04-17 11:51:38 +03:00
c8e620ad24 [#53] sdk-go: Drop subnet
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-04-14 16:31:08 +03:00
591dd1247d [#48] client: Refactor ContainerPut()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-14 09:07:18 +03:00
57619fbbe4 [#48] client: Refactor ContainerSetEACL()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-14 09:07:18 +03:00
8bc8f1f365 [#48] client: Refactor ContainerDelete()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-14 09:07:18 +03:00
09ed2863fc [#48] client: Refactor ContainerEACL()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-14 09:07:18 +03:00
8e2f77890f [#48] client: Refactor ContainerGet()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-14 09:07:18 +03:00
8852b262f2 [#48] client: Refactor ContainerList()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-14 09:07:18 +03:00
b2c66cb99e [#48] client: Refactor ContainerAnnounceUsedSpace()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-14 09:07:18 +03:00
6c9b92c9dc [#48] client: Execute metainfo callback in processResponse()
It was lost in 8c5333ea55.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-14 09:07:18 +03:00
772fa90983 [#48] client/container: Form requests in a separate function
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-14 09:06:52 +03:00
1bfa9ecdb0 [#48] client: Remove ctx == nil checks
Much less useful after we made context to be passed explicitly.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-13 09:04:09 +03:00
55b06cd764 [#48] client: Split container methods by files
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-13 09:04:09 +03:00
Pavel Karpy
f41860f9bd [#46] client: Allow set copy_number for every placement vector
Signed-off-by: Pavel Karpy <p.karpy@yadro.com>
2023-04-11 10:06:55 +00:00
Pavel Karpy
423b320f91 [#46] go.mod: Update api-go version
Signed-off-by: Pavel Karpy <p.karpy@yadro.com>
2023-04-11 10:06:55 +00:00
f8c34b45f3 [#47] eacl: Fix duplicate imports
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-07 08:59:19 +03:00
fa9573e857 [#47] client: Pass context to Dial() explicitly
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-07 08:59:19 +03:00
bc62e2f712 [#47] pool: Resolve contextcheck and containedctx linters
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-07 08:59:19 +03:00
31271ad8b1 [#47] netmap: Make PlacementPolicy.WriteStringTo() pass nofunlen, cogognit
REP statement is obligatory, thus insert newline before each statement
after REP.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-07 08:59:19 +03:00
25e9336d68 [#47] container: Make readFromV2() pass funlen
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-07 08:59:19 +03:00
4cd755877c [#47] client: Do not check context in NetmapSnapshot()
It is passed explicitly, non-nil by convention.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-07 08:59:19 +03:00
1395b282fe [#47] acl: Remove unused resetBit()
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-07 08:59:19 +03:00
708d933fe3 [#47] .golangci.yml: Unify with other FrostFS repos
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-07 08:59:19 +03:00
4fa52312c7 [#47] reputation: Fix misspelling
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-04-07 08:59:19 +03:00
552219b8e1 [#16] pool: Fix counting context canceled error
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-03-29 15:58:04 +03:00
cfb8a7b914 [#41] .gitlint: Synchronize settings across FrostFS repos
This change allows to use `[#xx]` placeholders for issue number.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-24 22:07:13 +03:00
4438f115fb [#39] Add Issue Template
Add bug report and feature request templates

Signed-off-by: Liza <e.chichindaeva@yadro.com>
2023-03-23 12:25:57 +03:00
bec77f280a [#37] container: Support legacy sys attributes
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-03-16 11:14:42 +03:00
df2090c2be [#37] netmap: Update tests for new sys attributes
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-03-16 11:14:36 +03:00
7e6592b28e [#37] go.mod: Update api-go for new sys attributes
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-03-16 11:14:27 +03:00
d589d51509 [#19] transformer: Fix dependencies
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-03-16 09:51:03 +03:00
25588ee3be [#19] transformer: Do not allocate intermeate slice for hashers
```
name                 old time/op    new time/op    delta
Transformer/small-8    73.7µs ±15%    72.4µs ±16%    ~     (p=0.604 n=10+9)
Transformer/big-8       1.36s ± 4%     1.36s ± 8%    ~     (p=0.579 n=10+10)

name                 old alloc/op   new alloc/op   delta
Transformer/small-8    7.67kB ± 0%    7.57kB ± 0%  -1.36%  (p=0.000 n=10+10)
Transformer/big-8      49.0kB ± 0%    48.3kB ± 0%  -1.48%  (p=0.000 n=10+10)

name                 old allocs/op  new allocs/op  delta
Transformer/small-8       101 ± 0%        98 ± 0%  -2.97%  (p=0.000 n=10+10)
Transformer/big-8         609 ± 0%       591 ± 1%  -3.00%  (p=0.000 n=10+9)
```

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
9407f30248 [#19] transformer: Optimize payload hashers a bit
```
name                 old time/op    new time/op    delta
Transformer/small-8    74.8µs ±11%    73.7µs ±15%    ~     (p=0.529 n=10+10)
Transformer/big-8       1.38s ±11%     1.36s ± 4%    ~     (p=0.796 n=10+10)

name                 old alloc/op   new alloc/op   delta
Transformer/small-8    7.69kB ± 0%    7.67kB ± 0%  -0.21%  (p=0.000 n=10+10)
Transformer/big-8      49.2kB ± 0%    49.0kB ± 0%  -0.48%  (p=0.004 n=10+10)

name                 old allocs/op  new allocs/op  delta
Transformer/small-8       102 ± 0%       101 ± 0%  -0.98%  (p=0.000 n=9+10)
Transformer/big-8         620 ± 1%       609 ± 0%  -1.66%  (p=0.000 n=10+10)
```

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
94c0a607b5 [#19] transformer: Add a target which sends parts to a channel
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
e45647de3c [#19] transformer: Do not reuse memory of sent objects
Slower, but more correct.
```
name                 old time/op    new time/op    delta
Transformer/small-8    72.4µs ± 8%    74.8µs ±11%     ~     (p=0.278 n=9+10)
Transformer/big-8       1.31s ± 8%     1.38s ±11%   +5.50%  (p=0.035 n=10+10)

name                 old alloc/op   new alloc/op   delta
Transformer/small-8    7.39kB ± 0%    7.69kB ± 0%   +4.04%  (p=0.000 n=10+10)
Transformer/big-8      46.9kB ± 0%    49.2kB ± 0%   +4.87%  (p=0.000 n=10+10)

name                 old allocs/op  new allocs/op  delta
Transformer/small-8      94.6 ± 1%     102.0 ± 0%   +7.82%  (p=0.000 n=10+9)
Transformer/big-8         560 ± 0%       620 ± 1%  +10.66%  (p=0.000 n=10+10)
```

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
611e20587b [#19] transformer/test: Check owner ID and payload hash for parts
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
eba6831125 [#19] transformer/test: Add helper functions
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
7e3810d654 [#19] transformer: Move EpochSource to other types
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
cc0fef2c55 [#19] transformer: Merge formatter and payload splitter
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
b696d3c70e [#19] transformer: Make writeChunk non-recursive
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
1c94309d7a [#19] transformer: Simplify AccessIdentifiers
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
f43f18ecda [#19] transformer: Cover with unit-tests
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
ac8442bf99 [#19] object: Move transformer implementation from node
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-15 05:39:09 +00:00
0ad877288e [TrueCloudLab#16] pool: Don't count grpc canceled error
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-03-10 06:58:34 +00:00
0e1999c965 [#23] pre-commit: Add gitlint hook
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-09 22:53:16 +03:00
b461aa64b8 [#23] pre-commit: Add golangci-lint hook
Also, fix minor issues. Skip deprecated warning for now.

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-09 22:53:14 +03:00
b761fd8070 [#23] pre-commit: Add initial configuration
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-03-09 22:52:51 +03:00
94476f9055 Rename package name
Due to source code relocation from GitHub.

Signed-off-by: Alex Vanin <a.vanin@yadro.com>
2023-03-07 15:47:21 +03:00
5e759bf089 [#2] Remove panic from RPCs
Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
2023-03-01 10:29:23 +03:00
d4f5bba459 [#2] Update lint config, fix lint errors
Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
2023-03-01 10:29:23 +03:00
e9c1a2ab2b [TrueCloudLab/hrw#2] sdk-go: Optimize node hash
Compute node hash by node initialization

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-02-28 18:07:14 +03:00
2cbc585edd [TrueCloudLab/hrw#2] sdk-go: Use typed HRW methods
Update HRW pkg and use typed HRW methods to sort nodes

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2023-02-28 18:07:14 +03:00
e355e5eeba [TrueCloudLab#22] .github: Fix CODEOWNERS
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-02-28 16:35:38 +03:00
f08069ceeb [#20] .github: Update CODEOWNERS
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-02-27 17:47:21 +03:00
dad99bad48 [#20] .github: Drop go1.17, add go1.20
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-02-27 17:47:21 +03:00
0d3a238d9c [#5] pool: Update hashicorp/lru to v2
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-02-24 17:32:40 +03:00
247 changed files with 9833 additions and 6690 deletions

View file

@ -0,0 +1,20 @@
on: [pull_request]
jobs:
dco:
name: DCO
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
- name: Run commit format checker
uses: https://git.alexvan.in/alexvanin/dco-go@v1
with:
from: 406c2324

View file

@ -0,0 +1,31 @@
on: [pull_request]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: golangci-lint
uses: https://github.com/golangci/golangci-lint-action@v2
with:
version: latest
tests:
name: Tests
runs-on: ubuntu-latest
strategy:
matrix:
go_versions: [ '1.19', '1.20' ]
fail-fast: false
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '${{ matrix.go_versions }}'
- name: Run tests
run: make test

2
.github/CODEOWNERS vendored
View file

@ -1 +1 @@
* @alexvanin @fyrchik @cthulhu-rider
* @TrueCloudLab/storage-core @TrueCloudLab/storage-services

45
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,45 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: community, triage, bug
assignees: ''
---
<!--- Provide a general summary of the issue in the Title above -->
## Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
## Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory -->
<!--- If no reason/fix/additions for the bug can be suggested, -->
<!--- uncomment the following phrase: -->
<!--- No fix can be suggested by a QA engineer. Further solutions shall be up to developers. -->
## Steps to Reproduce (for bugs)
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. -->
1.
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
## Regression
<!-- Is this issue a regression? (Yes / No) -->
<!-- If Yes, optionally please include version or commit id or PR# that caused this regression, if you have these details. -->
## Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
* Version used:
* Server setup and configuration:
* Operating System and version (`uname -a`):

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1 @@
blank_issues_enabled: false

View file

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: community, triage
assignees: ''
---
## Is your feature request related to a problem? Please describe.
<!--- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
## Describe the solution you'd like
<!--- A clear and concise description of what you want to happen. -->
## Describe alternatives you've considered
<!--- A clear and concise description of any alternative solutions or features you've considered. -->
## Additional context
<!--- Add any other context or screenshots about the feature request here. -->

View file

@ -1,21 +0,0 @@
name: DCO check
on:
pull_request:
branches:
- master
jobs:
commits_check_job:
runs-on: ubuntu-latest
name: Commits Check
steps:
- name: Get PR Commits
id: 'get-pr-commits'
uses: tim-actions/get-pr-commits@master
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: DCO Check
uses: tim-actions/dco@master
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}

View file

@ -1,52 +0,0 @@
name: neofs-sdk-go tests
on:
pull_request:
branches:
- master
types: [opened, synchronize]
paths-ignore:
- '**/*.md'
workflow_dispatch:
jobs:
tests:
name: Tests
runs-on: ubuntu-20.04
strategy:
matrix:
go_versions: [ '1.17.x', '1.18.x', '1.19.x' ]
fail-fast: false
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '${{ matrix.go_versions }}'
- name: Restore Go modules from cache
uses: actions/cache@v3
with:
path: /home/runner/go/pkg/mod
key: deps-${{ hashFiles('go.sum') }}
- name: Update Go modules
run: make dep
- name: Run tests
run: make test
lint:
runs-on: ubuntu-20.04
steps:
- name: Check out code
uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
only-new-issues: true

6
.gitignore vendored
View file

@ -21,3 +21,9 @@ vendor/
# coverage
coverage.txt
coverage.html
# antlr tool jar
antlr-*.jar
# tempfiles
.cache

10
.gitlint Normal file
View file

@ -0,0 +1,10 @@
[general]
fail-without-commits=true
contrib=CC1
[title-match-regex]
regex=^\[\#[0-9Xx]+\]\s
[ignore-by-title]
regex=^Release(.*)
ignore=title-match-regex

View file

@ -4,10 +4,10 @@
# options for analysis running
run:
# timeout for analysis, e.g. 30s, 5m, default is 1m
timeout: 5m
timeout: 10m
# include test files or not, default is true
tests: true
tests: false
# output configuration options
output:
@ -24,6 +24,13 @@ linters-settings:
govet:
# report about shadowed variables
check-shadowing: false
staticcheck:
checks: ["all", "-SA1019"] # TODO Enable SA1019 after deprecated warning are fixed.
funlen:
lines: 80 # default 60
statements: 60 # default 40
gocognit:
min-complexity: 40 # default 30
linters:
enable:
@ -32,28 +39,28 @@ linters:
- revive
# some default golangci-lint linters
- deadcode
- errcheck
- gosimple
- godot
- ineffassign
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
# extra linters
- bidichk
- durationcheck
- exhaustive
- godot
- exportloopref
- gofmt
- whitespace
- goimports
- misspell
- predeclared
- reassign
- whitespace
- containedctx
- funlen
- gocognit
- contextcheck
disable-all: true
fast: false
issues:
include:
- EXC0002 # should have a comment
- EXC0003 # test/Test ... consider calling this
- EXC0004 # govet
- EXC0005 # C-style breaks

30
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,30 @@
ci:
autofix_prs: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
- id: check-merge-conflict
- id: check-json
- id: check-xml
- id: check-yaml
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
- id: end-of-file-fixer
exclude: "(.key|.interp|.tokens)$"
- repo: https://github.com/golangci/golangci-lint
rev: v1.51.2
hooks:
- id: golangci-lint
- repo: https://github.com/jorisroovers/gitlint
rev: v0.18.0
hooks:
- id: gitlint
stages: [commit-msg]

4
Dockerfile Normal file
View file

@ -0,0 +1,4 @@
FROM golang:1.19
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install make openjdk-11-jre -y
WORKDIR /work

19
Makefile Normal file → Executable file
View file

@ -1,5 +1,7 @@
#!/usr/bin/make -f
ANTLR_VERSION="4.13.0"
# Run tests
test:
@go test ./... -cover
@ -29,6 +31,23 @@ format:
@echo "⇒ Processing goimports check"
@goimports -w ./
policy:
@wget -q https://www.antlr.org/download/antlr-${ANTLR_VERSION}-complete.jar -O antlr4-tool.jar
@java -Xmx500M -cp "`pwd`/antlr4-tool.jar" "org.antlr.v4.Tool" -o `pwd`/netmap/parser/ -Dlanguage=Go -no-listener -visitor `pwd`/netmap/parser/Query.g4 `pwd`/netmap/parser/QueryLexer.g4
# Run `make %` in truecloudlab/frostfs-sdk-go container(Golang+Java)
docker/%:
@docker build -t truecloudlab/frostfs-sdk-go --platform linux/amd64 . > /dev/null
@docker run --rm -t \
-v `pwd`:/work \
-u "$$(id -u):$$(id -g)" \
--env HOME=/work \
truecloudlab/frostfs-sdk-go make $*
# Synchronize tree service
sync-tree:
@./syncTree.sh
# Show this help prompt
help:
@echo ' Usage:'

View file

@ -1,6 +1,6 @@
# frostfs-sdk-go
Go implementation of FrostFS SDK. It contains high-level version-independent wrappers
for structures from [frostfs-api-go](https://github.com/TrueCloudLab/frostfs-api-go) as well as
for structures from [frostfs-api-go](https://git.frostfs.info/TrueCloudLab/frostfs-api-go) as well as
helper functions for simplifying node/dApp implementations.
## Repository structure
@ -14,7 +14,7 @@ There is also a reference implementation of checking algorithm which is used in
### checksum
Contains `Checksum` type encapsulating checksum as well as it's kind.
Currently Sha256 and [Tillich-Zemor hashsum](https://github.com/TrueCloudLab/tzhash) are in use.
Currently Sha256 and [Tillich-Zemor hashsum](https://git.frostfs.info/TrueCloudLab/tzhash) are in use.
### owner
`owner.ID` type represents single account interacting with FrostFS. In v2 version of protocol
@ -27,7 +27,7 @@ Contains Bearer token type with several FrostFS-specific methods.
### ns
In FrostFS there are 2 types of name resolution: DNS and NNS. NNS stands for Neo Name Service
is just a [contract](https://github.com/TrueCloudLab/frostfs-contract) deployed on a Neo blockchain.
is just a [contract](https://git.frostfs.info/TrueCloudLab/frostfs-contract) deployed on a Neo blockchain.
Basically, NNS is just a DNS-on-chain which can be used for resolving container nice-names as well
as any other name in dApps. See our [CoreDNS plugin](https://github.com/nspcc-dev/coredns/tree/master/plugin/nns)
for the example of how NNS can be integrated in DNS.
@ -77,7 +77,7 @@ if needed and perform any desired action. In the case above we may want to repor
these details to the user as well as retry an operation, possibly with different parameters.
Status wire-format is extendable and each node can report any set of details it wants.
The set of reserved status codes can be found in
[FrostFS API](https://github.com/TrueCloudLab/frostfs-api/blob/master/status/types.proto). There is also
[FrostFS API](https://git.frostfs.info/TrueCloudLab/frostfs-api/src/branch/master/status/types.proto). There is also
a `client.PrmInit.ResolveFrostFSFailures()` to seamlessly convert erroneous statuses into Go error type.
### policy
@ -102,8 +102,8 @@ outdated in some details.
```go
import (
"github.com/TrueCloudLab/frostfs-sdk-go/netmap"
"github.com/TrueCloudLab/frostfs-sdk-go/object"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
)
func placementNodes(addr *object.Address, p *netmap.PlacementPolicy, frostfsNodes []netmap.NodeInfo) {

View file

@ -1,10 +1,10 @@
package accounting
import "github.com/TrueCloudLab/frostfs-api-go/v2/accounting"
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
// Decimal represents decimal number for accounting operations.
//
// Decimal is mutually compatible with github.com/TrueCloudLab/frostfs-api-go/v2/accounting.Decimal
// Decimal is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting.Decimal
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.

View file

@ -3,8 +3,8 @@ package accounting_test
import (
"testing"
v2accounting "github.com/TrueCloudLab/frostfs-api-go/v2/accounting"
"github.com/TrueCloudLab/frostfs-sdk-go/accounting"
v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/accounting"
"github.com/stretchr/testify/require"
)

View file

@ -9,11 +9,11 @@ working with Fixed8 balance precision:
dec.SetPrecision(8)
Instances can be also used to process FrostFS API V2 protocol messages
(see neo.fs.v2.accounting package in https://github.com/TrueCloudLab/frostfs-api).
(see neo.fs.v2.accounting package in https://git.frostfs.info/TrueCloudLab/frostfs-api).
On client side:
import "github.com/TrueCloudLab/frostfs-api-go/v2/accounting"
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
var msg accounting.Decimal
dec.WriteToV2(&msg)

View file

@ -3,7 +3,7 @@ package accountingtest
import (
"math/rand"
"github.com/TrueCloudLab/frostfs-sdk-go/accounting"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/accounting"
)
// Decimal returns random accounting.Decimal.

View file

@ -5,7 +5,7 @@ Note that importing the package into source files is highly discouraged.
Random instance generation functions can be useful when testing expects any value, e.g.:
import accountingtest "github.com/TrueCloudLab/frostfs-sdk-go/accounting/test"
import accountingtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/accounting/test"
dec := accountingtest.Decimal()
// test the value

View file

@ -1,26 +0,0 @@
/*
Package audit provides features to process data audit in FrostFS system.
Result type groups values which can be gathered during data audit process:
var res audit.Result
res.ForEpoch(32)
res.ForContainer(cnr)
// ...
res.Complete()
Result instances can be stored in a binary format. On reporter side:
data := res.Marshal()
// send data
On receiver side:
var res audit.Result
err := res.Unmarshal(data)
// ...
Using package types in an application is recommended to potentially work with
different protocol versions with which these types are compatible.
*/
package audit

View file

@ -1,377 +0,0 @@
package audit
import (
"errors"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/audit"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/TrueCloudLab/frostfs-sdk-go/version"
)
// Result represents report on the results of the data audit in FrostFS system.
//
// Result is mutually binary-compatible with github.com/TrueCloudLab/frostfs-api-go/v2/audit.DataAuditResult
// message. See Marshal / Unmarshal methods.
//
// Instances can be created using built-in var declaration.
type Result struct {
versionEncoded bool
v2 audit.DataAuditResult
}
// Marshal encodes Result into a canonical FrostFS binary format (Protocol Buffers
// with direct field order).
//
// Writes version.Current() protocol version into the resulting message if Result
// hasn't been already decoded from such a message using Unmarshal.
//
// See also Unmarshal.
func (r *Result) Marshal() []byte {
if !r.versionEncoded {
var verV2 refs.Version
version.Current().WriteToV2(&verV2)
r.v2.SetVersion(&verV2)
r.versionEncoded = true
}
return r.v2.StableMarshal(nil)
}
var errCIDNotSet = errors.New("container ID is not set")
// Unmarshal decodes Result from its canonical FrostFS binary format (Protocol Buffers
// with direct field order). Returns an error describing a format violation.
//
// See also Marshal.
func (r *Result) Unmarshal(data []byte) error {
err := r.v2.Unmarshal(data)
if err != nil {
return err
}
r.versionEncoded = true
// format checks
var cID cid.ID
cidV2 := r.v2.GetContainerID()
if cidV2 == nil {
return errCIDNotSet
}
err = cID.ReadFromV2(*cidV2)
if err != nil {
return fmt.Errorf("could not convert V2 container ID: %w", err)
}
var (
oID oid.ID
oidV2 refs.ObjectID
)
for _, oidV2 = range r.v2.GetPassSG() {
err = oID.ReadFromV2(oidV2)
if err != nil {
return fmt.Errorf("invalid passed storage group ID: %w", err)
}
}
for _, oidV2 = range r.v2.GetFailSG() {
err = oID.ReadFromV2(oidV2)
if err != nil {
return fmt.Errorf("invalid failed storage group ID: %w", err)
}
}
return nil
}
// Epoch returns FrostFS epoch when the data associated with the Result was audited.
//
// Zero Result has zero epoch.
//
// See also ForEpoch.
func (r Result) Epoch() uint64 {
return r.v2.GetAuditEpoch()
}
// ForEpoch specifies FrostFS epoch when the data associated with the Result was audited.
//
// See also Epoch.
func (r *Result) ForEpoch(epoch uint64) {
r.v2.SetAuditEpoch(epoch)
}
// Container returns identifier of the container with which the data audit Result
// is associated and a bool that indicates container ID field presence in the Result.
//
// Zero Result does not have container ID.
//
// See also ForContainer.
func (r Result) Container() (cid.ID, bool) {
var cID cid.ID
cidV2 := r.v2.GetContainerID()
if cidV2 != nil {
_ = cID.ReadFromV2(*cidV2)
return cID, true
}
return cID, false
}
// ForContainer sets identifier of the container with which the data audit Result
// is associated.
//
// See also Container.
func (r *Result) ForContainer(cnr cid.ID) {
var cidV2 refs.ContainerID
cnr.WriteToV2(&cidV2)
r.v2.SetContainerID(&cidV2)
}
// AuditorKey returns public key of the auditing FrostFS Inner Ring node in
// a FrostFS binary key format.
//
// Zero Result has nil key. Return value MUST NOT be mutated: to do this,
// first make a copy.
//
// See also SetAuditorPublicKey.
func (r Result) AuditorKey() []byte {
return r.v2.GetPublicKey()
}
// SetAuditorKey specifies public key of the auditing FrostFS Inner Ring node in
// a FrostFS binary key format.
//
// Argument MUST NOT be mutated at least until the end of using the Result.
//
// See also AuditorKey.
func (r *Result) SetAuditorKey(key []byte) {
r.v2.SetPublicKey(key)
}
// Completed returns completion state of the data audit associated with the Result.
//
// Zero Result corresponds to incomplete data audit.
//
// See also Complete.
func (r Result) Completed() bool {
return r.v2.GetComplete()
}
// Complete marks the data audit associated with the Result as completed.
//
// See also Completed.
func (r *Result) Complete() {
r.v2.SetComplete(true)
}
// RequestsPoR returns number of requests made by Proof-of-Retrievability
// audit check to get all headers of the objects inside storage groups.
//
// Zero Result has zero requests.
//
// See also SetRequestsPoR.
func (r Result) RequestsPoR() uint32 {
return r.v2.GetRequests()
}
// SetRequestsPoR sets number of requests made by Proof-of-Retrievability
// audit check to get all headers of the objects inside storage groups.
//
// See also RequestsPoR.
func (r *Result) SetRequestsPoR(v uint32) {
r.v2.SetRequests(v)
}
// RetriesPoR returns number of retries made by Proof-of-Retrievability
// audit check to get all headers of the objects inside storage groups.
//
// Zero Result has zero retries.
//
// See also SetRetriesPoR.
func (r Result) RetriesPoR() uint32 {
return r.v2.GetRetries()
}
// SetRetriesPoR sets number of retries made by Proof-of-Retrievability
// audit check to get all headers of the objects inside storage groups.
//
// See also RetriesPoR.
func (r *Result) SetRetriesPoR(v uint32) {
r.v2.SetRetries(v)
}
// IteratePassedStorageGroups iterates over all storage groups that passed
// Proof-of-Retrievability audit check and passes them into f. Breaks on f's
// false return, f MUST NOT be nil.
//
// Zero Result has no passed storage groups and doesn't call f.
//
// See also SubmitPassedStorageGroup.
func (r Result) IteratePassedStorageGroups(f func(oid.ID) bool) {
r2 := r.v2.GetPassSG()
var id oid.ID
for i := range r2 {
_ = id.ReadFromV2(r2[i])
if !f(id) {
return
}
}
}
// SubmitPassedStorageGroup marks storage group as passed Proof-of-Retrievability
// audit check.
//
// See also IteratePassedStorageGroups.
func (r *Result) SubmitPassedStorageGroup(sg oid.ID) {
var idV2 refs.ObjectID
sg.WriteToV2(&idV2)
r.v2.SetPassSG(append(r.v2.GetPassSG(), idV2))
}
// IterateFailedStorageGroups is similar to IteratePassedStorageGroups but for failed groups.
//
// See also SubmitFailedStorageGroup.
func (r Result) IterateFailedStorageGroups(f func(oid.ID) bool) {
v := r.v2.GetFailSG()
var id oid.ID
for i := range v {
_ = id.ReadFromV2(v[i])
if !f(id) {
return
}
}
}
// SubmitFailedStorageGroup is similar to SubmitPassedStorageGroup but for failed groups.
//
// See also IterateFailedStorageGroups.
func (r *Result) SubmitFailedStorageGroup(sg oid.ID) {
var idV2 refs.ObjectID
sg.WriteToV2(&idV2)
r.v2.SetFailSG(append(r.v2.GetFailSG(), idV2))
}
// Hits returns number of sampled objects under audit placed
// in an optimal way according to the container's placement policy
// when checking Proof-of-Placement.
//
// Zero result has zero hits.
//
// See also SetHits.
func (r Result) Hits() uint32 {
return r.v2.GetHit()
}
// SetHits sets number of sampled objects under audit placed
// in an optimal way according to the containers placement policy
// when checking Proof-of-Placement.
//
// See also Hits.
func (r *Result) SetHits(hit uint32) {
r.v2.SetHit(hit)
}
// Misses returns number of sampled objects under audit placed
// in suboptimal way according to the container's placement policy,
// but still at a satisfactory level when checking Proof-of-Placement.
//
// Zero Result has zero misses.
//
// See also SetMisses.
func (r Result) Misses() uint32 {
return r.v2.GetMiss()
}
// SetMisses sets number of sampled objects under audit placed
// in suboptimal way according to the container's placement policy,
// but still at a satisfactory level when checking Proof-of-Placement.
//
// See also Misses.
func (r *Result) SetMisses(miss uint32) {
r.v2.SetMiss(miss)
}
// Failures returns number of sampled objects under audit stored
// in a way not confirming placement policy or not found at all
// when checking Proof-of-Placement.
//
// Zero result has zero failures.
//
// See also SetFailures.
func (r Result) Failures() uint32 {
return r.v2.GetFail()
}
// SetFailures sets number of sampled objects under audit stored
// in a way not confirming placement policy or not found at all
// when checking Proof-of-Placement.
//
// See also Failures.
func (r *Result) SetFailures(fail uint32) {
r.v2.SetFail(fail)
}
// IteratePassedStorageNodes iterates over all storage nodes that passed at least one
// Proof-of-Data-Possession audit check and passes their public keys into f. Breaks on
// f's false return.
//
// f MUST NOT be nil and MUST NOT mutate parameter passed into it at least until
// the end of using the Result.
//
// Zero Result has no passed storage nodes and doesn't call f.
//
// See also SubmitPassedStorageNode.
func (r Result) IteratePassedStorageNodes(f func([]byte) bool) {
v := r.v2.GetPassNodes()
for i := range v {
if !f(v[i]) {
return
}
}
}
// SubmitPassedStorageNodes marks storage node list as passed Proof-of-Data-Possession
// audit check. The list contains public keys.
//
// Argument and its elements MUST NOT be mutated at least until the end of using the Result.
//
// See also IteratePassedStorageNodes.
func (r *Result) SubmitPassedStorageNodes(list [][]byte) {
r.v2.SetPassNodes(list)
}
// IterateFailedStorageNodes is similar to IteratePassedStorageNodes but for failed nodes.
//
// See also SubmitPassedStorageNodes.
func (r Result) IterateFailedStorageNodes(f func([]byte) bool) {
v := r.v2.GetFailNodes()
for i := range v {
if !f(v[i]) {
return
}
}
}
// SubmitFailedStorageNodes is similar to SubmitPassedStorageNodes but for failed nodes.
//
// See also IterateFailedStorageNodes.
func (r *Result) SubmitFailedStorageNodes(list [][]byte) {
r.v2.SetFailNodes(list)
}

View file

@ -1,191 +0,0 @@
package audit_test
import (
"bytes"
"testing"
"github.com/TrueCloudLab/frostfs-sdk-go/audit"
audittest "github.com/TrueCloudLab/frostfs-sdk-go/audit/test"
cidtest "github.com/TrueCloudLab/frostfs-sdk-go/container/id/test"
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
oidtest "github.com/TrueCloudLab/frostfs-sdk-go/object/id/test"
"github.com/stretchr/testify/require"
)
func TestResultData(t *testing.T) {
var r audit.Result
countSG := func(passed bool, f func(oid.ID)) int {
called := 0
ff := func(arg oid.ID) bool {
called++
if f != nil {
f(arg)
}
return true
}
if passed {
r.IteratePassedStorageGroups(ff)
} else {
r.IterateFailedStorageGroups(ff)
}
return called
}
countPassSG := func(f func(oid.ID)) int { return countSG(true, f) }
countFailSG := func(f func(oid.ID)) int { return countSG(false, f) }
countNodes := func(passed bool, f func([]byte)) int {
called := 0
ff := func(arg []byte) bool {
called++
if f != nil {
f(arg)
}
return true
}
if passed {
r.IteratePassedStorageNodes(ff)
} else {
r.IterateFailedStorageNodes(ff)
}
return called
}
countPassNodes := func(f func([]byte)) int { return countNodes(true, f) }
countFailNodes := func(f func([]byte)) int { return countNodes(false, f) }
require.Zero(t, r.Epoch())
_, set := r.Container()
require.False(t, set)
require.Nil(t, r.AuditorKey())
require.False(t, r.Completed())
require.Zero(t, r.RequestsPoR())
require.Zero(t, r.RetriesPoR())
require.Zero(t, countPassSG(nil))
require.Zero(t, countFailSG(nil))
require.Zero(t, countPassNodes(nil))
require.Zero(t, countFailNodes(nil))
epoch := uint64(13)
r.ForEpoch(epoch)
require.Equal(t, epoch, r.Epoch())
cnr := cidtest.ID()
r.ForContainer(cnr)
cID, set := r.Container()
require.True(t, set)
require.Equal(t, cnr, cID)
key := []byte{1, 2, 3}
r.SetAuditorKey(key)
require.Equal(t, key, r.AuditorKey())
r.Complete()
require.True(t, r.Completed())
requests := uint32(2)
r.SetRequestsPoR(requests)
require.Equal(t, requests, r.RequestsPoR())
retries := uint32(1)
r.SetRetriesPoR(retries)
require.Equal(t, retries, r.RetriesPoR())
passSG1, passSG2 := oidtest.ID(), oidtest.ID()
r.SubmitPassedStorageGroup(passSG1)
r.SubmitPassedStorageGroup(passSG2)
called1, called2 := false, false
require.EqualValues(t, 2, countPassSG(func(id oid.ID) {
if id.Equals(passSG1) {
called1 = true
} else if id.Equals(passSG2) {
called2 = true
}
}))
require.True(t, called1)
require.True(t, called2)
failSG1, failSG2 := oidtest.ID(), oidtest.ID()
r.SubmitFailedStorageGroup(failSG1)
r.SubmitFailedStorageGroup(failSG2)
called1, called2 = false, false
require.EqualValues(t, 2, countFailSG(func(id oid.ID) {
if id.Equals(failSG1) {
called1 = true
} else if id.Equals(failSG2) {
called2 = true
}
}))
require.True(t, called1)
require.True(t, called2)
hit := uint32(1)
r.SetHits(hit)
require.Equal(t, hit, r.Hits())
miss := uint32(2)
r.SetMisses(miss)
require.Equal(t, miss, r.Misses())
fail := uint32(3)
r.SetFailures(fail)
require.Equal(t, fail, r.Failures())
passNodes := [][]byte{{1}, {2}}
r.SubmitPassedStorageNodes(passNodes)
called1, called2 = false, false
require.EqualValues(t, 2, countPassNodes(func(arg []byte) {
if bytes.Equal(arg, passNodes[0]) {
called1 = true
} else if bytes.Equal(arg, passNodes[1]) {
called2 = true
}
}))
require.True(t, called1)
require.True(t, called2)
failNodes := [][]byte{{3}, {4}}
r.SubmitFailedStorageNodes(failNodes)
called1, called2 = false, false
require.EqualValues(t, 2, countFailNodes(func(arg []byte) {
if bytes.Equal(arg, failNodes[0]) {
called1 = true
} else if bytes.Equal(arg, failNodes[1]) {
called2 = true
}
}))
require.True(t, called1)
require.True(t, called2)
}
func TestResultEncoding(t *testing.T) {
r := *audittest.Result()
t.Run("binary", func(t *testing.T) {
data := r.Marshal()
var r2 audit.Result
require.NoError(t, r2.Unmarshal(data))
require.Equal(t, r, r2)
})
}

View file

@ -1,13 +0,0 @@
/*
Package audittest provides functions for convenient testing of audit package API.
Note that importing the package into source files is highly discouraged.
Random instance generation functions can be useful when testing expects any value, e.g.:
import audittest "github.com/TrueCloudLab/frostfs-sdk-go/audit/test"
dec := audittest.Result()
// test the value
*/
package audittest

View file

@ -1,36 +0,0 @@
package audittest
import (
"github.com/TrueCloudLab/frostfs-sdk-go/audit"
cidtest "github.com/TrueCloudLab/frostfs-sdk-go/container/id/test"
oidtest "github.com/TrueCloudLab/frostfs-sdk-go/object/id/test"
)
// Result returns random audit.Result.
func Result() *audit.Result {
var x audit.Result
x.ForContainer(cidtest.ID())
x.SetAuditorKey([]byte("key"))
x.Complete()
x.ForEpoch(44)
x.SetHits(55)
x.SetMisses(66)
x.SetFailures(77)
x.SetRequestsPoR(88)
x.SetRequestsPoR(99)
x.SubmitFailedStorageNodes([][]byte{
[]byte("node1"),
[]byte("node2"),
})
x.SubmitPassedStorageNodes([][]byte{
[]byte("node3"),
[]byte("node4"),
})
x.SubmitPassedStorageGroup(oidtest.ID())
x.SubmitPassedStorageGroup(oidtest.ID())
x.SubmitFailedStorageGroup(oidtest.ID())
x.SubmitFailedStorageGroup(oidtest.ID())
return &x
}

View file

@ -5,18 +5,18 @@ import (
"errors"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/acl"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "github.com/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "github.com/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"github.com/TrueCloudLab/frostfs-sdk-go/eacl"
"github.com/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
)
// Token represents bearer token for object service operations.
//
// Token is mutually compatible with github.com/TrueCloudLab/frostfs-api-go/v2/acl.BearerToken
// Token is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl.BearerToken
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
@ -32,6 +32,8 @@ type Token struct {
sigSet bool
sig refs.Signature
impersonate bool
}
// reads Token from the acl.BearerToken message. If checkFieldPresence is set,
@ -44,10 +46,12 @@ func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
return errors.New("missing token body")
}
b.impersonate = body.GetImpersonate()
eaclTable := body.GetEACL()
if b.eaclTableSet = eaclTable != nil; b.eaclTableSet {
b.eaclTable = *eacl.NewTableFromV2(eaclTable)
} else if checkFieldPresence {
} else if checkFieldPresence && !b.impersonate {
return errors.New("missing eACL table")
}
@ -86,7 +90,7 @@ func (b *Token) ReadFromV2(m acl.BearerToken) error {
}
func (b Token) fillBody() *acl.BearerTokenBody {
if !b.eaclTableSet && !b.targetUserSet && !b.lifetimeSet {
if !b.eaclTableSet && !b.targetUserSet && !b.lifetimeSet && !b.impersonate {
return nil
}
@ -112,6 +116,8 @@ func (b Token) fillBody() *acl.BearerTokenBody {
body.SetLifetime(&lifetime)
}
body.SetImpersonate(b.impersonate)
return &body
}
@ -208,6 +214,17 @@ func (b Token) EACLTable() eacl.Table {
return eacl.Table{}
}
// SetImpersonate mark token as impersonate to consider token signer as request owner.
// If this field is true extended EACLTable in token body isn't processed.
func (b *Token) SetImpersonate(v bool) {
b.impersonate = v
}
// Impersonate returns true if token is impersonated.
func (b Token) Impersonate() bool {
return b.impersonate
}
// AssertContainer checks if the token is valid within the given container.
//
// Note: cnr is assumed to refer to the issuer's container, otherwise the check

View file

@ -5,17 +5,17 @@ import (
"math/rand"
"testing"
"github.com/TrueCloudLab/frostfs-api-go/v2/acl"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"github.com/TrueCloudLab/frostfs-sdk-go/bearer"
bearertest "github.com/TrueCloudLab/frostfs-sdk-go/bearer/test"
cidtest "github.com/TrueCloudLab/frostfs-sdk-go/container/id/test"
frostfscrypto "github.com/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "github.com/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"github.com/TrueCloudLab/frostfs-sdk-go/eacl"
eacltest "github.com/TrueCloudLab/frostfs-sdk-go/eacl/test"
"github.com/TrueCloudLab/frostfs-sdk-go/user"
usertest "github.com/TrueCloudLab/frostfs-sdk-go/user/test"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
bearertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer/test"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
eacltest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
)
@ -323,6 +323,10 @@ func TestToken_ReadFromV2(t *testing.T) {
require.NoError(t, val.ReadFromV2(m))
body.SetEACL(nil)
body.SetImpersonate(true)
require.NoError(t, val.ReadFromV2(m))
var m2 acl.BearerToken
val.WriteToV2(&m2)

View file

@ -22,7 +22,7 @@ Bearer token must be signed by owner of the container.
Provide signed token in JSON or binary format to the request sender. Request
sender can attach this bearer token to the object service requests:
import sdkClient "github.com/TrueCloudLab/frostfs-sdk-go/client"
import sdkClient "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
var headParams sdkClient.PrmObjectHead
headParams.WithBearerToken(bearerToken)

View file

@ -1,9 +1,9 @@
package bearertest
import (
"github.com/TrueCloudLab/frostfs-sdk-go/bearer"
eacltest "github.com/TrueCloudLab/frostfs-sdk-go/eacl/test"
usertest "github.com/TrueCloudLab/frostfs-sdk-go/user/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
eacltest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl/test"
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
)
// Token returns random bearer.Token.

View file

@ -6,13 +6,13 @@ import (
"errors"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"github.com/TrueCloudLab/tzhash/tz"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/tzhash/tz"
)
// Checksum represents checksum of some digital data.
//
// Checksum is mutually compatible with github.com/TrueCloudLab/frostfs-api-go/v2/refs.Checksum
// Checksum is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.Checksum
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.

View file

@ -5,8 +5,8 @@ import (
"crypto/sha256"
"testing"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"github.com/TrueCloudLab/tzhash/tz"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/tzhash/tz"
"github.com/stretchr/testify/require"
)

View file

@ -6,7 +6,7 @@ import (
"fmt"
"math/rand"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
)
func ExampleCalculate() {

View file

@ -5,7 +5,7 @@ Note that importing the package into source files is highly discouraged.
Random instance generation functions can be useful when testing expects any value, e.g.:
import checksumtest "github.com/TrueCloudLab/frostfs-sdk-go/checksum/test"
import checksumtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum/test"
cs := checksumtest.Checksum()
// test the value

View file

@ -4,7 +4,7 @@ import (
"crypto/sha256"
"math/rand"
"github.com/TrueCloudLab/frostfs-sdk-go/checksum"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
)
// Checksum returns random checksum.Checksum.

View file

@ -3,12 +3,12 @@ package client
import (
"context"
v2accounting "github.com/TrueCloudLab/frostfs-api-go/v2/accounting"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"github.com/TrueCloudLab/frostfs-sdk-go/accounting"
"github.com/TrueCloudLab/frostfs-sdk-go/user"
v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/accounting"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
)
// PrmBalanceGet groups parameters of BalanceGet operation.
@ -46,17 +46,14 @@ func (x ResBalanceGet) Amount() accounting.Decimal {
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmBalanceGet docs).
// Returns an error if parameters are set incorrectly (see PrmBalanceGet docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalanceGet, error) {
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.accountSet:
panic("account not set")
if !prm.accountSet {
return nil, errorAccountNotSet
}
// form request body

View file

@ -4,9 +4,9 @@ import (
"context"
"fmt"
v2netmap "github.com/TrueCloudLab/frostfs-api-go/v2/netmap"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
)
// interface of FrostFS API server. Exists for test purposes only.

View file

@ -7,9 +7,10 @@ import (
"errors"
"time"
v2accounting "github.com/TrueCloudLab/frostfs-api-go/v2/accounting"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"google.golang.org/grpc"
)
// Client represents virtual connection to the FrostFS network to communicate
@ -69,21 +70,21 @@ func (c *Client) Init(prm PrmInit) {
// argument, otherwise context.Background() is used. Dial returns context
// errors, see context package docs for details.
//
// Panics if required parameters are set incorrectly, look carefully
// Returns an error if required parameters are set incorrectly, look carefully
// at the method documentation.
//
// One-time method call during application start-up stage (after Init ) is expected.
// Calling multiple times leads to undefined behavior.
//
// See also Init / Close.
func (c *Client) Dial(prm PrmDial) error {
func (c *Client) Dial(ctx context.Context, prm PrmDial) error {
if prm.endpoint == "" {
panic("server address is unset or empty")
return errorServerAddrUnset
}
if prm.timeoutDialSet {
if prm.timeoutDial <= 0 {
panic("non-positive timeout")
return errorNonPositiveTimeout
}
} else {
prm.timeoutDial = 5 * time.Second
@ -91,7 +92,7 @@ func (c *Client) Dial(prm PrmDial) error {
if prm.streamTimeoutSet {
if prm.streamTimeout <= 0 {
panic("non-positive timeout")
return errorNonPositiveTimeout
}
} else {
prm.streamTimeout = 10 * time.Second
@ -101,17 +102,14 @@ func (c *Client) Dial(prm PrmDial) error {
client.WithNetworkURIAddress(prm.endpoint, prm.tlsConfig),
client.WithDialTimeout(prm.timeoutDial),
client.WithRWTimeout(prm.streamTimeout),
client.WithGRPCDialOptions(prm.dialOptions),
)...)
c.setFrostFSAPIServer((*coreServer)(&c.c))
if prm.parentCtx == nil {
prm.parentCtx = context.Background()
}
// TODO: (neofs-api-go#382) perform generic dial stage of the client.Client
_, err := rpc.Balance(&c.c, new(v2accounting.BalanceRequest),
client.WithContext(prm.parentCtx),
client.WithContext(ctx),
)
// return context errors since they signal about dial problem
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
@ -123,7 +121,7 @@ func (c *Client) Dial(prm PrmDial) error {
// sets underlying provider of frostFSAPIServer. The method is used for testing as an approach
// to skip Dial stage and override FrostFS API server. MUST NOT be used outside test code.
// In real applications wrapper over github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client
// In real applications wrapper over git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client
// is statically used.
func (c *Client) setFrostFSAPIServer(server frostFSAPIServer) {
c.server = server
@ -191,7 +189,7 @@ type PrmDial struct {
streamTimeoutSet bool
streamTimeout time.Duration
parentCtx context.Context
dialOptions []grpc.DialOption
}
// SetServerURI sets server URI in the FrostFS network.
@ -233,10 +231,7 @@ func (x *PrmDial) SetStreamTimeout(timeout time.Duration) {
x.streamTimeout = timeout
}
// SetContext allows to specify optional base context within which connection
// should be established.
//
// Context SHOULD NOT be nil.
func (x *PrmDial) SetContext(ctx context.Context) {
x.parentCtx = ctx
// SetGRPCDialOptions sets the gRPC dial options for new gRPC client connection.
func (x *PrmDial) SetGRPCDialOptions(opts ...grpc.DialOption) {
x.dialOptions = opts
}

View file

@ -7,7 +7,7 @@ import (
"crypto/rand"
"testing"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/stretchr/testify/require"
)
@ -47,11 +47,8 @@ func TestClient_DialContext(t *testing.T) {
prm.SetServerURI("localhost:8080")
assert := func(ctx context.Context, errExpected error) {
// use the particular context
prm.SetContext(ctx)
// expect particular context error according to Dial docs
require.ErrorIs(t, c.Dial(prm), errExpected)
require.ErrorIs(t, c.Dial(ctx, prm), errExpected)
}
// create pre-abandoned context

View file

@ -2,14 +2,15 @@ package client
import (
"crypto/ecdsa"
"errors"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/TrueCloudLab/frostfs-sdk-go/version"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
)
// common interface of resulting structures with API status.
@ -70,11 +71,17 @@ func writeXHeadersToMeta(xHeaders []string, h *v2session.RequestMetaHeader) {
h.SetXHeaders(hs)
}
// panic messages.
const (
panicMsgMissingContext = "missing context"
panicMsgMissingContainer = "missing container"
panicMsgMissingObject = "missing object"
// error messages.
var (
errorMissingContainer = errors.New("missing container")
errorMissingObject = errors.New("missing object")
errorAccountNotSet = errors.New("account not set")
errorServerAddrUnset = errors.New("server address is unset or empty")
errorNonPositiveTimeout = errors.New("non-positive timeout")
errorEACLTableNotSet = errors.New("eACL table not set")
errorMissingAnnouncements = errors.New("missing announcements")
errorZeroRangeLength = errors.New("zero range length")
errorMissingRanges = errors.New("missing ranges")
)
// groups all the details required to send a single request and process a response to it.
@ -250,6 +257,16 @@ func (x *contextCall) processResponse() bool {
// processResponse verifies response signature and converts status to an error if needed.
func (c *Client) processResponse(resp responseV2) (apistatus.Status, error) {
if c.prm.cbRespInfo != nil {
rmi := ResponseMetaInfo{
key: resp.GetVerificationHeader().GetBodySignature().GetKey(),
epoch: resp.GetMetaHeader().GetEpoch(),
}
if err := c.prm.cbRespInfo(rmi); err != nil {
return nil, fmt.Errorf("response callback error: %w", err)
}
}
err := signature.VerifyServiceMessage(resp)
if err != nil {
return nil, fmt.Errorf("invalid response signature: %w", err)
@ -334,7 +351,7 @@ func (c *Client) initCallContext(ctx *contextCall) {
ctx.netMagic = c.prm.netMagic
}
// ExecRaw executes f with underlying github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client.Client
// ExecRaw executes f with underlying git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client.Client
// instance. Communicate over the Protocol Buffers protocol in a more flexible way:
// most often used to transmit data over a fixed version of the FrostFS protocol, as well
// as to support custom services.
@ -345,7 +362,7 @@ func (c *Client) initCallContext(ctx *contextCall) {
// before closing the connection.
//
// See also Dial and Close.
// See also github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client package docs.
// See also git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client package docs.
func (c *Client) ExecRaw(f func(client *client.Client) error) error {
return f(&c.c)
}

View file

@ -2,803 +2,11 @@ package client
import (
"context"
"errors"
"fmt"
v2container "github.com/TrueCloudLab/frostfs-api-go/v2/container"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-sdk-go/container"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "github.com/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "github.com/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"github.com/TrueCloudLab/frostfs-sdk-go/eacl"
"github.com/TrueCloudLab/frostfs-sdk-go/session"
"github.com/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
)
// PrmContainerPut groups parameters of ContainerPut operation.
type PrmContainerPut struct {
prmCommonMeta
cnrSet bool
cnr container.Container
sessionSet bool
session session.Container
}
// SetContainer sets structured information about new FrostFS container.
// Required parameter.
func (x *PrmContainerPut) SetContainer(cnr container.Container) {
x.cnr = cnr
x.cnrSet = true
}
// WithinSession specifies session within which container should be saved.
//
// Creator of the session acquires the authorship of the request. This affects
// the execution of an operation (e.g. access control).
//
// Session is optional, if set the following requirements apply:
// - session operation MUST be session.VerbContainerPut (ForVerb)
// - token MUST be signed using private key of the owner of the container to be saved
func (x *PrmContainerPut) WithinSession(s session.Container) {
x.session = s
x.sessionSet = true
}
// ResContainerPut groups resulting values of ContainerPut operation.
type ResContainerPut struct {
statusRes
id cid.ID
}
// ID returns identifier of the container declared to be stored in the system.
// Used as a link to information about the container (in particular, you can
// asynchronously check if the save was successful).
func (x ResContainerPut) ID() cid.ID {
return x.id
}
// ContainerPut sends request to save container in FrostFS.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// Success can be verified by reading by identifier (see ResContainerPut.ID).
//
// Immediately panics if parameters are set incorrectly (see PrmContainerPut docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResContainerPut, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.cnrSet:
panic(panicMsgMissingContainer)
}
// TODO: check private key is set before forming the request
// sign container
var cnr v2container.Container
prm.cnr.WriteToV2(&cnr)
var sig frostfscrypto.Signature
err := container.CalculateSignature(&sig, prm.cnr, c.prm.key)
if err != nil {
return nil, fmt.Errorf("calculate container signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
// form request body
reqBody := new(v2container.PutRequestBody)
reqBody.SetContainer(&cnr)
reqBody.SetSignature(&sigv2)
// form meta header
var meta v2session.RequestMetaHeader
writeXHeadersToMeta(prm.prmCommonMeta.xHeaders, &meta)
if prm.sessionSet {
var tokv2 v2session.Token
prm.session.WriteToV2(&tokv2)
meta.SetSessionToken(&tokv2)
}
// form request
var req v2container.PutRequest
req.SetBody(reqBody)
req.SetMetaHeader(&meta)
// init call context
var (
cc contextCall
res ResContainerPut
)
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.PutContainer(&c.c, &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2container.PutResponse)
const fieldCnrID = "container ID"
cidV2 := resp.GetBody().GetContainerID()
if cidV2 == nil {
cc.err = newErrMissingResponseField(fieldCnrID)
return
}
cc.err = res.id.ReadFromV2(*cidV2)
if cc.err != nil {
cc.err = newErrInvalidResponseField(fieldCnrID, cc.err)
}
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// PrmContainerGet groups parameters of ContainerGet operation.
type PrmContainerGet struct {
prmCommonMeta
idSet bool
id cid.ID
}
// SetContainer sets identifier of the container to be read.
// Required parameter.
func (x *PrmContainerGet) SetContainer(id cid.ID) {
x.id = id
x.idSet = true
}
// ResContainerGet groups resulting values of ContainerGet operation.
type ResContainerGet struct {
statusRes
cnr container.Container
}
// Container returns structured information about the requested container.
//
// Client doesn't retain value so modification is safe.
func (x ResContainerGet) Container() container.Container {
return x.cnr
}
// ContainerGet reads FrostFS container by ID.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmContainerGet docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs);
// - *apistatus.ContainerNotFound.
func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResContainerGet, error) {
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.idSet:
panic(panicMsgMissingContainer)
}
var cidV2 refs.ContainerID
prm.id.WriteToV2(&cidV2)
// form request body
reqBody := new(v2container.GetRequestBody)
reqBody.SetContainerID(&cidV2)
// form request
var req v2container.GetRequest
req.SetBody(reqBody)
// init call context
var (
cc contextCall
res ResContainerGet
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.GetContainer(&c.c, &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2container.GetResponse)
cnrV2 := resp.GetBody().GetContainer()
if cnrV2 == nil {
cc.err = errors.New("missing container in response")
return
}
cc.err = res.cnr.ReadFromV2(*cnrV2)
if cc.err != nil {
cc.err = fmt.Errorf("invalid container in response: %w", cc.err)
}
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// PrmContainerList groups parameters of ContainerList operation.
type PrmContainerList struct {
prmCommonMeta
ownerSet bool
ownerID user.ID
}
// SetAccount sets identifier of the FrostFS account to list the containers.
// Required parameter.
func (x *PrmContainerList) SetAccount(id user.ID) {
x.ownerID = id
x.ownerSet = true
}
// ResContainerList groups resulting values of ContainerList operation.
type ResContainerList struct {
statusRes
ids []cid.ID
}
// Containers returns list of identifiers of the account-owned containers.
//
// Client doesn't retain value so modification is safe.
func (x ResContainerList) Containers() []cid.ID {
return x.ids
}
// ContainerList requests identifiers of the account-owned containers.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmContainerList docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) ContainerList(ctx context.Context, prm PrmContainerList) (*ResContainerList, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.ownerSet:
panic("account not set")
}
// form request body
var ownerV2 refs.OwnerID
prm.ownerID.WriteToV2(&ownerV2)
reqBody := new(v2container.ListRequestBody)
reqBody.SetOwnerID(&ownerV2)
// form request
var req v2container.ListRequest
req.SetBody(reqBody)
// init call context
var (
cc contextCall
res ResContainerList
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.ListContainers(&c.c, &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2container.ListResponse)
res.ids = make([]cid.ID, len(resp.GetBody().GetContainerIDs()))
for i, cidV2 := range resp.GetBody().GetContainerIDs() {
cc.err = res.ids[i].ReadFromV2(cidV2)
if cc.err != nil {
cc.err = fmt.Errorf("invalid ID in the response: %w", cc.err)
return
}
}
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// PrmContainerDelete groups parameters of ContainerDelete operation.
type PrmContainerDelete struct {
prmCommonMeta
idSet bool
id cid.ID
tokSet bool
tok session.Container
}
// SetContainer sets identifier of the FrostFS container to be removed.
// Required parameter.
func (x *PrmContainerDelete) SetContainer(id cid.ID) {
x.id = id
x.idSet = true
}
// WithinSession specifies session within which container should be removed.
//
// Creator of the session acquires the authorship of the request.
// This may affect the execution of an operation (e.g. access control).
//
// Must be signed.
func (x *PrmContainerDelete) WithinSession(tok session.Container) {
x.tok = tok
x.tokSet = true
}
// ResContainerDelete groups resulting values of ContainerDelete operation.
type ResContainerDelete struct {
statusRes
}
// ContainerDelete sends request to remove the FrostFS container.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// Success can be verified by reading by identifier (see GetContainer).
//
// Immediately panics if parameters are set incorrectly (see PrmContainerDelete docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ResContainerDelete.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
//
// Return statuses:
// - global (see Client docs).
func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) (*ResContainerDelete, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.idSet:
panic(panicMsgMissingContainer)
}
// sign container ID
var cidV2 refs.ContainerID
prm.id.WriteToV2(&cidV2)
// container contract expects signature of container ID value
// don't get confused with stable marshaled protobuf container.ID structure
data := cidV2.GetValue()
var sig frostfscrypto.Signature
err := sig.Calculate(frostfsecdsa.SignerRFC6979(c.prm.key), data)
if err != nil {
return nil, fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
// form request body
reqBody := new(v2container.DeleteRequestBody)
reqBody.SetContainerID(&cidV2)
reqBody.SetSignature(&sigv2)
// form meta header
var meta v2session.RequestMetaHeader
writeXHeadersToMeta(prm.prmCommonMeta.xHeaders, &meta)
if prm.tokSet {
var tokv2 v2session.Token
prm.tok.WriteToV2(&tokv2)
meta.SetSessionToken(&tokv2)
}
// form request
var req v2container.DeleteRequest
req.SetBody(reqBody)
req.SetMetaHeader(&meta)
// init call context
var (
cc contextCall
res ResContainerDelete
)
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.DeleteContainer(&c.c, &req, client.WithContext(ctx))
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// PrmContainerEACL groups parameters of ContainerEACL operation.
type PrmContainerEACL struct {
prmCommonMeta
idSet bool
id cid.ID
}
// SetContainer sets identifier of the FrostFS container to read the eACL table.
// Required parameter.
func (x *PrmContainerEACL) SetContainer(id cid.ID) {
x.id = id
x.idSet = true
}
// ResContainerEACL groups resulting values of ContainerEACL operation.
type ResContainerEACL struct {
statusRes
table eacl.Table
}
// Table returns eACL table of the requested container.
func (x ResContainerEACL) Table() eacl.Table {
return x.table
}
// ContainerEACL reads eACL table of the FrostFS container.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmContainerEACL docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs);
// - *apistatus.ContainerNotFound;
// - *apistatus.EACLNotFound.
func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResContainerEACL, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.idSet:
panic(panicMsgMissingContainer)
}
var cidV2 refs.ContainerID
prm.id.WriteToV2(&cidV2)
// form request body
reqBody := new(v2container.GetExtendedACLRequestBody)
reqBody.SetContainerID(&cidV2)
// form request
var req v2container.GetExtendedACLRequest
req.SetBody(reqBody)
// init call context
var (
cc contextCall
res ResContainerEACL
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.GetEACL(&c.c, &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2container.GetExtendedACLResponse)
eACL := resp.GetBody().GetEACL()
if eACL == nil {
cc.err = newErrMissingResponseField("eACL")
return
}
res.table = *eacl.NewTableFromV2(eACL)
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// PrmContainerSetEACL groups parameters of ContainerSetEACL operation.
type PrmContainerSetEACL struct {
prmCommonMeta
tableSet bool
table eacl.Table
sessionSet bool
session session.Container
}
// SetTable sets eACL table structure to be set for the container.
// Required parameter.
func (x *PrmContainerSetEACL) SetTable(table eacl.Table) {
x.table = table
x.tableSet = true
}
// WithinSession specifies session within which extended ACL of the container
// should be saved.
//
// Creator of the session acquires the authorship of the request. This affects
// the execution of an operation (e.g. access control).
//
// Session is optional, if set the following requirements apply:
// - if particular container is specified (ApplyOnlyTo), it MUST equal the container
// for which extended ACL is going to be set
// - session operation MUST be session.VerbContainerSetEACL (ForVerb)
// - token MUST be signed using private key of the owner of the container to be saved
func (x *PrmContainerSetEACL) WithinSession(s session.Container) {
x.session = s
x.sessionSet = true
}
// ResContainerSetEACL groups resulting values of ContainerSetEACL operation.
type ResContainerSetEACL struct {
statusRes
}
// ContainerSetEACL sends request to update eACL table of the FrostFS container.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// Success can be verified by reading by identifier (see EACL).
//
// Immediately panics if parameters are set incorrectly (see PrmContainerSetEACL docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) (*ResContainerSetEACL, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.tableSet:
panic("eACL table not set")
}
// sign the eACL table
eaclV2 := prm.table.ToV2()
var sig frostfscrypto.Signature
err := sig.Calculate(frostfsecdsa.SignerRFC6979(c.prm.key), eaclV2.StableMarshal(nil))
if err != nil {
return nil, fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
// form request body
reqBody := new(v2container.SetExtendedACLRequestBody)
reqBody.SetEACL(eaclV2)
reqBody.SetSignature(&sigv2)
// form meta header
var meta v2session.RequestMetaHeader
writeXHeadersToMeta(prm.prmCommonMeta.xHeaders, &meta)
if prm.sessionSet {
var tokv2 v2session.Token
prm.session.WriteToV2(&tokv2)
meta.SetSessionToken(&tokv2)
}
// form request
var req v2container.SetExtendedACLRequest
req.SetBody(reqBody)
req.SetMetaHeader(&meta)
// init call context
var (
cc contextCall
res ResContainerSetEACL
)
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.SetEACL(&c.c, &req, client.WithContext(ctx))
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// PrmAnnounceSpace groups parameters of ContainerAnnounceUsedSpace operation.
type PrmAnnounceSpace struct {
prmCommonMeta
announcements []container.SizeEstimation
}
// SetValues sets values describing volume of space that is used for the container objects.
// Required parameter. Must not be empty.
//
// Must not be mutated before the end of the operation.
func (x *PrmAnnounceSpace) SetValues(vs []container.SizeEstimation) {
x.announcements = vs
}
// ResAnnounceSpace groups resulting values of ContainerAnnounceUsedSpace operation.
type ResAnnounceSpace struct {
statusRes
}
// ContainerAnnounceUsedSpace sends request to announce volume of the space used for the container objects.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// At this moment success can not be checked.
//
// Immediately panics if parameters are set incorrectly (see PrmAnnounceSpace docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) ContainerAnnounceUsedSpace(ctx context.Context, prm PrmAnnounceSpace) (*ResAnnounceSpace, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case len(prm.announcements) == 0:
panic("missing announcements")
}
// convert list of SDK announcement structures into FrostFS-API v2 list
v2announce := make([]v2container.UsedSpaceAnnouncement, len(prm.announcements))
for i := range prm.announcements {
prm.announcements[i].WriteToV2(&v2announce[i])
}
// prepare body of the FrostFS-API v2 request and request itself
reqBody := new(v2container.AnnounceUsedSpaceRequestBody)
reqBody.SetAnnouncements(v2announce)
// form request
var req v2container.AnnounceUsedSpaceRequest
req.SetBody(reqBody)
// init call context
var (
cc contextCall
res ResAnnounceSpace
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.AnnounceUsedSpace(&c.c, &req, client.WithContext(ctx))
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// SyncContainerWithNetwork requests network configuration using passed client
// and applies it to the container. Container MUST not be nil.
//

134
client/container_delete.go Normal file
View file

@ -0,0 +1,134 @@
package client
import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
)
// PrmContainerDelete groups parameters of ContainerDelete operation.
type PrmContainerDelete struct {
prmCommonMeta
idSet bool
id cid.ID
tokSet bool
tok session.Container
}
// SetContainer sets identifier of the FrostFS container to be removed.
// Required parameter.
func (x *PrmContainerDelete) SetContainer(id cid.ID) {
x.id = id
x.idSet = true
}
func (x *PrmContainerDelete) buildRequest(c *Client) (*v2container.DeleteRequest, error) {
if !x.idSet {
return nil, errorMissingContainer
}
var cidV2 refs.ContainerID
x.id.WriteToV2(&cidV2)
// Container contract expects signature of container ID value,
// don't get confused with stable marshaled protobuf container.ID structure.
data := cidV2.GetValue()
var sig frostfscrypto.Signature
err := sig.Calculate(frostfsecdsa.SignerRFC6979(c.prm.key), data)
if err != nil {
return nil, fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
reqBody := new(v2container.DeleteRequestBody)
reqBody.SetContainerID(&cidV2)
reqBody.SetSignature(&sigv2)
var meta v2session.RequestMetaHeader
writeXHeadersToMeta(x.prmCommonMeta.xHeaders, &meta)
if x.tokSet {
var tokv2 v2session.Token
x.tok.WriteToV2(&tokv2)
meta.SetSessionToken(&tokv2)
}
var req v2container.DeleteRequest
req.SetBody(reqBody)
c.prepareRequest(&req, &meta)
return &req, nil
}
// WithinSession specifies session within which container should be removed.
//
// Creator of the session acquires the authorship of the request.
// This may affect the execution of an operation (e.g. access control).
//
// Must be signed.
func (x *PrmContainerDelete) WithinSession(tok session.Container) {
x.tok = tok
x.tokSet = true
}
// ResContainerDelete groups resulting values of ContainerDelete operation.
type ResContainerDelete struct {
statusRes
}
// ContainerDelete sends request to remove the FrostFS container.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// Success can be verified by reading by identifier (see GetContainer).
//
// Returns an error if parameters are set incorrectly (see PrmContainerDelete docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ResContainerDelete.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
//
// Return statuses:
// - global (see Client docs).
func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) (*ResContainerDelete, error) {
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := rpcapi.DeleteContainer(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResContainerDelete
res.st, err = c.processResponse(resp)
return &res, err
}

105
client/container_eacl.go Normal file
View file

@ -0,0 +1,105 @@
package client
import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
)
// PrmContainerEACL groups parameters of ContainerEACL operation.
type PrmContainerEACL struct {
prmCommonMeta
idSet bool
id cid.ID
}
// SetContainer sets identifier of the FrostFS container to read the eACL table.
// Required parameter.
func (x *PrmContainerEACL) SetContainer(id cid.ID) {
x.id = id
x.idSet = true
}
func (x *PrmContainerEACL) buildRequest(c *Client) (*v2container.GetExtendedACLRequest, error) {
if !x.idSet {
return nil, errorMissingContainer
}
var cidV2 refs.ContainerID
x.id.WriteToV2(&cidV2)
reqBody := new(v2container.GetExtendedACLRequestBody)
reqBody.SetContainerID(&cidV2)
var req v2container.GetExtendedACLRequest
req.SetBody(reqBody)
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
return &req, nil
}
// ResContainerEACL groups resulting values of ContainerEACL operation.
type ResContainerEACL struct {
statusRes
table eacl.Table
}
// Table returns eACL table of the requested container.
func (x ResContainerEACL) Table() eacl.Table {
return x.table
}
// ContainerEACL reads eACL table of the FrostFS container.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Returns an error if parameters are set incorrectly (see PrmContainerEACL docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs);
// - *apistatus.ContainerNotFound;
// - *apistatus.EACLNotFound.
func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResContainerEACL, error) {
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := rpcapi.GetEACL(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResContainerEACL
res.st, err = c.processResponse(resp)
if err != nil || !apistatus.IsSuccessful(res.st) {
return &res, err
}
eACL := resp.GetBody().GetEACL()
if eACL == nil {
return &res, newErrMissingResponseField("eACL")
}
res.table = *eacl.NewTableFromV2(eACL)
return &res, nil
}

108
client/container_get.go Normal file
View file

@ -0,0 +1,108 @@
package client
import (
"context"
"errors"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
)
// PrmContainerGet groups parameters of ContainerGet operation.
type PrmContainerGet struct {
prmCommonMeta
idSet bool
id cid.ID
}
// SetContainer sets identifier of the container to be read.
// Required parameter.
func (x *PrmContainerGet) SetContainer(id cid.ID) {
x.id = id
x.idSet = true
}
func (x *PrmContainerGet) buildRequest(c *Client) (*v2container.GetRequest, error) {
if !x.idSet {
return nil, errorMissingContainer
}
var cidV2 refs.ContainerID
x.id.WriteToV2(&cidV2)
reqBody := new(v2container.GetRequestBody)
reqBody.SetContainerID(&cidV2)
var req v2container.GetRequest
req.SetBody(reqBody)
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
return &req, nil
}
// ResContainerGet groups resulting values of ContainerGet operation.
type ResContainerGet struct {
statusRes
cnr container.Container
}
// Container returns structured information about the requested container.
//
// Client doesn't retain value so modification is safe.
func (x ResContainerGet) Container() container.Container {
return x.cnr
}
// ContainerGet reads FrostFS container by ID.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Returns an error if parameters are set incorrectly (see PrmContainerGet docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs);
// - *apistatus.ContainerNotFound.
func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResContainerGet, error) {
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := rpcapi.GetContainer(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResContainerGet
res.st, err = c.processResponse(resp)
if err != nil || !apistatus.IsSuccessful(res.st) {
return &res, err
}
cnrV2 := resp.GetBody().GetContainer()
if cnrV2 == nil {
return &res, errors.New("missing container in response")
}
if err := res.cnr.ReadFromV2(*cnrV2); err != nil {
return &res, fmt.Errorf("invalid container in response: %w", err)
}
return &res, nil
}

106
client/container_list.go Normal file
View file

@ -0,0 +1,106 @@
package client
import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
)
// PrmContainerList groups parameters of ContainerList operation.
type PrmContainerList struct {
prmCommonMeta
ownerSet bool
ownerID user.ID
}
// SetAccount sets identifier of the FrostFS account to list the containers.
// Required parameter.
func (x *PrmContainerList) SetAccount(id user.ID) {
x.ownerID = id
x.ownerSet = true
}
func (x *PrmContainerList) buildRequest(c *Client) (*v2container.ListRequest, error) {
if !x.ownerSet {
return nil, errorAccountNotSet
}
var ownerV2 refs.OwnerID
x.ownerID.WriteToV2(&ownerV2)
reqBody := new(v2container.ListRequestBody)
reqBody.SetOwnerID(&ownerV2)
var req v2container.ListRequest
req.SetBody(reqBody)
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
return &req, nil
}
// ResContainerList groups resulting values of ContainerList operation.
type ResContainerList struct {
statusRes
ids []cid.ID
}
// Containers returns list of identifiers of the account-owned containers.
//
// Client doesn't retain value so modification is safe.
func (x ResContainerList) Containers() []cid.ID {
return x.ids
}
// ContainerList requests identifiers of the account-owned containers.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Returns an error if parameters are set incorrectly (see PrmContainerList docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) ContainerList(ctx context.Context, prm PrmContainerList) (*ResContainerList, error) {
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := rpcapi.ListContainers(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResContainerList
res.st, err = c.processResponse(resp)
if err != nil || !apistatus.IsSuccessful(res.st) {
return &res, err
}
res.ids = make([]cid.ID, len(resp.GetBody().GetContainerIDs()))
for i, cidV2 := range resp.GetBody().GetContainerIDs() {
if err := res.ids[i].ReadFromV2(cidV2); err != nil {
return &res, fmt.Errorf("invalid ID in the response: %w", err)
}
}
return &res, nil
}

155
client/container_put.go Normal file
View file

@ -0,0 +1,155 @@
package client
import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
)
// PrmContainerPut groups parameters of ContainerPut operation.
type PrmContainerPut struct {
prmCommonMeta
cnrSet bool
cnr container.Container
sessionSet bool
session session.Container
}
// SetContainer sets structured information about new FrostFS container.
// Required parameter.
func (x *PrmContainerPut) SetContainer(cnr container.Container) {
x.cnr = cnr
x.cnrSet = true
}
// WithinSession specifies session within which container should be saved.
//
// Creator of the session acquires the authorship of the request. This affects
// the execution of an operation (e.g. access control).
//
// Session is optional, if set the following requirements apply:
// - session operation MUST be session.VerbContainerPut (ForVerb)
// - token MUST be signed using private key of the owner of the container to be saved
func (x *PrmContainerPut) WithinSession(s session.Container) {
x.session = s
x.sessionSet = true
}
func (x *PrmContainerPut) buildRequest(c *Client) (*v2container.PutRequest, error) {
if !x.cnrSet {
return nil, errorMissingContainer
}
// TODO: check private key is set before forming the request
var cnr v2container.Container
x.cnr.WriteToV2(&cnr)
var sig frostfscrypto.Signature
err := container.CalculateSignature(&sig, x.cnr, c.prm.key)
if err != nil {
return nil, fmt.Errorf("calculate container signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
reqBody := new(v2container.PutRequestBody)
reqBody.SetContainer(&cnr)
reqBody.SetSignature(&sigv2)
var meta v2session.RequestMetaHeader
writeXHeadersToMeta(x.prmCommonMeta.xHeaders, &meta)
if x.sessionSet {
var tokv2 v2session.Token
x.session.WriteToV2(&tokv2)
meta.SetSessionToken(&tokv2)
}
var req v2container.PutRequest
req.SetBody(reqBody)
c.prepareRequest(&req, &meta)
return &req, nil
}
// ResContainerPut groups resulting values of ContainerPut operation.
type ResContainerPut struct {
statusRes
id cid.ID
}
// ID returns identifier of the container declared to be stored in the system.
// Used as a link to information about the container (in particular, you can
// asynchronously check if the save was successful).
func (x ResContainerPut) ID() cid.ID {
return x.id
}
// ContainerPut sends request to save container in FrostFS.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// Success can be verified by reading by identifier (see ResContainerPut.ID).
//
// Returns an error if parameters are set incorrectly (see PrmContainerPut docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
//
// nolint: funlen
func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResContainerPut, error) {
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := rpcapi.PutContainer(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResContainerPut
res.st, err = c.processResponse(resp)
if err != nil || !apistatus.IsSuccessful(res.st) {
return &res, err
}
const fieldCnrID = "container ID"
cidV2 := resp.GetBody().GetContainerID()
if cidV2 == nil {
return &res, newErrMissingResponseField(fieldCnrID)
}
if err := res.id.ReadFromV2(*cidV2); err != nil {
return &res, newErrInvalidResponseField(fieldCnrID, err)
}
return &res, nil
}

View file

@ -0,0 +1,131 @@
package client
import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
)
// PrmContainerSetEACL groups parameters of ContainerSetEACL operation.
type PrmContainerSetEACL struct {
prmCommonMeta
tableSet bool
table eacl.Table
sessionSet bool
session session.Container
}
// SetTable sets eACL table structure to be set for the container.
// Required parameter.
func (x *PrmContainerSetEACL) SetTable(table eacl.Table) {
x.table = table
x.tableSet = true
}
// WithinSession specifies session within which extended ACL of the container
// should be saved.
//
// Creator of the session acquires the authorship of the request. This affects
// the execution of an operation (e.g. access control).
//
// Session is optional, if set the following requirements apply:
// - if particular container is specified (ApplyOnlyTo), it MUST equal the container
// for which extended ACL is going to be set
// - session operation MUST be session.VerbContainerSetEACL (ForVerb)
// - token MUST be signed using private key of the owner of the container to be saved
func (x *PrmContainerSetEACL) WithinSession(s session.Container) {
x.session = s
x.sessionSet = true
}
func (x *PrmContainerSetEACL) buildRequest(c *Client) (*v2container.SetExtendedACLRequest, error) {
if !x.tableSet {
return nil, errorEACLTableNotSet
}
eaclV2 := x.table.ToV2()
var sig frostfscrypto.Signature
err := sig.Calculate(frostfsecdsa.SignerRFC6979(c.prm.key), eaclV2.StableMarshal(nil))
if err != nil {
return nil, fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
reqBody := new(v2container.SetExtendedACLRequestBody)
reqBody.SetEACL(eaclV2)
reqBody.SetSignature(&sigv2)
var meta v2session.RequestMetaHeader
writeXHeadersToMeta(x.prmCommonMeta.xHeaders, &meta)
if x.sessionSet {
var tokv2 v2session.Token
x.session.WriteToV2(&tokv2)
meta.SetSessionToken(&tokv2)
}
var req v2container.SetExtendedACLRequest
req.SetBody(reqBody)
c.prepareRequest(&req, &meta)
return &req, nil
}
// ResContainerSetEACL groups resulting values of ContainerSetEACL operation.
type ResContainerSetEACL struct {
statusRes
}
// ContainerSetEACL sends request to update eACL table of the FrostFS container.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// Success can be verified by reading by identifier (see EACL).
//
// Returns an error if parameters are set incorrectly (see PrmContainerSetEACL docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) (*ResContainerSetEACL, error) {
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := rpcapi.SetEACL(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResContainerSetEACL
res.st, err = c.processResponse(resp)
return &res, err
}

90
client/container_space.go Normal file
View file

@ -0,0 +1,90 @@
package client
import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
)
// PrmAnnounceSpace groups parameters of ContainerAnnounceUsedSpace operation.
type PrmAnnounceSpace struct {
prmCommonMeta
announcements []container.SizeEstimation
}
// SetValues sets values describing volume of space that is used for the container objects.
// Required parameter. Must not be empty.
//
// Must not be mutated before the end of the operation.
func (x *PrmAnnounceSpace) SetValues(vs []container.SizeEstimation) {
x.announcements = vs
}
func (x *PrmAnnounceSpace) buildRequest(c *Client) (*v2container.AnnounceUsedSpaceRequest, error) {
if len(x.announcements) == 0 {
return nil, errorMissingAnnouncements
}
v2announce := make([]v2container.UsedSpaceAnnouncement, len(x.announcements))
for i := range x.announcements {
x.announcements[i].WriteToV2(&v2announce[i])
}
reqBody := new(v2container.AnnounceUsedSpaceRequestBody)
reqBody.SetAnnouncements(v2announce)
var req v2container.AnnounceUsedSpaceRequest
req.SetBody(reqBody)
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
return &req, nil
}
// ResAnnounceSpace groups resulting values of ContainerAnnounceUsedSpace operation.
type ResAnnounceSpace struct {
statusRes
}
// ContainerAnnounceUsedSpace sends request to announce volume of the space used for the container objects.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// At this moment success can not be checked.
//
// Returns an error if parameters are set incorrectly (see PrmAnnounceSpace docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) ContainerAnnounceUsedSpace(ctx context.Context, prm PrmAnnounceSpace) (*ResAnnounceSpace, error) {
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := rpcapi.AnnounceUsedSpace(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResAnnounceSpace
res.st, err = c.processResponse(resp)
return &res, err
}

View file

@ -47,8 +47,8 @@ Consume custom service of the server:
rpc CustomRPC(CustomRPCRequest) returns (CustomRPCResponse);
}
import "github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
import "github.com/TrueCloudLab/frostfs-api-go/v2/rpc/common"
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/common"
req := new(CustomRPCRequest)
// ...
@ -72,7 +72,7 @@ for the all operations are write-only and the results of the all operations are
read-only. To be able to override client behavior (e.g. for tests), abstract it
with an interface:
import "github.com/TrueCloudLab/frostfs-sdk-go/client"
import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
type FrostFSClient interface {
// Operations according to the application needs

View file

@ -4,7 +4,7 @@ import (
"errors"
"fmt"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
)
// unwraps err using errors.Unwrap and returns the result.

View file

@ -4,8 +4,8 @@ import (
"fmt"
"testing"
"github.com/TrueCloudLab/frostfs-sdk-go/client"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/stretchr/testify/require"
)

View file

@ -4,14 +4,14 @@ import (
"context"
"fmt"
v2netmap "github.com/TrueCloudLab/frostfs-api-go/v2/netmap"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/TrueCloudLab/frostfs-sdk-go/netmap"
"github.com/TrueCloudLab/frostfs-sdk-go/version"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
)
// PrmEndpointInfo groups parameters of EndpointInfo operation.
@ -19,6 +19,16 @@ type PrmEndpointInfo struct {
prmCommonMeta
}
func (x *PrmEndpointInfo) buildRequest(c *Client) (*v2netmap.LocalNodeInfoRequest, error) {
meta := new(v2session.RequestMetaHeader)
writeXHeadersToMeta(x.xHeaders, meta)
req := new(v2netmap.LocalNodeInfoRequest)
req.SetBody(new(v2netmap.LocalNodeInfoRequestBody))
c.prepareRequest(req, meta)
return req, nil
}
// ResEndpointInfo group resulting values of EndpointInfo operation.
type ResEndpointInfo struct {
statusRes
@ -47,7 +57,7 @@ func (x ResEndpointInfo) NodeInfo() netmap.NodeInfo {
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmEndpointInfo docs).
// Returns an error if parameters are set incorrectly (see PrmEndpointInfo docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ResEndpointInfo.
@ -56,30 +66,25 @@ func (x ResEndpointInfo) NodeInfo() netmap.NodeInfo {
// Return statuses:
// - global (see Client docs).
func (c *Client) EndpointInfo(ctx context.Context, prm PrmEndpointInfo) (*ResEndpointInfo, error) {
// check context
if ctx == nil {
panic(panicMsgMissingContext)
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
// form request
var req v2netmap.LocalNodeInfoRequest
// init call context
var (
cc contextCall
res ResEndpointInfo
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.LocalNodeInfo(&c.c, &req, client.WithContext(ctx))
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := rpcapi.LocalNodeInfo(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResEndpointInfo
res.st, err = c.processResponse(resp)
if err != nil || !apistatus.IsSuccessful(res.st) {
return &res, err
}
cc.result = func(r responseV2) {
resp := r.(*v2netmap.LocalNodeInfoResponse)
body := resp.GetBody()
@ -87,36 +92,21 @@ func (c *Client) EndpointInfo(ctx context.Context, prm PrmEndpointInfo) (*ResEnd
verV2 := body.GetVersion()
if verV2 == nil {
cc.err = newErrMissingResponseField(fieldVersion)
return
return nil, newErrMissingResponseField(fieldVersion)
}
cc.err = res.version.ReadFromV2(*verV2)
if cc.err != nil {
cc.err = newErrInvalidResponseField(fieldVersion, cc.err)
return
if err := res.version.ReadFromV2(*verV2); err != nil {
return nil, newErrInvalidResponseField(fieldVersion, err)
}
const fieldNodeInfo = "node info"
nodeInfoV2 := body.GetNodeInfo()
if nodeInfoV2 == nil {
cc.err = newErrMissingResponseField(fieldNodeInfo)
return
return nil, newErrMissingResponseField(fieldNodeInfo)
}
cc.err = res.ni.ReadFromV2(*nodeInfoV2)
if cc.err != nil {
cc.err = newErrInvalidResponseField(fieldNodeInfo, cc.err)
return
if err := res.ni.ReadFromV2(*nodeInfoV2); err != nil {
return nil, newErrInvalidResponseField(fieldNodeInfo, err)
}
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
@ -125,6 +115,16 @@ type PrmNetworkInfo struct {
prmCommonMeta
}
func (x PrmNetworkInfo) buildRequest(c *Client) (*v2netmap.NetworkInfoRequest, error) {
meta := new(v2session.RequestMetaHeader)
writeXHeadersToMeta(x.xHeaders, meta)
var req v2netmap.NetworkInfoRequest
req.SetBody(new(v2netmap.NetworkInfoRequestBody))
c.prepareRequest(&req, meta)
return &req, nil
}
// ResNetworkInfo groups resulting values of NetworkInfo operation.
type ResNetworkInfo struct {
statusRes
@ -144,7 +144,7 @@ func (x ResNetworkInfo) Info() netmap.NetworkInfo {
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmNetworkInfo docs).
// Returns an error if parameters are set incorrectly (see PrmNetworkInfo docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ResNetworkInfo.
@ -153,51 +153,35 @@ func (x ResNetworkInfo) Info() netmap.NetworkInfo {
// Return statuses:
// - global (see Client docs).
func (c *Client) NetworkInfo(ctx context.Context, prm PrmNetworkInfo) (*ResNetworkInfo, error) {
// check context
if ctx == nil {
panic(panicMsgMissingContext)
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
// form request
var req v2netmap.NetworkInfoRequest
// init call context
var (
cc contextCall
res ResNetworkInfo
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.NetworkInfo(&c.c, &req, client.WithContext(ctx))
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := rpcapi.NetworkInfo(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResNetworkInfo
res.st, err = c.processResponse(resp)
if err != nil || !apistatus.IsSuccessful(res.st) {
return &res, err
}
cc.result = func(r responseV2) {
resp := r.(*v2netmap.NetworkInfoResponse)
const fieldNetInfo = "network info"
netInfoV2 := resp.GetBody().GetNetworkInfo()
if netInfoV2 == nil {
cc.err = newErrMissingResponseField(fieldNetInfo)
return
return nil, newErrMissingResponseField(fieldNetInfo)
}
cc.err = res.info.ReadFromV2(*netInfoV2)
if cc.err != nil {
cc.err = newErrInvalidResponseField(fieldNetInfo, cc.err)
return
if err := res.info.ReadFromV2(*netInfoV2); err != nil {
return nil, newErrInvalidResponseField(fieldNetInfo, err)
}
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
@ -224,6 +208,7 @@ func (x ResNetMapSnapshot) NetMap() netmap.NetMap {
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Returns an error if parameters are set incorrectly.
// Context is required and MUST NOT be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ResNetMapSnapshot.
@ -232,11 +217,6 @@ func (x ResNetMapSnapshot) NetMap() netmap.NetMap {
// Return statuses:
// - global (see Client docs).
func (c *Client) NetMapSnapshot(ctx context.Context, _ PrmNetMapSnapshot) (*ResNetMapSnapshot, error) {
// check context
if ctx == nil {
panic(panicMsgMissingContext)
}
// form request body
var body v2netmap.SnapshotRequestBody

View file

@ -6,11 +6,11 @@ import (
"fmt"
"testing"
v2netmap "github.com/TrueCloudLab/frostfs-api-go/v2/netmap"
"github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/TrueCloudLab/frostfs-sdk-go/netmap"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
"github.com/stretchr/testify/require"
)
@ -69,12 +69,6 @@ func TestClient_NetMapSnapshot(t *testing.T) {
c := newClient(&srv)
ctx := context.Background()
// missing context
require.PanicsWithValue(t, panicMsgMissingContext, func() {
//nolint:staticcheck
_, _ = c.NetMapSnapshot(nil, prm)
})
// request signature
srv.errTransport = errors.New("any error")

View file

@ -5,18 +5,18 @@ import (
"crypto/ecdsa"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "github.com/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "github.com/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/signature"
"github.com/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
)
// PrmObjectDelete groups parameters of ObjectDelete operation.
@ -114,7 +114,7 @@ func (x ResObjectDelete) Tombstone() oid.ID {
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmObjectDelete docs).
// Returns an error if parameters are set incorrectly (see PrmObjectDelete docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
@ -125,12 +125,10 @@ func (x ResObjectDelete) Tombstone() oid.ID {
// - *apistatus.SessionTokenExpired.
func (c *Client) ObjectDelete(ctx context.Context, prm PrmObjectDelete) (*ResObjectDelete, error) {
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case prm.addr.GetContainerID() == nil:
panic(panicMsgMissingContainer)
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
panic(panicMsgMissingObject)
return nil, errorMissingObject
}
// form request body

View file

@ -7,19 +7,19 @@ import (
"fmt"
"io"
"github.com/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "github.com/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "github.com/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/signature"
"github.com/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
"github.com/TrueCloudLab/frostfs-sdk-go/object"
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
)
// shared parameters of GET/HEAD/RANGE.
@ -296,17 +296,15 @@ func (x *ObjectReader) Read(p []byte) (int, error) {
// The call only opens the transmission channel, explicit fetching is done using the ObjectReader.
// Exactly one return value is non-nil. Resulting reader must be finally closed.
//
// Immediately panics if parameters are set incorrectly (see PrmObjectGet docs).
// Returns an error if parameters are set incorrectly (see PrmObjectGet docs).
// Context is required and must not be nil. It is used for network communication.
func (c *Client) ObjectGetInit(ctx context.Context, prm PrmObjectGet) (*ObjectReader, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case prm.addr.GetContainerID() == nil:
panic(panicMsgMissingContainer)
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
panic(panicMsgMissingObject)
return nil, errorMissingObject
}
// form request body
@ -400,7 +398,7 @@ func (x *ResObjectHead) ReadHeader(dst *object.Object) bool {
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmObjectHead docs).
// Returns an error if parameters are set incorrectly (see PrmObjectHead docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return errors:
@ -416,12 +414,10 @@ func (x *ResObjectHead) ReadHeader(dst *object.Object) bool {
// - *apistatus.SessionTokenExpired.
func (c *Client) ObjectHead(ctx context.Context, prm PrmObjectHead) (*ResObjectHead, error) {
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case prm.addr.GetContainerID() == nil:
panic(panicMsgMissingContainer)
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
panic(panicMsgMissingObject)
return nil, errorMissingObject
}
var body v2object.HeadRequestBody
@ -663,19 +659,17 @@ func (x *ObjectRangeReader) Read(p []byte) (int, error) {
// The call only opens the transmission channel, explicit fetching is done using the ObjectRangeReader.
// Exactly one return value is non-nil. Resulting reader must be finally closed.
//
// Immediately panics if parameters are set incorrectly (see PrmObjectRange docs).
// Returns an error if parameters are set incorrectly (see PrmObjectRange docs).
// Context is required and must not be nil. It is used for network communication.
func (c *Client) ObjectRangeInit(ctx context.Context, prm PrmObjectRange) (*ObjectRangeReader, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case prm.addr.GetContainerID() == nil:
panic(panicMsgMissingContainer)
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
panic(panicMsgMissingObject)
return nil, errorMissingObject
case prm.rng.GetLength() == 0:
panic("zero range length")
return nil, errorZeroRangeLength
}
// form request body

View file

@ -5,18 +5,18 @@ import (
"crypto/ecdsa"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "github.com/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "github.com/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/signature"
"github.com/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
)
// PrmObjectHash groups parameters of ObjectHash operation.
@ -154,7 +154,7 @@ func (x ResObjectHash) Checksums() [][]byte {
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmObjectHash docs).
// Returns an error if parameters are set incorrectly (see PrmObjectHash docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
@ -166,14 +166,12 @@ func (x ResObjectHash) Checksums() [][]byte {
// - *apistatus.SessionTokenExpired.
func (c *Client) ObjectHash(ctx context.Context, prm PrmObjectHash) (*ResObjectHash, error) {
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case prm.addr.GetContainerID() == nil:
panic(panicMsgMissingContainer)
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
panic(panicMsgMissingObject)
return nil, errorMissingObject
case len(prm.body.GetRanges()) == 0:
panic("missing ranges")
return nil, errorMissingRanges
}
prm.body.SetAddress(&prm.addr)

View file

@ -3,33 +3,50 @@ package client
import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"io"
"github.com/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "github.com/TrueCloudLab/frostfs-api-go/v2/object"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/signature"
"github.com/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/TrueCloudLab/frostfs-sdk-go/object"
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/transformer"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
)
// defaultGRPCPayloadChunkLen default value for maxChunkLen.
// See PrmObjectPutInit.SetGRPCPayloadChunkLen for details.
const defaultGRPCPayloadChunkLen = 3 << 20
// PrmObjectPutInit groups parameters of ObjectPutInit operation.
type PrmObjectPutInit struct {
copyNum uint32
copyNum []uint32
key *ecdsa.PrivateKey
meta v2session.RequestMetaHeader
maxChunkLen int
maxSize uint64
epochSource transformer.EpochSource
withoutHomomorphicHash bool
}
// SetCopiesNumber sets number of object copies that is enough to consider put successful.
func (x *PrmObjectPutInit) SetCopiesNumber(copiesNumber uint32) {
x.copyNum = copiesNumber
x.copyNum = []uint32{copiesNumber}
}
// SetCopiesNumberByVectors sets ordered list of minimal required object copies numbers
// per placement vector. List's length MUST equal container's placement vector number,
// otherwise request will fail.
func (x *PrmObjectPutInit) SetCopiesNumberByVectors(copiesNumbers []uint32) {
x.copyNum = copiesNumbers
}
// SetGRPCPayloadChunkLen sets maximum chunk length value for gRPC Put request.
// Maximum chunk length restricts maximum byte length of the chunk
// transmitted in a single stream message. It depends on
// server settings and other message fields.
// If not specified or negative value set, default value of 3MiB will be used.
func (x *PrmObjectPutInit) SetGRPCPayloadChunkLen(v int) {
x.maxChunkLen = v
}
// ResObjectPut groups the final result values of ObjectPutInit operation.
@ -44,29 +61,35 @@ func (x ResObjectPut) StoredObjectID() oid.ID {
return x.obj
}
// ObjectWriter is designed to write one object to FrostFS system.
// ObjectWriter is designed to write one object or
// multiple parts of one object to FrostFS system.
//
// Must be initialized using Client.ObjectPutInit, any other
// usage is unsafe.
type ObjectWriter struct {
cancelCtxStream context.CancelFunc
client *Client
stream interface {
Write(*v2object.PutRequest) error
Close() error
}
key *ecdsa.PrivateKey
res ResObjectPut
err error
chunkCalled bool
respV2 v2object.PutResponse
req v2object.PutRequest
partInit v2object.PutObjectPartInit
partChunk v2object.PutObjectPartChunk
type ObjectWriter interface {
// WriteHeader writes header of the object. Result means success.
// Failure reason can be received via Close.
WriteHeader(context.Context, object.Object) bool
// WritePayloadChunk writes chunk of the object payload. Result means success.
// Failure reason can be received via Close.
WritePayloadChunk(context.Context, []byte) bool
// Close ends writing the object and returns the result of the operation
// along with the final results. Must be called after using the ObjectWriter.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as Go built-in error.
// If Client is tuned to resolve FrostFS API statuses, then FrostFS failures
// codes are returned as error.
//
// Return statuses:
// - global (see Client docs);
// - *apistatus.ContainerNotFound;
// - *apistatus.ObjectAccessDenied;
// - *apistatus.ObjectLocked;
// - *apistatus.LockNonRegularObject;
// - *apistatus.SessionTokenNotFound;
// - *apistatus.SessionTokenExpired.
Close(context.Context) (*ResObjectPut, error)
}
// UseKey specifies private key to sign the requests.
@ -105,129 +128,21 @@ func (x *PrmObjectPutInit) WithXHeaders(hs ...string) {
writeXHeadersToMeta(hs, &x.meta)
}
// WriteHeader writes header of the object. Result means success.
// Failure reason can be received via Close.
func (x *ObjectWriter) WriteHeader(hdr object.Object) bool {
v2Hdr := hdr.ToV2()
x.partInit.SetObjectID(v2Hdr.GetObjectID())
x.partInit.SetHeader(v2Hdr.GetHeader())
x.partInit.SetSignature(v2Hdr.GetSignature())
x.req.GetBody().SetObjectPart(&x.partInit)
x.req.SetVerificationHeader(nil)
x.err = signature.SignServiceMessage(x.key, &x.req)
if x.err != nil {
x.err = fmt.Errorf("sign message: %w", x.err)
return false
}
x.err = x.stream.Write(&x.req)
return x.err == nil
// WithObjectMaxSize specifies max object size value and use it during object splitting.
// When specified, start writing to the stream only after the object is formed.
// Continue processing the input only when the previous formed object has been successfully written.
func (x *PrmObjectPutInit) WithObjectMaxSize(maxSize uint64) {
x.maxSize = maxSize
}
// WritePayloadChunk writes chunk of the object payload. Result means success.
// Failure reason can be received via Close.
func (x *ObjectWriter) WritePayloadChunk(chunk []byte) bool {
if !x.chunkCalled {
x.chunkCalled = true
x.req.GetBody().SetObjectPart(&x.partChunk)
}
for ln := len(chunk); ln > 0; ln = len(chunk) {
// maxChunkLen restricts maximum byte length of the chunk
// transmitted in a single stream message. It depends on
// server settings and other message fields, but for now
// we simply assume that 3MB is large enough to reduce the
// number of messages, and not to exceed the limit
// (4MB by default for gRPC servers).
const maxChunkLen = 3 << 20
if ln > maxChunkLen {
ln = maxChunkLen
}
// we deal with size limit overflow above, but there is another case:
// what if method is called with "small" chunk many times? We write
// a message to the stream on each call. Alternatively, we could use buffering.
// In most cases, the chunk length does not vary between calls. Given this
// assumption, as well as the length of the payload from the header, it is
// possible to buffer the data of intermediate chunks, and send a message when
// the allocated buffer is filled, or when the last chunk is received.
// It is mentally assumed that allocating and filling the buffer is better than
// synchronous sending, but this needs to be tested.
x.partChunk.SetChunk(chunk[:ln])
x.req.SetVerificationHeader(nil)
x.err = signature.SignServiceMessage(x.key, &x.req)
if x.err != nil {
x.err = fmt.Errorf("sign message: %w", x.err)
return false
}
x.err = x.stream.Write(&x.req)
if x.err != nil {
return false
}
chunk = chunk[ln:]
}
return true
// WithoutHomomorphicHash if set to true do not use Tillich-Zémor hash for payload.
func (x *PrmObjectPutInit) WithoutHomomorphicHash(v bool) {
x.withoutHomomorphicHash = v
}
// Close ends writing the object and returns the result of the operation
// along with the final results. Must be called after using the ObjectWriter.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as Go built-in error.
// If Client is tuned to resolve FrostFS API statuses, then FrostFS failures
// codes are returned as error.
//
// Return statuses:
// - global (see Client docs);
// - *apistatus.ContainerNotFound;
// - *apistatus.ObjectAccessDenied;
// - *apistatus.ObjectLocked;
// - *apistatus.LockNonRegularObject;
// - *apistatus.SessionTokenNotFound;
// - *apistatus.SessionTokenExpired.
func (x *ObjectWriter) Close() (*ResObjectPut, error) {
defer x.cancelCtxStream()
// Ignore io.EOF error, because it is expected error for client-side
// stream termination by the server. E.g. when stream contains invalid
// message. Server returns an error in response message (in status).
if x.err != nil && !errors.Is(x.err, io.EOF) {
return nil, x.err
}
if x.err = x.stream.Close(); x.err != nil {
return nil, x.err
}
x.res.st, x.err = x.client.processResponse(&x.respV2)
if x.err != nil {
return nil, x.err
}
if !apistatus.IsSuccessful(x.res.st) {
return &x.res, nil
}
const fieldID = "ID"
idV2 := x.respV2.GetBody().GetObjectID()
if idV2 == nil {
return nil, newErrMissingResponseField(fieldID)
}
x.err = x.res.obj.ReadFromV2(*idV2)
if x.err != nil {
x.err = newErrInvalidResponseField(fieldID, x.err)
}
return &x.res, nil
// WithEpochSource specifies epoch for object when split it on client side.
func (x *PrmObjectPutInit) WithEpochSource(es transformer.EpochSource) {
x.epochSource = es
}
// ObjectPutInit initiates writing an object through a remote server using FrostFS API protocol.
@ -235,32 +150,11 @@ func (x *ObjectWriter) Close() (*ResObjectPut, error) {
// The call only opens the transmission channel, explicit recording is done using the ObjectWriter.
// Exactly one return value is non-nil. Resulting writer must be finally closed.
//
// Returns an error if parameters are set incorrectly.
// Context is required and must not be nil. It is used for network communication.
func (c *Client) ObjectPutInit(ctx context.Context, prm PrmObjectPutInit) (*ObjectWriter, error) {
// check parameters
if ctx == nil {
panic(panicMsgMissingContext)
func (c *Client) ObjectPutInit(ctx context.Context, prm PrmObjectPutInit) (ObjectWriter, error) {
if prm.maxSize > 0 {
return c.objectPutInitTransformer(prm)
}
var w ObjectWriter
ctx, cancel := context.WithCancel(ctx)
stream, err := rpcapi.PutObject(&c.c, &w.respV2, client.WithContext(ctx))
if err != nil {
cancel()
return nil, fmt.Errorf("open stream: %w", err)
}
w.key = &c.prm.key
if prm.key != nil {
w.key = prm.key
}
w.cancelCtxStream = cancel
w.client = c
w.stream = stream
w.partInit.SetCopiesNumber(prm.copyNum)
w.req.SetBody(new(v2object.PutRequestBody))
c.prepareRequest(&w.req, &prm.meta)
return &w, nil
return c.objectPutInitRaw(ctx, prm)
}

154
client/object_put_raw.go Normal file
View file

@ -0,0 +1,154 @@
package client
import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"io"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
)
func (c *Client) objectPutInitRaw(ctx context.Context, prm PrmObjectPutInit) (*objectWriterRaw, error) {
var w objectWriterRaw
stream, err := rpcapi.PutObject(&c.c, &w.respV2, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("open stream: %w", err)
}
w.key = &c.prm.key
if prm.key != nil {
w.key = prm.key
}
w.client = c
w.stream = stream
w.partInit.SetCopiesNumber(prm.copyNum)
w.req.SetBody(new(v2object.PutRequestBody))
if prm.maxChunkLen > 0 {
w.maxChunkLen = prm.maxChunkLen
} else {
w.maxChunkLen = defaultGRPCPayloadChunkLen
}
c.prepareRequest(&w.req, &prm.meta)
return &w, nil
}
type objectWriterRaw struct {
client *Client
stream interface {
Write(*v2object.PutRequest) error
Close() error
}
key *ecdsa.PrivateKey
res ResObjectPut
err error
chunkCalled bool
respV2 v2object.PutResponse
req v2object.PutRequest
partInit v2object.PutObjectPartInit
partChunk v2object.PutObjectPartChunk
maxChunkLen int
}
func (x *objectWriterRaw) WriteHeader(_ context.Context, hdr object.Object) bool {
v2Hdr := hdr.ToV2()
x.partInit.SetObjectID(v2Hdr.GetObjectID())
x.partInit.SetHeader(v2Hdr.GetHeader())
x.partInit.SetSignature(v2Hdr.GetSignature())
x.req.GetBody().SetObjectPart(&x.partInit)
x.req.SetVerificationHeader(nil)
x.err = signature.SignServiceMessage(x.key, &x.req)
if x.err != nil {
x.err = fmt.Errorf("sign message: %w", x.err)
return false
}
x.err = x.stream.Write(&x.req)
return x.err == nil
}
func (x *objectWriterRaw) WritePayloadChunk(_ context.Context, chunk []byte) bool {
if !x.chunkCalled {
x.chunkCalled = true
x.req.GetBody().SetObjectPart(&x.partChunk)
}
for ln := len(chunk); ln > 0; ln = len(chunk) {
if ln > x.maxChunkLen {
ln = x.maxChunkLen
}
// we deal with size limit overflow above, but there is another case:
// what if method is called with "small" chunk many times? We write
// a message to the stream on each call. Alternatively, we could use buffering.
// In most cases, the chunk length does not vary between calls. Given this
// assumption, as well as the length of the payload from the header, it is
// possible to buffer the data of intermediate chunks, and send a message when
// the allocated buffer is filled, or when the last chunk is received.
// It is mentally assumed that allocating and filling the buffer is better than
// synchronous sending, but this needs to be tested.
x.partChunk.SetChunk(chunk[:ln])
x.req.SetVerificationHeader(nil)
x.err = signature.SignServiceMessage(x.key, &x.req)
if x.err != nil {
x.err = fmt.Errorf("sign message: %w", x.err)
return false
}
x.err = x.stream.Write(&x.req)
if x.err != nil {
return false
}
chunk = chunk[ln:]
}
return true
}
func (x *objectWriterRaw) Close(_ context.Context) (*ResObjectPut, error) {
// Ignore io.EOF error, because it is expected error for client-side
// stream termination by the server. E.g. when stream contains invalid
// message. Server returns an error in response message (in status).
if x.err != nil && !errors.Is(x.err, io.EOF) {
return nil, x.err
}
if x.err = x.stream.Close(); x.err != nil {
return nil, x.err
}
x.res.st, x.err = x.client.processResponse(&x.respV2)
if x.err != nil {
return nil, x.err
}
if !apistatus.IsSuccessful(x.res.st) {
return &x.res, nil
}
const fieldID = "ID"
idV2 := x.respV2.GetBody().GetObjectID()
if idV2 == nil {
return nil, newErrMissingResponseField(fieldID)
}
x.err = x.res.obj.ReadFromV2(*idV2)
if x.err != nil {
x.err = newErrInvalidResponseField(fieldID, x.err)
}
return &x.res, nil
}

View file

@ -0,0 +1,88 @@
package client
import (
"context"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/transformer"
)
func (c *Client) objectPutInitTransformer(prm PrmObjectPutInit) (*objectWriterTransformer, error) {
var w objectWriterTransformer
w.it = internalTarget{
client: c,
prm: prm,
}
key := &c.prm.key
if prm.key != nil {
key = prm.key
}
w.ot = transformer.NewPayloadSizeLimiter(transformer.Params{
Key: key,
NextTargetInit: func() transformer.ObjectTarget { return &w.it },
MaxSize: prm.maxSize,
WithoutHomomorphicHash: prm.withoutHomomorphicHash,
NetworkState: prm.epochSource,
})
return &w, nil
}
type objectWriterTransformer struct {
ot transformer.ObjectTarget
it internalTarget
err error
}
func (x *objectWriterTransformer) WriteHeader(ctx context.Context, hdr object.Object) bool {
x.err = x.ot.WriteHeader(ctx, &hdr)
return x.err == nil
}
func (x *objectWriterTransformer) WritePayloadChunk(ctx context.Context, chunk []byte) bool {
_, x.err = x.ot.Write(ctx, chunk)
return x.err == nil
}
func (x *objectWriterTransformer) Close(ctx context.Context) (*ResObjectPut, error) {
if ai, err := x.ot.Close(ctx); err != nil {
return nil, err
} else {
if ai != nil && ai.ParentID != nil {
x.it.res.obj = *ai.ParentID
}
return x.it.res, nil
}
}
type internalTarget struct {
current *object.Object
client *Client
res *ResObjectPut
prm PrmObjectPutInit
payload []byte
}
func (it *internalTarget) WriteHeader(_ context.Context, object *object.Object) error {
it.current = object
return nil
}
func (it *internalTarget) Write(_ context.Context, p []byte) (n int, err error) {
it.payload = append(it.payload, p...)
return len(p), nil
}
func (it *internalTarget) Close(ctx context.Context) (*transformer.AccessIdentifiers, error) {
it.current.SetPayload(it.payload)
wrt, err := it.client.objectPutInitRaw(ctx, it.prm)
if err != nil {
return nil, err
}
if wrt.WriteHeader(ctx, *it.current) {
wrt.WritePayloadChunk(ctx, it.current.Payload())
}
it.res, err = wrt.Close(ctx)
it.current = nil
it.payload = nil
return nil, err
}

View file

@ -7,19 +7,19 @@ import (
"fmt"
"io"
"github.com/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "github.com/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "github.com/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/signature"
"github.com/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
"github.com/TrueCloudLab/frostfs-sdk-go/object"
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
)
// PrmObjectSearch groups parameters of ObjectSearch operation.
@ -218,15 +218,12 @@ func (x *ObjectListReader) Close() (*ResObjectSearch, error) {
// is done using the ObjectListReader. Exactly one return value is non-nil.
// Resulting reader must be finally closed.
//
// Immediately panics if parameters are set incorrectly (see PrmObjectSearch docs).
// Returns an error if parameters are set incorrectly (see PrmObjectSearch docs).
// Context is required and must not be nil. It is used for network communication.
func (c *Client) ObjectSearchInit(ctx context.Context, prm PrmObjectSearch) (*ObjectListReader, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.cnrSet:
panic(panicMsgMissingContainer)
if !prm.cnrSet {
return nil, errorMissingContainer
}
var cidV2 v2refs.ContainerID

View file

@ -7,11 +7,11 @@ import (
"io"
"testing"
v2object "github.com/TrueCloudLab/frostfs-api-go/v2/object"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
signatureV2 "github.com/TrueCloudLab/frostfs-api-go/v2/signature"
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
oidtest "github.com/TrueCloudLab/frostfs-sdk-go/object/id/test"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
signatureV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
)

View file

@ -1,200 +0,0 @@
package client
import (
"context"
v2reputation "github.com/TrueCloudLab/frostfs-api-go/v2/reputation"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"github.com/TrueCloudLab/frostfs-sdk-go/reputation"
)
// PrmAnnounceLocalTrust groups parameters of AnnounceLocalTrust operation.
type PrmAnnounceLocalTrust struct {
prmCommonMeta
epoch uint64
trusts []reputation.Trust
}
// SetEpoch sets number of FrostFS epoch in which the trust was assessed.
// Required parameter, must not be zero.
func (x *PrmAnnounceLocalTrust) SetEpoch(epoch uint64) {
x.epoch = epoch
}
// SetValues sets values describing trust of the client to the FrostFS network participants.
// Required parameter. Must not be empty.
//
// Must not be mutated before the end of the operation.
func (x *PrmAnnounceLocalTrust) SetValues(trusts []reputation.Trust) {
x.trusts = trusts
}
// ResAnnounceLocalTrust groups results of AnnounceLocalTrust operation.
type ResAnnounceLocalTrust struct {
statusRes
}
// AnnounceLocalTrust sends client's trust values to the FrostFS network participants.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmAnnounceLocalTrust docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) AnnounceLocalTrust(ctx context.Context, prm PrmAnnounceLocalTrust) (*ResAnnounceLocalTrust, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case prm.epoch == 0:
panic("zero epoch")
case len(prm.trusts) == 0:
panic("missing trusts")
}
// form request body
reqBody := new(v2reputation.AnnounceLocalTrustRequestBody)
reqBody.SetEpoch(prm.epoch)
trusts := make([]v2reputation.Trust, len(prm.trusts))
for i := range prm.trusts {
prm.trusts[i].WriteToV2(&trusts[i])
}
reqBody.SetTrusts(trusts)
// form request
var req v2reputation.AnnounceLocalTrustRequest
req.SetBody(reqBody)
// init call context
var (
cc contextCall
res ResAnnounceLocalTrust
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.AnnounceLocalTrust(&c.c, &req, client.WithContext(ctx))
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// PrmAnnounceIntermediateTrust groups parameters of AnnounceIntermediateTrust operation.
type PrmAnnounceIntermediateTrust struct {
prmCommonMeta
epoch uint64
iter uint32
trustSet bool
trust reputation.PeerToPeerTrust
}
// SetEpoch sets number of FrostFS epoch with which client's calculation algorithm is initialized.
// Required parameter, must not be zero.
func (x *PrmAnnounceIntermediateTrust) SetEpoch(epoch uint64) {
x.epoch = epoch
}
// SetIteration sets current sequence number of the client's calculation algorithm.
// By default, corresponds to initial (zero) iteration.
func (x *PrmAnnounceIntermediateTrust) SetIteration(iter uint32) {
x.iter = iter
}
// SetCurrentValue sets current global trust value computed at the specified iteration
// of the client's calculation algorithm. Required parameter.
func (x *PrmAnnounceIntermediateTrust) SetCurrentValue(trust reputation.PeerToPeerTrust) {
x.trust = trust
x.trustSet = true
}
// ResAnnounceIntermediateTrust groups results of AnnounceIntermediateTrust operation.
type ResAnnounceIntermediateTrust struct {
statusRes
}
// AnnounceIntermediateTrust sends global trust values calculated for the specified FrostFS network participants
// at some stage of client's calculation algorithm.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmAnnounceIntermediateTrust docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) AnnounceIntermediateTrust(ctx context.Context, prm PrmAnnounceIntermediateTrust) (*ResAnnounceIntermediateTrust, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case prm.epoch == 0:
panic("zero epoch")
case !prm.trustSet:
panic("current trust value not set")
}
var trust v2reputation.PeerToPeerTrust
prm.trust.WriteToV2(&trust)
// form request body
reqBody := new(v2reputation.AnnounceIntermediateResultRequestBody)
reqBody.SetEpoch(prm.epoch)
reqBody.SetIteration(prm.iter)
reqBody.SetTrust(&trust)
// form request
var req v2reputation.AnnounceIntermediateResultRequest
req.SetBody(reqBody)
// init call context
var (
cc contextCall
res ResAnnounceIntermediateTrust
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.AnnounceIntermediateResult(&c.c, &req, client.WithContext(ctx))
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}

View file

@ -1,6 +1,6 @@
package client
import "github.com/TrueCloudLab/frostfs-api-go/v2/session"
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
// ResponseMetaInfo groups meta information about any FrostFS API response.
type ResponseMetaInfo struct {

View file

@ -3,12 +3,15 @@ package client
import (
"context"
"crypto/ecdsa"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "github.com/TrueCloudLab/frostfs-api-go/v2/rpc"
"github.com/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
)
// PrmSessionCreate groups parameters of SessionCreate operation.
@ -33,6 +36,30 @@ func (x *PrmSessionCreate) UseKey(key ecdsa.PrivateKey) {
x.key = key
}
func (x *PrmSessionCreate) buildRequest(c *Client) (*v2session.CreateRequest, error) {
ownerKey := c.prm.key.PublicKey
if x.keySet {
ownerKey = x.key.PublicKey
}
var ownerID user.ID
user.IDFromKey(&ownerID, ownerKey)
var ownerIDV2 refs.OwnerID
ownerID.WriteToV2(&ownerIDV2)
reqBody := new(v2session.CreateRequestBody)
reqBody.SetOwnerID(&ownerIDV2)
reqBody.SetExpiration(x.exp)
var meta v2session.RequestMetaHeader
writeXHeadersToMeta(x.xHeaders, &meta)
var req v2session.CreateRequest
req.SetBody(reqBody)
c.prepareRequest(&req, &meta)
return &req, nil
}
// ResSessionCreate groups resulting values of SessionCreate operation.
type ResSessionCreate struct {
statusRes
@ -42,10 +69,6 @@ type ResSessionCreate struct {
sessionKey []byte
}
func (x *ResSessionCreate) setID(id []byte) {
x.id = id
}
// ID returns identifier of the opened session in a binary FrostFS API protocol format.
//
// Client doesn't retain value so modification is safe.
@ -53,10 +76,6 @@ func (x ResSessionCreate) ID() []byte {
return x.id
}
func (x *ResSessionCreate) setSessionKey(key []byte) {
x.sessionKey = key
}
// PublicKey returns public key of the opened session in a binary FrostFS API protocol format.
func (x ResSessionCreate) PublicKey() []byte {
return x.sessionKey
@ -72,68 +91,34 @@ func (x ResSessionCreate) PublicKey() []byte {
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Immediately panics if parameters are set incorrectly (see PrmSessionCreate docs).
// Returns an error if parameters are set incorrectly (see PrmSessionCreate docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) SessionCreate(ctx context.Context, prm PrmSessionCreate) (*ResSessionCreate, error) {
// check context
if ctx == nil {
panic(panicMsgMissingContext)
req, err := prm.buildRequest(c)
if err != nil {
return nil, err
}
ownerKey := c.prm.key.PublicKey
if prm.keySet {
ownerKey = prm.key.PublicKey
}
var ownerID user.ID
user.IDFromKey(&ownerID, ownerKey)
var ownerIDV2 refs.OwnerID
ownerID.WriteToV2(&ownerIDV2)
// form request body
reqBody := new(v2session.CreateRequestBody)
reqBody.SetOwnerID(&ownerIDV2)
reqBody.SetExpiration(prm.exp)
// for request
var req v2session.CreateRequest
req.SetBody(reqBody)
// init call context
var (
cc contextCall
res ResSessionCreate
)
c.initCallContext(&cc)
if prm.keySet {
cc.key = prm.key
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.CreateSession(&c.c, &req, client.WithContext(ctx))
resp, err := rpcapi.CreateSession(&c.c, req, client.WithContext(ctx))
if err != nil {
return nil, err
}
var res ResSessionCreate
res.st, err = c.processResponse(resp)
if err != nil || !apistatus.IsSuccessful(res.st) {
return &res, err
}
cc.result = func(r responseV2) {
resp := r.(*v2session.CreateResponse)
body := resp.GetBody()
res.setID(body.GetID())
res.setSessionKey(body.GetSessionKey())
}
// process call
if !cc.processCall() {
return nil, cc.err
}
res.id = body.GetID()
res.sessionKey = body.GetSessionKey()
return &res, nil
}

View file

@ -3,7 +3,7 @@ package apistatus
import (
"encoding/binary"
"github.com/TrueCloudLab/frostfs-api-go/v2/status"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
)
// ServerInternal describes failure statuses related to internal server errors.

View file

@ -3,8 +3,8 @@ package apistatus_test
import (
"testing"
"github.com/TrueCloudLab/frostfs-api-go/v2/status"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/stretchr/testify/require"
)

View file

@ -1,8 +1,8 @@
package apistatus
import (
"github.com/TrueCloudLab/frostfs-api-go/v2/container"
"github.com/TrueCloudLab/frostfs-api-go/v2/status"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
)
// ContainerNotFound describes status of the failure because of the missing container.

View file

@ -1,8 +1,8 @@
package apistatus
import (
"github.com/TrueCloudLab/frostfs-api-go/v2/object"
"github.com/TrueCloudLab/frostfs-api-go/v2/status"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
)
// ObjectLocked describes status of the failure because of the locked object.

View file

@ -3,7 +3,7 @@ package apistatus_test
import (
"testing"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/stretchr/testify/require"
)

View file

@ -1,8 +1,8 @@
package apistatus
import (
"github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/status"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
)
// SessionTokenNotFound describes status of the failure because of the missing session token.

View file

@ -15,7 +15,7 @@ package apistatus
// It should be noted that using direct typecasting is not a compatible approach.
//
// To transport statuses using the FrostFS API V2 protocol, see StatusV2 interface and FromStatusV2 and ToStatusV2 functions.
type Status interface{}
type Status any
// ErrFromStatus converts Status instance to error if it is failed. Returns nil on successful Status.
//

View file

@ -4,7 +4,7 @@ import (
"errors"
"testing"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/stretchr/testify/require"
)

View file

@ -1,7 +1,7 @@
package apistatus
import (
"github.com/TrueCloudLab/frostfs-api-go/v2/status"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
)
// SuccessDefaultV2 represents Status instance of default success. Implements StatusV2.

View file

@ -1,7 +1,7 @@
package apistatus
import (
"github.com/TrueCloudLab/frostfs-api-go/v2/status"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
)
type unrecognizedStatusV2 struct {

View file

@ -3,10 +3,10 @@ package apistatus
import (
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/container"
"github.com/TrueCloudLab/frostfs-api-go/v2/object"
"github.com/TrueCloudLab/frostfs-api-go/v2/session"
"github.com/TrueCloudLab/frostfs-api-go/v2/status"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
)
// StatusV2 defines a variety of Status instances compatible with FrostFS API V2 protocol.
@ -15,7 +15,7 @@ import (
type StatusV2 interface {
Status
// ToStatusV2 returns the status as github.com/TrueCloudLab/frostfs-api-go/v2/status.Status message structure.
// ToStatusV2 returns the status as git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status.Status message structure.
ToStatusV2() *status.Status
}
@ -123,7 +123,7 @@ func ToStatusV2(st Status) *status.Status {
return internalErrorStatus
}
func errMessageStatusV2(code interface{}, msg string) string {
func errMessageStatusV2(code any, msg string) string {
const (
noMsgFmt = "status: code = %v"
msgFmt = noMsgFmt + " message = %s"

View file

@ -4,7 +4,7 @@ import (
"errors"
"testing"
apistatus "github.com/TrueCloudLab/frostfs-sdk-go/client/status"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/stretchr/testify/require"
)
@ -12,7 +12,7 @@ func TestToStatusV2(t *testing.T) {
type statusConstructor func() apistatus.Status
for _, testItem := range [...]struct {
status interface{} // Status or statusConstructor
status any // Status or statusConstructor
codeV2 uint64
messageV2 string
}{
@ -165,7 +165,7 @@ func TestFromStatusV2(t *testing.T) {
type statusConstructor func() apistatus.Status
for _, testItem := range [...]struct {
status interface{} // Status or statusConstructor
status any // Status or statusConstructor
codeV2 uint64
messageV2 string
}{

View file

@ -9,6 +9,7 @@ import "strconv"
// use corresponding constants and/or methods instead.
type Op uint32
// nolint: unused
const (
opZero Op = iota // extreme value for testing
@ -53,6 +54,7 @@ func (x Op) String() string {
// use corresponding constants and/or methods instead.
type Role uint32
// nolint: unused
const (
roleZero Role = iota // extreme value for testing

View file

@ -7,14 +7,6 @@ func setBit(num *uint32, n uint8) {
*num |= 1 << n
}
// resets n-th bit in num (starting at 0).
func resetBit(num *uint32, n uint8) {
var mask uint32
setBit(&mask, n)
*num &= ^mask
}
// checks if n-th bit in num is set (starting at 0).
func isBitSet(num uint32, n uint8) bool {
mask := uint32(1 << n)

View file

@ -22,9 +22,6 @@ func TestBits(t *testing.T) {
setBit(&num, 6)
require.EqualValues(t, 0b1011110, num)
resetBit(&num, 1)
require.EqualValues(t, 0b1011100, num)
}
func TestOpBits(t *testing.T) {

View file

@ -8,17 +8,16 @@ import (
"strconv"
"time"
"github.com/TrueCloudLab/frostfs-api-go/v2/container"
v2netmap "github.com/TrueCloudLab/frostfs-api-go/v2/netmap"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"github.com/TrueCloudLab/frostfs-sdk-go/container/acl"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "github.com/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "github.com/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"github.com/TrueCloudLab/frostfs-sdk-go/netmap"
subnetid "github.com/TrueCloudLab/frostfs-sdk-go/subnet/id"
"github.com/TrueCloudLab/frostfs-sdk-go/user"
"github.com/TrueCloudLab/frostfs-sdk-go/version"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
"github.com/google/uuid"
)
@ -37,7 +36,7 @@ import (
// Instances for existing containers can be initialized using decoding methods
// (e.g Unmarshal).
//
// Container is mutually compatible with github.com/TrueCloudLab/frostfs-api-go/v2/container.Container
// Container is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container.Container
// message. See ReadFromV2 / WriteToV2 methods.
type Container struct {
v2 container.Container
@ -96,6 +95,16 @@ func (x *Container) readFromV2(m container.Container, checkFieldPresence bool) e
return errors.New("missing placement policy")
}
if err := checkAttributes(m); err != nil {
return err
}
x.v2 = m
return nil
}
func checkAttributes(m container.Container) error {
attrs := m.GetAttributes()
mAttr := make(map[string]struct{}, len(attrs))
var key, val string
@ -117,10 +126,8 @@ func (x *Container) readFromV2(m container.Container, checkFieldPresence bool) e
return fmt.Errorf("empty attribute value %s", key)
}
switch key {
case container.SysAttributeSubnet:
err = new(subnetid.ID).DecodeString(val)
case attributeTimestamp:
var err error
if key == attributeTimestamp {
_, err = strconv.ParseInt(val, 10, 64)
}
@ -130,9 +137,6 @@ func (x *Container) readFromV2(m container.Container, checkFieldPresence bool) e
mAttr[key] = struct{}{}
}
x.v2 = m
return nil
}
@ -383,28 +387,6 @@ func CreatedAt(cnr Container) time.Time {
return time.Unix(sec, 0)
}
// SetSubnet places the Container on the specified FrostFS subnet. If called,
// container nodes will only be selected from the given subnet, otherwise from
// the entire network.
func SetSubnet(cnr *Container, subNet subnetid.ID) {
cnr.SetAttribute(container.SysAttributeSubnet, subNet.EncodeToString())
}
// Subnet return container subnet set using SetSubnet.
//
// Zero Container is bound to zero subnet.
func Subnet(cnr Container) (res subnetid.ID) {
val := cnr.Attribute(container.SysAttributeSubnet)
if val != "" {
err := res.DecodeString(val)
if err != nil {
panic(fmt.Sprintf("invalid subnet attribute: %s (%v)", val, err))
}
}
return
}
const attributeHomoHashEnabled = "true"
// DisableHomomorphicHashing sets flag to disable homomorphic hashing of the
@ -419,7 +401,8 @@ func DisableHomomorphicHashing(cnr *Container) {
//
// Zero Container has enabled hashing.
func IsHomomorphicHashingDisabled(cnr Container) bool {
return cnr.Attribute(container.SysAttributeHomomorphicHashing) == attributeHomoHashEnabled
return cnr.Attribute(container.SysAttributeHomomorphicHashing) == attributeHomoHashEnabled ||
cnr.Attribute(container.SysAttributeHomomorphicHashingNeoFS) == attributeHomoHashEnabled
}
// Domain represents information about container domain registered in the NNS
@ -465,10 +448,12 @@ func WriteDomain(cnr *Container, domain Domain) {
// ReadDomain reads Domain from the Container. Returns value with empty name
// if domain is not specified.
func ReadDomain(cnr Container) (res Domain) {
name := cnr.Attribute(container.SysAttributeName)
if name != "" {
if name := cnr.Attribute(container.SysAttributeName); name != "" {
res.SetName(name)
res.SetZone(cnr.Attribute(container.SysAttributeZone))
} else if name = cnr.Attribute(container.SysAttributeNameNeoFS); name != "" {
res.SetName(name)
res.SetZone(cnr.Attribute(container.SysAttributeZoneNeoFS))
}
return

View file

@ -6,19 +6,17 @@ import (
"testing"
"time"
v2container "github.com/TrueCloudLab/frostfs-api-go/v2/container"
v2netmap "github.com/TrueCloudLab/frostfs-api-go/v2/netmap"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"github.com/TrueCloudLab/frostfs-sdk-go/container"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
cidtest "github.com/TrueCloudLab/frostfs-sdk-go/container/id/test"
containertest "github.com/TrueCloudLab/frostfs-sdk-go/container/test"
frostfscrypto "github.com/TrueCloudLab/frostfs-sdk-go/crypto"
netmaptest "github.com/TrueCloudLab/frostfs-sdk-go/netmap/test"
subnetid "github.com/TrueCloudLab/frostfs-sdk-go/subnet/id"
subnetidtest "github.com/TrueCloudLab/frostfs-sdk-go/subnet/id/test"
usertest "github.com/TrueCloudLab/frostfs-sdk-go/user/test"
"github.com/TrueCloudLab/frostfs-sdk-go/version"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
containertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/test"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
netmaptest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap/test"
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
@ -233,28 +231,6 @@ func TestSetCreationTime(t *testing.T) {
require.Equal(t, creat.Unix(), container.CreatedAt(val2).Unix())
}
func TestSetSubnet(t *testing.T) {
var val container.Container
require.True(t, subnetid.IsZero(container.Subnet(val)))
val = containertest.Container()
sub := subnetidtest.ID()
container.SetSubnet(&val, sub)
var msg v2container.Container
val.WriteToV2(&msg)
assertContainsAttribute(t, msg, v2container.SysAttributeSubnet, sub.EncodeToString())
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
require.Equal(t, sub, container.Subnet(val))
}
func TestDisableHomomorphicHashing(t *testing.T) {
var val container.Container

View file

@ -23,11 +23,11 @@ it using the instance of Container types
// process the container data
Instances can be also used to process FrostFS API V2 protocol messages
(see neo.fs.v2.container package in https://github.com/TrueCloudLab/frostfs-api).
(see neo.fs.v2.container package in https://git.frostfs.info/TrueCloudLab/frostfs-api).
On client side:
import "github.com/TrueCloudLab/frostfs-api-go/v2/container"
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
var msg container.Container
cnr.WriteToV2(&msg)

View file

@ -4,13 +4,13 @@ import (
"crypto/sha256"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"github.com/mr-tron/base58"
)
// ID represents FrostFS container identifier.
//
// ID is mutually compatible with github.com/TrueCloudLab/frostfs-api-go/v2/refs.ContainerID
// ID is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.ContainerID
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.

View file

@ -5,9 +5,9 @@ import (
"math/rand"
"testing"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
cidtest "github.com/TrueCloudLab/frostfs-sdk-go/container/id/test"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
"github.com/mr-tron/base58"
"github.com/stretchr/testify/require"
)

View file

@ -5,7 +5,7 @@ Note that importing the package into source files is highly discouraged.
Random instance generation functions can be useful when testing expects any value, e.g.:
import cidtest "github.com/TrueCloudLab/frostfs-sdk-go/container/id/test"
import cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
cid := cidtest.ID()
// test the value

View file

@ -4,7 +4,7 @@ import (
"crypto/sha256"
"math/rand"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
)
// ID returns random cid.ID.

View file

@ -1,7 +1,7 @@
package container
import (
"github.com/TrueCloudLab/frostfs-sdk-go/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
)
// ApplyNetworkConfig applies network configuration to the

View file

@ -3,9 +3,9 @@ package container_test
import (
"testing"
"github.com/TrueCloudLab/frostfs-sdk-go/container"
containertest "github.com/TrueCloudLab/frostfs-sdk-go/container/test"
netmaptest "github.com/TrueCloudLab/frostfs-sdk-go/netmap/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
containertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/test"
netmaptest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap/test"
"github.com/stretchr/testify/require"
)

View file

@ -4,15 +4,15 @@ import (
"errors"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/container"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
)
// SizeEstimation groups information about estimation of the size of the data
// stored in the FrostFS container.
//
// SizeEstimation is mutually compatible with github.com/TrueCloudLab/frostfs-api-go/v2/container.UsedSpaceAnnouncement
// SizeEstimation is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container.UsedSpaceAnnouncement
// message. See ReadFromV2 / WriteToV2 methods.
type SizeEstimation struct {
m container.UsedSpaceAnnouncement

View file

@ -4,11 +4,11 @@ import (
"crypto/sha256"
"testing"
v2container "github.com/TrueCloudLab/frostfs-api-go/v2/container"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"github.com/TrueCloudLab/frostfs-sdk-go/container"
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
cidtest "github.com/TrueCloudLab/frostfs-sdk-go/container/id/test"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
"github.com/stretchr/testify/require"
)

View file

@ -3,11 +3,11 @@ package containertest
import (
"math/rand"
"github.com/TrueCloudLab/frostfs-sdk-go/container"
"github.com/TrueCloudLab/frostfs-sdk-go/container/acl"
cidtest "github.com/TrueCloudLab/frostfs-sdk-go/container/id/test"
netmaptest "github.com/TrueCloudLab/frostfs-sdk-go/netmap/test"
usertest "github.com/TrueCloudLab/frostfs-sdk-go/user/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
netmaptest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap/test"
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
)
// Container returns random container.Container.

View file

@ -4,9 +4,9 @@ import (
"math/rand"
"testing"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
frostfscrypto "github.com/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "github.com/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
)

View file

@ -25,11 +25,11 @@ PublicKey allows to verify signatures.
// ...
Signature can be also used to process FrostFS API V2 protocol messages
(see neo.fs.v2.refs package in https://github.com/TrueCloudLab/frostfs-api).
(see neo.fs.v2.refs package in https://git.frostfs.info/TrueCloudLab/frostfs-api).
On client side:
import "github.com/TrueCloudLab/frostfs-api-go/v2/refs"
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
var msg refs.Signature
sig.WriteToV2(&msg)

View file

@ -1,6 +1,6 @@
package frostfsecdsa
import frostfscrypto "github.com/TrueCloudLab/frostfs-sdk-go/crypto"
import frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
func init() {
frostfscrypto.RegisterScheme(frostfscrypto.ECDSA_SHA512, func() frostfscrypto.PublicKey {

View file

@ -6,7 +6,7 @@ import (
"crypto/rand"
"crypto/sha512"
frostfscrypto "github.com/TrueCloudLab/frostfs-sdk-go/crypto"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
)

View file

@ -6,8 +6,8 @@ import (
"encoding/base64"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/util/signature/walletconnect"
frostfscrypto "github.com/TrueCloudLab/frostfs-sdk-go/crypto"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/signature/walletconnect"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
)

View file

@ -4,13 +4,13 @@ import (
"errors"
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
)
// Signature represents a confirmation of data integrity received by the
// digital signature mechanism.
//
// Signature is mutually compatible with github.com/TrueCloudLab/frostfs-api-go/v2/refs.Signature
// Signature is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.Signature
// message. See ReadFromV2 / WriteToV2 methods.
//
// Note that direct typecast is not safe and may result in loss of compatibility:

View file

@ -3,7 +3,7 @@ package frostfscrypto
import (
"fmt"
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
)
// Scheme represents digital signature algorithm with fixed cryptographic hash function.

View file

@ -1,7 +1,7 @@
package eacl
import (
v2acl "github.com/TrueCloudLab/frostfs-api-go/v2/acl"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
)
// Action taken if ContainerEACL record matched request.

View file

@ -3,8 +3,8 @@ package eacl_test
import (
"testing"
v2acl "github.com/TrueCloudLab/frostfs-api-go/v2/acl"
"github.com/TrueCloudLab/frostfs-sdk-go/eacl"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
"github.com/stretchr/testify/require"
)

View file

@ -3,7 +3,7 @@ package eacl
import (
"strconv"
v2acl "github.com/TrueCloudLab/frostfs-api-go/v2/acl"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
)
// Filter defines check conditions if request header is matched or not. Matched

Some files were not shown because too many files have changed in this diff Show more