rpyc-pve-cloud 0.1.7rc0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {rpyc_pve_cloud-0.1.7rc0/src/rpyc_pve_cloud.egg-info → rpyc_pve_cloud-0.2.0}/PKG-INFO +2 -2
  2. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/requirements.txt +1 -1
  3. rpyc_pve_cloud-0.2.0/src/pve_cloud_rpc/_version.py +1 -0
  4. rpyc_pve_cloud-0.2.0/src/pve_cloud_rpc/protos/cloud_pb2.py +115 -0
  5. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/src/pve_cloud_rpc/protos/cloud_pb2_grpc.py +344 -0
  6. rpyc_pve_cloud-0.2.0/src/pve_cloud_rpc/server.py +379 -0
  7. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0/src/rpyc_pve_cloud.egg-info}/PKG-INFO +2 -2
  8. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/src/rpyc_pve_cloud.egg-info/requires.txt +1 -1
  9. rpyc_pve_cloud-0.1.7rc0/src/pve_cloud_rpc/_version.py +0 -1
  10. rpyc_pve_cloud-0.1.7rc0/src/pve_cloud_rpc/protos/cloud_pb2.py +0 -75
  11. rpyc_pve_cloud-0.1.7rc0/src/pve_cloud_rpc/server.py +0 -188
  12. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/LICENSE.md +0 -0
  13. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/README.md +0 -0
  14. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/pyproject.toml +0 -0
  15. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/setup.cfg +0 -0
  16. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/src/pve_cloud_rpc/protos/health_pb2.py +0 -0
  17. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/src/pve_cloud_rpc/protos/health_pb2_grpc.py +0 -0
  18. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/src/rpyc_pve_cloud.egg-info/SOURCES.txt +0 -0
  19. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/src/rpyc_pve_cloud.egg-info/dependency_links.txt +0 -0
  20. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/src/rpyc_pve_cloud.egg-info/entry_points.txt +0 -0
  21. {rpyc_pve_cloud-0.1.7rc0 → rpyc_pve_cloud-0.2.0}/src/rpyc_pve_cloud.egg-info/top_level.txt +0 -0
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rpyc-pve-cloud
3
- Version: 0.1.7rc0
3
+ Version: 0.2.0
4
4
  Author-email: Tobias Huebner <tobias.huebner@vmzberlin.com>
5
5
  License-Expression: GPL-3.0-or-later
6
6
  License-File: LICENSE.md
7
- Requires-Dist: py-pve-cloud==0.14.6rc0
7
+ Requires-Dist: py-pve-cloud<0.16.0,>=0.15.0
8
8
  Requires-Dist: grpcio==1.76.0
9
9
  Requires-Dist: asyncssh==2.22.0
10
10
  Requires-Dist: protobuf==6.33.4
@@ -1,5 +1,5 @@
1
1
  # pessimistic operator for local tdd installs (pip install -e .)
2
- py-pve-cloud==0.14.6rc0
2
+ py-pve-cloud>=0.15.0,<0.16.0
3
3
  grpcio==1.76.0
4
4
  asyncssh==2.22.0
5
5
  protobuf==6.33.4
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0"
@@ -0,0 +1,115 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: cloud.proto
5
+ # Protobuf Python Version: 6.31.1
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 6,
15
+ 31,
16
+ 1,
17
+ '',
18
+ 'cloud.proto'
19
+ )
20
+ # @@protoc_insertion_point(imports)
21
+
22
+ _sym_db = _symbol_database.Default()
23
+
24
+
25
+
26
+
27
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0b\x63loud.proto\x12\x06protos\",\n\x16GetPveInventoryRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\"B\n\x17GetPveInventoryResponse\x12\x11\n\tinventory\x18\x01 \x01(\t\x12\x14\n\x0c\x63loud_domain\x18\x02 \x01(\t\"+\n\x15GetProxmoxHostRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\"*\n\x16GetProxmoxHostResponse\x12\x10\n\x08pve_host\x18\x01 \x01(\t\"\xa9\x01\n\x14GetProxmoxApiRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x10\n\x08\x61pi_path\x18\x02 \x01(\t\x12;\n\x08get_args\x18\x03 \x03(\x0b\x32).protos.GetProxmoxApiRequest.GetArgsEntry\x1a.\n\x0cGetArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"*\n\x15GetProxmoxApiResponse\x12\x11\n\tjson_resp\x18\x01 \x01(\t\"\xb8\x01\n\x17\x43reateProxmoxApiRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x10\n\x08\x61pi_path\x18\x02 \x01(\t\x12\x44\n\x0b\x63reate_args\x18\x03 \x03(\x0b\x32/.protos.CreateProxmoxApiRequest.CreateArgsEntry\x1a\x31\n\x0f\x43reateArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"@\n\x18\x43reateProxmoxApiResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x0b\x65rr_message\x18\x02 \x01(\t\"?\n\x17\x44\x65leteProxmoxApiRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x10\n\x08\x61pi_path\x18\x02 \x01(\t\"@\n\x18\x44\x65leteProxmoxApiResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x0b\x65rr_message\x18\x02 \x01(\t\"\x87\x01\n\x10GetSshKeyRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x32\n\x08key_type\x18\x02 \x01(\x0e\x32 .protos.GetSshKeyRequest.KeyType\"+\n\x07KeyType\x12\x0e\n\nAUTOMATION\x10\x00\x12\x10\n\x0cPVE_HOST_RSA\x10\x01\" \n\x11GetSshKeyResponse\x12\x0b\n\x03key\x18\x01 \x01(\t\"*\n\x14GetCephAccessRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\"A\n\x15GetCephAccessResponse\x12\x11\n\tceph_conf\x18\x01 \x01(\t\x12\x15\n\radmin_keyring\x18\x02 \x01(\t\">\n\x14GetKubeconfigRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x12\n\nstack_name\x18\x02 \x01(\t\"\'\n\x15GetKubeconfigResponse\x12\x0e\n\x06\x63onfig\x18\x01 \x01(\t\"+\n\x15GetClusterVarsRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\"&\n\x16GetClusterVarsResponse\x12\x0c\n\x04vars\x18\x01 \x01(\t\"T\n\x19GetCloudFileSecretRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x13\n\x0bsecret_name\x18\x02 \x01(\t\x12\x0e\n\x06rstrip\x18\x03 \x01(\x08\",\n\x1aGetCloudFileSecretResponse\x12\x0e\n\x06secret\x18\x01 \x01(\t\"\x83\x01\n\x18\x43reateCloudSecretRequest\x12\x14\n\x0c\x63loud_domain\x18\x01 \x01(\t\x12\x12\n\ntarget_pve\x18\x02 \x01(\t\x12\x13\n\x0bsecret_name\x18\x03 \x01(\t\x12\x13\n\x0bsecret_data\x18\x04 \x01(\t\x12\x13\n\x0bsecret_type\x18\x05 \x01(\t\"A\n\x19\x43reateCloudSecretResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x0b\x65rr_message\x18\x02 \x01(\t\"Y\n\x18\x44\x65leteCloudSecretRequest\x12\x14\n\x0c\x63loud_domain\x18\x01 \x01(\t\x12\x12\n\ntarget_pve\x18\x02 \x01(\t\x12\x13\n\x0bsecret_name\x18\x03 \x01(\t\"A\n\x19\x44\x65leteCloudSecretResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x0b\x65rr_message\x18\x02 \x01(\t\"V\n\x15GetCloudSecretRequest\x12\x14\n\x0c\x63loud_domain\x18\x01 \x01(\t\x12\x12\n\ntarget_pve\x18\x02 \x01(\t\x12\x13\n\x0bsecret_name\x18\x03 \x01(\t\"(\n\x16GetCloudSecretResponse\x12\x0e\n\x06secret\x18\x01 \x01(\t\"W\n\x16GetCloudSecretsRequest\x12\x14\n\x0c\x63loud_domain\x18\x01 \x01(\t\x12\x12\n\ntarget_pve\x18\x02 \x01(\t\x12\x13\n\x0bsecret_type\x18\x03 \x01(\t\"*\n\x17GetCloudSecretsResponse\x12\x0f\n\x07secrets\x18\x01 \x01(\t\"T\n\x15GetVmVarsBlakeRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x14\n\x0c\x63loud_domain\x18\x02 \x01(\t\x12\x11\n\tblake_ids\x18\x03 \x03(\t\"\x94\x01\n\x16GetVmVarsBlakeResponse\x12\x46\n\rblake_id_vars\x18\x01 \x03(\x0b\x32/.protos.GetVmVarsBlakeResponse.BlakeIdVarsEntry\x1a\x32\n\x10\x42lakeIdVarsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"+\n\x15GetCloudDomainRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\"(\n\x16GetCloudDomainResponse\x12\x0e\n\x06\x64omain\x18\x01 \x01(\t2\xbc\n\n\x0c\x43loudService\x12R\n\x13GetMasterKubeconfig\x12\x1c.protos.GetKubeconfigRequest\x1a\x1d.protos.GetKubeconfigResponse\x12O\n\x0eGetClusterVars\x12\x1d.protos.GetClusterVarsRequest\x1a\x1e.protos.GetClusterVarsResponse\x12[\n\x12GetCloudFileSecret\x12!.protos.GetCloudFileSecretRequest\x1a\".protos.GetCloudFileSecretResponse\x12X\n\x11\x43reateCloudSecret\x12 .protos.CreateCloudSecretRequest\x1a!.protos.CreateCloudSecretResponse\x12X\n\x11\x44\x65leteCloudSecret\x12 .protos.DeleteCloudSecretRequest\x1a!.protos.DeleteCloudSecretResponse\x12O\n\x0eGetCloudSecret\x12\x1d.protos.GetCloudSecretRequest\x1a\x1e.protos.GetCloudSecretResponse\x12R\n\x0fGetCloudSecrets\x12\x1e.protos.GetCloudSecretsRequest\x1a\x1f.protos.GetCloudSecretsResponse\x12L\n\rGetCephAccess\x12\x1c.protos.GetCephAccessRequest\x1a\x1d.protos.GetCephAccessResponse\x12@\n\tGetSshKey\x12\x18.protos.GetSshKeyRequest\x1a\x19.protos.GetSshKeyResponse\x12L\n\rGetProxmoxApi\x12\x1c.protos.GetProxmoxApiRequest\x1a\x1d.protos.GetProxmoxApiResponse\x12U\n\x10\x43reateProxmoxApi\x12\x1f.protos.CreateProxmoxApiRequest\x1a .protos.CreateProxmoxApiResponse\x12U\n\x10\x44\x65leteProxmoxApi\x12\x1f.protos.DeleteProxmoxApiRequest\x1a .protos.DeleteProxmoxApiResponse\x12O\n\x0eGetProxmoxHost\x12\x1d.protos.GetProxmoxHostRequest\x1a\x1e.protos.GetProxmoxHostResponse\x12R\n\x0fGetPveInventory\x12\x1e.protos.GetPveInventoryRequest\x1a\x1f.protos.GetPveInventoryResponse\x12O\n\x0eGetCloudDomain\x12\x1d.protos.GetCloudDomainRequest\x1a\x1e.protos.GetCloudDomainResponse\x12O\n\x0eGetVmVarsBlake\x12\x1d.protos.GetVmVarsBlakeRequest\x1a\x1e.protos.GetVmVarsBlakeResponseBQZOgithub.com/Proxmox-Cloud/terraform-provider-pxc/internal/provider/protos;protosb\x06proto3')
28
+
29
+ _globals = globals()
30
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cloud_pb2', _globals)
32
+ if not _descriptor._USE_C_DESCRIPTORS:
33
+ _globals['DESCRIPTOR']._loaded_options = None
34
+ _globals['DESCRIPTOR']._serialized_options = b'ZOgithub.com/Proxmox-Cloud/terraform-provider-pxc/internal/provider/protos;protos'
35
+ _globals['_GETPROXMOXAPIREQUEST_GETARGSENTRY']._loaded_options = None
36
+ _globals['_GETPROXMOXAPIREQUEST_GETARGSENTRY']._serialized_options = b'8\001'
37
+ _globals['_CREATEPROXMOXAPIREQUEST_CREATEARGSENTRY']._loaded_options = None
38
+ _globals['_CREATEPROXMOXAPIREQUEST_CREATEARGSENTRY']._serialized_options = b'8\001'
39
+ _globals['_GETVMVARSBLAKERESPONSE_BLAKEIDVARSENTRY']._loaded_options = None
40
+ _globals['_GETVMVARSBLAKERESPONSE_BLAKEIDVARSENTRY']._serialized_options = b'8\001'
41
+ _globals['_GETPVEINVENTORYREQUEST']._serialized_start=23
42
+ _globals['_GETPVEINVENTORYREQUEST']._serialized_end=67
43
+ _globals['_GETPVEINVENTORYRESPONSE']._serialized_start=69
44
+ _globals['_GETPVEINVENTORYRESPONSE']._serialized_end=135
45
+ _globals['_GETPROXMOXHOSTREQUEST']._serialized_start=137
46
+ _globals['_GETPROXMOXHOSTREQUEST']._serialized_end=180
47
+ _globals['_GETPROXMOXHOSTRESPONSE']._serialized_start=182
48
+ _globals['_GETPROXMOXHOSTRESPONSE']._serialized_end=224
49
+ _globals['_GETPROXMOXAPIREQUEST']._serialized_start=227
50
+ _globals['_GETPROXMOXAPIREQUEST']._serialized_end=396
51
+ _globals['_GETPROXMOXAPIREQUEST_GETARGSENTRY']._serialized_start=350
52
+ _globals['_GETPROXMOXAPIREQUEST_GETARGSENTRY']._serialized_end=396
53
+ _globals['_GETPROXMOXAPIRESPONSE']._serialized_start=398
54
+ _globals['_GETPROXMOXAPIRESPONSE']._serialized_end=440
55
+ _globals['_CREATEPROXMOXAPIREQUEST']._serialized_start=443
56
+ _globals['_CREATEPROXMOXAPIREQUEST']._serialized_end=627
57
+ _globals['_CREATEPROXMOXAPIREQUEST_CREATEARGSENTRY']._serialized_start=578
58
+ _globals['_CREATEPROXMOXAPIREQUEST_CREATEARGSENTRY']._serialized_end=627
59
+ _globals['_CREATEPROXMOXAPIRESPONSE']._serialized_start=629
60
+ _globals['_CREATEPROXMOXAPIRESPONSE']._serialized_end=693
61
+ _globals['_DELETEPROXMOXAPIREQUEST']._serialized_start=695
62
+ _globals['_DELETEPROXMOXAPIREQUEST']._serialized_end=758
63
+ _globals['_DELETEPROXMOXAPIRESPONSE']._serialized_start=760
64
+ _globals['_DELETEPROXMOXAPIRESPONSE']._serialized_end=824
65
+ _globals['_GETSSHKEYREQUEST']._serialized_start=827
66
+ _globals['_GETSSHKEYREQUEST']._serialized_end=962
67
+ _globals['_GETSSHKEYREQUEST_KEYTYPE']._serialized_start=919
68
+ _globals['_GETSSHKEYREQUEST_KEYTYPE']._serialized_end=962
69
+ _globals['_GETSSHKEYRESPONSE']._serialized_start=964
70
+ _globals['_GETSSHKEYRESPONSE']._serialized_end=996
71
+ _globals['_GETCEPHACCESSREQUEST']._serialized_start=998
72
+ _globals['_GETCEPHACCESSREQUEST']._serialized_end=1040
73
+ _globals['_GETCEPHACCESSRESPONSE']._serialized_start=1042
74
+ _globals['_GETCEPHACCESSRESPONSE']._serialized_end=1107
75
+ _globals['_GETKUBECONFIGREQUEST']._serialized_start=1109
76
+ _globals['_GETKUBECONFIGREQUEST']._serialized_end=1171
77
+ _globals['_GETKUBECONFIGRESPONSE']._serialized_start=1173
78
+ _globals['_GETKUBECONFIGRESPONSE']._serialized_end=1212
79
+ _globals['_GETCLUSTERVARSREQUEST']._serialized_start=1214
80
+ _globals['_GETCLUSTERVARSREQUEST']._serialized_end=1257
81
+ _globals['_GETCLUSTERVARSRESPONSE']._serialized_start=1259
82
+ _globals['_GETCLUSTERVARSRESPONSE']._serialized_end=1297
83
+ _globals['_GETCLOUDFILESECRETREQUEST']._serialized_start=1299
84
+ _globals['_GETCLOUDFILESECRETREQUEST']._serialized_end=1383
85
+ _globals['_GETCLOUDFILESECRETRESPONSE']._serialized_start=1385
86
+ _globals['_GETCLOUDFILESECRETRESPONSE']._serialized_end=1429
87
+ _globals['_CREATECLOUDSECRETREQUEST']._serialized_start=1432
88
+ _globals['_CREATECLOUDSECRETREQUEST']._serialized_end=1563
89
+ _globals['_CREATECLOUDSECRETRESPONSE']._serialized_start=1565
90
+ _globals['_CREATECLOUDSECRETRESPONSE']._serialized_end=1630
91
+ _globals['_DELETECLOUDSECRETREQUEST']._serialized_start=1632
92
+ _globals['_DELETECLOUDSECRETREQUEST']._serialized_end=1721
93
+ _globals['_DELETECLOUDSECRETRESPONSE']._serialized_start=1723
94
+ _globals['_DELETECLOUDSECRETRESPONSE']._serialized_end=1788
95
+ _globals['_GETCLOUDSECRETREQUEST']._serialized_start=1790
96
+ _globals['_GETCLOUDSECRETREQUEST']._serialized_end=1876
97
+ _globals['_GETCLOUDSECRETRESPONSE']._serialized_start=1878
98
+ _globals['_GETCLOUDSECRETRESPONSE']._serialized_end=1918
99
+ _globals['_GETCLOUDSECRETSREQUEST']._serialized_start=1920
100
+ _globals['_GETCLOUDSECRETSREQUEST']._serialized_end=2007
101
+ _globals['_GETCLOUDSECRETSRESPONSE']._serialized_start=2009
102
+ _globals['_GETCLOUDSECRETSRESPONSE']._serialized_end=2051
103
+ _globals['_GETVMVARSBLAKEREQUEST']._serialized_start=2053
104
+ _globals['_GETVMVARSBLAKEREQUEST']._serialized_end=2137
105
+ _globals['_GETVMVARSBLAKERESPONSE']._serialized_start=2140
106
+ _globals['_GETVMVARSBLAKERESPONSE']._serialized_end=2288
107
+ _globals['_GETVMVARSBLAKERESPONSE_BLAKEIDVARSENTRY']._serialized_start=2238
108
+ _globals['_GETVMVARSBLAKERESPONSE_BLAKEIDVARSENTRY']._serialized_end=2288
109
+ _globals['_GETCLOUDDOMAINREQUEST']._serialized_start=2290
110
+ _globals['_GETCLOUDDOMAINREQUEST']._serialized_end=2333
111
+ _globals['_GETCLOUDDOMAINRESPONSE']._serialized_start=2335
112
+ _globals['_GETCLOUDDOMAINRESPONSE']._serialized_end=2375
113
+ _globals['_CLOUDSERVICE']._serialized_start=2378
114
+ _globals['_CLOUDSERVICE']._serialized_end=3718
115
+ # @@protoc_insertion_point(module_scope)
@@ -44,11 +44,31 @@ class CloudServiceStub(object):
44
44
  request_serializer=cloud__pb2.GetClusterVarsRequest.SerializeToString,
45
45
  response_deserializer=cloud__pb2.GetClusterVarsResponse.FromString,
46
46
  _registered_method=True)
47
+ self.GetCloudFileSecret = channel.unary_unary(
48
+ '/protos.CloudService/GetCloudFileSecret',
49
+ request_serializer=cloud__pb2.GetCloudFileSecretRequest.SerializeToString,
50
+ response_deserializer=cloud__pb2.GetCloudFileSecretResponse.FromString,
51
+ _registered_method=True)
52
+ self.CreateCloudSecret = channel.unary_unary(
53
+ '/protos.CloudService/CreateCloudSecret',
54
+ request_serializer=cloud__pb2.CreateCloudSecretRequest.SerializeToString,
55
+ response_deserializer=cloud__pb2.CreateCloudSecretResponse.FromString,
56
+ _registered_method=True)
57
+ self.DeleteCloudSecret = channel.unary_unary(
58
+ '/protos.CloudService/DeleteCloudSecret',
59
+ request_serializer=cloud__pb2.DeleteCloudSecretRequest.SerializeToString,
60
+ response_deserializer=cloud__pb2.DeleteCloudSecretResponse.FromString,
61
+ _registered_method=True)
47
62
  self.GetCloudSecret = channel.unary_unary(
48
63
  '/protos.CloudService/GetCloudSecret',
49
64
  request_serializer=cloud__pb2.GetCloudSecretRequest.SerializeToString,
50
65
  response_deserializer=cloud__pb2.GetCloudSecretResponse.FromString,
51
66
  _registered_method=True)
67
+ self.GetCloudSecrets = channel.unary_unary(
68
+ '/protos.CloudService/GetCloudSecrets',
69
+ request_serializer=cloud__pb2.GetCloudSecretsRequest.SerializeToString,
70
+ response_deserializer=cloud__pb2.GetCloudSecretsResponse.FromString,
71
+ _registered_method=True)
52
72
  self.GetCephAccess = channel.unary_unary(
53
73
  '/protos.CloudService/GetCephAccess',
54
74
  request_serializer=cloud__pb2.GetCephAccessRequest.SerializeToString,
@@ -64,6 +84,16 @@ class CloudServiceStub(object):
64
84
  request_serializer=cloud__pb2.GetProxmoxApiRequest.SerializeToString,
65
85
  response_deserializer=cloud__pb2.GetProxmoxApiResponse.FromString,
66
86
  _registered_method=True)
87
+ self.CreateProxmoxApi = channel.unary_unary(
88
+ '/protos.CloudService/CreateProxmoxApi',
89
+ request_serializer=cloud__pb2.CreateProxmoxApiRequest.SerializeToString,
90
+ response_deserializer=cloud__pb2.CreateProxmoxApiResponse.FromString,
91
+ _registered_method=True)
92
+ self.DeleteProxmoxApi = channel.unary_unary(
93
+ '/protos.CloudService/DeleteProxmoxApi',
94
+ request_serializer=cloud__pb2.DeleteProxmoxApiRequest.SerializeToString,
95
+ response_deserializer=cloud__pb2.DeleteProxmoxApiResponse.FromString,
96
+ _registered_method=True)
67
97
  self.GetProxmoxHost = channel.unary_unary(
68
98
  '/protos.CloudService/GetProxmoxHost',
69
99
  request_serializer=cloud__pb2.GetProxmoxHostRequest.SerializeToString,
@@ -74,6 +104,16 @@ class CloudServiceStub(object):
74
104
  request_serializer=cloud__pb2.GetPveInventoryRequest.SerializeToString,
75
105
  response_deserializer=cloud__pb2.GetPveInventoryResponse.FromString,
76
106
  _registered_method=True)
107
+ self.GetCloudDomain = channel.unary_unary(
108
+ '/protos.CloudService/GetCloudDomain',
109
+ request_serializer=cloud__pb2.GetCloudDomainRequest.SerializeToString,
110
+ response_deserializer=cloud__pb2.GetCloudDomainResponse.FromString,
111
+ _registered_method=True)
112
+ self.GetVmVarsBlake = channel.unary_unary(
113
+ '/protos.CloudService/GetVmVarsBlake',
114
+ request_serializer=cloud__pb2.GetVmVarsBlakeRequest.SerializeToString,
115
+ response_deserializer=cloud__pb2.GetVmVarsBlakeResponse.FromString,
116
+ _registered_method=True)
77
117
 
78
118
 
79
119
  class CloudServiceServicer(object):
@@ -91,12 +131,36 @@ class CloudServiceServicer(object):
91
131
  context.set_details('Method not implemented!')
92
132
  raise NotImplementedError('Method not implemented!')
93
133
 
134
+ def GetCloudFileSecret(self, request, context):
135
+ """Missing associated documentation comment in .proto file."""
136
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
137
+ context.set_details('Method not implemented!')
138
+ raise NotImplementedError('Method not implemented!')
139
+
140
+ def CreateCloudSecret(self, request, context):
141
+ """Missing associated documentation comment in .proto file."""
142
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
143
+ context.set_details('Method not implemented!')
144
+ raise NotImplementedError('Method not implemented!')
145
+
146
+ def DeleteCloudSecret(self, request, context):
147
+ """Missing associated documentation comment in .proto file."""
148
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
149
+ context.set_details('Method not implemented!')
150
+ raise NotImplementedError('Method not implemented!')
151
+
94
152
  def GetCloudSecret(self, request, context):
95
153
  """Missing associated documentation comment in .proto file."""
96
154
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
97
155
  context.set_details('Method not implemented!')
98
156
  raise NotImplementedError('Method not implemented!')
99
157
 
158
+ def GetCloudSecrets(self, request, context):
159
+ """Missing associated documentation comment in .proto file."""
160
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
161
+ context.set_details('Method not implemented!')
162
+ raise NotImplementedError('Method not implemented!')
163
+
100
164
  def GetCephAccess(self, request, context):
101
165
  """Missing associated documentation comment in .proto file."""
102
166
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -115,6 +179,18 @@ class CloudServiceServicer(object):
115
179
  context.set_details('Method not implemented!')
116
180
  raise NotImplementedError('Method not implemented!')
117
181
 
182
+ def CreateProxmoxApi(self, request, context):
183
+ """Missing associated documentation comment in .proto file."""
184
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
185
+ context.set_details('Method not implemented!')
186
+ raise NotImplementedError('Method not implemented!')
187
+
188
+ def DeleteProxmoxApi(self, request, context):
189
+ """Missing associated documentation comment in .proto file."""
190
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
191
+ context.set_details('Method not implemented!')
192
+ raise NotImplementedError('Method not implemented!')
193
+
118
194
  def GetProxmoxHost(self, request, context):
119
195
  """Missing associated documentation comment in .proto file."""
120
196
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -127,6 +203,18 @@ class CloudServiceServicer(object):
127
203
  context.set_details('Method not implemented!')
128
204
  raise NotImplementedError('Method not implemented!')
129
205
 
206
+ def GetCloudDomain(self, request, context):
207
+ """Missing associated documentation comment in .proto file."""
208
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
209
+ context.set_details('Method not implemented!')
210
+ raise NotImplementedError('Method not implemented!')
211
+
212
+ def GetVmVarsBlake(self, request, context):
213
+ """Missing associated documentation comment in .proto file."""
214
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
215
+ context.set_details('Method not implemented!')
216
+ raise NotImplementedError('Method not implemented!')
217
+
130
218
 
131
219
  def add_CloudServiceServicer_to_server(servicer, server):
132
220
  rpc_method_handlers = {
@@ -140,11 +228,31 @@ def add_CloudServiceServicer_to_server(servicer, server):
140
228
  request_deserializer=cloud__pb2.GetClusterVarsRequest.FromString,
141
229
  response_serializer=cloud__pb2.GetClusterVarsResponse.SerializeToString,
142
230
  ),
231
+ 'GetCloudFileSecret': grpc.unary_unary_rpc_method_handler(
232
+ servicer.GetCloudFileSecret,
233
+ request_deserializer=cloud__pb2.GetCloudFileSecretRequest.FromString,
234
+ response_serializer=cloud__pb2.GetCloudFileSecretResponse.SerializeToString,
235
+ ),
236
+ 'CreateCloudSecret': grpc.unary_unary_rpc_method_handler(
237
+ servicer.CreateCloudSecret,
238
+ request_deserializer=cloud__pb2.CreateCloudSecretRequest.FromString,
239
+ response_serializer=cloud__pb2.CreateCloudSecretResponse.SerializeToString,
240
+ ),
241
+ 'DeleteCloudSecret': grpc.unary_unary_rpc_method_handler(
242
+ servicer.DeleteCloudSecret,
243
+ request_deserializer=cloud__pb2.DeleteCloudSecretRequest.FromString,
244
+ response_serializer=cloud__pb2.DeleteCloudSecretResponse.SerializeToString,
245
+ ),
143
246
  'GetCloudSecret': grpc.unary_unary_rpc_method_handler(
144
247
  servicer.GetCloudSecret,
145
248
  request_deserializer=cloud__pb2.GetCloudSecretRequest.FromString,
146
249
  response_serializer=cloud__pb2.GetCloudSecretResponse.SerializeToString,
147
250
  ),
251
+ 'GetCloudSecrets': grpc.unary_unary_rpc_method_handler(
252
+ servicer.GetCloudSecrets,
253
+ request_deserializer=cloud__pb2.GetCloudSecretsRequest.FromString,
254
+ response_serializer=cloud__pb2.GetCloudSecretsResponse.SerializeToString,
255
+ ),
148
256
  'GetCephAccess': grpc.unary_unary_rpc_method_handler(
149
257
  servicer.GetCephAccess,
150
258
  request_deserializer=cloud__pb2.GetCephAccessRequest.FromString,
@@ -160,6 +268,16 @@ def add_CloudServiceServicer_to_server(servicer, server):
160
268
  request_deserializer=cloud__pb2.GetProxmoxApiRequest.FromString,
161
269
  response_serializer=cloud__pb2.GetProxmoxApiResponse.SerializeToString,
162
270
  ),
271
+ 'CreateProxmoxApi': grpc.unary_unary_rpc_method_handler(
272
+ servicer.CreateProxmoxApi,
273
+ request_deserializer=cloud__pb2.CreateProxmoxApiRequest.FromString,
274
+ response_serializer=cloud__pb2.CreateProxmoxApiResponse.SerializeToString,
275
+ ),
276
+ 'DeleteProxmoxApi': grpc.unary_unary_rpc_method_handler(
277
+ servicer.DeleteProxmoxApi,
278
+ request_deserializer=cloud__pb2.DeleteProxmoxApiRequest.FromString,
279
+ response_serializer=cloud__pb2.DeleteProxmoxApiResponse.SerializeToString,
280
+ ),
163
281
  'GetProxmoxHost': grpc.unary_unary_rpc_method_handler(
164
282
  servicer.GetProxmoxHost,
165
283
  request_deserializer=cloud__pb2.GetProxmoxHostRequest.FromString,
@@ -170,6 +288,16 @@ def add_CloudServiceServicer_to_server(servicer, server):
170
288
  request_deserializer=cloud__pb2.GetPveInventoryRequest.FromString,
171
289
  response_serializer=cloud__pb2.GetPveInventoryResponse.SerializeToString,
172
290
  ),
291
+ 'GetCloudDomain': grpc.unary_unary_rpc_method_handler(
292
+ servicer.GetCloudDomain,
293
+ request_deserializer=cloud__pb2.GetCloudDomainRequest.FromString,
294
+ response_serializer=cloud__pb2.GetCloudDomainResponse.SerializeToString,
295
+ ),
296
+ 'GetVmVarsBlake': grpc.unary_unary_rpc_method_handler(
297
+ servicer.GetVmVarsBlake,
298
+ request_deserializer=cloud__pb2.GetVmVarsBlakeRequest.FromString,
299
+ response_serializer=cloud__pb2.GetVmVarsBlakeResponse.SerializeToString,
300
+ ),
173
301
  }
174
302
  generic_handler = grpc.method_handlers_generic_handler(
175
303
  'protos.CloudService', rpc_method_handlers)
@@ -235,6 +363,87 @@ class CloudService(object):
235
363
  metadata,
236
364
  _registered_method=True)
237
365
 
366
+ @staticmethod
367
+ def GetCloudFileSecret(request,
368
+ target,
369
+ options=(),
370
+ channel_credentials=None,
371
+ call_credentials=None,
372
+ insecure=False,
373
+ compression=None,
374
+ wait_for_ready=None,
375
+ timeout=None,
376
+ metadata=None):
377
+ return grpc.experimental.unary_unary(
378
+ request,
379
+ target,
380
+ '/protos.CloudService/GetCloudFileSecret',
381
+ cloud__pb2.GetCloudFileSecretRequest.SerializeToString,
382
+ cloud__pb2.GetCloudFileSecretResponse.FromString,
383
+ options,
384
+ channel_credentials,
385
+ insecure,
386
+ call_credentials,
387
+ compression,
388
+ wait_for_ready,
389
+ timeout,
390
+ metadata,
391
+ _registered_method=True)
392
+
393
+ @staticmethod
394
+ def CreateCloudSecret(request,
395
+ target,
396
+ options=(),
397
+ channel_credentials=None,
398
+ call_credentials=None,
399
+ insecure=False,
400
+ compression=None,
401
+ wait_for_ready=None,
402
+ timeout=None,
403
+ metadata=None):
404
+ return grpc.experimental.unary_unary(
405
+ request,
406
+ target,
407
+ '/protos.CloudService/CreateCloudSecret',
408
+ cloud__pb2.CreateCloudSecretRequest.SerializeToString,
409
+ cloud__pb2.CreateCloudSecretResponse.FromString,
410
+ options,
411
+ channel_credentials,
412
+ insecure,
413
+ call_credentials,
414
+ compression,
415
+ wait_for_ready,
416
+ timeout,
417
+ metadata,
418
+ _registered_method=True)
419
+
420
+ @staticmethod
421
+ def DeleteCloudSecret(request,
422
+ target,
423
+ options=(),
424
+ channel_credentials=None,
425
+ call_credentials=None,
426
+ insecure=False,
427
+ compression=None,
428
+ wait_for_ready=None,
429
+ timeout=None,
430
+ metadata=None):
431
+ return grpc.experimental.unary_unary(
432
+ request,
433
+ target,
434
+ '/protos.CloudService/DeleteCloudSecret',
435
+ cloud__pb2.DeleteCloudSecretRequest.SerializeToString,
436
+ cloud__pb2.DeleteCloudSecretResponse.FromString,
437
+ options,
438
+ channel_credentials,
439
+ insecure,
440
+ call_credentials,
441
+ compression,
442
+ wait_for_ready,
443
+ timeout,
444
+ metadata,
445
+ _registered_method=True)
446
+
238
447
  @staticmethod
239
448
  def GetCloudSecret(request,
240
449
  target,
@@ -262,6 +471,33 @@ class CloudService(object):
262
471
  metadata,
263
472
  _registered_method=True)
264
473
 
474
+ @staticmethod
475
+ def GetCloudSecrets(request,
476
+ target,
477
+ options=(),
478
+ channel_credentials=None,
479
+ call_credentials=None,
480
+ insecure=False,
481
+ compression=None,
482
+ wait_for_ready=None,
483
+ timeout=None,
484
+ metadata=None):
485
+ return grpc.experimental.unary_unary(
486
+ request,
487
+ target,
488
+ '/protos.CloudService/GetCloudSecrets',
489
+ cloud__pb2.GetCloudSecretsRequest.SerializeToString,
490
+ cloud__pb2.GetCloudSecretsResponse.FromString,
491
+ options,
492
+ channel_credentials,
493
+ insecure,
494
+ call_credentials,
495
+ compression,
496
+ wait_for_ready,
497
+ timeout,
498
+ metadata,
499
+ _registered_method=True)
500
+
265
501
  @staticmethod
266
502
  def GetCephAccess(request,
267
503
  target,
@@ -343,6 +579,60 @@ class CloudService(object):
343
579
  metadata,
344
580
  _registered_method=True)
345
581
 
582
+ @staticmethod
583
+ def CreateProxmoxApi(request,
584
+ target,
585
+ options=(),
586
+ channel_credentials=None,
587
+ call_credentials=None,
588
+ insecure=False,
589
+ compression=None,
590
+ wait_for_ready=None,
591
+ timeout=None,
592
+ metadata=None):
593
+ return grpc.experimental.unary_unary(
594
+ request,
595
+ target,
596
+ '/protos.CloudService/CreateProxmoxApi',
597
+ cloud__pb2.CreateProxmoxApiRequest.SerializeToString,
598
+ cloud__pb2.CreateProxmoxApiResponse.FromString,
599
+ options,
600
+ channel_credentials,
601
+ insecure,
602
+ call_credentials,
603
+ compression,
604
+ wait_for_ready,
605
+ timeout,
606
+ metadata,
607
+ _registered_method=True)
608
+
609
+ @staticmethod
610
+ def DeleteProxmoxApi(request,
611
+ target,
612
+ options=(),
613
+ channel_credentials=None,
614
+ call_credentials=None,
615
+ insecure=False,
616
+ compression=None,
617
+ wait_for_ready=None,
618
+ timeout=None,
619
+ metadata=None):
620
+ return grpc.experimental.unary_unary(
621
+ request,
622
+ target,
623
+ '/protos.CloudService/DeleteProxmoxApi',
624
+ cloud__pb2.DeleteProxmoxApiRequest.SerializeToString,
625
+ cloud__pb2.DeleteProxmoxApiResponse.FromString,
626
+ options,
627
+ channel_credentials,
628
+ insecure,
629
+ call_credentials,
630
+ compression,
631
+ wait_for_ready,
632
+ timeout,
633
+ metadata,
634
+ _registered_method=True)
635
+
346
636
  @staticmethod
347
637
  def GetProxmoxHost(request,
348
638
  target,
@@ -396,3 +686,57 @@ class CloudService(object):
396
686
  timeout,
397
687
  metadata,
398
688
  _registered_method=True)
689
+
690
+ @staticmethod
691
+ def GetCloudDomain(request,
692
+ target,
693
+ options=(),
694
+ channel_credentials=None,
695
+ call_credentials=None,
696
+ insecure=False,
697
+ compression=None,
698
+ wait_for_ready=None,
699
+ timeout=None,
700
+ metadata=None):
701
+ return grpc.experimental.unary_unary(
702
+ request,
703
+ target,
704
+ '/protos.CloudService/GetCloudDomain',
705
+ cloud__pb2.GetCloudDomainRequest.SerializeToString,
706
+ cloud__pb2.GetCloudDomainResponse.FromString,
707
+ options,
708
+ channel_credentials,
709
+ insecure,
710
+ call_credentials,
711
+ compression,
712
+ wait_for_ready,
713
+ timeout,
714
+ metadata,
715
+ _registered_method=True)
716
+
717
+ @staticmethod
718
+ def GetVmVarsBlake(request,
719
+ target,
720
+ options=(),
721
+ channel_credentials=None,
722
+ call_credentials=None,
723
+ insecure=False,
724
+ compression=None,
725
+ wait_for_ready=None,
726
+ timeout=None,
727
+ metadata=None):
728
+ return grpc.experimental.unary_unary(
729
+ request,
730
+ target,
731
+ '/protos.CloudService/GetVmVarsBlake',
732
+ cloud__pb2.GetVmVarsBlakeRequest.SerializeToString,
733
+ cloud__pb2.GetVmVarsBlakeResponse.FromString,
734
+ options,
735
+ channel_credentials,
736
+ insecure,
737
+ call_credentials,
738
+ compression,
739
+ wait_for_ready,
740
+ timeout,
741
+ metadata,
742
+ _registered_method=True)
@@ -0,0 +1,379 @@
1
+ import asyncio
2
+ import json
3
+ import socket
4
+ import sys
5
+
6
+ import asyncssh
7
+ import grpc
8
+ import yaml
9
+ from pve_cloud.cli.pvclu import get_cluster_vars, get_ssh_master_kubeconfig
10
+ from pve_cloud.lib.inventory import *
11
+ from pve_cloud.orm.alchemy import ProxmoxCloudSecrets, VirtualMachineVars
12
+ from sqlalchemy import create_engine, delete, select
13
+ from sqlalchemy.exc import IntegrityError
14
+ from sqlalchemy.orm import Session
15
+
16
+ import pve_cloud_rpc.protos.cloud_pb2 as cloud_pb2
17
+ import pve_cloud_rpc.protos.cloud_pb2_grpc as cloud_pb2_grpc
18
+ import pve_cloud_rpc.protos.health_pb2 as health_pb2
19
+ import pve_cloud_rpc.protos.health_pb2_grpc as health_pb2_grpc
20
+
21
+
22
+ class HealthServicer(health_pb2_grpc.HealthServicer):
23
+
24
+ # this also performs the py-pve-cloud version check to not run against incompatible
25
+ # installed proxmox cloud versions
26
+ async def Check(self, request, context):
27
+ target_pve = request.target_pve
28
+ try:
29
+ get_online_pve_host(
30
+ target_pve, skip_py_cloud_check=False
31
+ ) # actually perform the check
32
+ return health_pb2.HealthCheckResponse(
33
+ status=health_pb2.HealthCheckResponse.SERVING
34
+ )
35
+ except RuntimeError as e:
36
+ return health_pb2.HealthCheckResponse(
37
+ status=health_pb2.HealthCheckResponse.MISSMATCH,
38
+ error_message=f"py-pve-cloud version check failed with: {e}",
39
+ ) # go provider process will kill
40
+
41
+
42
+ async def get_engine(online_pve_host):
43
+ async with asyncssh.connect(
44
+ online_pve_host, username="root", known_hosts=None
45
+ ) as conn:
46
+ cmd = await conn.run("cat /etc/pve/cloud/secrets/patroni.pass", check=True)
47
+ patroni_pass = cmd.stdout.rstrip()
48
+
49
+ # fetch cluster vars to get internal proxy ip
50
+ cmd = await conn.run("cat /etc/pve/cloud/cluster_vars.yaml", check=True)
51
+ cluster_vars = yaml.safe_load(cmd.stdout)
52
+
53
+ # build the connection string
54
+ patroni_cstr = f"postgresql+psycopg2://postgres:{patroni_pass}@{cluster_vars['pve_haproxy_floating_ip_internal']}:5000/pve_cloud?sslmode=disable"
55
+
56
+ # insert the secret
57
+ engine = create_engine(patroni_cstr)
58
+
59
+ return engine
60
+
61
+
62
+ class CloudServiceServicer(cloud_pb2_grpc.CloudServiceServicer):
63
+
64
+ async def GetMasterKubeconfig(self, request, context):
65
+ target_pve = request.target_pve
66
+ stack_name = request.stack_name
67
+
68
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
69
+ cluster_vars = get_cluster_vars(online_pve_host)
70
+
71
+ return cloud_pb2.GetKubeconfigResponse(
72
+ config=get_ssh_master_kubeconfig(cluster_vars, stack_name)
73
+ )
74
+
75
+ async def GetClusterVars(self, request, context):
76
+ target_pve = request.target_pve
77
+
78
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
79
+ cluster_vars = get_cluster_vars(online_pve_host)
80
+
81
+ return cloud_pb2.GetClusterVarsResponse(vars=yaml.safe_dump(cluster_vars))
82
+
83
+ # file secrets are default secrets created by the collections playbook stored on the proxmox hosts
84
+ # under /etc/pve/cloud/secrets
85
+ async def GetCloudFileSecret(self, request, context):
86
+ target_pve = request.target_pve
87
+ secret_name = request.secret_name
88
+
89
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
90
+ async with asyncssh.connect(
91
+ online_pve_host, username="root", known_hosts=None
92
+ ) as conn:
93
+ cmd = await conn.run(
94
+ f"cat /etc/pve/cloud/secrets/{secret_name}", check=True
95
+ )
96
+ catted_secret = cmd.stdout
97
+
98
+ if (
99
+ request.rstrip
100
+ ): # defaults to true but in special cases user might want to keep newlines (e.g. certs)
101
+ catted_secret = catted_secret.rstrip()
102
+
103
+ return cloud_pb2.GetCloudFileSecretResponse(secret=catted_secret)
104
+
105
+ # non file proxmox cloud secrets are stored in the patroni database
106
+ async def CreateCloudSecret(self, request, context):
107
+ target_pve = request.target_pve
108
+ cloud_domain = request.cloud_domain
109
+ secret_name = request.secret_name
110
+ secret_data = json.loads(request.secret_data)
111
+ secret_type = request.secret_type
112
+
113
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
114
+ engine = await get_engine(online_pve_host)
115
+
116
+ with Session(engine) as session:
117
+ try:
118
+ session.add(
119
+ ProxmoxCloudSecrets(
120
+ cloud_domain=cloud_domain,
121
+ secret_name=secret_name,
122
+ secret_data=secret_data,
123
+ secret_type=secret_type,
124
+ )
125
+ )
126
+ session.commit()
127
+
128
+ except IntegrityError as e:
129
+ session.rollback()
130
+ return cloud_pb2.CreateCloudSecretResponse(
131
+ success=False, err_message=str(e)
132
+ )
133
+
134
+ return cloud_pb2.CreateCloudSecretResponse(success=True)
135
+
136
+ async def DeleteCloudSecret(self, request, context):
137
+ target_pve = request.target_pve
138
+ secret_name = request.secret_name
139
+ cloud_domain = request.cloud_domain
140
+
141
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
142
+ engine = await get_engine(online_pve_host)
143
+
144
+ with Session(engine) as session:
145
+ stmt = delete(ProxmoxCloudSecrets).where(
146
+ ProxmoxCloudSecrets.cloud_domain == cloud_domain,
147
+ ProxmoxCloudSecrets.secret_name == secret_name,
148
+ )
149
+
150
+ result = session.execute(stmt)
151
+ session.commit()
152
+
153
+ return cloud_pb2.DeleteCloudSecretResponse(success=True)
154
+
155
+ async def GetCloudSecret(self, request, context):
156
+ target_pve = request.target_pve
157
+ secret_name = request.secret_name
158
+ cloud_domain = request.cloud_domain
159
+
160
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
161
+ engine = await get_engine(online_pve_host)
162
+
163
+ with Session(engine) as session:
164
+ stmt = select(ProxmoxCloudSecrets).where(
165
+ ProxmoxCloudSecrets.cloud_domain == cloud_domain
166
+ and ProxmoxCloudSecrets.secret_name == secret_name
167
+ )
168
+ record = session.scalars(stmt).first()
169
+
170
+ return cloud_pb2.GetCloudSecretResponse(secret=json.dumps(record.secret_data))
171
+
172
+ # fetch by type
173
+ async def GetCloudSecrets(self, request, context):
174
+ target_pve = request.target_pve
175
+ secret_type = request.secret_type
176
+ cloud_domain = request.cloud_domain
177
+
178
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
179
+ engine = await get_engine(online_pve_host)
180
+
181
+ with Session(engine) as session:
182
+ stmt = select(ProxmoxCloudSecrets).where(
183
+ ProxmoxCloudSecrets.cloud_domain == cloud_domain,
184
+ ProxmoxCloudSecrets.secret_type == secret_type,
185
+ )
186
+ records = session.scalars(stmt).all()
187
+
188
+ return cloud_pb2.GetCloudSecretsResponse(
189
+ secrets=json.dumps(
190
+ {record.secret_name: record.secret_data for record in records}
191
+ )
192
+ )
193
+
194
+ async def GetVmVarsBlake(self, request, context):
195
+ blake_ids = request.blake_ids
196
+ target_pve = request.target_pve
197
+ cloud_domain = request.cloud_domain
198
+
199
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
200
+ engine = await get_engine(online_pve_host)
201
+
202
+ with Session(engine) as session:
203
+ stmt = select(VirtualMachineVars).where(
204
+ VirtualMachineVars.blake_id.in_(blake_ids),
205
+ VirtualMachineVars.cloud_domain == cloud_domain,
206
+ )
207
+ records = session.scalars(stmt).all()
208
+
209
+ return cloud_pb2.GetVmVarsBlakeResponse(
210
+ blake_id_vars={
211
+ entry.blake_id: json.dumps(entry.vm_vars) for entry in records
212
+ }
213
+ )
214
+
215
+ async def GetCephAccess(self, request, context):
216
+ target_pve = request.target_pve
217
+
218
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
219
+ async with asyncssh.connect(
220
+ online_pve_host, username="root", known_hosts=None
221
+ ) as conn:
222
+ cmd = await conn.run(f"cat /etc/ceph/ceph.conf", check=True)
223
+ catted_conf = cmd.stdout
224
+
225
+ cmd = await conn.run(
226
+ f"cat /etc/pve/priv/ceph.client.admin.keyring", check=True
227
+ )
228
+ catted_keyring = cmd.stdout
229
+
230
+ return cloud_pb2.GetCephAccessResponse(
231
+ ceph_conf=catted_conf, admin_keyring=catted_keyring
232
+ )
233
+
234
+ async def GetSshKey(self, request, context):
235
+ target_pve = request.target_pve
236
+
237
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
238
+ async with asyncssh.connect(
239
+ online_pve_host, username="root", known_hosts=None
240
+ ) as conn:
241
+ match request.key_type:
242
+ case cloud_pb2.GetSshKeyRequest.PVE_HOST_RSA:
243
+ cmd = await conn.run(f"cat /root/.ssh/id_rsa", check=True)
244
+ catted_key = cmd.stdout
245
+ case cloud_pb2.GetSshKeyRequest.AUTOMATION:
246
+ cmd = await conn.run(
247
+ f"cat /etc/pve/cloud/automation_id_ed25519", check=True
248
+ )
249
+ catted_key = cmd.stdout
250
+
251
+ return cloud_pb2.GetSshKeyResponse(key=catted_key)
252
+
253
+ async def GetProxmoxApi(self, request, context):
254
+ target_pve = request.target_pve
255
+
256
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
257
+ async with asyncssh.connect(
258
+ online_pve_host, username="root", known_hosts=None
259
+ ) as conn:
260
+ args_string = None
261
+ if request.get_args:
262
+ args_string = " ".join(
263
+ f"{k} '{v}'" for k, v in request.get_args.items()
264
+ )
265
+
266
+ cmd = await conn.run(
267
+ f"pvesh get {request.api_path} {args_string} --output-format json",
268
+ check=True,
269
+ )
270
+ resp_json = cmd.stdout
271
+
272
+ return cloud_pb2.GetProxmoxApiResponse(json_resp=resp_json)
273
+
274
+ async def CreateProxmoxApi(self, request, context):
275
+ target_pve = request.target_pve
276
+
277
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
278
+ async with asyncssh.connect(
279
+ online_pve_host, username="root", known_hosts=None
280
+ ) as conn:
281
+ args_string = None
282
+ if request.create_args:
283
+ args_string = " ".join(
284
+ f"{k} '{v}'" for k, v in request.create_args.items()
285
+ )
286
+ try:
287
+ print(f"pvesh create {request.api_path} {args_string}")
288
+ cmd = await conn.run(
289
+ f"pvesh create {request.api_path} {args_string}",
290
+ check=True,
291
+ )
292
+ print(cmd.stdout)
293
+ except asyncssh.ProcessError as e:
294
+ return cloud_pb2.CreateProxmoxApiResponse(
295
+ success=False, err_message=f"Exit code {e.exit_status} - {e.stderr}"
296
+ )
297
+
298
+ return cloud_pb2.CreateProxmoxApiResponse(success=True)
299
+
300
+ async def DeleteProxmoxApi(self, request, context):
301
+ target_pve = request.target_pve
302
+
303
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
304
+ async with asyncssh.connect(
305
+ online_pve_host, username="root", known_hosts=None
306
+ ) as conn:
307
+ try:
308
+ cmd = await conn.run(
309
+ f"pvesh delete {request.api_path}",
310
+ check=True,
311
+ )
312
+ print(cmd.stdout)
313
+ except asyncssh.ProcessError as e:
314
+ return cloud_pb2.DeleteProxmoxApiResponse(
315
+ success=False, err_message=f"Exit code {e.exit_status} - {e.stderr}"
316
+ )
317
+
318
+ return cloud_pb2.DeleteProxmoxApiResponse(success=True)
319
+
320
+ async def GetProxmoxHost(self, request, context):
321
+ target_pve = request.target_pve
322
+ online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
323
+
324
+ return cloud_pb2.GetProxmoxHostResponse(pve_host=online_pve_host)
325
+
326
+ async def GetCloudDomain(self, request, context):
327
+ target_pve = request.target_pve
328
+
329
+ cloud_domain = get_cloud_domain(target_pve)
330
+ return cloud_pb2.GetCloudDomainResponse(domain=cloud_domain)
331
+
332
+ async def GetPveInventory(self, request, context):
333
+ target_pve = request.target_pve
334
+
335
+ cloud_domain = get_cloud_domain(target_pve)
336
+ pve_inventory = get_pve_inventory(cloud_domain, skip_py_cloud_check=True)
337
+
338
+ return cloud_pb2.GetPveInventoryResponse(
339
+ inventory=yaml.safe_dump(pve_inventory), cloud_domain=cloud_domain
340
+ )
341
+
342
+
343
+ def is_port_bound(port, host="0.0.0.0"):
344
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
345
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
346
+ try:
347
+ s.bind((host, port))
348
+ return False # not bound
349
+ except OSError:
350
+ return True # bound
351
+
352
+
353
+ async def serve():
354
+ server = grpc.aio.server()
355
+ cloud_pb2_grpc.add_CloudServiceServicer_to_server(CloudServiceServicer(), server)
356
+
357
+ health_servicer = HealthServicer()
358
+ health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)
359
+
360
+ socket_file = f"/tmp/pc-rpc-{sys.argv[1]}.sock"
361
+
362
+ server.add_insecure_port(f"unix://{socket_file}")
363
+ await server.start()
364
+
365
+ print(f"gRPC AsyncIO server running on {socket_file}")
366
+ try:
367
+ await server.wait_for_termination()
368
+ finally:
369
+ # Ensure cleanup
370
+ await server.stop(grace=0)
371
+ print("gRPC server stopped and port released.")
372
+
373
+ # delete unix socket file
374
+ if os.path.exists(socket_file):
375
+ os.remove(socket_file)
376
+
377
+
378
+ def main():
379
+ asyncio.run(serve())
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rpyc-pve-cloud
3
- Version: 0.1.7rc0
3
+ Version: 0.2.0
4
4
  Author-email: Tobias Huebner <tobias.huebner@vmzberlin.com>
5
5
  License-Expression: GPL-3.0-or-later
6
6
  License-File: LICENSE.md
7
- Requires-Dist: py-pve-cloud==0.14.6rc0
7
+ Requires-Dist: py-pve-cloud<0.16.0,>=0.15.0
8
8
  Requires-Dist: grpcio==1.76.0
9
9
  Requires-Dist: asyncssh==2.22.0
10
10
  Requires-Dist: protobuf==6.33.4
@@ -1,4 +1,4 @@
1
- py-pve-cloud==0.14.6rc0
1
+ py-pve-cloud<0.16.0,>=0.15.0
2
2
  grpcio==1.76.0
3
3
  asyncssh==2.22.0
4
4
  protobuf==6.33.4
@@ -1 +0,0 @@
1
- __version__ = "0.1.7-rc0"
@@ -1,75 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Generated by the protocol buffer compiler. DO NOT EDIT!
3
- # NO CHECKED-IN PROTOBUF GENCODE
4
- # source: cloud.proto
5
- # Protobuf Python Version: 6.31.1
6
- """Generated protocol buffer code."""
7
- from google.protobuf import descriptor as _descriptor
8
- from google.protobuf import descriptor_pool as _descriptor_pool
9
- from google.protobuf import runtime_version as _runtime_version
10
- from google.protobuf import symbol_database as _symbol_database
11
- from google.protobuf.internal import builder as _builder
12
- _runtime_version.ValidateProtobufRuntimeVersion(
13
- _runtime_version.Domain.PUBLIC,
14
- 6,
15
- 31,
16
- 1,
17
- '',
18
- 'cloud.proto'
19
- )
20
- # @@protoc_insertion_point(imports)
21
-
22
- _sym_db = _symbol_database.Default()
23
-
24
-
25
-
26
-
27
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0b\x63loud.proto\x12\x06protos\",\n\x16GetPveInventoryRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\"B\n\x17GetPveInventoryResponse\x12\x11\n\tinventory\x18\x01 \x01(\t\x12\x14\n\x0c\x63loud_domain\x18\x02 \x01(\t\"+\n\x15GetProxmoxHostRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\"*\n\x16GetProxmoxHostResponse\x12\x10\n\x08pve_host\x18\x01 \x01(\t\"\xa9\x01\n\x14GetProxmoxApiRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x10\n\x08\x61pi_path\x18\x02 \x01(\t\x12;\n\x08get_args\x18\x03 \x03(\x0b\x32).protos.GetProxmoxApiRequest.GetArgsEntry\x1a.\n\x0cGetArgsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"*\n\x15GetProxmoxApiResponse\x12\x11\n\tjson_resp\x18\x01 \x01(\t\"\x87\x01\n\x10GetSshKeyRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x32\n\x08key_type\x18\x02 \x01(\x0e\x32 .protos.GetSshKeyRequest.KeyType\"+\n\x07KeyType\x12\x0e\n\nAUTOMATION\x10\x00\x12\x10\n\x0cPVE_HOST_RSA\x10\x01\" \n\x11GetSshKeyResponse\x12\x0b\n\x03key\x18\x01 \x01(\t\"*\n\x14GetCephAccessRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\"A\n\x15GetCephAccessResponse\x12\x11\n\tceph_conf\x18\x01 \x01(\t\x12\x15\n\radmin_keyring\x18\x02 \x01(\t\">\n\x14GetKubeconfigRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x12\n\nstack_name\x18\x02 \x01(\t\"\'\n\x15GetKubeconfigResponse\x12\x0e\n\x06\x63onfig\x18\x01 \x01(\t\"+\n\x15GetClusterVarsRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\"&\n\x16GetClusterVarsResponse\x12\x0c\n\x04vars\x18\x01 \x01(\t\"P\n\x15GetCloudSecretRequest\x12\x12\n\ntarget_pve\x18\x01 \x01(\t\x12\x13\n\x0bsecret_name\x18\x02 \x01(\t\x12\x0e\n\x06rstrip\x18\x03 \x01(\x08\"(\n\x16GetCloudSecretResponse\x12\x0e\n\x06secret\x18\x01 \x01(\t2\x87\x05\n\x0c\x43loudService\x12R\n\x13GetMasterKubeconfig\x12\x1c.protos.GetKubeconfigRequest\x1a\x1d.protos.GetKubeconfigResponse\x12O\n\x0eGetClusterVars\x12\x1d.protos.GetClusterVarsRequest\x1a\x1e.protos.GetClusterVarsResponse\x12O\n\x0eGetCloudSecret\x12\x1d.protos.GetCloudSecretRequest\x1a\x1e.protos.GetCloudSecretResponse\x12L\n\rGetCephAccess\x12\x1c.protos.GetCephAccessRequest\x1a\x1d.protos.GetCephAccessResponse\x12@\n\tGetSshKey\x12\x18.protos.GetSshKeyRequest\x1a\x19.protos.GetSshKeyResponse\x12L\n\rGetProxmoxApi\x12\x1c.protos.GetProxmoxApiRequest\x1a\x1d.protos.GetProxmoxApiResponse\x12O\n\x0eGetProxmoxHost\x12\x1d.protos.GetProxmoxHostRequest\x1a\x1e.protos.GetProxmoxHostResponse\x12R\n\x0fGetPveInventory\x12\x1e.protos.GetPveInventoryRequest\x1a\x1f.protos.GetPveInventoryResponseBQZOgithub.com/Proxmox-Cloud/terraform-provider-pxc/internal/provider/protos;protosb\x06proto3')
28
-
29
- _globals = globals()
30
- _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31
- _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cloud_pb2', _globals)
32
- if not _descriptor._USE_C_DESCRIPTORS:
33
- _globals['DESCRIPTOR']._loaded_options = None
34
- _globals['DESCRIPTOR']._serialized_options = b'ZOgithub.com/Proxmox-Cloud/terraform-provider-pxc/internal/provider/protos;protos'
35
- _globals['_GETPROXMOXAPIREQUEST_GETARGSENTRY']._loaded_options = None
36
- _globals['_GETPROXMOXAPIREQUEST_GETARGSENTRY']._serialized_options = b'8\001'
37
- _globals['_GETPVEINVENTORYREQUEST']._serialized_start=23
38
- _globals['_GETPVEINVENTORYREQUEST']._serialized_end=67
39
- _globals['_GETPVEINVENTORYRESPONSE']._serialized_start=69
40
- _globals['_GETPVEINVENTORYRESPONSE']._serialized_end=135
41
- _globals['_GETPROXMOXHOSTREQUEST']._serialized_start=137
42
- _globals['_GETPROXMOXHOSTREQUEST']._serialized_end=180
43
- _globals['_GETPROXMOXHOSTRESPONSE']._serialized_start=182
44
- _globals['_GETPROXMOXHOSTRESPONSE']._serialized_end=224
45
- _globals['_GETPROXMOXAPIREQUEST']._serialized_start=227
46
- _globals['_GETPROXMOXAPIREQUEST']._serialized_end=396
47
- _globals['_GETPROXMOXAPIREQUEST_GETARGSENTRY']._serialized_start=350
48
- _globals['_GETPROXMOXAPIREQUEST_GETARGSENTRY']._serialized_end=396
49
- _globals['_GETPROXMOXAPIRESPONSE']._serialized_start=398
50
- _globals['_GETPROXMOXAPIRESPONSE']._serialized_end=440
51
- _globals['_GETSSHKEYREQUEST']._serialized_start=443
52
- _globals['_GETSSHKEYREQUEST']._serialized_end=578
53
- _globals['_GETSSHKEYREQUEST_KEYTYPE']._serialized_start=535
54
- _globals['_GETSSHKEYREQUEST_KEYTYPE']._serialized_end=578
55
- _globals['_GETSSHKEYRESPONSE']._serialized_start=580
56
- _globals['_GETSSHKEYRESPONSE']._serialized_end=612
57
- _globals['_GETCEPHACCESSREQUEST']._serialized_start=614
58
- _globals['_GETCEPHACCESSREQUEST']._serialized_end=656
59
- _globals['_GETCEPHACCESSRESPONSE']._serialized_start=658
60
- _globals['_GETCEPHACCESSRESPONSE']._serialized_end=723
61
- _globals['_GETKUBECONFIGREQUEST']._serialized_start=725
62
- _globals['_GETKUBECONFIGREQUEST']._serialized_end=787
63
- _globals['_GETKUBECONFIGRESPONSE']._serialized_start=789
64
- _globals['_GETKUBECONFIGRESPONSE']._serialized_end=828
65
- _globals['_GETCLUSTERVARSREQUEST']._serialized_start=830
66
- _globals['_GETCLUSTERVARSREQUEST']._serialized_end=873
67
- _globals['_GETCLUSTERVARSRESPONSE']._serialized_start=875
68
- _globals['_GETCLUSTERVARSRESPONSE']._serialized_end=913
69
- _globals['_GETCLOUDSECRETREQUEST']._serialized_start=915
70
- _globals['_GETCLOUDSECRETREQUEST']._serialized_end=995
71
- _globals['_GETCLOUDSECRETRESPONSE']._serialized_start=997
72
- _globals['_GETCLOUDSECRETRESPONSE']._serialized_end=1037
73
- _globals['_CLOUDSERVICE']._serialized_start=1040
74
- _globals['_CLOUDSERVICE']._serialized_end=1687
75
- # @@protoc_insertion_point(module_scope)
@@ -1,188 +0,0 @@
1
- import asyncio
2
- import socket
3
- import sys
4
-
5
- import asyncssh
6
- import grpc
7
- import yaml
8
- from pve_cloud.cli.pvclu import get_cluster_vars, get_ssh_master_kubeconfig
9
- from pve_cloud.lib.inventory import *
10
-
11
- import pve_cloud_rpc.protos.cloud_pb2 as cloud_pb2
12
- import pve_cloud_rpc.protos.cloud_pb2_grpc as cloud_pb2_grpc
13
- import pve_cloud_rpc.protos.health_pb2 as health_pb2
14
- import pve_cloud_rpc.protos.health_pb2_grpc as health_pb2_grpc
15
-
16
-
17
- class HealthServicer(health_pb2_grpc.HealthServicer):
18
-
19
- # this also performs the py-pve-cloud version check to not run against incompatible
20
- # installed proxmox cloud versions
21
- async def Check(self, request, context):
22
- target_pve = request.target_pve
23
- try:
24
- get_online_pve_host(
25
- target_pve, skip_py_cloud_check=False
26
- ) # actually perform the check
27
- return health_pb2.HealthCheckResponse(
28
- status=health_pb2.HealthCheckResponse.SERVING
29
- )
30
- except RuntimeError as e:
31
- return health_pb2.HealthCheckResponse(
32
- status=health_pb2.HealthCheckResponse.MISSMATCH,
33
- error_message=f"py-pve-cloud version check failed with: {e}",
34
- ) # go provider process will kill
35
-
36
-
37
- class CloudServiceServicer(cloud_pb2_grpc.CloudServiceServicer):
38
-
39
- async def GetMasterKubeconfig(self, request, context):
40
- target_pve = request.target_pve
41
- stack_name = request.stack_name
42
-
43
- online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
44
- cluster_vars = get_cluster_vars(online_pve_host)
45
-
46
- return cloud_pb2.GetKubeconfigResponse(
47
- config=get_ssh_master_kubeconfig(cluster_vars, stack_name)
48
- )
49
-
50
- async def GetClusterVars(self, request, context):
51
- target_pve = request.target_pve
52
-
53
- online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
54
- cluster_vars = get_cluster_vars(online_pve_host)
55
-
56
- return cloud_pb2.GetClusterVarsResponse(vars=yaml.safe_dump(cluster_vars))
57
-
58
- async def GetCloudSecret(self, request, context):
59
- target_pve = request.target_pve
60
- secret_name = request.secret_name
61
-
62
- online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
63
- async with asyncssh.connect(
64
- online_pve_host, username="root", known_hosts=None
65
- ) as conn:
66
- cmd = await conn.run(
67
- f"cat /etc/pve/cloud/secrets/{secret_name}", check=True
68
- )
69
- catted_secret = cmd.stdout
70
-
71
- if (
72
- request.rstrip
73
- ): # defaults to true but in special cases user might want to keep newlines (e.g. certs)
74
- catted_secret = catted_secret.rstrip()
75
-
76
- return cloud_pb2.GetCloudSecretResponse(secret=catted_secret)
77
-
78
- async def GetCephAccess(self, request, context):
79
- target_pve = request.target_pve
80
-
81
- online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
82
- async with asyncssh.connect(
83
- online_pve_host, username="root", known_hosts=None
84
- ) as conn:
85
- cmd = await conn.run(f"cat /etc/ceph/ceph.conf", check=True)
86
- catted_conf = cmd.stdout
87
-
88
- cmd = await conn.run(
89
- f"cat /etc/pve/priv/ceph.client.admin.keyring", check=True
90
- )
91
- catted_keyring = cmd.stdout
92
-
93
- return cloud_pb2.GetCephAccessResponse(
94
- ceph_conf=catted_conf, admin_keyring=catted_keyring
95
- )
96
-
97
- async def GetSshKey(self, request, context):
98
- target_pve = request.target_pve
99
-
100
- online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
101
- async with asyncssh.connect(
102
- online_pve_host, username="root", known_hosts=None
103
- ) as conn:
104
- match request.key_type:
105
- case cloud_pb2.GetSshKeyRequest.PVE_HOST_RSA:
106
- cmd = await conn.run(f"cat /root/.ssh/id_rsa", check=True)
107
- catted_key = cmd.stdout
108
- case cloud_pb2.GetSshKeyRequest.AUTOMATION:
109
- cmd = await conn.run(
110
- f"cat /etc/pve/cloud/automation_id_ed25519", check=True
111
- )
112
- catted_key = cmd.stdout
113
-
114
- return cloud_pb2.GetSshKeyResponse(key=catted_key)
115
-
116
- async def GetProxmoxApi(self, request, context):
117
- target_pve = request.target_pve
118
-
119
- online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
120
- async with asyncssh.connect(
121
- online_pve_host, username="root", known_hosts=None
122
- ) as conn:
123
- args_string = None
124
- if request.get_args:
125
- args_string = " ".join(f"{k} {v}" for k, v in request.get_args.items())
126
-
127
- cmd = await conn.run(
128
- f"pvesh get {request.api_path} {args_string} --output-format json",
129
- check=True,
130
- )
131
- resp_json = cmd.stdout
132
-
133
- return cloud_pb2.GetProxmoxApiResponse(json_resp=resp_json)
134
-
135
- async def GetProxmoxHost(self, request, context):
136
- target_pve = request.target_pve
137
- online_pve_host = get_online_pve_host(target_pve, skip_py_cloud_check=True)
138
-
139
- return cloud_pb2.GetProxmoxHostResponse(pve_host=online_pve_host)
140
-
141
- async def GetPveInventory(self, request, context):
142
- target_pve = request.target_pve
143
-
144
- cloud_domain = get_cloud_domain(target_pve)
145
- pve_inventory = get_pve_inventory(cloud_domain, skip_py_cloud_check=True)
146
-
147
- return cloud_pb2.GetPveInventoryResponse(
148
- inventory=yaml.safe_dump(pve_inventory), cloud_domain=cloud_domain
149
- )
150
-
151
-
152
- def is_port_bound(port, host="0.0.0.0"):
153
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
154
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
155
- try:
156
- s.bind((host, port))
157
- return False # not bound
158
- except OSError:
159
- return True # bound
160
-
161
-
162
- async def serve():
163
- server = grpc.aio.server()
164
- cloud_pb2_grpc.add_CloudServiceServicer_to_server(CloudServiceServicer(), server)
165
-
166
- health_servicer = HealthServicer()
167
- health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)
168
-
169
- socket_file = f"/tmp/pc-rpc-{sys.argv[1]}.sock"
170
-
171
- server.add_insecure_port(f"unix://{socket_file}")
172
- await server.start()
173
-
174
- print(f"gRPC AsyncIO server running on {socket_file}")
175
- try:
176
- await server.wait_for_termination()
177
- finally:
178
- # Ensure cleanup
179
- await server.stop(grace=0)
180
- print("gRPC server stopped and port released.")
181
-
182
- # delete unix socket file
183
- if os.path.exists(socket_file):
184
- os.remove(socket_file)
185
-
186
-
187
- def main():
188
- asyncio.run(serve())