mirror of
https://github.com/psviderski/uncloud.git
synced 2026-11-10 20:54:17 +00:00
Compare commits
55
Commits
v0.20.0
...
e81e130544
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e81e130544 | ||
|
|
1e471d3ec4 | ||
|
|
f7be7c55c9 | ||
|
|
6ab02f95fe | ||
|
|
9a4098694c | ||
|
|
992b819f5b | ||
|
|
842f796e38 | ||
|
|
0f6c03240b | ||
|
|
c6d0371f15 | ||
|
|
5e01db5e20 | ||
|
|
8aedc2bf19 | ||
|
|
7a88865f64 | ||
|
|
a24fc11caf | ||
|
|
c7e0e36daa | ||
|
|
01426ca03d | ||
|
|
3f86b3de44 | ||
|
|
aaf67687d2 | ||
|
|
1c29d4d5d0 | ||
|
|
00d68d9465 | ||
|
|
43bf2baaf7 | ||
|
|
613cd6e418 | ||
|
|
7a7a313426 | ||
|
|
a5ab6e3788 | ||
|
|
5a956e72de | ||
|
|
ac56754281 | ||
|
|
b7e224a1ef | ||
|
|
351698c280 | ||
|
|
fa77edf53e | ||
|
|
b99abb7c39 | ||
|
|
c2ae11a293 | ||
|
|
f1555259de | ||
|
|
50f8fbcfda | ||
|
|
73f29092ff | ||
|
|
08b24af341 | ||
|
|
b9c54f1ff5 | ||
|
|
4d76dd601c | ||
|
|
3af9936d27 | ||
|
|
dc721e511e | ||
|
|
054b3b8fd4 | ||
|
|
b3896ff642 | ||
|
|
5b2823de1e | ||
|
|
0007f76d09 | ||
|
|
f8e6d1caaa | ||
|
|
e684795aee | ||
|
|
7964273552 | ||
|
|
4ad4bce29d | ||
|
|
d670d18810 | ||
|
|
a1957a156e | ||
|
|
6266e9ec3a | ||
|
|
7c4fcde88d | ||
|
|
d36b28c55a | ||
|
|
6b41340f1d | ||
|
|
4b9ea43402 | ||
|
|
e5f23a9189 | ||
|
|
15e3e32b47 |
@@ -2,6 +2,7 @@
|
|||||||
*
|
*
|
||||||
|
|
||||||
# Allow files and directories.
|
# Allow files and directories.
|
||||||
|
!api/
|
||||||
!cmd/
|
!cmd/
|
||||||
!internal/
|
!internal/
|
||||||
!pkg/
|
!pkg/
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ jobs:
|
|||||||
|
|
||||||
The commands below show how to install the nightly version of uncloud.
|
The commands below show how to install the nightly version of uncloud.
|
||||||
|
|
||||||
> **Warning**: These are nightly development builds and may be unstable.
|
> [!WARNING]
|
||||||
|
> These are nightly development builds and may be unstable.
|
||||||
|
|
||||||
**Install uncloud CLI:**
|
**Install uncloud CLI:**
|
||||||
|
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ uc context use <name> # Switch context
|
|||||||
- **Package naming**: Use clear, descriptive names
|
- **Package naming**: Use clear, descriptive names
|
||||||
- **Error handling**: Wrap errors with context using `fmt.Errorf`
|
- **Error handling**: Wrap errors with context using `fmt.Errorf`
|
||||||
- **Logging**: Use structured logging with levels
|
- **Logging**: Use structured logging with levels
|
||||||
- **gRPC**: Services defined in `internal/machine/api/pb/`
|
- **gRPC**: Services defined in `api/pb/`
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -107,7 +107,7 @@ make lint-and-fix
|
|||||||
|
|
||||||
## Code generation
|
## Code generation
|
||||||
|
|
||||||
Update the generated Go code for the machine gRPC API after modifying `.proto` files:
|
Update the generated Go code for the gRPC API after modifying files in [`api/pb`](./api/pb):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
mise run proto
|
mise run proto
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ Here is a diagram of an Uncloud multi-provider cluster of 3 machines:
|
|||||||
```bash
|
```bash
|
||||||
$ uc machine init --name oracle-vm ubuntu@152.67.101.197
|
$ uc machine init --name oracle-vm ubuntu@152.67.101.197
|
||||||
|
|
||||||
Downloading Uncloud install script: https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/install.sh
|
|
||||||
⏳ Running Uncloud install script...
|
⏳ Running Uncloud install script...
|
||||||
✓ Docker is already installed.
|
✓ Docker is already installed.
|
||||||
⏳ Installing Docker...
|
⏳ Installing Docker...
|
||||||
@@ -169,9 +168,6 @@ Downloading Uncloud install script: https://raw.githubusercontent.com/psviderski
|
|||||||
✓ uncloud-uninstall script installed: /usr/local/bin/uncloud-uninstall
|
✓ uncloud-uninstall script installed: /usr/local/bin/uncloud-uninstall
|
||||||
✓ Systemd unit file created: /etc/systemd/system/uncloud.service
|
✓ Systemd unit file created: /etc/systemd/system/uncloud.service
|
||||||
Created symlink /etc/systemd/system/multi-user.target.wants/uncloud.service → /etc/systemd/system/uncloud.service.
|
Created symlink /etc/systemd/system/multi-user.target.wants/uncloud.service → /etc/systemd/system/uncloud.service.
|
||||||
⏳ Downloading uncloud-corrosion binary: https://github.com/psviderski/corrosion/releases/latest/download/corrosion-aarch64-unknown-linux-gnu.tar.gz
|
|
||||||
✓ uncloud-corrosion binary installed: /usr/local/bin/uncloud-corrosion
|
|
||||||
✓ Systemd unit file created: /etc/systemd/system/uncloud-corrosion.service
|
|
||||||
⏳ Starting Uncloud machine daemon (uncloud.service)...
|
⏳ Starting Uncloud machine daemon (uncloud.service)...
|
||||||
✓ Uncloud machine daemon started.
|
✓ Uncloud machine daemon started.
|
||||||
✓ Uncloud installed on the machine successfully! 🎉
|
✓ Uncloud installed on the machine successfully! 🎉
|
||||||
@@ -190,21 +186,20 @@ DNS records updated to use only the internet-reachable machines running caddy se
|
|||||||
*.xuw3xd.cluster.uncloud.run A → 152.67.101.197
|
*.xuw3xd.cluster.uncloud.run A → 152.67.101.197
|
||||||
```
|
```
|
||||||
|
|
||||||
1. The CLI SSHs into the machine and installs Docker, the `uncloudd` machine daemon and
|
1. The CLI SSHs into the machine and installs Docker and the `uncloudd` machine daemon, managed by systemd.
|
||||||
[corrosion](https://github.com/superfly/corrosion) service, managed by systemd.
|
|
||||||
2. Generates a unique WireGuard key pair, allocates a dedicated subnet `10.210.0.0/24` for the machine and its
|
2. Generates a unique WireGuard key pair, allocates a dedicated subnet `10.210.0.0/24` for the machine and its
|
||||||
containers, and configures `uncloudd` accordingly. All subsequent communication happens with `uncloudd`
|
containers, and configures `uncloudd` accordingly. All subsequent communication happens with `uncloudd`
|
||||||
through its gRPC API over SSH.
|
through its gRPC API over SSH.
|
||||||
3. Configures and starts `corrosion`, a CRDT-based distributed SQLite database to share cluster state between machines.
|
3. Configures and starts [corrosion](https://github.com/superfly/corrosion), a CRDT-based distributed SQLite database to
|
||||||
|
share cluster state between machines, as a Docker container managed by `uncloudd`.
|
||||||
4. Creates a Docker bridge network connected to the WireGuard interface.
|
4. Creates a Docker bridge network connected to the WireGuard interface.
|
||||||
5. This machine becomes an entry point for the newly created cluster which is stored in the cluster config under
|
5. This machine becomes an entry point for the newly created cluster. Its address is stored as a connection info in the
|
||||||
`~/.config/uncloud` on your local machine.
|
cluster config at `~/.config/uncloud/config.yaml` on your local machine.
|
||||||
|
|
||||||
**When you add another machine:**
|
**When you add another machine:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ uc machine add --name hetzner-server root@5.223.45.199
|
$ uc machine add --name hetzner-server root@5.223.45.199
|
||||||
Downloading Uncloud install script: https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/install.sh
|
|
||||||
⏳ Running Uncloud install script...
|
⏳ Running Uncloud install script...
|
||||||
✓ Docker is already installed.
|
✓ Docker is already installed.
|
||||||
✓ Linux user and group 'uncloud' created.
|
✓ Linux user and group 'uncloud' created.
|
||||||
@@ -215,9 +210,6 @@ Downloading Uncloud install script: https://raw.githubusercontent.com/psviderski
|
|||||||
✓ uncloud-uninstall script installed: /usr/local/bin/uncloud-uninstall
|
✓ uncloud-uninstall script installed: /usr/local/bin/uncloud-uninstall
|
||||||
✓ Systemd unit file created: /etc/systemd/system/uncloud.service
|
✓ Systemd unit file created: /etc/systemd/system/uncloud.service
|
||||||
Created symlink /etc/systemd/system/multi-user.target.wants/uncloud.service → /etc/systemd/system/uncloud.service.
|
Created symlink /etc/systemd/system/multi-user.target.wants/uncloud.service → /etc/systemd/system/uncloud.service.
|
||||||
⏳ Downloading uncloud-corrosion binary: https://github.com/psviderski/corrosion/releases/latest/download/corrosion-x86_64-unknown-linux-gnu.tar.gz
|
|
||||||
✓ uncloud-corrosion binary installed: /usr/local/bin/uncloud-corrosion
|
|
||||||
✓ Systemd unit file created: /etc/systemd/system/uncloud-corrosion.service
|
|
||||||
⏳ Starting Uncloud machine daemon (uncloud.service)...
|
⏳ Starting Uncloud machine daemon (uncloud.service)...
|
||||||
✓ Uncloud machine daemon started.
|
✓ Uncloud machine daemon started.
|
||||||
✓ Uncloud installed on the machine successfully! 🎉
|
✓ Uncloud installed on the machine successfully! 🎉
|
||||||
@@ -246,9 +238,10 @@ hetzner-server Up 10.210.1.1/24 5.223.45.199 5.223.45.199:51820, [2
|
|||||||
3. Registers the second machine in the cluster state and exchanges WireGuard keys with the first machine.
|
3. Registers the second machine in the cluster state and exchanges WireGuard keys with the first machine.
|
||||||
4. Both machines establish a WireGuard tunnel between each other, allowing Docker containers connected to the bridge
|
4. Both machines establish a WireGuard tunnel between each other, allowing Docker containers connected to the bridge
|
||||||
network to communicate directly across machines.
|
network to communicate directly across machines.
|
||||||
5. Configures and starts `corrosion` on the second machine to sync the cluster state.
|
5. Configures and starts the `uncloud-corrosion` container on the second machine to sync the cluster state.
|
||||||
6. The second machine is added as an alternative entry point in the cluster config.
|
6. The second machine is added as an alternative entry point in the cluster config.
|
||||||
7. If one of the machines goes offline, the other machine can still serve cluster operations.
|
7. If one of the machines goes offline, the other machine can still be used by `uc` to connect and run cluster
|
||||||
|
operations.
|
||||||
|
|
||||||
If one more machine is added, the process repeats with a new subnet. The new machine needs to establish a WireGuard
|
If one more machine is added, the process repeats with a new subnet. The new machine needs to establish a WireGuard
|
||||||
connection with only one of the existing machines. Other machines will learn about it through the shared cluster state
|
connection with only one of the existing machines. Other machines will learn about it through the shared cluster state
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.34.2
|
||||||
|
// protoc v5.27.3
|
||||||
|
// source: api/pb/caddy.proto
|
||||||
|
|
||||||
|
package pb
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||||
|
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetCaddyConfigResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// The generated Caddyfile content.
|
||||||
|
Caddyfile string `protobuf:"bytes,1,opt,name=caddyfile,proto3" json:"caddyfile,omitempty"`
|
||||||
|
// Timestamp when the config was last modified.
|
||||||
|
ModifiedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=modified_at,json=modifiedAt,proto3" json:"modified_at,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetCaddyConfigResponse) Reset() {
|
||||||
|
*x = GetCaddyConfigResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_pb_caddy_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetCaddyConfigResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetCaddyConfigResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetCaddyConfigResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_pb_caddy_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetCaddyConfigResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetCaddyConfigResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_pb_caddy_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetCaddyConfigResponse) GetCaddyfile() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Caddyfile
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetCaddyConfigResponse) GetModifiedAt() *timestamppb.Timestamp {
|
||||||
|
if x != nil {
|
||||||
|
return x.ModifiedAt
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_api_pb_caddy_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_api_pb_caddy_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x12, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||||
|
0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79,
|
||||||
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
||||||
|
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x43, 0x61,
|
||||||
|
0x64, 0x64, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
|
0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x61, 0x64, 0x64, 0x79, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x64, 0x64, 0x79, 0x66, 0x69, 0x6c, 0x65, 0x12,
|
||||||
|
0x3b, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02,
|
||||||
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
||||||
|
0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x41, 0x74, 0x32, 0x49, 0x0a, 0x05,
|
||||||
|
0x43, 0x61, 0x64, 0x64, 0x79, 0x12, 0x40, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66,
|
||||||
|
0x69, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x61, 0x70, 0x69,
|
||||||
|
0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
|
||||||
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||||
|
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b, 0x69,
|
||||||
|
0x2f, 0x75, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x62,
|
||||||
|
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_api_pb_caddy_proto_rawDescOnce sync.Once
|
||||||
|
file_api_pb_caddy_proto_rawDescData = file_api_pb_caddy_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_api_pb_caddy_proto_rawDescGZIP() []byte {
|
||||||
|
file_api_pb_caddy_proto_rawDescOnce.Do(func() {
|
||||||
|
file_api_pb_caddy_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_pb_caddy_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_api_pb_caddy_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_api_pb_caddy_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
|
var file_api_pb_caddy_proto_goTypes = []any{
|
||||||
|
(*GetCaddyConfigResponse)(nil), // 0: api.GetCaddyConfigResponse
|
||||||
|
(*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp
|
||||||
|
(*emptypb.Empty)(nil), // 2: google.protobuf.Empty
|
||||||
|
}
|
||||||
|
var file_api_pb_caddy_proto_depIdxs = []int32{
|
||||||
|
1, // 0: api.GetCaddyConfigResponse.modified_at:type_name -> google.protobuf.Timestamp
|
||||||
|
2, // 1: api.Caddy.GetConfig:input_type -> google.protobuf.Empty
|
||||||
|
0, // 2: api.Caddy.GetConfig:output_type -> api.GetCaddyConfigResponse
|
||||||
|
2, // [2:3] is the sub-list for method output_type
|
||||||
|
1, // [1:2] is the sub-list for method input_type
|
||||||
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
|
0, // [0:1] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_api_pb_caddy_proto_init() }
|
||||||
|
func file_api_pb_caddy_proto_init() {
|
||||||
|
if File_api_pb_caddy_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_api_pb_caddy_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*GetCaddyConfigResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_api_pb_caddy_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 1,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_api_pb_caddy_proto_goTypes,
|
||||||
|
DependencyIndexes: file_api_pb_caddy_proto_depIdxs,
|
||||||
|
MessageInfos: file_api_pb_caddy_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_api_pb_caddy_proto = out.File
|
||||||
|
file_api_pb_caddy_proto_rawDesc = nil
|
||||||
|
file_api_pb_caddy_proto_goTypes = nil
|
||||||
|
file_api_pb_caddy_proto_depIdxs = nil
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ syntax = "proto3";
|
|||||||
|
|
||||||
package api;
|
package api;
|
||||||
|
|
||||||
option go_package = "github.com/psviderski/uncloud/internal/machine/api/pb";
|
option go_package = "github.com/psviderski/uncloud/api/pb";
|
||||||
|
|
||||||
import "google/protobuf/empty.proto";
|
import "google/protobuf/empty.proto";
|
||||||
import "google/protobuf/timestamp.proto";
|
import "google/protobuf/timestamp.proto";
|
||||||
@@ -17,4 +17,4 @@ message GetCaddyConfigResponse {
|
|||||||
string caddyfile = 1;
|
string caddyfile = 1;
|
||||||
// Timestamp when the config was last modified.
|
// Timestamp when the config was last modified.
|
||||||
google.protobuf.Timestamp modified_at = 2;
|
google.protobuf.Timestamp modified_at = 2;
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.5.1
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc v5.27.3
|
// - protoc v5.27.3
|
||||||
// source: internal/machine/api/pb/caddy.proto
|
// source: api/pb/caddy.proto
|
||||||
|
|
||||||
package pb
|
package pb
|
||||||
|
|
||||||
@@ -120,5 +120,5 @@ var Caddy_ServiceDesc = grpc.ServiceDesc{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{},
|
Streams: []grpc.StreamDesc{},
|
||||||
Metadata: "internal/machine/api/pb/caddy.proto",
|
Metadata: "api/pb/caddy.proto",
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,689 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.34.2
|
||||||
|
// protoc v5.27.3
|
||||||
|
// source: api/pb/caddy_storage.proto
|
||||||
|
|
||||||
|
package pb
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||||
|
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type StoreCaddyStorageRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StoreCaddyStorageRequest) Reset() {
|
||||||
|
*x = StoreCaddyStorageRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StoreCaddyStorageRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*StoreCaddyStorageRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *StoreCaddyStorageRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use StoreCaddyStorageRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*StoreCaddyStorageRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_pb_caddy_storage_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StoreCaddyStorageRequest) GetKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StoreCaddyStorageRequest) GetValue() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoadCaddyStorageRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LoadCaddyStorageRequest) Reset() {
|
||||||
|
*x = LoadCaddyStorageRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LoadCaddyStorageRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*LoadCaddyStorageRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *LoadCaddyStorageRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use LoadCaddyStorageRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*LoadCaddyStorageRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_pb_caddy_storage_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LoadCaddyStorageRequest) GetKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoadCaddyStorageResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LoadCaddyStorageResponse) Reset() {
|
||||||
|
*x = LoadCaddyStorageResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LoadCaddyStorageResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*LoadCaddyStorageResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *LoadCaddyStorageResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use LoadCaddyStorageResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*LoadCaddyStorageResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_pb_caddy_storage_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LoadCaddyStorageResponse) GetValue() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LoadCaddyStorageResponse) GetUpdatedAt() *timestamppb.Timestamp {
|
||||||
|
if x != nil {
|
||||||
|
return x.UpdatedAt
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteCaddyStorageRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DeleteCaddyStorageRequest) Reset() {
|
||||||
|
*x = DeleteCaddyStorageRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DeleteCaddyStorageRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*DeleteCaddyStorageRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *DeleteCaddyStorageRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use DeleteCaddyStorageRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*DeleteCaddyStorageRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_pb_caddy_storage_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DeleteCaddyStorageRequest) GetKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListCaddyStorageRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"`
|
||||||
|
Recursive bool `protobuf:"varint,2,opt,name=recursive,proto3" json:"recursive,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListCaddyStorageRequest) Reset() {
|
||||||
|
*x = ListCaddyStorageRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListCaddyStorageRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ListCaddyStorageRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ListCaddyStorageRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[4]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ListCaddyStorageRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ListCaddyStorageRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_pb_caddy_storage_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListCaddyStorageRequest) GetPrefix() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Prefix
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListCaddyStorageRequest) GetRecursive() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Recursive
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListCaddyStorageResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListCaddyStorageResponse) Reset() {
|
||||||
|
*x = ListCaddyStorageResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListCaddyStorageResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ListCaddyStorageResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ListCaddyStorageResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[5]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ListCaddyStorageResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ListCaddyStorageResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_pb_caddy_storage_proto_rawDescGZIP(), []int{5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListCaddyStorageResponse) GetKeys() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Keys
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatCaddyStorageRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageRequest) Reset() {
|
||||||
|
*x = StatCaddyStorageRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*StatCaddyStorageRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[6]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use StatCaddyStorageRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*StatCaddyStorageRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_pb_caddy_storage_proto_rawDescGZIP(), []int{6}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageRequest) GetKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatCaddyStorageResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
|
||||||
|
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
|
||||||
|
IsTerminal bool `protobuf:"varint,4,opt,name=is_terminal,json=isTerminal,proto3" json:"is_terminal,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageResponse) Reset() {
|
||||||
|
*x = StatCaddyStorageResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[7]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*StatCaddyStorageResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_pb_caddy_storage_proto_msgTypes[7]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use StatCaddyStorageResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*StatCaddyStorageResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_pb_caddy_storage_proto_rawDescGZIP(), []int{7}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageResponse) GetKey() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageResponse) GetUpdatedAt() *timestamppb.Timestamp {
|
||||||
|
if x != nil {
|
||||||
|
return x.UpdatedAt
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageResponse) GetSize() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Size
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StatCaddyStorageResponse) GetIsTerminal() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.IsTerminal
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_api_pb_caddy_storage_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_api_pb_caddy_storage_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x1a, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x61, 0x64, 0x64, 0x79, 0x5f, 0x73,
|
||||||
|
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70,
|
||||||
|
0x69, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||||
|
0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f,
|
||||||
|
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f,
|
||||||
|
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
||||||
|
0x42, 0x0a, 0x18, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f,
|
||||||
|
0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
||||||
|
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
|
||||||
|
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61,
|
||||||
|
0x6c, 0x75, 0x65, 0x22, 0x2b, 0x0a, 0x17, 0x4c, 0x6f, 0x61, 0x64, 0x43, 0x61, 0x64, 0x64, 0x79,
|
||||||
|
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10,
|
||||||
|
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
|
||||||
|
0x22, 0x6b, 0x0a, 0x18, 0x4c, 0x6f, 0x61, 0x64, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f,
|
||||||
|
0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05,
|
||||||
|
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c,
|
||||||
|
0x75, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74,
|
||||||
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||||
|
0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x2d, 0x0a,
|
||||||
|
0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72,
|
||||||
|
0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
||||||
|
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x4f, 0x0a, 0x17,
|
||||||
|
0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
|
||||||
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69,
|
||||||
|
0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12,
|
||||||
|
0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||||
|
0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x22, 0x2e, 0x0a,
|
||||||
|
0x18, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67,
|
||||||
|
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79,
|
||||||
|
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x2b, 0x0a,
|
||||||
|
0x17, 0x53, 0x74, 0x61, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67,
|
||||||
|
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
||||||
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x9c, 0x01, 0x0a, 0x18, 0x53,
|
||||||
|
0x74, 0x61, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52,
|
||||||
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64,
|
||||||
|
0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
|
||||||
|
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||||
|
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74,
|
||||||
|
0x65, 0x64, 0x41, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01,
|
||||||
|
0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x74,
|
||||||
|
0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69,
|
||||||
|
0x73, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x32, 0xdf, 0x02, 0x0a, 0x0c, 0x43, 0x61,
|
||||||
|
0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x3e, 0x0a, 0x05, 0x53, 0x74,
|
||||||
|
0x6f, 0x72, 0x65, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x43,
|
||||||
|
0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||||
|
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x43, 0x0a, 0x04, 0x4c, 0x6f,
|
||||||
|
0x61, 0x64, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x43, 0x61, 0x64,
|
||||||
|
0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
|
0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x43, 0x61, 0x64, 0x64, 0x79,
|
||||||
|
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
|
0x40, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||||
|
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61,
|
||||||
|
0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
|
||||||
|
0x79, 0x12, 0x43, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||||
|
0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
|
||||||
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69,
|
||||||
|
0x73, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65,
|
||||||
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x04, 0x53, 0x74, 0x61, 0x74, 0x12, 0x1c,
|
||||||
|
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74,
|
||||||
|
0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61,
|
||||||
|
0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x53, 0x74, 0x6f, 0x72,
|
||||||
|
0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x26, 0x5a, 0x24, 0x67,
|
||||||
|
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65,
|
||||||
|
0x72, 0x73, 0x6b, 0x69, 0x2f, 0x75, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x61, 0x70, 0x69,
|
||||||
|
0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_api_pb_caddy_storage_proto_rawDescOnce sync.Once
|
||||||
|
file_api_pb_caddy_storage_proto_rawDescData = file_api_pb_caddy_storage_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_api_pb_caddy_storage_proto_rawDescGZIP() []byte {
|
||||||
|
file_api_pb_caddy_storage_proto_rawDescOnce.Do(func() {
|
||||||
|
file_api_pb_caddy_storage_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_pb_caddy_storage_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_api_pb_caddy_storage_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_api_pb_caddy_storage_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||||
|
var file_api_pb_caddy_storage_proto_goTypes = []any{
|
||||||
|
(*StoreCaddyStorageRequest)(nil), // 0: api.StoreCaddyStorageRequest
|
||||||
|
(*LoadCaddyStorageRequest)(nil), // 1: api.LoadCaddyStorageRequest
|
||||||
|
(*LoadCaddyStorageResponse)(nil), // 2: api.LoadCaddyStorageResponse
|
||||||
|
(*DeleteCaddyStorageRequest)(nil), // 3: api.DeleteCaddyStorageRequest
|
||||||
|
(*ListCaddyStorageRequest)(nil), // 4: api.ListCaddyStorageRequest
|
||||||
|
(*ListCaddyStorageResponse)(nil), // 5: api.ListCaddyStorageResponse
|
||||||
|
(*StatCaddyStorageRequest)(nil), // 6: api.StatCaddyStorageRequest
|
||||||
|
(*StatCaddyStorageResponse)(nil), // 7: api.StatCaddyStorageResponse
|
||||||
|
(*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp
|
||||||
|
(*emptypb.Empty)(nil), // 9: google.protobuf.Empty
|
||||||
|
}
|
||||||
|
var file_api_pb_caddy_storage_proto_depIdxs = []int32{
|
||||||
|
8, // 0: api.LoadCaddyStorageResponse.updated_at:type_name -> google.protobuf.Timestamp
|
||||||
|
8, // 1: api.StatCaddyStorageResponse.updated_at:type_name -> google.protobuf.Timestamp
|
||||||
|
0, // 2: api.CaddyStorage.Store:input_type -> api.StoreCaddyStorageRequest
|
||||||
|
1, // 3: api.CaddyStorage.Load:input_type -> api.LoadCaddyStorageRequest
|
||||||
|
3, // 4: api.CaddyStorage.Delete:input_type -> api.DeleteCaddyStorageRequest
|
||||||
|
4, // 5: api.CaddyStorage.List:input_type -> api.ListCaddyStorageRequest
|
||||||
|
6, // 6: api.CaddyStorage.Stat:input_type -> api.StatCaddyStorageRequest
|
||||||
|
9, // 7: api.CaddyStorage.Store:output_type -> google.protobuf.Empty
|
||||||
|
2, // 8: api.CaddyStorage.Load:output_type -> api.LoadCaddyStorageResponse
|
||||||
|
9, // 9: api.CaddyStorage.Delete:output_type -> google.protobuf.Empty
|
||||||
|
5, // 10: api.CaddyStorage.List:output_type -> api.ListCaddyStorageResponse
|
||||||
|
7, // 11: api.CaddyStorage.Stat:output_type -> api.StatCaddyStorageResponse
|
||||||
|
7, // [7:12] is the sub-list for method output_type
|
||||||
|
2, // [2:7] is the sub-list for method input_type
|
||||||
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
|
0, // [0:2] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_api_pb_caddy_storage_proto_init() }
|
||||||
|
func file_api_pb_caddy_storage_proto_init() {
|
||||||
|
if File_api_pb_caddy_storage_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_api_pb_caddy_storage_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*StoreCaddyStorageRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_pb_caddy_storage_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*LoadCaddyStorageRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_pb_caddy_storage_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*LoadCaddyStorageResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_pb_caddy_storage_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*DeleteCaddyStorageRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_pb_caddy_storage_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*ListCaddyStorageRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_pb_caddy_storage_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*ListCaddyStorageResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_pb_caddy_storage_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*StatCaddyStorageRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_pb_caddy_storage_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*StatCaddyStorageResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_api_pb_caddy_storage_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 8,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_api_pb_caddy_storage_proto_goTypes,
|
||||||
|
DependencyIndexes: file_api_pb_caddy_storage_proto_depIdxs,
|
||||||
|
MessageInfos: file_api_pb_caddy_storage_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_api_pb_caddy_storage_proto = out.File
|
||||||
|
file_api_pb_caddy_storage_proto_rawDesc = nil
|
||||||
|
file_api_pb_caddy_storage_proto_goTypes = nil
|
||||||
|
file_api_pb_caddy_storage_proto_depIdxs = nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package api;
|
||||||
|
|
||||||
|
option go_package = "github.com/psviderski/uncloud/api/pb";
|
||||||
|
|
||||||
|
import "google/protobuf/empty.proto";
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
|
// CaddyStorage exposes the CertMagic storage operations backed by the distributed cluster store.
|
||||||
|
// Each request operates on the receiving machine's store replica. Callers that need replication to catch up before
|
||||||
|
// reading should capture store versions with Machine.InspectMachine and call Machine.WaitForStoreVersion on the
|
||||||
|
// receiving machine, subject to that RPC's data-availability limitations (see WaitForStoreVersion docs).
|
||||||
|
// See Storage interface in https://github.com/caddyserver/certmagic/blob/master/storage.go.
|
||||||
|
service CaddyStorage {
|
||||||
|
rpc Store(StoreCaddyStorageRequest) returns (google.protobuf.Empty);
|
||||||
|
rpc Load(LoadCaddyStorageRequest) returns (LoadCaddyStorageResponse);
|
||||||
|
rpc Delete(DeleteCaddyStorageRequest) returns (google.protobuf.Empty);
|
||||||
|
rpc List(ListCaddyStorageRequest) returns (ListCaddyStorageResponse);
|
||||||
|
rpc Stat(StatCaddyStorageRequest) returns (StatCaddyStorageResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message StoreCaddyStorageRequest {
|
||||||
|
string key = 1;
|
||||||
|
bytes value = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LoadCaddyStorageRequest {
|
||||||
|
string key = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LoadCaddyStorageResponse {
|
||||||
|
bytes value = 1;
|
||||||
|
google.protobuf.Timestamp updated_at = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteCaddyStorageRequest {
|
||||||
|
string key = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListCaddyStorageRequest {
|
||||||
|
string prefix = 1;
|
||||||
|
bool recursive = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListCaddyStorageResponse {
|
||||||
|
repeated string keys = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StatCaddyStorageRequest {
|
||||||
|
string key = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StatCaddyStorageResponse {
|
||||||
|
string key = 1;
|
||||||
|
google.protobuf.Timestamp updated_at = 2;
|
||||||
|
int64 size = 3;
|
||||||
|
bool is_terminal = 4;
|
||||||
|
}
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
|
// - protoc v5.27.3
|
||||||
|
// source: api/pb/caddy_storage.proto
|
||||||
|
|
||||||
|
package pb
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.64.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion9
|
||||||
|
|
||||||
|
const (
|
||||||
|
CaddyStorage_Store_FullMethodName = "/api.CaddyStorage/Store"
|
||||||
|
CaddyStorage_Load_FullMethodName = "/api.CaddyStorage/Load"
|
||||||
|
CaddyStorage_Delete_FullMethodName = "/api.CaddyStorage/Delete"
|
||||||
|
CaddyStorage_List_FullMethodName = "/api.CaddyStorage/List"
|
||||||
|
CaddyStorage_Stat_FullMethodName = "/api.CaddyStorage/Stat"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CaddyStorageClient is the client API for CaddyStorage service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
//
|
||||||
|
// CaddyStorage exposes the CertMagic storage operations backed by the distributed cluster store.
|
||||||
|
// Each request operates on the receiving machine's store replica. Callers that need replication to catch up before
|
||||||
|
// reading should capture store versions with Machine.InspectMachine and call Machine.WaitForStoreVersion on the
|
||||||
|
// receiving machine, subject to that RPC's data-availability limitations (see WaitForStoreVersion docs).
|
||||||
|
// See Storage interface in https://github.com/caddyserver/certmagic/blob/master/storage.go.
|
||||||
|
type CaddyStorageClient interface {
|
||||||
|
Store(ctx context.Context, in *StoreCaddyStorageRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||||
|
Load(ctx context.Context, in *LoadCaddyStorageRequest, opts ...grpc.CallOption) (*LoadCaddyStorageResponse, error)
|
||||||
|
Delete(ctx context.Context, in *DeleteCaddyStorageRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||||
|
List(ctx context.Context, in *ListCaddyStorageRequest, opts ...grpc.CallOption) (*ListCaddyStorageResponse, error)
|
||||||
|
Stat(ctx context.Context, in *StatCaddyStorageRequest, opts ...grpc.CallOption) (*StatCaddyStorageResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type caddyStorageClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCaddyStorageClient(cc grpc.ClientConnInterface) CaddyStorageClient {
|
||||||
|
return &caddyStorageClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *caddyStorageClient) Store(ctx context.Context, in *StoreCaddyStorageRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(emptypb.Empty)
|
||||||
|
err := c.cc.Invoke(ctx, CaddyStorage_Store_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *caddyStorageClient) Load(ctx context.Context, in *LoadCaddyStorageRequest, opts ...grpc.CallOption) (*LoadCaddyStorageResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(LoadCaddyStorageResponse)
|
||||||
|
err := c.cc.Invoke(ctx, CaddyStorage_Load_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *caddyStorageClient) Delete(ctx context.Context, in *DeleteCaddyStorageRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(emptypb.Empty)
|
||||||
|
err := c.cc.Invoke(ctx, CaddyStorage_Delete_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *caddyStorageClient) List(ctx context.Context, in *ListCaddyStorageRequest, opts ...grpc.CallOption) (*ListCaddyStorageResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(ListCaddyStorageResponse)
|
||||||
|
err := c.cc.Invoke(ctx, CaddyStorage_List_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *caddyStorageClient) Stat(ctx context.Context, in *StatCaddyStorageRequest, opts ...grpc.CallOption) (*StatCaddyStorageResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(StatCaddyStorageResponse)
|
||||||
|
err := c.cc.Invoke(ctx, CaddyStorage_Stat_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaddyStorageServer is the server API for CaddyStorage service.
|
||||||
|
// All implementations must embed UnimplementedCaddyStorageServer
|
||||||
|
// for forward compatibility.
|
||||||
|
//
|
||||||
|
// CaddyStorage exposes the CertMagic storage operations backed by the distributed cluster store.
|
||||||
|
// Each request operates on the receiving machine's store replica. Callers that need replication to catch up before
|
||||||
|
// reading should capture store versions with Machine.InspectMachine and call Machine.WaitForStoreVersion on the
|
||||||
|
// receiving machine, subject to that RPC's data-availability limitations (see WaitForStoreVersion docs).
|
||||||
|
// See Storage interface in https://github.com/caddyserver/certmagic/blob/master/storage.go.
|
||||||
|
type CaddyStorageServer interface {
|
||||||
|
Store(context.Context, *StoreCaddyStorageRequest) (*emptypb.Empty, error)
|
||||||
|
Load(context.Context, *LoadCaddyStorageRequest) (*LoadCaddyStorageResponse, error)
|
||||||
|
Delete(context.Context, *DeleteCaddyStorageRequest) (*emptypb.Empty, error)
|
||||||
|
List(context.Context, *ListCaddyStorageRequest) (*ListCaddyStorageResponse, error)
|
||||||
|
Stat(context.Context, *StatCaddyStorageRequest) (*StatCaddyStorageResponse, error)
|
||||||
|
mustEmbedUnimplementedCaddyStorageServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedCaddyStorageServer must be embedded to have
|
||||||
|
// forward compatible implementations.
|
||||||
|
//
|
||||||
|
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||||
|
// pointer dereference when methods are called.
|
||||||
|
type UnimplementedCaddyStorageServer struct{}
|
||||||
|
|
||||||
|
func (UnimplementedCaddyStorageServer) Store(context.Context, *StoreCaddyStorageRequest) (*emptypb.Empty, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Store not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedCaddyStorageServer) Load(context.Context, *LoadCaddyStorageRequest) (*LoadCaddyStorageResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Load not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedCaddyStorageServer) Delete(context.Context, *DeleteCaddyStorageRequest) (*emptypb.Empty, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedCaddyStorageServer) List(context.Context, *ListCaddyStorageRequest) (*ListCaddyStorageResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method List not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedCaddyStorageServer) Stat(context.Context, *StatCaddyStorageRequest) (*StatCaddyStorageResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Stat not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedCaddyStorageServer) mustEmbedUnimplementedCaddyStorageServer() {}
|
||||||
|
func (UnimplementedCaddyStorageServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
|
// UnsafeCaddyStorageServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to CaddyStorageServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeCaddyStorageServer interface {
|
||||||
|
mustEmbedUnimplementedCaddyStorageServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterCaddyStorageServer(s grpc.ServiceRegistrar, srv CaddyStorageServer) {
|
||||||
|
// If the following call pancis, it indicates UnimplementedCaddyStorageServer was
|
||||||
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||||
|
t.testEmbeddedByValue()
|
||||||
|
}
|
||||||
|
s.RegisterService(&CaddyStorage_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _CaddyStorage_Store_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(StoreCaddyStorageRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(CaddyStorageServer).Store(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: CaddyStorage_Store_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(CaddyStorageServer).Store(ctx, req.(*StoreCaddyStorageRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _CaddyStorage_Load_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(LoadCaddyStorageRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(CaddyStorageServer).Load(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: CaddyStorage_Load_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(CaddyStorageServer).Load(ctx, req.(*LoadCaddyStorageRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _CaddyStorage_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(DeleteCaddyStorageRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(CaddyStorageServer).Delete(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: CaddyStorage_Delete_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(CaddyStorageServer).Delete(ctx, req.(*DeleteCaddyStorageRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _CaddyStorage_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(ListCaddyStorageRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(CaddyStorageServer).List(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: CaddyStorage_List_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(CaddyStorageServer).List(ctx, req.(*ListCaddyStorageRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _CaddyStorage_Stat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(StatCaddyStorageRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(CaddyStorageServer).Stat(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: CaddyStorage_Stat_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(CaddyStorageServer).Stat(ctx, req.(*StatCaddyStorageRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaddyStorage_ServiceDesc is the grpc.ServiceDesc for CaddyStorage service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var CaddyStorage_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "api.CaddyStorage",
|
||||||
|
HandlerType: (*CaddyStorageServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "Store",
|
||||||
|
Handler: _CaddyStorage_Store_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Load",
|
||||||
|
Handler: _CaddyStorage_Load_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Delete",
|
||||||
|
Handler: _CaddyStorage_Delete_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "List",
|
||||||
|
Handler: _CaddyStorage_List_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Stat",
|
||||||
|
Handler: _CaddyStorage_Stat_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "api/pb/caddy_storage.proto",
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.34.2
|
// protoc-gen-go v1.34.2
|
||||||
// protoc v5.27.3
|
// protoc v5.27.3
|
||||||
// source: internal/machine/api/pb/cluster.proto
|
// source: api/pb/cluster.proto
|
||||||
|
|
||||||
package pb
|
package pb
|
||||||
|
|
||||||
@@ -62,11 +62,11 @@ func (x MachineMember_MembershipState) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (MachineMember_MembershipState) Descriptor() protoreflect.EnumDescriptor {
|
func (MachineMember_MembershipState) Descriptor() protoreflect.EnumDescriptor {
|
||||||
return file_internal_machine_api_pb_cluster_proto_enumTypes[0].Descriptor()
|
return file_api_pb_cluster_proto_enumTypes[0].Descriptor()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (MachineMember_MembershipState) Type() protoreflect.EnumType {
|
func (MachineMember_MembershipState) Type() protoreflect.EnumType {
|
||||||
return &file_internal_machine_api_pb_cluster_proto_enumTypes[0]
|
return &file_api_pb_cluster_proto_enumTypes[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x MachineMember_MembershipState) Number() protoreflect.EnumNumber {
|
func (x MachineMember_MembershipState) Number() protoreflect.EnumNumber {
|
||||||
@@ -75,7 +75,7 @@ func (x MachineMember_MembershipState) Number() protoreflect.EnumNumber {
|
|||||||
|
|
||||||
// Deprecated: Use MachineMember_MembershipState.Descriptor instead.
|
// Deprecated: Use MachineMember_MembershipState.Descriptor instead.
|
||||||
func (MachineMember_MembershipState) EnumDescriptor() ([]byte, []int) {
|
func (MachineMember_MembershipState) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{2, 0}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{2, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DNSRecord_RecordType int32
|
type DNSRecord_RecordType int32
|
||||||
@@ -111,11 +111,11 @@ func (x DNSRecord_RecordType) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (DNSRecord_RecordType) Descriptor() protoreflect.EnumDescriptor {
|
func (DNSRecord_RecordType) Descriptor() protoreflect.EnumDescriptor {
|
||||||
return file_internal_machine_api_pb_cluster_proto_enumTypes[1].Descriptor()
|
return file_api_pb_cluster_proto_enumTypes[1].Descriptor()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (DNSRecord_RecordType) Type() protoreflect.EnumType {
|
func (DNSRecord_RecordType) Type() protoreflect.EnumType {
|
||||||
return &file_internal_machine_api_pb_cluster_proto_enumTypes[1]
|
return &file_api_pb_cluster_proto_enumTypes[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x DNSRecord_RecordType) Number() protoreflect.EnumNumber {
|
func (x DNSRecord_RecordType) Number() protoreflect.EnumNumber {
|
||||||
@@ -124,7 +124,7 @@ func (x DNSRecord_RecordType) Number() protoreflect.EnumNumber {
|
|||||||
|
|
||||||
// Deprecated: Use DNSRecord_RecordType.Descriptor instead.
|
// Deprecated: Use DNSRecord_RecordType.Descriptor instead.
|
||||||
func (DNSRecord_RecordType) EnumDescriptor() ([]byte, []int) {
|
func (DNSRecord_RecordType) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{9, 0}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{9, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddMachineRequest struct {
|
type AddMachineRequest struct {
|
||||||
@@ -140,7 +140,7 @@ type AddMachineRequest struct {
|
|||||||
func (x *AddMachineRequest) Reset() {
|
func (x *AddMachineRequest) Reset() {
|
||||||
*x = AddMachineRequest{}
|
*x = AddMachineRequest{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[0]
|
mi := &file_api_pb_cluster_proto_msgTypes[0]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ func (x *AddMachineRequest) String() string {
|
|||||||
func (*AddMachineRequest) ProtoMessage() {}
|
func (*AddMachineRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *AddMachineRequest) ProtoReflect() protoreflect.Message {
|
func (x *AddMachineRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[0]
|
mi := &file_api_pb_cluster_proto_msgTypes[0]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -166,7 +166,7 @@ func (x *AddMachineRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use AddMachineRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use AddMachineRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*AddMachineRequest) Descriptor() ([]byte, []int) {
|
func (*AddMachineRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{0}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddMachineRequest) GetName() string {
|
func (x *AddMachineRequest) GetName() string {
|
||||||
@@ -201,7 +201,7 @@ type AddMachineResponse struct {
|
|||||||
func (x *AddMachineResponse) Reset() {
|
func (x *AddMachineResponse) Reset() {
|
||||||
*x = AddMachineResponse{}
|
*x = AddMachineResponse{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[1]
|
mi := &file_api_pb_cluster_proto_msgTypes[1]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -214,7 +214,7 @@ func (x *AddMachineResponse) String() string {
|
|||||||
func (*AddMachineResponse) ProtoMessage() {}
|
func (*AddMachineResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *AddMachineResponse) ProtoReflect() protoreflect.Message {
|
func (x *AddMachineResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[1]
|
mi := &file_api_pb_cluster_proto_msgTypes[1]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -227,7 +227,7 @@ func (x *AddMachineResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use AddMachineResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use AddMachineResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*AddMachineResponse) Descriptor() ([]byte, []int) {
|
func (*AddMachineResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{1}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AddMachineResponse) GetMachine() *MachineInfo {
|
func (x *AddMachineResponse) GetMachine() *MachineInfo {
|
||||||
@@ -249,7 +249,7 @@ type MachineMember struct {
|
|||||||
func (x *MachineMember) Reset() {
|
func (x *MachineMember) Reset() {
|
||||||
*x = MachineMember{}
|
*x = MachineMember{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[2]
|
mi := &file_api_pb_cluster_proto_msgTypes[2]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -262,7 +262,7 @@ func (x *MachineMember) String() string {
|
|||||||
func (*MachineMember) ProtoMessage() {}
|
func (*MachineMember) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *MachineMember) ProtoReflect() protoreflect.Message {
|
func (x *MachineMember) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[2]
|
mi := &file_api_pb_cluster_proto_msgTypes[2]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -275,7 +275,7 @@ func (x *MachineMember) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use MachineMember.ProtoReflect.Descriptor instead.
|
// Deprecated: Use MachineMember.ProtoReflect.Descriptor instead.
|
||||||
func (*MachineMember) Descriptor() ([]byte, []int) {
|
func (*MachineMember) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{2}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MachineMember) GetMachine() *MachineInfo {
|
func (x *MachineMember) GetMachine() *MachineInfo {
|
||||||
@@ -303,7 +303,7 @@ type ListMachinesResponse struct {
|
|||||||
func (x *ListMachinesResponse) Reset() {
|
func (x *ListMachinesResponse) Reset() {
|
||||||
*x = ListMachinesResponse{}
|
*x = ListMachinesResponse{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[3]
|
mi := &file_api_pb_cluster_proto_msgTypes[3]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -316,7 +316,7 @@ func (x *ListMachinesResponse) String() string {
|
|||||||
func (*ListMachinesResponse) ProtoMessage() {}
|
func (*ListMachinesResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message {
|
func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[3]
|
mi := &file_api_pb_cluster_proto_msgTypes[3]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -329,7 +329,7 @@ func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use ListMachinesResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use ListMachinesResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*ListMachinesResponse) Descriptor() ([]byte, []int) {
|
func (*ListMachinesResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{3}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ListMachinesResponse) GetMachines() []*MachineMember {
|
func (x *ListMachinesResponse) GetMachines() []*MachineMember {
|
||||||
@@ -350,7 +350,7 @@ type RemoveMachineRequest struct {
|
|||||||
func (x *RemoveMachineRequest) Reset() {
|
func (x *RemoveMachineRequest) Reset() {
|
||||||
*x = RemoveMachineRequest{}
|
*x = RemoveMachineRequest{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[4]
|
mi := &file_api_pb_cluster_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -363,7 +363,7 @@ func (x *RemoveMachineRequest) String() string {
|
|||||||
func (*RemoveMachineRequest) ProtoMessage() {}
|
func (*RemoveMachineRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *RemoveMachineRequest) ProtoReflect() protoreflect.Message {
|
func (x *RemoveMachineRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[4]
|
mi := &file_api_pb_cluster_proto_msgTypes[4]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -376,7 +376,7 @@ func (x *RemoveMachineRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use RemoveMachineRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use RemoveMachineRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*RemoveMachineRequest) Descriptor() ([]byte, []int) {
|
func (*RemoveMachineRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{4}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RemoveMachineRequest) GetId() string {
|
func (x *RemoveMachineRequest) GetId() string {
|
||||||
@@ -397,7 +397,7 @@ type Domain struct {
|
|||||||
func (x *Domain) Reset() {
|
func (x *Domain) Reset() {
|
||||||
*x = Domain{}
|
*x = Domain{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[5]
|
mi := &file_api_pb_cluster_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -410,7 +410,7 @@ func (x *Domain) String() string {
|
|||||||
func (*Domain) ProtoMessage() {}
|
func (*Domain) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Domain) ProtoReflect() protoreflect.Message {
|
func (x *Domain) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[5]
|
mi := &file_api_pb_cluster_proto_msgTypes[5]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -423,7 +423,7 @@ func (x *Domain) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Domain.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Domain.ProtoReflect.Descriptor instead.
|
||||||
func (*Domain) Descriptor() ([]byte, []int) {
|
func (*Domain) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{5}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Domain) GetName() string {
|
func (x *Domain) GetName() string {
|
||||||
@@ -444,7 +444,7 @@ type ReserveDomainRequest struct {
|
|||||||
func (x *ReserveDomainRequest) Reset() {
|
func (x *ReserveDomainRequest) Reset() {
|
||||||
*x = ReserveDomainRequest{}
|
*x = ReserveDomainRequest{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[6]
|
mi := &file_api_pb_cluster_proto_msgTypes[6]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -457,7 +457,7 @@ func (x *ReserveDomainRequest) String() string {
|
|||||||
func (*ReserveDomainRequest) ProtoMessage() {}
|
func (*ReserveDomainRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *ReserveDomainRequest) ProtoReflect() protoreflect.Message {
|
func (x *ReserveDomainRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[6]
|
mi := &file_api_pb_cluster_proto_msgTypes[6]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -470,7 +470,7 @@ func (x *ReserveDomainRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use ReserveDomainRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use ReserveDomainRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*ReserveDomainRequest) Descriptor() ([]byte, []int) {
|
func (*ReserveDomainRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{6}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReserveDomainRequest) GetEndpoint() string {
|
func (x *ReserveDomainRequest) GetEndpoint() string {
|
||||||
@@ -491,7 +491,7 @@ type CreateDomainRecordsRequest struct {
|
|||||||
func (x *CreateDomainRecordsRequest) Reset() {
|
func (x *CreateDomainRecordsRequest) Reset() {
|
||||||
*x = CreateDomainRecordsRequest{}
|
*x = CreateDomainRecordsRequest{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[7]
|
mi := &file_api_pb_cluster_proto_msgTypes[7]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -504,7 +504,7 @@ func (x *CreateDomainRecordsRequest) String() string {
|
|||||||
func (*CreateDomainRecordsRequest) ProtoMessage() {}
|
func (*CreateDomainRecordsRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *CreateDomainRecordsRequest) ProtoReflect() protoreflect.Message {
|
func (x *CreateDomainRecordsRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[7]
|
mi := &file_api_pb_cluster_proto_msgTypes[7]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -517,7 +517,7 @@ func (x *CreateDomainRecordsRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use CreateDomainRecordsRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use CreateDomainRecordsRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*CreateDomainRecordsRequest) Descriptor() ([]byte, []int) {
|
func (*CreateDomainRecordsRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{7}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *CreateDomainRecordsRequest) GetRecords() []*DNSRecord {
|
func (x *CreateDomainRecordsRequest) GetRecords() []*DNSRecord {
|
||||||
@@ -538,7 +538,7 @@ type CreateDomainRecordsResponse struct {
|
|||||||
func (x *CreateDomainRecordsResponse) Reset() {
|
func (x *CreateDomainRecordsResponse) Reset() {
|
||||||
*x = CreateDomainRecordsResponse{}
|
*x = CreateDomainRecordsResponse{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[8]
|
mi := &file_api_pb_cluster_proto_msgTypes[8]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -551,7 +551,7 @@ func (x *CreateDomainRecordsResponse) String() string {
|
|||||||
func (*CreateDomainRecordsResponse) ProtoMessage() {}
|
func (*CreateDomainRecordsResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *CreateDomainRecordsResponse) ProtoReflect() protoreflect.Message {
|
func (x *CreateDomainRecordsResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[8]
|
mi := &file_api_pb_cluster_proto_msgTypes[8]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -564,7 +564,7 @@ func (x *CreateDomainRecordsResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use CreateDomainRecordsResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use CreateDomainRecordsResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*CreateDomainRecordsResponse) Descriptor() ([]byte, []int) {
|
func (*CreateDomainRecordsResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{8}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{8}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *CreateDomainRecordsResponse) GetRecords() []*DNSRecord {
|
func (x *CreateDomainRecordsResponse) GetRecords() []*DNSRecord {
|
||||||
@@ -587,7 +587,7 @@ type DNSRecord struct {
|
|||||||
func (x *DNSRecord) Reset() {
|
func (x *DNSRecord) Reset() {
|
||||||
*x = DNSRecord{}
|
*x = DNSRecord{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[9]
|
mi := &file_api_pb_cluster_proto_msgTypes[9]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -600,7 +600,7 @@ func (x *DNSRecord) String() string {
|
|||||||
func (*DNSRecord) ProtoMessage() {}
|
func (*DNSRecord) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *DNSRecord) ProtoReflect() protoreflect.Message {
|
func (x *DNSRecord) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_cluster_proto_msgTypes[9]
|
mi := &file_api_pb_cluster_proto_msgTypes[9]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -613,7 +613,7 @@ func (x *DNSRecord) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use DNSRecord.ProtoReflect.Descriptor instead.
|
// Deprecated: Use DNSRecord.ProtoReflect.Descriptor instead.
|
||||||
func (*DNSRecord) Descriptor() ([]byte, []int) {
|
func (*DNSRecord) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescGZIP(), []int{9}
|
return file_api_pb_cluster_proto_rawDescGZIP(), []int{9}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *DNSRecord) GetName() string {
|
func (x *DNSRecord) GetName() string {
|
||||||
@@ -637,123 +637,119 @@ func (x *DNSRecord) GetValues() []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_internal_machine_api_pb_cluster_proto protoreflect.FileDescriptor
|
var File_api_pb_cluster_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_internal_machine_api_pb_cluster_proto_rawDesc = []byte{
|
var file_api_pb_cluster_proto_rawDesc = []byte{
|
||||||
0x0a, 0x25, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
0x0a, 0x14, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
|
||||||
0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69, 0x1a, 0x1b, 0x67, 0x6f, 0x6f,
|
||||||
0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69, 0x1a, 0x1b, 0x67, 0x6f,
|
0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70,
|
||||||
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d,
|
0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62,
|
||||||
0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x24, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x61,
|
||||||
0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f,
|
0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2e, 0x70, 0x72,
|
||||||
0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
|
0x6f, 0x74, 0x6f, 0x22, 0x7b, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
||||||
0x25, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x07,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7b, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63,
|
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e,
|
||||||
0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e,
|
0x61, 0x70, 0x69, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||||
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
|
0x67, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x24, 0x0a, 0x09, 0x70, 0x75,
|
||||||
0x2c, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e,
|
||||||
0x32, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x6f,
|
0x61, 0x70, 0x69, 0x2e, 0x49, 0x50, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x70,
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x24, 0x0a,
|
0x22, 0x40, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65,
|
||||||
0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
||||||
0x32, 0x07, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x50, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69,
|
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61,
|
||||||
0x63, 0x49, 0x70, 0x22, 0x40, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
||||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x07, 0x6d, 0x61, 0x63,
|
0x6e, 0x65, 0x22, 0xb4, 0x01, 0x0a, 0x0d, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x4d, 0x65,
|
||||||
0x68, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69,
|
0x6d, 0x62, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18,
|
||||||
0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6d, 0x61,
|
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63, 0x68,
|
||||||
0x63, 0x68, 0x69, 0x6e, 0x65, 0x22, 0xb4, 0x01, 0x0a, 0x0d, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
0x69, 0x6e, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
||||||
0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
0x12, 0x38, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||||
0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d,
|
0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x4d, 0x65, 0x6d,
|
||||||
0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68,
|
0x62, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74,
|
||||||
0x69, 0x6e, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01,
|
0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x3d, 0x0a, 0x0f, 0x4d, 0x65,
|
||||||
0x28, 0x0e, 0x32, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a,
|
||||||
0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69,
|
0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x55, 0x50,
|
||||||
0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x3d, 0x0a,
|
0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x53, 0x50, 0x45, 0x43, 0x54, 0x10, 0x02, 0x12,
|
||||||
0x0f, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65,
|
0x08, 0x0a, 0x04, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x22, 0x46, 0x0a, 0x14, 0x4c, 0x69, 0x73,
|
||||||
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x06, 0x0a,
|
0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x02, 0x55, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x53, 0x50, 0x45, 0x43, 0x54,
|
0x65, 0x12, 0x2e, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20,
|
||||||
0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x22, 0x46, 0x0a, 0x14,
|
0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
||||||
0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
|
0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
||||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73,
|
0x73, 0x22, 0x26, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
||||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63,
|
0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||||
0x68, 0x69, 0x6e, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x68,
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1c, 0x0a, 0x06, 0x44, 0x6f, 0x6d,
|
||||||
0x69, 0x6e, 0x65, 0x73, 0x22, 0x26, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x61,
|
0x61, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02,
|
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x32, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x65, 0x72,
|
||||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1c, 0x0a, 0x06,
|
0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x32, 0x0a, 0x14, 0x52, 0x65,
|
0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x46, 0x0a, 0x1a, 0x43,
|
||||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
|
||||||
0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01,
|
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x46,
|
|
||||||
0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65,
|
|
||||||
0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x07,
|
|
||||||
0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
|
|
||||||
0x61, 0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72,
|
|
||||||
0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x47, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
|
||||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73,
|
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73,
|
|
||||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53,
|
|
||||||
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22,
|
|
||||||
0x96, 0x01, 0x0a, 0x09, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a,
|
|
||||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
|
|
||||||
0x65, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
|
||||||
0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e,
|
|
||||||
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
|
||||||
0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09,
|
|
||||||
0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x2e, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f,
|
|
||||||
0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
|
|
||||||
0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x05, 0x0a, 0x01, 0x41, 0x10, 0x01, 0x12, 0x08,
|
|
||||||
0x0a, 0x04, 0x41, 0x41, 0x41, 0x41, 0x10, 0x02, 0x32, 0xca, 0x03, 0x0a, 0x07, 0x43, 0x6c, 0x75,
|
|
||||||
0x73, 0x74, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
|
||||||
0x6e, 0x65, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68,
|
|
||||||
0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69,
|
|
||||||
0x2e, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
|
||||||
0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
|
||||||
0x6e, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x61, 0x70,
|
|
||||||
0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65,
|
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
|
||||||
0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65,
|
|
||||||
0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
|
||||||
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
|
||||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x37, 0x0a, 0x0d, 0x52, 0x65,
|
|
||||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x70,
|
|
||||||
0x69, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
|
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x6d,
|
|
||||||
0x61, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
|
||||||
0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
|
||||||
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44,
|
|
||||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
|
|
||||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0b,
|
|
||||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x58, 0x0a, 0x13, 0x43,
|
|
||||||
0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72,
|
0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72,
|
||||||
0x64, 0x73, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44,
|
0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x07, 0x72, 0x65, 0x63,
|
||||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75,
|
0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69,
|
||||||
0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f,
|
||||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73,
|
0x72, 0x64, 0x73, 0x22, 0x47, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b, 0x69, 0x2f, 0x75,
|
0x73, 0x65, 0x12, 0x28, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20,
|
||||||
0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63,
|
||||||
0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x62, 0x06,
|
0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x96, 0x01, 0x0a,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x09, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
|
||||||
|
0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d,
|
||||||
|
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x61,
|
||||||
|
0x70, 0x69, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x52, 0x65, 0x63,
|
||||||
|
0x6f, 0x72, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a,
|
||||||
|
0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76,
|
||||||
|
0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x2e, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54,
|
||||||
|
0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
|
||||||
|
0x45, 0x44, 0x10, 0x00, 0x12, 0x05, 0x0a, 0x01, 0x41, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x41,
|
||||||
|
0x41, 0x41, 0x41, 0x10, 0x02, 0x32, 0xca, 0x03, 0x0a, 0x07, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65,
|
||||||
|
0x72, 0x12, 0x3d, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12,
|
||||||
|
0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
||||||
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64,
|
||||||
|
0x64, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
|
0x12, 0x41, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73,
|
||||||
|
0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||||
|
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c,
|
||||||
|
0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
|
0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x61, 0x63,
|
||||||
|
0x68, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76,
|
||||||
|
0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
|
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||||
|
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x37, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x65, 0x72,
|
||||||
|
0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52,
|
||||||
|
0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75,
|
||||||
|
0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||||
|
0x12, 0x30, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x16, 0x2e,
|
||||||
|
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||||
|
0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x6d, 0x61,
|
||||||
|
0x69, 0x6e, 0x12, 0x34, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x44, 0x6f, 0x6d,
|
||||||
|
0x61, 0x69, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0b, 0x2e, 0x61, 0x70,
|
||||||
|
0x69, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x58, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61,
|
||||||
|
0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12,
|
||||||
|
0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61,
|
||||||
|
0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
|
0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d,
|
||||||
|
0x61, 0x69, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
|
0x73, 0x65, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
|
0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b, 0x69, 0x2f, 0x75, 0x6e, 0x63, 0x6c,
|
||||||
|
0x6f, 0x75, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_internal_machine_api_pb_cluster_proto_rawDescOnce sync.Once
|
file_api_pb_cluster_proto_rawDescOnce sync.Once
|
||||||
file_internal_machine_api_pb_cluster_proto_rawDescData = file_internal_machine_api_pb_cluster_proto_rawDesc
|
file_api_pb_cluster_proto_rawDescData = file_api_pb_cluster_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_internal_machine_api_pb_cluster_proto_rawDescGZIP() []byte {
|
func file_api_pb_cluster_proto_rawDescGZIP() []byte {
|
||||||
file_internal_machine_api_pb_cluster_proto_rawDescOnce.Do(func() {
|
file_api_pb_cluster_proto_rawDescOnce.Do(func() {
|
||||||
file_internal_machine_api_pb_cluster_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_machine_api_pb_cluster_proto_rawDescData)
|
file_api_pb_cluster_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_pb_cluster_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_internal_machine_api_pb_cluster_proto_rawDescData
|
return file_api_pb_cluster_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_internal_machine_api_pb_cluster_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
var file_api_pb_cluster_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||||
var file_internal_machine_api_pb_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
var file_api_pb_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||||
var file_internal_machine_api_pb_cluster_proto_goTypes = []any{
|
var file_api_pb_cluster_proto_goTypes = []any{
|
||||||
(MachineMember_MembershipState)(0), // 0: api.MachineMember.MembershipState
|
(MachineMember_MembershipState)(0), // 0: api.MachineMember.MembershipState
|
||||||
(DNSRecord_RecordType)(0), // 1: api.DNSRecord.RecordType
|
(DNSRecord_RecordType)(0), // 1: api.DNSRecord.RecordType
|
||||||
(*AddMachineRequest)(nil), // 2: api.AddMachineRequest
|
(*AddMachineRequest)(nil), // 2: api.AddMachineRequest
|
||||||
@@ -771,7 +767,7 @@ var file_internal_machine_api_pb_cluster_proto_goTypes = []any{
|
|||||||
(*MachineInfo)(nil), // 14: api.MachineInfo
|
(*MachineInfo)(nil), // 14: api.MachineInfo
|
||||||
(*emptypb.Empty)(nil), // 15: google.protobuf.Empty
|
(*emptypb.Empty)(nil), // 15: google.protobuf.Empty
|
||||||
}
|
}
|
||||||
var file_internal_machine_api_pb_cluster_proto_depIdxs = []int32{
|
var file_api_pb_cluster_proto_depIdxs = []int32{
|
||||||
12, // 0: api.AddMachineRequest.network:type_name -> api.NetworkConfig
|
12, // 0: api.AddMachineRequest.network:type_name -> api.NetworkConfig
|
||||||
13, // 1: api.AddMachineRequest.public_ip:type_name -> api.IP
|
13, // 1: api.AddMachineRequest.public_ip:type_name -> api.IP
|
||||||
14, // 2: api.AddMachineResponse.machine:type_name -> api.MachineInfo
|
14, // 2: api.AddMachineResponse.machine:type_name -> api.MachineInfo
|
||||||
@@ -802,15 +798,15 @@ var file_internal_machine_api_pb_cluster_proto_depIdxs = []int32{
|
|||||||
0, // [0:9] is the sub-list for field type_name
|
0, // [0:9] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_internal_machine_api_pb_cluster_proto_init() }
|
func init() { file_api_pb_cluster_proto_init() }
|
||||||
func file_internal_machine_api_pb_cluster_proto_init() {
|
func file_api_pb_cluster_proto_init() {
|
||||||
if File_internal_machine_api_pb_cluster_proto != nil {
|
if File_api_pb_cluster_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_common_proto_init()
|
file_api_pb_common_proto_init()
|
||||||
file_internal_machine_api_pb_machine_proto_init()
|
file_api_pb_machine_proto_init()
|
||||||
if !protoimpl.UnsafeEnabled {
|
if !protoimpl.UnsafeEnabled {
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*AddMachineRequest); i {
|
switch v := v.(*AddMachineRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -822,7 +818,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*AddMachineResponse); i {
|
switch v := v.(*AddMachineResponse); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -834,7 +830,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*MachineMember); i {
|
switch v := v.(*MachineMember); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -846,7 +842,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*ListMachinesResponse); i {
|
switch v := v.(*ListMachinesResponse); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -858,7 +854,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*RemoveMachineRequest); i {
|
switch v := v.(*RemoveMachineRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -870,7 +866,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*Domain); i {
|
switch v := v.(*Domain); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -882,7 +878,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*ReserveDomainRequest); i {
|
switch v := v.(*ReserveDomainRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -894,7 +890,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*CreateDomainRecordsRequest); i {
|
switch v := v.(*CreateDomainRecordsRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -906,7 +902,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[8].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[8].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*CreateDomainRecordsResponse); i {
|
switch v := v.(*CreateDomainRecordsResponse); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -918,7 +914,7 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_cluster_proto_msgTypes[9].Exporter = func(v any, i int) any {
|
file_api_pb_cluster_proto_msgTypes[9].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*DNSRecord); i {
|
switch v := v.(*DNSRecord); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -935,19 +931,19 @@ func file_internal_machine_api_pb_cluster_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_internal_machine_api_pb_cluster_proto_rawDesc,
|
RawDescriptor: file_api_pb_cluster_proto_rawDesc,
|
||||||
NumEnums: 2,
|
NumEnums: 2,
|
||||||
NumMessages: 10,
|
NumMessages: 10,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
GoTypes: file_internal_machine_api_pb_cluster_proto_goTypes,
|
GoTypes: file_api_pb_cluster_proto_goTypes,
|
||||||
DependencyIndexes: file_internal_machine_api_pb_cluster_proto_depIdxs,
|
DependencyIndexes: file_api_pb_cluster_proto_depIdxs,
|
||||||
EnumInfos: file_internal_machine_api_pb_cluster_proto_enumTypes,
|
EnumInfos: file_api_pb_cluster_proto_enumTypes,
|
||||||
MessageInfos: file_internal_machine_api_pb_cluster_proto_msgTypes,
|
MessageInfos: file_api_pb_cluster_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_internal_machine_api_pb_cluster_proto = out.File
|
File_api_pb_cluster_proto = out.File
|
||||||
file_internal_machine_api_pb_cluster_proto_rawDesc = nil
|
file_api_pb_cluster_proto_rawDesc = nil
|
||||||
file_internal_machine_api_pb_cluster_proto_goTypes = nil
|
file_api_pb_cluster_proto_goTypes = nil
|
||||||
file_internal_machine_api_pb_cluster_proto_depIdxs = nil
|
file_api_pb_cluster_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
@@ -2,11 +2,11 @@ syntax = "proto3";
|
|||||||
|
|
||||||
package api;
|
package api;
|
||||||
|
|
||||||
option go_package = "github.com/psviderski/uncloud/internal/machine/api/pb";
|
option go_package = "github.com/psviderski/uncloud/api/pb";
|
||||||
|
|
||||||
import "google/protobuf/empty.proto";
|
import "google/protobuf/empty.proto";
|
||||||
import "internal/machine/api/pb/common.proto";
|
import "api/pb/common.proto";
|
||||||
import "internal/machine/api/pb/machine.proto";
|
import "api/pb/machine.proto";
|
||||||
|
|
||||||
service Cluster {
|
service Cluster {
|
||||||
rpc AddMachine(AddMachineRequest) returns (AddMachineResponse);
|
rpc AddMachine(AddMachineRequest) returns (AddMachineResponse);
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.5.1
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc v5.27.3
|
// - protoc v5.27.3
|
||||||
// source: internal/machine/api/pb/cluster.proto
|
// source: api/pb/cluster.proto
|
||||||
|
|
||||||
package pb
|
package pb
|
||||||
|
|
||||||
@@ -346,5 +346,5 @@ var Cluster_ServiceDesc = grpc.ServiceDesc{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{},
|
Streams: []grpc.StreamDesc{},
|
||||||
Metadata: "internal/machine/api/pb/cluster.proto",
|
Metadata: "api/pb/cluster.proto",
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.34.2
|
// protoc-gen-go v1.34.2
|
||||||
// protoc v5.27.3
|
// protoc v5.27.3
|
||||||
// source: internal/machine/api/pb/common.proto
|
// source: api/pb/common.proto
|
||||||
|
|
||||||
package pb
|
package pb
|
||||||
|
|
||||||
@@ -58,11 +58,11 @@ func (x LogEntry_StreamType) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (LogEntry_StreamType) Descriptor() protoreflect.EnumDescriptor {
|
func (LogEntry_StreamType) Descriptor() protoreflect.EnumDescriptor {
|
||||||
return file_internal_machine_api_pb_common_proto_enumTypes[0].Descriptor()
|
return file_api_pb_common_proto_enumTypes[0].Descriptor()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (LogEntry_StreamType) Type() protoreflect.EnumType {
|
func (LogEntry_StreamType) Type() protoreflect.EnumType {
|
||||||
return &file_internal_machine_api_pb_common_proto_enumTypes[0]
|
return &file_api_pb_common_proto_enumTypes[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x LogEntry_StreamType) Number() protoreflect.EnumNumber {
|
func (x LogEntry_StreamType) Number() protoreflect.EnumNumber {
|
||||||
@@ -71,7 +71,7 @@ func (x LogEntry_StreamType) Number() protoreflect.EnumNumber {
|
|||||||
|
|
||||||
// Deprecated: Use LogEntry_StreamType.Descriptor instead.
|
// Deprecated: Use LogEntry_StreamType.Descriptor instead.
|
||||||
func (LogEntry_StreamType) EnumDescriptor() ([]byte, []int) {
|
func (LogEntry_StreamType) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescGZIP(), []int{7, 0}
|
return file_api_pb_common_proto_rawDescGZIP(), []int{7, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common metadata message nested in all reply message types, injected by the gRPC proxy to provide information
|
// Common metadata message nested in all reply message types, injected by the gRPC proxy to provide information
|
||||||
@@ -96,7 +96,7 @@ type Metadata struct {
|
|||||||
func (x *Metadata) Reset() {
|
func (x *Metadata) Reset() {
|
||||||
*x = Metadata{}
|
*x = Metadata{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[0]
|
mi := &file_api_pb_common_proto_msgTypes[0]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ func (x *Metadata) String() string {
|
|||||||
func (*Metadata) ProtoMessage() {}
|
func (*Metadata) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Metadata) ProtoReflect() protoreflect.Message {
|
func (x *Metadata) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[0]
|
mi := &file_api_pb_common_proto_msgTypes[0]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -122,7 +122,7 @@ func (x *Metadata) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Metadata.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Metadata.ProtoReflect.Descriptor instead.
|
||||||
func (*Metadata) Descriptor() ([]byte, []int) {
|
func (*Metadata) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescGZIP(), []int{0}
|
return file_api_pb_common_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Metadata) GetMachineId() string {
|
func (x *Metadata) GetMachineId() string {
|
||||||
@@ -172,7 +172,7 @@ type Empty struct {
|
|||||||
func (x *Empty) Reset() {
|
func (x *Empty) Reset() {
|
||||||
*x = Empty{}
|
*x = Empty{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[1]
|
mi := &file_api_pb_common_proto_msgTypes[1]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,7 @@ func (x *Empty) String() string {
|
|||||||
func (*Empty) ProtoMessage() {}
|
func (*Empty) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Empty) ProtoReflect() protoreflect.Message {
|
func (x *Empty) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[1]
|
mi := &file_api_pb_common_proto_msgTypes[1]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -198,7 +198,7 @@ func (x *Empty) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Empty.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Empty.ProtoReflect.Descriptor instead.
|
||||||
func (*Empty) Descriptor() ([]byte, []int) {
|
func (*Empty) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescGZIP(), []int{1}
|
return file_api_pb_common_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Empty) GetMetadata() *Metadata {
|
func (x *Empty) GetMetadata() *Metadata {
|
||||||
@@ -221,7 +221,7 @@ type EmptyResponse struct {
|
|||||||
func (x *EmptyResponse) Reset() {
|
func (x *EmptyResponse) Reset() {
|
||||||
*x = EmptyResponse{}
|
*x = EmptyResponse{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[2]
|
mi := &file_api_pb_common_proto_msgTypes[2]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -234,7 +234,7 @@ func (x *EmptyResponse) String() string {
|
|||||||
func (*EmptyResponse) ProtoMessage() {}
|
func (*EmptyResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *EmptyResponse) ProtoReflect() protoreflect.Message {
|
func (x *EmptyResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[2]
|
mi := &file_api_pb_common_proto_msgTypes[2]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -247,7 +247,7 @@ func (x *EmptyResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use EmptyResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use EmptyResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*EmptyResponse) Descriptor() ([]byte, []int) {
|
func (*EmptyResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescGZIP(), []int{2}
|
return file_api_pb_common_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EmptyResponse) GetMessages() []*Empty {
|
func (x *EmptyResponse) GetMessages() []*Empty {
|
||||||
@@ -268,7 +268,7 @@ type IP struct {
|
|||||||
func (x *IP) Reset() {
|
func (x *IP) Reset() {
|
||||||
*x = IP{}
|
*x = IP{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[3]
|
mi := &file_api_pb_common_proto_msgTypes[3]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ func (x *IP) String() string {
|
|||||||
func (*IP) ProtoMessage() {}
|
func (*IP) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *IP) ProtoReflect() protoreflect.Message {
|
func (x *IP) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[3]
|
mi := &file_api_pb_common_proto_msgTypes[3]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -294,7 +294,7 @@ func (x *IP) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use IP.ProtoReflect.Descriptor instead.
|
// Deprecated: Use IP.ProtoReflect.Descriptor instead.
|
||||||
func (*IP) Descriptor() ([]byte, []int) {
|
func (*IP) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescGZIP(), []int{3}
|
return file_api_pb_common_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *IP) GetIp() []byte {
|
func (x *IP) GetIp() []byte {
|
||||||
@@ -316,7 +316,7 @@ type IPPort struct {
|
|||||||
func (x *IPPort) Reset() {
|
func (x *IPPort) Reset() {
|
||||||
*x = IPPort{}
|
*x = IPPort{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[4]
|
mi := &file_api_pb_common_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ func (x *IPPort) String() string {
|
|||||||
func (*IPPort) ProtoMessage() {}
|
func (*IPPort) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *IPPort) ProtoReflect() protoreflect.Message {
|
func (x *IPPort) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[4]
|
mi := &file_api_pb_common_proto_msgTypes[4]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -342,7 +342,7 @@ func (x *IPPort) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use IPPort.ProtoReflect.Descriptor instead.
|
// Deprecated: Use IPPort.ProtoReflect.Descriptor instead.
|
||||||
func (*IPPort) Descriptor() ([]byte, []int) {
|
func (*IPPort) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescGZIP(), []int{4}
|
return file_api_pb_common_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *IPPort) GetIp() *IP {
|
func (x *IPPort) GetIp() *IP {
|
||||||
@@ -371,7 +371,7 @@ type IPPrefix struct {
|
|||||||
func (x *IPPrefix) Reset() {
|
func (x *IPPrefix) Reset() {
|
||||||
*x = IPPrefix{}
|
*x = IPPrefix{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[5]
|
mi := &file_api_pb_common_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -384,7 +384,7 @@ func (x *IPPrefix) String() string {
|
|||||||
func (*IPPrefix) ProtoMessage() {}
|
func (*IPPrefix) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *IPPrefix) ProtoReflect() protoreflect.Message {
|
func (x *IPPrefix) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[5]
|
mi := &file_api_pb_common_proto_msgTypes[5]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -397,7 +397,7 @@ func (x *IPPrefix) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use IPPrefix.ProtoReflect.Descriptor instead.
|
// Deprecated: Use IPPrefix.ProtoReflect.Descriptor instead.
|
||||||
func (*IPPrefix) Descriptor() ([]byte, []int) {
|
func (*IPPrefix) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescGZIP(), []int{5}
|
return file_api_pb_common_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *IPPrefix) GetIp() *IP {
|
func (x *IPPrefix) GetIp() *IP {
|
||||||
@@ -430,7 +430,7 @@ type LogsRequest struct {
|
|||||||
func (x *LogsRequest) Reset() {
|
func (x *LogsRequest) Reset() {
|
||||||
*x = LogsRequest{}
|
*x = LogsRequest{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[6]
|
mi := &file_api_pb_common_proto_msgTypes[6]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -443,7 +443,7 @@ func (x *LogsRequest) String() string {
|
|||||||
func (*LogsRequest) ProtoMessage() {}
|
func (*LogsRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *LogsRequest) ProtoReflect() protoreflect.Message {
|
func (x *LogsRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[6]
|
mi := &file_api_pb_common_proto_msgTypes[6]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -456,7 +456,7 @@ func (x *LogsRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use LogsRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use LogsRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*LogsRequest) Descriptor() ([]byte, []int) {
|
func (*LogsRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescGZIP(), []int{6}
|
return file_api_pb_common_proto_rawDescGZIP(), []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *LogsRequest) GetId() string {
|
func (x *LogsRequest) GetId() string {
|
||||||
@@ -508,7 +508,7 @@ type LogEntry struct {
|
|||||||
func (x *LogEntry) Reset() {
|
func (x *LogEntry) Reset() {
|
||||||
*x = LogEntry{}
|
*x = LogEntry{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[7]
|
mi := &file_api_pb_common_proto_msgTypes[7]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -521,7 +521,7 @@ func (x *LogEntry) String() string {
|
|||||||
func (*LogEntry) ProtoMessage() {}
|
func (*LogEntry) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *LogEntry) ProtoReflect() protoreflect.Message {
|
func (x *LogEntry) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_internal_machine_api_pb_common_proto_msgTypes[7]
|
mi := &file_api_pb_common_proto_msgTypes[7]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -534,7 +534,7 @@ func (x *LogEntry) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use LogEntry.ProtoReflect.Descriptor instead.
|
// Deprecated: Use LogEntry.ProtoReflect.Descriptor instead.
|
||||||
func (*LogEntry) Descriptor() ([]byte, []int) {
|
func (*LogEntry) Descriptor() ([]byte, []int) {
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescGZIP(), []int{7}
|
return file_api_pb_common_proto_rawDescGZIP(), []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *LogEntry) GetStream() LogEntry_StreamType {
|
func (x *LogEntry) GetStream() LogEntry_StreamType {
|
||||||
@@ -558,84 +558,82 @@ func (x *LogEntry) GetMessage() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_internal_machine_api_pb_common_proto protoreflect.FileDescriptor
|
var File_api_pb_common_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_internal_machine_api_pb_common_proto_rawDesc = []byte{
|
var file_api_pb_common_proto_rawDesc = []byte{
|
||||||
0x0a, 0x24, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
0x0a, 0x13, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||||
0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69, 0x1a, 0x17, 0x67, 0x6f, 0x6f,
|
0x6c, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72,
|
||||||
0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70,
|
0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
|
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70,
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e,
|
0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb1, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb1, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
|
0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18,
|
||||||
0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64,
|
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64,
|
||||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49,
|
0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
|
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x4e,
|
||||||
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x61,
|
||||||
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f,
|
0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
||||||
0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x63, 0x68,
|
0x6e, 0x65, 0x41, 0x64, 0x64, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18,
|
||||||
0x69, 0x6e, 0x65, 0x41, 0x64, 0x64, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x06,
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2a, 0x0a,
|
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67,
|
||||||
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e,
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75,
|
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x32, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74,
|
||||||
0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x32, 0x0a, 0x05, 0x45, 0x6d, 0x70,
|
0x79, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20,
|
||||||
0x74, 0x79, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01,
|
0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
|
0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x37, 0x0a, 0x0d,
|
||||||
0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x37, 0x0a,
|
0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a,
|
||||||
0x0d, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26,
|
0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||||
0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
0x0a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x73,
|
||||||
0x32, 0x0a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x08, 0x6d, 0x65,
|
0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x14, 0x0a, 0x02, 0x49, 0x50, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x14, 0x0a, 0x02, 0x49, 0x50, 0x12, 0x0e, 0x0a, 0x02,
|
0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x22, 0x35, 0x0a, 0x06, 0x49,
|
||||||
0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x22, 0x35, 0x0a, 0x06,
|
0x50, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x49, 0x50, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01,
|
0x0b, 0x32, 0x07, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x50, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12,
|
||||||
0x28, 0x0b, 0x32, 0x07, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x50, 0x52, 0x02, 0x69, 0x70, 0x12,
|
0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f,
|
||||||
0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70,
|
0x72, 0x74, 0x22, 0x37, 0x0a, 0x08, 0x49, 0x50, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x17,
|
||||||
0x6f, 0x72, 0x74, 0x22, 0x37, 0x0a, 0x08, 0x49, 0x50, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12,
|
0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x61, 0x70, 0x69,
|
||||||
0x17, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x61, 0x70,
|
0x2e, 0x49, 0x50, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18,
|
||||||
0x69, 0x2e, 0x49, 0x50, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73,
|
0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x22, 0x75, 0x0a, 0x0b, 0x4c,
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x22, 0x75, 0x0a, 0x0b,
|
0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||||
0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f,
|
||||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66,
|
0x6c, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x6c,
|
||||||
0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x66, 0x6f, 0x6c,
|
0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
|
||||||
0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
|
0x52, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18,
|
||||||
0x05, 0x52, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65,
|
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05,
|
||||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x14, 0x0a,
|
0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x75, 0x6e, 0x74,
|
||||||
0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x75, 0x6e,
|
0x69, 0x6c, 0x22, 0xd2, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
|
||||||
0x74, 0x69, 0x6c, 0x22, 0xd2, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
0x30, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||||
0x12, 0x30, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
|
0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53,
|
||||||
0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e,
|
0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61,
|
||||||
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65,
|
0x6d, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02,
|
||||||
0x61, 0x6d, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18,
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x6d,
|
||||||
0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x18, 0x0a, 0x07,
|
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65,
|
||||||
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d,
|
0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x40, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54,
|
||||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x40, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
|
0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00,
|
||||||
0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10,
|
0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x44, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06,
|
||||||
0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x44, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a,
|
0x53, 0x54, 0x44, 0x45, 0x52, 0x52, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x45, 0x41, 0x52,
|
||||||
0x06, 0x53, 0x54, 0x44, 0x45, 0x52, 0x52, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x45, 0x41,
|
0x54, 0x42, 0x45, 0x41, 0x54, 0x10, 0x03, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||||
0x52, 0x54, 0x42, 0x45, 0x41, 0x54, 0x10, 0x03, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68,
|
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b, 0x69,
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b,
|
0x2f, 0x75, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x62,
|
||||||
0x69, 0x2f, 0x75, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70,
|
|
||||||
0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_internal_machine_api_pb_common_proto_rawDescOnce sync.Once
|
file_api_pb_common_proto_rawDescOnce sync.Once
|
||||||
file_internal_machine_api_pb_common_proto_rawDescData = file_internal_machine_api_pb_common_proto_rawDesc
|
file_api_pb_common_proto_rawDescData = file_api_pb_common_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_internal_machine_api_pb_common_proto_rawDescGZIP() []byte {
|
func file_api_pb_common_proto_rawDescGZIP() []byte {
|
||||||
file_internal_machine_api_pb_common_proto_rawDescOnce.Do(func() {
|
file_api_pb_common_proto_rawDescOnce.Do(func() {
|
||||||
file_internal_machine_api_pb_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_machine_api_pb_common_proto_rawDescData)
|
file_api_pb_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_pb_common_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_internal_machine_api_pb_common_proto_rawDescData
|
return file_api_pb_common_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_internal_machine_api_pb_common_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_api_pb_common_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
var file_internal_machine_api_pb_common_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
var file_api_pb_common_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||||
var file_internal_machine_api_pb_common_proto_goTypes = []any{
|
var file_api_pb_common_proto_goTypes = []any{
|
||||||
(LogEntry_StreamType)(0), // 0: api.LogEntry.StreamType
|
(LogEntry_StreamType)(0), // 0: api.LogEntry.StreamType
|
||||||
(*Metadata)(nil), // 1: api.Metadata
|
(*Metadata)(nil), // 1: api.Metadata
|
||||||
(*Empty)(nil), // 2: api.Empty
|
(*Empty)(nil), // 2: api.Empty
|
||||||
@@ -648,7 +646,7 @@ var file_internal_machine_api_pb_common_proto_goTypes = []any{
|
|||||||
(*status.Status)(nil), // 9: google.rpc.Status
|
(*status.Status)(nil), // 9: google.rpc.Status
|
||||||
(*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp
|
(*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp
|
||||||
}
|
}
|
||||||
var file_internal_machine_api_pb_common_proto_depIdxs = []int32{
|
var file_api_pb_common_proto_depIdxs = []int32{
|
||||||
9, // 0: api.Metadata.status:type_name -> google.rpc.Status
|
9, // 0: api.Metadata.status:type_name -> google.rpc.Status
|
||||||
1, // 1: api.Empty.metadata:type_name -> api.Metadata
|
1, // 1: api.Empty.metadata:type_name -> api.Metadata
|
||||||
2, // 2: api.EmptyResponse.messages:type_name -> api.Empty
|
2, // 2: api.EmptyResponse.messages:type_name -> api.Empty
|
||||||
@@ -663,13 +661,13 @@ var file_internal_machine_api_pb_common_proto_depIdxs = []int32{
|
|||||||
0, // [0:7] is the sub-list for field type_name
|
0, // [0:7] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_internal_machine_api_pb_common_proto_init() }
|
func init() { file_api_pb_common_proto_init() }
|
||||||
func file_internal_machine_api_pb_common_proto_init() {
|
func file_api_pb_common_proto_init() {
|
||||||
if File_internal_machine_api_pb_common_proto != nil {
|
if File_api_pb_common_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !protoimpl.UnsafeEnabled {
|
if !protoimpl.UnsafeEnabled {
|
||||||
file_internal_machine_api_pb_common_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
file_api_pb_common_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*Metadata); i {
|
switch v := v.(*Metadata); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -681,7 +679,7 @@ func file_internal_machine_api_pb_common_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_common_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
file_api_pb_common_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*Empty); i {
|
switch v := v.(*Empty); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -693,7 +691,7 @@ func file_internal_machine_api_pb_common_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_common_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
file_api_pb_common_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*EmptyResponse); i {
|
switch v := v.(*EmptyResponse); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -705,7 +703,7 @@ func file_internal_machine_api_pb_common_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_common_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
file_api_pb_common_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*IP); i {
|
switch v := v.(*IP); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -717,7 +715,7 @@ func file_internal_machine_api_pb_common_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_common_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
file_api_pb_common_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*IPPort); i {
|
switch v := v.(*IPPort); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -729,7 +727,7 @@ func file_internal_machine_api_pb_common_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_common_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
file_api_pb_common_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*IPPrefix); i {
|
switch v := v.(*IPPrefix); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -741,7 +739,7 @@ func file_internal_machine_api_pb_common_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_common_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
file_api_pb_common_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*LogsRequest); i {
|
switch v := v.(*LogsRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -753,7 +751,7 @@ func file_internal_machine_api_pb_common_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_internal_machine_api_pb_common_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
file_api_pb_common_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*LogEntry); i {
|
switch v := v.(*LogEntry); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -770,19 +768,19 @@ func file_internal_machine_api_pb_common_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_internal_machine_api_pb_common_proto_rawDesc,
|
RawDescriptor: file_api_pb_common_proto_rawDesc,
|
||||||
NumEnums: 1,
|
NumEnums: 1,
|
||||||
NumMessages: 8,
|
NumMessages: 8,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
GoTypes: file_internal_machine_api_pb_common_proto_goTypes,
|
GoTypes: file_api_pb_common_proto_goTypes,
|
||||||
DependencyIndexes: file_internal_machine_api_pb_common_proto_depIdxs,
|
DependencyIndexes: file_api_pb_common_proto_depIdxs,
|
||||||
EnumInfos: file_internal_machine_api_pb_common_proto_enumTypes,
|
EnumInfos: file_api_pb_common_proto_enumTypes,
|
||||||
MessageInfos: file_internal_machine_api_pb_common_proto_msgTypes,
|
MessageInfos: file_api_pb_common_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_internal_machine_api_pb_common_proto = out.File
|
File_api_pb_common_proto = out.File
|
||||||
file_internal_machine_api_pb_common_proto_rawDesc = nil
|
file_api_pb_common_proto_rawDesc = nil
|
||||||
file_internal_machine_api_pb_common_proto_goTypes = nil
|
file_api_pb_common_proto_goTypes = nil
|
||||||
file_internal_machine_api_pb_common_proto_depIdxs = nil
|
file_api_pb_common_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,9 @@ syntax = "proto3";
|
|||||||
|
|
||||||
package api;
|
package api;
|
||||||
|
|
||||||
option go_package = "github.com/psviderski/uncloud/internal/machine/api/pb";
|
option go_package = "github.com/psviderski/uncloud/api/pb";
|
||||||
|
|
||||||
// Vendored at internal/machine/api/vendor/google/rpc/status.proto.
|
// Vendored at api/pb/vendor/google/rpc/status.proto.
|
||||||
import "google/rpc/status.proto";
|
import "google/rpc/status.proto";
|
||||||
import "google/protobuf/timestamp.proto";
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -2,10 +2,10 @@ syntax = "proto3";
|
|||||||
|
|
||||||
package api;
|
package api;
|
||||||
|
|
||||||
option go_package = "github.com/psviderski/uncloud/internal/machine/api/pb";
|
option go_package = "github.com/psviderski/uncloud/api/pb";
|
||||||
|
|
||||||
import "google/protobuf/empty.proto";
|
import "google/protobuf/empty.proto";
|
||||||
import "internal/machine/api/pb/common.proto";
|
import "api/pb/common.proto";
|
||||||
|
|
||||||
service Docker {
|
service Docker {
|
||||||
rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse);
|
rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse);
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.5.1
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc v5.27.3
|
// - protoc v5.27.3
|
||||||
// source: internal/machine/api/pb/docker.proto
|
// source: api/pb/docker.proto
|
||||||
|
|
||||||
package pb
|
package pb
|
||||||
|
|
||||||
@@ -807,5 +807,5 @@ var Docker_ServiceDesc = grpc.ServiceDesc{
|
|||||||
ServerStreams: true,
|
ServerStreams: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Metadata: "internal/machine/api/pb/docker.proto",
|
Metadata: "api/pb/docker.proto",
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -2,12 +2,12 @@ syntax = "proto3";
|
|||||||
|
|
||||||
package api;
|
package api;
|
||||||
|
|
||||||
option go_package = "github.com/psviderski/uncloud/internal/machine/api/pb";
|
option go_package = "github.com/psviderski/uncloud/api/pb";
|
||||||
|
|
||||||
import "google/protobuf/duration.proto";
|
import "google/protobuf/duration.proto";
|
||||||
import "google/protobuf/empty.proto";
|
import "google/protobuf/empty.proto";
|
||||||
import "google/protobuf/timestamp.proto";
|
import "google/protobuf/timestamp.proto";
|
||||||
import "internal/machine/api/pb/common.proto";
|
import "api/pb/common.proto";
|
||||||
|
|
||||||
service Machine {
|
service Machine {
|
||||||
// CheckPrerequisites verifies if the machine meets all necessary system requirements to participate in the cluster.
|
// CheckPrerequisites verifies if the machine meets all necessary system requirements to participate in the cluster.
|
||||||
@@ -19,6 +19,22 @@ service Machine {
|
|||||||
rpc Inspect(google.protobuf.Empty) returns (MachineInfo);
|
rpc Inspect(google.protobuf.Empty) returns (MachineInfo);
|
||||||
// InspectMachine retrieves detailed information about the machine. Supports broadcasting to multiple machines.
|
// InspectMachine retrieves detailed information about the machine. Supports broadcasting to multiple machines.
|
||||||
rpc InspectMachine(google.protobuf.Empty) returns (InspectMachineResponse);
|
rpc InspectMachine(google.protobuf.Empty) returns (InspectMachineResponse);
|
||||||
|
// WaitForStoreVersion waits until the cluster store on this machine has reached each requested actor version, with
|
||||||
|
// no known missing or pending transactions through those versions.
|
||||||
|
// Corrosion may satisfy a version by applying its surviving changes or by marking it complete because its changes
|
||||||
|
// have been superseded.
|
||||||
|
//
|
||||||
|
// Waiting normally makes the captured data available on this machine. However, another write may replace some of that
|
||||||
|
// data before it arrives. Corrosion can then complete the older version without transferring the replaced data.
|
||||||
|
// If the replacement is outside the requested versions, this RPC can succeed while the affected data is still missing
|
||||||
|
// or outdated. This can happen during concurrent updates even when all machines are well connected.
|
||||||
|
//
|
||||||
|
// Success does not guarantee an exact snapshot or delivery of every historical value. Callers that require a specific
|
||||||
|
// record or condition should verify it after waiting.
|
||||||
|
//
|
||||||
|
// This RPC observes native replication without initiating synchronisation.
|
||||||
|
// Use the RPC deadline to bound the wait.
|
||||||
|
rpc WaitForStoreVersion(WaitForStoreVersionRequest) returns (google.protobuf.Empty);
|
||||||
// UpdateMachine updates the configuration of the machine.
|
// UpdateMachine updates the configuration of the machine.
|
||||||
rpc UpdateMachine(UpdateMachineRequest) returns (UpdateMachineResponse);
|
rpc UpdateMachine(UpdateMachineRequest) returns (UpdateMachineResponse);
|
||||||
// InspectWireGuardNetwork retrieves the current WireGuard network configuration and peer status.
|
// InspectWireGuardNetwork retrieves the current WireGuard network configuration and peer status.
|
||||||
@@ -105,8 +121,8 @@ message JoinClusterRequest {
|
|||||||
// MTU of the WireGuard interface on this machine. The daemon auto-detects the optimal MTU if 0 or not set.
|
// MTU of the WireGuard interface on this machine. The daemon auto-detects the optimal MTU if 0 or not set.
|
||||||
int32 wireguard_mtu = 7;
|
int32 wireguard_mtu = 7;
|
||||||
// Cluster store version this machine must reach before participating.
|
// Cluster store version this machine must reach before participating.
|
||||||
// Per-actor vector (Corrosion actor UUID → max applied db_version).
|
// Per-actor vector (Corrosion actor UUID → minimum required db_version).
|
||||||
map<string, int64> min_store_version = 6;
|
map<string, uint64> min_store_version = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InspectMachineResponse {
|
message InspectMachineResponse {
|
||||||
@@ -119,9 +135,24 @@ message MachineDetails {
|
|||||||
MachineInfo machine = 2;
|
MachineInfo machine = 2;
|
||||||
// Round-trip times to other machines in the cluster, keyed by peer machine ID.
|
// Round-trip times to other machines in the cluster, keyed by peer machine ID.
|
||||||
map<string, RTTStats> rtts = 4;
|
map<string, RTTStats> rtts = 4;
|
||||||
// Current cluster store version observed on this machine.
|
// Store replication progress observed on this machine.
|
||||||
// Per-actor vector (Corrosion actor UUID → max applied db_version) read from Corrosion crsql_db_versions.
|
// Maps each Corrosion actor UUID to its highest processed database version. Corrosion also counts versions whose
|
||||||
map<string, int64> store_version = 5;
|
// changes were superseded and skipped. Versions at or below a reported version may still be missing or pending
|
||||||
|
// locally.
|
||||||
|
//
|
||||||
|
// Pass this vector to WaitForStoreVersion on another machine to wait for replication through these versions.
|
||||||
|
// See that RPC's data-availability limitations. To combine observations from several machines, take the maximum
|
||||||
|
// for each actor.
|
||||||
|
// Capturing this vector does not wait for replication or prevent further writes.
|
||||||
|
map<string, uint64> store_version = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message WaitForStoreVersionRequest {
|
||||||
|
// Minimum database version to reach for each Corrosion actor UUID.
|
||||||
|
// Obtain a vector from InspectMachine. To combine several responses, take the maximum version for each actor.
|
||||||
|
// Actors omitted from this vector and versions above its targets are not awaited. An empty vector requires
|
||||||
|
// no replication. Unknown actors with positive targets remain pending until replication reaches them or the RPC ends.
|
||||||
|
map<string, uint64> min_version = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TokenResponse {
|
message TokenResponse {
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.5.1
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc v5.27.3
|
// - protoc v5.27.3
|
||||||
// source: internal/machine/api/pb/machine.proto
|
// source: api/pb/machine.proto
|
||||||
|
|
||||||
package pb
|
package pb
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@ const (
|
|||||||
Machine_Token_FullMethodName = "/api.Machine/Token"
|
Machine_Token_FullMethodName = "/api.Machine/Token"
|
||||||
Machine_Inspect_FullMethodName = "/api.Machine/Inspect"
|
Machine_Inspect_FullMethodName = "/api.Machine/Inspect"
|
||||||
Machine_InspectMachine_FullMethodName = "/api.Machine/InspectMachine"
|
Machine_InspectMachine_FullMethodName = "/api.Machine/InspectMachine"
|
||||||
|
Machine_WaitForStoreVersion_FullMethodName = "/api.Machine/WaitForStoreVersion"
|
||||||
Machine_UpdateMachine_FullMethodName = "/api.Machine/UpdateMachine"
|
Machine_UpdateMachine_FullMethodName = "/api.Machine/UpdateMachine"
|
||||||
Machine_InspectWireGuardNetwork_FullMethodName = "/api.Machine/InspectWireGuardNetwork"
|
Machine_InspectWireGuardNetwork_FullMethodName = "/api.Machine/InspectWireGuardNetwork"
|
||||||
Machine_Reset_FullMethodName = "/api.Machine/Reset"
|
Machine_Reset_FullMethodName = "/api.Machine/Reset"
|
||||||
@@ -46,6 +47,22 @@ type MachineClient interface {
|
|||||||
Inspect(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MachineInfo, error)
|
Inspect(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MachineInfo, error)
|
||||||
// InspectMachine retrieves detailed information about the machine. Supports broadcasting to multiple machines.
|
// InspectMachine retrieves detailed information about the machine. Supports broadcasting to multiple machines.
|
||||||
InspectMachine(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*InspectMachineResponse, error)
|
InspectMachine(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*InspectMachineResponse, error)
|
||||||
|
// WaitForStoreVersion waits until the cluster store on this machine has reached each requested actor version, with
|
||||||
|
// no known missing or pending transactions through those versions.
|
||||||
|
// Corrosion may satisfy a version by applying its surviving changes or by marking it complete because its changes
|
||||||
|
// have been superseded.
|
||||||
|
//
|
||||||
|
// Waiting normally makes the captured data available on this machine. However, another write may replace some of that
|
||||||
|
// data before it arrives. Corrosion can then complete the older version without transferring the replaced data.
|
||||||
|
// If the replacement is outside the requested versions, this RPC can succeed while the affected data is still missing
|
||||||
|
// or outdated. This can happen during concurrent updates even when all machines are well connected.
|
||||||
|
//
|
||||||
|
// Success does not guarantee an exact snapshot or delivery of every historical value. Callers that require a specific
|
||||||
|
// record or condition should verify it after waiting.
|
||||||
|
//
|
||||||
|
// This RPC observes native replication without initiating synchronisation.
|
||||||
|
// Use the RPC deadline to bound the wait.
|
||||||
|
WaitForStoreVersion(ctx context.Context, in *WaitForStoreVersionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||||
// UpdateMachine updates the configuration of the machine.
|
// UpdateMachine updates the configuration of the machine.
|
||||||
UpdateMachine(ctx context.Context, in *UpdateMachineRequest, opts ...grpc.CallOption) (*UpdateMachineResponse, error)
|
UpdateMachine(ctx context.Context, in *UpdateMachineRequest, opts ...grpc.CallOption) (*UpdateMachineResponse, error)
|
||||||
// InspectWireGuardNetwork retrieves the current WireGuard network configuration and peer status.
|
// InspectWireGuardNetwork retrieves the current WireGuard network configuration and peer status.
|
||||||
@@ -124,6 +141,16 @@ func (c *machineClient) InspectMachine(ctx context.Context, in *emptypb.Empty, o
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *machineClient) WaitForStoreVersion(ctx context.Context, in *WaitForStoreVersionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(emptypb.Empty)
|
||||||
|
err := c.cc.Invoke(ctx, Machine_WaitForStoreVersion_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *machineClient) UpdateMachine(ctx context.Context, in *UpdateMachineRequest, opts ...grpc.CallOption) (*UpdateMachineResponse, error) {
|
func (c *machineClient) UpdateMachine(ctx context.Context, in *UpdateMachineRequest, opts ...grpc.CallOption) (*UpdateMachineResponse, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
out := new(UpdateMachineResponse)
|
out := new(UpdateMachineResponse)
|
||||||
@@ -196,6 +223,22 @@ type MachineServer interface {
|
|||||||
Inspect(context.Context, *emptypb.Empty) (*MachineInfo, error)
|
Inspect(context.Context, *emptypb.Empty) (*MachineInfo, error)
|
||||||
// InspectMachine retrieves detailed information about the machine. Supports broadcasting to multiple machines.
|
// InspectMachine retrieves detailed information about the machine. Supports broadcasting to multiple machines.
|
||||||
InspectMachine(context.Context, *emptypb.Empty) (*InspectMachineResponse, error)
|
InspectMachine(context.Context, *emptypb.Empty) (*InspectMachineResponse, error)
|
||||||
|
// WaitForStoreVersion waits until the cluster store on this machine has reached each requested actor version, with
|
||||||
|
// no known missing or pending transactions through those versions.
|
||||||
|
// Corrosion may satisfy a version by applying its surviving changes or by marking it complete because its changes
|
||||||
|
// have been superseded.
|
||||||
|
//
|
||||||
|
// Waiting normally makes the captured data available on this machine. However, another write may replace some of that
|
||||||
|
// data before it arrives. Corrosion can then complete the older version without transferring the replaced data.
|
||||||
|
// If the replacement is outside the requested versions, this RPC can succeed while the affected data is still missing
|
||||||
|
// or outdated. This can happen during concurrent updates even when all machines are well connected.
|
||||||
|
//
|
||||||
|
// Success does not guarantee an exact snapshot or delivery of every historical value. Callers that require a specific
|
||||||
|
// record or condition should verify it after waiting.
|
||||||
|
//
|
||||||
|
// This RPC observes native replication without initiating synchronisation.
|
||||||
|
// Use the RPC deadline to bound the wait.
|
||||||
|
WaitForStoreVersion(context.Context, *WaitForStoreVersionRequest) (*emptypb.Empty, error)
|
||||||
// UpdateMachine updates the configuration of the machine.
|
// UpdateMachine updates the configuration of the machine.
|
||||||
UpdateMachine(context.Context, *UpdateMachineRequest) (*UpdateMachineResponse, error)
|
UpdateMachine(context.Context, *UpdateMachineRequest) (*UpdateMachineResponse, error)
|
||||||
// InspectWireGuardNetwork retrieves the current WireGuard network configuration and peer status.
|
// InspectWireGuardNetwork retrieves the current WireGuard network configuration and peer status.
|
||||||
@@ -232,6 +275,9 @@ func (UnimplementedMachineServer) Inspect(context.Context, *emptypb.Empty) (*Mac
|
|||||||
func (UnimplementedMachineServer) InspectMachine(context.Context, *emptypb.Empty) (*InspectMachineResponse, error) {
|
func (UnimplementedMachineServer) InspectMachine(context.Context, *emptypb.Empty) (*InspectMachineResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method InspectMachine not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method InspectMachine not implemented")
|
||||||
}
|
}
|
||||||
|
func (UnimplementedMachineServer) WaitForStoreVersion(context.Context, *WaitForStoreVersionRequest) (*emptypb.Empty, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method WaitForStoreVersion not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedMachineServer) UpdateMachine(context.Context, *UpdateMachineRequest) (*UpdateMachineResponse, error) {
|
func (UnimplementedMachineServer) UpdateMachine(context.Context, *UpdateMachineRequest) (*UpdateMachineResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateMachine not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method UpdateMachine not implemented")
|
||||||
}
|
}
|
||||||
@@ -376,6 +422,24 @@ func _Machine_InspectMachine_Handler(srv interface{}, ctx context.Context, dec f
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _Machine_WaitForStoreVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(WaitForStoreVersionRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(MachineServer).WaitForStoreVersion(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: Machine_WaitForStoreVersion_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(MachineServer).WaitForStoreVersion(ctx, req.(*WaitForStoreVersionRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
func _Machine_UpdateMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _Machine_UpdateMachine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(UpdateMachineRequest)
|
in := new(UpdateMachineRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@@ -490,6 +554,10 @@ var Machine_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "InspectMachine",
|
MethodName: "InspectMachine",
|
||||||
Handler: _Machine_InspectMachine_Handler,
|
Handler: _Machine_InspectMachine_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "WaitForStoreVersion",
|
||||||
|
Handler: _Machine_WaitForStoreVersion_Handler,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
MethodName: "UpdateMachine",
|
MethodName: "UpdateMachine",
|
||||||
Handler: _Machine_UpdateMachine_Handler,
|
Handler: _Machine_UpdateMachine_Handler,
|
||||||
@@ -514,5 +582,5 @@ var Machine_ServiceDesc = grpc.ServiceDesc{
|
|||||||
ServerStreams: true,
|
ServerStreams: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Metadata: "internal/machine/api/pb/machine.proto",
|
Metadata: "api/pb/machine.proto",
|
||||||
}
|
}
|
||||||
Vendored
@@ -0,0 +1,165 @@
|
|||||||
|
package caddystorage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"slices"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
|
"github.com/psviderski/uncloud/pkg/distlock"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
lockPrefix = "caddy_storage:"
|
||||||
|
storeReplicationTimeout = 10 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
// Lock acquires an automatically renewed distributed lock and waits for the local store to catch up with versions
|
||||||
|
// observed on responding machines. Writers using the same lock can then read locally. Unavailable machines may have
|
||||||
|
// writes that this wait does not cover, and reads outside a lock remain eventually consistent.
|
||||||
|
func (s *Storage) Lock(ctx context.Context, name string) (err error) {
|
||||||
|
if name == "" {
|
||||||
|
return errors.New("lock name is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the call first. If Cleanup has already observed zero, Caddy has cancelled s.ctx and the check below rejects
|
||||||
|
// this call before it uses the client.
|
||||||
|
s.lockOps.Add(1)
|
||||||
|
// A failed Lock owns its lifecycle through any lease rollback. A successful Lock transfers that responsibility to
|
||||||
|
// Unlock, which keeps the client open until its release attempt finishes.
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
s.lockOps.Add(-1)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if s.ctx.Err() != nil {
|
||||||
|
return errors.New("storage is closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop acquisition retries when Caddy unloads the module (cancels s.ctx), even if the caller's context
|
||||||
|
// is still active.
|
||||||
|
ctx, cancel := context.WithCancelCause(ctx)
|
||||||
|
defer cancel(nil)
|
||||||
|
stopOnCleanup := context.AfterFunc(s.ctx, func() {
|
||||||
|
cancel(context.Cause(s.ctx))
|
||||||
|
})
|
||||||
|
defer stopOnCleanup()
|
||||||
|
|
||||||
|
log := s.log.With("lock", name)
|
||||||
|
started := time.Now()
|
||||||
|
log.Debug("acquiring lock", "ttl", time.Duration(s.LockTTL))
|
||||||
|
lease, err := s.locker.Acquire(ctx, lockPrefix+name)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("failed to acquire lock", "duration", time.Since(started), "error", err)
|
||||||
|
return fmt.Errorf("acquire lock '%s': %w", name, err)
|
||||||
|
}
|
||||||
|
log.Debug("lock lease acquired", "duration", time.Since(started))
|
||||||
|
// Release the lease if the lock acquisition fails after this point.
|
||||||
|
// Unlock will take care of releasing the lease on success.
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if releaseErr := s.releaseLock(ctx, name, lease, "cancelled acquisition"); releaseErr != nil {
|
||||||
|
err = errors.Join(err, releaseErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Catch up with the latest store versions observed on responding machines to increase the chance of reading
|
||||||
|
// the latest writes on them locally.
|
||||||
|
version, machines, err := s.clusterStoreVersion(ctx, log)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
waitStarted := time.Now()
|
||||||
|
log.Debug("waiting for local store replication", "machine_names", machines, "store_version", version)
|
||||||
|
waitCtx, cancelWait := context.WithTimeout(ctx, storeReplicationTimeout)
|
||||||
|
err = s.client.WaitForStoreVersion(waitCtx, version)
|
||||||
|
cancelWait()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("wait for local store replication: %w", err)
|
||||||
|
}
|
||||||
|
log.Debug("local store replication complete", "duration", time.Since(waitStarted))
|
||||||
|
|
||||||
|
s.locksMu.Lock()
|
||||||
|
defer s.locksMu.Unlock()
|
||||||
|
if s.ctx.Err() != nil {
|
||||||
|
return errors.New("storage is closed")
|
||||||
|
}
|
||||||
|
if lost := context.Cause(lease.Context()); lost != nil {
|
||||||
|
return lost
|
||||||
|
}
|
||||||
|
if _, exists := s.locks[name]; exists {
|
||||||
|
return errors.New("lock is already tracked by this storage instance")
|
||||||
|
}
|
||||||
|
s.locks[name] = lease
|
||||||
|
|
||||||
|
log.Debug("lock acquired", "duration", time.Since(started))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// clusterStoreVersion returns the per-actor maximum store versions from responding machines and their names.
|
||||||
|
func (s *Storage) clusterStoreVersion(ctx context.Context, log *slog.Logger) (map[string]uint64, []string, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, distlock.DefaultMaxNodeCallTimeout)
|
||||||
|
defer cancel()
|
||||||
|
resp, err := s.client.MachineClient.InspectMachine(client.ProxyMachinesContext(ctx, nil), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("inspect machines for store versions: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
maxVersion := make(map[string]uint64)
|
||||||
|
machines := make([]string, 0, len(resp.Machines))
|
||||||
|
for _, m := range resp.Machines {
|
||||||
|
if m.Metadata.Error != "" {
|
||||||
|
log.Debug("skipping machine when collecting store versions",
|
||||||
|
"id", m.Metadata.MachineId, "name", m.Metadata.MachineName, "error", m.Metadata.Error)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
machines = append(machines, m.Metadata.MachineName)
|
||||||
|
for actor, v := range m.StoreVersion {
|
||||||
|
maxVersion[actor] = max(maxVersion[actor], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slices.Sort(machines)
|
||||||
|
return maxVersion, machines, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock releases a previously acquired distributed lock.
|
||||||
|
func (s *Storage) Unlock(ctx context.Context, name string) error {
|
||||||
|
s.locksMu.Lock()
|
||||||
|
lease, exists := s.locks[name]
|
||||||
|
if exists {
|
||||||
|
delete(s.locks, name)
|
||||||
|
}
|
||||||
|
s.locksMu.Unlock()
|
||||||
|
if !exists {
|
||||||
|
return fmt.Errorf("lock '%s' is not held by this storage instance", name)
|
||||||
|
}
|
||||||
|
defer s.lockOps.Add(-1)
|
||||||
|
|
||||||
|
// Release stops renewal even on error. Any nodes that cannot be reached will let the lease expire.
|
||||||
|
if err := s.releaseLock(ctx, name, lease, "unlock"); err != nil {
|
||||||
|
return fmt.Errorf("release lock '%s': %w", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// releaseLock releases the lease with a context that ignores cancellation and logs the release attempt.
|
||||||
|
func (s *Storage) releaseLock(ctx context.Context, name string, lease *distlock.Lease, reason string) error {
|
||||||
|
// Unlock and rollback must attempt node cleanup even if the caller or module has already been cancelled.
|
||||||
|
ctx = context.WithoutCancel(ctx)
|
||||||
|
|
||||||
|
log := s.log.With("lock", name, "reason", reason)
|
||||||
|
started := time.Now()
|
||||||
|
log.Debug("releasing lock")
|
||||||
|
if err := lease.Release(ctx); err != nil {
|
||||||
|
log.Debug("failed to release lock", "duration", time.Since(started), "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debug("lock released", "duration", time.Since(started))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
// Package caddystorage provides Caddy storage backed by an Uncloud cluster.
|
||||||
|
package caddystorage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/v2"
|
||||||
|
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||||
|
"github.com/caddyserver/certmagic"
|
||||||
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
|
"github.com/psviderski/uncloud/pkg/client/connector"
|
||||||
|
"github.com/psviderski/uncloud/pkg/distlock"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ModuleID is the Caddy module ID for Uncloud storage.
|
||||||
|
ModuleID = "caddy.storage.uncloud"
|
||||||
|
// DefaultSocketPath is the default path to the Uncloud API socket.
|
||||||
|
DefaultSocketPath = "/run/uncloud/uncloud.sock"
|
||||||
|
// DefaultLockTTL is the default duration of a distributed lock lease.
|
||||||
|
DefaultLockTTL = 20 * time.Second
|
||||||
|
// lockCleanupTimeout bounds how long an unloaded module waits for active lock operations when cleaning up.
|
||||||
|
lockCleanupTimeout = 5 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
//nolint:gochecknoinits // Caddy modules must register during package initialisation.
|
||||||
|
func init() {
|
||||||
|
caddy.RegisterModule(new(Storage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storage implements a Caddy storage backend that uses an Uncloud cluster to store assets such as TLS certificates.
|
||||||
|
type Storage struct {
|
||||||
|
// Socket is the path to the Uncloud API socket.
|
||||||
|
// Defaults to /run/uncloud/uncloud.sock when not set.
|
||||||
|
Socket string `json:"socket,omitempty"`
|
||||||
|
// LockTTL is the duration of a distributed lock after which it expires if not renewed. Locks renew automatically
|
||||||
|
// until unlocked. If an instance crashes or cannot renew, expiry allows another instance to acquire the stale lock.
|
||||||
|
// Longer durations tolerate longer interruptions but delay recovery after a crash. Normal unlocks release the lock
|
||||||
|
// immediately.
|
||||||
|
// Defaults to 20 seconds when not set.
|
||||||
|
LockTTL caddy.Duration `json:"lock_ttl,omitempty"`
|
||||||
|
|
||||||
|
client *client.Client
|
||||||
|
locker *distlock.Locker
|
||||||
|
log *slog.Logger
|
||||||
|
|
||||||
|
// ctx is the module context from Provision. Caddy cancels it when it unloads the module and calls Cleanup.
|
||||||
|
ctx context.Context
|
||||||
|
|
||||||
|
// locksMu protects locks.
|
||||||
|
locksMu sync.Mutex
|
||||||
|
// locks maps successfully acquired lock names to held leases.
|
||||||
|
locks map[string]*distlock.Lease
|
||||||
|
// lockOps counts Lock calls until they fail or their locks are released.
|
||||||
|
lockOps atomic.Int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaddyModule returns the Caddy module information.
|
||||||
|
func (*Storage) CaddyModule() caddy.ModuleInfo {
|
||||||
|
return caddy.ModuleInfo{
|
||||||
|
ID: ModuleID,
|
||||||
|
New: func() caddy.Module { return new(Storage) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provision connects the storage to the local Uncloud API and initialises the distributed locker.
|
||||||
|
func (s *Storage) Provision(ctx caddy.Context) error {
|
||||||
|
s.ctx = ctx
|
||||||
|
s.log = ctx.Slogger()
|
||||||
|
|
||||||
|
if s.Socket == "" {
|
||||||
|
s.Socket = DefaultSocketPath
|
||||||
|
}
|
||||||
|
if s.LockTTL == 0 {
|
||||||
|
s.LockTTL = caddy.Duration(DefaultLockTTL)
|
||||||
|
}
|
||||||
|
if s.LockTTL < 0 {
|
||||||
|
return errors.New("lock_ttl must be positive")
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := client.New(ctx, connector.NewUnixConnector(s.Socket))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("connect to Uncloud API: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
locker, err := cli.NewLocker(distlock.Config{
|
||||||
|
LeaseDuration: time.Duration(s.LockTTL),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
_ = cli.Close()
|
||||||
|
return fmt.Errorf("create distributed locker: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.client = cli
|
||||||
|
s.locker = locker
|
||||||
|
s.locks = make(map[string]*distlock.Lease)
|
||||||
|
|
||||||
|
s.log.Debug("module provisioned", "socket", s.Socket, "lock_ttl", time.Duration(s.LockTTL))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup keeps the Uncloud API connection open so acquired lock leases can renew until Caddy releases them. It closes
|
||||||
|
// the connection after all lock operations finish or the cleanup timeout expires.
|
||||||
|
func (s *Storage) Cleanup() error {
|
||||||
|
if s.client == nil {
|
||||||
|
// Provision failed before opening the storage.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
started := time.Now()
|
||||||
|
s.log.Debug("cleaning up module", "locks", s.lockOps.Load())
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
timer := time.NewTimer(lockCleanupTimeout)
|
||||||
|
defer timer.Stop()
|
||||||
|
ticker := time.NewTicker(1 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
timedOut := false
|
||||||
|
for !timedOut && s.lockOps.Load() > 0 {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
case <-timer.C:
|
||||||
|
timedOut = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if remaining := s.lockOps.Load(); timedOut && remaining > 0 {
|
||||||
|
s.log.Debug("timed out waiting for active locks to be unlocked",
|
||||||
|
"locks", remaining, "timeout", lockCleanupTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.client.Close(); err != nil {
|
||||||
|
s.log.Debug("failed to clean up module", "duration", time.Since(started), "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.log.Debug("module cleanup complete", "duration", time.Since(started))
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertMagicStorage returns the provisioned CertMagic storage implementation.
|
||||||
|
func (s *Storage) CertMagicStorage() (certmagic.Storage, error) {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalCaddyfile configures Uncloud storage from the Caddyfile global storage block.
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// storage uncloud {
|
||||||
|
// socket /run/uncloud/uncloud.sock
|
||||||
|
// lock_ttl 20s
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
func (s *Storage) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||||
|
d.Next() // Skip the module name 'uncloud'.
|
||||||
|
// Reject inline arguments. NextArg leaves an opening brace for NextBlock.
|
||||||
|
if d.NextArg() {
|
||||||
|
return d.ArgErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the optional options block, skipping its surrounding braces.
|
||||||
|
for d.NextBlock(0) {
|
||||||
|
switch d.Val() {
|
||||||
|
case "socket":
|
||||||
|
// Require a socket path on the same line as 'socket' option.
|
||||||
|
if !d.NextArg() {
|
||||||
|
return d.ArgErr()
|
||||||
|
}
|
||||||
|
s.Socket = d.Val()
|
||||||
|
// Reject extra arguments after the socket path.
|
||||||
|
if d.NextArg() {
|
||||||
|
return d.ArgErr()
|
||||||
|
}
|
||||||
|
case "lock_ttl":
|
||||||
|
if !d.NextArg() {
|
||||||
|
return d.ArgErr()
|
||||||
|
}
|
||||||
|
ttl, err := caddy.ParseDuration(d.Val())
|
||||||
|
if err != nil {
|
||||||
|
return d.Errf("invalid lock_ttl '%s': %v", d.Val(), err)
|
||||||
|
}
|
||||||
|
if ttl <= 0 {
|
||||||
|
return d.Err("lock_ttl must be positive")
|
||||||
|
}
|
||||||
|
if d.NextArg() {
|
||||||
|
return d.ArgErr()
|
||||||
|
}
|
||||||
|
s.LockTTL = caddy.Duration(ttl)
|
||||||
|
default:
|
||||||
|
return d.Errf("unknown uncloud storage option: '%s'", d.Val())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ caddy.Module = (*Storage)(nil)
|
||||||
|
_ caddy.Provisioner = (*Storage)(nil)
|
||||||
|
_ caddy.CleanerUpper = (*Storage)(nil)
|
||||||
|
_ caddy.StorageConverter = (*Storage)(nil)
|
||||||
|
_ caddyfile.Unmarshaler = (*Storage)(nil)
|
||||||
|
_ certmagic.Storage = (*Storage)(nil)
|
||||||
|
)
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package caddystorage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
|
||||||
|
"github.com/caddyserver/certmagic"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store writes a value to the cluster store.
|
||||||
|
func (s *Storage) Store(ctx context.Context, key string, value []byte) error {
|
||||||
|
if _, err := s.client.CaddyStorage.Store(ctx, &pb.StoreCaddyStorageRequest{Key: key, Value: value}); err != nil {
|
||||||
|
return storageError("store", key, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load reads a value from the cluster store.
|
||||||
|
func (s *Storage) Load(ctx context.Context, key string) ([]byte, error) {
|
||||||
|
resp, err := s.client.CaddyStorage.Load(ctx, &pb.LoadCaddyStorageRequest{Key: key})
|
||||||
|
if err != nil {
|
||||||
|
return nil, storageError("load", key, err)
|
||||||
|
}
|
||||||
|
return resp.Value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes a key and its descendants from the cluster store.
|
||||||
|
func (s *Storage) Delete(ctx context.Context, key string) error {
|
||||||
|
if _, err := s.client.CaddyStorage.Delete(ctx, &pb.DeleteCaddyStorageRequest{Key: key}); err != nil {
|
||||||
|
return storageError("delete", key, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists reports whether a key exists in the cluster store.
|
||||||
|
func (s *Storage) Exists(ctx context.Context, key string) bool {
|
||||||
|
_, err := s.Stat(ctx, key)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns keys under prefix from the cluster store.
|
||||||
|
func (s *Storage) List(ctx context.Context, prefix string, recursive bool) ([]string, error) {
|
||||||
|
resp, err := s.client.CaddyStorage.List(ctx, &pb.ListCaddyStorageRequest{
|
||||||
|
Prefix: prefix,
|
||||||
|
Recursive: recursive,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, storageError("list", prefix, err)
|
||||||
|
}
|
||||||
|
return resp.Keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat returns information about a key in the cluster store.
|
||||||
|
func (s *Storage) Stat(ctx context.Context, key string) (certmagic.KeyInfo, error) {
|
||||||
|
resp, err := s.client.CaddyStorage.Stat(ctx, &pb.StatCaddyStorageRequest{Key: key})
|
||||||
|
if err != nil {
|
||||||
|
return certmagic.KeyInfo{}, storageError("stat", key, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info := certmagic.KeyInfo{
|
||||||
|
Key: resp.Key,
|
||||||
|
Size: resp.Size,
|
||||||
|
IsTerminal: resp.IsTerminal,
|
||||||
|
}
|
||||||
|
if resp.UpdatedAt != nil {
|
||||||
|
if err := resp.UpdatedAt.CheckValid(); err != nil {
|
||||||
|
return certmagic.KeyInfo{}, storageError("stat", key, fmt.Errorf("invalid updated_at timestamp: %w", err))
|
||||||
|
}
|
||||||
|
info.Modified = resp.UpdatedAt.AsTime()
|
||||||
|
}
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func storageError(operation, key string, err error) error {
|
||||||
|
if status.Code(err) == codes.NotFound {
|
||||||
|
err = fs.ErrNotExist
|
||||||
|
}
|
||||||
|
return fmt.Errorf("uncloud storage: %s key %q: %w", operation, key, err)
|
||||||
|
}
|
||||||
@@ -12,10 +12,10 @@ import (
|
|||||||
"charm.land/lipgloss/v2"
|
"charm.land/lipgloss/v2"
|
||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
"github.com/psviderski/uncloud/internal/cli/completion"
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/psviderski/uncloud/pkg/client"
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/cmd/uc/caddy"
|
"github.com/psviderski/uncloud/cmd/uc/caddy"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/psviderski/uncloud/pkg/client"
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|||||||
+10
-4
@@ -40,13 +40,19 @@ func NewAddCommand() *cobra.Command {
|
|||||||
Short: "Add a remote machine to a cluster.",
|
Short: "Add a remote machine to a cluster.",
|
||||||
Long: `Add a new machine to an existing Uncloud cluster.
|
Long: `Add a new machine to an existing Uncloud cluster.
|
||||||
|
|
||||||
|
By default, it installs Docker and the Uncloud daemon on the machine over SSH unless --no-install
|
||||||
|
is specified, which assumes they are already installed and running.
|
||||||
|
|
||||||
Connection methods:
|
Connection methods:
|
||||||
[ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required)
|
[ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required)
|
||||||
ssh+go://user@host - Use Go's built-in SSH library`,
|
ssh+go://user@host - Use Go's built-in SSH library`,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
|
cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
|
||||||
|
cli.BindEnvToFlag(cmd, "version", "UNCLOUD_DAEMON_VERSION")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
|
||||||
// Determine connection mode and strip scheme.
|
// Determine connection mode and strip scheme.
|
||||||
@@ -79,7 +85,7 @@ Connection methods:
|
|||||||
)
|
)
|
||||||
cmd.Flags().BoolVar(
|
cmd.Flags().BoolVar(
|
||||||
&opts.noInstall, "no-install", false,
|
&opts.noInstall, "no-install", false,
|
||||||
"Skip installation of Docker, Uncloud daemon, and dependencies on the machine. "+
|
"Skip installation of Docker and the Uncloud daemon on the machine. "+
|
||||||
"Assumes they're already installed and running.",
|
"Assumes they're already installed and running.",
|
||||||
)
|
)
|
||||||
cmd.Flags().StringVar(
|
cmd.Flags().StringVar(
|
||||||
@@ -94,7 +100,7 @@ Connection methods:
|
|||||||
)
|
)
|
||||||
cmd.Flags().StringVar(
|
cmd.Flags().StringVar(
|
||||||
&opts.version, "version", "latest",
|
&opts.version, "version", "latest",
|
||||||
"Version of the Uncloud daemon to install on the machine.",
|
"Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION]",
|
||||||
)
|
)
|
||||||
cmd.Flags().StringSliceVar(
|
cmd.Flags().StringSliceVar(
|
||||||
&opts.wgEndpoints, "wg-endpoint", nil,
|
&opts.wgEndpoints, "wg-endpoint", nil,
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// runVersionFlagEnvTest builds the given command for each case, stubs out RunE so only flag
|
||||||
|
// parsing and PreRunE run (no SSH calls), and asserts the resolved --version flag value.
|
||||||
|
// Note: cannot use t.Parallel() because subtests use t.Setenv().
|
||||||
|
func runVersionFlagEnvTest(t *testing.T, newCommand func() *cobra.Command) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
env string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "env var sets version when flag not passed",
|
||||||
|
args: []string{"root@localhost"},
|
||||||
|
env: "v1.2.3",
|
||||||
|
want: "v1.2.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "explicit flag wins over env var",
|
||||||
|
args: []string{"root@localhost", "--version", "v9.9.9"},
|
||||||
|
env: "v1.2.3",
|
||||||
|
want: "v9.9.9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "defaults to latest when neither flag nor env var set",
|
||||||
|
args: []string{"root@localhost"},
|
||||||
|
want: "latest",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.env != "" {
|
||||||
|
t.Setenv("UNCLOUD_DAEMON_VERSION", tt.env)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := newCommand()
|
||||||
|
cmd.RunE = func(*cobra.Command, []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cmd.SetArgs(tt.args)
|
||||||
|
require.NoError(t, cmd.Execute())
|
||||||
|
|
||||||
|
version, err := cmd.Flags().GetString("version")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, version)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInitCommandVersionFlagEnvVar verifies that the UNCLOUD_DAEMON_VERSION environment variable
|
||||||
|
// is bound to the --version flag of 'machine init', and that an explicit flag wins.
|
||||||
|
func TestInitCommandVersionFlagEnvVar(t *testing.T) {
|
||||||
|
runVersionFlagEnvTest(t, NewInitCommand)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestAddCommandVersionFlagEnvVar verifies that the UNCLOUD_DAEMON_VERSION environment variable
|
||||||
|
// is bound to the --version flag of 'machine add', and that an explicit flag wins.
|
||||||
|
func TestAddCommandVersionFlagEnvVar(t *testing.T) {
|
||||||
|
runVersionFlagEnvTest(t, NewAddCommand)
|
||||||
|
}
|
||||||
+11
-5
@@ -8,12 +8,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/cmd/uc/caddy"
|
"github.com/psviderski/uncloud/cmd/uc/caddy"
|
||||||
"github.com/psviderski/uncloud/cmd/uc/dns"
|
"github.com/psviderski/uncloud/cmd/uc/dns"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
"github.com/psviderski/uncloud/internal/cli/config"
|
"github.com/psviderski/uncloud/internal/cli/config"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/cluster"
|
"github.com/psviderski/uncloud/internal/machine/cluster"
|
||||||
"github.com/psviderski/uncloud/internal/machine/network"
|
"github.com/psviderski/uncloud/internal/machine/network"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
@@ -45,6 +45,9 @@ func NewInitCommand() *cobra.Command {
|
|||||||
Long: `Initialise a new cluster by setting up a remote machine as the first member.
|
Long: `Initialise a new cluster by setting up a remote machine as the first member.
|
||||||
This command creates a new context in your Uncloud config to manage the cluster.
|
This command creates a new context in your Uncloud config to manage the cluster.
|
||||||
|
|
||||||
|
By default, it installs Docker and the Uncloud daemon on the machine over SSH unless --no-install
|
||||||
|
is specified, which assumes they are already installed and running.
|
||||||
|
|
||||||
Connection methods:
|
Connection methods:
|
||||||
[ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required)
|
[ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required)
|
||||||
ssh+go://user@host - Use Go's built-in SSH library`,
|
ssh+go://user@host - Use Go's built-in SSH library`,
|
||||||
@@ -62,9 +65,12 @@ Connection methods:
|
|||||||
uc machine init root@<your-server-ip> --no-caddy --no-dns`,
|
uc machine init root@<your-server-ip> --no-caddy --no-dns`,
|
||||||
// TODO: support initialising a cluster on the local machine.
|
// TODO: support initialising a cluster on the local machine.
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
|
cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
|
||||||
|
cli.BindEnvToFlag(cmd, "version", "UNCLOUD_DAEMON_VERSION")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
|
||||||
var remoteMachine *cli.RemoteMachine
|
var remoteMachine *cli.RemoteMachine
|
||||||
@@ -117,7 +123,7 @@ Connection methods:
|
|||||||
)
|
)
|
||||||
cmd.Flags().BoolVar(
|
cmd.Flags().BoolVar(
|
||||||
&opts.noInstall, "no-install", false,
|
&opts.noInstall, "no-install", false,
|
||||||
"Skip installation of Docker, Uncloud daemon, and dependencies on the machine. "+
|
"Skip installation of Docker and the Uncloud daemon on the machine. "+
|
||||||
"Assumes they're already installed and running.",
|
"Assumes they're already installed and running.",
|
||||||
)
|
)
|
||||||
cmd.Flags().StringVar(
|
cmd.Flags().StringVar(
|
||||||
@@ -132,7 +138,7 @@ Connection methods:
|
|||||||
)
|
)
|
||||||
cmd.Flags().StringVar(
|
cmd.Flags().StringVar(
|
||||||
&opts.version, "version", "latest",
|
&opts.version, "version", "latest",
|
||||||
"Version of the Uncloud daemon to install on the machine.",
|
"Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION]",
|
||||||
)
|
)
|
||||||
cmd.Flags().StringSliceVar(
|
cmd.Flags().StringSliceVar(
|
||||||
&opts.wgEndpoints, "wg-endpoint", nil,
|
&opts.wgEndpoints, "wg-endpoint", nil,
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
"charm.land/lipgloss/v2/tree"
|
"charm.land/lipgloss/v2/tree"
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
"github.com/psviderski/uncloud/internal/cli/completion"
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@@ -136,8 +136,7 @@ func remove(ctx context.Context, uncli *cli.CLI, nameOrID string, opts removeOpt
|
|||||||
return fmt.Errorf("confirm removal: %w", err)
|
return fmt.Errorf("confirm removal: %w", err)
|
||||||
}
|
}
|
||||||
if !confirmed {
|
if !confirmed {
|
||||||
fmt.Println("Cancelled. Machine was not removed.")
|
return cli.Cancelled("Cancelled. Machine was not removed.")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
"github.com/psviderski/uncloud/internal/cli/completion"
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/network"
|
"github.com/psviderski/uncloud/internal/machine/network"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/psviderski/uncloud/internal/machine"
|
"github.com/psviderski/uncloud/internal/machine"
|
||||||
"github.com/psviderski/uncloud/internal/version"
|
"github.com/psviderski/uncloud/internal/version"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
type globalOptions struct {
|
type globalOptions struct {
|
||||||
@@ -42,6 +43,13 @@ func main() {
|
|||||||
SilenceUsage: true,
|
SilenceUsage: true,
|
||||||
SilenceErrors: true,
|
SilenceErrors: true,
|
||||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
// Shell completion runs through the hidden __complete command which has flag parsing disabled,
|
||||||
|
// so the global flags from the completed command line are never parsed. Apply them manually to make
|
||||||
|
// completion work with --connect, --context, and --uncloud-config.
|
||||||
|
if cmd.Name() == cobra.ShellCompRequestCmd {
|
||||||
|
applyGlobalFlagsFromCompletionArgs(cmd.Root().PersistentFlags(), os.Args[1:])
|
||||||
|
}
|
||||||
|
|
||||||
cli.BindEnvToFlag(cmd, "connect", "UNCLOUD_CONNECT")
|
cli.BindEnvToFlag(cmd, "connect", "UNCLOUD_CONNECT")
|
||||||
cli.BindEnvToFlag(cmd, "context", "UNCLOUD_CONTEXT")
|
cli.BindEnvToFlag(cmd, "context", "UNCLOUD_CONTEXT")
|
||||||
cli.BindEnvToFlag(cmd, "uncloud-config", "UNCLOUD_CONFIG")
|
cli.BindEnvToFlag(cmd, "uncloud-config", "UNCLOUD_CONFIG")
|
||||||
@@ -159,3 +167,27 @@ func main() {
|
|||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applyGlobalFlagsFromCompletionArgs parses the global flags from the raw arguments of a __complete command and applies
|
||||||
|
// the ones found to flags. The trailing word being completed, unknown flags, and positional arguments are ignored.
|
||||||
|
func applyGlobalFlagsFromCompletionArgs(flags *pflag.FlagSet, args []string) {
|
||||||
|
// The shell always passes the word being completed as the last argument, even if it's empty.
|
||||||
|
// Exclude it from parsing as its value may not be complete yet.
|
||||||
|
if len(args) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
args = args[:len(args)-1]
|
||||||
|
|
||||||
|
fset := pflag.NewFlagSet("global", pflag.ContinueOnError)
|
||||||
|
fset.ParseErrorsAllowlist.UnknownFlags = true
|
||||||
|
fset.String("connect", "", "")
|
||||||
|
fset.StringP("context", "c", "", "")
|
||||||
|
fset.String("uncloud-config", "", "")
|
||||||
|
// Parsing an incomplete command line may fail, apply the flags parsed so far anyway.
|
||||||
|
_ = fset.Parse(args)
|
||||||
|
|
||||||
|
fset.Visit(func(f *pflag.Flag) {
|
||||||
|
// Setting the flag marks it as changed so it takes precedence over environment variables.
|
||||||
|
_ = flags.Set(f.Name, f.Value.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApplyGlobalFlagsFromCompletionArgs(t *testing.T) {
|
||||||
|
defaultConfigPath := "~/.config/uncloud/config.yaml"
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
wantConnect string
|
||||||
|
wantContext string
|
||||||
|
wantConfigPath string
|
||||||
|
// Flag names expected to be marked as changed on the target flag set.
|
||||||
|
wantChanged []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no flags",
|
||||||
|
args: []string{"__complete", "inspect", ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "connect with space",
|
||||||
|
args: []string{"__complete", "--connect", "ssh://user@host", "inspect", ""},
|
||||||
|
wantConnect: "ssh://user@host",
|
||||||
|
wantChanged: []string{"connect"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "connect with equals",
|
||||||
|
args: []string{"__complete", "--connect=tcp://127.0.0.1:51000", "inspect", ""},
|
||||||
|
wantConnect: "tcp://127.0.0.1:51000",
|
||||||
|
wantChanged: []string{"connect"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "context shorthand",
|
||||||
|
args: []string{"__complete", "-c", "prod", "inspect", ""},
|
||||||
|
wantContext: "prod",
|
||||||
|
wantChanged: []string{"context"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all flags",
|
||||||
|
args: []string{"__complete", "--connect", "user@host", "-c", "prod", "--uncloud-config", "/tmp/uncloud.yaml", "inspect", ""},
|
||||||
|
wantConnect: "user@host",
|
||||||
|
wantContext: "prod",
|
||||||
|
wantConfigPath: "/tmp/uncloud.yaml",
|
||||||
|
wantChanged: []string{"connect", "context", "uncloud-config"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown flags are ignored",
|
||||||
|
args: []string{"__complete", "--quiet", "-n", "5", "--connect", "user@host", "logs", ""},
|
||||||
|
wantConnect: "user@host",
|
||||||
|
wantChanged: []string{"connect"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "flags after double dash are ignored",
|
||||||
|
args: []string{"__complete", "exec", "svc", "--", "sh", "--connect", "user@host"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "flags before double dash are applied",
|
||||||
|
args: []string{"__complete", "--connect", "user@host", "exec", "svc", "--", "sh", "-c", "env"},
|
||||||
|
wantConnect: "user@host",
|
||||||
|
wantChanged: []string{"connect"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "partial flag name being completed is excluded",
|
||||||
|
args: []string{"__complete", "--connect", "user@host", "inspect", "--context"},
|
||||||
|
wantConnect: "user@host",
|
||||||
|
wantChanged: []string{"connect"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "partial flag value being completed is excluded",
|
||||||
|
args: []string{"__complete", "--uncloud-config", "/tmp/"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "partial connect value being completed is excluded",
|
||||||
|
args: []string{"__complete", "--connect", "tcp://127.0.0.1:5"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "completed flag value with partial command word",
|
||||||
|
args: []string{"__complete", "--uncloud-config", "/tmp/uncloud.yaml", "insp"},
|
||||||
|
wantConfigPath: "/tmp/uncloud.yaml",
|
||||||
|
wantChanged: []string{"uncloud-config"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
// Mirror the global persistent flags defined on the root command.
|
||||||
|
var opts globalOptions
|
||||||
|
flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||||
|
flags.StringVar(&opts.connect, "connect", "", "")
|
||||||
|
flags.StringVarP(&opts.context, "context", "c", "", "")
|
||||||
|
flags.StringVar(&opts.configPath, "uncloud-config", defaultConfigPath, "")
|
||||||
|
|
||||||
|
applyGlobalFlagsFromCompletionArgs(flags, tt.args)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.wantConnect, opts.connect)
|
||||||
|
assert.Equal(t, tt.wantContext, opts.context)
|
||||||
|
wantConfigPath := tt.wantConfigPath
|
||||||
|
if wantConfigPath == "" {
|
||||||
|
wantConfigPath = defaultConfigPath
|
||||||
|
}
|
||||||
|
assert.Equal(t, wantConfigPath, opts.configPath)
|
||||||
|
|
||||||
|
for _, name := range []string{"connect", "context", "uncloud-config"} {
|
||||||
|
assert.Equal(t, slices.Contains(tt.wantChanged, name), flags.Changed(name),
|
||||||
|
"changed status of flag '%s'", name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-16
@@ -132,35 +132,34 @@ func runProxy(ctx context.Context, uncli *cli.CLI, opts proxyOptions) error {
|
|||||||
// endpoint and shuffles the data, *it* will actually experience errors.
|
// endpoint and shuffles the data, *it* will actually experience errors.
|
||||||
remoteAddr := net.JoinHostPort(ip.String(), strconv.Itoa(opts.remotePort))
|
remoteAddr := net.JoinHostPort(ip.String(), strconv.Itoa(opts.remotePort))
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
p := &proxy.Proxy{
|
p := &proxy.Proxy{
|
||||||
Listener: listener,
|
Listener: listener,
|
||||||
RemoteAddr: remoteAddr,
|
RemoteAddr: remoteAddr,
|
||||||
DialContext: dialer.DialContext,
|
DialContext: dialer.DialContext,
|
||||||
OnError: func(err error) {
|
OnError: func(err error) {
|
||||||
fmt.Printf("Failed to proxy to '%s': %v\n", remoteAddr, err)
|
if proxy.IsConnectionClosedError(err) {
|
||||||
cancel()
|
return
|
||||||
|
}
|
||||||
|
// A more actionable error instead of the cryptic [ssh -W] command error.
|
||||||
|
if strings.Contains(err.Error(), "Session open refused by peer") {
|
||||||
|
fmt.Printf("Could not connect to '%s': connection refused. "+
|
||||||
|
"Check that the service is running and listening on port %d inside the container.\n",
|
||||||
|
remoteAddr, opts.remotePort)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Failed to proxy a connection to '%s': %v\n", remoteAddr, err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the proxy in the background and signal when it has fully shut down.
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
p.Run(ctx)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Prefix the local address with the scheme for common HTTP ports so it becomes control-clickable in most
|
// Prefix the local address with the scheme for common HTTP ports so it becomes control-clickable in most
|
||||||
// terminals. We assume plain HTTP since TLS is typically terminated by Caddy in front of the service.
|
// terminals. We assume plain HTTP since TLS is typically terminated by Caddy in front of the service.
|
||||||
fmt.Printf("%s%s → %s (%s%s%s)\n", schemeForPort(opts.remotePort), p.Listener.Addr().String(),
|
fmt.Printf("%s%s → %s (%s%s%s)\n", schemeForPort(opts.remotePort), p.Listener.Addr().String(),
|
||||||
remoteAddr, opts.service, tui.Faint.Render("/"), containerID)
|
remoteAddr, opts.service, tui.Faint.Render("/"), containerID)
|
||||||
|
|
||||||
<-ctx.Done()
|
if err = p.Run(ctx); err != nil {
|
||||||
// Wait for the proxy to drain in-flight connections and shut down gracefully.
|
return fmt.Errorf("run proxy to '%s': %w", remoteAddr, err)
|
||||||
<-done
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -187,7 +187,7 @@ func printContainers(containers []containerInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func collectContainers(ctx context.Context, cli *client.Client) ([]containerInfo, error) {
|
func collectContainers(ctx context.Context, cli *client.Client) ([]containerInfo, error) {
|
||||||
listCtx := cli.ProxyMachinesContext(ctx, nil)
|
listCtx := client.ProxyMachinesContext(ctx, nil)
|
||||||
|
|
||||||
// List all service containers across all machines in the cluster.
|
// List all service containers across all machines in the cluster.
|
||||||
machineContainers, err := cli.Docker.ListServiceContainers(
|
machineContainers, err := cli.Docker.ListServiceContainers(
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/machine/docker"
|
"github.com/psviderski/uncloud/internal/machine/docker"
|
||||||
"github.com/psviderski/uncloud/pkg/client"
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|||||||
@@ -30,9 +30,11 @@ func NewScaleCommand(groupID string) *cobra.Command {
|
|||||||
Short: "Scale a replicated service by changing the number of replicas.",
|
Short: "Scale a replicated service by changing the number of replicas.",
|
||||||
Long: "Scale a replicated service by changing the number of replicas.",
|
Long: "Scale a replicated service by changing the number of replicas.",
|
||||||
Args: cobra.ExactArgs(2),
|
Args: cobra.ExactArgs(2),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
|
cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
|
||||||
opts.service = args[0]
|
opts.service = args[0]
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
|
|
||||||
"charm.land/huh/v2"
|
"charm.land/huh/v2"
|
||||||
"github.com/docker/docker/api/types/volume"
|
"github.com/docker/docker/api/types/volume"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
"github.com/psviderski/uncloud/internal/cli/completion"
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-2
@@ -92,8 +92,7 @@ func remove(ctx context.Context, uncli *cli.CLI, names []string, opts removeOpti
|
|||||||
return fmt.Errorf("confirm removal: %w", err)
|
return fmt.Errorf("confirm removal: %w", err)
|
||||||
}
|
}
|
||||||
if !confirmed {
|
if !confirmed {
|
||||||
fmt.Println("Cancelled. No volumes were removed.")
|
return cli.Cancelled("Cancelled. No volumes were removed.")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,10 +8,10 @@ import (
|
|||||||
|
|
||||||
"charm.land/lipgloss/v2"
|
"charm.land/lipgloss/v2"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
"github.com/psviderski/uncloud/internal/cli/completion"
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
|||||||
+2
-2
@@ -124,8 +124,8 @@ require (
|
|||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||||
golang.org/x/mod v0.27.0 // indirect
|
golang.org/x/mod v0.27.0 // indirect
|
||||||
golang.org/x/net v0.43.0 // indirect
|
golang.org/x/net v0.43.0 // indirect
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.42.0 // indirect
|
golang.org/x/sys v0.45.0 // indirect
|
||||||
golang.org/x/text v0.28.0 // indirect
|
golang.org/x/text v0.28.0 // indirect
|
||||||
golang.org/x/tools v0.36.0 // indirect
|
golang.org/x/tools v0.36.0 // indirect
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
||||||
|
|||||||
+4
-4
@@ -660,8 +660,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -694,8 +694,8 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ require (
|
|||||||
github.com/alecthomas/chroma/v2 v2.20.0
|
github.com/alecthomas/chroma/v2 v2.20.0
|
||||||
github.com/caarlos0/go-version v0.2.2
|
github.com/caarlos0/go-version v0.2.2
|
||||||
github.com/caddyserver/caddy/v2 v2.8.4
|
github.com/caddyserver/caddy/v2 v2.8.4
|
||||||
|
github.com/caddyserver/certmagic v0.21.4
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0
|
github.com/cenkalti/backoff/v4 v4.3.0
|
||||||
github.com/charmbracelet/colorprofile v0.4.3
|
github.com/charmbracelet/colorprofile v0.4.3
|
||||||
github.com/charmbracelet/x/ansi v0.11.7
|
github.com/charmbracelet/x/ansi v0.11.7
|
||||||
@@ -93,7 +94,6 @@ require (
|
|||||||
github.com/aws/smithy-go v1.20.3 // indirect
|
github.com/aws/smithy-go v1.20.3 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/buger/goterm v1.0.4 // indirect
|
github.com/buger/goterm v1.0.4 // indirect
|
||||||
github.com/caddyserver/certmagic v0.21.4 // indirect
|
|
||||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||||
github.com/catppuccin/go v0.3.0 // indirect
|
github.com/catppuccin/go v0.3.0 // indirect
|
||||||
github.com/cespare/xxhash v1.1.0 // indirect
|
github.com/cespare/xxhash v1.1.0 // indirect
|
||||||
|
|||||||
+2
-2
@@ -8,9 +8,9 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/cli/config"
|
"github.com/psviderski/uncloud/internal/cli/config"
|
||||||
"github.com/psviderski/uncloud/internal/machine"
|
"github.com/psviderski/uncloud/internal/machine"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/cluster"
|
"github.com/psviderski/uncloud/internal/machine/cluster"
|
||||||
"github.com/psviderski/uncloud/internal/machine/network"
|
"github.com/psviderski/uncloud/internal/machine/network"
|
||||||
"github.com/psviderski/uncloud/internal/sshexec"
|
"github.com/psviderski/uncloud/internal/sshexec"
|
||||||
@@ -458,7 +458,7 @@ func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (_ *clie
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot the cluster store version so the new machine can catch up before participating.
|
// Snapshot the cluster store version so the new machine can catch up before participating.
|
||||||
var storeVersion map[string]int64
|
var storeVersion map[string]uint64
|
||||||
inspectResp, err = c.MachineClient.InspectMachine(ctx, &emptypb.Empty{})
|
inspectResp, err = c.MachineClient.InspectMachine(ctx, &emptypb.Empty{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO(lhf): remove Unimplemented check when v0.17.0 is released.
|
// TODO(lhf): remove Unimplemented check when v0.17.0 is released.
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Contexts(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
func Contexts(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
// There are no contexts to complete when the CLI uses a direct machine connection (--connect) without a config.
|
||||||
|
if uncli.Config == nil {
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
|
||||||
contexts := slices.Sorted(maps.Keys(uncli.Config.Contexts))
|
contexts := slices.Sorted(maps.Keys(uncli.Config.Contexts))
|
||||||
|
|
||||||
names := []cobra.Completion{}
|
names := []cobra.Completion{}
|
||||||
@@ -21,7 +26,6 @@ func Contexts(ctx context.Context, uncli *cli.CLI, args []string, toComplete str
|
|||||||
if strings.HasPrefix(context, toComplete) {
|
if strings.HasPrefix(context, toComplete) {
|
||||||
names = append(names, context)
|
names = append(names, context)
|
||||||
}
|
}
|
||||||
names = append(names, context)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return names, cobra.ShellCompDirectiveNoFileComp
|
return names, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Machines(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
func Machines(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
client, err := uncli.ConnectCluster(ctx)
|
// Disable the connection progress output to not interfere with the shell completion output.
|
||||||
|
client, err := uncli.ConnectClusterWithOptions(ctx, cli.ConnectOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cobra.ShellCompDirectiveError
|
return nil, cobra.ShellCompDirectiveError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Services(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
func Services(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
client, err := uncli.ConnectCluster(ctx)
|
// Disable the connection progress output to not interfere with the shell completion output.
|
||||||
|
client, err := uncli.ConnectClusterWithOptions(ctx, cli.ConnectOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cobra.ShellCompDirectiveError
|
return nil, cobra.ShellCompDirectiveError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Volumes(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
func Volumes(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
client, err := uncli.ConnectCluster(ctx)
|
// Disable the connection progress output to not interfere with the shell completion output.
|
||||||
|
client, err := uncli.ConnectClusterWithOptions(ctx, cli.ConnectOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cobra.ShellCompDirectiveError
|
return nil, cobra.ShellCompDirectiveError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
|
|
||||||
"charm.land/huh/v2"
|
"charm.land/huh/v2"
|
||||||
"github.com/cenkalti/backoff/v4"
|
"github.com/cenkalti/backoff/v4"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/internal/sshexec"
|
"github.com/psviderski/uncloud/internal/sshexec"
|
||||||
"github.com/psviderski/uncloud/scripts"
|
"github.com/psviderski/uncloud/scripts"
|
||||||
"google.golang.org/protobuf/types/known/emptypb"
|
"google.golang.org/protobuf/types/known/emptypb"
|
||||||
|
|||||||
@@ -31,9 +31,8 @@ const (
|
|||||||
//
|
//
|
||||||
// The two minimums are independent: a client might require a newer daemon for new
|
// The two minimums are independent: a client might require a newer daemon for new
|
||||||
// features, while that same daemon could still handle requests from older clients.
|
// features, while that same daemon could still handle requests from older clients.
|
||||||
// TODO: update to 0.20.0 before releasing 0.20.0.
|
MinClientVersion = "0.20.0"
|
||||||
MinClientVersion = "0.20.0-nightly"
|
MinServerVersion = "0.20.0"
|
||||||
MinServerVersion = "0.20.0-nightly"
|
|
||||||
|
|
||||||
ReleaseURL = "https://github.com/psviderski/uncloud/releases/latest"
|
ReleaseURL = "https://github.com/psviderski/uncloud/releases/latest"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,176 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.34.2
|
|
||||||
// protoc v5.27.3
|
|
||||||
// source: internal/machine/api/pb/caddy.proto
|
|
||||||
|
|
||||||
package pb
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
|
||||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type GetCaddyConfigResponse struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// The generated Caddyfile content.
|
|
||||||
Caddyfile string `protobuf:"bytes,1,opt,name=caddyfile,proto3" json:"caddyfile,omitempty"`
|
|
||||||
// Timestamp when the config was last modified.
|
|
||||||
ModifiedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=modified_at,json=modifiedAt,proto3" json:"modified_at,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetCaddyConfigResponse) Reset() {
|
|
||||||
*x = GetCaddyConfigResponse{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_internal_machine_api_pb_caddy_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetCaddyConfigResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*GetCaddyConfigResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *GetCaddyConfigResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_internal_machine_api_pb_caddy_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use GetCaddyConfigResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*GetCaddyConfigResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_internal_machine_api_pb_caddy_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetCaddyConfigResponse) GetCaddyfile() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Caddyfile
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetCaddyConfigResponse) GetModifiedAt() *timestamppb.Timestamp {
|
|
||||||
if x != nil {
|
|
||||||
return x.ModifiedAt
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_internal_machine_api_pb_caddy_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_internal_machine_api_pb_caddy_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
|
||||||
0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x61, 0x64, 0x64, 0x79, 0x2e,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67,
|
|
||||||
0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74,
|
|
||||||
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
|
||||||
0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x43,
|
|
||||||
0x61, 0x64, 0x64, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
|
||||||
0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x61, 0x64, 0x64, 0x79, 0x66, 0x69, 0x6c, 0x65, 0x18,
|
|
||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x64, 0x64, 0x79, 0x66, 0x69, 0x6c, 0x65,
|
|
||||||
0x12, 0x3b, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18,
|
|
||||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
|
||||||
0x70, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x41, 0x74, 0x32, 0x49, 0x0a,
|
|
||||||
0x05, 0x43, 0x61, 0x64, 0x64, 0x79, 0x12, 0x40, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e,
|
|
||||||
0x66, 0x69, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x61, 0x70,
|
|
||||||
0x69, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x64, 0x64, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68,
|
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b,
|
|
||||||
0x69, 0x2f, 0x75, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
|
||||||
0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70,
|
|
||||||
0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_internal_machine_api_pb_caddy_proto_rawDescOnce sync.Once
|
|
||||||
file_internal_machine_api_pb_caddy_proto_rawDescData = file_internal_machine_api_pb_caddy_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_internal_machine_api_pb_caddy_proto_rawDescGZIP() []byte {
|
|
||||||
file_internal_machine_api_pb_caddy_proto_rawDescOnce.Do(func() {
|
|
||||||
file_internal_machine_api_pb_caddy_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_machine_api_pb_caddy_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_internal_machine_api_pb_caddy_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_internal_machine_api_pb_caddy_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_internal_machine_api_pb_caddy_proto_goTypes = []any{
|
|
||||||
(*GetCaddyConfigResponse)(nil), // 0: api.GetCaddyConfigResponse
|
|
||||||
(*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp
|
|
||||||
(*emptypb.Empty)(nil), // 2: google.protobuf.Empty
|
|
||||||
}
|
|
||||||
var file_internal_machine_api_pb_caddy_proto_depIdxs = []int32{
|
|
||||||
1, // 0: api.GetCaddyConfigResponse.modified_at:type_name -> google.protobuf.Timestamp
|
|
||||||
2, // 1: api.Caddy.GetConfig:input_type -> google.protobuf.Empty
|
|
||||||
0, // 2: api.Caddy.GetConfig:output_type -> api.GetCaddyConfigResponse
|
|
||||||
2, // [2:3] is the sub-list for method output_type
|
|
||||||
1, // [1:2] is the sub-list for method input_type
|
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_internal_machine_api_pb_caddy_proto_init() }
|
|
||||||
func file_internal_machine_api_pb_caddy_proto_init() {
|
|
||||||
if File_internal_machine_api_pb_caddy_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_internal_machine_api_pb_caddy_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
|
||||||
switch v := v.(*GetCaddyConfigResponse); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_internal_machine_api_pb_caddy_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 1,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 1,
|
|
||||||
},
|
|
||||||
GoTypes: file_internal_machine_api_pb_caddy_proto_goTypes,
|
|
||||||
DependencyIndexes: file_internal_machine_api_pb_caddy_proto_depIdxs,
|
|
||||||
MessageInfos: file_internal_machine_api_pb_caddy_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_internal_machine_api_pb_caddy_proto = out.File
|
|
||||||
file_internal_machine_api_pb_caddy_proto_rawDesc = nil
|
|
||||||
file_internal_machine_api_pb_caddy_proto_goTypes = nil
|
|
||||||
file_internal_machine_api_pb_caddy_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@ package proxy
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/siderolabs/grpc-proxy/proxy"
|
"github.com/siderolabs/grpc-proxy/proxy"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"google.golang.org/protobuf/encoding/protowire"
|
"google.golang.org/protobuf/encoding/protowire"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MachineTarget represents a resolved machine target.
|
// MachineTarget represents a resolved machine target.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"google.golang.org/protobuf/types/known/emptypb"
|
"google.golang.org/protobuf/types/known/emptypb"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server implements the gRPC Caddy service.
|
// Server implements the gRPC Caddy service.
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
// Package caddystorage implements the machine-local Caddy storage API.
|
||||||
|
// See api/pb/caddy_storage.proto for the gRPC service definition.
|
||||||
|
package caddystorage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
"path"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
|
"github.com/psviderski/uncloud/internal/machine/store"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
"google.golang.org/protobuf/types/known/emptypb"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Namespace identifies Caddy storage records in the cluster key-value store.
|
||||||
|
const Namespace = "caddy_storage"
|
||||||
|
|
||||||
|
// Server implements the machine-local CaddyStorage gRPC service.
|
||||||
|
type Server struct {
|
||||||
|
pb.UnimplementedCaddyStorageServer
|
||||||
|
store *store.Keyspace
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(store *store.Keyspace) *Server {
|
||||||
|
return &Server{store: store}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Store(ctx context.Context, req *pb.StoreCaddyStorageRequest) (*emptypb.Empty, error) {
|
||||||
|
if err := validateKey(req.Key); err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
if err := s.store.Put(ctx, req.Key, req.Value); err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "put value: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &emptypb.Empty{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Load(ctx context.Context, req *pb.LoadCaddyStorageRequest) (*pb.LoadCaddyStorageResponse, error) {
|
||||||
|
if err := validateKey(req.Key); err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
record, err := s.store.Get(ctx, req.Key)
|
||||||
|
if errors.Is(err, store.ErrKeyNotFound) {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "Caddy storage key %q not found", req.Key)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "get value: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.LoadCaddyStorageResponse{
|
||||||
|
Value: record.Value,
|
||||||
|
UpdatedAt: timestamppb.New(record.UpdatedAt),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Delete(ctx context.Context, req *pb.DeleteCaddyStorageRequest) (*emptypb.Empty, error) {
|
||||||
|
if err := validateKey(req.Key); err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the key and all keys prefixed by it in case it's a directory.
|
||||||
|
if err := errors.Join(
|
||||||
|
s.store.Delete(ctx, req.Key, store.KeyspaceDeleteOptions{}),
|
||||||
|
s.store.Delete(ctx, req.Key+"/", store.KeyspaceDeleteOptions{Prefix: true}),
|
||||||
|
); err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "delete key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &emptypb.Empty{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) List(ctx context.Context, req *pb.ListCaddyStorageRequest) (*pb.ListCaddyStorageResponse, error) {
|
||||||
|
if req.Prefix != "" {
|
||||||
|
if err := validateKey(req.Prefix); err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
storagePrefix := req.Prefix
|
||||||
|
if storagePrefix != "" {
|
||||||
|
storagePrefix += "/"
|
||||||
|
}
|
||||||
|
records, err := s.store.List(ctx, storagePrefix, store.KeyspaceListOptions{KeysOnly: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "list keys: %v", err)
|
||||||
|
}
|
||||||
|
// No descendants can mean an existing terminal key or a missing path.
|
||||||
|
// Check the exact key for non-root prefixes. An empty prefix lists the storage root.
|
||||||
|
if len(records) == 0 && req.Prefix != "" {
|
||||||
|
if _, err = s.store.Get(ctx, req.Prefix); errors.Is(err, store.ErrKeyNotFound) {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "Caddy storage prefix %q not found", req.Prefix)
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "get prefix value: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.ListCaddyStorageResponse{
|
||||||
|
Keys: listKeys(records, req.Prefix, req.Recursive),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listKeys(records []store.Record, prefix string, recursive bool) []string {
|
||||||
|
keys := make(map[string]struct{})
|
||||||
|
for _, record := range records {
|
||||||
|
relative := record.Key
|
||||||
|
if prefix != "" {
|
||||||
|
relative = strings.TrimPrefix(record.Key, prefix+"/")
|
||||||
|
}
|
||||||
|
components := strings.Split(relative, "/")
|
||||||
|
if !recursive {
|
||||||
|
keys[path.Join(prefix, components[0])] = struct{}{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range components {
|
||||||
|
keys[path.Join(prefix, path.Join(components[:i+1]...))] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return slices.Sorted(maps.Keys(keys))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Stat(ctx context.Context, req *pb.StatCaddyStorageRequest) (*pb.StatCaddyStorageResponse, error) {
|
||||||
|
if err := validateKey(req.Key); err != nil {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
record, err := s.store.Get(ctx, req.Key)
|
||||||
|
if err == nil {
|
||||||
|
return &pb.StatCaddyStorageResponse{
|
||||||
|
Key: req.Key,
|
||||||
|
UpdatedAt: timestamppb.New(record.UpdatedAt),
|
||||||
|
Size: int64(len(record.Value)),
|
||||||
|
IsTerminal: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
if !errors.Is(err, store.ErrKeyNotFound) {
|
||||||
|
return nil, status.Errorf(codes.Internal, "get value: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A terminal key is not found. Check if there are any keys prefixed by the key to determine if it's a directory.
|
||||||
|
records, err := s.store.List(ctx, req.Key+"/", store.KeyspaceListOptions{KeysOnly: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "list keys: %v", err)
|
||||||
|
}
|
||||||
|
if len(records) == 0 {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "Caddy storage key %q not found", req.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.StatCaddyStorageResponse{
|
||||||
|
Key: req.Key,
|
||||||
|
IsTerminal: false,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateKey(key string) error {
|
||||||
|
if key == "" {
|
||||||
|
return fmt.Errorf("key is empty")
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(key, "/") || strings.HasSuffix(key, "/") {
|
||||||
|
return fmt.Errorf("key %q must not have a leading or trailing slash", key)
|
||||||
|
}
|
||||||
|
if strings.Contains(key, "\\") {
|
||||||
|
return fmt.Errorf("key %q must use forward slashes", key)
|
||||||
|
}
|
||||||
|
for component := range strings.SplitSeq(key, "/") {
|
||||||
|
if component == "" || component == "." || component == ".." {
|
||||||
|
return fmt.Errorf("key %q contains an invalid path component", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package caddystorage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/internal/machine/store"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestListKeys(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
records []store.Record
|
||||||
|
prefix string
|
||||||
|
recursive bool
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty root",
|
||||||
|
recursive: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "root immediate children",
|
||||||
|
records: []store.Record{
|
||||||
|
{Key: "ocsp/example.com"},
|
||||||
|
{Key: "certificates/issuer/example.com/example.com.key"},
|
||||||
|
{Key: "certificates/issuer/example.com/example.com.crt"},
|
||||||
|
},
|
||||||
|
want: []string{
|
||||||
|
"certificates",
|
||||||
|
"ocsp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "root recursive",
|
||||||
|
records: []store.Record{
|
||||||
|
{Key: "ocsp/example.com"},
|
||||||
|
{Key: "certificates/issuer/example.com/example.com.key"},
|
||||||
|
{Key: "certificates/issuer/example.com/example.com.crt"},
|
||||||
|
},
|
||||||
|
recursive: true,
|
||||||
|
want: []string{
|
||||||
|
"certificates",
|
||||||
|
"certificates/issuer",
|
||||||
|
"certificates/issuer/example.com",
|
||||||
|
"certificates/issuer/example.com/example.com.crt",
|
||||||
|
"certificates/issuer/example.com/example.com.key",
|
||||||
|
"ocsp",
|
||||||
|
"ocsp/example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nested immediate children",
|
||||||
|
records: []store.Record{
|
||||||
|
{Key: "certificates/issuer/example.net/example.net.crt"},
|
||||||
|
{Key: "certificates/issuer/example.com/example.com.key"},
|
||||||
|
{Key: "certificates/issuer/example.com/example.com.crt"},
|
||||||
|
},
|
||||||
|
prefix: "certificates/issuer",
|
||||||
|
want: []string{
|
||||||
|
"certificates/issuer/example.com",
|
||||||
|
"certificates/issuer/example.net",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nested terminal children",
|
||||||
|
records: []store.Record{
|
||||||
|
{Key: "ocsp/example.net"},
|
||||||
|
{Key: "ocsp/example.com"},
|
||||||
|
},
|
||||||
|
prefix: "ocsp",
|
||||||
|
want: []string{
|
||||||
|
"ocsp/example.com",
|
||||||
|
"ocsp/example.net",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nested recursive",
|
||||||
|
records: []store.Record{
|
||||||
|
{Key: "certificates/issuer/example.net/example.net.crt"},
|
||||||
|
{Key: "certificates/issuer/example.com/example.com.key"},
|
||||||
|
{Key: "certificates/issuer/example.com/example.com.crt"},
|
||||||
|
},
|
||||||
|
prefix: "certificates/issuer",
|
||||||
|
recursive: true,
|
||||||
|
want: []string{
|
||||||
|
"certificates/issuer/example.com",
|
||||||
|
"certificates/issuer/example.com/example.com.crt",
|
||||||
|
"certificates/issuer/example.com/example.com.key",
|
||||||
|
"certificates/issuer/example.net",
|
||||||
|
"certificates/issuer/example.net/example.net.crt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := listKeys(tt.records, tt.prefix, tt.recursive)
|
||||||
|
if len(tt.want) == 0 {
|
||||||
|
require.Empty(t, got)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
-102
@@ -12,7 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cenkalti/backoff/v4"
|
"github.com/cenkalti/backoff/v4"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/machine/caddyconfig"
|
"github.com/psviderski/uncloud/internal/machine/caddyconfig"
|
||||||
"github.com/psviderski/uncloud/internal/machine/constants"
|
"github.com/psviderski/uncloud/internal/machine/constants"
|
||||||
"github.com/psviderski/uncloud/internal/machine/corromigrate"
|
"github.com/psviderski/uncloud/internal/machine/corromigrate"
|
||||||
@@ -189,9 +189,10 @@ func (cc *clusterController) Run(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
// Wait for the store database to sync to the minimum version before starting store-dependent components.
|
// Wait for initial replication before starting store-dependent components, such as WireGuard peer reconciliation.
|
||||||
// This prevents issues with using partially replicated data when the machine just joined the cluster,
|
// This prevents issues with using partially replicated data when the machine just joined the cluster, e.g.,
|
||||||
// e.g., an empty machine list causing WireGuard peer misconfiguration.
|
// an empty machine list causing WireGuard peer misconfiguration.
|
||||||
|
// This uses Store.WaitForVersion's replication-progress semantics, not an exact snapshot of the join-time data.
|
||||||
if err = cc.waitStoreSync(ctx); err != nil {
|
if err = cc.waitStoreSync(ctx); err != nil {
|
||||||
return fmt.Errorf("wait initial cluster store sync: %w", err)
|
return fmt.Errorf("wait initial cluster store sync: %w", err)
|
||||||
}
|
}
|
||||||
@@ -366,120 +367,67 @@ func (cc *clusterController) handleEndpointChanges(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// waitStoreSync blocks until the local store version >= state.MinStoreVersion and any known gaps are synced.
|
// waitStoreSync waits for initial replication using [store.Store.WaitForVersion].
|
||||||
// No-op when MinStoreVersion is empty. Clears state.MinStoreVersion when reached.
|
// No-op when MinStoreVersion is empty. Retries until cancellation and clears state.MinStoreVersion after success.
|
||||||
func (cc *clusterController) waitStoreSync(ctx context.Context) error {
|
func (cc *clusterController) waitStoreSync(ctx context.Context) error {
|
||||||
target := cc.state.MinStoreVersion
|
minVersion := cc.state.MinStoreVersion
|
||||||
if len(target) == 0 {
|
if len(minVersion) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("Waiting for the initial cluster store sync.", "actors", len(target))
|
slog.Info("Waiting for the initial cluster store sync.", "min_version", minVersion)
|
||||||
|
|
||||||
ticker := time.NewTicker(500 * time.Millisecond)
|
// Periodic deadlines surface stuck NAT/connectivity issues without aborting startup.
|
||||||
defer ticker.Stop()
|
|
||||||
// Periodic warning to surface stuck NAT/connectivity issues without aborting.
|
|
||||||
warnInterval := 5 * time.Minute
|
warnInterval := 5 * time.Minute
|
||||||
warnTimer := time.NewTimer(warnInterval)
|
nextWarning := time.Now().Add(warnInterval)
|
||||||
defer warnTimer.Stop()
|
var lastErrLogTime time.Time
|
||||||
|
|
||||||
var (
|
|
||||||
lastLagging int
|
|
||||||
lastErrLogTime time.Time
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
waitCtx, cancel := context.WithDeadline(ctx, nextWarning)
|
||||||
|
err := cc.store.WaitForVersion(waitCtx, minVersion)
|
||||||
|
cancel()
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if errors.Is(err, store.ErrInvalidStoreVersion) {
|
||||||
|
return fmt.Errorf("wait for minimum cluster store version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !time.Now().Before(nextWarning) {
|
||||||
|
slog.Warn("Cluster store sync still pending. Check connectivity to peers.")
|
||||||
|
nextWarning = time.Now().Add(warnInterval)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry store errors, throttling logs to once every 5 seconds.
|
||||||
|
if time.Since(lastErrLogTime) >= 5*time.Second {
|
||||||
|
slog.Error("Failed to check cluster store replication, retrying.", "err", err)
|
||||||
|
lastErrLogTime = time.Now()
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil
|
return nil
|
||||||
case <-warnTimer.C:
|
case <-time.After(500 * time.Millisecond):
|
||||||
local, err := cc.store.Version(ctx)
|
|
||||||
if err == nil {
|
|
||||||
slog.Error("Cluster store sync still pending. Check connectivity to peers.",
|
|
||||||
"lagging_actors", laggingActors(local, target))
|
|
||||||
} else {
|
|
||||||
slog.Error("Cluster store sync still pending. Check connectivity to peers.", "err", err)
|
|
||||||
}
|
|
||||||
warnTimer.Reset(warnInterval)
|
|
||||||
case <-ticker.C:
|
|
||||||
local, err := cc.store.Version(ctx)
|
|
||||||
if err != nil {
|
|
||||||
// Throttle error logs to once every 5 seconds.
|
|
||||||
if time.Since(lastErrLogTime) >= 5*time.Second {
|
|
||||||
slog.Error("Failed to get the cluster store version, retrying.", "err", err)
|
|
||||||
lastErrLogTime = time.Now()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
lagging := laggingActors(local, target)
|
|
||||||
if len(lagging) == 0 {
|
|
||||||
// Per-actor max doesn't imply contiguous apply: corrosion can buffer X:N before
|
|
||||||
// X:N-1 arrives and track the gap separately. Wait for any remaining gaps to be synced.
|
|
||||||
if err := cc.waitKnownMissingChanges(ctx); err != nil {
|
|
||||||
return fmt.Errorf("wait for known missing changes: %w", err)
|
|
||||||
}
|
|
||||||
// If the context was cancelled mid-gap-fill, don't persist a "synced" state.
|
|
||||||
if ctx.Err() != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear MinStoreVersion so next restart doesn't wait for sync.
|
|
||||||
cc.state.mu.Lock()
|
|
||||||
cc.state.MinStoreVersion = nil
|
|
||||||
err = cc.state.Save()
|
|
||||||
cc.state.mu.Unlock()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("save machine state after the initial cluster store sync: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Info("Cluster store completed the initial sync.", "actors", len(target))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(lagging) != lastLagging {
|
|
||||||
slog.Info("Syncing cluster store.", "lagging_actors", lagging)
|
|
||||||
lastLagging = len(lagging)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// laggingActors returns target actors whose local version is below the required value, as [have, need].
|
// Clear MinStoreVersion so the next restart doesn't wait for sync.
|
||||||
func laggingActors(local, target map[string]int64) map[string][2]int64 {
|
cc.state.mu.Lock()
|
||||||
lagging := make(map[string][2]int64)
|
cc.state.MinStoreVersion = nil
|
||||||
for actor, need := range target {
|
err := cc.state.Save()
|
||||||
if have := local[actor]; have < need {
|
if err != nil {
|
||||||
lagging[actor] = [2]int64{have, need}
|
cc.state.MinStoreVersion = minVersion
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return lagging
|
cc.state.mu.Unlock()
|
||||||
}
|
if err != nil {
|
||||||
|
return fmt.Errorf("save machine state after the initial cluster store sync: %w", err)
|
||||||
// waitKnownMissingChanges polls the store until all known missing changes have been synced.
|
|
||||||
func (cc *clusterController) waitKnownMissingChanges(ctx context.Context) error {
|
|
||||||
ticker := time.NewTicker(1 * time.Second)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil
|
|
||||||
case <-ticker.C:
|
|
||||||
changes, err := cc.store.KnownMissingChanges(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("query known missing changes from cluster store: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(changes) == 0 {
|
|
||||||
slog.Debug("All known missing changes have been synced to the cluster store.")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("Waiting for known missing changes to be synced to the cluster store.", "remaining",
|
|
||||||
len(changes))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slog.Info("Cluster store completed the initial sync.", "min_version", minVersion)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// runMachineSync keeps this machine's info in the cluster store in sync with the local state and the Docker engine
|
// runMachineSync keeps this machine's info in the cluster store in sync with the local state and the Docker engine
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/corrosion"
|
"github.com/psviderski/uncloud/internal/corrosion"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/network"
|
"github.com/psviderski/uncloud/internal/machine/network"
|
||||||
"github.com/psviderski/uncloud/internal/machine/store"
|
"github.com/psviderski/uncloud/internal/machine/store"
|
||||||
"github.com/psviderski/uncloud/internal/secret"
|
"github.com/psviderski/uncloud/internal/secret"
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/dns"
|
"github.com/psviderski/uncloud/internal/dns"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/store"
|
"github.com/psviderski/uncloud/internal/machine/store"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/fs"
|
"github.com/psviderski/uncloud/internal/fs"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/store"
|
"github.com/psviderski/uncloud/internal/machine/store"
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/errdefs"
|
"github.com/containerd/errdefs"
|
||||||
|
systemd "github.com/coreos/go-systemd/daemon"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/docker/docker/api/types/mount"
|
"github.com/docker/docker/api/types/mount"
|
||||||
@@ -22,6 +23,13 @@ const (
|
|||||||
Image = "ghcr.io/unlabs-dev/corrosion:2026.6.15"
|
Image = "ghcr.io/unlabs-dev/corrosion:2026.6.15"
|
||||||
// ContainerName is the name of the managed Corrosion container.
|
// ContainerName is the name of the managed Corrosion container.
|
||||||
ContainerName = "uncloud-corrosion"
|
ContainerName = "uncloud-corrosion"
|
||||||
|
|
||||||
|
// systemdStartTimeoutExtension is the duration of each systemd service start timeout extension that prevents
|
||||||
|
// a slow image pull from exceeding the start timeout (TimeoutStartSec). Extensions are a no-op if Corrosion
|
||||||
|
// is not starting during a systemd service startup.
|
||||||
|
systemdStartTimeoutExtension = 30 * time.Second
|
||||||
|
// systemdStartTimeoutExtendMax caps the total duration the start timeout can be extended for.
|
||||||
|
systemdStartTimeoutExtendMax = 5 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
type DockerService struct {
|
type DockerService struct {
|
||||||
@@ -175,8 +183,14 @@ func (s *DockerService) createAndStart(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
defer respBody.Close()
|
defer respBody.Close()
|
||||||
|
|
||||||
|
// The pull on the first daemon start may take longer than the systemd service start timeout (TimeoutStartSec)
|
||||||
|
// on a slow connection. Keep extending the timeout while the pull is in progress so systemd doesn't kill
|
||||||
|
// the daemon before it reports readiness. This is a no-op if not running under systemd.
|
||||||
|
stopExtending := extendSystemdStartTimeout(ctx)
|
||||||
// Wait for pull to complete.
|
// Wait for pull to complete.
|
||||||
if _, err := io.Copy(io.Discard, respBody); err != nil {
|
_, err = io.Copy(io.Discard, respBody)
|
||||||
|
stopExtending()
|
||||||
|
if err != nil {
|
||||||
return fmt.Errorf("read pull response: %w", err)
|
return fmt.Errorf("read pull response: %w", err)
|
||||||
}
|
}
|
||||||
slog.Info("Docker image pulled.", "image", s.Image, "duration", time.Since(start).String())
|
slog.Info("Docker image pulled.", "image", s.Image, "duration", time.Since(start).String())
|
||||||
@@ -192,3 +206,40 @@ func (s *DockerService) createAndStart(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extendSystemdStartTimeout periodically asks systemd to extend the service start timeout, for up to
|
||||||
|
// systemdStartTimeoutExtendMax. The returned function stops the extensions. It is a no-op when the service
|
||||||
|
// is not running under systemd (NOTIFY_SOCKET is not set).
|
||||||
|
func extendSystemdStartTimeout(ctx context.Context) (stop context.CancelFunc) {
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// Send extensions more frequently than they expire so a single missed tick doesn't time out the start.
|
||||||
|
ticker := time.NewTicker(systemdStartTimeoutExtension / 3)
|
||||||
|
defer ticker.Stop()
|
||||||
|
deadline := time.Now().Add(systemdStartTimeoutExtendMax)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
if time.Now().After(deadline) {
|
||||||
|
slog.Warn("Stopped extending the systemd service start timeout: corrosion service is taking "+
|
||||||
|
"too long to start.", "timeout", systemdStartTimeoutExtendMax)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg := fmt.Sprintf("EXTEND_TIMEOUT_USEC=%d", systemdStartTimeoutExtension.Microseconds())
|
||||||
|
if _, err := systemd.SdNotify(false, msg); err != nil {
|
||||||
|
slog.Warn("Failed to extend the systemd service start timeout when starting corrosion service.",
|
||||||
|
"err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
slog.Info("Extended systemd service start timeout while corrosion service is starting.",
|
||||||
|
"duration", systemdStartTimeoutExtension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return cancel
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import (
|
|||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
regtypes "github.com/google/go-containerregistry/pkg/v1/types"
|
regtypes "github.com/google/go-containerregistry/pkg/v1/types"
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/docker"
|
"github.com/psviderski/uncloud/internal/docker"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
||||||
"github.com/moby/term"
|
"github.com/moby/term"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import (
|
|||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/machine/dns"
|
"github.com/psviderski/uncloud/internal/machine/dns"
|
||||||
"github.com/psviderski/uncloud/internal/secret"
|
"github.com/psviderski/uncloud/internal/secret"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
@@ -562,7 +562,9 @@ func (s *Server) CreateServiceContainer(
|
|||||||
api.LabelServiceMode: spec.Mode,
|
api.LabelServiceMode: spec.Mode,
|
||||||
api.LabelManaged: "",
|
api.LabelManaged: "",
|
||||||
},
|
},
|
||||||
User: spec.Container.User,
|
User: spec.Container.User,
|
||||||
|
Tty: spec.Container.Tty,
|
||||||
|
OpenStdin: spec.Container.OpenStdin,
|
||||||
}
|
}
|
||||||
if spec.Mode == "" {
|
if spec.Mode == "" {
|
||||||
config.Labels[api.LabelServiceMode] = api.ServiceModeReplicated
|
config.Labels[api.LabelServiceMode] = api.ServiceModeReplicated
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -233,11 +235,17 @@ func (s *Service) ListImages(ctx context.Context, opts image.ListOptions) (Image
|
|||||||
return imagesResp, nil
|
return imagesResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerLogs streams logs from a container and returns demultiplexed entries via a channel.
|
// ContainerLogs streams logs from a container and returns entries via a channel.
|
||||||
// The channel is closed when streaming completes or context is cancelled.
|
// The channel is closed when streaming completes or context is cancelled.
|
||||||
func (s *Service) ContainerLogs(
|
func (s *Service) ContainerLogs(
|
||||||
ctx context.Context, containerID string, opts api.ServiceLogsOptions,
|
ctx context.Context, containerID string, opts api.ServiceLogsOptions,
|
||||||
) (<-chan api.LogEntry, error) {
|
) (<-chan api.LogEntry, error) {
|
||||||
|
ctr, err := s.Client.ContainerInspect(ctx, containerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("inspect container '%s': %w", containerID, err)
|
||||||
|
}
|
||||||
|
isTTY := ctr.Config != nil && ctr.Config.Tty
|
||||||
|
|
||||||
dockerOpts := container.LogsOptions{
|
dockerOpts := container.LogsOptions{
|
||||||
ShowStdout: true,
|
ShowStdout: true,
|
||||||
ShowStderr: true,
|
ShowStderr: true,
|
||||||
@@ -257,25 +265,31 @@ func (s *Service) ContainerLogs(
|
|||||||
stdoutWriter := &logsChannelWriter{ctx: ctx, ch: outCh, isStderr: false}
|
stdoutWriter := &logsChannelWriter{ctx: ctx, ch: outCh, isStderr: false}
|
||||||
stderrWriter := &logsChannelWriter{ctx: ctx, ch: outCh, isStderr: true}
|
stderrWriter := &logsChannelWriter{ctx: ctx, ch: outCh, isStderr: true}
|
||||||
|
|
||||||
// Wrap the context in a cancellable one to unblock the second goroutine below when StdCopy completes.
|
// Wrap the context in a cancellable one to unblock the second goroutine when log copying completes.
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
// Run StdCopy in a goroutine to be able to handle context cancellation.
|
// Copy logs in a goroutine to be able to handle context cancellation.
|
||||||
go func() {
|
go func() {
|
||||||
defer close(outCh)
|
defer close(outCh)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// StdCopy is blocking and will return when the reader is closed in another goroutine below or on error.
|
// Docker returns raw stdout for TTY containers and multiplexed stdout/stderr otherwise.
|
||||||
if _, err := stdcopy.StdCopy(stdoutWriter, stderrWriter, reader); err != nil {
|
var err error
|
||||||
|
if isTTY {
|
||||||
|
_, err = copyRawContainerLogs(stdoutWriter, reader)
|
||||||
|
} else {
|
||||||
|
_, err = stdcopy.StdCopy(stdoutWriter, stderrWriter, reader)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
// Send error as the last entry.
|
// Send error as the last entry.
|
||||||
select {
|
select {
|
||||||
case outCh <- api.LogEntry{Err: fmt.Errorf("demultiplex container logs: %w", err)}:
|
case outCh <- api.LogEntry{Err: fmt.Errorf("copy container logs: %w", err)}:
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Close the reader when the context is done to cancel StdCopy if it's still running.
|
// Close the reader when the context is done to cancel log copying if it's still running.
|
||||||
go func() {
|
go func() {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
reader.Close()
|
reader.Close()
|
||||||
@@ -284,7 +298,32 @@ func (s *Service) ContainerLogs(
|
|||||||
return outCh, nil
|
return outCh, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// logsChannelWriter is a writer for stdcopy.StdCopy that sends demultiplexed container logs to a channel.
|
// copyRawContainerLogs copies a raw TTY log stream one line at a time so each write produces one log entry.
|
||||||
|
func copyRawContainerLogs(dst io.Writer, src io.Reader) (written int64, _ error) {
|
||||||
|
reader := bufio.NewReader(src)
|
||||||
|
for {
|
||||||
|
line, readErr := reader.ReadBytes('\n')
|
||||||
|
if len(line) > 0 {
|
||||||
|
n, writeErr := dst.Write(line)
|
||||||
|
written += int64(n)
|
||||||
|
if writeErr != nil {
|
||||||
|
return written, writeErr
|
||||||
|
}
|
||||||
|
if n != len(line) {
|
||||||
|
return written, io.ErrShortWrite
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if readErr != nil {
|
||||||
|
if errors.Is(readErr, io.EOF) {
|
||||||
|
return written, nil
|
||||||
|
}
|
||||||
|
return written, readErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// logsChannelWriter sends container log writes to a channel.
|
||||||
type logsChannelWriter struct {
|
type logsChannelWriter struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ch chan<- api.LogEntry
|
ch chan<- api.LogEntry
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
dockerclient "github.com/docker/docker/client"
|
||||||
|
"github.com/docker/docker/pkg/stdcopy"
|
||||||
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServiceContainerLogs(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const (
|
||||||
|
containerID = "container-id"
|
||||||
|
firstLog = "2025-01-01T00:00:00.000000000Z first message\n"
|
||||||
|
secondLog = "2025-01-01T00:00:01.000000000Z second message\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
var multiplexedLogs bytes.Buffer
|
||||||
|
_, err := stdcopy.NewStdWriter(&multiplexedLogs, stdcopy.Stdout).Write([]byte(firstLog))
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = stdcopy.NewStdWriter(&multiplexedLogs, stdcopy.Stderr).Write([]byte(secondLog))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
tty bool
|
||||||
|
logs []byte
|
||||||
|
streams []api.LogStreamType
|
||||||
|
messages []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "TTY raw stream",
|
||||||
|
tty: true,
|
||||||
|
logs: []byte(firstLog + secondLog),
|
||||||
|
streams: []api.LogStreamType{api.LogStreamStdout, api.LogStreamStdout},
|
||||||
|
messages: []string{"first message\n", "second message\n"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-TTY multiplexed stream",
|
||||||
|
logs: multiplexedLogs.Bytes(),
|
||||||
|
streams: []api.LogStreamType{api.LogStreamStdout, api.LogStreamStderr},
|
||||||
|
messages: []string{"first message\n", "second message\n"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
dockerClient := newLogsTestClient(t, tt.tty, tt.logs)
|
||||||
|
service := NewService(dockerClient, nil)
|
||||||
|
|
||||||
|
logsCh, err := service.ContainerLogs(context.Background(), containerID, api.ServiceLogsOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var entries []api.LogEntry
|
||||||
|
for entry := range logsCh {
|
||||||
|
require.NoError(t, entry.Err)
|
||||||
|
entries = append(entries, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Len(t, entries, len(tt.messages))
|
||||||
|
for i := range entries {
|
||||||
|
assert.Equal(t, tt.streams[i], entries[i].Stream)
|
||||||
|
assert.Equal(t, tt.messages[i], string(entries[i].Message))
|
||||||
|
assert.False(t, entries[i].Timestamp.IsZero())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLogsTestClient(t *testing.T, tty bool, logs []byte) *dockerclient.Client {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(r.URL.Path, "/containers/container-id/json"):
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
if err := json.NewEncoder(w).Encode(container.InspectResponse{
|
||||||
|
ContainerJSONBase: &container.ContainerJSONBase{ID: "container-id"},
|
||||||
|
Config: &container.Config{Tty: tty},
|
||||||
|
}); err != nil {
|
||||||
|
t.Errorf("encode inspect response: %v", err)
|
||||||
|
}
|
||||||
|
case strings.HasSuffix(r.URL.Path, "/containers/container-id/logs"):
|
||||||
|
w.Header().Set("Content-Type", "application/vnd.docker.raw-stream")
|
||||||
|
if _, err := w.Write(logs); err != nil {
|
||||||
|
t.Errorf("write logs response: %v", err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
t.Cleanup(server.Close)
|
||||||
|
|
||||||
|
serverURL, err := url.Parse(server.URL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
dockerClient, err := dockerclient.NewClientWithOpts(
|
||||||
|
dockerclient.WithHost("tcp://"+serverURL.Host),
|
||||||
|
dockerclient.WithHTTPClient(server.Client()),
|
||||||
|
dockerclient.WithVersion("1.48"),
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
require.NoError(t, dockerClient.Close())
|
||||||
|
})
|
||||||
|
|
||||||
|
return dockerClient
|
||||||
|
}
|
||||||
@@ -21,14 +21,15 @@ import (
|
|||||||
"github.com/containerd/errdefs"
|
"github.com/containerd/errdefs"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/docker/go-connections/sockets"
|
"github.com/docker/go-connections/sockets"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/corrosion"
|
"github.com/psviderski/uncloud/internal/corrosion"
|
||||||
"github.com/psviderski/uncloud/internal/docker"
|
"github.com/psviderski/uncloud/internal/docker"
|
||||||
"github.com/psviderski/uncloud/internal/fs"
|
"github.com/psviderski/uncloud/internal/fs"
|
||||||
"github.com/psviderski/uncloud/internal/grpcversion"
|
"github.com/psviderski/uncloud/internal/grpcversion"
|
||||||
"github.com/psviderski/uncloud/internal/journal"
|
"github.com/psviderski/uncloud/internal/journal"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
apiproxy "github.com/psviderski/uncloud/internal/machine/api/proxy"
|
apiproxy "github.com/psviderski/uncloud/internal/machine/api/proxy"
|
||||||
"github.com/psviderski/uncloud/internal/machine/caddyconfig"
|
"github.com/psviderski/uncloud/internal/machine/caddyconfig"
|
||||||
|
"github.com/psviderski/uncloud/internal/machine/caddystorage"
|
||||||
"github.com/psviderski/uncloud/internal/machine/cluster"
|
"github.com/psviderski/uncloud/internal/machine/cluster"
|
||||||
"github.com/psviderski/uncloud/internal/machine/constants"
|
"github.com/psviderski/uncloud/internal/machine/constants"
|
||||||
"github.com/psviderski/uncloud/internal/machine/corromigrate"
|
"github.com/psviderski/uncloud/internal/machine/corromigrate"
|
||||||
@@ -42,6 +43,8 @@ import (
|
|||||||
"github.com/psviderski/uncloud/internal/secret"
|
"github.com/psviderski/uncloud/internal/secret"
|
||||||
"github.com/psviderski/uncloud/internal/version"
|
"github.com/psviderski/uncloud/internal/version"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
|
"github.com/psviderski/uncloud/pkg/distlock"
|
||||||
|
distlockgrpc "github.com/psviderski/uncloud/pkg/distlock/grpc"
|
||||||
"github.com/psviderski/unregistry"
|
"github.com/psviderski/unregistry"
|
||||||
"github.com/siderolabs/grpc-proxy/proxy"
|
"github.com/siderolabs/grpc-proxy/proxy"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
@@ -305,7 +308,15 @@ func NewMachine(config *Config) (*Machine, error) {
|
|||||||
WaitForNetworkReady: m.WaitForNetworkReady,
|
WaitForNetworkReady: m.WaitForNetworkReady,
|
||||||
})
|
})
|
||||||
caddyServer := caddyconfig.NewServer(caddyconfig.NewService(config.CaddyConfigDir))
|
caddyServer := caddyconfig.NewServer(caddyconfig.NewService(config.CaddyConfigDir))
|
||||||
m.localMachineServer = newGRPCServer(m, c, m.dockerServer, caddyServer)
|
|
||||||
|
caddyStore, err := corroStore.Keyspace(caddystorage.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("create namespaced cluster store for Caddy storage: %w", err)
|
||||||
|
}
|
||||||
|
caddyStorageServer := caddystorage.NewServer(caddyStore)
|
||||||
|
|
||||||
|
leaseServer := distlockgrpc.NewServer(distlock.NewMemoryStore())
|
||||||
|
m.localMachineServer = newGRPCServer(m, c, m.dockerServer, caddyServer, caddyStorageServer, leaseServer)
|
||||||
|
|
||||||
if m.Initialised() {
|
if m.Initialised() {
|
||||||
close(m.initialised)
|
close(m.initialised)
|
||||||
@@ -314,12 +325,21 @@ func NewMachine(config *Config) (*Machine, error) {
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGRPCServer(m pb.MachineServer, c pb.ClusterServer, d pb.DockerServer, caddy pb.CaddyServer) *grpc.Server {
|
func newGRPCServer(
|
||||||
|
m pb.MachineServer,
|
||||||
|
c pb.ClusterServer,
|
||||||
|
d pb.DockerServer,
|
||||||
|
caddy pb.CaddyServer,
|
||||||
|
caddyStorage pb.CaddyStorageServer,
|
||||||
|
lease distlockgrpc.LeaseServer,
|
||||||
|
) *grpc.Server {
|
||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
pb.RegisterMachineServer(s, m)
|
pb.RegisterMachineServer(s, m)
|
||||||
pb.RegisterClusterServer(s, c)
|
pb.RegisterClusterServer(s, c)
|
||||||
pb.RegisterDockerServer(s, d)
|
pb.RegisterDockerServer(s, d)
|
||||||
pb.RegisterCaddyServer(s, caddy)
|
pb.RegisterCaddyServer(s, caddy)
|
||||||
|
pb.RegisterCaddyStorageServer(s, caddyStorage)
|
||||||
|
distlockgrpc.RegisterLeaseServer(s, lease)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1104,6 +1124,19 @@ func (m *Machine) InspectMachine(ctx context.Context, _ *emptypb.Empty) (*pb.Ins
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Machine) WaitForStoreVersion(ctx context.Context, req *pb.WaitForStoreVersionRequest) (*emptypb.Empty, error) {
|
||||||
|
if err := m.store.WaitForVersion(ctx, req.MinVersion); err != nil {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return nil, status.FromContextError(ctx.Err()).Err()
|
||||||
|
}
|
||||||
|
if errors.Is(err, store.ErrInvalidStoreVersion) {
|
||||||
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
|
}
|
||||||
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
|
}
|
||||||
|
return &emptypb.Empty{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateMachine updates the configuration of this machine in its local state (the source of truth) and syncs
|
// UpdateMachine updates the configuration of this machine in its local state (the source of truth) and syncs
|
||||||
// the result to the cluster store.
|
// the result to the cluster store.
|
||||||
func (m *Machine) UpdateMachine(ctx context.Context, req *pb.UpdateMachineRequest) (*pb.UpdateMachineResponse, error) {
|
func (m *Machine) UpdateMachine(ctx context.Context, req *pb.UpdateMachineRequest) (*pb.UpdateMachineResponse, error) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/machine/network"
|
"github.com/psviderski/uncloud/internal/machine/network"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ type State struct {
|
|||||||
// PublicIP is this machine's advertised public IP for ingress. Zero value if unset.
|
// PublicIP is this machine's advertised public IP for ingress. Zero value if unset.
|
||||||
PublicIP netip.Addr `json:",omitempty"`
|
PublicIP netip.Addr `json:",omitempty"`
|
||||||
// MinStoreVersion is the cluster store version this machine must reach before participating.
|
// MinStoreVersion is the cluster store version this machine must reach before participating.
|
||||||
// Per-actor vector (Corrosion actor UUID → max applied db_version) captured from an existing
|
// Per-actor vector (Corrosion actor UUID → max processed db_version) captured from an existing
|
||||||
// member at join time. Cleared once reached.
|
// member at join time. Cleared once reached.
|
||||||
MinStoreVersion map[string]int64 `json:",omitempty"`
|
MinStoreVersion map[string]uint64 `json:",omitempty"`
|
||||||
// CorrosionAPIToken authenticates requests to the local Corrosion API.
|
// CorrosionAPIToken authenticates requests to the local Corrosion API.
|
||||||
CorrosionAPIToken secret.Secret `json:",omitempty"`
|
CorrosionAPIToken secret.Secret `json:",omitempty"`
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/internal/corrosion"
|
||||||
|
)
|
||||||
|
|
||||||
|
const namespaceSeparator = ":"
|
||||||
|
|
||||||
|
var namespacePattern = regexp.MustCompile(`^[a-z][a-z0-9]*(?:[_-][a-z0-9]+)*$`)
|
||||||
|
|
||||||
|
// Record is a key-value entry and its metadata.
|
||||||
|
type Record struct {
|
||||||
|
Key string
|
||||||
|
Value []byte
|
||||||
|
UpdatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyspaceListOptions controls the records returned by [Keyspace.List].
|
||||||
|
type KeyspaceListOptions struct {
|
||||||
|
// KeysOnly omits record values from the query when true.
|
||||||
|
KeysOnly bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyspaceDeleteOptions controls which records [Keyspace.Delete] deletes.
|
||||||
|
type KeyspaceDeleteOptions struct {
|
||||||
|
// Prefix deletes the key and every key that starts with it.
|
||||||
|
Prefix bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keyspace provides namespace-scoped key-value storage.
|
||||||
|
// Keys are relative to the namespace. Prefix operations use simple string-prefix matching.
|
||||||
|
type Keyspace struct {
|
||||||
|
corro *corrosion.APIClient
|
||||||
|
namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keyspace returns key-value storage scoped to namespace.
|
||||||
|
func (s *Store) Keyspace(namespace string) (*Keyspace, error) {
|
||||||
|
if !namespacePattern.MatchString(namespace) {
|
||||||
|
return nil, fmt.Errorf("invalid namespace %q", namespace)
|
||||||
|
}
|
||||||
|
return &Keyspace{
|
||||||
|
corro: s.corro,
|
||||||
|
namespace: namespace,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the entry for key. It returns [ErrKeyNotFound] when the key does not exist.
|
||||||
|
func (k *Keyspace) Get(ctx context.Context, key string) (Record, error) {
|
||||||
|
if key == "" {
|
||||||
|
return Record{}, fmt.Errorf("key is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := k.corro.QueryContext(ctx, "SELECT value, updated_at FROM cluster WHERE key = ?", k.namespacedKey(key))
|
||||||
|
if err != nil {
|
||||||
|
return Record{}, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
if !rows.Next() {
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return Record{}, err
|
||||||
|
}
|
||||||
|
return Record{}, ErrKeyNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
record := Record{Key: key}
|
||||||
|
var updatedAt string
|
||||||
|
if err = rows.Scan(&record.Value, &updatedAt); err != nil {
|
||||||
|
return Record{}, err
|
||||||
|
}
|
||||||
|
if record.UpdatedAt, err = parseTimestamp(updatedAt); err != nil {
|
||||||
|
return Record{}, fmt.Errorf("parse updated_at for key %q: %w", key, err)
|
||||||
|
}
|
||||||
|
return record, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put stores value at key.
|
||||||
|
func (k *Keyspace) Put(ctx context.Context, key string, value []byte) error {
|
||||||
|
if key == "" {
|
||||||
|
return fmt.Errorf("key is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := k.corro.ExecContext(ctx,
|
||||||
|
"INSERT OR REPLACE INTO cluster (key, value, updated_at) VALUES (?, ?, datetime('now', 'subsec'))",
|
||||||
|
k.namespacedKey(key), value)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes key. When Prefix is true, it also deletes every key that starts with key.
|
||||||
|
func (k *Keyspace) Delete(ctx context.Context, key string, opts KeyspaceDeleteOptions) error {
|
||||||
|
if key == "" {
|
||||||
|
return fmt.Errorf("key is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacedKey := k.namespacedKey(key)
|
||||||
|
if !opts.Prefix {
|
||||||
|
_, err := k.corro.ExecContext(ctx, "DELETE FROM cluster WHERE key = ?", namespacedKey)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := k.corro.ExecContext(ctx, `DELETE FROM cluster WHERE key >= ? AND key < ?`,
|
||||||
|
namespacedKey, prefixRangeEnd(namespacedKey))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns entries whose keys start with prefix, ordered by key. An empty prefix lists every entry in the keyspace.
|
||||||
|
func (k *Keyspace) List(ctx context.Context, prefix string, opts KeyspaceListOptions) ([]Record, error) {
|
||||||
|
keyspacePrefix := k.namespacedKey("")
|
||||||
|
namespacedPrefix := k.namespacedKey(prefix)
|
||||||
|
query := "SELECT key, value, updated_at FROM cluster WHERE key >= ? AND key < ? ORDER BY key"
|
||||||
|
if opts.KeysOnly {
|
||||||
|
query = "SELECT key, updated_at FROM cluster WHERE key >= ? AND key < ? ORDER BY key"
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := k.corro.QueryContext(ctx, query, namespacedPrefix, prefixRangeEnd(namespacedPrefix))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var records []Record
|
||||||
|
for rows.Next() {
|
||||||
|
var (
|
||||||
|
record Record
|
||||||
|
updatedAt string
|
||||||
|
)
|
||||||
|
if opts.KeysOnly {
|
||||||
|
err = rows.Scan(&record.Key, &updatedAt)
|
||||||
|
} else {
|
||||||
|
err = rows.Scan(&record.Key, &record.Value, &updatedAt)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if record.UpdatedAt, err = parseTimestamp(updatedAt); err != nil {
|
||||||
|
return nil, fmt.Errorf("parse updated_at for key %q: %w", record.Key, err)
|
||||||
|
}
|
||||||
|
record.Key = strings.TrimPrefix(record.Key, keyspacePrefix)
|
||||||
|
records = append(records, record)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *Keyspace) namespacedKey(key string) string {
|
||||||
|
return k.namespace + namespaceSeparator + key
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTimestamp(value string) (time.Time, error) {
|
||||||
|
return time.Parse(time.DateTime, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefixRangeEnd returns an exclusive upper bound for a key prefix.
|
||||||
|
func prefixRangeEnd(prefix string) string {
|
||||||
|
return prefix + string(utf8.MaxRune)
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrInvalidStoreVersion indicates an invalid actor UUID in a store version vector.
|
||||||
|
var ErrInvalidStoreVersion = errors.New("invalid store version")
|
||||||
|
|
||||||
|
// WaitForVersion waits until the local store has reached each actor's minimum version in minVersion, with no known
|
||||||
|
// missing or pending transactions through those versions. Corrosion may satisfy a version by applying its surviving
|
||||||
|
// changes or by marking it complete because its changes have been superseded.
|
||||||
|
//
|
||||||
|
// Waiting normally makes the captured data available locally. However, if another write replaces some of that data
|
||||||
|
// before it arrives, Corrosion can complete the older version without transferring the replaced data. If the
|
||||||
|
// replacement is outside minVersion, this method can return while the affected data is still missing or outdated.
|
||||||
|
// This can happen during concurrent updates even when all machines are well connected.
|
||||||
|
//
|
||||||
|
// This method does not guarantee an exact snapshot or delivery of every historical value.
|
||||||
|
// Callers that require a specific record or condition should verify it after waiting.
|
||||||
|
//
|
||||||
|
// The method observes native replication without initiating synchronisation.
|
||||||
|
// An empty minVersion requires no replication. The context controls cancellation and the deadline.
|
||||||
|
func (s *Store) WaitForVersion(ctx context.Context, minVersion map[string]uint64) error {
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
placeholders := make([]string, 0, len(minVersion))
|
||||||
|
args := make([]any, 0, 2*len(minVersion))
|
||||||
|
for actor, version := range minVersion {
|
||||||
|
actorID, err := uuid.Parse(actor)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%w: actor '%s' is not a UUID: %v", ErrInvalidStoreVersion, actor, err)
|
||||||
|
}
|
||||||
|
if version == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Corrosion accepts a JSON array of bytes as a BLOB parameter. A UUID marshals as a string,
|
||||||
|
// and a byte slice marshals as base64, so use a plain fixed-size array instead.
|
||||||
|
placeholders = append(placeholders, "(?, ?)")
|
||||||
|
args = append(args, [16]byte(actorID), version)
|
||||||
|
}
|
||||||
|
if len(args) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check all bookkeeping in one SQLite snapshot. Raw buffered rows can remain after application,
|
||||||
|
// but sequence bookkeeping is removed in the same transaction that applies or clears a version.
|
||||||
|
query := `WITH min_version(actor_id, version) AS (VALUES ` + strings.Join(placeholders, ", ") + `)
|
||||||
|
SELECT NOT EXISTS (
|
||||||
|
SELECT 1 FROM min_version
|
||||||
|
LEFT JOIN crsql_db_versions AS current ON current.site_id = min_version.actor_id
|
||||||
|
WHERE COALESCE(current.db_version, 0) < min_version.version
|
||||||
|
OR EXISTS (
|
||||||
|
SELECT 1 FROM __corro_bookkeeping_gaps
|
||||||
|
WHERE actor_id = min_version.actor_id AND start <= min_version.version
|
||||||
|
)
|
||||||
|
OR EXISTS (
|
||||||
|
SELECT 1 FROM __corro_seq_bookkeeping
|
||||||
|
WHERE site_id = min_version.actor_id AND db_version <= min_version.version
|
||||||
|
)
|
||||||
|
)`
|
||||||
|
|
||||||
|
ticker := time.NewTicker(100 * time.Millisecond)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
rows, err := s.corro.QueryContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("check store replication: %w", err)
|
||||||
|
}
|
||||||
|
if !rows.Next() {
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return fmt.Errorf("check store replication: %w", err)
|
||||||
|
}
|
||||||
|
return errors.New("check store replication: store version query returned no rows")
|
||||||
|
}
|
||||||
|
var reached int
|
||||||
|
if err = rows.Scan(&reached); err != nil {
|
||||||
|
rows.Close()
|
||||||
|
return fmt.Errorf("check store replication: %w", err)
|
||||||
|
}
|
||||||
|
rows.Next() // Consume the end-of-query event.
|
||||||
|
rows.Close()
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return fmt.Errorf("check store replication: %w", err)
|
||||||
|
}
|
||||||
|
if reached == 1 {
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-ticker.C:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,14 +3,13 @@ package store
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/corrosion"
|
"github.com/psviderski/uncloud/internal/corrosion"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,14 +30,19 @@ func New(corro *corrosion.APIClient) *Store {
|
|||||||
return &Store{corro: corro}
|
return &Store{corro: corro}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get retrieves an unnamespaced legacy value.
|
||||||
|
//
|
||||||
|
// Deprecated: Existing callers may continue to use Get for legacy records. New
|
||||||
|
// code should use [Store.Keyspace].
|
||||||
func (s *Store) Get(ctx context.Context, key string, value any) error {
|
func (s *Store) Get(ctx context.Context, key string, value any) error {
|
||||||
rows, err := s.corro.QueryContext(ctx, "SELECT value FROM cluster WHERE key = ?", key)
|
rows, err := s.corro.QueryContext(ctx, "SELECT value FROM cluster WHERE key = ?", key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer rows.Close()
|
||||||
if !rows.Next() {
|
if !rows.Next() {
|
||||||
if rows.Err() != nil {
|
if err = rows.Err(); err != nil {
|
||||||
return rows.Err()
|
return err
|
||||||
}
|
}
|
||||||
return ErrKeyNotFound
|
return ErrKeyNotFound
|
||||||
}
|
}
|
||||||
@@ -48,32 +52,47 @@ func (s *Store) Get(ctx context.Context, key string, value any) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put stores an unnamespaced legacy value.
|
||||||
|
//
|
||||||
|
// Deprecated: Existing callers may continue to use Put for legacy records. New
|
||||||
|
// code should use [Store.Keyspace].
|
||||||
func (s *Store) Put(ctx context.Context, key string, value any) error {
|
func (s *Store) Put(ctx context.Context, key string, value any) error {
|
||||||
_, err := s.corro.ExecContext(ctx,
|
_, err := s.corro.ExecContext(ctx,
|
||||||
"INSERT OR REPLACE INTO cluster (key, value, updated_at) VALUES (?, ?, datetime('now'))",
|
"INSERT OR REPLACE INTO cluster (key, value, updated_at) VALUES (?, ?, datetime('now', 'subsec'))",
|
||||||
key, value)
|
key, value)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete deletes an unnamespaced legacy value.
|
||||||
|
//
|
||||||
|
// Deprecated: Existing callers may continue to use Delete for legacy records.
|
||||||
|
// New code should use [Store.Keyspace].
|
||||||
func (s *Store) Delete(ctx context.Context, key string) error {
|
func (s *Store) Delete(ctx context.Context, key string) error {
|
||||||
_, err := s.corro.ExecContext(ctx, "DELETE FROM cluster WHERE key = ?", key)
|
_, err := s.corro.ExecContext(ctx, "DELETE FROM cluster WHERE key = ?", key)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version returns the cluster store's per-actor version vector:
|
// Version returns the replication progress observed by this store.
|
||||||
// Corrosion actor ID (UUID string) → max received db_version for that actor.
|
// Each entry maps a Corrosion actor UUID to its highest processed database version. Corrosion also counts versions
|
||||||
func (s *Store) Version(ctx context.Context) (map[string]int64, error) {
|
// whose changes were superseded and skipped. Versions at or below a reported version may still be missing or pending
|
||||||
|
// locally.
|
||||||
|
//
|
||||||
|
// You can use [Store.WaitForVersion] to wait for replication through these versions, subject to the data-availability
|
||||||
|
// limitations documented there.
|
||||||
|
//
|
||||||
|
// Capturing a vector does not wait for replication or prevent further writes.
|
||||||
|
func (s *Store) Version(ctx context.Context) (map[string]uint64, error) {
|
||||||
rows, err := s.corro.QueryContext(ctx, "SELECT site_id, db_version FROM crsql_db_versions")
|
rows, err := s.corro.QueryContext(ctx, "SELECT site_id, db_version FROM crsql_db_versions")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("query crsql_db_versions: %w", err)
|
return nil, fmt.Errorf("query crsql_db_versions: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
versions := make(map[string]int64)
|
versions := make(map[string]uint64)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var (
|
var (
|
||||||
siteID []byte
|
siteID []byte
|
||||||
version int64
|
version uint64
|
||||||
)
|
)
|
||||||
if err = rows.Scan(&siteID, &version); err != nil {
|
if err = rows.Scan(&siteID, &version); err != nil {
|
||||||
return nil, fmt.Errorf("scan actor version: %w", err)
|
return nil, fmt.Errorf("scan actor version: %w", err)
|
||||||
@@ -87,35 +106,6 @@ func (s *Store) Version(ctx context.Context) (map[string]int64, error) {
|
|||||||
return versions, nil
|
return versions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type MissingChange struct {
|
|
||||||
ActorID string
|
|
||||||
StartVersion int64
|
|
||||||
EndVersion int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// KnownMissingChanges returns a list of currently known missing changes in the Corrosion database.
|
|
||||||
func (s *Store) KnownMissingChanges(ctx context.Context) ([]MissingChange, error) {
|
|
||||||
rows, err := s.corro.QueryContext(ctx, "SELECT actor_id, start, end FROM __corro_bookkeeping_gaps")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("query missing changes: %w", err)
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
var changes []MissingChange
|
|
||||||
for rows.Next() {
|
|
||||||
var c MissingChange
|
|
||||||
var actorBytes []byte
|
|
||||||
if err = rows.Scan(&actorBytes, &c.StartVersion, &c.EndVersion); err != nil {
|
|
||||||
return nil, fmt.Errorf("scan missing change: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ActorID = hex.EncodeToString(actorBytes)
|
|
||||||
changes = append(changes, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
return changes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) CreateMachine(ctx context.Context, m *pb.MachineInfo) error {
|
func (s *Store) CreateMachine(ctx context.Context, m *pb.MachineInfo) error {
|
||||||
mJSON, err := protojson.Marshal(m)
|
mJSON, err := protojson.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+61
-48
@@ -2,11 +2,12 @@ package proxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,58 +16,53 @@ type Proxy struct {
|
|||||||
Listener net.Listener
|
Listener net.Listener
|
||||||
RemoteAddr string
|
RemoteAddr string
|
||||||
DialContext func(ctx context.Context, network, address string) (net.Conn, error)
|
DialContext func(ctx context.Context, network, address string) (net.Conn, error)
|
||||||
|
// OnError is called for errors that occur during proxying individual connections. It may be called concurrently
|
||||||
|
// for different connections.
|
||||||
OnError func(error)
|
OnError func(error)
|
||||||
activeConns sync.WaitGroup
|
activeConns sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// deadliner is an interface for listeners that support setting deadlines.
|
|
||||||
type deadliner interface {
|
|
||||||
SetDeadline(t time.Time) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// halfCloser is an interface for connections that support half-close.
|
// halfCloser is an interface for connections that support half-close.
|
||||||
type halfCloser interface {
|
type halfCloser interface {
|
||||||
CloseWrite() error
|
CloseWrite() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts the proxy and runs until the context is canceled.
|
// IsConnectionClosedError reports whether err indicates that a connection was closed or aborted by either peer.
|
||||||
func (p *Proxy) Run(ctx context.Context) {
|
// Callers can use it to ignore routine connection shutdown or broken pipe errors reported to Proxy.OnError.
|
||||||
|
func IsConnectionClosedError(err error) bool {
|
||||||
|
return errors.Is(err, net.ErrClosed) || errors.Is(err, io.ErrClosedPipe) ||
|
||||||
|
errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run starts the proxy and runs until the context is canceled or the listener fails. It returns nil when the context
|
||||||
|
// is canceled. Errors handling individual connections are reported to OnError and do not stop the proxy.
|
||||||
|
func (p *Proxy) Run(ctx context.Context) error {
|
||||||
if p.DialContext == nil {
|
if p.DialContext == nil {
|
||||||
p.DialContext = (&net.Dialer{}).DialContext
|
p.DialContext = (&net.Dialer{}).DialContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
defer p.Listener.Close()
|
defer p.Listener.Close()
|
||||||
|
|
||||||
// Handle incoming connections until context is canceled.
|
// Closing the listener unblocks Accept when the context is canceled. This works for both TCP and Unix listeners
|
||||||
Loop:
|
// and avoids polling with listener deadlines.
|
||||||
|
stopClose := context.AfterFunc(ctx, func() {
|
||||||
|
p.Listener.Close()
|
||||||
|
})
|
||||||
|
defer stopClose()
|
||||||
|
|
||||||
|
var runErr error
|
||||||
for {
|
for {
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
break Loop
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a deadline on the listener if supported to check context periodically.
|
|
||||||
if dl, ok := p.Listener.(deadliner); ok {
|
|
||||||
dl.SetDeadline(time.Now().Add(1 * time.Second))
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := p.Listener.Accept()
|
conn, err := p.Listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsTimeout(err) {
|
if ctx.Err() != nil {
|
||||||
// Just a timeout, continue to check context and accept again.
|
break
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
runErr = fmt.Errorf("accept local connection: %w", err)
|
||||||
case <-ctx.Done():
|
cancel()
|
||||||
break Loop
|
break
|
||||||
default:
|
|
||||||
if p.OnError != nil {
|
|
||||||
p.OnError(fmt.Errorf("accept local connection: %w", err))
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.activeConns.Add(1)
|
p.activeConns.Add(1)
|
||||||
@@ -75,6 +71,7 @@ Loop:
|
|||||||
|
|
||||||
// Wait for all connections to finish.
|
// Wait for all connections to finish.
|
||||||
p.activeConns.Wait()
|
p.activeConns.Wait()
|
||||||
|
return runErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proxy) handleConnection(ctx context.Context, localConn net.Conn) {
|
func (p *Proxy) handleConnection(ctx context.Context, localConn net.Conn) {
|
||||||
@@ -87,46 +84,62 @@ func (p *Proxy) handleConnection(ctx context.Context, localConn net.Conn) {
|
|||||||
|
|
||||||
remoteConn, err := p.DialContext(dialCtx, "tcp", p.RemoteAddr)
|
remoteConn, err := p.DialContext(dialCtx, "tcp", p.RemoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if p.OnError != nil {
|
if ctx.Err() == nil && p.OnError != nil {
|
||||||
p.OnError(fmt.Errorf("connect remote address '%s': %w", p.RemoteAddr, err))
|
p.OnError(fmt.Errorf("connect remote address '%s': %w", p.RemoteAddr, err))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer remoteConn.Close()
|
defer remoteConn.Close()
|
||||||
|
|
||||||
// Bidirectional copy with proper half-close handling.
|
// Closing both connections aborts both copies after cancellation or a copy error. A clean EOF still uses
|
||||||
|
// half-close so the other direction can finish sending any remaining data.
|
||||||
|
closeConnections := func() {
|
||||||
|
localConn.Close()
|
||||||
|
remoteConn.Close()
|
||||||
|
}
|
||||||
|
stopClose := context.AfterFunc(ctx, closeConnections)
|
||||||
|
defer stopClose()
|
||||||
|
|
||||||
done := make(chan error, 2)
|
done := make(chan error, 2)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
_, err := io.Copy(remoteConn, localConn)
|
_, err := io.Copy(remoteConn, localConn)
|
||||||
|
if err != nil {
|
||||||
|
done <- err
|
||||||
|
closeConnections()
|
||||||
|
return
|
||||||
|
}
|
||||||
// Close write half of remote connection if supported.
|
// Close write half of remote connection if supported.
|
||||||
if hc, ok := remoteConn.(halfCloser); ok {
|
if hc, ok := remoteConn.(halfCloser); ok {
|
||||||
hc.CloseWrite()
|
hc.CloseWrite()
|
||||||
}
|
}
|
||||||
done <- err
|
done <- nil
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
_, err := io.Copy(localConn, remoteConn)
|
_, err := io.Copy(localConn, remoteConn)
|
||||||
|
if err != nil {
|
||||||
|
done <- err
|
||||||
|
closeConnections()
|
||||||
|
return
|
||||||
|
}
|
||||||
// Close write half of local connection if supported.
|
// Close write half of local connection if supported.
|
||||||
if hc, ok := localConn.(halfCloser); ok {
|
if hc, ok := localConn.(halfCloser); ok {
|
||||||
hc.CloseWrite()
|
hc.CloseWrite()
|
||||||
}
|
}
|
||||||
done <- err
|
done <- nil
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Wait for both copies to complete or context cancel.
|
// Wait for both copies to complete. The first error is the original failure because a copy reports it before
|
||||||
|
// closing the connections to unblock the other copy.
|
||||||
|
var copyErr error
|
||||||
for range 2 {
|
for range 2 {
|
||||||
select {
|
if err = <-done; err != nil && copyErr == nil {
|
||||||
case <-ctx.Done():
|
copyErr = err
|
||||||
// Close connections to abort ongoing copies.
|
|
||||||
localConn.Close()
|
|
||||||
remoteConn.Close()
|
|
||||||
return
|
|
||||||
case err = <-done:
|
|
||||||
if err != nil && p.OnError != nil {
|
|
||||||
p.OnError(fmt.Errorf("data copy: %w", err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if copyErr != nil && ctx.Err() == nil && p.OnError != nil {
|
||||||
|
p.OnError(fmt.Errorf("data copy: %w", copyErr))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsConnectionClosedError(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{name: "closed network connection", err: net.ErrClosed, want: true},
|
||||||
|
{name: "closed pipe", err: io.ErrClosedPipe, want: true},
|
||||||
|
{name: "broken pipe", err: syscall.EPIPE, want: true},
|
||||||
|
{name: "connection reset", err: syscall.ECONNRESET, want: true},
|
||||||
|
{name: "wrapped connection error", err: fmt.Errorf("copy data: %w", syscall.EPIPE), want: true},
|
||||||
|
{name: "other error", err: errors.New("copy failed"), want: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
require.Equal(t, tt.want, IsConnectionClosedError(tt.err))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunContinuesAfterClosedConnectionError(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
listener := newTestListener()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
closedErrCh := make(chan error, 1)
|
||||||
|
unexpectedErrCh := make(chan error, 1)
|
||||||
|
var dialCount atomic.Int32
|
||||||
|
|
||||||
|
p := &Proxy{
|
||||||
|
Listener: listener,
|
||||||
|
RemoteAddr: "remote:80",
|
||||||
|
DialContext: func(context.Context, string, string) (net.Conn, error) {
|
||||||
|
if dialCount.Add(1) == 1 {
|
||||||
|
return readErrorConn{err: syscall.EPIPE}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyConn, upstreamConn := net.Pipe()
|
||||||
|
go func() {
|
||||||
|
defer upstreamConn.Close()
|
||||||
|
_, _ = upstreamConn.Write([]byte("ok"))
|
||||||
|
}()
|
||||||
|
return proxyConn, nil
|
||||||
|
},
|
||||||
|
OnError: func(err error) {
|
||||||
|
if IsConnectionClosedError(err) {
|
||||||
|
closedErrCh <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
unexpectedErrCh <- err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runErrCh := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
runErrCh <- p.Run(ctx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
firstConn := listener.connect()
|
||||||
|
defer firstConn.Close()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case connErr := <-closedErrCh:
|
||||||
|
require.ErrorIs(t, connErr, syscall.EPIPE)
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Fatal("timed out waiting for closed connection error")
|
||||||
|
}
|
||||||
|
|
||||||
|
secondConn := listener.connect()
|
||||||
|
defer secondConn.Close()
|
||||||
|
require.NoError(t, secondConn.SetReadDeadline(time.Now().Add(time.Second)))
|
||||||
|
|
||||||
|
got := make([]byte, 2)
|
||||||
|
_, err := io.ReadFull(secondConn, got)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "ok", string(got))
|
||||||
|
|
||||||
|
select {
|
||||||
|
case unexpectedErr := <-unexpectedErrCh:
|
||||||
|
t.Fatalf("unexpected connection error: %v", unexpectedErr)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
select {
|
||||||
|
case runErr := <-runErrCh:
|
||||||
|
require.NoError(t, runErr)
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Fatal("timed out waiting for proxy to stop")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunReturnsListenerError(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
listenerErr := errors.New("listener failed")
|
||||||
|
listener := errorListener{err: listenerErr}
|
||||||
|
|
||||||
|
p := &Proxy{Listener: listener}
|
||||||
|
err := p.Run(context.Background())
|
||||||
|
require.Error(t, err)
|
||||||
|
require.ErrorContains(t, err, "accept local connection")
|
||||||
|
require.ErrorIs(t, err, listenerErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type testListener struct {
|
||||||
|
conns chan net.Conn
|
||||||
|
closed chan struct{}
|
||||||
|
closeOnce sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestListener() *testListener {
|
||||||
|
return &testListener{
|
||||||
|
conns: make(chan net.Conn),
|
||||||
|
closed: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *testListener) connect() net.Conn {
|
||||||
|
clientConn, proxyConn := net.Pipe()
|
||||||
|
l.conns <- proxyConn
|
||||||
|
return clientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *testListener) Accept() (net.Conn, error) {
|
||||||
|
select {
|
||||||
|
case conn := <-l.conns:
|
||||||
|
return conn, nil
|
||||||
|
case <-l.closed:
|
||||||
|
return nil, net.ErrClosed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *testListener) Close() error {
|
||||||
|
l.closeOnce.Do(func() {
|
||||||
|
close(l.closed)
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *testListener) Addr() net.Addr {
|
||||||
|
return &net.TCPAddr{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorListener struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l errorListener) Accept() (net.Conn, error) { return nil, l.err }
|
||||||
|
func (errorListener) Close() error { return nil }
|
||||||
|
func (errorListener) Addr() net.Addr { return &net.TCPAddr{} }
|
||||||
|
|
||||||
|
// readErrorConn fails reads immediately so tests can deterministically exercise a proxy copy failure.
|
||||||
|
type readErrorConn struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c readErrorConn) Read([]byte) (int, error) { return 0, c.err }
|
||||||
|
func (readErrorConn) Write(p []byte) (int, error) { return len(p), nil }
|
||||||
|
func (readErrorConn) Close() error { return nil }
|
||||||
|
func (readErrorConn) LocalAddr() net.Addr { return &net.TCPAddr{} }
|
||||||
|
func (readErrorConn) RemoteAddr() net.Addr { return &net.TCPAddr{} }
|
||||||
|
func (readErrorConn) SetDeadline(time.Time) error { return nil }
|
||||||
|
func (readErrorConn) SetReadDeadline(time.Time) error { return nil }
|
||||||
|
func (readErrorConn) SetWriteDeadline(time.Time) error { return nil }
|
||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/machine"
|
"github.com/psviderski/uncloud/internal/machine"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/cluster"
|
"github.com/psviderski/uncloud/internal/machine/cluster"
|
||||||
"google.golang.org/protobuf/types/known/emptypb"
|
"google.golang.org/protobuf/types/known/emptypb"
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ Uncloud stores its configuration in `~/.config/uncloud/config.yaml`. If you wish
|
|||||||
|
|
||||||
Begin by initialising the first node in your cluster with `uc machine init [USER@HOST:PORT]`. If you do not have a need for Caddy reverse proxy, you may disable this feature with `--no-caddy`. If you want to avoid using uncloud's managed DNS service, add the `--no-dns` flag.
|
Begin by initialising the first node in your cluster with `uc machine init [USER@HOST:PORT]`. If you do not have a need for Caddy reverse proxy, you may disable this feature with `--no-caddy`. If you want to avoid using uncloud's managed DNS service, add the `--no-dns` flag.
|
||||||
|
|
||||||
This command will idempotently install Docker, uncloudd, uncloud-corrosion. If Caddy is enabled, it will set up a reverse proxy. If Uncloud DNS is enabled, it will create a DNS A record for the machine's public IP address under `*.[CLUSTER ID].uncld.dev`.
|
This command will idempotently install Docker and uncloudd. If Caddy is enabled, it will set up a reverse proxy. If Uncloud DNS is enabled, it will create a DNS A record for the machine's public IP address under `*.[CLUSTER ID].uncld.dev`.
|
||||||
|
|
||||||
If you wish to uninstall Uncloud and its components, run `uncloud-uninstall`.
|
If you wish to uninstall Uncloud and its components, run `uncloud-uninstall`.
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ run = "mise lock --platform linux-x64,macos-arm64"
|
|||||||
description = "Regenerate gRPC API code from .proto files"
|
description = "Regenerate gRPC API code from .proto files"
|
||||||
run = """
|
run = """
|
||||||
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative \
|
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative \
|
||||||
--proto_path=. --proto_path=internal/machine/api/vendor internal/machine/api/pb/*.proto
|
--proto_path=. --proto_path=api/pb/vendor api/pb/*.proto pkg/distlock/grpc/*.proto
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[tasks.uc]
|
[tasks.uc]
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/volume"
|
"github.com/docker/docker/api/types/volume"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client interface {
|
type Client interface {
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ import (
|
|||||||
"github.com/distribution/reference"
|
"github.com/distribution/reference"
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MachineImage struct {
|
type MachineImage struct {
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MachineFilter defines criteria to filter machines in ListMachines.
|
// MachineFilter defines criteria to filter machines in ListMachines.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|||||||
+6
-1
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/distribution/reference"
|
"github.com/distribution/reference"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -265,6 +265,11 @@ type ContainerSpec struct {
|
|||||||
LogDriver *LogDriver
|
LogDriver *LogDriver
|
||||||
// PidMode sets the PID namespace mode for the container. Currently only "" or "host" is supported.
|
// PidMode sets the PID namespace mode for the container. Currently only "" or "host" is supported.
|
||||||
PidMode string
|
PidMode string
|
||||||
|
// Tty allocates a pseudo-TTY and connects the container's standard streams to it.
|
||||||
|
// Standard output and standard error share one stream.
|
||||||
|
Tty bool
|
||||||
|
// OpenStdin allocates standard input and keeps it open.
|
||||||
|
OpenStdin bool
|
||||||
// Privileged gives extended privileges to the container. This is a security risk and should be used with caution.
|
// Privileged gives extended privileges to the container. This is a security risk and should be used with caution.
|
||||||
Privileged bool
|
Privileged bool
|
||||||
// PullPolicy determines when to pull the image from the registry or use the image already available in the cluster.
|
// PullPolicy determines when to pull the image from the registry or use the image already available in the cluster.
|
||||||
|
|||||||
+30
-6
@@ -7,9 +7,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/machine/docker"
|
"github.com/psviderski/uncloud/internal/machine/docker"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
|
distlockgrpc "github.com/psviderski/uncloud/pkg/distlock/grpc"
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
@@ -24,10 +25,12 @@ type Client struct {
|
|||||||
// Methods such as Reset or Inspect are ambiguous in the context of a machine+cluster client.
|
// Methods such as Reset or Inspect are ambiguous in the context of a machine+cluster client.
|
||||||
pb.MachineClient
|
pb.MachineClient
|
||||||
pb.ClusterClient
|
pb.ClusterClient
|
||||||
Caddy pb.CaddyClient
|
Caddy pb.CaddyClient
|
||||||
|
CaddyStorage pb.CaddyStorageClient
|
||||||
// Docker is a namespaced client for the Docker service to distinguish Uncloud-specific service container operations
|
// Docker is a namespaced client for the Docker service to distinguish Uncloud-specific service container operations
|
||||||
// from generic Docker operations.
|
// from generic Docker operations.
|
||||||
Docker *docker.Client
|
Docker *docker.Client
|
||||||
|
leases distlockgrpc.LeaseClient
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ api.Client = (*Client)(nil)
|
var _ api.Client = (*Client)(nil)
|
||||||
@@ -56,7 +59,9 @@ func New(ctx context.Context, connector Connector) (*Client, error) {
|
|||||||
c.MachineClient = pb.NewMachineClient(c.conn)
|
c.MachineClient = pb.NewMachineClient(c.conn)
|
||||||
c.ClusterClient = pb.NewClusterClient(c.conn)
|
c.ClusterClient = pb.NewClusterClient(c.conn)
|
||||||
c.Caddy = pb.NewCaddyClient(c.conn)
|
c.Caddy = pb.NewCaddyClient(c.conn)
|
||||||
|
c.CaddyStorage = pb.NewCaddyStorageClient(c.conn)
|
||||||
c.Docker = docker.NewClient(c.conn)
|
c.Docker = docker.NewClient(c.conn)
|
||||||
|
c.leases = distlockgrpc.NewLeaseClient(c.conn)
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
@@ -78,8 +83,8 @@ func (cli *Client) progressOut() *streams.Out {
|
|||||||
// ProxyMachinesContext returns a new context that proxies gRPC requests to the specified machines.
|
// ProxyMachinesContext returns a new context that proxies gRPC requests to the specified machines.
|
||||||
// If namesOrIDs is nil or empty, all machines are included.
|
// If namesOrIDs is nil or empty, all machines are included.
|
||||||
// This triggers One2Many proxying, which always injects metadata into the response.
|
// This triggers One2Many proxying, which always injects metadata into the response.
|
||||||
func (cli *Client) ProxyMachinesContext(ctx context.Context, namesOrIDs []string) context.Context {
|
func ProxyMachinesContext(ctx context.Context, namesOrIDs []string) context.Context {
|
||||||
md := metadata.New(nil)
|
md := outgoingMetadataWithoutProxyTargets(ctx)
|
||||||
if len(namesOrIDs) == 0 {
|
if len(namesOrIDs) == 0 {
|
||||||
md.Append("machines", "*")
|
md.Append("machines", "*")
|
||||||
} else {
|
} else {
|
||||||
@@ -92,7 +97,26 @@ func (cli *Client) ProxyMachinesContext(ctx context.Context, namesOrIDs []string
|
|||||||
// ProxySingleMachineContext returns a new context that proxies gRPC requests to a single specified machine.
|
// ProxySingleMachineContext returns a new context that proxies gRPC requests to a single specified machine.
|
||||||
// This triggers One2One proxying, which does NOT inject metadata into the response.
|
// This triggers One2One proxying, which does NOT inject metadata into the response.
|
||||||
// Use this for requests that expect a single response message without metadata wrapper.
|
// Use this for requests that expect a single response message without metadata wrapper.
|
||||||
func (cli *Client) ProxySingleMachineContext(ctx context.Context, nameOrID string) context.Context {
|
func ProxySingleMachineContext(ctx context.Context, nameOrID string) context.Context {
|
||||||
md := metadata.Pairs("machine", nameOrID)
|
md := outgoingMetadataWithoutProxyTargets(ctx)
|
||||||
|
md.Set("machine", nameOrID)
|
||||||
return metadata.NewOutgoingContext(ctx, md)
|
return metadata.NewOutgoingContext(ctx, md)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func outgoingMetadataWithoutProxyTargets(ctx context.Context) metadata.MD {
|
||||||
|
md, _ := metadata.FromOutgoingContext(ctx)
|
||||||
|
md = md.Copy()
|
||||||
|
md.Delete("machine")
|
||||||
|
md.Delete("machines")
|
||||||
|
return md
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProxyMachinesContext returns a new context that proxies gRPC requests to the specified machines.
|
||||||
|
func (cli *Client) ProxyMachinesContext(ctx context.Context, namesOrIDs []string) context.Context {
|
||||||
|
return ProxyMachinesContext(ctx, namesOrIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProxySingleMachineContext returns a new context that proxies gRPC requests to a single specified machine.
|
||||||
|
func (cli *Client) ProxySingleMachineContext(ctx context.Context, nameOrID string) context.Context {
|
||||||
|
return ProxySingleMachineContext(ctx, nameOrID)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProxySingleMachineContext(t *testing.T) {
|
||||||
|
original := metadata.Pairs(
|
||||||
|
"authorization", "token",
|
||||||
|
"machine", "old-machine",
|
||||||
|
"machines", "old-machine-a",
|
||||||
|
"machines", "old-machine-b",
|
||||||
|
)
|
||||||
|
ctx := metadata.NewOutgoingContext(context.Background(), original)
|
||||||
|
|
||||||
|
proxyCtx := ProxySingleMachineContext(ctx, "new-machine")
|
||||||
|
|
||||||
|
md, ok := metadata.FromOutgoingContext(proxyCtx)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, metadata.Pairs(
|
||||||
|
"authorization", "token",
|
||||||
|
"machine", "new-machine",
|
||||||
|
), md)
|
||||||
|
require.Equal(t, metadata.Pairs(
|
||||||
|
"authorization", "token",
|
||||||
|
"machine", "old-machine",
|
||||||
|
"machines", "old-machine-a",
|
||||||
|
"machines", "old-machine-b",
|
||||||
|
), original)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProxyMachinesContext(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
machines []string
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "specified machines",
|
||||||
|
machines: []string{"machine-a", "machine-b"},
|
||||||
|
want: []string{"machine-a", "machine-b"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all machines",
|
||||||
|
want: []string{"*"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
original := metadata.Pairs(
|
||||||
|
"authorization", "token",
|
||||||
|
"machine", "old-machine",
|
||||||
|
"machines", "old-machine-a",
|
||||||
|
"machines", "old-machine-b",
|
||||||
|
)
|
||||||
|
ctx := metadata.NewOutgoingContext(context.Background(), original)
|
||||||
|
|
||||||
|
proxyCtx := ProxyMachinesContext(ctx, tt.machines)
|
||||||
|
|
||||||
|
md, ok := metadata.FromOutgoingContext(proxyCtx)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, metadata.MD{
|
||||||
|
"authorization": {"token"},
|
||||||
|
"machines": tt.want,
|
||||||
|
}, md)
|
||||||
|
require.Equal(t, metadata.Pairs(
|
||||||
|
"authorization", "token",
|
||||||
|
"machine", "old-machine",
|
||||||
|
"machines", "old-machine-a",
|
||||||
|
"machines", "old-machine-b",
|
||||||
|
), original)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -322,6 +322,67 @@ volumes:
|
|||||||
`,
|
`,
|
||||||
shouldErr: true,
|
shouldErr: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "external configs",
|
||||||
|
composeYAML: `services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
configs:
|
||||||
|
http_config:
|
||||||
|
external: true
|
||||||
|
`,
|
||||||
|
warnCount: 1,
|
||||||
|
warnContains: []string{"external"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "container_name",
|
||||||
|
composeYAML: `services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
container_name: my_container
|
||||||
|
`,
|
||||||
|
warnCount: 1,
|
||||||
|
warnContains: []string{"container_name"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deploy labels",
|
||||||
|
composeYAML: `services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
deploy:
|
||||||
|
mode: replicated
|
||||||
|
labels:
|
||||||
|
- foo
|
||||||
|
replicas: 2
|
||||||
|
`,
|
||||||
|
warnCount: 1,
|
||||||
|
warnContains: []string{"deploy labels"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deploy restart_policy",
|
||||||
|
composeYAML: `services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
`,
|
||||||
|
warnCount: 1,
|
||||||
|
warnContains: []string{"deploy restart_policy"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deploy placement",
|
||||||
|
composeYAML: `services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
deploy:
|
||||||
|
placement:
|
||||||
|
preferences:
|
||||||
|
- spread: foo
|
||||||
|
`,
|
||||||
|
warnCount: 1,
|
||||||
|
warnContains: []string{"deploy placement"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ func ServiceSpecFromCompose(project *types.Project, serviceName string) (api.Ser
|
|||||||
Image: service.Image,
|
Image: service.Image,
|
||||||
Init: service.Init,
|
Init: service.Init,
|
||||||
PidMode: service.Pid,
|
PidMode: service.Pid,
|
||||||
|
Tty: service.Tty,
|
||||||
|
OpenStdin: service.StdinOpen,
|
||||||
Privileged: service.Privileged,
|
Privileged: service.Privileged,
|
||||||
PullPolicy: pullPolicy,
|
PullPolicy: pullPolicy,
|
||||||
Resources: resourcesFromCompose(service),
|
Resources: resourcesFromCompose(service),
|
||||||
@@ -452,13 +454,22 @@ func validateServicesExtensions(project *types.Project) error {
|
|||||||
|
|
||||||
// validateServicesFeatures checks services for unsupported features and returns all found.
|
// validateServicesFeatures checks services for unsupported features and returns all found.
|
||||||
func validateServicesFeatures(project *types.Project) []error {
|
func validateServicesFeatures(project *types.Project) []error {
|
||||||
err := func(service, feature string) error {
|
// XXX(miek): as of Sep 2026 these checks are in check with the support-matrix, except for a short syntax
|
||||||
return fmt.Errorf("service '%s': unsupported feature '%s', see %s",
|
// check.
|
||||||
service, feature, "https://uncloud.run/docs/compose-file-reference/support-matrix")
|
var errs []error
|
||||||
|
const supportmatrix = "https://uncloud.run/docs/compose-file-reference/support-matrix"
|
||||||
|
|
||||||
|
for _, config := range project.Configs {
|
||||||
|
if config.External {
|
||||||
|
errs = append(errs, fmt.Errorf("config '%s': unsupported feature '%s', see %s",
|
||||||
|
config.Name, "external", supportmatrix))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check other commonly used but unsupported features.
|
err := func(service, feature string) error {
|
||||||
var errs []error
|
return fmt.Errorf("service '%s': unsupported feature '%s', see %s",
|
||||||
|
service, feature, supportmatrix)
|
||||||
|
}
|
||||||
for _, service := range project.Services {
|
for _, service := range project.Services {
|
||||||
if service.SecurityOpt != nil {
|
if service.SecurityOpt != nil {
|
||||||
errs = append(errs, err(service.Name, "security_opt"))
|
errs = append(errs, err(service.Name, "security_opt"))
|
||||||
@@ -487,6 +498,29 @@ func validateServicesFeatures(project *types.Project) []error {
|
|||||||
if service.StorageOpt != nil {
|
if service.StorageOpt != nil {
|
||||||
errs = append(errs, err(service.Name, "storage_opt"))
|
errs = append(errs, err(service.Name, "storage_opt"))
|
||||||
}
|
}
|
||||||
|
if service.ContainerName != "" {
|
||||||
|
errs = append(errs, err(service.Name, "container_name"))
|
||||||
|
}
|
||||||
|
if service.Deploy != nil {
|
||||||
|
if len(service.Deploy.Placement.Constraints) > 0 || len(service.Deploy.Placement.Preferences) > 0 ||
|
||||||
|
service.Deploy.Placement.MaxReplicas > 0 {
|
||||||
|
errs = append(errs, fmt.Errorf(
|
||||||
|
"service '%s': deploy placement is not supported, "+
|
||||||
|
"use x-machines instead: %s", service.Name,
|
||||||
|
"https://uncloud.run/docs/compose-file-reference/extensions#x-machines"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if service.Deploy.RestartPolicy != nil {
|
||||||
|
errs = append(errs, fmt.Errorf(
|
||||||
|
"service '%s': deploy restart_policy defaults to 'unless-stopped'", service.Name))
|
||||||
|
}
|
||||||
|
if service.Deploy.RollbackConfig != nil {
|
||||||
|
errs = append(errs, err(service.Name, "deploy rollback_config"))
|
||||||
|
}
|
||||||
|
if len(service.Deploy.Labels) != 0 {
|
||||||
|
errs = append(errs, err(service.Name, "deploy labels"))
|
||||||
|
}
|
||||||
|
}
|
||||||
// we only allow the 'default' network, nothing else.
|
// we only allow the 'default' network, nothing else.
|
||||||
if x := service.Networks; x != nil {
|
if x := service.Networks; x != nil {
|
||||||
if len(x) != 1 {
|
if len(x) != 1 {
|
||||||
|
|||||||
@@ -128,6 +128,8 @@ func TestServiceSpecFromCompose(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
PidMode: "host",
|
PidMode: "host",
|
||||||
|
Tty: true,
|
||||||
|
OpenStdin: true,
|
||||||
Privileged: true,
|
Privileged: true,
|
||||||
PullPolicy: api.PullPolicyAlways,
|
PullPolicy: api.PullPolicyAlways,
|
||||||
Resources: api.ContainerResources{
|
Resources: api.ContainerResources{
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ services:
|
|||||||
command: ["nginx", "updated", "command"]
|
command: ["nginx", "updated", "command"]
|
||||||
cpus: 0.5
|
cpus: 0.5
|
||||||
pid: host
|
pid: host
|
||||||
|
tty: true
|
||||||
|
stdin_open: true
|
||||||
deploy:
|
deploy:
|
||||||
update_config:
|
update_config:
|
||||||
order: stop-first
|
order: stop-first
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
cliprogress "github.com/psviderski/uncloud/internal/cli/progress"
|
cliprogress "github.com/psviderski/uncloud/internal/cli/progress"
|
||||||
"github.com/psviderski/uncloud/internal/docker"
|
"github.com/psviderski/uncloud/internal/docker"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
|
||||||
machinedocker "github.com/psviderski/uncloud/internal/machine/docker"
|
machinedocker "github.com/psviderski/uncloud/internal/machine/docker"
|
||||||
"github.com/psviderski/uncloud/internal/secret"
|
"github.com/psviderski/uncloud/internal/secret"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
@@ -74,7 +74,7 @@ func (cli *Client) createServiceContainerWithPull(
|
|||||||
resp.Name = containerName
|
resp.Name = containerName
|
||||||
|
|
||||||
// Proxy Docker gRPC requests to the selected machine.
|
// Proxy Docker gRPC requests to the selected machine.
|
||||||
ctx = cli.ProxySingleMachineContext(ctx, machine.Machine.Id)
|
ctx = ProxySingleMachineContext(ctx, machine.Machine.Id)
|
||||||
|
|
||||||
pw := progress.ContextWriter(ctx)
|
pw := progress.ContextWriter(ctx)
|
||||||
eventID := cliprogress.NewContainerEventID(ctx, containerName, machine.Machine.Name)
|
eventID := cliprogress.NewContainerEventID(ctx, containerName, machine.Machine.Name)
|
||||||
@@ -277,7 +277,7 @@ func (cli *Client) resolveContainerOperation(
|
|||||||
|
|
||||||
eventID := cliprogress.ContainerEventID(ctx, ctr.Container.ServiceSpec.Name, ctr.Container.ID, ctr.MachineName)
|
eventID := cliprogress.ContainerEventID(ctx, ctr.Container.ServiceSpec.Name, ctr.Container.ID, ctr.MachineName)
|
||||||
return containerOperationContext{
|
return containerOperationContext{
|
||||||
ctx: cli.ProxySingleMachineContext(ctx, ctr.MachineID),
|
ctx: ProxySingleMachineContext(ctx, ctr.MachineID),
|
||||||
containerID: ctr.Container.ID,
|
containerID: ctr.Container.ID,
|
||||||
eventID: eventID,
|
eventID: eventID,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -375,7 +375,7 @@ func (cli *Client) ExecContainer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Proxy Docker gRPC requests to the machine hosting the container
|
// Proxy Docker gRPC requests to the machine hosting the container
|
||||||
ctx = cli.ProxySingleMachineContext(ctx, machine.Machine.Id)
|
ctx = ProxySingleMachineContext(ctx, machine.Machine.Id)
|
||||||
|
|
||||||
// Execute the command in the container
|
// Execute the command in the container
|
||||||
exitCode, err := cli.Docker.ExecContainer(ctx, machinedocker.ExecConfig{
|
exitCode, err := cli.Docker.ExecContainer(ctx, machinedocker.ExecConfig{
|
||||||
@@ -452,7 +452,7 @@ func (cli *Client) WaitContainerHealthy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For containers with a health check, wait until Docker reports healthy or unhealthy.
|
// For containers with a health check, wait until Docker reports healthy or unhealthy.
|
||||||
mctx := cli.ProxySingleMachineContext(ctx, machine.Machine.Id)
|
mctx := ProxySingleMachineContext(ctx, machine.Machine.Id)
|
||||||
mctx, cancel := context.WithTimeout(mctx, healthcheckTimeout(mc.Container.Config.Healthcheck))
|
mctx, cancel := context.WithTimeout(mctx, healthcheckTimeout(mc.Container.Config.Healthcheck))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ticker := time.NewTicker(1 * time.Second)
|
ticker := time.NewTicker(1 * time.Second)
|
||||||
|
|||||||
@@ -66,6 +66,26 @@ func TestEvalContainerSpecChange_ContainerPidMode(t *testing.T) {
|
|||||||
assert.Equal(t, ContainerNeedsRecreate, EvalContainerSpecChange(newSpec, currentSpec))
|
assert.Equal(t, ContainerNeedsRecreate, EvalContainerSpecChange(newSpec, currentSpec))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEvalContainerSpecChange_ContainerTty(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
currentSpec := api.ServiceSpec{
|
||||||
|
Container: api.ContainerSpec{
|
||||||
|
Image: "nginx:latest",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
newSpec := api.ServiceSpec{
|
||||||
|
Container: api.ContainerSpec{
|
||||||
|
Image: "nginx:latest",
|
||||||
|
Tty: true,
|
||||||
|
OpenStdin: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, ContainerNeedsRecreate, EvalContainerSpecChange(currentSpec, newSpec))
|
||||||
|
assert.Equal(t, ContainerNeedsRecreate, EvalContainerSpecChange(newSpec, currentSpec))
|
||||||
|
}
|
||||||
|
|
||||||
func TestEvalContainerSpecChange_ContainerResources(t *testing.T) {
|
func TestEvalContainerSpecChange_ContainerResources(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package scheduler
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/volume"
|
"github.com/docker/docker/api/types/volume"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/api/types/mount"
|
"github.com/docker/docker/api/types/mount"
|
||||||
"github.com/docker/docker/api/types/volume"
|
"github.com/docker/docker/api/types/volume"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user