mirror of https://github.com/apache/cloudstack.git
wip new method to allow assigning and checking of a VM to a Veeam job
Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
01059d9d5f
commit
400f1412fd
|
|
@ -33,9 +33,12 @@ import javax.net.ssl.X509TrustManager;
|
|||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.backup.BackupPolicy;
|
||||
import org.apache.cloudstack.backup.veeam.api.CreateObjectInJobSpec;
|
||||
import org.apache.cloudstack.backup.veeam.api.EntityReferences;
|
||||
import org.apache.cloudstack.backup.veeam.api.Ref;
|
||||
import org.apache.cloudstack.backup.veeam.api.Task;
|
||||
import org.apache.cloudstack.utils.security.SSLUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
|
|
@ -47,12 +50,14 @@ 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.HttpDelete;
|
||||
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.entity.StringEntity;
|
||||
import org.apache.http.impl.auth.BasicScheme;
|
||||
import org.apache.http.impl.client.BasicAuthCache;
|
||||
import org.apache.http.impl.client.BasicCookieStore;
|
||||
|
|
@ -64,6 +69,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
|
|||
import com.cloud.utils.nio.TrustAllManager;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
|
||||
|
||||
public class VeeamClient {
|
||||
private static final Logger LOG = Logger.getLogger(VeeamClient.class);
|
||||
|
|
@ -132,8 +138,8 @@ public class VeeamClient {
|
|||
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.");
|
||||
if (!(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK || response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED) && response.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to get valid response from Veeam B&R API call, please ask your administrator to diagnose and fix issues.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,13 +156,34 @@ public class VeeamClient {
|
|||
return response;
|
||||
}
|
||||
|
||||
private HttpResponse post(final String path, final Object item) throws IOException {
|
||||
private HttpResponse post(final String path, final Object obj) throws IOException {
|
||||
String xml = null;
|
||||
if (obj != null) {
|
||||
XmlMapper xmlMapper = new XmlMapper();
|
||||
xml = xmlMapper.writer()
|
||||
.with(ToXmlGenerator.Feature.WRITE_XML_DECLARATION)
|
||||
.writeValueAsString(obj);
|
||||
// Remove invalid/empty xmlns
|
||||
xml = xml.replace(" xmlns=\"\"", "");
|
||||
}
|
||||
|
||||
final HttpPost request = new HttpPost(apiURI.toString() + path);
|
||||
request.setHeader("Content-type", "application/xml");
|
||||
if (StringUtils.isNotBlank(xml)) {
|
||||
request.setEntity(new StringEntity(xml));
|
||||
}
|
||||
|
||||
final HttpResponse response = httpClient.execute(request, httpContext);
|
||||
checkAuthFailure(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
private HttpResponse delete(final String path) throws IOException {
|
||||
final HttpResponse response = httpClient.execute(new HttpDelete(apiURI.toString() + path), httpContext);
|
||||
checkAuthFailure(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
//////////////// Public APIs: Backup /////////////////////
|
||||
//////////////////////////////////////////////////////////
|
||||
|
|
@ -180,7 +207,6 @@ public class VeeamClient {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
public List<BackupPolicy> listBackupPolicies() {
|
||||
LOG.debug("Trying to list Veeam jobs that are backup policies");
|
||||
try {
|
||||
|
|
@ -200,4 +226,47 @@ public class VeeamClient {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private Task parseTaskResponse(HttpResponse response) throws IOException {
|
||||
checkResponseOK(response);
|
||||
final ObjectMapper objectMapper = new XmlMapper();
|
||||
return objectMapper.readValue(response.getEntity().getContent(), Task.class);
|
||||
}
|
||||
|
||||
// FIXME: pass an object that implement a common interface across backup plugins
|
||||
public boolean assignBackupPolicyToVM(final String jobId, final String vmwareInstanceName, final String vcIpOrName) {
|
||||
LOG.debug("Trying to assign VM to backup policy that is a veeam job");
|
||||
try {
|
||||
//FIXME: add logic to find hierarical root based on vCenter details this is useful in env with multiple VCs
|
||||
final String heirarchyId = "dec37163-39df-4c4b-9690-899cf5543bf6";
|
||||
final CreateObjectInJobSpec vmToBackupJob = new CreateObjectInJobSpec();
|
||||
vmToBackupJob.setObjName(vmwareInstanceName);
|
||||
vmToBackupJob.setObjRef(String.format("urn:VMware:VM:%s.%s", heirarchyId, vmwareInstanceName));
|
||||
final HttpResponse response = post(String.format("/jobs/%s/includes", jobId), vmToBackupJob);
|
||||
final Task task = parseTaskResponse(response);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final HttpResponse taskResponse = get("/tasks/" + task.getTaskId());
|
||||
final Task polledTask = parseTaskResponse(taskResponse);
|
||||
if (polledTask.getState().equals("Finished")) {
|
||||
final HttpResponse taskDeleteResponse = delete("/tasks/" + task.getTaskId());
|
||||
if (taskDeleteResponse.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) {
|
||||
LOG.warn("Failed to cleanup VM assign task on veeam job for task id=" + task.getTaskId());
|
||||
}
|
||||
if (polledTask.getResult().getSuccess().equals("true")) {
|
||||
return true;
|
||||
}
|
||||
throw new CloudRuntimeException("Failed to assign VM to backup policy due to: " + polledTask.getResult().getMessage());
|
||||
}
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.debug("Failed to sleep while polling for task status due to: ", e);
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
LOG.error("Failed to list Veeam jobs due to:", e);
|
||||
checkResponseTimeOut(e);
|
||||
}
|
||||
throw new CloudRuntimeException("Failed to assign VM to backup policy likely due to timeout, please check veeam tasks");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
// 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.api;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||
|
||||
@JacksonXmlRootElement(localName = "CreateObjectInJobSpec", namespace = "http://www.veeam.com/ent/v1.0")
|
||||
public class CreateObjectInJobSpec {
|
||||
@JacksonXmlProperty(localName = "HierarchyObjRef")
|
||||
String objRef;
|
||||
|
||||
@JacksonXmlProperty(localName = "HierarchyObjName")
|
||||
String objName;
|
||||
|
||||
public String getObjRef() {
|
||||
return objRef;
|
||||
}
|
||||
|
||||
public void setObjRef(String objRef) {
|
||||
this.objRef = objRef;
|
||||
}
|
||||
|
||||
public String getObjName() {
|
||||
return objName;
|
||||
}
|
||||
|
||||
public void setObjName(String objName) {
|
||||
this.objName = objName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// 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.api;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||
|
||||
@JacksonXmlRootElement(localName = "Result")
|
||||
public class Result {
|
||||
|
||||
@JacksonXmlProperty(localName = "Success", isAttribute = true)
|
||||
private String success;
|
||||
|
||||
@JacksonXmlProperty(localName = "Message")
|
||||
private String message;
|
||||
|
||||
public String getSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(String success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// 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.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||
|
||||
@JacksonXmlRootElement(localName = "CreateObjectInJobSpec")
|
||||
public class Task {
|
||||
@JacksonXmlProperty(localName = "Type", isAttribute = true)
|
||||
private String type;
|
||||
|
||||
@JacksonXmlProperty(localName = "Href", isAttribute = true)
|
||||
private String href;
|
||||
|
||||
@JacksonXmlProperty(localName = "Link")
|
||||
@JacksonXmlElementWrapper(localName = "Links")
|
||||
private List<Link> link;
|
||||
|
||||
@JacksonXmlProperty(localName = "TaskId")
|
||||
private String taskId;
|
||||
|
||||
@JacksonXmlProperty(localName = "State")
|
||||
private String state;
|
||||
|
||||
@JacksonXmlProperty(localName = "Operation")
|
||||
private String operation;
|
||||
|
||||
@JacksonXmlProperty(localName = "Result")
|
||||
@JacksonXmlElementWrapper(localName = "Result", useWrapping = false)
|
||||
private Result result;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getHref() {
|
||||
return href;
|
||||
}
|
||||
|
||||
public void setHref(String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
public List<Link> getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
public void setLink(List<Link> link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public String getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public void setTaskId(String taskId) {
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public void setOperation(String operation) {
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public Result getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(Result result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
|
|
@ -38,4 +38,10 @@ public class VeeamClientTest {
|
|||
public void testPolicies() {
|
||||
client.listBackupPolicies();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssignVMToPolicy() {
|
||||
client.assignBackupPolicyToVM("8acac50d-3711-4c99-bf7b-76fe9c7e39c3", "i-2-9-VM", "10.2.2.52");
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue