| <!-- | |
| 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. | |
| --> | |
| # CloudStack Volume Provider Adaptive Plugin Base | |
| The Adaptive Plugin Base is an abstract volume storage provider that | |
| provides a generic implementation for managing volumes that are exposed | |
| to hosts through FiberChannel and similar methods but managed independently | |
| through a storage API or interface. The ProviderAdapter, and associated | |
| classes, provide a decoupled interface from the rest of | |
| Cloudstack that covers the exact actions needed | |
| to interface with a storage provider. Each storage provider can extend | |
| and implement the ProviderAdapter without needing to understand the internal | |
| logic of volume management, database structure, etc. | |
| ## Implement the Provider Interface | |
| To implement a provider, create another module -- or a standalone project -- | |
| and implement the following interfaces from the **org.apache.cloudstack.storage.datastore.adapter** package: | |
| 1. **ProviderAdapter** - this is the primary interface used to communicate with the storage provider when volume management actions are required. | |
| 2. **ProviderAdapterFactory** - the implementation of this class creates the correct ProviderAdapter when needed. | |
| Follow Javadoc for each class on further instructions for implementing each function. | |
| ## Implement the Primary Datastore Provider Plugin | |
| Once the provider interface is implemented, you will need to extend the **org.apache.cloudstack.storage.datastore.provider.AdaptiveProviderDatastoreProviderImpl** class. When extending it, you simply need to implement a default | |
| constructor that creates an instance of the ProviderAdapterFactory implementation created in #2 above. Once created, you need to call the parent constructor and pass the factory object. | |
| ## Provide the Configuration for the Provider Plugin | |
| Lastly, you need to include a module file and Spring configuration for your Primary Datastore Provider Plugin class so Cloudstack will load it during startup. | |
| ### Module Properties | |
| This provides the hint to Cloudstack to load this as a module during startup. | |
| ``` | |
| #resources/META-INF/cloudstack/storage-volume-<providername>/module.properties | |
| name=storage-volume-<providername> | |
| parent=storage | |
| ``` | |
| ### Spring Bean Context Configuration | |
| This provides instructions of which provider implementation class to load when the Spring bean initialization is running. | |
| ``` | |
| <!-- resources/META-INF/cloudstack/storage-volume-<providername>/spring-storage-volume-<providername>-context.xml --> | |
| <beans xmlns="http://www.springframework.org/schema/beans" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xmlns:context="http://www.springframework.org/schema/context" | |
| xmlns:aop="http://www.springframework.org/schema/aop" | |
| xsi:schemaLocation="http://www.springframework.org/schema/beans | |
| http://www.springframework.org/schema/beans/spring-beans.xsd | |
| http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd | |
| http://www.springframework.org/schema/context | |
| http://www.springframework.org/schema/context/spring-context.xsd" | |
| > | |
| <bean id="<providername>DataStoreProvider" | |
| class="org.apache.cloudstack.storage.datastore.provider.<providername>PrimaryDatastoreProviderImpl"> | |
| </bean> | |
| </beans> | |
| ``` | |
| ## Build and Deploy the Jar | |
| Once you build the new jar, start Cloudstack Management Server or, if a standalone jar, add it to the classpath before start. You should now have a new storage provider of the designated name once Cloudstack finishes loading | |
| all configured modules. | |
| ### Test Cases | |
| The following test cases should be run against configured installations of each storage array in a working Cloudstack installation. | |
| 1. Create New Primera Storage Pool for Zone | |
| 2. Create New Primera Storage Pool for Cluster | |
| 3. Update Primera Storage Pool for Zone | |
| 4. Update Primera Storage Pool for Cluster | |
| 5. Create VM with Root Disk using Primera pool | |
| 6. Create VM with Root and Data Disk using Primera pool | |
| 7. Create VM with Root Disk using NFS and Data Disk on Primera pool | |
| 8. Create VM with Root Disk on Primera Pool and Data Disk on NFS | |
| 9. Snapshot root disk with VM using Primera Pool for root disk | |
| 10. Snapshot data disk with VM using Primera Pool for data disk | |
| 11. Snapshot VM (non-memory) with root and data disk using Primera pool | |
| 12. Snapshot VM (non-memory) with root disk using Primera pool and data disk using NFS | |
| 13. Snapshot VM (non-memory) with root disk using NFS pool and data disk using Primera pool | |
| 14. Create new template from previous snapshot root disk on Primera pool | |
| 15. Create new volume from previous snapshot root disk on Primera pool | |
| 16. Create new volume from previous snapshot data disk on Primera pool | |
| 17. Create new VM using template created from Primera root snapshot and using Primera as root volume pool | |
| 18. Create new VM using template created from Primera root snapshot and using NFS as root volume pool | |
| 19. Delete previously created Primera snapshot | |
| 20. Create previously created Primera volume attached to a VM that is running (should fail) | |
| 21. Create previously created Primera volume attached to a VM that is not running (should fail) | |
| 22. Detach a Primera volume from a non-running VM (should work) | |
| 23. Attach a Primera volume to a running VM (should work) | |
| 24. Attach a Primera volume to a non-running VM (should work) | |
| 25. Create a 'thin' Disk Offering tagged for Primera pool and provision and attach a data volume to a VM using this offering (ttpv=true, reduce=false) | |
| 26. Create a 'sparse' Disk Offering tagged for Primera pool and provision and attach a data volume to a VM using this offering (ttpv=false, reduce=true) | |
| 27. Create a 'fat' Disk Offering and tagged for Primera pool and provision and attach a data volume to a VM using this offering (should fail as 'fat' not supported) | |
| 28. Perform volume migration of root volume from Primera pool to NFS pool on stopped VM | |
| 29. Perform volume migration of root volume from NFS pool to Primera pool on stopped VM | |
| 30. Perform volume migration of data volume from Primera pool to NFS pool on stopped VM | |
| 31. Perform volume migration of data volume from NFS pool to Primera pool on stopped VM | |
| 32. Perform VM data migration for a VM with 1 or more data volumes from all volumes on Primera pool to all volumes on NFS pool | |
| 33. Perform VM data migration for a VM with 1 or more data volumes from all volumes on NFS pool to all volumes on Primera pool | |
| 34. Perform live migration of a VM with a Primera root disk | |
| 35. Perform live migration of a VM with a Primera data disk and NFS root disk | |
| 36. Perform live migration of a VM with a Primera root disk and NFS data disk | |
| 37. Perform volume migration between 2 Primera pools on the same backend Primera IP address | |
| 38. Perform volume migration between 2 Primera pools on different Primera IP address |