mirror of https://github.com/apache/cloudstack.git
veeam: add wip API client
auth and API listing works for backups and jobs, parsing of XML is next step Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
cabe4e5f54
commit
dc4bf22487
|
|
@ -17,6 +17,12 @@
|
|||
|
||||
package org.apache.cloudstack.backup;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.backup.veeam.VeeamClient;
|
||||
import org.apache.cloudstack.framework.backup.BackupPolicy;
|
||||
import org.apache.cloudstack.framework.backup.BackupProvider;
|
||||
import org.apache.cloudstack.framework.backup.BackupService;
|
||||
|
|
@ -25,50 +31,43 @@ import org.apache.cloudstack.framework.config.Configurable;
|
|||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.utils.component.AdapterBase;
|
||||
|
||||
import java.util.List;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
public class VeeamBackupProvider extends AdapterBase implements BackupProvider, Configurable {
|
||||
private static final Logger LOG = Logger.getLogger(VeeamBackupProvider.class);
|
||||
|
||||
private ConfigKey<String> VeeamUrl = new ConfigKey<>("Advanced", String.class,
|
||||
"backup.plugin.veeam.url",
|
||||
"",
|
||||
"http://localhost:9399/api/",
|
||||
"The Veeam backup and recovery URL.", true, ConfigKey.Scope.Zone);
|
||||
|
||||
private ConfigKey<String> VeeamUsername = new ConfigKey<>("Advanced", String.class,
|
||||
"backup.plugin.veeam.username",
|
||||
"",
|
||||
"administrator",
|
||||
"The Veeam backup and recovery username.", true, ConfigKey.Scope.Zone);
|
||||
|
||||
private ConfigKey<String> VeeamPassword = new ConfigKey<>("Advanced", String.class,
|
||||
"backup.plugin.veeam.password",
|
||||
"",
|
||||
"P@ssword123",
|
||||
"The Veeam backup and recovery password.", true, ConfigKey.Scope.Zone);
|
||||
|
||||
private ConfigKey<Boolean> VeeamValidateSSLSecurity = new ConfigKey<>("Advanced", Boolean.class, "backup.plugin.veeam.validate.ssl", "true",
|
||||
"When set to true, this will validate the SSL certificate when connecting to https/ssl enabled Veeam API service.", true, ConfigKey.Scope.Zone);
|
||||
|
||||
@Override
|
||||
public String getConfigComponentName() {
|
||||
return BackupService.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigKey<?>[] getConfigKeys() {
|
||||
return new ConfigKey[]{
|
||||
VeeamUrl,
|
||||
VeeamUsername,
|
||||
VeeamPassword
|
||||
};
|
||||
}
|
||||
private ConfigKey<Integer> VeeamApiRequestTimeout = new ConfigKey<>("Advanced", Integer.class, "backup.plugin.veeam.request.timeout", "300",
|
||||
"The Veeam B&R API request timeout in seconds.", true, ConfigKey.Scope.Zone);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "veeam";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Veeam B&R Plugin";
|
||||
private VeeamClient getClient(final Long zoneId) {
|
||||
try {
|
||||
return new VeeamClient(VeeamUrl.valueIn(zoneId), VeeamUsername.valueIn(zoneId), VeeamPassword.valueIn(zoneId),
|
||||
VeeamValidateSSLSecurity.valueIn(zoneId), VeeamApiRequestTimeout.valueIn(zoneId));
|
||||
} catch (URISyntaxException e) {
|
||||
throw new CloudRuntimeException("Failed to parse Veeam API URL: " + e.getMessage());
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
LOG.error("Failed to build Veeam API client due to: ", e);
|
||||
}
|
||||
throw new CloudRuntimeException("Failed to build Veeam API client");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -85,4 +84,30 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
|
|||
public boolean isBackupPolicy(String uuid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigComponentName() {
|
||||
return BackupService.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigKey<?>[] getConfigKeys() {
|
||||
return new ConfigKey[]{
|
||||
VeeamUrl,
|
||||
VeeamUsername,
|
||||
VeeamPassword,
|
||||
VeeamValidateSSLSecurity,
|
||||
VeeamApiRequestTimeout
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "veeam";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Veeam B&R Plugin";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.backup.veeam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class VeeamBackup implements VeeamObject {
|
||||
|
||||
String uuid;
|
||||
String name;
|
||||
String href;
|
||||
List<VeeamObject> links;
|
||||
|
||||
@Override
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHref() {
|
||||
return href;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VeeamObjectType getType() {
|
||||
return VeeamObjectType.Backup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VeeamObject> getLinks() {
|
||||
return links;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.backup.veeam;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.utils.security.SSLUtils;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.Credentials;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.AuthCache;
|
||||
import org.apache.http.client.CookieStore;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.conn.ConnectTimeoutException;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.impl.auth.BasicScheme;
|
||||
import org.apache.http.impl.client.BasicAuthCache;
|
||||
import org.apache.http.impl.client.BasicCookieStore;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.nio.TrustAllManager;
|
||||
|
||||
public class VeeamClient {
|
||||
private static final Logger LOG = Logger.getLogger(VeeamClient.class);
|
||||
|
||||
private final URI apiURI;
|
||||
private final HttpClient httpClient;
|
||||
private final HttpClientContext httpContext = HttpClientContext.create();
|
||||
private final CookieStore httpCookieStore = new BasicCookieStore();
|
||||
|
||||
public VeeamClient(final String url, final String username, final String password, final boolean validateCertificate, final int timeout) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
|
||||
this.apiURI = new URI(url);
|
||||
|
||||
final CredentialsProvider provider = new BasicCredentialsProvider();
|
||||
provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
|
||||
final HttpHost adminHost = new HttpHost(this.apiURI.getHost(), this.apiURI.getPort(), this.apiURI.getScheme());
|
||||
final AuthCache authCache = new BasicAuthCache();
|
||||
authCache.put(adminHost, new BasicScheme());
|
||||
|
||||
this.httpContext.setCredentialsProvider(provider);
|
||||
this.httpContext.setAuthCache(authCache);
|
||||
|
||||
final RequestConfig config = RequestConfig.custom()
|
||||
.setConnectTimeout(timeout * 1000)
|
||||
.setConnectionRequestTimeout(timeout * 1000)
|
||||
.setSocketTimeout(timeout * 1000)
|
||||
.build();
|
||||
|
||||
if (!validateCertificate) {
|
||||
final SSLContext sslcontext = SSLUtils.getSSLContext();
|
||||
sslcontext.init(null, new X509TrustManager[]{new TrustAllManager()}, new SecureRandom());
|
||||
final SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE);
|
||||
this.httpClient = HttpClientBuilder.create()
|
||||
.setDefaultCredentialsProvider(provider)
|
||||
.setDefaultCookieStore(httpCookieStore)
|
||||
.setDefaultRequestConfig(config)
|
||||
.setSSLSocketFactory(factory)
|
||||
.build();
|
||||
} else {
|
||||
this.httpClient = HttpClientBuilder.create()
|
||||
.setDefaultCredentialsProvider(provider)
|
||||
.setDefaultCookieStore(httpCookieStore)
|
||||
.setDefaultRequestConfig(config)
|
||||
.build();
|
||||
}
|
||||
|
||||
try {
|
||||
final HttpResponse response = post("/sessionMngr/", null);
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) {
|
||||
throw new CloudRuntimeException("Failed to create and authenticate Veeam API client, please check the settings.");
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
throw new CloudRuntimeException("Failed to authenticate Veeam API service due to:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAuthFailure(final HttpResponse response) {
|
||||
if (response != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
final Credentials credentials = httpContext.getCredentialsProvider().getCredentials(AuthScope.ANY);
|
||||
LOG.error("Veeam API authentication failed, please check Veeam configuration. Admin auth principal=" + credentials.getUserPrincipal() + ", password=" + credentials.getPassword() + ", API url=" + apiURI.toString());
|
||||
throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, "Veeam B&R API call unauthorized, please ask your administrator to fix integration issues.");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkResponseOK(final HttpResponse response) {
|
||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NO_CONTENT) {
|
||||
LOG.debug("Requested Veeam resource does not exist");
|
||||
return;
|
||||
}
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK && response.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to find the requested resource and get valid response from Veeam B&R API call, please ask your administrator to diagnose and fix issues.");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkResponseTimeOut(final Exception e) {
|
||||
if (e instanceof ConnectTimeoutException || e instanceof SocketTimeoutException) {
|
||||
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, "Veeam API operation timed out, please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
private HttpResponse get(final String path) throws IOException {
|
||||
final HttpGet request = new HttpGet(apiURI.toString() + path);
|
||||
final HttpResponse response = httpClient.execute(request, httpContext);
|
||||
checkAuthFailure(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
private HttpResponse post(final String path, final Object item) throws IOException {
|
||||
final HttpPost request = new HttpPost(apiURI.toString() + path);
|
||||
final HttpResponse response = httpClient.execute(request, httpContext);
|
||||
checkAuthFailure(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
//////////////// Public APIs: Backup /////////////////////
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
public List<VeeamBackup> listAllBackups() {
|
||||
LOG.debug("Trying to list Veeam backups");
|
||||
try {
|
||||
final HttpResponse response = get("/backups");
|
||||
checkResponseOK(response);
|
||||
// FIXME: parse XML to object
|
||||
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
|
||||
response.getEntity().writeTo(outstream);
|
||||
byte [] responseBody = outstream.toByteArray();
|
||||
|
||||
System.out.println(new String(responseBody));
|
||||
LOG.debug("Response received = " + response.getEntity().getContent());
|
||||
return null;
|
||||
} catch (final IOException e) {
|
||||
LOG.error("Failed to list Veeam backups due to:", e);
|
||||
checkResponseTimeOut(e);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public List<VeeamBackup> listJobs() {
|
||||
LOG.debug("Trying to list Veeam jobs");
|
||||
try {
|
||||
final HttpResponse response = get("/jobs");
|
||||
checkResponseOK(response);
|
||||
|
||||
// FIXME: parse XML to object
|
||||
|
||||
return null;
|
||||
} catch (final IOException e) {
|
||||
LOG.error("Failed to list Veeam jobs due to:", e);
|
||||
checkResponseTimeOut(e);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.backup.veeam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface VeeamObject {
|
||||
String getUuid();
|
||||
String getName();
|
||||
String getHref();
|
||||
VeeamObjectType getType();
|
||||
List<VeeamObject> getLinks();
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.backup.veeam;
|
||||
|
||||
public enum VeeamObjectType {
|
||||
Backup,
|
||||
BackupReference,
|
||||
BackupServerReference,
|
||||
RestorePointReferenceList,
|
||||
BackupFileReferenceList,
|
||||
RepositoryReference,
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.backup.veeam;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class VeeamClientTest {
|
||||
|
||||
private VeeamClient client;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
client = new VeeamClient("http://10.2.2.89:9399/api/", "administrator", "P@ssword123", true, 300);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicAuth() {
|
||||
client.listAllBackups();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue