2222import com .cloud .host .HostVO ;
2323import com .cloud .utils .exception .CloudRuntimeException ;
2424import feign .FeignException ;
25+ import org .apache .cloudstack .storage .datastore .db .StoragePoolDetailsDao ;
2526import org .apache .cloudstack .storage .feign .FeignClientFactory ;
27+ import org .apache .cloudstack .storage .feign .client .JobFeignClient ;
2628import org .apache .cloudstack .storage .feign .client .NASFeignClient ;
2729import org .apache .cloudstack .storage .feign .client .VolumeFeignClient ;
2830import org .apache .cloudstack .storage .feign .model .ExportPolicy ;
2931import org .apache .cloudstack .storage .feign .model .ExportRule ;
3032import org .apache .cloudstack .storage .feign .model .FileInfo ;
33+ import org .apache .cloudstack .storage .feign .model .Job ;
3134import org .apache .cloudstack .storage .feign .model .Nas ;
3235import org .apache .cloudstack .storage .feign .model .OntapStorage ;
3336import org .apache .cloudstack .storage .feign .model .Svm ;
3437import org .apache .cloudstack .storage .feign .model .Volume ;
38+ import org .apache .cloudstack .storage .feign .model .response .JobResponse ;
3539import org .apache .cloudstack .storage .feign .model .response .OntapResponse ;
3640import org .apache .cloudstack .storage .service .model .AccessGroup ;
3741import org .apache .cloudstack .storage .service .model .CloudStackVolume ;
4044import org .apache .logging .log4j .LogManager ;
4145import org .apache .logging .log4j .Logger ;
4246
47+ import javax .inject .Inject ;
4348import java .util .ArrayList ;
4449import java .util .List ;
4550import java .util .Map ;
@@ -50,6 +55,9 @@ public class UnifiedNASStrategy extends NASStrategy {
5055 private final FeignClientFactory feignClientFactory ;
5156 private final NASFeignClient nasFeignClient ;
5257 private final VolumeFeignClient volumeFeignClient ;
58+ private final JobFeignClient jobFeignClient ;
59+ @ Inject
60+ private StoragePoolDetailsDao storagePoolDetailsDao ;
5361
5462 public UnifiedNASStrategy (OntapStorage ontapStorage ) {
5563 super (ontapStorage );
@@ -58,6 +66,7 @@ public UnifiedNASStrategy(OntapStorage ontapStorage) {
5866 this .feignClientFactory = new FeignClientFactory ();
5967 this .nasFeignClient = feignClientFactory .createClient (NASFeignClient .class , baseURL );
6068 this .volumeFeignClient = feignClientFactory .createClient (VolumeFeignClient .class , baseURL );
69+ this .jobFeignClient = feignClientFactory .createClient (JobFeignClient .class , baseURL );
6170 }
6271
6372 public void setOntapStorage (OntapStorage ontapStorage ) {
@@ -99,35 +108,54 @@ CloudStackVolume getCloudStackVolume(CloudStackVolume cloudstackVolume) {
99108 @ Override
100109 public AccessGroup createAccessGroup (AccessGroup accessGroup ) {
101110
102-
103111 // Create the export policy
104- String svmName = accessGroup .getPolicy ().getSvm ().getName ();
105- String exportPolicyName = "export-" + svmName + "-" + accessGroup .getPrimaryDataStoreInfo ().getName ();
112+ Map <String , String > details = accessGroup .getPrimaryDataStoreInfo ().getDetails ();
113+ String svmName = details .get (Constants .SVM_NAME );
114+ String volumeUUID = details .get (Constants .VOLUME_UUID );
115+ String volumeName = details .get (Constants .VOLUME_NAME );
116+ String exportPolicyName = "export-" + svmName + "-" + volumeName ;// TODO move this to util
106117
107118 ExportPolicy exportPolicy = new ExportPolicy ();
108- exportPolicy .setName (exportPolicyName );
109-
110- Svm svm = new Svm ();
111- svm .setName (svmName );
112- exportPolicy .setSvm (svm );
113119
114120 List <ExportRule > rules = new ArrayList <>();
115121 ExportRule exportRule = new ExportRule ();
116122
123+ List <ExportRule .ExportClient > exportClients = new ArrayList <>();
117124 List <HostVO > hosts = accessGroup .getHostsToConnect ();
118125 for (HostVO host : hosts ) {
119- host .getStorageIpAddress ()
126+ String hostStorageIp = host .getStorageIpAddress ();
127+ String ip = (hostStorageIp != null && !hostStorageIp .isEmpty ())
128+ ? hostStorageIp
129+ : host .getPrivateIpAddress ();
130+ String ipToUse = ip + "/32" ;
131+ ExportRule .ExportClient exportClient = new ExportRule .ExportClient ();
132+ exportClient .setMatch (ipToUse );
133+ exportClients .add (exportClient );
120134 }
135+ exportRule .setClients (exportClients );
136+ exportRule .setProtocols (List .of (ExportRule .ProtocolsEnum .any ));
137+ exportRule .setRoRule (List .of ("any" ));
138+ exportRule .setRwRule (List .of ("any" ));
139+ rules .add (exportRule );
121140
122-
141+ Svm svm = new Svm ();
142+ svm .setName (svmName );
143+ exportPolicy .setSvm (svm );
123144 exportPolicy .setRules (rules );
124- ExportPolicy createExportPolicy = createExportPolicy (svmName , exportPolicy );
125-
126-
127-
128-
129- // attach export policy to volume of storage pool
130- return null ;
145+ exportPolicy .setName (exportPolicyName );
146+ try {
147+ createExportPolicy (svmName , exportPolicy );
148+ s_logger .info ("ExportPolicy created: {}, now attaching this policy to storage pool volume" , exportPolicy .getName ());
149+
150+ // attach export policy to volume of storage pool
151+ assignExportPolicyToVolume (volumeUUID ,exportPolicy .getName ());
152+ s_logger .info ("Successfully assigned exportPolicy {} to volume {}" , exportPolicy .getName (), volumeName );
153+ accessGroup .setPolicy (exportPolicy );
154+ return accessGroup ;
155+ }catch (Exception e ){
156+ s_logger .error ("Exception occurred while creating access group: " + e );
157+ throw new CloudRuntimeException ("Failed to create access group: " + e );
158+ }
131159 }
132160
133161 @ Override
@@ -158,31 +186,13 @@ void disableLogicalAccess(Map<String, String> values) {
158186 }
159187
160188
161- private ExportPolicy createExportPolicy (String svmName , ExportPolicy policy ) {
189+ private void createExportPolicy (String svmName , ExportPolicy policy ) {
162190 s_logger .info ("Creating export policy: {} for SVM: {}" , policy , svmName );
163191
164192 try {
165193 String authHeader = Utility .generateAuthHeader (storage .getUsername (), storage .getPassword ());
166-
167- // // Create ExportPolicy object
168- // ExportPolicy exportPolicy = new ExportPolicy();
169- // exportPolicy.setName(policyName);
170- //
171- // // Set SVM
172- // Svm svm = new Svm();
173- // svm.setName(svmName);
174- // exportPolicy.setSvm(svm);
175-
176- // Create export policy
177- ExportPolicy createdPolicy = nasFeignClient .createExportPolicy (authHeader , policy );
178-
179- if (createdPolicy != null && createdPolicy .getId () != null ) {
180- s_logger .info ("Export policy created successfully with ID: {}" , createdPolicy .getId ());
181- return createdPolicy ;
182- } else {
183- throw new CloudRuntimeException ("Failed to create export policy: " + policy );
184- }
185-
194+ nasFeignClient .createExportPolicy (authHeader , policy );
195+ s_logger .info ("Export policy created successfully with name {}" , policy .getName ());
186196 } catch (FeignException e ) {
187197 s_logger .error ("Failed to create export policy: {}" , policy , e );
188198 throw new CloudRuntimeException ("Failed to create export policy: " + e .getMessage ());
@@ -192,17 +202,16 @@ private ExportPolicy createExportPolicy(String svmName, ExportPolicy policy) {
192202 }
193203 }
194204
195-
196205 private void deleteExportPolicy (String svmName , String policyName ) {
197206 try {
198207 String authHeader = Utility .generateAuthHeader (storage .getUsername (), storage .getPassword ());
199- OntapResponse < ExportPolicy > policiesResponse = nasFeignClient .getExportPolicyResponse (authHeader );
208+ ExportPolicy policiesResponse = nasFeignClient .getExportPolicyResponse (authHeader );
200209
201- if (policiesResponse . getRecords () == null || policiesResponse . getRecords (). isEmpty () ) {
210+ if (policiesResponse == null ) {
202211 s_logger .warn ("Export policy not found for deletion: {}" , policyName );
203212 throw new CloudRuntimeException ("Export policy not found : " + policyName );
204213 }
205- String policyId = policiesResponse .getRecords (). get ( 0 ). getId ().toString ();
214+ String policyId = policiesResponse .getId ().toString ();
206215 nasFeignClient .deleteExportPolicyById (authHeader , policyId );
207216 s_logger .info ("Export policy deleted successfully: {}" , policyName );
208217 } catch (Exception e ) {
@@ -216,26 +225,64 @@ private String addExportRule(String policyName, String clientMatch, String[] pro
216225 return "" ;
217226 }
218227
219- private String assignExportPolicyToVolume (String volumeUuid , String policyName ) {
228+ private void assignExportPolicyToVolume (String volumeUuid , String policyName ) {
220229 s_logger .info ("Assigning export policy: {} to volume: {}" , policyName , volumeUuid );
221230
222231 try {
223232 String authHeader = Utility .generateAuthHeader (storage .getUsername (), storage .getPassword ());
224- OntapResponse < ExportPolicy > policiesResponse = nasFeignClient .getExportPolicyResponse (authHeader );
225- if (policiesResponse . getRecords () == null || policiesResponse . getRecords (). isEmpty () ) {
233+ ExportPolicy policiesResponse = nasFeignClient .getExportPolicyResponse (authHeader );
234+ if (policiesResponse == null ) {
226235 throw new CloudRuntimeException ("Export policy not found: " + policyName );
227236 }
228- ExportPolicy exportPolicy = policiesResponse .getRecords ().get (0 );
229237 // Create Volume update object with NAS configuration
230238 Volume volumeUpdate = new Volume ();
231239 Nas nas = new Nas ();
232- nas .setExportPolicy (exportPolicy );
240+ ExportPolicy policy = new ExportPolicy ();
241+ policy .setName (policiesResponse .getName ());
242+ nas .setExportPolicy (policy );
233243 volumeUpdate .setNas (nas );
234244
235- volumeFeignClient .updateVolumeRebalancing (authHeader , volumeUuid , volumeUpdate );
236- s_logger .info ("Export policy successfully assigned to volume: {}" , volumeUuid );
237- return "Export policy " + policyName + " assigned to volume " + volumeUuid ;
245+ try {
246+ /*
247+ ONTAP created a default rule of 0.0.0.0 if no export rule are defined while creating volume
248+ and since in storage pool creation, cloudstack is not aware of the host , we can either create default or
249+ permissive rule and later update it as part of attachCluster or attachZone implementation
250+ */
251+ JobResponse jobResponse = volumeFeignClient .updateVolumeRebalancing (authHeader , volumeUuid , volumeUpdate );
252+ if (jobResponse == null || jobResponse .getJob () == null ) {
253+ throw new CloudRuntimeException ("Failed to attach policy " + policiesResponse .getName () + "to volume " + volumeUuid );
254+ }
255+ String jobUUID = jobResponse .getJob ().getUuid ();
256+
257+ //Create URI for GET Job API
258+ int jobRetryCount = 0 ;
259+ Job createVolumeJob = null ;
260+ while (createVolumeJob == null || !createVolumeJob .getState ().equals (Constants .JOB_SUCCESS )) {
261+ if (jobRetryCount >= Constants .JOB_MAX_RETRIES ) {
262+ s_logger .error ("Job to update volume " + volumeUuid + " did not complete within expected time." );
263+ throw new CloudRuntimeException ("Job to update volume " + volumeUuid + " did not complete within expected time." );
264+ }
265+
266+ try {
267+ createVolumeJob = jobFeignClient .getJobByUUID (authHeader , jobUUID );
268+ if (createVolumeJob == null ) {
269+ s_logger .warn ("Job with UUID " + jobUUID + " not found. Retrying..." );
270+ } else if (createVolumeJob .getState ().equals (Constants .JOB_FAILURE )) {
271+ throw new CloudRuntimeException ("Job to update volume " + volumeUuid + " failed with error: " + createVolumeJob .getMessage ());
272+ }
273+ } catch (FeignException .FeignClientException e ) {
274+ throw new CloudRuntimeException ("Failed to fetch job status: " + e .getMessage ());
275+ }
276+
277+ jobRetryCount ++;
278+ Thread .sleep (Constants .CREATE_VOLUME_CHECK_SLEEP_TIME ); // Sleep for 2 seconds before polling again
279+ }
280+ } catch (Exception e ) {
281+ s_logger .error ("Exception while updating volume: " , e );
282+ throw new CloudRuntimeException ("Failed to update volume: " + e .getMessage ());
283+ }
238284
285+ s_logger .info ("Export policy successfully assigned to volume: {}" , volumeUuid );
239286 } catch (FeignException e ) {
240287 s_logger .error ("Failed to assign export policy to volume: {}" , volumeUuid , e );
241288 throw new CloudRuntimeException ("Failed to assign export policy: " + e .getMessage ());
0 commit comments