diff --git a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart index 16c87750..f24f49ca 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart @@ -23,6 +23,8 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { @override bool isWithToken; + final String region = 'fra1'; + @override BaseOptions get options { final BaseOptions options = BaseOptions(baseUrl: rootAddress); @@ -92,25 +94,22 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { dbCreateResponse = await client.post( '/volumes', data: { - 'size': 10, + 'size_gigabytes': 10, 'name': StringGenerators.dbStorageName(), 'labels': {'labelkey': 'value'}, - 'location': 'fsn1', - 'automount': false, - 'format': 'ext4' + 'region': region, + 'filesystem_type': 'ext4', }, ); final dbId = dbCreateResponse.data['volume']['id']; - final dbSize = dbCreateResponse.data['volume']['size']; - final dbServer = dbCreateResponse.data['volume']['server']; + final dbSize = dbCreateResponse.data['volume']['size_gigabytes']; final dbName = dbCreateResponse.data['volume']['name']; - final dbDevice = dbCreateResponse.data['volume']['linux_device']; volume = ServerVolume( id: dbId, name: dbName, sizeByte: dbSize, - serverId: dbServer, - linuxDevice: dbDevice, + serverId: null, + linuxDevice: null, ); } catch (e) { print(e); @@ -135,18 +134,19 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { }, ); final List rawVolumes = dbGetResponse.data['volumes']; + int id = 0; for (final rawVolume in rawVolumes) { - final int dbId = rawVolume['id']; - final int dbSize = rawVolume['size'] * 1024 * 1024 * 1024; - final dbServer = rawVolume['server']; + final dbId = rawVolume['id']; + final int dbSize = rawVolume['size_gigabytes'] * 1024 * 1024 * 1024; + final dbDropletIds = rawVolume['droplet_ids']; final String dbName = rawVolume['name']; - final dbDevice = rawVolume['linux_device']; final volume = ServerVolume( - id: dbId, + id: id++, name: dbName, sizeByte: dbSize, - serverId: dbServer, - linuxDevice: dbDevice, + serverId: dbDropletIds.isNotEmpty ? dbDropletIds[0] : null, + linuxDevice: null, + uuid: dbId, ); volumes.add(volume); } @@ -160,39 +160,29 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { } @override - Future getVolume(final int id) async { - ServerVolume? volume; - final Response dbGetResponse; - final Dio client = await getClient(); - try { - dbGetResponse = await client.get('/volumes/$id'); - final int dbId = dbGetResponse.data['volume']['id']; - final int dbSize = dbGetResponse.data['volume']['size']; - final int dbServer = dbGetResponse.data['volume']['server']; - final String dbName = dbGetResponse.data['volume']['name']; - final dbDevice = dbGetResponse.data['volume']['linux_device']; - volume = ServerVolume( - id: dbId, - name: dbName, - sizeByte: dbSize, - serverId: dbServer, - linuxDevice: dbDevice, - ); - } catch (e) { - print(e); - } finally { - client.close(); + /// volumeId is storage's UUID for Digital Ocean + Future getVolume(final String volumeId) async { + ServerVolume? neededVolume; + + final List volumes = await getVolumes(); + + for (final volume in volumes) { + if (volume.uuid == volumeId) { + neededVolume = volume; + } } - return volume; + return neededVolume; } @override - Future deleteVolume(final int id) async { + + /// volumeId is storage's UUID for Digital Ocean + Future deleteVolume(final String volumeId) async { final Dio client = await getClient(); try { - await client.delete('/volumes/$id'); + await client.delete('/volumes/$volumeId'); } catch (e) { print(e); } finally { @@ -201,20 +191,30 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { } @override - Future attachVolume(final int volumeId, final int serverId) async { + + /// volumeId is storage's UUID for Digital Ocean + Future attachVolume(final String volumeId, final int serverId) async { bool success = false; + final ServerVolume? volumeToAttach = await getVolume(volumeId); + if (volumeToAttach == null) { + return success; + } + final Response dbPostResponse; final Dio client = await getClient(); try { dbPostResponse = await client.post( - '/volumes/$volumeId/actions/attach', + '/volumes/actions', data: { - 'automount': true, - 'server': serverId, + 'type': 'attach', + 'volume_name': volumeToAttach.name, + 'region': region, + 'droplet_id': serverId, }, ); - success = dbPostResponse.data['action']['status'].toString() != 'error'; + success = + dbPostResponse.data['action']['status'].toString() == 'completed'; } catch (e) { print(e); } finally { @@ -225,14 +225,29 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { } @override - Future detachVolume(final int volumeId) async { + + /// volumeId is storage's UUID for Digital Ocean + Future detachVolume(final String volumeId) async { bool success = false; + final ServerVolume? volumeToAttach = await getVolume(volumeId); + if (volumeToAttach == null) { + return success; + } + final Response dbPostResponse; final Dio client = await getClient(); try { - dbPostResponse = await client.post('/volumes/$volumeId/actions/detach'); - success = dbPostResponse.data['action']['status'].toString() != 'error'; + dbPostResponse = await client.post( + '/volumes/actions', + data: { + 'type': 'detach', + 'droplet_id': volumeToAttach.serverId, + 'region': region, + }, + ); + success = + dbPostResponse.data['action']['status'].toString() == 'completed'; } catch (e) { print(e); } finally { @@ -243,19 +258,24 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { } @override - Future resizeVolume(final int volumeId, final int sizeGb) async { + + /// volumeId is storage's UUID for Digital Ocean + Future resizeVolume(final String volumeId, final int sizeGb) async { bool success = false; final Response dbPostResponse; final Dio client = await getClient(); try { dbPostResponse = await client.post( - '/volumes/$volumeId/actions/resize', + '/volumes/actions', data: { - 'size': sizeGb, + 'type': 'resize', + 'size_gigabytes': sizeGb, + 'region': region, }, ); - success = dbPostResponse.data['action']['status'].toString() != 'error'; + success = + dbPostResponse.data['action']['status'].toString() == 'completed'; } catch (e) { print(e); } finally { @@ -300,17 +320,11 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { final int dbId = dataBase.id; final String apiToken = StringGenerators.apiToken(); - final String hostname = getHostnameFromDomain(domainName); final String base64Password = base64.encode(utf8.encode(rootUser.password ?? 'PASS')); - print('hostname: $hostname'); - - /// add ssh key when you need it: e.g. "ssh_keys":["kherel"] - /// check the branch name, it could be "development" or "master". - /// final String userdataString = "#cloud-config\nruncmd:\n- curl https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect/raw/branch/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-21.05 DOMAIN='$domainName' LUSER='${rootUser.login}' ENCODED_PASSWORD='$base64Password' CF_TOKEN=$dnsApiToken DB_PASSWORD=$dbPassword API_TOKEN=$apiToken HOSTNAME=$hostname bash 2>&1 | tee /tmp/infect.log"; print(userdataString); diff --git a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart index 3b8ff016..dceb5a47 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart @@ -179,13 +179,13 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi { } @override - Future getVolume(final int id) async { + Future getVolume(final String volumeId) async { ServerVolume? volume; final Response dbGetResponse; final Dio client = await getClient(); try { - dbGetResponse = await client.get('/volumes/$id'); + dbGetResponse = await client.get('/volumes/$volumeId'); final int dbId = dbGetResponse.data['volume']['id']; final int dbSize = dbGetResponse.data['volume']['size']; final int dbServer = dbGetResponse.data['volume']['server']; @@ -208,10 +208,10 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi { } @override - Future deleteVolume(final int id) async { + Future deleteVolume(final String volumeId) async { final Dio client = await getClient(); try { - await client.delete('/volumes/$id'); + await client.delete('/volumes/$volumeId'); } catch (e) { print(e); } finally { @@ -220,7 +220,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi { } @override - Future attachVolume(final int volumeId, final int serverId) async { + Future attachVolume(final String volumeId, final int serverId) async { bool success = false; final Response dbPostResponse; @@ -244,7 +244,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi { } @override - Future detachVolume(final int volumeId) async { + Future detachVolume(final String volumeId) async { bool success = false; final Response dbPostResponse; @@ -262,7 +262,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi { } @override - Future resizeVolume(final int volumeId, final int sizeGb) async { + Future resizeVolume(final String volumeId, final int sizeGb) async { bool success = false; final Response dbPostResponse; @@ -319,20 +319,13 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi { final int dbId = dataBase.id; final String apiToken = StringGenerators.apiToken(); - final String hostname = getHostnameFromDomain(domainName); final String base64Password = base64.encode(utf8.encode(rootUser.password ?? 'PASS')); - print('hostname: $hostname'); - - /// add ssh key when you need it: e.g. "ssh_keys":["kherel"] - /// check the branch name, it could be "development" or "master". - /// final String userdataString = "#cloud-config\nruncmd:\n- curl https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect/raw/branch/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-21.05 DOMAIN='$domainName' LUSER='${rootUser.login}' ENCODED_PASSWORD='$base64Password' CF_TOKEN=$dnsApiToken DB_PASSWORD=$dbPassword API_TOKEN=$apiToken HOSTNAME=$hostname bash 2>&1 | tee /tmp/infect.log"; - print(userdataString); final Map data = { 'name': hostname, @@ -378,7 +371,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi { if (!success) { await Future.delayed(const Duration(seconds: 10)); - await deleteVolume(dbId); + await deleteVolume(dbId.toString()); } if (hetznerError != null) { diff --git a/lib/logic/api_maps/rest_maps/server_providers/volume_provider.dart b/lib/logic/api_maps/rest_maps/server_providers/volume_provider.dart index d6feae2c..52458217 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/volume_provider.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/volume_provider.dart @@ -5,10 +5,10 @@ import 'package:selfprivacy/logic/models/price.dart'; mixin VolumeProviderApi on ApiMap { Future createVolume(); Future> getVolumes({final String? status}); - Future getVolume(final int id); - Future attachVolume(final int volumeId, final int serverId); - Future detachVolume(final int volumeId); - Future resizeVolume(final int volumeId, final int sizeGb); - Future deleteVolume(final int id); + Future getVolume(final String volumeId); + Future attachVolume(final String volumeId, final int serverId); + Future detachVolume(final String volumeId); + Future resizeVolume(final String volumeId, final int sizeGb); + Future deleteVolume(final String volumeId); Future getPricePerGb(); } diff --git a/lib/logic/models/hive/server_details.dart b/lib/logic/models/hive/server_details.dart index 27e9829a..faaf37b4 100644 --- a/lib/logic/models/hive/server_details.dart +++ b/lib/logic/models/hive/server_details.dart @@ -58,6 +58,7 @@ class ServerVolume { required this.sizeByte, required this.serverId, required this.linuxDevice, + this.uuid, }); @HiveField(1) @@ -70,6 +71,8 @@ class ServerVolume { int? serverId; @HiveField(5, defaultValue: null) String? linuxDevice; + @HiveField(6, defaultValue: null) + String? uuid; } @HiveType(typeId: 101)