Skip to content

Commit 4855d40

Browse files
abh1sarDaan Hoogland
authored andcommitted
[22.0] secondary storage resource limit for download
1 parent 95816b4 commit 4855d40

12 files changed

Lines changed: 174 additions & 22 deletions

File tree

api/src/main/java/com/cloud/storage/VMTemplateStorageResourceAssoc.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323

2424
public interface VMTemplateStorageResourceAssoc extends InternalIdentity {
2525
public static enum Status {
26-
UNKNOWN, DOWNLOAD_ERROR, NOT_DOWNLOADED, DOWNLOAD_IN_PROGRESS, DOWNLOADED, ABANDONED, UPLOADED, NOT_UPLOADED, UPLOAD_ERROR, UPLOAD_IN_PROGRESS, CREATING, CREATED, BYPASSED
26+
UNKNOWN, DOWNLOAD_ERROR, NOT_DOWNLOADED, DOWNLOAD_IN_PROGRESS, DOWNLOADED, ABANDONED, LIMIT_REACHED, UPLOADED, NOT_UPLOADED, UPLOAD_ERROR, UPLOAD_IN_PROGRESS, CREATING, CREATED, BYPASSED
2727
}
2828

29+
List<Status> ERROR_DOWNLOAD_STATES = List.of(Status.DOWNLOAD_ERROR, Status.ABANDONED, Status.LIMIT_REACHED, Status.UNKNOWN);
2930
List<Status> PENDING_DOWNLOAD_STATES = List.of(Status.NOT_DOWNLOADED, Status.DOWNLOAD_IN_PROGRESS);
3031

3132
String getInstallPath();

core/src/main/java/com/cloud/agent/api/storage/DownloadAnswer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public void setTemplateSize(long templateSize) {
140140
}
141141

142142
public Long getTemplateSize() {
143-
return templateSize;
143+
return templateSize == 0 ? templatePhySicalSize : templateSize;
144144
}
145145

146146
public void setTemplatePhySicalSize(long templatePhySicalSize) {

engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,10 @@ protected Void createTemplateAsyncCallback(AsyncCallbackDispatcher<? extends Bas
230230
updateBuilder.setJobId(answer.getJobId());
231231
updateBuilder.setLocalDownloadPath(answer.getDownloadPath());
232232
updateBuilder.setInstallPath(answer.getInstallPath());
233-
updateBuilder.setSize(answer.getTemplateSize());
234-
updateBuilder.setPhysicalSize(answer.getTemplatePhySicalSize());
233+
if (!VMTemplateStorageResourceAssoc.ERROR_DOWNLOAD_STATES.contains(answer.getDownloadStatus())) {
234+
updateBuilder.setSize(answer.getTemplateSize());
235+
updateBuilder.setPhysicalSize(answer.getTemplatePhySicalSize());
236+
}
235237
_templateStoreDao.update(tmpltStoreVO.getId(), updateBuilder);
236238
// update size in vm_template table
237239
VMTemplateVO tmlptUpdater = _templateDao.createForUpdate();
@@ -241,8 +243,7 @@ protected Void createTemplateAsyncCallback(AsyncCallbackDispatcher<? extends Bas
241243

242244
AsyncCompletionCallback<CreateCmdResult> caller = context.getParentCallback();
243245

244-
if (answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR ||
245-
answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.ABANDONED || answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.UNKNOWN) {
246+
if (VMTemplateStorageResourceAssoc.ERROR_DOWNLOAD_STATES.contains(answer.getDownloadStatus())) {
246247
CreateCmdResult result = new CreateCmdResult(null, null);
247248
result.setSuccess(false);
248249
result.setResult(answer.getErrorString());

server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ public boolean configure(final String name, final Map<String, Object> params) th
269269

270270
templateSizeSearch = _vmTemplateStoreDao.createSearchBuilder(SumCount.class);
271271
templateSizeSearch.select("sum", Func.SUM, templateSizeSearch.entity().getSize());
272-
templateSizeSearch.and("downloadState", templateSizeSearch.entity().getDownloadState(), Op.EQ);
272+
templateSizeSearch.and("downloadState", templateSizeSearch.entity().getDownloadState(), Op.IN);
273273
templateSizeSearch.and("destroyed", templateSizeSearch.entity().getDestroyed(), Op.EQ);
274274
SearchBuilder<VMTemplateVO> join1 = _vmTemplateDao.createSearchBuilder();
275275
join1.and("accountId", join1.entity().getAccountId(), Op.EQ);
@@ -1493,7 +1493,7 @@ public long calculateSecondaryStorageForAccount(long accountId) {
14931493
long totalTemplatesSize = 0;
14941494

14951495
SearchCriteria<SumCount> sc = templateSizeSearch.create();
1496-
sc.setParameters("downloadState", Status.DOWNLOADED);
1496+
sc.setParameters("downloadState", Status.DOWNLOADED, Status.DOWNLOAD_IN_PROGRESS);
14971497
sc.setParameters("destroyed", false);
14981498
sc.setJoinParameters("templates", "accountId", accountId);
14991499
List<SumCount> templates = _vmTemplateStoreDao.customSearch(sc, null);

server/src/main/java/com/cloud/storage/download/DownloadActiveState.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ public String handleAbort() {
9595
return Status.ABANDONED.toString();
9696
}
9797

98+
@Override
99+
public String handleLimitReached() {
100+
return Status.LIMIT_REACHED.toString();
101+
}
102+
98103
@Override
99104
public String handleDisconnect() {
100105

server/src/main/java/com/cloud/storage/download/DownloadErrorState.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ public String handleAbort() {
6060
return Status.ABANDONED.toString();
6161
}
6262

63+
@Override
64+
public String handleLimitReached() {
65+
return Status.LIMIT_REACHED.toString();
66+
}
67+
6368
@Override
6469
public String getName() {
6570
return Status.DOWNLOAD_ERROR.toString();

server/src/main/java/com/cloud/storage/download/DownloadInactiveState.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ public String handleAbort() {
3636
return getName();
3737
}
3838

39+
@Override
40+
public String handleLimitReached() {
41+
// ignore and stay put
42+
return getName();
43+
}
44+
3945
@Override
4046
public String handleDisconnect() {
4147
//ignore and stay put
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.storage.download;
18+
19+
import org.apache.cloudstack.storage.command.DownloadProgressCommand.RequestType;
20+
import org.apache.logging.log4j.Level;
21+
22+
import com.cloud.agent.api.storage.DownloadAnswer;
23+
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
24+
25+
public class DownloadLimitReachedState extends DownloadInactiveState {
26+
27+
public DownloadLimitReachedState(DownloadListener dl) {
28+
super(dl);
29+
}
30+
31+
@Override
32+
public String getName() {
33+
return Status.LIMIT_REACHED.toString();
34+
}
35+
36+
@Override
37+
public String handleEvent(DownloadEvent event, Object eventObj) {
38+
if (logger.isTraceEnabled()) {
39+
getDownloadListener().log("handleEvent, event type=" + event + ", curr state=" + getName(), Level.TRACE);
40+
}
41+
return Status.LIMIT_REACHED.toString();
42+
}
43+
44+
@Override
45+
public void onEntry(String prevState, DownloadEvent event, Object evtObj) {
46+
if (!prevState.equalsIgnoreCase(getName())) {
47+
DownloadAnswer answer = new DownloadAnswer("Storage Limit Reached", Status.LIMIT_REACHED);
48+
getDownloadListener().callback(answer);
49+
getDownloadListener().cancelStatusTask();
50+
getDownloadListener().cancelTimeoutTask();
51+
getDownloadListener().scheduleImmediateStatusCheck(RequestType.PURGE);
52+
}
53+
}
54+
}

server/src/main/java/com/cloud/storage/download/DownloadListener.java

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@
2525

2626
import javax.inject.Inject;
2727

28+
import com.cloud.configuration.Resource;
29+
import com.cloud.resourcelimit.CheckedReservation;
30+
import com.cloud.storage.VMTemplateVO;
31+
import com.cloud.storage.VolumeVO;
32+
import com.cloud.storage.dao.VMTemplateDao;
33+
import com.cloud.storage.dao.VolumeDao;
34+
import com.cloud.user.Account;
35+
import com.cloud.user.AccountManager;
36+
import com.cloud.user.ResourceLimitService;
2837
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
2938
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
3039
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
@@ -34,10 +43,13 @@
3443
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
3544
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
3645
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
46+
import org.apache.cloudstack.reservation.dao.ReservationDao;
3747
import org.apache.cloudstack.storage.command.DownloadCommand;
3848
import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType;
3949
import org.apache.cloudstack.storage.command.DownloadProgressCommand;
4050
import org.apache.cloudstack.storage.command.DownloadProgressCommand.RequestType;
51+
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
52+
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
4153
import org.apache.cloudstack.utils.cache.LazyCache;
4254
import org.apache.logging.log4j.Level;
4355
import org.apache.logging.log4j.LogManager;
@@ -107,6 +119,7 @@ protected void runInContext() {
107119
public static final String DOWNLOAD_ERROR = Status.DOWNLOAD_ERROR.toString();
108120
public static final String DOWNLOAD_IN_PROGRESS = Status.DOWNLOAD_IN_PROGRESS.toString();
109121
public static final String DOWNLOAD_ABANDONED = Status.ABANDONED.toString();
122+
public static final String DOWNLOAD_LIMIT_REACHED = Status.LIMIT_REACHED.toString();
110123

111124
private EndPoint _ssAgent;
112125

@@ -137,6 +150,18 @@ protected void runInContext() {
137150
private DataStoreManager _storeMgr;
138151
@Inject
139152
private VolumeService _volumeSrv;
153+
@Inject
154+
private VMTemplateDao _templateDao;
155+
@Inject
156+
private TemplateDataStoreDao _templateDataStoreDao;
157+
@Inject
158+
private VolumeDao _volumeDao;
159+
@Inject
160+
private ResourceLimitService _resourceLimitMgr;
161+
@Inject
162+
private AccountManager _accountMgr;
163+
@Inject
164+
ReservationDao _reservationDao;
140165

141166
private LazyCache<Long, List<Hypervisor.HypervisorType>> zoneHypervisorsCache;
142167

@@ -160,7 +185,7 @@ public DownloadListener(EndPoint ssAgent, DataStore store, DataObject object, Ti
160185
_downloadMonitor = downloadMonitor;
161186
_cmd = cmd;
162187
initStateMachine();
163-
_currState = getState(Status.NOT_DOWNLOADED.toString());
188+
_currState = getState(NOT_DOWNLOADED);
164189
this._timer = timer;
165190
_timeoutTask = new TimeoutTask(this);
166191
this._timer.schedule(_timeoutTask, 3 * STATUS_POLL_INTERVAL);
@@ -184,11 +209,12 @@ public void setCurrState(Status currState) {
184209
}
185210

186211
private void initStateMachine() {
187-
_stateMap.put(Status.NOT_DOWNLOADED.toString(), new NotDownloadedState(this));
188-
_stateMap.put(Status.DOWNLOADED.toString(), new DownloadCompleteState(this));
189-
_stateMap.put(Status.DOWNLOAD_ERROR.toString(), new DownloadErrorState(this));
190-
_stateMap.put(Status.DOWNLOAD_IN_PROGRESS.toString(), new DownloadInProgressState(this));
191-
_stateMap.put(Status.ABANDONED.toString(), new DownloadAbandonedState(this));
212+
_stateMap.put(NOT_DOWNLOADED, new NotDownloadedState(this));
213+
_stateMap.put(DOWNLOADED, new DownloadCompleteState(this));
214+
_stateMap.put(DOWNLOAD_ERROR, new DownloadErrorState(this));
215+
_stateMap.put(DOWNLOAD_IN_PROGRESS, new DownloadInProgressState(this));
216+
_stateMap.put(DOWNLOAD_ABANDONED, new DownloadAbandonedState(this));
217+
_stateMap.put(DOWNLOAD_LIMIT_REACHED, new DownloadLimitReachedState(this));
192218
}
193219

194220
private DownloadState getState(String stateName) {
@@ -239,18 +265,65 @@ public boolean isRecurring() {
239265
return false;
240266
}
241267

268+
private Long getAccountIdForDataObject() {
269+
if (object == null) {
270+
return null;
271+
}
272+
if (DataObjectType.TEMPLATE.equals(object.getType())) {
273+
VMTemplateVO t = _templateDao.findById(object.getId());
274+
return t != null ? t.getAccountId() : null;
275+
} else if (DataObjectType.VOLUME.equals(object.getType())) {
276+
VolumeVO v = _volumeDao.findById(object.getId());
277+
return v != null ? v.getAccountId() : null;
278+
}
279+
return null;
280+
}
281+
282+
private Long getSizeFromDB() {
283+
Long lastSize = 0L;
284+
if (DataObjectType.TEMPLATE.equals(object.getType())) {
285+
TemplateDataStoreVO t = _templateDataStoreDao.findByStoreTemplate(object.getDataStore().getId(), object.getId());
286+
lastSize = t.getSize();
287+
} else if (DataObjectType.VOLUME.equals(object.getType())) {
288+
VolumeVO v = _volumeDao.findById(object.getId());
289+
lastSize = v.getSize();
290+
}
291+
return lastSize;
292+
}
293+
294+
private Boolean checkAndUpdateResourceLimits(DownloadAnswer answer) {
295+
Long lastSize = getSizeFromDB();
296+
Long currentSize = answer.getTemplateSize();
297+
298+
if (currentSize > lastSize) {
299+
Long accountId = getAccountIdForDataObject();
300+
Account account = _accountMgr.getAccount(accountId);
301+
Long usage = currentSize - lastSize;
302+
try (CheckedReservation secStorageReservation = new CheckedReservation(account, Resource.ResourceType.secondary_storage, usage, _reservationDao, _resourceLimitMgr)) {
303+
_resourceLimitMgr.incrementResourceCount(accountId, Resource.ResourceType.secondary_storage, usage);
304+
} catch (Exception e) {
305+
return false;
306+
}
307+
}
308+
return true;
309+
}
310+
242311
@Override
243312
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
244313
boolean processed = false;
245-
if (answers != null & answers.length > 0) {
314+
if (answers != null && answers.length > 0) {
246315
if (answers[0] instanceof DownloadAnswer) {
247316
final DownloadAnswer answer = (DownloadAnswer)answers[0];
248317
if (getJobId() == null) {
249318
setJobId(answer.getJobId());
250319
} else if (!getJobId().equalsIgnoreCase(answer.getJobId())) {
251320
return false;//TODO
252321
}
253-
transition(DownloadEvent.DOWNLOAD_ANSWER, answer);
322+
if (!checkAndUpdateResourceLimits(answer)) {
323+
transition(DownloadEvent.LIMIT_REACHED, answer);
324+
} else {
325+
transition(DownloadEvent.DOWNLOAD_ANSWER, answer);
326+
}
254327
processed = true;
255328
}
256329
}

server/src/main/java/com/cloud/storage/download/DownloadState.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
public abstract class DownloadState {
2828
public static enum DownloadEvent {
29-
DOWNLOAD_ANSWER, ABANDON_DOWNLOAD, TIMEOUT_CHECK, DISCONNECT
29+
DOWNLOAD_ANSWER, ABANDON_DOWNLOAD, LIMIT_REACHED, TIMEOUT_CHECK, DISCONNECT
3030
};
3131

3232
protected Logger logger = LogManager.getLogger(getClass());
@@ -51,6 +51,8 @@ public String handleEvent(DownloadEvent event, Object eventObj) {
5151
return handleAnswer(answer);
5252
case ABANDON_DOWNLOAD:
5353
return handleAbort();
54+
case LIMIT_REACHED:
55+
return handleLimitReached();
5456
case TIMEOUT_CHECK:
5557
Date now = new Date();
5658
long update = now.getTime() - dl.getLastUpdated().getTime();
@@ -78,6 +80,8 @@ public void onExit() {
7880

7981
public abstract String handleAbort();
8082

83+
public abstract String handleLimitReached();
84+
8185
public abstract String handleDisconnect();
8286

8387
public abstract String handleAnswer(DownloadAnswer answer);

0 commit comments

Comments
 (0)