You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2023/01/09 14:46:32 UTC

[cloudstack] branch main updated: Emc networker b&r (#6550)

This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 9009dd1db8 Emc networker b&r (#6550)
9009dd1db8 is described below

commit 9009dd1db885bdf07953cf37b26cfca7e91fe1c9
Author: fermosan <78...@users.noreply.github.com>
AuthorDate: Mon Jan 9 16:46:25 2023 +0200

    Emc networker b&r (#6550)
    
    Co-authored-by: Rohit Yadav <ro...@shapeblue.com>
---
 client/pom.xml                                     |   5 +
 plugins/backup/networker/pom.xml                   |  54 ++
 .../cloudstack/backup/NetworkerBackupProvider.java | 639 ++++++++++++++++++
 .../backup/networker/NetworkerBackupOffering.java  |  76 +++
 .../backup/networker/NetworkerClient.java          | 351 ++++++++++
 .../backup/networker/NetworkerObject.java          |  27 +
 .../cloudstack/backup/networker/api/Action.java    | 350 ++++++++++
 .../backup/networker/api/ActionSpecificData.java   | 107 +++
 .../cloudstack/backup/networker/api/Attribute.java |  92 +++
 .../backup/networker/api/BackupSpecificData.java   |  75 +++
 .../networker/api/CompletionNotification.java      |  91 +++
 .../cloudstack/backup/networker/api/Expire.java    |  47 ++
 .../cloudstack/backup/networker/api/Instance.java  | 124 ++++
 .../cloudstack/backup/networker/api/Link.java      |  91 +++
 .../backup/networker/api/NetworkerBackup.java      | 334 ++++++++++
 .../backup/networker/api/NetworkerBackups.java     |  92 +++
 .../backup/networker/api/ProtectionPolicies.java   |  92 +++
 .../backup/networker/api/ProtectionPolicy.java     | 175 +++++
 .../backup/networker/api/ResourceId.java           |  91 +++
 .../backup/networker/api/ServerBackup.java         | 140 ++++
 .../cloudstack/backup/networker/api/Size.java      |  90 +++
 .../backup/networker/api/SummaryNotification.java  |  91 +++
 .../backup/networker/api/Traditional.java          | 238 +++++++
 .../cloudstack/networker/module.properties         |  18 +
 .../networker/spring-backup-networker-context.xml  |  27 +
 .../backup/networker/NetworkerClientTest.java      | 732 +++++++++++++++++++++
 plugins/pom.xml                                    |   1 +
 scripts/vm/hypervisor/kvm/nsrkvmbackup.sh          | 260 ++++++++
 scripts/vm/hypervisor/kvm/nsrkvmrestore.sh         | 223 +++++++
 .../main/java/com/cloud/hypervisor/KVMGuru.java    | 127 +++-
 ui/public/config.json                              |   2 +-
 31 files changed, 4848 insertions(+), 14 deletions(-)

diff --git a/client/pom.xml b/client/pom.xml
index 5934b340dd..9157894ba4 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -518,6 +518,11 @@
             <artifactId>cloud-plugin-backup-dummy</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-plugin-backup-networker</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.cloudstack</groupId>
             <artifactId>cloud-plugin-integrations-kubernetes-service</artifactId>
diff --git a/plugins/backup/networker/pom.xml b/plugins/backup/networker/pom.xml
new file mode 100644
index 0000000000..4fdcdd1f62
--- /dev/null
+++ b/plugins/backup/networker/pom.xml
@@ -0,0 +1,54 @@
+<!--
+  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.
+-->
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>cloud-plugin-backup-networker</artifactId>
+    <name>Apache CloudStack Plugin - EMC Networker Backup and Recovery Plugin</name>
+    <parent>
+        <artifactId>cloudstack-plugins</artifactId>
+        <groupId>org.apache.cloudstack</groupId>
+        <version>4.18.0.0-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-plugin-hypervisor-kvm</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${cs.commons-lang3.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${cs.jackson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.tomakehurst</groupId>
+            <artifactId>wiremock-standalone</artifactId>
+            <version>${cs.wiremock.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java
new file mode 100644
index 0000000000..075b1a876d
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java
@@ -0,0 +1,639 @@
+// 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;
+
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.host.HostVO;
+import com.cloud.host.Status;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.storage.StoragePoolHostVO;
+import com.cloud.storage.Volume;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.utils.Pair;
+import com.cloud.utils.Ternary;
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallbackNoReturn;
+import com.cloud.utils.db.TransactionStatus;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.ssh.SshHelper;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.dao.VMInstanceDao;
+import org.apache.cloudstack.api.InternalIdentity;
+import org.apache.cloudstack.backup.dao.BackupDao;
+import org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl;
+import org.apache.cloudstack.backup.networker.NetworkerClient;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.log4j.Logger;
+import org.apache.xml.utils.URI;
+import org.apache.cloudstack.backup.networker.api.NetworkerBackup;
+import javax.inject.Inject;
+import java.net.URISyntaxException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Date;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import com.cloud.utils.script.Script;
+
+public class NetworkerBackupProvider extends AdapterBase implements BackupProvider, Configurable {
+
+    public static final String BACKUP_IDENTIFIER = "-CSBKP-";
+    private static final Logger LOG = Logger.getLogger(NetworkerBackupProvider.class);
+
+    public ConfigKey<String> NetworkerUrl = new ConfigKey<>("Advanced", String.class,
+            "backup.plugin.networker.url", "https://localhost:9090/nwrestapi/v3",
+            "The EMC Networker API URL.", true, ConfigKey.Scope.Zone);
+
+    private final ConfigKey<String> NetworkerUsername = new ConfigKey<>("Advanced", String.class,
+            "backup.plugin.networker.username", "administrator",
+            "The EMC Networker API username.", true, ConfigKey.Scope.Zone);
+
+    private final ConfigKey<String> NetworkerPassword = new ConfigKey<>("Secure", String.class,
+            "backup.plugin.networker.password", "password",
+            "The EMC Networker API password.", true, ConfigKey.Scope.Zone);
+
+    private final ConfigKey<String> NetworkerMediaPool = new ConfigKey<>("Advanced", String.class,
+            "backup.plugin.networker.pool", "Default",
+            "The EMC Networker Media Pool", true, ConfigKey.Scope.Zone);
+
+    private final ConfigKey<Boolean> NetworkerValidateSSLSecurity = new ConfigKey<>("Advanced", Boolean.class,
+            "backup.plugin.networker.validate.ssl", "false",
+            "Validate the SSL certificate when connecting to EMC Networker API service.", true, ConfigKey.Scope.Zone);
+
+    private final ConfigKey<Integer> NetworkerApiRequestTimeout = new ConfigKey<>("Advanced", Integer.class,
+            "backup.plugin.networker.request.timeout", "300",
+            "The EMC Networker API request timeout in seconds.", true, ConfigKey.Scope.Zone);
+
+    private final ConfigKey<Boolean> NetworkerClientVerboseLogs = new ConfigKey<>("Advanced", Boolean.class,
+            "backup.plugin.networker.client.verbosity", "false",
+            "Produce Verbose logs in Hypervisor", true, ConfigKey.Scope.Zone);
+
+    @Inject
+    private BackupDao backupDao;
+
+    @Inject
+    private HostDao hostDao;
+
+    @Inject
+    private ClusterDao clusterDao;
+
+    @Inject
+    private VolumeDao volumeDao;
+
+    @Inject
+    private StoragePoolHostDao storagePoolHostDao;
+
+    @Inject
+    private VMInstanceDao vmInstanceDao;
+
+    private static String getUrlDomain(String url) throws URISyntaxException {
+        URI uri;
+        try {
+            uri = new URI(url);
+        } catch (URI.MalformedURIException e) {
+            throw new CloudRuntimeException("Failed to cast URI");
+        }
+
+        return uri.getHost();
+    }
+
+    @Override
+    public ConfigKey<?>[] getConfigKeys() {
+        return new ConfigKey[]{
+                NetworkerUrl,
+                NetworkerUsername,
+                NetworkerPassword,
+                NetworkerValidateSSLSecurity,
+                NetworkerApiRequestTimeout,
+                NetworkerMediaPool,
+                NetworkerClientVerboseLogs
+        };
+    }
+
+    @Override
+    public String getName() {
+        return "networker";
+    }
+
+    @Override
+    public String getDescription() {
+        return "EMC Networker Backup Plugin";
+    }
+
+    @Override
+    public String getConfigComponentName() {
+        return BackupService.class.getSimpleName();
+    }
+
+    protected HostVO getLastVMHypervisorHost(VirtualMachine vm) {
+        HostVO host;
+        Long hostId = vm.getLastHostId();
+
+        if (hostId == null) {
+            LOG.debug("Cannot find last host for vm. This should never happen, please check your database.");
+            return null;
+        }
+        host = hostDao.findById(hostId);
+
+        if ( host.getStatus() == Status.Up ) {
+            return host;
+        } else {
+            // Try to find a host in the same cluster
+            List<HostVO> altClusterHosts = hostDao.findHypervisorHostInCluster(host.getClusterId());
+            for (final HostVO candidateClusterHost : altClusterHosts) {
+                if ( candidateClusterHost.getStatus() == Status.Up ) {
+                    LOG.debug("Found Host " + candidateClusterHost.getName());
+                    return candidateClusterHost;
+                }
+            }
+        }
+        // Try to find a Host in the zone
+        List<HostVO> altZoneHosts = hostDao.findByDataCenterId(host.getDataCenterId());
+        for (final HostVO candidateZoneHost : altZoneHosts) {
+            if ( candidateZoneHost.getStatus() == Status.Up && candidateZoneHost.getHypervisorType() == Hypervisor.HypervisorType.KVM ) {
+                LOG.debug("Found Host " + candidateZoneHost.getName());
+                return candidateZoneHost;
+            }
+        }
+        return null;
+    }
+
+    protected HostVO getRunningVMHypervisorHost(VirtualMachine vm) {
+
+        HostVO host;
+        Long hostId = vm.getHostId();
+
+        if (hostId == null) {
+            throw new CloudRuntimeException("Unable to find the HYPERVISOR for " + vm.getName() + ". Make sure the virtual machine is running");
+        }
+
+        host = hostDao.findById(hostId);
+
+        return host;
+    }
+
+    protected String getVMHypervisorCluster(HostVO host) {
+
+        return clusterDao.findById(host.getClusterId()).getName();
+    }
+
+    protected Ternary<String, String, String> getKVMHyperisorCredentials(HostVO host) {
+
+        String username = null;
+        String password = null;
+
+        if (host != null && host.getHypervisorType() == Hypervisor.HypervisorType.KVM) {
+            hostDao.loadDetails(host);
+            password = host.getDetail("password");
+            username = host.getDetail("username");
+        }
+        if ( password == null  || username == null) {
+            throw new CloudRuntimeException("Cannot find login credentials for HYPERVISOR " + Objects.requireNonNull(host).getUuid());
+        }
+
+        return new Ternary<>(username, password, null);
+    }
+
+    private String executeBackupCommand(HostVO host, String username, String password, String command) {
+        String nstRegex = "\\bcompleted savetime=([0-9]{10})";
+        Pattern saveTimePattern = Pattern.compile(nstRegex);
+
+        try {
+            Pair<Boolean, String> response = SshHelper.sshExecute(host.getPrivateIpAddress(), 22,
+                    username, null, password, command, 120000, 120000, 3600000);
+            if (!response.first()) {
+                LOG.error(String.format("Backup Script failed on HYPERVISOR %s due to: %s", host, response.second()));
+            } else {
+                LOG.debug(String.format("Networker Backup Results: %s", response.second()));
+            }
+            Matcher saveTimeMatcher = saveTimePattern.matcher(response.second());
+            if (saveTimeMatcher.find()) {
+                LOG.debug(String.format("Got saveTimeMatcher: %s", saveTimeMatcher.group(1)));
+                return saveTimeMatcher.group(1);
+            }
+        } catch (final Exception e) {
+            throw new CloudRuntimeException(String.format("Failed to take backup on host %s due to: %s", host.getName(), e.getMessage()));
+        }
+
+        return null;
+    }
+    private boolean executeRestoreCommand(HostVO host, String username, String password, String command) {
+
+        try {
+            Pair<Boolean, String> response = SshHelper.sshExecute(host.getPrivateIpAddress(), 22,
+                username, null, password, command, 120000, 120000, 3600000);
+
+            if (!response.first()) {
+                LOG.error(String.format("Restore Script failed on HYPERVISOR %s due to: %s", host, response.second()));
+            } else {
+                LOG.debug(String.format("Networker Restore Results: %s",response.second()));
+                return true;
+            }
+        } catch (final Exception e) {
+            throw new CloudRuntimeException(String.format("Failed to restore backup on host %s due to: %s", host.getName(), e.getMessage()));
+        }
+        return false;
+    }
+
+    private NetworkerClient getClient(final Long zoneId) {
+        try {
+            return new NetworkerClient(NetworkerUrl.valueIn(zoneId), NetworkerUsername.valueIn(zoneId), NetworkerPassword.valueIn(zoneId),
+                    NetworkerValidateSSLSecurity.valueIn(zoneId), NetworkerApiRequestTimeout.valueIn(zoneId));
+        } catch (URISyntaxException e) {
+            throw new CloudRuntimeException("Failed to parse EMC Networker API URL: " + e.getMessage());
+        } catch (NoSuchAlgorithmException | KeyManagementException e) {
+            LOG.error("Failed to build EMC Networker API client due to: ", e);
+        }
+        throw new CloudRuntimeException("Failed to build EMC Networker API client");
+    }
+
+    @Override
+    public List<BackupOffering> listBackupOfferings(Long zoneId) {
+        List<BackupOffering> policies = new ArrayList<>();
+        for (final BackupOffering policy : getClient(zoneId).listPolicies()) {
+            if (!policy.getName().contains(BACKUP_IDENTIFIER)) {
+                policies.add(policy);
+            }
+        }
+
+        return policies;
+    }
+
+    @Override
+    public boolean isValidProviderOffering(Long zoneId, String uuid) {
+        List<BackupOffering> policies = listBackupOfferings(zoneId);
+        if (CollectionUtils.isEmpty(policies)) {
+            return false;
+        }
+        for (final BackupOffering policy : policies) {
+            if (Objects.equals(policy.getExternalId(), uuid)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean assignVMToBackupOffering(VirtualMachine vm, BackupOffering backupOffering) { return true; }
+
+    @Override
+    public boolean removeVMFromBackupOffering(VirtualMachine vm) {
+        LOG.debug("Removing VirtualMachine from Backup offering and Deleting any existing backups");
+
+        List<String> backupsTaken = getClient(vm.getDataCenterId()).getBackupsForVm(vm);
+
+        for (String backupId : backupsTaken) {
+            LOG.debug("Trying to remove backup with id" + backupId);
+            getClient(vm.getDataCenterId()).deleteBackupForVM(backupId);
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
+        String networkerServer;
+        HostVO hostVO;
+
+        final Long zoneId = backup.getZoneId();
+        final String externalBackupId = backup.getExternalId();
+        final NetworkerBackup networkerBackup=getClient(zoneId).getNetworkerBackupInfo(externalBackupId);
+        final String SSID = networkerBackup.getShortId();
+
+        LOG.debug("Restoring vm " + vm.getUuid() + "from backup " + backup.getUuid() + " on the Networker Backup Provider");
+
+        if ( SSID.isEmpty() ) {
+            LOG.debug("There was an error retrieving the SSID for backup with id " + externalBackupId + " from EMC NEtworker");
+            return false;
+        }
+
+        // Find where the VM was last running
+        hostVO = getLastVMHypervisorHost(vm);
+        // Get credentials for that host
+        Ternary<String, String, String> credentials = getKVMHyperisorCredentials(hostVO);
+        LOG.debug("The SSID was reported successfully " + externalBackupId);
+        try {
+            networkerServer = getUrlDomain(NetworkerUrl.value());
+        } catch (URISyntaxException e) {
+            throw new CloudRuntimeException(String.format("Failed to convert API to HOST : %s", e));
+        }
+        String networkerRestoreScr = "/usr/share/cloudstack-common/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh";
+        final Script script = new Script(networkerRestoreScr);
+        script.add("-s");
+        script.add(networkerServer);
+        script.add("-S");
+        script.add(SSID);
+
+        if ( Boolean.TRUE.equals(NetworkerClientVerboseLogs.value()) )
+            script.add("-v");
+
+        Date restoreJobStart = new Date();
+        LOG.debug("Starting Restore for VM ID " + vm.getUuid() + " and SSID" + SSID + " at " + restoreJobStart);
+
+        if ( executeRestoreCommand(hostVO, credentials.first(), credentials.second(), script.toString()) ) {
+            Date restoreJobEnd = new Date();
+            LOG.debug("Restore Job for SSID " + SSID + " completed successfully at " + restoreJobEnd);
+            return true;
+        } else {
+            LOG.debug("Restore Job for SSID " + SSID + " failed!");
+            return false;
+        }
+    }
+
+    @Override
+    public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid) {
+        String networkerServer;
+        VolumeVO volume = volumeDao.findByUuid(volumeUuid);
+        VMInstanceVO backupSourceVm = vmInstanceDao.findById(backup.getVmId());
+        StoragePoolHostVO dataStore = storagePoolHostDao.findByUuid(dataStoreUuid);
+        HostVO hostVO = hostDao.findByIp(hostIp);
+
+        final Long zoneId = backup.getZoneId();
+        final String externalBackupId = backup.getExternalId();
+        final NetworkerBackup networkerBackup=getClient(zoneId).getNetworkerBackupInfo(externalBackupId);
+        final String SSID = networkerBackup.getShortId();
+        final String clusterName = networkerBackup.getClientHostname();
+        final String destinationNetworkerClient = hostVO.getName().split("\\.")[0];
+        Long restoredVolumeDiskSize = 0L;
+
+        LOG.debug("Restoring volume " + volumeUuid + "from backup " + backup.getUuid() + " on the Networker Backup Provider");
+
+        if ( SSID.isEmpty() ) {
+            LOG.debug("There was an error retrieving the SSID for backup with id " + externalBackupId + " from EMC NEtworker");
+            return null;
+        }
+
+        Ternary<String, String, String> credentials = getKVMHyperisorCredentials(hostVO);
+        LOG.debug("The SSID was reported successfully " + externalBackupId);
+        try {
+            networkerServer = getUrlDomain(NetworkerUrl.value());
+        } catch (URISyntaxException e) {
+            throw new CloudRuntimeException(String.format("Failed to convert API to HOST : %s", e));
+        }
+
+        // Find volume size  from backup vols
+        for ( Backup.VolumeInfo VMVolToRestore : backupSourceVm.getBackupVolumeList()) {
+            if (VMVolToRestore.getUuid().equals(volumeUuid))
+                restoredVolumeDiskSize = (VMVolToRestore.getSize());
+        }
+
+        VolumeVO restoredVolume = new VolumeVO(Volume.Type.DATADISK, null, backup.getZoneId(),
+                backup.getDomainId(), backup.getAccountId(), 0, null,
+                backup.getSize(), null, null, null);
+
+        restoredVolume.setName("RV-"+volume.getName());
+        restoredVolume.setProvisioningType(volume.getProvisioningType());
+        restoredVolume.setUpdated(new Date());
+        restoredVolume.setUuid(UUID.randomUUID().toString());
+        restoredVolume.setRemoved(null);
+        restoredVolume.setDisplayVolume(true);
+        restoredVolume.setPoolId(volume.getPoolId());
+        restoredVolume.setPath(restoredVolume.getUuid());
+        restoredVolume.setState(Volume.State.Copying);
+        restoredVolume.setSize(restoredVolumeDiskSize);
+        restoredVolume.setDiskOfferingId(volume.getDiskOfferingId());
+
+        try {
+            volumeDao.persist(restoredVolume);
+        } catch (Exception e) {
+            throw new CloudRuntimeException("Unable to craft restored volume due to: "+e);
+        }
+        String networkerRestoreScr = "/usr/share/cloudstack-common/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh";
+        final Script script = new Script(networkerRestoreScr);
+        script.add("-s");
+        script.add(networkerServer);
+        script.add("-c");
+        script.add(clusterName);
+        script.add("-d");
+        script.add(destinationNetworkerClient);
+        script.add("-n");
+        script.add(restoredVolume.getUuid());
+        script.add("-p");
+        script.add(dataStore.getLocalPath());
+        script.add("-a");
+        script.add(volume.getUuid());
+
+        if ( Boolean.TRUE.equals(NetworkerClientVerboseLogs.value()) )
+            script.add("-v");
+
+        Date restoreJobStart = new Date();
+        LOG.debug("Starting Restore for Volume UUID " + volume.getUuid() + " and SSID" + SSID + " at " + restoreJobStart);
+
+        if ( executeRestoreCommand(hostVO, credentials.first(), credentials.second(), script.toString()) ) {
+            Date restoreJobEnd = new Date();
+            LOG.debug("Restore Job for SSID " + SSID + " completed successfully at " + restoreJobEnd);
+            return new Pair<>(true,restoredVolume.getUuid());
+        } else {
+            volumeDao.expunge(restoredVolume.getId());
+            LOG.debug("Restore Job for SSID " + SSID + " failed!");
+            return null;
+        }
+    }
+
+    @Override
+    public boolean takeBackup(VirtualMachine vm) {
+        String networkerServer;
+        String clusterName;
+
+        try {
+            networkerServer = getUrlDomain(NetworkerUrl.value());
+        } catch (URISyntaxException e) {
+            throw new CloudRuntimeException(String.format("Failed to convert API to HOST : %s", e));
+        }
+
+        // Find where the VM is currently running
+        HostVO hostVO = getRunningVMHypervisorHost(vm);
+        // Get credentials for that host
+        Ternary<String, String, String> credentials = getKVMHyperisorCredentials(hostVO);
+        // Get retention Period for our Backup
+        BackupOfferingVO vmBackupOffering = new BackupOfferingDaoImpl().findById(vm.getBackupOfferingId());
+        final String backupProviderPolicyId = vmBackupOffering.getExternalId();
+        String backupRentionPeriod = getClient(vm.getDataCenterId()).getBackupPolicyRetentionInterval(backupProviderPolicyId);
+
+        if ( backupRentionPeriod == null ) {
+            LOG.warn("There is no retention setting for Emc Networker Policy, setting default for 1 day");
+            backupRentionPeriod = "1 Day";
+        }
+
+        // Get Cluster
+        clusterName = getVMHypervisorCluster(hostVO);
+        String networkerBackupScr = "/usr/share/cloudstack-common/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh";
+        final Script script = new Script(networkerBackupScr);
+        script.add("-s");
+        script.add(networkerServer);
+        script.add("-R");
+        script.add("'"+backupRentionPeriod+"'");
+        script.add("-P");
+        script.add(NetworkerMediaPool.valueIn(vm.getDataCenterId()));
+        script.add("-c");
+        script.add(clusterName);
+        script.add("-u");
+        script.add(vm.getUuid());
+        script.add("-t");
+        script.add(vm.getName());
+        if ( Boolean.TRUE.equals(NetworkerClientVerboseLogs.value()) )
+            script.add("-v");
+
+        LOG.debug("Starting backup for VM ID " + vm.getUuid() + " on Networker provider");
+        Date backupJobStart = new Date();
+
+        String saveTime = executeBackupCommand(hostVO, credentials.first(), credentials.second(), script.toString());
+        LOG.info ("EMC Networker finished backup job for vm " + vm.getName() + " with saveset Time: " + saveTime);
+        BackupVO backup = getClient(vm.getDataCenterId()).registerBackupForVm(vm, backupJobStart, saveTime);
+        if (backup != null) {
+            backupDao.persist(backup);
+            return true;
+        } else {
+            LOG.error("Could not register backup for vm " + vm.getName() + " with saveset Time: " + saveTime);
+            // We need to handle this rare situation where backup is successful but can't be registered properly.
+            return false;
+        }
+    }
+
+    @Override
+    public boolean deleteBackup(Backup backup, boolean forced) {
+
+        final Long zoneId = backup.getZoneId();
+        final String externalBackupId = backup.getExternalId();
+
+        if (getClient(zoneId).deleteBackupForVM(externalBackupId)) {
+            LOG.debug("EMC Networker successfully deleted backup with id " + externalBackupId);
+            return true;
+        } else {
+            LOG.debug("There was an error removing the backup with id " + externalBackupId + " from EMC NEtworker");
+        }
+        return false;
+    }
+
+    @Override
+    public Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<VirtualMachine> vms) {
+        final Map<VirtualMachine, Backup.Metric> metrics = new HashMap<>();
+        Long vmBackupSize=0L;
+        Long vmBackupProtectedSize=0L;
+
+        if (CollectionUtils.isEmpty(vms)) {
+            LOG.warn("Unable to get VM Backup Metrics because the list of VMs is empty.");
+            return metrics;
+        }
+
+        for (final VirtualMachine vm : vms) {
+            for ( Backup.VolumeInfo thisVMVol : vm.getBackupVolumeList()) {
+                vmBackupSize += (thisVMVol.getSize() / 1024L / 1024L);
+            }
+            final ArrayList<String> vmBackups = getClient(zoneId).getBackupsForVm(vm);
+            for ( String vmBackup : vmBackups ) {
+                NetworkerBackup vmNwBackup = getClient(zoneId).getNetworkerBackupInfo(vmBackup);
+                vmBackupProtectedSize+= vmNwBackup.getSize().getValue() / 1024L;
+            }
+            Backup.Metric vmBackupMetric = new Backup.Metric(vmBackupSize,vmBackupProtectedSize);
+            LOG.debug(String.format("Metrics for VM [uuid: %s, name: %s] is [backup size: %s, data size: %s].", vm.getUuid(),
+                    vm.getInstanceName(), vmBackupMetric.getBackupSize(), vmBackupMetric.getDataSize()));
+            metrics.put(vm, vmBackupMetric);
+        }
+        return metrics;
+    }
+
+    @Override
+    public void syncBackups(VirtualMachine vm, Backup.Metric metric) {
+        final Long zoneId = vm.getDataCenterId();
+        Transaction.execute(new TransactionCallbackNoReturn() {
+            @Override
+            public void doInTransactionWithoutResult(TransactionStatus status) {
+                final List<Backup> backupsInDb = backupDao.listByVmId(null, vm.getId());
+                final ArrayList<String> backupsInNetworker = getClient(zoneId).getBackupsForVm(vm);
+                final List<Long> removeList = backupsInDb.stream().map(InternalIdentity::getId).collect(Collectors.toList());
+                for (final String networkerBackupId : backupsInNetworker ) {
+                    Long vmBackupSize=0L;
+                    boolean backupExists = false;
+                    for (final Backup backupInDb : backupsInDb) {
+                        LOG.debug("Checking if Backup with external ID " + backupInDb.getName() + " for VM " + backupInDb.getVmId() + "is valid");
+                        if ( networkerBackupId.equals(backupInDb.getExternalId()) ) {
+                            LOG.debug("Found Backup with id " + backupInDb.getId() + " in both Database and Networker");
+                            backupExists = true;
+                            removeList.remove(backupInDb.getId());
+                            if (metric != null) {
+                                LOG.debug(String.format("Update backup with [uuid: %s, external id: %s] from [size: %s, protected size: %s] to [size: %s, protected size: %s].",
+                                        backupInDb.getUuid(), backupInDb.getExternalId(), backupInDb.getSize(), backupInDb.getProtectedSize(),
+                                        metric.getBackupSize(), metric.getDataSize()));
+                                ((BackupVO) backupInDb).setSize(metric.getBackupSize());
+                                ((BackupVO) backupInDb).setProtectedSize(metric.getDataSize());
+                                backupDao.update(backupInDb.getId(), ((BackupVO) backupInDb));
+                            }
+                            break;
+                        }
+                    }
+                    if (backupExists) {
+                        continue;
+                    }
+                    // Technically an administrator can manually create a backup for a VM by utilizing the KVM scripts
+                    // with the proper parameters. So we will register any backups taken on the Networker side from
+                    // outside Cloudstack. If ever Networker will support KVM out of the box this functionality also will
+                    // ensure that SLA like backups will be found and registered.
+                    NetworkerBackup strayNetworkerBackup = getClient(vm.getDataCenterId()).getNetworkerBackupInfo(networkerBackupId);
+                    // Since running backups are already present in Networker Server but not completed
+                    // make sure the backup is not in progress at this time.
+                    if ( strayNetworkerBackup.getCompletionTime() != null) {
+                        BackupVO strayBackup = new BackupVO();
+                        strayBackup.setVmId(vm.getId());
+                        strayBackup.setExternalId(strayNetworkerBackup.getId());
+                        strayBackup.setType(strayNetworkerBackup.getType());
+                        strayBackup.setDate(strayNetworkerBackup.getSaveTime());
+                        strayBackup.setStatus(Backup.Status.BackedUp);
+                        for ( Backup.VolumeInfo thisVMVol : vm.getBackupVolumeList()) {
+                            vmBackupSize += (thisVMVol.getSize() / 1024L /1024L);
+                        }
+                        strayBackup.setSize(vmBackupSize);
+                        strayBackup.setProtectedSize(strayNetworkerBackup.getSize().getValue() / 1024L );
+                        strayBackup.setBackupOfferingId(vm.getBackupOfferingId());
+                        strayBackup.setAccountId(vm.getAccountId());
+                        strayBackup.setDomainId(vm.getDomainId());
+                        strayBackup.setZoneId(vm.getDataCenterId());
+                        LOG.debug(String.format("Creating a new entry in backups: [uuid: %s, vm_id: %s, external_id: %s, type: %s, date: %s, backup_offering_id: %s, account_id: %s, "
+                                        + "domain_id: %s, zone_id: %s].", strayBackup.getUuid(), strayBackup.getVmId(), strayBackup.getExternalId(),
+                                strayBackup.getType(), strayBackup.getDate(), strayBackup.getBackupOfferingId(), strayBackup.getAccountId(),
+                                strayBackup.getDomainId(), strayBackup.getZoneId()));
+                        backupDao.persist(strayBackup);
+                        LOG.warn("Added backup found in provider with ID: [" + strayBackup.getId() + "]");
+                    } else {
+                        LOG.debug ("Backup is in progress, skipping addition for this run");
+                    }
+                }
+                for (final Long backupIdToRemove : removeList) {
+                    LOG.warn(String.format("Removing backup with ID: [%s].", backupIdToRemove));
+                    backupDao.remove(backupIdToRemove);
+                }
+            }
+        });
+    }
+
+    @Override
+    public boolean willDeleteBackupsOnOfferingRemoval() { return false; }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerBackupOffering.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerBackupOffering.java
new file mode 100644
index 0000000000..896b4e32a1
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerBackupOffering.java
@@ -0,0 +1,76 @@
+// 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.networker;
+
+import org.apache.cloudstack.backup.BackupOffering;
+import java.util.Date;
+
+public class NetworkerBackupOffering implements BackupOffering {
+
+    private String name;
+    private String uid;
+
+    public NetworkerBackupOffering(String name, String uid) {
+        this.name = name;
+        this.uid = uid;
+    }
+
+    @Override
+    public String getExternalId() {
+        return uid;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getDescription() {
+        return "EMC Networker Backup Offering (Job)";
+    }
+
+    @Override
+    public long getZoneId() {
+        return -1;
+    }
+
+    @Override
+    public boolean isUserDrivenBackupAllowed() {
+        return false;
+    }
+
+    @Override
+    public String getProvider() {
+        return "networker";
+    }
+
+    @Override
+    public Date getCreated() {
+        return null;
+    }
+
+    @Override
+    public String getUuid() {
+        return uid;
+    }
+
+    @Override
+    public long getId() {
+        return -1;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerClient.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerClient.java
new file mode 100644
index 0000000000..c99a68cf30
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerClient.java
@@ -0,0 +1,351 @@
+// 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.networker;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.nio.TrustAllManager;
+import com.cloud.vm.VirtualMachine;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.backup.BackupOffering;
+import org.apache.cloudstack.backup.BackupVO;
+import org.apache.cloudstack.backup.networker.api.NetworkerBackup;
+import org.apache.cloudstack.backup.networker.api.NetworkerBackups;
+import org.apache.cloudstack.backup.networker.api.ProtectionPolicies;
+import org.apache.cloudstack.backup.networker.api.ProtectionPolicy;
+import org.apache.cloudstack.utils.security.SSLUtils;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+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.conn.ConnectTimeoutException;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.log4j.Logger;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.X509TrustManager;
+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.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Date;
+import java.util.List;
+
+import static org.apache.cloudstack.backup.NetworkerBackupProvider.BACKUP_IDENTIFIER;
+
+public class NetworkerClient {
+    private static final Logger LOG = Logger.getLogger(NetworkerClient.class);
+    private final URI apiURI;
+    private final String apiName;
+    private final String apiPassword;
+    private final HttpClient httpClient;
+
+    public NetworkerClient(final String url, final String username, final String password, final boolean validateCertificate, final int timeout) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
+
+        apiName = username;
+        apiPassword = password;
+
+        this.apiURI = new URI(url);
+        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()
+                    .setDefaultRequestConfig(config)
+                    .setSSLSocketFactory(factory)
+                    .build();
+        } else {
+            this.httpClient = HttpClientBuilder.create()
+                    .setDefaultRequestConfig(config)
+                    .build();
+        }
+
+        authenticate(username, password);
+    }
+
+    private void authenticate(final String username, final String password) {
+
+        final HttpGet request = new HttpGet(apiURI.toString());
+        request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes()));
+        request.setHeader(HttpHeaders.ACCEPT, "application/json");
+        request.setHeader(HttpHeaders.USER_AGENT, "CloudStack B&R");
+        request.setHeader(HttpHeaders.CONNECTION, "keep-alive");
+        try {
+            final HttpResponse response = httpClient.execute(request);
+            checkAuthFailure(response);
+            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+                throw new CloudRuntimeException("Failed to create and authenticate EMC Networker API client, please check the settings.");
+            }
+        } catch (final IOException e) {
+            throw new CloudRuntimeException("Failed to authenticate Networker API service due to:" + e.getMessage());
+        }
+    }
+
+    private void checkAuthFailure(final HttpResponse response) {
+        if (response != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
+            throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, "EMC Networker B&R API call unauthorized. Check username/password or contact your backup administrator.");
+        }
+    }
+
+    private void checkResponseOK(final HttpResponse response) {
+        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NO_CONTENT) {
+            LOG.debug("Requested EMC Networker resource does not exist");
+            return;
+        }
+        if (!(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK ||
+                response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED) &&
+                response.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) {
+            LOG.debug(String.format("HTTP request failed, status code is [%s], response is: [%s].", response.getStatusLine().getStatusCode(), response));
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Got invalid API status code returned by the EMC Networker server");
+        }
+    }
+
+    private void checkResponseTimeOut(final Exception e) {
+        if (e instanceof ConnectTimeoutException || e instanceof SocketTimeoutException) {
+            throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, "EMC Networker API operation timed out, please try again.");
+        }
+    }
+
+    private HttpResponse get(final String path) throws IOException {
+        String url = apiURI.toString() + path;
+        final HttpGet request = new HttpGet(url);
+        request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((apiName + ":" + apiPassword).getBytes()));
+        request.setHeader(HttpHeaders.ACCEPT, "application/json");
+        request.setHeader(HttpHeaders.USER_AGENT, "CloudStack B&R");
+        final HttpResponse response = httpClient.execute(request);
+        checkAuthFailure(response);
+
+        LOG.debug(String.format("Response received in GET request is: [%s] for URL: [%s].", response.toString(), url));
+        return response;
+    }
+
+    public  String getBackupPolicyRetentionInterval(String externalId) {
+        try {
+            final HttpResponse response = get("/global/protectionpolicies/?q=comment:" + BACKUP_IDENTIFIER);
+            checkResponseOK(response);
+            final ObjectMapper jsonMapper = new ObjectMapper();
+            jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+            final ProtectionPolicies protectionPolicies = jsonMapper.readValue(response.getEntity().getContent(), ProtectionPolicies.class);
+
+            if (protectionPolicies == null || protectionPolicies.getProtectionPolicies() == null) {
+                return null;
+            }
+            for (final ProtectionPolicy protectionPolicy : protectionPolicies.getProtectionPolicies()) {
+                if ( protectionPolicy.getResourceId().getId().equals(externalId)) {
+                    return protectionPolicy.getPolicyProtectionPeriod();
+                }
+            }
+        } catch (final IOException e) {
+            LOG.error("Failed to get Protection Policy Period from EMC Networker due to:", e);
+            checkResponseTimeOut(e);
+        }
+        return null;
+    }
+    private HttpResponse delete(final String path) throws IOException {
+        String url = apiURI.toString() + path;
+        final HttpDelete request = new HttpDelete(url);
+        request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((apiName + ":" + apiPassword).getBytes()));
+        request.setHeader(HttpHeaders.USER_AGENT, "CloudStack B&R");
+        final HttpResponse response = httpClient.execute(request);
+        checkAuthFailure(response);
+
+        LOG.debug(String.format("Response received in DELETE request is: [%s] for URL [%s].", response.toString(), url));
+        return response;
+    }
+
+    public boolean deleteBackupForVM(String externalId) {
+        try {
+            final HttpResponse response = delete("/global/backups/" + externalId);
+            checkResponseOK(response);
+            return true;
+        } catch (final IOException e) {
+            LOG.error("Failed to delete backup from EMC Networker due to:", e);
+            checkResponseTimeOut(e);
+        }
+        return false;
+    }
+
+
+    public BackupVO registerBackupForVm(VirtualMachine vm, Date backupJobStart, String saveTime) {
+        LOG.debug("Querying EMC Networker about latest backup");
+
+        NetworkerBackups networkerBackups;
+        BackupVO backup = new BackupVO();
+
+        SimpleDateFormat formatterDate = new SimpleDateFormat("yyyy-MM-dd");
+        SimpleDateFormat formatterTime = new SimpleDateFormat("HH:mm:ss");
+        SimpleDateFormat formatterDateTime = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
+
+        String startDate = formatterDate.format(backupJobStart);
+        String startTime = formatterTime.format(backupJobStart);
+        String endDate = formatterDate.format(new Date());
+        String endTime = formatterTime.format(new Date());
+
+        final String searchRange = "['" + startDate + "T" + startTime + "'+TO+'" + endDate + "T" + endTime + "']";
+        String backupJobCriteria;
+
+        try {
+            if ( saveTime != null ) {
+                Instant instant = Instant.ofEpochSecond(Long.parseLong(saveTime));
+                String completionTime = formatterDateTime.format(Date.from(instant));
+                backupJobCriteria = "+and+saveTime:" + "'" + completionTime + "'";
+            }
+            else {
+                backupJobCriteria = "+and+saveTime:" + searchRange;
+            }
+            final HttpResponse response = get("/global/backups/?q=name:" + vm.getName() + backupJobCriteria);
+            checkResponseOK(response);
+            final ObjectMapper jsonMapper = new ObjectMapper();
+            jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+            networkerBackups = jsonMapper.readValue(response.getEntity().getContent(), NetworkerBackups.class);
+            NetworkerBackup networkerLatestBackup = new NetworkerBackup();
+            LOG.debug("Found backups " + networkerBackups.getBackups() + " With Criteria: " + backupJobCriteria);
+            if ( networkerBackups.getBackups() == null || networkerBackups.getCount() == 0 ) {
+                return null;
+            }
+            if (networkerBackups.getCount() == 1) {
+                networkerLatestBackup = networkerBackups.getBackups().get(0);
+            } else {
+                for (final NetworkerBackup networkerBackup : networkerBackups.getBackups()) {
+                    LOG.debug("Found Backup :" + networkerBackup.getName());
+                }
+            }
+
+            backup.setVmId(vm.getId());
+            backup.setExternalId(networkerLatestBackup.getId());
+            backup.setType(networkerLatestBackup.getType());
+            backup.setDate(networkerLatestBackup.getCreationTime());
+            backup.setSize(networkerLatestBackup.getSize().getValue());
+            backup.setProtectedSize(networkerLatestBackup.getSize().getValue());
+            backup.setStatus(org.apache.cloudstack.backup.Backup.Status.BackedUp);
+            backup.setBackupOfferingId(vm.getBackupOfferingId());
+            backup.setAccountId(vm.getAccountId());
+            backup.setDomainId(vm.getDomainId());
+            backup.setZoneId(vm.getDataCenterId());
+            return backup;
+        } catch (final IOException e) {
+            LOG.error("Failed to register backup from EMC Networker due to:", e);
+            checkResponseTimeOut(e);
+        }
+        return null;
+    }
+
+
+    public NetworkerBackup getNetworkerBackupInfo(String backupId) {
+        LOG.debug("Trying to get EMC Networker details for backup " + backupId);
+        try {
+            final HttpResponse response = get("/global/backups/?q=id:" + backupId);
+            checkResponseOK(response);
+            final ObjectMapper jsonMapper = new ObjectMapper();
+            jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+            NetworkerBackups networkerBackups = jsonMapper.readValue(response.getEntity().getContent(), NetworkerBackups.class);
+            NetworkerBackup networkerBackup = networkerBackups.getBackups().get(0);
+            if ( networkerBackup.getShortId() == null ) {
+                return null;
+            }
+            return networkerBackup;
+        } catch (final IOException e) {
+            LOG.error("Failed to list EMC Networker backups due to:", e);
+            checkResponseTimeOut(e);
+        }
+        return null;
+    }
+    public ArrayList<String> getBackupsForVm(VirtualMachine vm) {
+        SimpleDateFormat formatterDateTime = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
+
+        LOG.debug("Trying to list EMC Networker backups for VM " + vm.getName());
+        try {
+            final HttpResponse response = get("/global/backups/?q=name:" + vm.getName());
+            checkResponseOK(response);
+            final ObjectMapper jsonMapper = new ObjectMapper();
+            jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+            NetworkerBackups networkerBackups = jsonMapper.readValue(response.getEntity().getContent(), NetworkerBackups.class);
+            final ArrayList<String> backupsTaken = new ArrayList<>();
+            if (networkerBackups == null || networkerBackups.getBackups() == null) {
+                return backupsTaken;
+            }
+            for (final NetworkerBackup backup : networkerBackups.getBackups()) {
+                LOG.debug("Found Backup " + backup.getId());
+                // Backups that have expired on the EMC Networker but not removed yet will not be added
+                try {
+                    Date backupRetentionTime = formatterDateTime.parse(backup.getRetentionTime());
+                    Date currentTime = new Date();
+                    if (currentTime.compareTo(backupRetentionTime) < 0) {
+                        backupsTaken.add(backup.getId());
+                    }
+                } catch (ParseException e) {
+                    throw new RuntimeException("Failed to parse EMC Networker backup retention time:  "+ e);
+                }
+            }
+            return backupsTaken;
+        } catch (final IOException e) {
+            LOG.error("Failed to list EMC Networker backups due to:", e);
+            checkResponseTimeOut(e);
+        }
+        return new ArrayList<>();
+    }
+    public List<BackupOffering> listPolicies() {
+        LOG.debug("Trying to list backup EMC Networker Policies we can use");
+        try {
+            final HttpResponse response = get("/global/protectionpolicies/?q=comment:" + BACKUP_IDENTIFIER);
+            checkResponseOK(response);
+            final ObjectMapper jsonMapper = new ObjectMapper();
+            jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+            final ProtectionPolicies protectionPolicies = jsonMapper.readValue(response.getEntity().getContent(), ProtectionPolicies.class);
+
+            final List<BackupOffering> policies = new ArrayList<>();
+
+            if (protectionPolicies == null || protectionPolicies.getProtectionPolicies() == null) {
+                return policies;
+            }
+            for (final ProtectionPolicy protectionPolicy : protectionPolicies.getProtectionPolicies()) {
+                LOG.debug("Found Protection Policy:" + protectionPolicy.getName());
+                policies.add(new NetworkerBackupOffering(protectionPolicy.getName(), protectionPolicy.getResourceId().getId()));
+            }
+            return policies;
+        } catch (final IOException e) {
+            LOG.error("Failed to list EMC Networker Protection Policies jobs due to:", e);
+            checkResponseTimeOut(e);
+        }
+        return new ArrayList<>();
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerObject.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerObject.java
new file mode 100644
index 0000000000..60b500934b
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerObject.java
@@ -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.networker;
+
+import java.util.List;
+
+public interface NetworkerObject {
+    String getUuid();
+    String getName();
+    String getHref();
+    String getType();
+    List<NetworkerObject> getLinks();
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Action.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Action.java
new file mode 100644
index 0000000000..93c435c1d4
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Action.java
@@ -0,0 +1,350 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+import java.util.List;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "actionReferSchedule",
+        "actionSpecificData",
+        "comment",
+        "completionNotification",
+        "concurrent",
+        "drivenBy",
+        "enabled",
+        "failureImpact",
+        "hardLimit",
+        "inactivityTimeoutInMin",
+        "name",
+        "parallelism",
+        "retries",
+        "retryDelayInSec",
+        "softLimit",
+        "scheduleActivities",
+        "scheduleOverrides",
+        "schedulePeriod"
+})
+@Generated("jsonschema2pojo")
+public class Action implements Serializable {
+
+    private final static long serialVersionUID = 1750989315434884936L;
+    @JsonProperty("actionReferSchedule")
+    private String actionReferSchedule;
+    @JsonProperty("actionSpecificData")
+    private ActionSpecificData actionSpecificData;
+    @JsonProperty("comment")
+    private String comment;
+    @JsonProperty("completionNotification")
+    private CompletionNotification completionNotification;
+    @JsonProperty("concurrent")
+    private Boolean concurrent;
+    @JsonProperty("drivenBy")
+    private String drivenBy;
+    @JsonProperty("enabled")
+    private Boolean enabled;
+    @JsonProperty("failureImpact")
+    private String failureImpact;
+    @JsonProperty("hardLimit")
+    private String hardLimit;
+    @JsonProperty("inactivityTimeoutInMin")
+    private Integer inactivityTimeoutInMin;
+    @JsonProperty("name")
+    private String name;
+    @JsonProperty("parallelism")
+    private Integer parallelism;
+    @JsonProperty("retries")
+    private Integer retries;
+    @JsonProperty("retryDelayInSec")
+    private Integer retryDelayInSec;
+    @JsonProperty("softLimit")
+    private String softLimit;
+    @JsonProperty("scheduleActivities")
+    private List<String> scheduleActivities = null;
+    @JsonProperty("scheduleOverrides")
+    private List<Object> scheduleOverrides = null;
+    @JsonProperty("schedulePeriod")
+    private String schedulePeriod;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Action() {
+    }
+
+    /**
+     * @param failureImpact
+     * @param actionSpecificData
+     * @param completionNotification
+     * @param parallelism
+     * @param concurrent
+     * @param retryDelayInSec
+     * @param drivenBy
+     * @param enabled
+     * @param scheduleActivities
+     * @param retries
+     * @param actionReferSchedule
+     * @param name
+     * @param inactivityTimeoutInMin
+     * @param comment
+     * @param hardLimit
+     * @param scheduleOverrides
+     * @param schedulePeriod
+     * @param softLimit
+     */
+    public Action(String actionReferSchedule, ActionSpecificData actionSpecificData, String comment, CompletionNotification completionNotification, Boolean concurrent, String drivenBy, Boolean enabled, String failureImpact, String hardLimit, Integer inactivityTimeoutInMin, String name, Integer parallelism, Integer retries, Integer retryDelayInSec, String softLimit, List<String> scheduleActivities, List<Object> scheduleOverrides, String schedulePeriod) {
+        super();
+        this.actionReferSchedule = actionReferSchedule;
+        this.actionSpecificData = actionSpecificData;
+        this.comment = comment;
+        this.completionNotification = completionNotification;
+        this.concurrent = concurrent;
+        this.drivenBy = drivenBy;
+        this.enabled = enabled;
+        this.failureImpact = failureImpact;
+        this.hardLimit = hardLimit;
+        this.inactivityTimeoutInMin = inactivityTimeoutInMin;
+        this.name = name;
+        this.parallelism = parallelism;
+        this.retries = retries;
+        this.retryDelayInSec = retryDelayInSec;
+        this.softLimit = softLimit;
+        this.scheduleActivities = scheduleActivities;
+        this.scheduleOverrides = scheduleOverrides;
+        this.schedulePeriod = schedulePeriod;
+    }
+
+    @JsonProperty("actionReferSchedule")
+    public String getActionReferSchedule() {
+        return actionReferSchedule;
+    }
+
+    @JsonProperty("actionReferSchedule")
+    public void setActionReferSchedule(String actionReferSchedule) {
+        this.actionReferSchedule = actionReferSchedule;
+    }
+
+    @JsonProperty("actionSpecificData")
+    public ActionSpecificData getActionSpecificData() {
+        return actionSpecificData;
+    }
+
+    @JsonProperty("actionSpecificData")
+    public void setActionSpecificData(ActionSpecificData actionSpecificData) {
+        this.actionSpecificData = actionSpecificData;
+    }
+
+    @JsonProperty("comment")
+    public String getComment() {
+        return comment;
+    }
+
+    @JsonProperty("comment")
+    public void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    @JsonProperty("completionNotification")
+    public CompletionNotification getCompletionNotification() {
+        return completionNotification;
+    }
+
+    @JsonProperty("completionNotification")
+    public void setCompletionNotification(CompletionNotification completionNotification) {
+        this.completionNotification = completionNotification;
+    }
+
+    @JsonProperty("concurrent")
+    public Boolean getConcurrent() {
+        return concurrent;
+    }
+
+    @JsonProperty("concurrent")
+    public void setConcurrent(Boolean concurrent) {
+        this.concurrent = concurrent;
+    }
+
+    @JsonProperty("drivenBy")
+    public String getDrivenBy() {
+        return drivenBy;
+    }
+
+    @JsonProperty("drivenBy")
+    public void setDrivenBy(String drivenBy) {
+        this.drivenBy = drivenBy;
+    }
+
+    @JsonProperty("enabled")
+    public Boolean getEnabled() {
+        return enabled;
+    }
+
+    @JsonProperty("enabled")
+    public void setEnabled(Boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    @JsonProperty("failureImpact")
+    public String getFailureImpact() {
+        return failureImpact;
+    }
+
+    @JsonProperty("failureImpact")
+    public void setFailureImpact(String failureImpact) {
+        this.failureImpact = failureImpact;
+    }
+
+    @JsonProperty("hardLimit")
+    public String getHardLimit() {
+        return hardLimit;
+    }
+
+    @JsonProperty("hardLimit")
+    public void setHardLimit(String hardLimit) {
+        this.hardLimit = hardLimit;
+    }
+
+    @JsonProperty("inactivityTimeoutInMin")
+    public Integer getInactivityTimeoutInMin() {
+        return inactivityTimeoutInMin;
+    }
+
+    @JsonProperty("inactivityTimeoutInMin")
+    public void setInactivityTimeoutInMin(Integer inactivityTimeoutInMin) {
+        this.inactivityTimeoutInMin = inactivityTimeoutInMin;
+    }
+
+    @JsonProperty("name")
+    public String getName() {
+        return name;
+    }
+
+    @JsonProperty("name")
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @JsonProperty("parallelism")
+    public Integer getParallelism() {
+        return parallelism;
+    }
+
+    @JsonProperty("parallelism")
+    public void setParallelism(Integer parallelism) {
+        this.parallelism = parallelism;
+    }
+
+    @JsonProperty("retries")
+    public Integer getRetries() {
+        return retries;
+    }
+
+    @JsonProperty("retries")
+    public void setRetries(Integer retries) {
+        this.retries = retries;
+    }
+
+    @JsonProperty("retryDelayInSec")
+    public Integer getRetryDelayInSec() {
+        return retryDelayInSec;
+    }
+
+    @JsonProperty("retryDelayInSec")
+    public void setRetryDelayInSec(Integer retryDelayInSec) {
+        this.retryDelayInSec = retryDelayInSec;
+    }
+
+    @JsonProperty("softLimit")
+    public String getSoftLimit() {
+        return softLimit;
+    }
+
+    @JsonProperty("softLimit")
+    public void setSoftLimit(String softLimit) {
+        this.softLimit = softLimit;
+    }
+
+    @JsonProperty("scheduleActivities")
+    public List<String> getScheduleActivities() {
+        return scheduleActivities;
+    }
+
+    @JsonProperty("scheduleActivities")
+    public void setScheduleActivities(List<String> scheduleActivities) {
+        this.scheduleActivities = scheduleActivities;
+    }
+
+    @JsonProperty("scheduleOverrides")
+    public List<Object> getScheduleOverrides() {
+        return scheduleOverrides;
+    }
+
+    @JsonProperty("scheduleOverrides")
+    public void setScheduleOverrides(List<Object> scheduleOverrides) {
+        this.scheduleOverrides = scheduleOverrides;
+    }
+
+    @JsonProperty("schedulePeriod")
+    public String getSchedulePeriod() {
+        return schedulePeriod;
+    }
+
+    @JsonProperty("schedulePeriod")
+    public void setSchedulePeriod(String schedulePeriod) {
+        this.schedulePeriod = schedulePeriod;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"actionReferSchedule","actionReferSchedule","comment","completionNotification",
+                "concurrent","drivenBy","enabled","failureImpact","hardLimit","inactivityTimeoutInMin","name",
+                "parallelism","retries","retryDelayInSec","softLimit","scheduleActivities","scheduleOverrides",
+                "schedulePeriod");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.failureImpact == null) ? 0 : this.failureImpact.hashCode()));
+        result = ((result * 31) + ((this.actionSpecificData == null) ? 0 : this.actionSpecificData.hashCode()));
+        result = ((result * 31) + ((this.completionNotification == null) ? 0 : this.completionNotification.hashCode()));
+        result = ((result * 31) + ((this.parallelism == null) ? 0 : this.parallelism.hashCode()));
+        result = ((result * 31) + ((this.concurrent == null) ? 0 : this.concurrent.hashCode()));
+        result = ((result * 31) + ((this.retryDelayInSec == null) ? 0 : this.retryDelayInSec.hashCode()));
+        result = ((result * 31) + ((this.drivenBy == null) ? 0 : this.drivenBy.hashCode()));
+        result = ((result * 31) + ((this.enabled == null) ? 0 : this.enabled.hashCode()));
+        result = ((result * 31) + ((this.scheduleActivities == null) ? 0 : this.scheduleActivities.hashCode()));
+        result = ((result * 31) + ((this.retries == null) ? 0 : this.retries.hashCode()));
+        result = ((result * 31) + ((this.actionReferSchedule == null) ? 0 : this.actionReferSchedule.hashCode()));
+        result = ((result * 31) + ((this.name == null) ? 0 : this.name.hashCode()));
+        result = ((result * 31) + ((this.inactivityTimeoutInMin == null) ? 0 : this.inactivityTimeoutInMin.hashCode()));
+        result = ((result * 31) + ((this.comment == null) ? 0 : this.comment.hashCode()));
+        result = ((result * 31) + ((this.hardLimit == null) ? 0 : this.hardLimit.hashCode()));
+        result = ((result * 31) + ((this.scheduleOverrides == null) ? 0 : this.scheduleOverrides.hashCode()));
+        result = ((result * 31) + ((this.schedulePeriod == null) ? 0 : this.schedulePeriod.hashCode()));
+        result = ((result * 31) + ((this.softLimit == null) ? 0 : this.softLimit.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ActionSpecificData.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ActionSpecificData.java
new file mode 100644
index 0000000000..57537c772f
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ActionSpecificData.java
@@ -0,0 +1,107 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "backup",
+        "serverBackup",
+        "expire"
+})
+@Generated("jsonschema2pojo")
+public class ActionSpecificData implements Serializable {
+
+    private final static long serialVersionUID = 2969226417055065194L;
+    @JsonProperty("backup")
+    private NetworkerBackup backup;
+    @JsonProperty("serverBackup")
+    private ServerBackup serverBackup;
+    @JsonProperty("expire")
+    private Expire expire;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public ActionSpecificData() {
+    }
+
+    /**
+     * @param backup
+     * @param expire
+     * @param serverBackup
+     */
+    public ActionSpecificData(NetworkerBackup backup, ServerBackup serverBackup, Expire expire) {
+        super();
+        this.backup = backup;
+        this.serverBackup = serverBackup;
+        this.expire = expire;
+    }
+
+    @JsonProperty("backup")
+    public NetworkerBackup getBackup() {
+        return backup;
+    }
+
+    @JsonProperty("backup")
+    public void setBackup(NetworkerBackup backup) {
+        this.backup = backup;
+    }
+
+    @JsonProperty("serverBackup")
+    public ServerBackup getServerBackup() {
+        return serverBackup;
+    }
+
+    @JsonProperty("serverBackup")
+    public void setServerBackup(ServerBackup serverBackup) {
+        this.serverBackup = serverBackup;
+    }
+
+    @JsonProperty("expire")
+    public Expire getExpire() {
+        return expire;
+    }
+
+    @JsonProperty("expire")
+    public void setExpire(Expire expire) {
+        this.expire = expire;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"backup","serverBackup","expire");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.backup == null) ? 0 : this.backup.hashCode()));
+        result = ((result * 31) + ((this.serverBackup == null) ? 0 : this.serverBackup.hashCode()));
+        result = ((result * 31) + ((this.expire == null) ? 0 : this.expire.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Attribute.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Attribute.java
new file mode 100644
index 0000000000..b24d1d102b
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Attribute.java
@@ -0,0 +1,92 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+import java.util.List;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "key",
+        "values"
+})
+@Generated("jsonschema2pojo")
+public class Attribute implements Serializable {
+
+    private final static long serialVersionUID = -8899380112144428567L;
+    @JsonProperty("key")
+    private String key;
+    @JsonProperty("values")
+    private List<String> values = null;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Attribute() {
+    }
+
+    /**
+     * @param values
+     * @param key
+     */
+    public Attribute(String key, List<String> values) {
+        super();
+        this.key = key;
+        this.values = values;
+    }
+
+    @JsonProperty("key")
+    public String getKey() {
+        return key;
+    }
+
+    @JsonProperty("key")
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    @JsonProperty("values")
+    public List<String> getValues() {
+        return values;
+    }
+
+    @JsonProperty("values")
+    public void setValues(List<String> values) {
+        this.values = values;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"key","values");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.key == null) ? 0 : this.key.hashCode()));
+        result = ((result * 31) + ((this.values == null) ? 0 : this.values.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/BackupSpecificData.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/BackupSpecificData.java
new file mode 100644
index 0000000000..872eef4382
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/BackupSpecificData.java
@@ -0,0 +1,75 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "traditional"
+})
+@Generated("jsonschema2pojo")
+public class BackupSpecificData implements Serializable {
+
+    private final static long serialVersionUID = -73775366615011864L;
+    @JsonProperty("traditional")
+    private Traditional traditional;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public BackupSpecificData() {
+    }
+
+    /**
+     * @param traditional
+     */
+    public BackupSpecificData(Traditional traditional) {
+        super();
+        this.traditional = traditional;
+    }
+
+    @JsonProperty("traditional")
+    public Traditional getTraditional() {
+        return traditional;
+    }
+
+    @JsonProperty("traditional")
+    public void setTraditional(Traditional traditional) {
+        this.traditional = traditional;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"traditional");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.traditional == null) ? 0 : this.traditional.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/CompletionNotification.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/CompletionNotification.java
new file mode 100644
index 0000000000..a84f0bacb2
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/CompletionNotification.java
@@ -0,0 +1,91 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "command",
+        "executeOn"
+})
+@Generated("jsonschema2pojo")
+public class CompletionNotification implements Serializable {
+
+    private final static long serialVersionUID = 3437745338486835459L;
+    @JsonProperty("command")
+    private String command;
+    @JsonProperty("executeOn")
+    private String executeOn;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public CompletionNotification() {
+    }
+
+    /**
+     * @param executeOn
+     * @param command
+     */
+    public CompletionNotification(String command, String executeOn) {
+        super();
+        this.command = command;
+        this.executeOn = executeOn;
+    }
+
+    @JsonProperty("command")
+    public String getCommand() {
+        return command;
+    }
+
+    @JsonProperty("command")
+    public void setCommand(String command) {
+        this.command = command;
+    }
+
+    @JsonProperty("executeOn")
+    public String getExecuteOn() {
+        return executeOn;
+    }
+
+    @JsonProperty("executeOn")
+    public void setExecuteOn(String executeOn) {
+        this.executeOn = executeOn;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"command","executeOn");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.executeOn == null) ? 0 : this.executeOn.hashCode()));
+        result = ((result * 31) + ((this.command == null) ? 0 : this.command.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Expire.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Expire.java
new file mode 100644
index 0000000000..7f024434f0
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Expire.java
@@ -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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+
+})
+@Generated("jsonschema2pojo")
+public class Expire implements Serializable {
+
+    private final static long serialVersionUID = 601211959344842864L;
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this);
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Instance.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Instance.java
new file mode 100644
index 0000000000..23f3013979
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Instance.java
@@ -0,0 +1,124 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+import java.util.List;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "clone",
+        "id",
+        "status",
+        "volumeIds"
+})
+@Generated("jsonschema2pojo")
+public class Instance implements Serializable {
+
+    private final static long serialVersionUID = -5708111855130556342L;
+    @JsonProperty("clone")
+    private Boolean clone;
+    @JsonProperty("id")
+    private String id;
+    @JsonProperty("status")
+    private String status;
+    @JsonProperty("volumeIds")
+    private List<String> volumeIds = null;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Instance() {
+    }
+
+    /**
+     * @param clone
+     * @param volumeIds
+     * @param id
+     * @param status
+     */
+    public Instance(Boolean clone, String id, String status, List<String> volumeIds) {
+        super();
+        this.clone = clone;
+        this.id = id;
+        this.status = status;
+        this.volumeIds = volumeIds;
+    }
+
+    @JsonProperty("clone")
+    public Boolean getClone() {
+        return clone;
+    }
+
+    @JsonProperty("clone")
+    public void setClone(Boolean clone) {
+        this.clone = clone;
+    }
+
+    @JsonProperty("id")
+    public String getId() {
+        return id;
+    }
+
+    @JsonProperty("id")
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @JsonProperty("status")
+    public String getStatus() {
+        return status;
+    }
+
+    @JsonProperty("status")
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    @JsonProperty("volumeIds")
+    public List<String> getVolumeIds() {
+        return volumeIds;
+    }
+
+    @JsonProperty("volumeIds")
+    public void setVolumeIds(List<String> volumeIds) {
+        this.volumeIds = volumeIds;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"clone","id","status","volumeIds");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.clone == null) ? 0 : this.clone.hashCode()));
+        result = ((result * 31) + ((this.volumeIds == null) ? 0 : this.volumeIds.hashCode()));
+        result = ((result * 31) + ((this.id == null) ? 0 : this.id.hashCode()));
+        result = ((result * 31) + ((this.status == null) ? 0 : this.status.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Link.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Link.java
new file mode 100644
index 0000000000..547a0ea89e
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Link.java
@@ -0,0 +1,91 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "href",
+        "rel"
+})
+@Generated("jsonschema2pojo")
+public class Link implements Serializable {
+
+    private final static long serialVersionUID = 1110347626425938231L;
+    @JsonProperty("href")
+    private String href;
+    @JsonProperty("rel")
+    private String rel;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Link() {
+    }
+
+    /**
+     * @param rel
+     * @param href
+     */
+    public Link(String href, String rel) {
+        super();
+        this.href = href;
+        this.rel = rel;
+    }
+
+    @JsonProperty("href")
+    public String getHref() {
+        return href;
+    }
+
+    @JsonProperty("href")
+    public void setHref(String href) {
+        this.href = href;
+    }
+
+    @JsonProperty("rel")
+    public String getRel() {
+        return rel;
+    }
+
+    @JsonProperty("rel")
+    public void setRel(String rel) {
+        this.rel = rel;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"href","rel");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.rel == null) ? 0 : this.rel.hashCode()));
+        result = ((result * 31) + ((this.href == null) ? 0 : this.href.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/NetworkerBackup.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/NetworkerBackup.java
new file mode 100644
index 0000000000..44ec839170
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/NetworkerBackup.java
@@ -0,0 +1,334 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import javax.annotation.Generated;
+import java.io.Serializable;
+import java.util.List;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "attributes",
+        "browseTime",
+        "clientHostname",
+        "clientId",
+        "completionTime",
+        "creationTime",
+        "fileCount",
+        "id",
+        "instances",
+        "level",
+        "links",
+        "name",
+        "retentionTime",
+        "saveTime",
+        "shortId",
+        "size",
+        "type"
+})
+@Generated("jsonschema2pojo")
+public class NetworkerBackup implements Serializable {
+
+    private final static long serialVersionUID = -4474500098917286405L;
+    @JsonProperty("attributes")
+    private List<Attribute> attributes = null;
+    @JsonProperty("browseTime")
+    private String browseTime;
+    @JsonProperty("clientHostname")
+    private String clientHostname;
+    @JsonProperty("clientId")
+    private String clientId;
+    @JsonProperty("completionTime")
+    private String completionTime;
+    @JsonProperty("creationTime")
+    private String creationTime;
+    @JsonProperty("fileCount")
+    private Integer fileCount;
+    @JsonProperty("id")
+    private String id;
+    @JsonProperty("instances")
+    private List<Instance> instances = null;
+    @JsonProperty("level")
+    private String level;
+    @JsonProperty("links")
+    private List<Link> links = null;
+    @JsonProperty("name")
+    private String name;
+    @JsonProperty("retentionTime")
+    private String retentionTime;
+    @JsonProperty("saveTime")
+    private String saveTime;
+    @JsonProperty("shortId")
+    private String shortId;
+    @JsonProperty("size")
+    private Size size;
+    @JsonProperty("type")
+    private String type;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public NetworkerBackup() {
+    }
+
+    /**
+     * @param shortId
+     * @param clientId
+     * @param browseTime
+     * @param creationTime
+     * @param instances
+     * @param level
+     * @param retentionTime
+     * @param type
+     * @param fileCount
+     * @param clientHostname
+     * @param completionTime
+     * @param size
+     * @param name
+     * @param attributes
+     * @param links
+     * @param id
+     * @param saveTime
+     */
+    public NetworkerBackup(List<Attribute> attributes, String browseTime, String clientHostname, String clientId, String completionTime, String creationTime, Integer fileCount, String id, List<Instance> instances, String level, List<Link> links, String name, String retentionTime, String saveTime, String shortId, Size size, String type) {
+        super();
+        this.attributes = attributes;
+        this.browseTime = browseTime;
+        this.clientHostname = clientHostname;
+        this.clientId = clientId;
+        this.completionTime = completionTime;
+        this.creationTime = creationTime;
+        this.fileCount = fileCount;
+        this.id = id;
+        this.instances = instances;
+        this.level = level;
+        this.links = links;
+        this.name = name;
+        this.retentionTime = retentionTime;
+        this.saveTime = saveTime;
+        this.shortId = shortId;
+        this.size = size;
+        this.type = type;
+    }
+
+    @JsonProperty("attributes")
+    public List<Attribute> getAttributes() {
+        return attributes;
+    }
+
+    @JsonProperty("attributes")
+    public void setAttributes(List<Attribute> attributes) {
+        this.attributes = attributes;
+    }
+
+    @JsonProperty("browseTime")
+    public String getBrowseTime() {
+        return browseTime;
+    }
+
+    @JsonProperty("browseTime")
+    public void setBrowseTime(String browseTime) {
+        this.browseTime = browseTime;
+    }
+
+    @JsonProperty("clientHostname")
+    public String getClientHostname() {
+        return clientHostname;
+    }
+
+    @JsonProperty("clientHostname")
+    public void setClientHostname(String clientHostname) {
+        this.clientHostname = clientHostname;
+    }
+
+    @JsonProperty("clientId")
+    public String getClientId() {
+        return clientId;
+    }
+
+    @JsonProperty("clientId")
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    @JsonProperty("completionTime")
+    public String getCompletionTime() {
+        return completionTime;
+    }
+
+    @JsonProperty("completionTime")
+    public void setCompletionTime(String completionTime) {
+        this.completionTime = completionTime;
+    }
+
+    @JsonProperty("creationTime")
+    public String getCreationTime() {
+        return creationTime;
+    }
+
+    @JsonProperty("creationTime")
+    public void setCreationTime(String creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    @JsonProperty("fileCount")
+    public Integer getFileCount() {
+        return fileCount;
+    }
+
+    @JsonProperty("fileCount")
+    public void setFileCount(Integer fileCount) {
+        this.fileCount = fileCount;
+    }
+
+    @JsonProperty("id")
+    public String getId() {
+        return id;
+    }
+
+    @JsonProperty("id")
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @JsonProperty("instances")
+    public List<Instance> getInstances() {
+        return instances;
+    }
+
+    @JsonProperty("instances")
+    public void setInstances(List<Instance> instances) {
+        this.instances = instances;
+    }
+
+    @JsonProperty("level")
+    public String getLevel() {
+        return level;
+    }
+
+    @JsonProperty("level")
+    public void setLevel(String level) {
+        this.level = level;
+    }
+
+    @JsonProperty("links")
+    public List<Link> getLinks() {
+        return links;
+    }
+
+    @JsonProperty("links")
+    public void setLinks(List<Link> links) {
+        this.links = links;
+    }
+
+    @JsonProperty("name")
+    public String getName() {
+        return name;
+    }
+
+    @JsonProperty("name")
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @JsonProperty("retentionTime")
+    public String getRetentionTime() {
+        return retentionTime;
+    }
+
+    @JsonProperty("retentionTime")
+    public void setRetentionTime(String retentionTime) {
+        this.retentionTime = retentionTime;
+    }
+
+    @JsonProperty("saveTime")
+    public String getSaveTime() {
+        return saveTime;
+    }
+
+    @JsonProperty("saveTime")
+    public void setSaveTime(String saveTime) {
+        this.saveTime = saveTime;
+    }
+
+    @JsonProperty("shortId")
+    public String getShortId() {
+        return shortId;
+    }
+
+    @JsonProperty("shortId")
+    public void setShortId(String shortId) {
+        this.shortId = shortId;
+    }
+
+    @JsonProperty("size")
+    public Size getSize() {
+        return size;
+    }
+
+    @JsonProperty("size")
+    public void setSize(Size size) {
+        this.size = size;
+    }
+
+    @JsonProperty("type")
+    public String getType() {
+        return type;
+    }
+
+    @JsonProperty("type")
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"attributes","browseTime","clientHostname","clientId",
+                "completionTime","creationTime","fileCount","id","instances","level","links","name","retentionTime",
+                "saveTime","shortId","size","type");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.shortId == null) ? 0 : this.shortId.hashCode()));
+        result = ((result * 31) + ((this.clientId == null) ? 0 : this.clientId.hashCode()));
+        result = ((result * 31) + ((this.browseTime == null) ? 0 : this.browseTime.hashCode()));
+        result = ((result * 31) + ((this.creationTime == null) ? 0 : this.creationTime.hashCode()));
+        result = ((result * 31) + ((this.instances == null) ? 0 : this.instances.hashCode()));
+        result = ((result * 31) + ((this.level == null) ? 0 : this.level.hashCode()));
+        result = ((result * 31) + ((this.retentionTime == null) ? 0 : this.retentionTime.hashCode()));
+        result = ((result * 31) + ((this.type == null) ? 0 : this.type.hashCode()));
+        result = ((result * 31) + ((this.fileCount == null) ? 0 : this.fileCount.hashCode()));
+        result = ((result * 31) + ((this.clientHostname == null) ? 0 : this.clientHostname.hashCode()));
+        result = ((result * 31) + ((this.completionTime == null) ? 0 : this.completionTime.hashCode()));
+        result = ((result * 31) + ((this.size == null) ? 0 : this.size.hashCode()));
+        result = ((result * 31) + ((this.name == null) ? 0 : this.name.hashCode()));
+        result = ((result * 31) + ((this.attributes == null) ? 0 : this.attributes.hashCode()));
+        result = ((result * 31) + ((this.links == null) ? 0 : this.links.hashCode()));
+        result = ((result * 31) + ((this.id == null) ? 0 : this.id.hashCode()));
+        result = ((result * 31) + ((this.saveTime == null) ? 0 : this.saveTime.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/NetworkerBackups.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/NetworkerBackups.java
new file mode 100644
index 0000000000..bae2720c30
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/NetworkerBackups.java
@@ -0,0 +1,92 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+import java.util.List;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "backups",
+        "count"
+})
+@Generated("jsonschema2pojo")
+public class NetworkerBackups implements Serializable {
+
+    private final static long serialVersionUID = -3805021350250865454L;
+    @JsonProperty("backups")
+    private List<NetworkerBackup> backups = null;
+    @JsonProperty("count")
+    private Integer count;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public NetworkerBackups() {
+    }
+
+    /**
+     * @param count
+     * @param backups
+     */
+    public NetworkerBackups(List<NetworkerBackup> backups, Integer count) {
+        super();
+        this.backups = backups;
+        this.count = count;
+    }
+
+    @JsonProperty("backups")
+    public List<NetworkerBackup> getBackups() {
+        return backups;
+    }
+
+    @JsonProperty("backups")
+    public void setBackups(List<NetworkerBackup> backups) {
+        this.backups = backups;
+    }
+
+    @JsonProperty("count")
+    public Integer getCount() {
+        return count;
+    }
+
+    @JsonProperty("count")
+    public void setCount(Integer count) {
+        this.count = count;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"backups","count");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.count == null) ? 0 : this.count.hashCode()));
+        result = ((result * 31) + ((this.backups == null) ? 0 : this.backups.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ProtectionPolicies.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ProtectionPolicies.java
new file mode 100644
index 0000000000..4dfae82f4d
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ProtectionPolicies.java
@@ -0,0 +1,92 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+import java.util.List;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "count",
+        "protectionPolicies"
+})
+@Generated("jsonschema2pojo")
+public class ProtectionPolicies implements Serializable {
+
+    private final static long serialVersionUID = 1357846434531599309L;
+    @JsonProperty("count")
+    private Integer count;
+    @JsonProperty("protectionPolicies")
+    private List<ProtectionPolicy> protectionPolicies = null;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public ProtectionPolicies() {
+    }
+
+    /**
+     * @param protectionPolicies
+     * @param count
+     */
+    public ProtectionPolicies(Integer count, List<ProtectionPolicy> protectionPolicies) {
+        super();
+        this.count = count;
+        this.protectionPolicies = protectionPolicies;
+    }
+
+    @JsonProperty("count")
+    public Integer getCount() {
+        return count;
+    }
+
+    @JsonProperty("count")
+    public void setCount(Integer count) {
+        this.count = count;
+    }
+
+    @JsonProperty("protectionPolicies")
+    public List<ProtectionPolicy> getProtectionPolicies() {
+        return protectionPolicies;
+    }
+
+    @JsonProperty("protectionPolicies")
+    public void setProtectionPolicies(List<ProtectionPolicy> protectionPolicies) {
+        this.protectionPolicies = protectionPolicies;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"count","protectionPolicies");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.count == null) ? 0 : this.count.hashCode()));
+        result = ((result * 31) + ((this.protectionPolicies == null) ? 0 : this.protectionPolicies.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ProtectionPolicy.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ProtectionPolicy.java
new file mode 100644
index 0000000000..45457201bf
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ProtectionPolicy.java
@@ -0,0 +1,175 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+import java.util.List;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "comment",
+        "links",
+        "name",
+        "policyProtectionEnable",
+        "policyProtectionPeriod",
+        "resourceId",
+        "summaryNotification",
+        "workflows"
+})
+@Generated("jsonschema2pojo")
+public class ProtectionPolicy implements Serializable {
+
+    private final static long serialVersionUID = 5407494949453441445L;
+    @JsonProperty("comment")
+    private String comment;
+    @JsonProperty("links")
+    private List<Link> links = null;
+    @JsonProperty("name")
+    private String name;
+    @JsonProperty("policyProtectionEnable")
+    private Boolean policyProtectionEnable;
+    @JsonProperty("policyProtectionPeriod")
+    private String policyProtectionPeriod;
+    @JsonProperty("resourceId")
+    private ResourceId resourceId;
+    @JsonProperty("summaryNotification")
+    private SummaryNotification summaryNotification;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public ProtectionPolicy() {
+    }
+
+    /**
+     * @param policyProtectionEnable
+     * @param policyProtectionPeriod
+     * @param summaryNotification
+     * @param resourceId
+     * @param name
+     * @param comment
+     * @param links
+     */
+    public ProtectionPolicy(String comment, List<Link> links, String name, Boolean policyProtectionEnable, String policyProtectionPeriod, ResourceId resourceId, SummaryNotification summaryNotification) {
+        super();
+        this.comment = comment;
+        this.links = links;
+        this.name = name;
+        this.policyProtectionEnable = policyProtectionEnable;
+        this.policyProtectionPeriod = policyProtectionPeriod;
+        this.resourceId = resourceId;
+        this.summaryNotification = summaryNotification;
+    }
+
+    @JsonProperty("comment")
+    public String getComment() {
+        return comment;
+    }
+
+    @JsonProperty("comment")
+    public void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    @JsonProperty("links")
+    public List<Link> getLinks() {
+        return links;
+    }
+
+    @JsonProperty("links")
+    public void setLinks(List<Link> links) {
+        this.links = links;
+    }
+
+    @JsonProperty("name")
+    public String getName() {
+        return name;
+    }
+
+    @JsonProperty("name")
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @JsonProperty("policyProtectionEnable")
+    public Boolean getPolicyProtectionEnable() {
+        return policyProtectionEnable;
+    }
+
+    @JsonProperty("policyProtectionEnable")
+    public void setPolicyProtectionEnable(Boolean policyProtectionEnable) {
+        this.policyProtectionEnable = policyProtectionEnable;
+    }
+
+    @JsonProperty("policyProtectionPeriod")
+    public String getPolicyProtectionPeriod() {
+        return policyProtectionPeriod;
+    }
+
+    @JsonProperty("policyProtectionPeriod")
+    public void setPolicyProtectionPeriod(String policyProtectionPeriod) {
+        this.policyProtectionPeriod = policyProtectionPeriod;
+    }
+
+    @JsonProperty("resourceId")
+    public ResourceId getResourceId() {
+        return resourceId;
+    }
+
+    @JsonProperty("resourceId")
+    public void setResourceId(ResourceId resourceId) {
+        this.resourceId = resourceId;
+    }
+
+    @JsonProperty("summaryNotification")
+    public SummaryNotification getSummaryNotification() {
+        return summaryNotification;
+    }
+
+    @JsonProperty("summaryNotification")
+    public void setSummaryNotification(SummaryNotification summaryNotification) {
+        this.summaryNotification = summaryNotification;
+    }
+
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"comment","links","name","policyProtectionEnable","resourceId",
+                "summaryNotification");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.policyProtectionEnable == null) ? 0 : this.policyProtectionEnable.hashCode()));
+        result = ((result * 31) + ((this.policyProtectionPeriod == null) ? 0 : this.policyProtectionPeriod.hashCode()));
+        result = ((result * 31) + ((this.summaryNotification == null) ? 0 : this.summaryNotification.hashCode()));
+        result = ((result * 31) + ((this.resourceId == null) ? 0 : this.resourceId.hashCode()));
+        result = ((result * 31) + ((this.name == null) ? 0 : this.name.hashCode()));
+        result = ((result * 31) + ((this.comment == null) ? 0 : this.comment.hashCode()));
+        result = ((result * 31) + ((this.links == null) ? 0 : this.links.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ResourceId.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ResourceId.java
new file mode 100644
index 0000000000..153daf0a1a
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ResourceId.java
@@ -0,0 +1,91 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "id",
+        "sequence"
+})
+@Generated("jsonschema2pojo")
+public class ResourceId implements Serializable {
+
+    private final static long serialVersionUID = -6987764740605099486L;
+    @JsonProperty("id")
+    private String id;
+    @JsonProperty("sequence")
+    private Integer sequence;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public ResourceId() {
+    }
+
+    /**
+     * @param sequence
+     * @param id
+     */
+    public ResourceId(String id, Integer sequence) {
+        super();
+        this.id = id;
+        this.sequence = sequence;
+    }
+
+    @JsonProperty("id")
+    public String getId() {
+        return id;
+    }
+
+    @JsonProperty("id")
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @JsonProperty("sequence")
+    public Integer getSequence() {
+        return sequence;
+    }
+
+    @JsonProperty("sequence")
+    public void setSequence(Integer sequence) {
+        this.sequence = sequence;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"id","sequence");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.sequence == null) ? 0 : this.sequence.hashCode()));
+        result = ((result * 31) + ((this.id == null) ? 0 : this.id.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ServerBackup.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ServerBackup.java
new file mode 100644
index 0000000000..e703a52d40
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/ServerBackup.java
@@ -0,0 +1,140 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "performBootstrap",
+        "performClientFileIndexing",
+        "destinationStorageNode",
+        "retentionPeriod",
+        "destinationPool"
+})
+@Generated("jsonschema2pojo")
+public class ServerBackup implements Serializable {
+
+    private final static long serialVersionUID = -542556595701706880L;
+    @JsonProperty("performBootstrap")
+    private Boolean performBootstrap;
+    @JsonProperty("performClientFileIndexing")
+    private Boolean performClientFileIndexing;
+    @JsonProperty("destinationStorageNode")
+    private String destinationStorageNode;
+    @JsonProperty("retentionPeriod")
+    private String retentionPeriod;
+    @JsonProperty("destinationPool")
+    private String destinationPool;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public ServerBackup() {
+    }
+
+    /**
+     * @param destinationPool
+     * @param performBootstrap
+     * @param performClientFileIndexing
+     * @param destinationStorageNode
+     * @param retentionPeriod
+     */
+    public ServerBackup(Boolean performBootstrap, Boolean performClientFileIndexing, String destinationStorageNode, String retentionPeriod, String destinationPool) {
+        super();
+        this.performBootstrap = performBootstrap;
+        this.performClientFileIndexing = performClientFileIndexing;
+        this.destinationStorageNode = destinationStorageNode;
+        this.retentionPeriod = retentionPeriod;
+        this.destinationPool = destinationPool;
+    }
+
+    @JsonProperty("performBootstrap")
+    public Boolean getPerformBootstrap() {
+        return performBootstrap;
+    }
+
+    @JsonProperty("performBootstrap")
+    public void setPerformBootstrap(Boolean performBootstrap) {
+        this.performBootstrap = performBootstrap;
+    }
+
+    @JsonProperty("performClientFileIndexing")
+    public Boolean getPerformClientFileIndexing() {
+        return performClientFileIndexing;
+    }
+
+    @JsonProperty("performClientFileIndexing")
+    public void setPerformClientFileIndexing(Boolean performClientFileIndexing) {
+        this.performClientFileIndexing = performClientFileIndexing;
+    }
+
+    @JsonProperty("destinationStorageNode")
+    public String getDestinationStorageNode() {
+        return destinationStorageNode;
+    }
+
+    @JsonProperty("destinationStorageNode")
+    public void setDestinationStorageNode(String destinationStorageNode) {
+        this.destinationStorageNode = destinationStorageNode;
+    }
+
+    @JsonProperty("retentionPeriod")
+    public String getRetentionPeriod() {
+        return retentionPeriod;
+    }
+
+    @JsonProperty("retentionPeriod")
+    public void setRetentionPeriod(String retentionPeriod) {
+        this.retentionPeriod = retentionPeriod;
+    }
+
+    @JsonProperty("destinationPool")
+    public String getDestinationPool() {
+        return destinationPool;
+    }
+
+    @JsonProperty("destinationPool")
+    public void setDestinationPool(String destinationPool) {
+        this.destinationPool = destinationPool;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"performBootstrap","performClientFileIndexing","destinationStorageNode",
+                "retentionPeriod","destinationPool");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.performBootstrap == null) ? 0 : this.performBootstrap.hashCode()));
+        result = ((result * 31) + ((this.performClientFileIndexing == null) ? 0 : this.performClientFileIndexing.hashCode()));
+        result = ((result * 31) + ((this.destinationPool == null) ? 0 : this.destinationPool.hashCode()));
+        result = ((result * 31) + ((this.destinationStorageNode == null) ? 0 : this.destinationStorageNode.hashCode()));
+        result = ((result * 31) + ((this.retentionPeriod == null) ? 0 : this.retentionPeriod.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Size.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Size.java
new file mode 100644
index 0000000000..826989714b
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Size.java
@@ -0,0 +1,90 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "unit",
+        "value"
+})
+@Generated("jsonschema2pojo")
+public class Size implements Serializable {
+
+    private final static long serialVersionUID = -8270448162523429622L;
+    @JsonProperty("unit")
+    private String unit;
+    @JsonProperty("value")
+    private Long value;
+    /**
+     * No args constructor for use in serialization
+     */
+    public Size() {
+    }
+
+    /**
+     * @param unit
+     * @param value
+     */
+    public Size(String unit, Long value) {
+        super();
+        this.unit = unit;
+        this.value = value;
+    }
+
+    @JsonProperty("unit")
+    public String getUnit() {
+        return unit;
+    }
+
+    @JsonProperty("unit")
+    public void setUnit(String unit) {
+        this.unit = unit;
+    }
+
+    @JsonProperty("value")
+    public Long getValue() {
+        return value;
+    }
+
+    @JsonProperty("value")
+    public void setValue(Long value) {
+        this.value = value;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"unit","value");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.value == null) ? 0 : this.value.hashCode()));
+        result = ((result * 31) + ((this.unit == null) ? 0 : this.unit.hashCode()));
+        return result;
+    }
+}
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/SummaryNotification.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/SummaryNotification.java
new file mode 100644
index 0000000000..a21a8c31ed
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/SummaryNotification.java
@@ -0,0 +1,91 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "command",
+        "executeOn"
+})
+@Generated("jsonschema2pojo")
+public class SummaryNotification implements Serializable {
+
+    private final static long serialVersionUID = -1142867788732047105L;
+    @JsonProperty("command")
+    private String command;
+    @JsonProperty("executeOn")
+    private String executeOn;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public SummaryNotification() {
+    }
+
+    /**
+     * @param executeOn
+     * @param command
+     */
+    public SummaryNotification(String command, String executeOn) {
+        super();
+        this.command = command;
+        this.executeOn = executeOn;
+    }
+
+    @JsonProperty("command")
+    public String getCommand() {
+        return command;
+    }
+
+    @JsonProperty("command")
+    public void setCommand(String command) {
+        this.command = command;
+    }
+
+    @JsonProperty("executeOn")
+    public String getExecuteOn() {
+        return executeOn;
+    }
+
+    @JsonProperty("executeOn")
+    public void setExecuteOn(String executeOn) {
+        this.executeOn = executeOn;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"command","executeOn");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.executeOn == null) ? 0 : this.executeOn.hashCode()));
+        result = ((result * 31) + ((this.command == null) ? 0 : this.command.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Traditional.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Traditional.java
new file mode 100644
index 0000000000..4648b71701
--- /dev/null
+++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/api/Traditional.java
@@ -0,0 +1,238 @@
+// 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.networker.api;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import javax.annotation.Generated;
+import java.io.Serializable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "forceBackupLevel",
+        "browsePeriod",
+        "estimate",
+        "enableDDRetentionLock",
+        "ddRetentionLockTime",
+        "destinationPool",
+        "timestampFormat",
+        "verifySyntheticFull",
+        "revertToFullWhenSyntheticFullFails",
+        "fileInactivityThresholdInDays",
+        "fileInactivityAlertThresholdPercentage"
+})
+@Generated("jsonschema2pojo")
+public class Traditional implements Serializable {
+
+    private final static long serialVersionUID = -6349295255710627836L;
+    @JsonProperty("forceBackupLevel")
+    private String forceBackupLevel;
+    @JsonProperty("browsePeriod")
+    private String browsePeriod;
+    @JsonProperty("estimate")
+    private Boolean estimate;
+    @JsonProperty("enableDDRetentionLock")
+    private Boolean enableDDRetentionLock;
+    @JsonProperty("ddRetentionLockTime")
+    private String ddRetentionLockTime;
+    @JsonProperty("destinationPool")
+    private String destinationPool;
+    @JsonProperty("timestampFormat")
+    private String timestampFormat;
+    @JsonProperty("verifySyntheticFull")
+    private Boolean verifySyntheticFull;
+    @JsonProperty("revertToFullWhenSyntheticFullFails")
+    private Boolean revertToFullWhenSyntheticFullFails;
+    @JsonProperty("fileInactivityThresholdInDays")
+    private Integer fileInactivityThresholdInDays;
+    @JsonProperty("fileInactivityAlertThresholdPercentage")
+    private Integer fileInactivityAlertThresholdPercentage;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Traditional() {
+    }
+
+    /**
+     * @param enableDDRetentionLock
+     * @param revertToFullWhenSyntheticFullFails
+     * @param fileInactivityThresholdInDays
+     * @param destinationPool
+     * @param fileInactivityAlertThresholdPercentage
+     * @param estimate
+     * @param ddRetentionLockTime
+     * @param timestampFormat
+     * @param forceBackupLevel
+     * @param verifySyntheticFull
+     * @param browsePeriod
+     */
+    public Traditional(String forceBackupLevel, String browsePeriod, Boolean estimate, Boolean enableDDRetentionLock, String ddRetentionLockTime, String destinationPool, String timestampFormat, Boolean verifySyntheticFull, Boolean revertToFullWhenSyntheticFullFails, Integer fileInactivityThresholdInDays, Integer fileInactivityAlertThresholdPercentage) {
+        super();
+        this.forceBackupLevel = forceBackupLevel;
+        this.browsePeriod = browsePeriod;
+        this.estimate = estimate;
+        this.enableDDRetentionLock = enableDDRetentionLock;
+        this.ddRetentionLockTime = ddRetentionLockTime;
+        this.destinationPool = destinationPool;
+        this.timestampFormat = timestampFormat;
+        this.verifySyntheticFull = verifySyntheticFull;
+        this.revertToFullWhenSyntheticFullFails = revertToFullWhenSyntheticFullFails;
+        this.fileInactivityThresholdInDays = fileInactivityThresholdInDays;
+        this.fileInactivityAlertThresholdPercentage = fileInactivityAlertThresholdPercentage;
+    }
+
+    @JsonProperty("forceBackupLevel")
+    public String getForceBackupLevel() {
+        return forceBackupLevel;
+    }
+
+    @JsonProperty("forceBackupLevel")
+    public void setForceBackupLevel(String forceBackupLevel) {
+        this.forceBackupLevel = forceBackupLevel;
+    }
+
+    @JsonProperty("browsePeriod")
+    public String getBrowsePeriod() {
+        return browsePeriod;
+    }
+
+    @JsonProperty("browsePeriod")
+    public void setBrowsePeriod(String browsePeriod) {
+        this.browsePeriod = browsePeriod;
+    }
+
+    @JsonProperty("estimate")
+    public Boolean getEstimate() {
+        return estimate;
+    }
+
+    @JsonProperty("estimate")
+    public void setEstimate(Boolean estimate) {
+        this.estimate = estimate;
+    }
+
+    @JsonProperty("enableDDRetentionLock")
+    public Boolean getEnableDDRetentionLock() {
+        return enableDDRetentionLock;
+    }
+
+    @JsonProperty("enableDDRetentionLock")
+    public void setEnableDDRetentionLock(Boolean enableDDRetentionLock) {
+        this.enableDDRetentionLock = enableDDRetentionLock;
+    }
+
+    @JsonProperty("ddRetentionLockTime")
+    public String getDdRetentionLockTime() {
+        return ddRetentionLockTime;
+    }
+
+    @JsonProperty("ddRetentionLockTime")
+    public void setDdRetentionLockTime(String ddRetentionLockTime) {
+        this.ddRetentionLockTime = ddRetentionLockTime;
+    }
+
+    @JsonProperty("destinationPool")
+    public String getDestinationPool() {
+        return destinationPool;
+    }
+
+    @JsonProperty("destinationPool")
+    public void setDestinationPool(String destinationPool) {
+        this.destinationPool = destinationPool;
+    }
+
+    @JsonProperty("timestampFormat")
+    public String getTimestampFormat() {
+        return timestampFormat;
+    }
+
+    @JsonProperty("timestampFormat")
+    public void setTimestampFormat(String timestampFormat) {
+        this.timestampFormat = timestampFormat;
+    }
+
+    @JsonProperty("verifySyntheticFull")
+    public Boolean getVerifySyntheticFull() {
+        return verifySyntheticFull;
+    }
+
+    @JsonProperty("verifySyntheticFull")
+    public void setVerifySyntheticFull(Boolean verifySyntheticFull) {
+        this.verifySyntheticFull = verifySyntheticFull;
+    }
+
+    @JsonProperty("revertToFullWhenSyntheticFullFails")
+    public Boolean getRevertToFullWhenSyntheticFullFails() {
+        return revertToFullWhenSyntheticFullFails;
+    }
+
+    @JsonProperty("revertToFullWhenSyntheticFullFails")
+    public void setRevertToFullWhenSyntheticFullFails(Boolean revertToFullWhenSyntheticFullFails) {
+        this.revertToFullWhenSyntheticFullFails = revertToFullWhenSyntheticFullFails;
+    }
+
+    @JsonProperty("fileInactivityThresholdInDays")
+    public Integer getFileInactivityThresholdInDays() {
+        return fileInactivityThresholdInDays;
+    }
+
+    @JsonProperty("fileInactivityThresholdInDays")
+    public void setFileInactivityThresholdInDays(Integer fileInactivityThresholdInDays) {
+        this.fileInactivityThresholdInDays = fileInactivityThresholdInDays;
+    }
+
+    @JsonProperty("fileInactivityAlertThresholdPercentage")
+    public Integer getFileInactivityAlertThresholdPercentage() {
+        return fileInactivityAlertThresholdPercentage;
+    }
+
+    @JsonProperty("fileInactivityAlertThresholdPercentage")
+    public void setFileInactivityAlertThresholdPercentage(Integer fileInactivityAlertThresholdPercentage) {
+        this.fileInactivityAlertThresholdPercentage = fileInactivityAlertThresholdPercentage;
+    }
+
+    @Override
+    public String toString() {
+        ReflectionToStringBuilderUtils sb = new ReflectionToStringBuilderUtils();
+        sb.reflectOnlySelectedFields(this,"forceBackupLevel","browsePeriod","estimate","enableDDRetentionLock",
+                "enableDDRetentionLock","ddRetentionLockTime","ddRetentionLockTime","destinationPool","timestampFormat",
+                "verifySyntheticFull","revertToFullWhenSyntheticFullFails","fileInactivityThresholdInDays",
+                "fileInactivityAlertThresholdPercentage");
+        return sb.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = ((result * 31) + ((this.enableDDRetentionLock == null) ? 0 : this.enableDDRetentionLock.hashCode()));
+        result = ((result * 31) + ((this.revertToFullWhenSyntheticFullFails == null) ? 0 : this.revertToFullWhenSyntheticFullFails.hashCode()));
+        result = ((result * 31) + ((this.fileInactivityThresholdInDays == null) ? 0 : this.fileInactivityThresholdInDays.hashCode()));
+        result = ((result * 31) + ((this.destinationPool == null) ? 0 : this.destinationPool.hashCode()));
+        result = ((result * 31) + ((this.fileInactivityAlertThresholdPercentage == null) ? 0 : this.fileInactivityAlertThresholdPercentage.hashCode()));
+        result = ((result * 31) + ((this.estimate == null) ? 0 : this.estimate.hashCode()));
+        result = ((result * 31) + ((this.ddRetentionLockTime == null) ? 0 : this.ddRetentionLockTime.hashCode()));
+        result = ((result * 31) + ((this.timestampFormat == null) ? 0 : this.timestampFormat.hashCode()));
+        result = ((result * 31) + ((this.forceBackupLevel == null) ? 0 : this.forceBackupLevel.hashCode()));
+        result = ((result * 31) + ((this.verifySyntheticFull == null) ? 0 : this.verifySyntheticFull.hashCode()));
+        result = ((result * 31) + ((this.browsePeriod == null) ? 0 : this.browsePeriod.hashCode()));
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/module.properties b/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/module.properties
new file mode 100644
index 0000000000..816ba25855
--- /dev/null
+++ b/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/module.properties
@@ -0,0 +1,18 @@
+# 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.
+name=networker
+parent=backup
\ No newline at end of file
diff --git a/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/spring-backup-networker-context.xml b/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/spring-backup-networker-context.xml
new file mode 100644
index 0000000000..271fcc791a
--- /dev/null
+++ b/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/spring-backup-networker-context.xml
@@ -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.
+-->
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns="http://www.springframework.org/schema/beans"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
+>
+
+    <bean id="networkerBackupProvider" class="org.apache.cloudstack.backup.NetworkerBackupProvider">
+        <property name="name" value="networker"/>
+    </bean>
+</beans>
+
diff --git a/plugins/backup/networker/src/test/java/org/apache/backup/networker/NetworkerClientTest.java b/plugins/backup/networker/src/test/java/org/apache/backup/networker/NetworkerClientTest.java
new file mode 100644
index 0000000000..e932b5ec2f
--- /dev/null
+++ b/plugins/backup/networker/src/test/java/org/apache/backup/networker/NetworkerClientTest.java
@@ -0,0 +1,732 @@
+// 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.backup.networker;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.delete;
+import static com.github.tomakehurst.wiremock.client.WireMock.deleteRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
+import static com.github.tomakehurst.wiremock.client.WireMock.verify;
+import static org.apache.cloudstack.backup.NetworkerBackupProvider.BACKUP_IDENTIFIER;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+import com.cloud.vm.VMInstanceVO;
+import com.github.tomakehurst.wiremock.client.VerificationException;
+import org.apache.cloudstack.backup.BackupOffering;
+import org.apache.cloudstack.backup.BackupVO;
+import org.apache.cloudstack.backup.networker.NetworkerClient;
+import org.apache.cloudstack.backup.networker.api.NetworkerBackup;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import com.github.tomakehurst.wiremock.client.BasicCredentials;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+
+public class NetworkerClientTest {
+    private final String adminUsername = "administrator";
+    private final String adminPassword = "password";
+    private final int port = 9399;
+    private final String url =  "http://localhost:" + port + "/nwrestapi/v3";
+    private NetworkerClient client;
+    @Rule
+    public WireMockRule wireMockRule = new WireMockRule(port);
+
+    @Before
+    public void setUp() throws Exception {
+        wireMockRule.stubFor(get(urlMatching(".*")).withBasicAuth(adminUsername, adminPassword)
+                        .willReturn(aResponse()
+                        .withStatus(200)));
+        client = new NetworkerClient(url, adminUsername, adminPassword, false, 60);
+    }
+
+    @Test
+    public void testBasicAuthSuccess() {
+        wireMockRule.stubFor(get(urlEqualTo("/nwrestapi/v3"))
+                .willReturn(aResponse().withStatus(200)));
+        verify(getRequestedFor(urlEqualTo("/nwrestapi/v3"))
+                .withBasicAuth(new BasicCredentials(adminUsername, adminPassword)));
+    }
+    @Test(expected = VerificationException.class)
+    public void testBasicAuthFailure() {
+        wireMockRule.stubFor(get(urlEqualTo("/nwrestapi/v3"))
+                .willReturn(aResponse().withStatus(200)));
+        verify(getRequestedFor(urlEqualTo("/nwrestapi/v3"))
+                .withBasicAuth(new BasicCredentials(adminUsername, "wrongPassword")));
+    }
+    @Test
+    public void testListPolicies() {
+        wireMockRule.stubFor(get(urlMatching(".*/protectionpolicies/.*"))
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", "application/json")
+                        .withStatus(200)
+                        .withBody("{\n" +
+                                "    \"count\": 3,\n" +
+                                "    \"protectionPolicies\": [\n" +
+                                "        {\n" +
+                                "            \"comment\": \"-CSBKP-\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"http://localhost:9399/nwrestapi/v3/global/protectionpolicies/CSBRONZE\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"CSBRONZE\",\n" +
+                                "            \"policyProtectionEnable\": true,\n" +
+                                "            \"policyProtectionPeriod\": \"1 Days\",\n" +
+                                "            \"resourceId\": {\n" +
+                                "                \"id\": \"50.0.224.7.0.0.0.0.164.230.188.98.192.168.1.203\",\n" +
+                                "                \"sequence\": 15\n" +
+                                "            },\n" +
+                                "            \"summaryNotification\": {\n" +
+                                "                \"command\": \"nsrlog -f policy_notifications.log\",\n" +
+                                "                \"executeOn\": \"Completion\"\n" +
+                                "            },\n" +
+                                "            \"workflows\": []\n" +
+                                "        },\n" +
+                                "        {\n" +
+                                "            \"comment\": \"-CSBKP-\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"http://localhost:9399/nwrestapi/v3/global/protectionpolicies/CSGOLD\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"CSGOLD\",\n" +
+                                "            \"policyProtectionEnable\": true,\n" +
+                                "            \"policyProtectionPeriod\": \"1 Months\",\n" +
+                                "            \"resourceId\": {\n" +
+                                "                \"id\": \"52.0.224.7.0.0.0.0.164.230.188.98.192.168.1.203\",\n" +
+                                "                \"sequence\": 37\n" +
+                                "            },\n" +
+                                "            \"summaryNotification\": {\n" +
+                                "                \"command\": \"nsrlog -f policy_notifications.log\",\n" +
+                                "                \"executeOn\": \"Completion\"\n" +
+                                "            },\n" +
+                                "            \"workflows\": []\n" +
+                                "        },\n" +
+                                "        {\n" +
+                                "            \"comment\": \"-CSBKP-\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"http://localhost:9399/nwrestapi/v3/global/protectionpolicies/CSSILVER\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"CSSILVER\",\n" +
+                                "            \"policyProtectionEnable\": true,\n" +
+                                "            \"policyProtectionPeriod\": \"7 Days\",\n" +
+                                "            \"resourceId\": {\n" +
+                                "                \"id\": \"51.0.224.7.0.0.0.0.164.230.188.98.192.168.1.203\",\n" +
+                                "                \"sequence\": 22\n" +
+                                "            },\n" +
+                                "            \"summaryNotification\": {\n" +
+                                "                \"command\": \"nsrlog -f policy_notifications.log\",\n" +
+                                "                \"executeOn\": \"Completion\"\n" +
+                                "            },\n" +
+                                "            \"workflows\": []\n" +
+                                "        }\n" +
+                                "    ]\n" +
+                                "}")));
+        List<BackupOffering> policies = client.listPolicies();
+        verify(getRequestedFor(urlEqualTo("/nwrestapi/v3/global/protectionpolicies/?q=comment:"+ BACKUP_IDENTIFIER)));
+        Assert.assertEquals(3,policies.size());
+        Assert.assertEquals("CSBRONZE",policies.get(0).getName());
+        Assert.assertEquals("CSGOLD",policies.get(1).getName());
+        Assert.assertEquals("CSSILVER",policies.get(2).getName());
+    }
+    @Test
+    public void testListBackupForVM() {
+        wireMockRule.stubFor(get(urlMatching(".*/backups/.*"))
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", "application/json")
+                        .withStatus(200)
+                        .withBody("{\n" +
+                                "    \"backups\": [\n" +
+                                "        {\n" +
+                                "            \"attributes\": [\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ACTUAL_HOST\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"cs-kvm-4\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*backup start time\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"1657607395\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ss clone retention\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"          1657607395:          1657607395:-204083220\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"saveset features\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"CLIENT_SAVETIME\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"browseTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"clientHostname\": \"C1\",\n" +
+                                "            \"clientId\": \"cb2bf6eb-00000004-62c176f2-62c176f1-00021500-5a80015d\",\n" +
+                                "            \"completionTime\": \"2022-07-12T09:29:57+03:00\",\n" +
+                                "            \"creationTime\": \"2022-07-12T09:29:55+03:00\",\n" +
+                                "            \"fileCount\": 5,\n" +
+                                "            \"id\": \"6034732f-00000006-7acd14e3-62cd14e3-00871500-5a80015d\",\n" +
+                                "            \"instances\": [\n" +
+                                "                {\n" +
+                                "                    \"clone\": false,\n" +
+                                "                    \"id\": \"1657607395\",\n" +
+                                "                    \"status\": \"Browsable\",\n" +
+                                "                    \"volumeIds\": [\n" +
+                                "                        \"2127369368\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"level\": \"Manual\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"http://localhost:9399/nwrestapi/v3/global/backups/6034732f-00000006-7acd14e3-62cd14e3-00871500-5a80015d\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"i-2-15-VM\",\n" +
+                                "            \"retentionTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"saveTime\": \"2022-07-12T09:29:55+03:00\",\n" +
+                                "            \"shortId\": \"2060260579\",\n" +
+                                "            \"size\": {\n" +
+                                "                \"unit\": \"Byte\",\n" +
+                                "                \"value\": 658603164\n" +
+                                "            },\n" +
+                                "            \"type\": \"File\"\n" +
+                                "        },\n" +
+                                "        {\n" +
+                                "            \"attributes\": [\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ACTUAL_HOST\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"cs-kvm-4\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*backup start time\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"1657592454\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ss clone retention\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"          1657592455:          1657592455:-204068280\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"saveset features\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"CLIENT_SAVETIME\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"browseTime\": \"2152-02-29T13:11:10+02:00\",\n" +
+                                "            \"clientHostname\": \"C1\",\n" +
+                                "            \"clientId\": \"cb2bf6eb-00000004-62c176f2-62c176f1-00021500-5a80015d\",\n" +
+                                "            \"completionTime\": \"2022-07-12T05:20:59+03:00\",\n" +
+                                "            \"creationTime\": \"2022-07-12T05:20:55+03:00\",\n" +
+                                "            \"fileCount\": 5,\n" +
+                                "            \"id\": \"98d29c5e-00000006-81ccda87-62ccda87-00801500-5a80015d\",\n" +
+                                "            \"instances\": [\n" +
+                                "                {\n" +
+                                "                    \"clone\": false,\n" +
+                                "                    \"id\": \"1657592455\",\n" +
+                                "                    \"status\": \"Browsable\",\n" +
+                                "                    \"volumeIds\": [\n" +
+                                "                        \"12647424\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"level\": \"Manual\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"http://localhost:9399/nwrestapi/v3/global/backups/98d29c5e-00000006-81ccda87-62ccda87-00801500-5a80015d\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"i-2-15-VM\",\n" +
+                                "            \"retentionTime\": \"2152-02-29T13:11:10+02:00\",\n" +
+                                "            \"saveTime\": \"2022-07-12T05:20:54+03:00\",\n" +
+                                "            \"shortId\": \"2177686151\",\n" +
+                                "            \"size\": {\n" +
+                                "                \"unit\": \"Byte\",\n" +
+                                "                \"value\": 658632924\n" +
+                                "            },\n" +
+                                "            \"type\": \"File\"\n" +
+                                "        },\n" +
+                                "        {\n" +
+                                "            \"attributes\": [\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ACTUAL_HOST\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"cs-kvm-4\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*backup start time\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"1657591323\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ss clone retention\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"          1657591323:          1657591323:-204067148\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"saveset features\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"CLIENT_SAVETIME\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"browseTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"clientHostname\": \"C1\",\n" +
+                                "            \"clientId\": \"cb2bf6eb-00000004-62c176f2-62c176f1-00021500-5a80015d\",\n" +
+                                "            \"completionTime\": \"2022-07-12T05:02:06+03:00\",\n" +
+                                "            \"creationTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"fileCount\": 5,\n" +
+                                "            \"id\": \"d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "            \"instances\": [\n" +
+                                "                {\n" +
+                                "                    \"clone\": false,\n" +
+                                "                    \"id\": \"1657591323\",\n" +
+                                "                    \"status\": \"Browsable\",\n" +
+                                "                    \"volumeIds\": [\n" +
+                                "                        \"12647424\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"level\": \"Manual\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"http://localhost:9399/nwrestapi/v3/global/backups/d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"i-2-15-VM\",\n" +
+                                "            \"retentionTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"saveTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"shortId\": \"2228016667\",\n" +
+                                "            \"size\": {\n" +
+                                "                \"unit\": \"Byte\",\n" +
+                                "                \"value\": 658580844\n" +
+                                "            },\n" +
+                                "            \"type\": \"File\"\n" +
+                                "        }\n" +
+                                "    ],\n" +
+                                "    \"count\": 3\n" +
+                                "}")));
+        VMInstanceVO backupedVM = new VMInstanceVO();
+        backupedVM.setInstanceName("i-2-15-VM");
+        List<String> backupsTaken = client.getBackupsForVm(backupedVM);
+        verify(getRequestedFor(urlEqualTo("/nwrestapi/v3/global/backups/?q=name:"+backupedVM.getName())));
+        Assert.assertEquals(3,backupsTaken.size());
+        Assert.assertEquals("6034732f-00000006-7acd14e3-62cd14e3-00871500-5a80015d",backupsTaken.get(0));
+        Assert.assertEquals("98d29c5e-00000006-81ccda87-62ccda87-00801500-5a80015d",backupsTaken.get(1));
+        Assert.assertEquals("d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d",backupsTaken.get(2));
+    }
+
+    @Test(expected = java.lang.AssertionError.class)
+    public void testRegisterBackupInvalid() {
+        wireMockRule.stubFor(get(urlMatching(".*/backups/.*"))
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", "application/json")
+                        .withStatus(200)
+                        .withBody("{\n" +
+                                "    \"backups\": [\n" +
+                                "        {\n" +
+                                "            \"attributes\": [\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ACTUAL_HOST\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"cs-kvm-4\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*backup start time\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"1657591323\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ss clone retention\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"          1657591323:          1657591323:-204067148\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"saveset features\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"CLIENT_SAVETIME\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"browseTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"clientHostname\": \"C1\",\n" +
+                                "            \"clientId\": \"cb2bf6eb-00000004-62c176f2-62c176f1-00021500-5a80015d\",\n" +
+                                "            \"completionTime\": \"2022-07-12T05:02:06+03:00\",\n" +
+                                "            \"creationTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"fileCount\": 5,\n" +
+                                "            \"id\": \"d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "            \"instances\": [\n" +
+                                "                {\n" +
+                                "                    \"clone\": false,\n" +
+                                "                    \"id\": \"1657591323\",\n" +
+                                "                    \"status\": \"Browsable\",\n" +
+                                "                    \"volumeIds\": [\n" +
+                                "                        \"12647424\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"level\": \"Manual\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"https://192.168.1.203:9090/nwrestapi/v3/global/backups/d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"i-2-15-VM\",\n" +
+                                "            \"retentionTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"saveTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"shortId\": \"2228016667\",\n" +
+                                "            \"size\": {\n" +
+                                "                \"unit\": \"Byte\",\n" +
+                                "                \"value\": 658580844\n" +
+                                "            },\n" +
+                                "            \"type\": \"File\"\n" +
+                                "        }\n" +
+                                "    ],\n" +
+                                "    \"count\": 1\n" +
+                                "}")));
+
+
+        VMInstanceVO backupedVM = new VMInstanceVO();
+        backupedVM.setInstanceName("some-random-vm");
+        backupedVM.setUuid("some-random-uuid");
+        backupedVM.setBackupOfferingId(0L);
+        backupedVM.setDataCenterId(1);
+        Date backupDate = new Date();
+        BackupVO vmBackup = client.registerBackupForVm(backupedVM, backupDate, null);
+        verify(getRequestedFor(urlEqualTo("/nwrestapi/v3/global/backups/?q=name:" + backupedVM.getName())));
+        Assert.assertEquals("658580844", vmBackup.getSize().toString());
+    }
+
+
+        @Test
+    public void testregisterBackupForVMwithSsid() {
+        wireMockRule.stubFor(get(urlMatching(".*/backups/.*"))
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", "application/json")
+                        .withStatus(200)
+                        .withBody("{\n" +
+                                "    \"backups\": [\n" +
+                                "        {\n" +
+                                "            \"attributes\": [\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ACTUAL_HOST\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"cs-kvm-4\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*backup start time\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"1657591323\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ss clone retention\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"          1657591323:          1657591323:-204067148\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"saveset features\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"CLIENT_SAVETIME\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"browseTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"clientHostname\": \"C1\",\n" +
+                                "            \"clientId\": \"cb2bf6eb-00000004-62c176f2-62c176f1-00021500-5a80015d\",\n" +
+                                "            \"completionTime\": \"2022-07-12T05:02:06+03:00\",\n" +
+                                "            \"creationTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"fileCount\": 5,\n" +
+                                "            \"id\": \"d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "            \"instances\": [\n" +
+                                "                {\n" +
+                                "                    \"clone\": false,\n" +
+                                "                    \"id\": \"1657591323\",\n" +
+                                "                    \"status\": \"Browsable\",\n" +
+                                "                    \"volumeIds\": [\n" +
+                                "                        \"12647424\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"level\": \"Manual\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"https://192.168.1.203:9090/nwrestapi/v3/global/backups/d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"i-2-15-VM\",\n" +
+                                "            \"retentionTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"saveTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"shortId\": \"2228016667\",\n" +
+                                "            \"size\": {\n" +
+                                "                \"unit\": \"Byte\",\n" +
+                                "                \"value\": 658580844\n" +
+                                "            },\n" +
+                                "            \"type\": \"File\"\n" +
+                                "        }\n" +
+                                "    ],\n" +
+                                "    \"count\": 1\n" +
+                                "}")));
+
+
+        VMInstanceVO backupedVM = new VMInstanceVO();
+        backupedVM.setInstanceName("i-2-15-VM");
+        backupedVM.setUuid("some-random-uuid");
+        backupedVM.setBackupOfferingId(0L);
+        backupedVM.setDataCenterId(1);
+        SimpleDateFormat formatterDateTime = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
+        Long startTS=1657591323L;
+        Instant instant = Instant.ofEpochSecond(startTS);
+        Date backupDate = Date.from(instant);
+        String saveTime = formatterDateTime.format(Date.from(instant));
+        BackupVO vmBackup = client.registerBackupForVm(backupedVM,backupDate,startTS.toString());
+        verify(getRequestedFor(urlEqualTo("/nwrestapi/v3/global/backups/?q=name:"+backupedVM.getName()+"+and+saveTime:'"+saveTime+"'")));
+        Assert.assertEquals("658580844", vmBackup.getSize().toString());
+        Assert.assertEquals("d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d",vmBackup.getExternalId());
+
+
+    }
+
+    @Test
+    public void testregisterBackupForVMwithOutSsid() {
+        wireMockRule.stubFor(get(urlMatching(".*/backups/.*"))
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", "application/json")
+                        .withStatus(200)
+                        .withBody("{\n" +
+                                "    \"backups\": [\n" +
+                                "        {\n" +
+                                "            \"attributes\": [\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ACTUAL_HOST\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"cs-kvm-4\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*backup start time\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"1657591323\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ss clone retention\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"          1657591323:          1657591323:-204067148\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"saveset features\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"CLIENT_SAVETIME\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"browseTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"clientHostname\": \"C1\",\n" +
+                                "            \"clientId\": \"cb2bf6eb-00000004-62c176f2-62c176f1-00021500-5a80015d\",\n" +
+                                "            \"completionTime\": \"2022-07-12T05:02:06+03:00\",\n" +
+                                "            \"creationTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"fileCount\": 5,\n" +
+                                "            \"id\": \"d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "            \"instances\": [\n" +
+                                "                {\n" +
+                                "                    \"clone\": false,\n" +
+                                "                    \"id\": \"1657591323\",\n" +
+                                "                    \"status\": \"Browsable\",\n" +
+                                "                    \"volumeIds\": [\n" +
+                                "                        \"12647424\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"level\": \"Manual\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"https://192.168.1.203:9090/nwrestapi/v3/global/backups/d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"i-2-15-VM\",\n" +
+                                "            \"retentionTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"saveTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"shortId\": \"2228016667\",\n" +
+                                "            \"size\": {\n" +
+                                "                \"unit\": \"Byte\",\n" +
+                                "                \"value\": 658580844\n" +
+                                "            },\n" +
+                                "            \"type\": \"File\"\n" +
+                                "        }\n" +
+                                "    ],\n" +
+                                "    \"count\": 1\n" +
+                                "}")));
+
+
+        VMInstanceVO backupedVM = new VMInstanceVO();
+        backupedVM.setInstanceName("i-2-15-VM");
+        backupedVM.setUuid("some-random-uuid");
+        backupedVM.setBackupOfferingId(0L);
+        backupedVM.setDataCenterId(1);
+        SimpleDateFormat formatterDate = new SimpleDateFormat("yyyy-MM-dd");
+        SimpleDateFormat formatterTime = new SimpleDateFormat("HH:mm:ss");
+        Long startTS=1657591323L;
+        Instant instant = Instant.ofEpochSecond(startTS);
+        Date backupDate = Date.from(instant);
+        String startDate = formatterDate.format(backupDate);
+        String startTime = formatterTime.format(backupDate);
+        String endDate = formatterDate.format(new Date());
+        String endTime = formatterTime.format(new Date());
+        final String searchRange = "['" + startDate + "T" + startTime + "'+TO+'" + endDate + "T" + endTime + "']";
+        BackupVO vmBackup = client.registerBackupForVm(backupedVM,backupDate,null);
+        verify(getRequestedFor(urlEqualTo("/nwrestapi/v3/global/backups/?q=name:"+backupedVM.getName()+"+and+saveTime:"+searchRange)));
+        Assert.assertEquals("658580844", vmBackup.getSize().toString());
+        Assert.assertEquals("d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d",vmBackup.getExternalId());
+    }
+
+    @Test
+    public void testDeleteVMBackup() {
+        wireMockRule.stubFor(delete(urlMatching(".*/backups/.*"))
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", "application/json")
+                        .withStatus(204)
+                        .withBody("1")));
+
+        String deleteBackupId = "d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d2";
+        Boolean status = client.deleteBackupForVM(deleteBackupId);
+        verify(deleteRequestedFor(urlEqualTo("/nwrestapi/v3/global/backups/" + deleteBackupId)));
+        Assert.assertEquals(true, status);
+
+    }
+
+    @Test
+    public void testNetworkerBackupInfo() {
+        wireMockRule.stubFor(get(urlMatching(".*/backups/.*"))
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", "application/json")
+                        .withStatus(200)
+                        .withBody("{\n" +
+                                "    \"backups\": [\n" +
+                                "        {\n" +
+                                "            \"attributes\": [\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ACTUAL_HOST\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"cs-kvm-4\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*backup start time\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"1657591323\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"*ss clone retention\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"          1657591323:          1657591323:-204067148\"\n" +
+                                "                    ]\n" +
+                                "                },\n" +
+                                "                {\n" +
+                                "                    \"key\": \"saveset features\",\n" +
+                                "                    \"values\": [\n" +
+                                "                        \"CLIENT_SAVETIME\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"browseTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"clientHostname\": \"C1\",\n" +
+                                "            \"clientId\": \"cb2bf6eb-00000004-62c176f2-62c176f1-00021500-5a80015d\",\n" +
+                                "            \"completionTime\": \"2022-07-12T05:02:06+03:00\",\n" +
+                                "            \"creationTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"fileCount\": 5,\n" +
+                                "            \"id\": \"d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "            \"instances\": [\n" +
+                                "                {\n" +
+                                "                    \"clone\": false,\n" +
+                                "                    \"id\": \"1657591323\",\n" +
+                                "                    \"status\": \"Browsable\",\n" +
+                                "                    \"volumeIds\": [\n" +
+                                "                        \"12647424\"\n" +
+                                "                    ]\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"level\": \"Manual\",\n" +
+                                "            \"links\": [\n" +
+                                "                {\n" +
+                                "                    \"href\": \"https://192.168.1.203:9090/nwrestapi/v3/global/backups/d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d\",\n" +
+                                "                    \"rel\": \"item\"\n" +
+                                "                }\n" +
+                                "            ],\n" +
+                                "            \"name\": \"i-2-15-VM\",\n" +
+                                "            \"retentionTime\": \"2152-02-29T13:11:11+02:00\",\n" +
+                                "            \"saveTime\": \"2022-07-12T05:02:03+03:00\",\n" +
+                                "            \"shortId\": \"2228016667\",\n" +
+                                "            \"size\": {\n" +
+                                "                \"unit\": \"Byte\",\n" +
+                                "                \"value\": 658580844\n" +
+                                "            },\n" +
+                                "            \"type\": \"File\"\n" +
+                                "        }\n" +
+                                "    ],\n" +
+                                "    \"count\": 1\n" +
+                                "}")));
+
+
+        String backupId="d371d629-00000006-84ccd61b-62ccd61b-007d1500-5a80015d";
+        NetworkerBackup backup = client.getNetworkerBackupInfo(backupId);
+        verify(getRequestedFor(urlEqualTo("/nwrestapi/v3/global/backups/?q=id:"+backupId)));
+        Assert.assertEquals("658580844", backup.getSize().getValue().toString());
+        Assert.assertEquals("cb2bf6eb-00000004-62c176f2-62c176f1-00021500-5a80015d", backup.getClientId());
+        Assert.assertEquals("2022-07-12T05:02:03+03:00", backup.getSaveTime());
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 461ec0e02c..736b5de0db 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -61,6 +61,7 @@
         <module>api/solidfire-intg-test</module>
 
         <module>backup/dummy</module>
+        <module>backup/networker</module>
 
         <module>ca/root-ca</module>
 
diff --git a/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh b/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh
new file mode 100755
index 0000000000..c6e115fdc6
--- /dev/null
+++ b/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh
@@ -0,0 +1,260 @@
+#!/bin/bash
+## 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.
+
+version=0.9.1
+OPTIND=1
+verb=0
+logDir="/nsr/logs/cloudstack/"
+snapPrefix="CSBKP_"$RANDOM"_"
+clusterClient=""
+networkerServer=""
+hvVersion=""
+libvVersion=""
+apiVersion=""
+kvmDName=""
+kvmDUuid=""
+logFile=""
+mediaPool=""
+retentionTime=""
+
+log () {
+
+    [[ "$verb" -eq 1 ]] && builtin echo "$@"
+    if [[ "$1" == "-ne"  || "$1" == "-e" || "$1" == "-n" ]]; then
+          builtin echo -e "$(date '+%Y-%m-%d %H-%M-%S>')" "${@: 2}" >> "$logFile"
+    else
+          builtin echo "$(date '+%Y-%m-%d %H-%M-%S>')" "$@" >> "$logFile"
+    fi
+}
+
+vercomp(){
+   local a b IFS=. -; set -f
+   printf -v a %08d $1; printf -v b %08d $3
+   test $a "$2" $b
+}
+
+usage() {
+        echo "
+
+Usage:[-v] [-h] [-l log_dir] [-dr] [-s networker_server] [-c networker_cluster_client] [-t target_vm] [-u target_uuid] [-p snapprefix] [-P media_pool ] [-R retention_time ]
+
+Options:
+        -h Help and usage
+        -v Enable verbose mode
+        -l log_dir. Specify log directory. Default is /nsr/logs/cloudstack
+        -s networker_server  Specifiy the EMC Networker server we are going to use
+        -c networker_cluster_client  Specify the EMC Networker client CLUSTER to use
+        -t target_vm KVM domain to backup
+        -u target_uuid KVM domain to backup
+        -p Snapshot Prefix for backups
+        -P mediaPool EMC Networker Media Pool
+        -R retention_time Backup retention time
+Supplements Apache Cloudstack B&R Framework  EMC Networker plugin and performs the backup of the Virtual Machines
+"
+
+}
+
+sanity_checks() {
+
+        log "Performing environment sanity checks..."
+        log -ne "\t[1] Checking if Networker is installed\t"
+        if [[ $(systemctl list-unit-files | grep networker) = *networker* ]]; then
+                        log "Success"
+        else
+                        log "Failure"
+                        log -e "\n\tNetworker Service NOT FOUND. Make sure that Networker client is properly installed"
+                        exit 1
+        fi
+
+        log -ne "\t[2] Checking if Networker is running\t"
+        if [[ $(systemctl is-active networker) = *active* ]]; then
+                        log "Success"
+        else
+                        log "Failure"
+                        log -e "\n\tNetworker Service is not running. Investigate Networker logs, startup server and try again"
+                        exit 2
+        fi
+        log -ne "\t[3] Checking Networker DNS Resolution\t"
+        if [[ $(getent hosts "$networkerServer") = *$networkerServer* ]]; then
+                        log "Success"
+        else
+                        log "Failure"
+                        log -e "\n\tNetworker Server cannot be resolved. Backups will most probably fail. Consider adding the ip/hostname to /etc/host or fix DNS resolution"
+                        exit 3
+        fi
+
+        log -ne "\t[4] Checking QEMU / Libvirt Versions \t"
+        hvVersion=$(virsh version | grep hypervisor | awk '{print $(NF)}')
+        libvVersion=$(virsh version | grep libvirt | awk '{print $(NF)}' | tail -n 1)
+        apiVersion=$(virsh version | grep API | awk '{print $(NF)}')
+        if vercomp "$hvVersion" \> 2.1.2; then
+                log -n "Success"
+                log -ne "\t\t [ Libvirt: $libvVersion apiVersion: $apiVersion ]"
+                echo
+
+        else
+                log "Failure"
+                log -e "\n\tYour QEMU version $hvVersion is unsupported. Consider upgrading at least to latest QEMU at branch 2"
+                exit 4
+        fi
+
+        log -ne "\t[4] Checking Permissions \t\t"
+        if groups $USER | grep -q '\blibvirt\b'; then
+            log -n "Success"
+            log -ne "\t\t User $USER is part of libvirt group"
+            echo
+        else
+            log "Failure - User $USER is not part of libvirt group"
+            exit 6
+        fi
+        log "Environment Sanity Checks successfully passed"
+}
+
+
+
+echo "
+Cloudstack B&R Framework - EMC Networker backup script
+Version $version
+"
+
+backup_domain() {
+
+        name=$1
+        snapName=$2
+        log  "Preparing snapshots and gathering information for backing up domain $name under snapshot name $snapName"
+        log  "Retention time is $retentionTime"
+
+        declare -A TRGSRC
+        while IFS=',' read -r TARGET SOURCE
+        do
+                if [[ $SOURCE != "-" ]]; then
+                        TRGSRC+=(["$TARGET"]="$SOURCE")
+                fi
+        done < <(virsh -c qemu:///system domblklist "$name" --details | grep file | grep -v 'cdrom' | grep -v 'floppy' | sed 's/  */,/g' |  cut -d',' -f 4-)
+        diskspec=""
+        for target in "${!TRGSRC[@]}"; do
+          log -e "\tDisk for $target is at ${TRGSRC[${target}]}"
+          diskspec="$diskspec --diskspec $target,snapshot=external"
+          disks="$disks ${TRGSRC[${target}]} "
+        done
+
+        cmd="$(virsh -c qemu:///system snapshot-create-as --domain "$name" --name "$snapName" --no-metadata --atomic --quiesce --disk-only "$diskspec")"
+        retVal=$?
+        log "$cmd"
+        if [ "$retVal" -ne 0 ]; then
+                log "Agent not responding, trying to snapshot directly"
+                cmd="$(virsh -c qemu:///system snapshot-create-as --domain "$name" --name "$snapName" --no-metadata --atomic --disk-only "$diskspec")"
+                retVal=$?
+                if [ "$retVal" -ne 0 ]; then
+                        log "Failed to create snapshot for $name"
+                        exit 7
+                fi
+                log "Created snapshot(s) for $name"
+        fi
+        cmd="$(save -LL -q -e "${retentionTime}" -s "$networkerServer" -c "$clusterClient" -N "$name" -b "$mediaPool" $disks)"
+        retVal=$?
+        log "$cmd"
+        echo "$cmd" | grep -oE 'savetime=[0-9]{10}'
+        if [ $retVal -ne 0 ]; then
+                log "Unable to backup $disks for $name"
+        else
+                log "Backup $disks for $name completed!!"
+        fi
+
+        #Merge changes and conclude
+        SNAPSHOTS="$(virsh -c qemu:///system domblklist "$name" --details | grep file | grep -v 'cdrom' | grep -v 'floppy' | awk '{print $4}')"
+        for target in "${!TRGSRC[@]}"; do
+                log "Merging Snasphots for $target"
+                cmd="$(virsh -c qemu:///system blockcommit "$name" "$target" --active --pivot)"
+                retVal=$?
+                log "$cmd"
+                if [ $retVal -ne 0 ]; then
+                        log "Unable to merge disk %target changes for domain $name"
+                        exit 8
+                fi
+        done
+        #Clean snapshots
+        for snapshot in $SNAPSHOTS; do
+             log "Deleting Snapshot $snapshot"
+             cmd=$(rm -f "$snapshot")
+             retVal=$?
+             log "$cmd"
+             if [ $retVal -ne 0 ]; then
+                     log "Unable to delete snapshot $snapshot"
+                     exit 8
+             fi
+             log "Deleted Snapshot: $snapshot"
+         done
+}
+
+while getopts "h?vs:l:c:t:u:p:P:R:" opt; do
+  case "$opt" in
+    h|\?)
+      usage
+      exit 254
+      ;;
+     c) clusterClient="$OPTARG"
+      ;;
+     s) networkerServer="$OPTARG"
+      ;;
+     l) logDir="$OPTARG"
+      ;;
+     t) kvmDName="$OPTARG"
+      ;;
+     u) kvmDUuid="$OPTARG"
+      ;;
+     p) snapPrefix="$OPTARG"
+      ;;
+     P) mediaPool="$OPTARG"
+          ;;
+     R) retentionTime="$OPTARG"
+       ;;
+     v)  verb=1
+       ;;
+   esac
+ done
+
+ shift $((OPTIND-1))
+
+ [ "${1:-}" = "--" ] && shift
+ if [[ -z "$networkerServer" || -z "$kvmDName" || -z "$clusterClient" || -z "$kvmDUuid" ]];  then
+     usage
+     exit 255
+ fi
+
+ if [ ! -d "$logDir" ]; then
+   mkdir -p "$logDir"
+ fi
+
+ logFile="$logDir/BACKUP-$kvmDName-$(date +'%Y_%m_%d_%I_%M_%p').log"
+
+ # Perform Initial sanity checks
+ sanity_checks
+
+ log -e "\nLooking for domain $kvmDName with UUID $kvmDUuid"
+ if [[ "$kvmDName" == $(virsh -c qemu:///system domname "$kvmDUuid" | head -1) && "$kvmDUuid" == $(virsh -c qemu:///system domuuid "$kvmDName" | head -1) ]]; then
+         log "Domain found...."
+ else
+         log "Domain not found on this host. Aborting....."
+         log "Check for the location of the Instance in the cloudstack management console"
+         exit 5
+ fi
+
+ backup_domain "$kvmDName" "$snapPrefix$kvmDName"
+
+ exit 0
\ No newline at end of file
diff --git a/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh b/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh
new file mode 100755
index 0000000000..ad3865d7f1
--- /dev/null
+++ b/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh
@@ -0,0 +1,223 @@
+#!/bin/bash
+## 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.
+
+version=0.9.1
+OPTIND=1
+OPTIND=1
+verb=0
+logDir="/nsr/logs/cloudstack/"
+clusterClient=""
+networkerServer=""
+hvVersion=""
+libvVersion=""
+apiVersion=""
+logFile=""
+destination=""
+volume=""
+ssid=""
+newvolumeUuid=""
+POOLPATH=""
+
+log () {
+     [[ "$verb" -eq 1 ]] && builtin echo "$@"
+     if [[ "$1" == "-ne"  || "$1" == "-e" || "$1" == "-n" ]]; then
+         builtin echo -e "$(date '+%Y-%m-%d %H-%M-%S>')" "${@: 2}" >> "$logFile"
+     else
+          builtin echo "$(date '+%Y-%m-%d %H-%M-%S>')" "$@" >> "$logFile"
+     fi
+}
+
+vercomp() {
+       local a b IFS=. -; set -f
+       printf -v a %08d $1; printf -v b %08d $3
+       test $a "$2" $b
+}
+
+usage() {
+        echo "
+
+Usage:[-v] [-h] [-l log_dir] [-s networker_server] [-c networker_cluster_client] [-S ssid] [-d networker_destination_client ] [ -a volume ] [ -p pool_local_path ]
+
+Options:
+        -h Help and usage
+        -v Enable log mode
+        -l log_dir. Specify log directory. Default is /nsr/logs/cloudstack
+        -s networker_server  Specify the EMC Networker server we are going to use
+        -c networker_cluster_client  Specify the EMC Networker client CLUSTER to use
+        -d networker_destination_client Specify the EMC Networker client that is going to be used for the restore
+        -a volume Specify volume to restore
+        -p pool_local_path Local Path to Pool
+        -S ssid Specify SSID
+Supplements Apache Cloudstack B&R Framework  EMC Networker plugin and performs the backup of the Virtual Machines
+"
+
+}
+
+sanity_checks() {
+        log "Performing environment sanity checks..."
+
+        log -ne "\t[1] Checking if Networker is installed\t"
+        if [[ $(systemctl list-unit-files | grep networker) = *networker* ]]; then
+                        log "Success"
+        else
+                        log "Failure"
+                        log -e "\n\tNetworker Service NOT FOUND. Make sure that Networker client is properly installed"
+                        exit 1
+        fi
+
+        log -ne "\t[2] Checking if Networker is running\t"
+        if [[ $(systemctl is-active networker) = *active* ]]; then
+                        log "Success"
+        else
+                        log "Failure"
+                        log -e "\n\tNetworker Service is not running. Investigate Networker logs, startup server and try again"
+                        exit 2
+        fi
+        log -ne "\t[3] Checking Networker DNS Resolution\t"
+        if [[ $(getent hosts "$networkerServer") = *$networkerServer* ]]; then
+                        log "Success"
+        else
+                        log "Failure"
+                        log -e "\n\tNetworker Server cannot be resolved. Backups will most probably fail. Consider adding the ip/hostname to /etc/host or fix DNS resolution"
+                        exit 3
+        fi
+
+        log -ne "\t[4] Checking QEMU / Libvirt Versions \t"
+        hvVersion=$(virsh version | grep hypervisor | awk '{print $(NF)}')
+        libvVersion=$(virsh version | grep libvirt | awk '{print $(NF)}' | tail -n 1)
+        apiVersion=$(virsh version | grep API | awk '{print $(NF)}')
+        if vercomp "$hvVersion" \> 2.1.2; then
+                log -n "Success"
+                log -ne "\t\t [ Libvirt: $libvVersion apiVersion: $apiVersion ]"
+                echo
+        else
+                log "Failure"
+                log -e "\n\tYour QEMU version $hvVersion is unsupported. Consider upgrading at least to latest QEMU at branch 2"
+                exit 4
+        fi
+        log "Environment Sanity Checks successfully passed"
+}
+echo "
+Cloudstack B&R Framework - EMC Networker backup script
+Version $version
+"
+restore_all_volumes() {
+        log "Preparing restore for SAVESET $ssid"
+        cmd="$(sudo recover -s "$networkerServer" -S "$ssid" -iY)"
+        retVal=$?
+        log "$cmd"
+        if [ "$retVal" -ne 0 ]; then
+                log "Unable to restore SAVESET $ssid"
+                exit 4
+        else
+                log "Restore of SAVESET $ssid has been completed"
+        fi
+}
+
+restore_volume() {
+        log "Preparning restore for volume $volume at destination as  $POOLPATH/$newvolumeUuid"
+        cmd="$(recover -R "$destination" -c "$clusterClient" -s "$networkerServer" -a "$POOLPATH/$volume" -iR)"
+        retVal=$?
+        log "$cmd"
+        if [ "$retVal" -ne 0 ]; then
+                log "Unable to restore SAVESET $ssid"
+                exit 5
+        else
+                log "Restore of SAVESET $ssid has been completed"
+        fi
+
+        if [ -f "$POOLPATH/$volume.R" ]; then
+            mv "$POOLPATH/$volume.R" "$POOLPATH/$newvolumeUuid"
+        else
+            mv "$POOLPATH/$volume" "$POOLPATH/$newvolumeUuid"
+        fi
+
+        if [ -f "$POOLPATH/$newvolumeUuid" ]; then
+                log "Volume restored under path/name: $POOLPATH/$newvolumeUuid"
+
+        else
+                log "Unable to verify final restored volume: $POOLPATH/$newvolumeUuid"
+                exit 6
+        fi
+
+}
+
+while getopts "h?vs:l:c:d:a:S:n:p:" opt; do
+  case "$opt" in
+    h|\?)
+      usage
+      exit 254
+      ;;
+    c) clusterClient="$OPTARG"
+     ;;
+    s) networkerServer="$OPTARG"
+     ;;
+    l) logDir="$OPTARG"
+     ;;
+    d) destination="$OPTARG"
+     ;;
+    a) volume="$OPTARG"
+     ;;
+    S) ssid="$OPTARG"
+     ;;
+    n) newvolumeUuid="$OPTARG"
+     ;;
+    p) POOLPATH="$OPTARG"
+     ;;
+    v)  verb=1
+      ;;
+  esac
+done
+shift $((OPTIND-1))
+
+[ "${1:-}" = "--" ] && shift
+
+if [[ -n "$newvolumeUuid" ]]; then
+  if [[ -z "$networkerServer" || -z "$destination" || -z "$clusterClient" || -z "$newvolumeUuid" || -z "$POOLPATH" ]];  then
+    usage
+    exit 255
+  fi
+elif [[ -n "$ssid" ]]; then
+   if [[ -z "$networkerServer" ]];  then
+      usage
+      exit 255
+    fi
+elif [[ -n "$ssid" && -n "$volumeUuid" ]]; then
+      echo "You can either restore a whole saveset or part of it but not both."
+      exit 250
+else
+  exit 255
+fi
+
+if [ ! -d "$logDir" ]; then
+  mkdir -p "$logDir"
+fi
+
+
+if [[ -z "$ssid" && -n "$newvolumeUuid" ]]; then
+        logFile="$logDir/RESTORE-$newvolumeUuid-$(date +'%Y_%m_%d_%I_%M_%p').log"
+        # Perform Initial sanity checks
+        sanity_checks
+        restore_volume
+elif [[ -n "$ssid" && -z "$newvolumeUuid" ]]; then
+        logFile="$logDir/RESTORE-$ssid-$(date +'%Y_%m_%d_%I_%M_%p').log"
+        # Perform Initial sanity checks
+        sanity_checks
+        restore_all_volumes
+fi
+exit 0
\ No newline at end of file
diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
index dfb72f6b47..412bd40f8f 100644
--- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
+++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
@@ -23,26 +23,35 @@ import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.configuration.ConfigurationManagerImpl;
 import com.cloud.host.HostVO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
 import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.GuestOSHypervisorVO;
 import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.Volume;
+import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.GuestOSDao;
 import com.cloud.storage.dao.GuestOSHypervisorDao;
+import com.cloud.storage.dao.VolumeDao;
 import com.cloud.utils.Pair;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.UserVmManager;
+import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.VMInstanceDao;
+import org.apache.cloudstack.backup.Backup;
 import org.apache.cloudstack.storage.command.CopyCommand;
 import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
 import org.apache.commons.collections.MapUtils;
 import org.apache.log4j.Logger;
-
 import javax.inject.Inject;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
@@ -55,7 +64,12 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
     GuestOSHypervisorDao _guestOsHypervisorDao;
     @Inject
     DpdkHelper dpdkHelper;
-
+    @Inject
+    VMInstanceDao _instanceDao;
+    @Inject
+    VolumeDao _volumeDao;
+    @Inject
+    HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
 
     public static final Logger s_logger = Logger.getLogger(KVMGuru.class);
 
@@ -68,6 +82,37 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
         super();
     }
 
+    /**
+     * Get next free DeviceId for a KVM Guest
+     */
+
+    protected Long getNextAvailableDeviceId(List<VolumeVO> vmVolumes) {
+
+        int maxDataVolumesSupported;
+        int maxDeviceId;
+        List<String> devIds = new ArrayList<>();
+
+        try {
+            maxDataVolumesSupported = _hypervisorCapabilitiesDao.getMaxDataVolumesLimit(HypervisorType.KVM,"default");
+            int maxDevices = maxDataVolumesSupported + 2; // add 2 to consider devices root volume and cdrom
+            maxDeviceId = maxDevices - 1;
+        } catch (Exception e) {
+            throw new RuntimeException("Cannot find maximum number of disk devices that can be attached to the KVM Hypervisor");
+        }
+        for (int i = 1; i <= maxDeviceId; i++) {
+            devIds.add(String.valueOf(i));
+        }
+        devIds.remove("3");
+        for (VolumeVO vmVolume : vmVolumes) {
+            devIds.remove(vmVolume.getDeviceId().toString().trim());
+        }
+        if (devIds.isEmpty()) {
+            throw new RuntimeException("All device Ids are in use.");
+        }
+        return Long.parseLong(devIds.iterator().next());
+    }
+
+
     /**
      * Retrieve host max CPU speed
      */
@@ -80,10 +125,10 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
     }
 
     /**
-    * Set VM CPU quota percentage with respect to host CPU on 'to' if CPU limit option is set
-    * @param to vm to
-    * @param vmProfile vm profile
-    */
+     * Set VM CPU quota percentage with respect to host CPU on 'to' if CPU limit option is set
+     * @param to vm to
+     * @param vmProfile vm profile
+     */
     protected void setVmQuotaPercentage(VirtualMachineTO to, VirtualMachineProfile vmProfile) {
         if (to.getLimitCpuUse()) {
             VirtualMachine vm = vmProfile.getVirtualMachine();
@@ -152,7 +197,7 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
         }
 
         if (virtualMachineTo.getType() == VirtualMachine.Type.User && MapUtils.isNotEmpty(virtualMachineTo.getExtraConfig()) &&
-          virtualMachineTo.getExtraConfig().containsKey(DpdkHelper.DPDK_NUMA) && virtualMachineTo.getExtraConfig().containsKey(DpdkHelper.DPDK_HUGE_PAGES)) {
+                virtualMachineTo.getExtraConfig().containsKey(DpdkHelper.DPDK_NUMA) && virtualMachineTo.getExtraConfig().containsKey(DpdkHelper.DPDK_HUGE_PAGES)) {
             for (final NicTO nic : virtualMachineTo.getNics()) {
                 nic.setDpdkEnabled(true);
             }
@@ -167,9 +212,9 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
         Long maxHostMemory = max.first();
         Integer maxHostCpuCore = max.second();
 
-        Long minMemory = virtualMachineTo.getMinRam();
+        long minMemory = virtualMachineTo.getMinRam();
         Long maxMemory = minMemory;
-        Integer minCpuCores = virtualMachineTo.getCpus();
+        int minCpuCores = virtualMachineTo.getCpus();
         Integer maxCpuCores = minCpuCores;
 
         ServiceOfferingVO serviceOfferingVO = serviceOfferingDao.findById(virtualMachineProfile.getId(), virtualMachineProfile.getServiceOfferingId());
@@ -204,7 +249,7 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
         if (lastHost != null) {
             maxHostMemory = lastHost.getTotalMemory();
             maxHostCpuCore = lastHost.getCpus();
-            s_logger.debug(String.format("Retrieved memory and cpu max values {\"memory\": %s, \"cpu\": %s} from %s last %s.", maxHostMemory, maxHostCpuCore, vmDescription, lastHost.toString()));
+            s_logger.debug(String.format("Retrieved memory and cpu max values {\"memory\": %s, \"cpu\": %s} from %s last %s.", maxHostMemory, maxHostCpuCore, vmDescription, lastHost));
         } else {
             s_logger.warn(String.format("%s host [%s] and last host [%s] are null. Using 'Long.MAX_VALUE' [%s] and 'Integer.MAX_VALUE' [%s] as max memory and cpu cores.", vmDescription, virtualMachine.getHostId(), lastHostId, maxHostMemory, maxHostCpuCore));
         }
@@ -225,7 +270,7 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
             String maxMemoryConfigKey = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_RAM_SIZE.key();
 
             s_logger.info(String.format("%s is a 'Custom unconstrained' service offering. Using config [%s] value [%s] as max %s memory.",
-              serviceOfferingDescription, maxMemoryConfigKey, maxMemoryConfig, vmDescription));
+                    serviceOfferingDescription, maxMemoryConfigKey, maxMemoryConfig, vmDescription));
 
             if (maxMemoryConfig > 0) {
                 maxMemory = ByteScaleUtils.mebibytesToBytes(maxMemoryConfig);
@@ -251,7 +296,7 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
             String maxCpuCoreConfigKey = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES.key();
 
             s_logger.info(String.format("%s is a 'Custom unconstrained' service offering. Using config [%s] value [%s] as max %s cpu cores.",
-              serviceOfferingDescription, maxCpuCoreConfigKey, maxCpuCoresConfig, vmDescription));
+                    serviceOfferingDescription, maxCpuCoreConfigKey, maxCpuCoresConfig, vmDescription));
 
             if (maxCpuCoresConfig > 0) {
                 maxCpuCores = maxCpuCoresConfig;
@@ -297,4 +342,60 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
         return null;
     }
 
-}
+    @Override
+    public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId, long accountId, long userId, String vmInternalName, Backup backup)  {
+        s_logger.debug(String.format("Trying to import VM [vmInternalName: %s] from Backup [%s].", vmInternalName,
+                ReflectionToStringBuilderUtils.reflectOnlySelectedFields(backup, "id", "uuid", "vmId", "externalId", "backupType")));
+
+        VMInstanceVO vm = _instanceDao.findVMByInstanceNameIncludingRemoved(vmInternalName);
+        if (vm == null) {
+            throw new CloudRuntimeException("Cannot find VM: " + vmInternalName);
+        }
+        try {
+            if (vm.getRemoved() == null) {
+                vm.setState(VirtualMachine.State.Stopped);
+                vm.setPowerState(VirtualMachine.PowerState.PowerOff);
+                _instanceDao.update(vm.getId(), vm);
+            }
+           for ( Backup.VolumeInfo VMVolToRestore : vm.getBackupVolumeList()) {
+               VolumeVO volume = _volumeDao.findByUuidIncludingRemoved(VMVolToRestore.getUuid());
+               volume.setState(Volume.State.Ready);
+               _volumeDao.update(volume.getId(), volume);
+               if (VMVolToRestore.getType() == Volume.Type.ROOT) {
+                   _volumeDao.update(volume.getId(), volume);
+                   _volumeDao.attachVolume(volume.getId(), vm.getId(), 0L);
+               }
+               else if ( VMVolToRestore.getType() == Volume.Type.DATADISK) {
+                   List<VolumeVO> vmVolumes = _volumeDao.findByInstance(vm.getId());
+                   _volumeDao.update(volume.getId(), volume);
+                   _volumeDao.attachVolume(volume.getId(), vm.getId(), getNextAvailableDeviceId(vmVolumes));
+               }
+           }
+        } catch (Exception e) {
+            throw new RuntimeException("Could not restore VM " + vm.getName() + " due to : " + e.getMessage());
+        }
+    return vm;
+    }
+
+    @Override public boolean attachRestoredVolumeToVirtualMachine(long zoneId, String location, Backup.VolumeInfo volumeInfo, VirtualMachine vm, long poolId, Backup backup) {
+
+        VMInstanceVO targetVM = _instanceDao.findVMByInstanceNameIncludingRemoved(vm.getName());
+        List<VolumeVO> vmVolumes = _volumeDao.findByInstance(targetVM.getId());
+        VolumeVO restoredVolume = _volumeDao.findByUuid(location);
+        if (restoredVolume != null) {
+            try {
+                _volumeDao.attachVolume(restoredVolume.getId(), vm.getId(), getNextAvailableDeviceId(vmVolumes));
+                restoredVolume.setState(Volume.State.Ready);
+                _volumeDao.update(restoredVolume.getId(), restoredVolume);
+                return true;
+            } catch (Exception e) {
+                restoredVolume.setDisplay(false);
+                restoredVolume.setDisplayVolume(false);
+                restoredVolume.setState(Volume.State.Destroy);
+                _volumeDao.update(restoredVolume.getId(), restoredVolume);
+                throw new RuntimeException("Unable to attach volume " + restoredVolume.getName() + " to VM" + vm.getName() + " due to : " + e.getMessage());
+            }
+        }
+    return false;
+    }
+}
\ No newline at end of file
diff --git a/ui/public/config.json b/ui/public/config.json
index 82d7c9adff..6c3acb91bb 100644
--- a/ui/public/config.json
+++ b/ui/public/config.json
@@ -64,4 +64,4 @@
   "multipleServer": false,
   "allowSettingTheme": true,
   "docHelpMappings": {}
-}
+}
\ No newline at end of file