Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@

package org.apache.cloudstack.storage.feign.client;

import java.util.Map;

import org.apache.cloudstack.storage.feign.model.Aggregate;
import org.apache.cloudstack.storage.feign.model.response.OntapResponse;

import feign.Headers;
import feign.Param;
import feign.QueryMap;
import feign.RequestLine;

public interface AggregateFeignClient {
Expand All @@ -33,5 +37,6 @@ public interface AggregateFeignClient {

@RequestLine("GET /api/storage/aggregates/{uuid}")
@Headers({"Authorization: {authHeader}"})
Aggregate getAggregateByUUID(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
Aggregate getAggregateByUUID(@Param("authHeader") String authHeader, @Param("uuid") String uuid,
@QueryMap Map<String, Object> queryParams);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@

package org.apache.cloudstack.storage.feign.model;

import java.util.Objects;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

import java.util.Objects;

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Aggregate {
Expand Down Expand Up @@ -77,6 +77,17 @@ public int hashCode() {
@JsonProperty("space")
private AggregateSpace space = null;

@JsonProperty("node")
private Node node = null;


public Node getNode() {
return node;
}

public void setNode(Node node) {
this.node = node;
}

public Aggregate name(String name) {
this.name = name;
Expand Down Expand Up @@ -107,10 +118,18 @@ public StateEnum getState() {
return state;
}

public void setState(StateEnum state) {
this.state = state;
}

public AggregateSpace getSpace() {
return space;
}

public void setSpace(AggregateSpace space) {
this.space = space;
}

public Double getAvailableBlockStorageSpace() {
if (space != null && space.blockStorage != null) {
return space.blockStorage.available;
Expand Down Expand Up @@ -148,9 +167,32 @@ public String toString() {
return "DiskAggregates [name=" + name + ", uuid=" + uuid + "]";
}

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Node {
@JsonProperty("name")
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

public static class AggregateSpace {
@JsonProperty("block_storage")
private AggregateSpaceBlockStorage blockStorage = null;

public AggregateSpaceBlockStorage getBlockStorage() {
return blockStorage;
}

public void setBlockStorage(AggregateSpaceBlockStorage blockStorage) {
this.blockStorage = blockStorage;
}
}

public static class AggregateSpaceBlockStorage {
Expand All @@ -160,6 +202,14 @@ public static class AggregateSpaceBlockStorage {
private Double size = null;
@JsonProperty("used")
private Double used = null;

public Double getAvailable() {
return available;
}

public void setAvailable(Double available) {
this.available = available;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@

package org.apache.cloudstack.storage.feign.model;

import java.util.List;
import java.util.Objects;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;
import java.util.Objects;

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class IpInterface {
Expand All @@ -44,6 +44,15 @@ public class IpInterface {
@JsonProperty("services")
private List<String> services;

@JsonProperty("state")
private String state;

@JsonProperty("enabled")
private Boolean enabled;

@JsonProperty("location")
private Location location;

// Getters and setters
public String getUuid() {
return uuid;
Expand Down Expand Up @@ -85,6 +94,30 @@ public void setServices(List<String> services) {
this.services = services;
}

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}

public Boolean getEnabled() {
return enabled;
}

public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}

public Location getLocation() {
return location;
}

public void setLocation(Location location) {
this.location = location;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand All @@ -98,12 +131,14 @@ public boolean equals(Object o) {
Objects.equals(name, that.name) &&
Objects.equals(ip, that.ip) &&
Objects.equals(svm, that.svm) &&
Objects.equals(services, that.services);
Objects.equals(services, that.services) &&
Objects.equals(state, that.state) &&
Objects.equals(enabled, that.enabled);
}

@Override
public int hashCode() {
return Objects.hash(uuid, name, ip, svm, services);
return Objects.hash(uuid, name, ip, svm, services, state, enabled);
}

@Override
Expand All @@ -114,9 +149,52 @@ public String toString() {
", ip=" + ip +
", svm=" + svm +
", services=" + services +
", state='" + state + '\'' +
", enabled=" + enabled +
'}';
}

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Node {
@JsonProperty("name")
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Location {
@JsonProperty("home_node")
private Node homeNode;

@JsonProperty("node")
private Node node;

public Node getHomeNode() {
return homeNode;
}

public void setHomeNode(Node homeNode) {
this.homeNode = homeNode;
}

public Node getNode() {
return node;
}

public void setNode(Node node) {
this.node = node;
}
}

// Nested class for IP information
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,27 @@

package org.apache.cloudstack.storage.lifecycle;

import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.resource.ResourceManager;
import com.cloud.storage.Storage;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolAutomation;
import com.cloud.utils.exception.CloudRuntimeException;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import javax.inject.Inject;

import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDetailsDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.lifecycle.BasePrimaryDataStoreLifeCycleImpl;
import org.apache.cloudstack.storage.feign.model.OntapStorage;
Expand All @@ -59,13 +55,21 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.alert.AlertManager;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.resource.ResourceManager;
import com.cloud.storage.Storage;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolAutomation;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import com.google.common.base.Preconditions;

public class OntapPrimaryDatastoreLifecycle extends BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
@Inject private ClusterDao _clusterDao;
Expand All @@ -76,6 +80,7 @@ public class OntapPrimaryDatastoreLifecycle extends BasePrimaryDataStoreLifeCycl
@Inject private StoragePoolAutomation _storagePoolAutomation;
@Inject private PrimaryDataStoreDao storagePoolDao;
@Inject private StoragePoolDetailsDao storagePoolDetailsDao;
@Inject private AlertManager _alertMgr;
private static final Logger logger = LogManager.getLogger(OntapPrimaryDatastoreLifecycle.class);

private static final long ONTAP_MIN_VOLUME_SIZE_IN_BYTES = 1677721600L;
Expand Down Expand Up @@ -135,13 +140,6 @@ public DataStore initialize(Map<String, Object> dsInfos) {
StorageStrategy storageStrategy = StorageProviderFactory.getStrategy(ontapStorage);
boolean isValid = storageStrategy.connect();
if (isValid) {
// Get the DataLIF for data access
String dataLIF = storageStrategy.getNetworkInterface();
if (dataLIF == null || dataLIF.isEmpty()) {
throw new CloudRuntimeException("Failed to retrieve Data LIF from ONTAP, cannot create primary storage");
}
logger.info("Using Data LIF for storage access: " + dataLIF);
details.put(OntapStorageConstants.DATA_LIF, dataLIF);
logger.info("Creating ONTAP volume '" + storagePoolName + "' with size: " + capacityBytes + " bytes (" +
(capacityBytes / (1024 * 1024 * 1024)) + " GB)");
try {
Expand All @@ -157,6 +155,30 @@ public DataStore initialize(Map<String, Object> dsInfos) {
logger.error("Exception occurred while creating ONTAP volume: " + storagePoolName, e);
throw new CloudRuntimeException("Failed to create ONTAP volume: " + storagePoolName + ". Error: " + e.getMessage(), e);
}

Pair<String, String> lifResult;
try {
lifResult = storageStrategy.getNetworkInterface();
} catch (Exception e) {
logger.error("Exception occurred while retrieving network interface for pool: " + storagePoolName, e);
throw new CloudRuntimeException("Failed to retrieve Data LIF from ONTAP: " + e.getMessage(), e);
}
Comment on lines +159 to +165
String dataLIF = lifResult.first();
if (dataLIF == null || dataLIF.isEmpty()) {
throw new CloudRuntimeException("Failed to retrieve Data LIF from ONTAP, cannot create primary storage");
}
logger.info("Using Data LIF for storage access: " + dataLIF);
details.put(OntapStorageConstants.DATA_LIF, dataLIF);

// Persist LIF warning as a pool detail and fire a storage alert so the user is informed
if (lifResult.second() != null) {
String lifWarning = lifResult.second();
details.put(OntapStorageConstants.LIF_WARNING, lifWarning);
logger.warn("LIF selection warning for pool '" + storagePoolName + "': " + lifWarning);
String alertSubject = "ONTAP Storage Pool '" + storagePoolName + "': "
+ lifWarning.split(OntapStorageConstants.SEMICOLON)[0].trim();
OntapStorageUtils.sendStorageAlert(_alertMgr, zoneId, podId, alertSubject, lifWarning);
}
} else {
throw new CloudRuntimeException("ONTAP details validation failed, cannot create primary storage");
}
Expand Down
Loading
Loading