chore: Implement server deletion for hetzner on provider layer

pull/213/head
NaiJi ✨ 2023-03-09 13:06:15 +04:00
parent 76536f8115
commit bc9ab447f0
2 changed files with 85 additions and 35 deletions

View File

@ -244,15 +244,25 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
return volume;
}
Future<void> deleteVolume(final ServerVolume volume) async {
Future<GenericResult<void>> deleteVolume(final int volumeId) async {
final Dio client = await getClient();
try {
await client.delete('/volumes/${volume.id}');
await client.delete('/volumes/$volumeId');
} catch (e) {
print(e);
return GenericResult(
success: false,
data: null,
message: e.toString(),
);
} finally {
client.close();
}
return GenericResult(
success: true,
data: null,
);
}
Future<GenericResult<bool>> attachVolume(
@ -287,24 +297,32 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
);
}
Future<bool> detachVolume(final ServerVolume volume) async {
Future<GenericResult<bool>> detachVolume(final int volumeId) async {
bool success = false;
final Response detachVolumeResponse;
final Dio client = await getClient();
try {
detachVolumeResponse = await client.post(
'/volumes/${volume.id}/actions/detach',
'/volumes/$volumeId/actions/detach',
);
success =
detachVolumeResponse.data['action']['status'].toString() != 'error';
} catch (e) {
print(e);
return GenericResult(
success: false,
data: false,
message: e.toString(),
);
} finally {
client.close();
}
return success;
return GenericResult(
success: false,
data: success,
);
}
Future<bool> resizeVolume(
@ -398,46 +416,24 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
);
}
Future<GenericResult<bool>> deleteServer({
required final String domainName,
Future<GenericResult<void>> deleteServer({
required final int serverId,
}) async {
final Dio client = await getClient();
try {
final String hostname = getHostnameFromDomain(domainName);
final Response serversReponse = await client.get('/servers');
final List servers = serversReponse.data['servers'];
final Map server =
servers.firstWhere((final el) => el['name'] == hostname);
final List volumes = server['volumes'];
final List<Future> laterFutures = <Future>[];
for (final volumeId in volumes) {
await client.post('/volumes/$volumeId/actions/detach');
}
await Future.delayed(const Duration(seconds: 10));
for (final volumeId in volumes) {
laterFutures.add(client.delete('/volumes/$volumeId'));
}
laterFutures.add(client.delete('/servers/${server['id']}'));
await Future.wait(laterFutures);
await client.delete('/servers/$serverId');
} catch (e) {
print(e);
return GenericResult(
success: false,
data: false,
data: null,
message: e.toString(),
);
} finally {
close(client);
}
return GenericResult(
success: true,
data: true,
);
return GenericResult(success: true, data: null);
}
Future<GenericResult<void>> restart(final int serverId) async {

View File

@ -455,7 +455,7 @@ class HetznerServerProvider extends ServerProvider {
);
if (!serverResult.success || serverResult.data == null) {
await _adapter.api().deleteVolume(volume);
await _adapter.api().deleteVolume(volume.id);
await Future.delayed(const Duration(seconds: 5));
if (serverResult.message != null &&
serverResult.message == 'uniqueness_error') {
@ -549,7 +549,7 @@ class HetznerServerProvider extends ServerProvider {
CallbackDialogueChoice(
title: 'basis.try_again'.tr(),
callback: () async {
await _adapter.api().deleteVolume(volume);
await _adapter.api().deleteVolume(volume.id);
await Future.delayed(const Duration(seconds: 5));
final deletion = await deleteServer(hostname);
if (deletion.success) {
@ -576,5 +576,59 @@ class HetznerServerProvider extends ServerProvider {
Future<GenericResult<CallbackDialogueBranching?>> deleteServer(
final String hostname,
) async {}
) async {
final serversResult = await _adapter.api().getServers();
try {
final servers = serversResult.data;
HetznerServerInfo? foundServer;
for (final server in servers) {
if (server.name == hostname) {
foundServer = server;
break;
}
}
for (final volumeId in foundServer!.volumes) {
await _adapter.api().detachVolume(volumeId);
}
await Future.delayed(const Duration(seconds: 10));
final List<Future> laterFutures = <Future>[];
for (final volumeId in foundServer.volumes) {
laterFutures.add(_adapter.api().deleteVolume(volumeId));
}
laterFutures.add(_adapter.api().deleteVolume(foundServer.id));
await Future.wait(laterFutures);
} catch (e) {
print(e);
return GenericResult(
success: false,
data: CallbackDialogueBranching(
choices: [
CallbackDialogueChoice(
title: 'basis.cancel'.tr(),
callback: null,
),
CallbackDialogueChoice(
title: 'basis.try_again'.tr(),
callback: () async {
await Future.delayed(const Duration(seconds: 5));
return deleteServer(hostname);
},
),
],
description: 'modals.try_again'.tr(),
title: 'modals.server_deletion_error'.tr(),
),
message: e.toString(),
);
}
return GenericResult(
success: true,
data: null,
);
}
}