package io.fathom.cloud.dns.services;
import io.fathom.cloud.CloudException;
import io.fathom.cloud.dns.backend.DnsBackend;
import io.fathom.cloud.dns.backend.aws.AwsDnsBackend;
import io.fathom.cloud.dns.backend.federated.FederatedDnsBackend;
import io.fathom.cloud.dns.backend.selfhosted.SelfHostedDnsBackend;
import io.fathom.cloud.dns.state.DnsRepository;
import io.fathom.cloud.openstack.client.RestClientException;
import io.fathom.cloud.openstack.client.identity.CertificateAuthTokenProvider;
import io.fathom.cloud.openstack.client.identity.OpenstackIdentityClient;
import io.fathom.cloud.protobuf.DnsModel.BackendData;
import io.fathom.cloud.protobuf.DnsModel.BackendDataOrBuilder;
import io.fathom.cloud.protobuf.DnsModel.BackendSecretData;
import io.fathom.cloud.protobuf.DnsModel.BackendSecretDataOrBuilder;
import io.fathom.cloud.protobuf.DnsModel.DnsBackendProviderType;
import io.fathom.cloud.ssh.SshContext;
import io.fathom.cloud.ssh.jsch.SshContextImpl;
import io.fathom.cloud.state.DuplicateValueException;
import java.net.URI;
import java.security.KeyPair;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
import com.google.inject.persist.Transactional;
@Singleton
@Transactional
public class DnsBackends {
private static final Logger log = LoggerFactory.getLogger(DnsBackends.class);
@Inject
DnsSecrets dnsSecrets;
@Inject
SshContext sshContext;
@Inject
Provider<AwsDnsBackend> awsProvider;
@Inject
Provider<FederatedDnsBackend> federatedProvider;
@Inject
Provider<SelfHostedDnsBackend> selfHostedProvider;
@Inject
DnsRepository repository;
// @Inject
// public DnsBackends(Configuration config) {
// this.defaultBackendProvider = config.lookup("dns.backend",
// DnsBackendProviderType.SELF_HOSTED);
// }
public DnsBackend getBackend(BackendData backendData) {
switch (backendData.getType()) {
case AWS_ROUTE53: {
AwsDnsBackend aws = awsProvider.get();
aws.init(backendData);
return aws;
}
case OPENSTACK: {
FederatedDnsBackend federated = federatedProvider.get();
federated.init(backendData);
return federated;
}
case SELF_HOSTED: {
SelfHostedDnsBackend selfHosted = selfHostedProvider.get();
selfHosted.init(backendData);
return selfHosted;
}
default:
throw new IllegalArgumentException();
}
}
public DnsBackend getGenericBackend() {
return selfHostedProvider.get();
}
public List<BackendData> listBackends() throws CloudException {
return repository.getBackends().list();
}
public BackendData register(BackendData.Builder backend, BackendSecretData.Builder secrets, String email)
throws CloudException {
if (repository.getBackends().find(backend.getKey()) != null) {
throw new WebApplicationException(Status.CONFLICT);
}
if (backend.getDefault()) {
for (BackendData b : repository.getBackends().list()) {
if (b.getDefault()) {
// TODO: Support changing
throw new IllegalArgumentException("Default backend already set");
}
}
}
if (backend.getType() == DnsBackendProviderType.OPENSTACK) {
registerOpenstackBackend(backend, email);
}
if (backend.getType() == DnsBackendProviderType.AWS_ROUTE53) {
registerAwsRoute53Backend(backend, secrets);
}
backend.setSecretData(dnsSecrets.encrypt(secrets.build()));
BackendData created;
{
try {
created = repository.getBackends().create(backend);
} catch (DuplicateValueException e) {
// Shouldn't happen, unless there's concurrent operation
throw new IllegalStateException("Duplicate provider name while creating registration");
}
}
return created;
}
private void registerAwsRoute53Backend(BackendDataOrBuilder backend, BackendSecretDataOrBuilder secrets) {
if (Strings.isNullOrEmpty(secrets.getUsername()) || Strings.isNullOrEmpty(secrets.getPassword())) {
throw new IllegalArgumentException("Username and password are required to use AWS Route 53 DNS backend");
}
}
void registerOpenstackBackend(BackendData.Builder backend, String email) throws CloudException {
KeyPair keypair = ((SshContextImpl) sshContext).getKeypair();
URI uri = URI.create(backend.getUrl());
OpenstackIdentityClient identityClient;
try {
identityClient = CertificateAuthTokenProvider.ensureRegistered(keypair, uri, email);
} catch (RestClientException e) {
throw new CloudException("Error registering with server", e);
}
String project;
try {
project = identityClient.getUtils().ensureProjectWithPrefix("__federation__");
} catch (RestClientException e) {
throw new CloudException("Error creating project", e);
}
backend.setBackendCookie(project);
}
}