feat(digital-ocean): Implement endpoints for server creation and deletion
parent
f5a75e6eb5
commit
d19531232c
|
@ -95,6 +95,9 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
final Response dbCreateResponse;
|
final Response dbCreateResponse;
|
||||||
final Dio client = await getClient();
|
final Dio client = await getClient();
|
||||||
try {
|
try {
|
||||||
|
final List<ServerVolume> volumes = await getVolumes();
|
||||||
|
await Future.delayed(const Duration(seconds: 6));
|
||||||
|
|
||||||
dbCreateResponse = await client.post(
|
dbCreateResponse = await client.post(
|
||||||
'/volumes',
|
'/volumes',
|
||||||
data: {
|
data: {
|
||||||
|
@ -109,11 +112,12 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
final dbSize = dbCreateResponse.data['volume']['size_gigabytes'];
|
final dbSize = dbCreateResponse.data['volume']['size_gigabytes'];
|
||||||
final dbName = dbCreateResponse.data['volume']['name'];
|
final dbName = dbCreateResponse.data['volume']['name'];
|
||||||
volume = ServerVolume(
|
volume = ServerVolume(
|
||||||
id: dbId,
|
id: volumes.length,
|
||||||
name: dbName,
|
name: dbName,
|
||||||
sizeByte: dbSize,
|
sizeByte: dbSize,
|
||||||
serverId: null,
|
serverId: null,
|
||||||
linuxDevice: null,
|
linuxDevice: null,
|
||||||
|
uuid: dbId,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
|
@ -296,36 +300,9 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
required final String domainName,
|
required final String domainName,
|
||||||
required final String serverType,
|
required final String serverType,
|
||||||
}) async {
|
}) async {
|
||||||
ServerHostingDetails? details;
|
ServerHostingDetails? serverDetails;
|
||||||
|
|
||||||
final ServerVolume? newVolume = await createVolume();
|
|
||||||
if (newVolume == null) {
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
details = await createServerWithVolume(
|
|
||||||
dnsApiToken: dnsApiToken,
|
|
||||||
rootUser: rootUser,
|
|
||||||
domainName: domainName,
|
|
||||||
dataBase: newVolume,
|
|
||||||
serverType: serverType,
|
|
||||||
);
|
|
||||||
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ServerHostingDetails?> createServerWithVolume({
|
|
||||||
required final String dnsApiToken,
|
|
||||||
required final User rootUser,
|
|
||||||
required final String domainName,
|
|
||||||
required final ServerVolume dataBase,
|
|
||||||
required final String serverType,
|
|
||||||
}) async {
|
|
||||||
final Dio client = await getClient();
|
|
||||||
|
|
||||||
final String dbPassword = StringGenerators.dbPassword();
|
final String dbPassword = StringGenerators.dbPassword();
|
||||||
final int dbId = dataBase.id;
|
|
||||||
final String? dbUuid = dataBase.uuid;
|
|
||||||
|
|
||||||
final String apiToken = StringGenerators.apiToken();
|
final String apiToken = StringGenerators.apiToken();
|
||||||
final String hostname = getHostnameFromDomain(domainName);
|
final String hostname = getHostnameFromDomain(domainName);
|
||||||
|
@ -334,58 +311,44 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
base64.encode(utf8.encode(rootUser.password ?? 'PASS'));
|
base64.encode(utf8.encode(rootUser.password ?? 'PASS'));
|
||||||
|
|
||||||
final String userdataString =
|
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";
|
"#cloud-config\nruncmd:\n- curl https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect/raw/branch/master/nixos-infect | PROVIDER=digital-ocean 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);
|
print(userdataString);
|
||||||
|
|
||||||
final Map<String, Object> data = {
|
final Dio client = await getClient();
|
||||||
'name': hostname,
|
|
||||||
'server_type': serverType,
|
|
||||||
'start_after_create': false,
|
|
||||||
'image': 'ubuntu-20.04',
|
|
||||||
'volumes': dbUuid == null ? [dbId] : [dbUuid],
|
|
||||||
'networks': [],
|
|
||||||
'user_data': userdataString,
|
|
||||||
'labels': {},
|
|
||||||
'automount': true,
|
|
||||||
'location': 'fsn1'
|
|
||||||
};
|
|
||||||
print('Decoded data: $data');
|
|
||||||
|
|
||||||
ServerHostingDetails? serverDetails;
|
|
||||||
DioError? hetznerError;
|
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
final Map<String, Object> data = {
|
||||||
|
'name': hostname,
|
||||||
|
'size': serverType,
|
||||||
|
'image': 'ubuntu-20-04-x64',
|
||||||
|
'user_data': userdataString,
|
||||||
|
'region': region!,
|
||||||
|
};
|
||||||
|
print('Decoded data: $data');
|
||||||
|
|
||||||
final Response serverCreateResponse = await client.post(
|
final Response serverCreateResponse = await client.post(
|
||||||
'/servers',
|
'/droplets',
|
||||||
data: data,
|
data: data,
|
||||||
);
|
);
|
||||||
print(serverCreateResponse.data);
|
|
||||||
serverDetails = ServerHostingDetails(
|
final int serverId = serverCreateResponse.data['server']['id'];
|
||||||
id: serverCreateResponse.data['server']['id'],
|
final ServerVolume? newVolume = await createVolume();
|
||||||
ip4: serverCreateResponse.data['server']['public_net']['ipv4']['ip'],
|
final bool attachedVolume =
|
||||||
createTime: DateTime.now(),
|
await attachVolume(newVolume!.uuid!, serverId);
|
||||||
volume: dataBase,
|
|
||||||
apiToken: apiToken,
|
if (attachedVolume) {
|
||||||
provider: ServerProvider.hetzner,
|
serverDetails = ServerHostingDetails(
|
||||||
);
|
id: serverId,
|
||||||
success = true;
|
ip4: serverCreateResponse.data['droplet']['networks']['v4'][0],
|
||||||
} on DioError catch (e) {
|
createTime: DateTime.now(),
|
||||||
print(e);
|
volume: newVolume,
|
||||||
hetznerError = e;
|
apiToken: apiToken,
|
||||||
|
provider: ServerProvider.digitalOcean,
|
||||||
|
);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
} finally {
|
} finally {
|
||||||
client.close();
|
close(client);
|
||||||
}
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
await Future.delayed(const Duration(seconds: 10));
|
|
||||||
await deleteVolume(dbUuid ?? dbId.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hetznerError != null) {
|
|
||||||
throw hetznerError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return serverDetails;
|
return serverDetails;
|
||||||
|
@ -416,24 +379,26 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
|
|
||||||
final String hostname = getHostnameFromDomain(domainName);
|
final String hostname = getHostnameFromDomain(domainName);
|
||||||
|
|
||||||
final Response serversReponse = await client.get('/servers');
|
final ServerBasicInfo serverToRemove = (await getServers()).firstWhere(
|
||||||
final List servers = serversReponse.data['servers'];
|
(final el) => el.name == hostname,
|
||||||
final Map server = servers.firstWhere((final el) => el['name'] == hostname);
|
);
|
||||||
final List volumes = server['volumes'];
|
final ServerVolume volumeToRemove = (await getVolumes()).firstWhere(
|
||||||
|
(final el) => el.serverId == serverToRemove.id,
|
||||||
|
);
|
||||||
final List<Future> laterFutures = <Future>[];
|
final List<Future> laterFutures = <Future>[];
|
||||||
|
|
||||||
for (final volumeId in volumes) {
|
await detachVolume(volumeToRemove.uuid!);
|
||||||
await client.post('/volumes/$volumeId/actions/detach');
|
|
||||||
}
|
|
||||||
await Future.delayed(const Duration(seconds: 10));
|
await Future.delayed(const Duration(seconds: 10));
|
||||||
|
|
||||||
for (final volumeId in volumes) {
|
try {
|
||||||
laterFutures.add(client.delete('/volumes/$volumeId'));
|
laterFutures.add(deleteVolume(volumeToRemove.uuid!));
|
||||||
|
laterFutures.add(client.delete('/droplets/$serverToRemove.id'));
|
||||||
|
await Future.wait(laterFutures);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
close(client);
|
||||||
}
|
}
|
||||||
laterFutures.add(client.delete('/servers/${server['id']}'));
|
|
||||||
|
|
||||||
await Future.wait(laterFutures);
|
|
||||||
close(client);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -530,7 +495,6 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
ip: server.publicNet.ipv4.ip,
|
ip: server.publicNet.ipv4.ip,
|
||||||
reverseDns: server.publicNet.ipv4.reverseDns,
|
reverseDns: server.publicNet.ipv4.reverseDns,
|
||||||
created: server.created,
|
created: server.created,
|
||||||
volumeId: server.volumes.isNotEmpty ? server.volumes[0] : 0,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
|
@ -532,7 +532,6 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
ip: server.publicNet.ipv4.ip,
|
ip: server.publicNet.ipv4.ip,
|
||||||
reverseDns: server.publicNet.ipv4.reverseDns,
|
reverseDns: server.publicNet.ipv4.reverseDns,
|
||||||
created: server.created,
|
created: server.created,
|
||||||
volumeId: server.volumes.isNotEmpty ? server.volumes[0] : 0,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
|
@ -588,7 +588,7 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
id: server.id,
|
id: server.id,
|
||||||
createTime: server.created,
|
createTime: server.created,
|
||||||
volume: ServerVolume(
|
volume: ServerVolume(
|
||||||
id: server.volumeId,
|
id: 0,
|
||||||
name: 'recovered_volume',
|
name: 'recovered_volume',
|
||||||
sizeByte: 0,
|
sizeByte: 0,
|
||||||
serverId: server.id,
|
serverId: server.id,
|
||||||
|
|
|
@ -5,14 +5,12 @@ class ServerBasicInfo {
|
||||||
required this.reverseDns,
|
required this.reverseDns,
|
||||||
required this.ip,
|
required this.ip,
|
||||||
required this.created,
|
required this.created,
|
||||||
required this.volumeId,
|
|
||||||
});
|
});
|
||||||
final int id;
|
final int id;
|
||||||
final String name;
|
final String name;
|
||||||
final String reverseDns;
|
final String reverseDns;
|
||||||
final String ip;
|
final String ip;
|
||||||
final DateTime created;
|
final DateTime created;
|
||||||
final int volumeId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServerBasicInfoWithValidators extends ServerBasicInfo {
|
class ServerBasicInfoWithValidators extends ServerBasicInfo {
|
||||||
|
@ -26,7 +24,6 @@ class ServerBasicInfoWithValidators extends ServerBasicInfo {
|
||||||
reverseDns: serverBasicInfo.reverseDns,
|
reverseDns: serverBasicInfo.reverseDns,
|
||||||
ip: serverBasicInfo.ip,
|
ip: serverBasicInfo.ip,
|
||||||
created: serverBasicInfo.created,
|
created: serverBasicInfo.created,
|
||||||
volumeId: serverBasicInfo.volumeId,
|
|
||||||
isIpValid: isIpValid,
|
isIpValid: isIpValid,
|
||||||
isReverseDnsValid: isReverseDnsValid,
|
isReverseDnsValid: isReverseDnsValid,
|
||||||
);
|
);
|
||||||
|
@ -37,7 +34,6 @@ class ServerBasicInfoWithValidators extends ServerBasicInfo {
|
||||||
required final super.reverseDns,
|
required final super.reverseDns,
|
||||||
required final super.ip,
|
required final super.ip,
|
||||||
required final super.created,
|
required final super.created,
|
||||||
required final super.volumeId,
|
|
||||||
required this.isIpValid,
|
required this.isIpValid,
|
||||||
required this.isReverseDnsValid,
|
required this.isReverseDnsValid,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue