mirror of https://github.com/apache/cloudstack.git
CLOUDSTACK-684 support vm snapshot
This commit is contained in:
parent
3a0c99b0a4
commit
9a12756ae4
|
|
@ -0,0 +1,62 @@
|
|||
// 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 com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
|
||||
public class CreateVMSnapshotAnswer extends Answer {
|
||||
|
||||
private List<VolumeTO> volumeTOs;
|
||||
private VMSnapshotTO vmSnapshotTo;
|
||||
|
||||
|
||||
public List<VolumeTO> getVolumeTOs() {
|
||||
return volumeTOs;
|
||||
}
|
||||
|
||||
public void setVolumeTOs(List<VolumeTO> volumeTOs) {
|
||||
this.volumeTOs = volumeTOs;
|
||||
}
|
||||
|
||||
public VMSnapshotTO getVmSnapshotTo() {
|
||||
return vmSnapshotTo;
|
||||
}
|
||||
|
||||
public void setVmSnapshotTo(VMSnapshotTO vmSnapshotTo) {
|
||||
this.vmSnapshotTo = vmSnapshotTo;
|
||||
}
|
||||
|
||||
public CreateVMSnapshotAnswer() {
|
||||
|
||||
}
|
||||
|
||||
public CreateVMSnapshotAnswer(CreateVMSnapshotCommand cmd, boolean success,
|
||||
String result) {
|
||||
super(cmd, success, result);
|
||||
}
|
||||
|
||||
public CreateVMSnapshotAnswer(CreateVMSnapshotCommand cmd,
|
||||
VMSnapshotTO vmSnapshotTo, List<VolumeTO> volumeTOs) {
|
||||
super(cmd, true, "");
|
||||
this.vmSnapshotTo = vmSnapshotTo;
|
||||
this.volumeTOs = volumeTOs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// 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 com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
|
||||
public class CreateVMSnapshotCommand extends VMSnapshotBaseCommand {
|
||||
|
||||
public CreateVMSnapshotCommand(String vmName, VMSnapshotTO snapshot, List<VolumeTO> volumeTOs, String guestOSType, VirtualMachine.State vmState) {
|
||||
super(vmName, snapshot, volumeTOs, guestOSType);
|
||||
this.vmState = vmState;
|
||||
}
|
||||
|
||||
private VirtualMachine.State vmState;
|
||||
|
||||
|
||||
public VirtualMachine.State getVmState() {
|
||||
return vmState;
|
||||
}
|
||||
|
||||
public void setVmState(VirtualMachine.State vmState) {
|
||||
this.vmState = vmState;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
||||
package com.cloud.agent.api;
|
||||
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
|
||||
public class CreateVolumeFromVMSnapshotAnswer extends Answer {
|
||||
private String path;
|
||||
private VolumeTO volumeTo;
|
||||
|
||||
public VolumeTO getVolumeTo() {
|
||||
return volumeTo;
|
||||
}
|
||||
|
||||
public CreateVolumeFromVMSnapshotAnswer(
|
||||
CreateVolumeFromVMSnapshotCommand cmd, VolumeTO volumeTo) {
|
||||
super(cmd, true, "");
|
||||
this.volumeTo = volumeTo;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
protected CreateVolumeFromVMSnapshotAnswer() {
|
||||
|
||||
}
|
||||
|
||||
public CreateVolumeFromVMSnapshotAnswer(
|
||||
CreateVolumeFromVMSnapshotCommand cmd, String path) {
|
||||
super(cmd, true, "");
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public CreateVolumeFromVMSnapshotAnswer(
|
||||
CreateVolumeFromVMSnapshotCommand cmd, boolean result, String string) {
|
||||
super(cmd, result, string);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// 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 com.cloud.agent.api;
|
||||
|
||||
import com.cloud.agent.api.to.StorageFilerTO;
|
||||
import com.cloud.vm.DiskProfile;
|
||||
|
||||
public class CreateVolumeFromVMSnapshotCommand extends Command {
|
||||
|
||||
protected String path;
|
||||
protected String name;
|
||||
protected Boolean fullClone;
|
||||
protected String storagePoolUuid;
|
||||
private StorageFilerTO pool;
|
||||
private DiskProfile diskProfile;
|
||||
private Long volumeId;
|
||||
|
||||
public DiskProfile getDskch() {
|
||||
return diskProfile;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public Long getVolumeId() {
|
||||
return volumeId;
|
||||
}
|
||||
|
||||
protected CreateVolumeFromVMSnapshotCommand() {
|
||||
|
||||
}
|
||||
|
||||
public CreateVolumeFromVMSnapshotCommand(String path, String name,
|
||||
Boolean fullClone, String storagePoolUuid) {
|
||||
this.path = path;
|
||||
this.name = name;
|
||||
this.fullClone = fullClone;
|
||||
this.storagePoolUuid = storagePoolUuid;
|
||||
}
|
||||
|
||||
public CreateVolumeFromVMSnapshotCommand(String path, String name,
|
||||
Boolean fullClone, String storagePoolUuid, StorageFilerTO pool,
|
||||
DiskProfile diskProfile, Long volumeId) {
|
||||
this.path = path;
|
||||
this.name = name;
|
||||
this.fullClone = fullClone;
|
||||
this.storagePoolUuid = storagePoolUuid;
|
||||
this.pool = pool;
|
||||
this.diskProfile = diskProfile;
|
||||
this.volumeId = volumeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Boolean getFullClone() {
|
||||
return fullClone;
|
||||
}
|
||||
|
||||
public String getStoragePoolUuid() {
|
||||
return storagePoolUuid;
|
||||
}
|
||||
|
||||
public StorageFilerTO getPool() {
|
||||
return pool;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// 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 com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
|
||||
public class DeleteVMSnapshotAnswer extends Answer {
|
||||
private List<VolumeTO> volumeTOs;
|
||||
|
||||
public DeleteVMSnapshotAnswer() {
|
||||
}
|
||||
|
||||
public DeleteVMSnapshotAnswer(DeleteVMSnapshotCommand cmd, boolean result,
|
||||
String message) {
|
||||
super(cmd, result, message);
|
||||
}
|
||||
|
||||
public DeleteVMSnapshotAnswer(DeleteVMSnapshotCommand cmd,
|
||||
List<VolumeTO> volumeTOs) {
|
||||
super(cmd, true, "");
|
||||
this.volumeTOs = volumeTOs;
|
||||
}
|
||||
|
||||
public List<VolumeTO> getVolumeTOs() {
|
||||
return volumeTOs;
|
||||
}
|
||||
|
||||
public void setVolumeTOs(List<VolumeTO> volumeTOs) {
|
||||
this.volumeTOs = volumeTOs;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// 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 com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
|
||||
|
||||
public class DeleteVMSnapshotCommand extends VMSnapshotBaseCommand {
|
||||
public DeleteVMSnapshotCommand(String vmName, VMSnapshotTO snapshot, List<VolumeTO> volumeTOs, String guestOSType) {
|
||||
super( vmName, snapshot, volumeTOs, guestOSType);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// 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 com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
|
||||
public class RevertToVMSnapshotAnswer extends Answer {
|
||||
|
||||
private List<VolumeTO> volumeTOs;
|
||||
private VirtualMachine.State vmState;
|
||||
|
||||
public RevertToVMSnapshotAnswer(RevertToVMSnapshotCommand cmd, boolean result,
|
||||
String message) {
|
||||
super(cmd, result, message);
|
||||
}
|
||||
|
||||
public RevertToVMSnapshotAnswer() {
|
||||
super();
|
||||
}
|
||||
|
||||
public RevertToVMSnapshotAnswer(RevertToVMSnapshotCommand cmd,
|
||||
List<VolumeTO> volumeTOs,
|
||||
VirtualMachine.State vmState) {
|
||||
super(cmd, true, "");
|
||||
this.volumeTOs = volumeTOs;
|
||||
this.vmState = vmState;
|
||||
}
|
||||
|
||||
public VirtualMachine.State getVmState() {
|
||||
return vmState;
|
||||
}
|
||||
|
||||
public List<VolumeTO> getVolumeTOs() {
|
||||
return volumeTOs;
|
||||
}
|
||||
|
||||
public void setVolumeTOs(List<VolumeTO> volumeTOs) {
|
||||
this.volumeTOs = volumeTOs;
|
||||
}
|
||||
|
||||
public void setVmState(VirtualMachine.State vmState) {
|
||||
this.vmState = vmState;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// 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 com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
|
||||
public class RevertToVMSnapshotCommand extends VMSnapshotBaseCommand {
|
||||
|
||||
public RevertToVMSnapshotCommand(String vmName, VMSnapshotTO snapshot, List<VolumeTO> volumeTOs, String guestOSType) {
|
||||
super(vmName, snapshot, volumeTOs, guestOSType);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// 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 com.cloud.agent.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
|
||||
public class VMSnapshotBaseCommand extends Command{
|
||||
protected List<VolumeTO> volumeTOs;
|
||||
protected VMSnapshotTO target;
|
||||
protected String vmName;
|
||||
protected String guestOSType;
|
||||
|
||||
|
||||
public VMSnapshotBaseCommand(String vmName, VMSnapshotTO snapshot, List<VolumeTO> volumeTOs, String guestOSType) {
|
||||
this.vmName = vmName;
|
||||
this.target = snapshot;
|
||||
this.volumeTOs = volumeTOs;
|
||||
this.guestOSType = guestOSType;
|
||||
}
|
||||
|
||||
public List<VolumeTO> getVolumeTOs() {
|
||||
return volumeTOs;
|
||||
}
|
||||
|
||||
public void setVolumeTOs(List<VolumeTO> volumeTOs) {
|
||||
this.volumeTOs = volumeTOs;
|
||||
}
|
||||
|
||||
public VMSnapshotTO getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(VMSnapshotTO target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
return vmName;
|
||||
}
|
||||
|
||||
public void setVmName(String vmName) {
|
||||
this.vmName = vmName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getGuestOSType() {
|
||||
return guestOSType;
|
||||
}
|
||||
|
||||
public void setGuestOSType(String guestOSType) {
|
||||
this.guestOSType = guestOSType;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 com.cloud.agent.api;
|
||||
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
|
||||
public class VMSnapshotTO {
|
||||
private Long id;
|
||||
private String snapshotName;
|
||||
private VMSnapshot.Type type;
|
||||
private Long createTime;
|
||||
private Boolean current;
|
||||
private String description;
|
||||
private VMSnapshotTO parent;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
public VMSnapshotTO(Long id, String snapshotName,
|
||||
VMSnapshot.Type type, Long createTime,
|
||||
String description, Boolean current, VMSnapshotTO parent) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.snapshotName = snapshotName;
|
||||
this.type = type;
|
||||
this.createTime = createTime;
|
||||
this.current = current;
|
||||
this.description = description;
|
||||
this.parent = parent;
|
||||
}
|
||||
public VMSnapshotTO() {
|
||||
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
public Boolean getCurrent() {
|
||||
return current;
|
||||
}
|
||||
public void setCurrent(Boolean current) {
|
||||
this.current = current;
|
||||
}
|
||||
public Long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
public void setCreateTime(Long createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public VMSnapshot.Type getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(VMSnapshot.Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getSnapshotName() {
|
||||
return snapshotName;
|
||||
}
|
||||
public void setSnapshotName(String snapshotName) {
|
||||
this.snapshotName = snapshotName;
|
||||
}
|
||||
public VMSnapshotTO getParent() {
|
||||
return parent;
|
||||
}
|
||||
public void setParent(VMSnapshotTO parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -124,6 +124,10 @@ public class VolumeTO implements InternalIdentity {
|
|||
public String getOsType() {
|
||||
return guestOsType;
|
||||
}
|
||||
|
||||
public void setPath(String path){
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
|
|
|||
|
|
@ -331,6 +331,11 @@ public class EventTypes {
|
|||
// tag related events
|
||||
public static final String EVENT_TAGS_CREATE = "CREATE_TAGS";
|
||||
public static final String EVENT_TAGS_DELETE = "DELETE_TAGS";
|
||||
|
||||
// vm snapshot events
|
||||
public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE";
|
||||
public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE";
|
||||
public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERTTO";
|
||||
|
||||
// external network device events
|
||||
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_ADD = "PHYSICAL.NVPCONTROLLER.ADD";
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit
|
|||
Project,
|
||||
Vpc,
|
||||
NetworkACL,
|
||||
StaticRoute
|
||||
StaticRoute,
|
||||
VMSnapshot
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
|
|||
s_fsm.addTransition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging);
|
||||
s_fsm.addTransition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging);
|
||||
}
|
||||
|
||||
|
||||
public static boolean isVmStarted(State oldState, Event e, State newState) {
|
||||
if (oldState == State.Starting && newState == State.Running) {
|
||||
return true;
|
||||
|
|
@ -174,7 +174,9 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
|
|||
OperationFailedToError,
|
||||
OperationRetry,
|
||||
AgentReportShutdowned,
|
||||
AgentReportMigrated
|
||||
AgentReportMigrated,
|
||||
RevertRequested,
|
||||
SnapshotRequested
|
||||
};
|
||||
|
||||
public enum Type {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
// 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 com.cloud.vm.snapshot;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import com.cloud.utils.fsm.StateMachine2;
|
||||
import com.cloud.utils.fsm.StateObject;
|
||||
|
||||
public interface VMSnapshot extends ControlledEntity, Identity, InternalIdentity,StateObject<VMSnapshot.State> {
|
||||
|
||||
enum State {
|
||||
Allocated("The VM snapshot is allocated but has not been created yet."),
|
||||
Creating("The VM snapshot is being created."),
|
||||
Ready("The VM snapshot is ready to be used."),
|
||||
Reverting("The VM snapshot is being used to revert"),
|
||||
Expunging("The volume is being expunging"),
|
||||
Removed("The volume is destroyed, and can't be recovered."),
|
||||
Error ("The volume is in error state, and can't be recovered");
|
||||
|
||||
String _description;
|
||||
|
||||
private State(String description) {
|
||||
_description = description;
|
||||
}
|
||||
|
||||
public static StateMachine2<State, Event, VMSnapshot> getStateMachine() {
|
||||
return s_fsm;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return _description;
|
||||
}
|
||||
|
||||
private final static StateMachine2<State, Event, VMSnapshot> s_fsm = new StateMachine2<State, Event, VMSnapshot>();
|
||||
static {
|
||||
s_fsm.addTransition(Allocated, Event.CreateRequested, Creating);
|
||||
s_fsm.addTransition(Creating, Event.OperationSucceeded, Ready);
|
||||
s_fsm.addTransition(Creating, Event.OperationFailed, Error);
|
||||
s_fsm.addTransition(Ready, Event.RevertRequested, Reverting);
|
||||
s_fsm.addTransition(Reverting, Event.OperationSucceeded, Ready);
|
||||
s_fsm.addTransition(Reverting, Event.OperationFailed, Ready);
|
||||
s_fsm.addTransition(Ready, Event.ExpungeRequested, Expunging);
|
||||
s_fsm.addTransition(Error, Event.ExpungeRequested, Expunging);
|
||||
s_fsm.addTransition(Expunging, Event.ExpungeRequested, Expunging);
|
||||
s_fsm.addTransition(Expunging, Event.OperationSucceeded, Removed);
|
||||
}
|
||||
}
|
||||
|
||||
enum Type{
|
||||
Disk, DiskAndMemory
|
||||
}
|
||||
|
||||
enum Event {
|
||||
CreateRequested,
|
||||
OperationFailed,
|
||||
OperationSucceeded,
|
||||
RevertRequested,
|
||||
ExpungeRequested,
|
||||
}
|
||||
|
||||
long getId();
|
||||
|
||||
public String getName();
|
||||
|
||||
public Long getVmId();
|
||||
|
||||
public State getState();
|
||||
|
||||
public Date getCreated();
|
||||
|
||||
public String getDescription();
|
||||
|
||||
public String getDisplayName();
|
||||
|
||||
public Long getParent();
|
||||
|
||||
public Boolean getCurrent();
|
||||
|
||||
public Type getType();
|
||||
|
||||
public long getUpdatedCount();
|
||||
|
||||
public void incrUpdatedCount();
|
||||
|
||||
public Date getUpdated();
|
||||
|
||||
public Date getRemoved();
|
||||
|
||||
public long getAccountId();
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// 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 com.cloud.vm.snapshot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
|
||||
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InsufficientServerCapacityException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
|
||||
public interface VMSnapshotService {
|
||||
|
||||
List<? extends VMSnapshot> listVMSnapshots(ListVMSnapshotCmd cmd);
|
||||
|
||||
VMSnapshot getVMSnapshotById(Long id);
|
||||
|
||||
VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId);
|
||||
|
||||
VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDescription, Boolean snapshotMemory)
|
||||
throws ResourceAllocationException;
|
||||
|
||||
boolean deleteVMSnapshot(Long vmSnapshotId);
|
||||
|
||||
UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientServerCapacityException, InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException;
|
||||
|
||||
VirtualMachine getVMBySnapshotId(Long id);
|
||||
}
|
||||
|
|
@ -438,6 +438,11 @@ public class ApiConstants {
|
|||
public static final String AUTOSCALE_USER_ID = "autoscaleuserid";
|
||||
public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername";
|
||||
public static final String UCS_DN = "ucsdn";
|
||||
public static final String VM_SNAPSHOT_DESCRIPTION = "description";
|
||||
public static final String VM_SNAPSHOT_DISPLAYNAME = "name";
|
||||
public static final String VM_SNAPSHOT_ID = "vmsnapshotid";
|
||||
public static final String VM_SNAPSHOT_DISK_IDS = "vmsnapshotdiskids";
|
||||
public static final String VM_SNAPSHOT_MEMORY = "snapshotmemory";
|
||||
|
||||
public enum HostDetails {
|
||||
all, capacity, events, stats, min;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,468 @@
|
|||
// 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.api;
|
||||
|
||||
|
||||
public class ApiConstants {
|
||||
public static final String ACCOUNT = "account";
|
||||
public static final String ACCOUNTS = "accounts";
|
||||
public static final String ACCOUNT_TYPE = "accounttype";
|
||||
public static final String ACCOUNT_ID = "accountid";
|
||||
public static final String ALGORITHM = "algorithm";
|
||||
public static final String ALLOCATED_ONLY = "allocatedonly";
|
||||
public static final String API_KEY = "userapikey";
|
||||
public static final String APPLIED = "applied";
|
||||
public static final String AVAILABLE = "available";
|
||||
public static final String BITS = "bits";
|
||||
public static final String BOOTABLE = "bootable";
|
||||
public static final String BIND_DN = "binddn";
|
||||
public static final String BIND_PASSWORD = "bindpass";
|
||||
public static final String CATEGORY = "category";
|
||||
public static final String CERTIFICATE = "certificate";
|
||||
public static final String PRIVATE_KEY = "privatekey";
|
||||
public static final String DOMAIN_SUFFIX = "domainsuffix";
|
||||
public static final String DNS_SEARCH_ORDER = "dnssearchorder";
|
||||
public static final String CIDR = "cidr";
|
||||
public static final String IP6_CIDR = "ip6cidr";
|
||||
public static final String CIDR_LIST = "cidrlist";
|
||||
public static final String CLEANUP = "cleanup";
|
||||
public static final String CLUSTER_ID = "clusterid";
|
||||
public static final String CLUSTER_NAME = "clustername";
|
||||
public static final String CLUSTER_TYPE = "clustertype";
|
||||
public static final String COMPONENT = "component";
|
||||
public static final String CPU_NUMBER = "cpunumber";
|
||||
public static final String CPU_SPEED = "cpuspeed";
|
||||
public static final String CREATED = "created";
|
||||
public static final String CUSTOMIZED = "customized";
|
||||
public static final String DESCRIPTION = "description";
|
||||
public static final String DESTINATION_ZONE_ID = "destzoneid";
|
||||
public static final String DETAILS = "details";
|
||||
public static final String DEVICE_ID = "deviceid";
|
||||
public static final String DISK_OFFERING_ID = "diskofferingid";
|
||||
public static final String DISK_SIZE = "disksize";
|
||||
public static final String DISPLAY_NAME = "displayname";
|
||||
public static final String DISPLAY_TEXT = "displaytext";
|
||||
public static final String DNS1 = "dns1";
|
||||
public static final String DNS2 = "dns2";
|
||||
public static final String DOMAIN = "domain";
|
||||
public static final String DOMAIN_ID = "domainid";
|
||||
public static final String DURATION = "duration";
|
||||
public static final String EMAIL = "email";
|
||||
public static final String END_DATE = "enddate";
|
||||
public static final String END_IP = "endip";
|
||||
public static final String END_IPV6 = "endipv6";
|
||||
public static final String END_PORT = "endport";
|
||||
public static final String ENTRY_TIME = "entrytime";
|
||||
public static final String FETCH_LATEST = "fetchlatest";
|
||||
public static final String FIRSTNAME = "firstname";
|
||||
public static final String FORCED = "forced";
|
||||
public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage";
|
||||
public static final String FORMAT = "format";
|
||||
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
|
||||
public static final String GATEWAY = "gateway";
|
||||
public static final String IP6_GATEWAY = "ip6gateway";
|
||||
public static final String GROUP = "group";
|
||||
public static final String GROUP_ID = "groupid";
|
||||
public static final String GUEST_CIDR_ADDRESS = "guestcidraddress";
|
||||
public static final String HA_ENABLE = "haenable";
|
||||
public static final String HOST_ID = "hostid";
|
||||
public static final String HOST_NAME = "hostname";
|
||||
public static final String HYPERVISOR = "hypervisor";
|
||||
public static final String INLINE = "inline";
|
||||
public static final String INSTANCE = "instance";
|
||||
public static final String ICMP_CODE = "icmpcode";
|
||||
public static final String ICMP_TYPE = "icmptype";
|
||||
public static final String ID = "id";
|
||||
public static final String IDS = "ids";
|
||||
public static final String INTERNAL_DNS1 = "internaldns1";
|
||||
public static final String INTERNAL_DNS2 = "internaldns2";
|
||||
public static final String INTERVAL_TYPE = "intervaltype";
|
||||
public static final String IP_ADDRESS = "ipaddress";
|
||||
public static final String IP6_ADDRESS = "ip6address";
|
||||
public static final String IP_ADDRESS_ID = "ipaddressid";
|
||||
public static final String IS_ASYNC = "isasync";
|
||||
public static final String IP_AVAILABLE = "ipavailable";
|
||||
public static final String IP_LIMIT = "iplimit";
|
||||
public static final String IP_TOTAL = "iptotal";
|
||||
public static final String IS_CLEANUP_REQUIRED = "iscleanuprequired";
|
||||
public static final String IS_EXTRACTABLE = "isextractable";
|
||||
public static final String IS_FEATURED = "isfeatured";
|
||||
public static final String IS_PUBLIC = "ispublic";
|
||||
public static final String IS_PERSISTENT = "ispersistent";
|
||||
public static final String IS_READY = "isready";
|
||||
public static final String IS_RECURSIVE = "isrecursive";
|
||||
public static final String ISO_FILTER = "isofilter";
|
||||
public static final String ISO_GUEST_OS_NONE = "None";
|
||||
public static final String JOB_ID = "jobid";
|
||||
public static final String JOB_STATUS = "jobstatus";
|
||||
public static final String LASTNAME = "lastname";
|
||||
public static final String LEVEL = "level";
|
||||
public static final String LENGTH = "length";
|
||||
public static final String LIMIT_CPU_USE = "limitcpuuse";
|
||||
public static final String LOCK = "lock";
|
||||
public static final String LUN = "lun";
|
||||
public static final String LBID = "lbruleid";
|
||||
public static final String MAX = "max";
|
||||
public static final String MAX_SNAPS = "maxsnaps";
|
||||
public static final String MEMORY = "memory";
|
||||
public static final String MODE = "mode";
|
||||
public static final String NAME = "name";
|
||||
public static final String METHOD_NAME = "methodname";
|
||||
public static final String NETWORK_DOMAIN = "networkdomain";
|
||||
public static final String NETMASK = "netmask";
|
||||
public static final String NEW_NAME = "newname";
|
||||
public static final String NUM_RETRIES = "numretries";
|
||||
public static final String OFFER_HA = "offerha";
|
||||
public static final String IS_SYSTEM_OFFERING = "issystem";
|
||||
public static final String IS_DEFAULT_USE = "defaultuse";
|
||||
public static final String OP = "op";
|
||||
public static final String OS_CATEGORY_ID = "oscategoryid";
|
||||
public static final String OS_TYPE_ID = "ostypeid";
|
||||
public static final String PARAMS = "params";
|
||||
public static final String PARENT_DOMAIN_ID = "parentdomainid";
|
||||
public static final String PASSWORD = "password";
|
||||
public static final String NEW_PASSWORD = "new_password";
|
||||
public static final String PASSWORD_ENABLED = "passwordenabled";
|
||||
public static final String SSHKEY_ENABLED = "sshkeyenabled";
|
||||
public static final String PATH = "path";
|
||||
public static final String POD_ID = "podid";
|
||||
public static final String POD_IDS = "podids";
|
||||
public static final String POLICY_ID = "policyid";
|
||||
public static final String PORT = "port";
|
||||
public static final String PORTAL = "portal";
|
||||
public static final String PORT_FORWARDING_SERVICE_ID = "portforwardingserviceid";
|
||||
public static final String PRIVATE_INTERFACE = "privateinterface";
|
||||
public static final String PRIVATE_IP = "privateip";
|
||||
public static final String PRIVATE_PORT = "privateport";
|
||||
public static final String PRIVATE_START_PORT = "privateport";
|
||||
public static final String PRIVATE_END_PORT = "privateendport";
|
||||
public static final String PRIVATE_ZONE = "privatezone";
|
||||
public static final String PROTOCOL = "protocol";
|
||||
public static final String PUBLIC_INTERFACE = "publicinterface";
|
||||
public static final String PUBLIC_IP_ID = "publicipid";
|
||||
public static final String PUBLIC_IP = "publicip";
|
||||
public static final String PUBLIC_PORT = "publicport";
|
||||
public static final String PUBLIC_START_PORT = "publicport";
|
||||
public static final String PUBLIC_END_PORT = "publicendport";
|
||||
public static final String PUBLIC_ZONE = "publiczone";
|
||||
public static final String RECEIVED_BYTES = "receivedbytes";
|
||||
public static final String REQUIRES_HVM = "requireshvm";
|
||||
public static final String RESOURCE_TYPE = "resourcetype";
|
||||
public static final String RESPONSE = "response";
|
||||
public static final String QUERY_FILTER = "queryfilter";
|
||||
public static final String SCHEDULE = "schedule";
|
||||
public static final String SCOPE = "scope";
|
||||
public static final String SECRET_KEY = "usersecretkey";
|
||||
public static final String SINCE = "since";
|
||||
public static final String KEY = "key";
|
||||
public static final String SEARCH_BASE = "searchbase";
|
||||
public static final String SECURITY_GROUP_IDS = "securitygroupids";
|
||||
public static final String SECURITY_GROUP_NAMES = "securitygroupnames";
|
||||
public static final String SECURITY_GROUP_NAME = "securitygroupname";
|
||||
public static final String SECURITY_GROUP_ID = "securitygroupid";
|
||||
public static final String SENT = "sent";
|
||||
public static final String SENT_BYTES = "sentbytes";
|
||||
public static final String SERVICE_OFFERING_ID = "serviceofferingid";
|
||||
public static final String SHOW_CAPACITIES = "showcapacities";
|
||||
public static final String SIZE = "size";
|
||||
public static final String SNAPSHOT_ID = "snapshotid";
|
||||
public static final String SNAPSHOT_POLICY_ID = "snapshotpolicyid";
|
||||
public static final String SNAPSHOT_TYPE = "snapshottype";
|
||||
public static final String SOURCE_ZONE_ID = "sourcezoneid";
|
||||
public static final String START_DATE = "startdate";
|
||||
public static final String START_IP = "startip";
|
||||
public static final String START_IPV6 = "startipv6";
|
||||
public static final String START_PORT = "startport";
|
||||
public static final String STATE = "state";
|
||||
public static final String STATUS = "status";
|
||||
public static final String STORAGE_TYPE = "storagetype";
|
||||
public static final String SYSTEM_VM_TYPE = "systemvmtype";
|
||||
public static final String TAGS = "tags";
|
||||
public static final String TARGET_IQN = "targetiqn";
|
||||
public static final String TEMPLATE_FILTER = "templatefilter";
|
||||
public static final String TEMPLATE_ID = "templateid";
|
||||
public static final String ISO_ID = "isoid";
|
||||
public static final String TIMEOUT = "timeout";
|
||||
public static final String TIMEZONE = "timezone";
|
||||
public static final String TYPE = "type";
|
||||
public static final String TRUST_STORE = "truststore";
|
||||
public static final String TRUST_STORE_PASSWORD = "truststorepass";
|
||||
public static final String URL = "url";
|
||||
public static final String USAGE_INTERFACE = "usageinterface";
|
||||
public static final String USER_DATA = "userdata";
|
||||
public static final String USER_ID = "userid";
|
||||
public static final String USE_SSL = "ssl";
|
||||
public static final String USERNAME = "username";
|
||||
public static final String USER_SECURITY_GROUP_LIST = "usersecuritygrouplist";
|
||||
public static final String USE_VIRTUAL_NETWORK = "usevirtualnetwork";
|
||||
public static final String VALUE = "value";
|
||||
public static final String VIRTUAL_MACHINE_ID = "virtualmachineid";
|
||||
public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids";
|
||||
public static final String VLAN = "vlan";
|
||||
public static final String VLAN_ID = "vlanid";
|
||||
public static final String VM_AVAILABLE = "vmavailable";
|
||||
public static final String VM_LIMIT = "vmlimit";
|
||||
public static final String VM_TOTAL = "vmtotal";
|
||||
public static final String VNET = "vnet";
|
||||
public static final String VOLUME_ID = "volumeid";
|
||||
public static final String ZONE_ID = "zoneid";
|
||||
public static final String ZONE_NAME = "zonename";
|
||||
public static final String NETWORK_TYPE = "networktype";
|
||||
public static final String PAGE = "page";
|
||||
public static final String PAGE_SIZE = "pagesize";
|
||||
public static final String COUNT = "count";
|
||||
public static final String TRAFFIC_TYPE = "traffictype";
|
||||
public static final String NETWORK_OFFERING_ID = "networkofferingid";
|
||||
public static final String NETWORK_IDS = "networkids";
|
||||
public static final String NETWORK_ID = "networkid";
|
||||
public static final String NIC_ID = "nicid";
|
||||
public static final String SPECIFY_VLAN = "specifyvlan";
|
||||
public static final String IS_DEFAULT = "isdefault";
|
||||
public static final String IS_SYSTEM = "issystem";
|
||||
public static final String AVAILABILITY = "availability";
|
||||
public static final String NETWORKRATE = "networkrate";
|
||||
public static final String HOST_TAGS = "hosttags";
|
||||
public static final String SSH_KEYPAIR = "keypair";
|
||||
public static final String HOST_CPU_CAPACITY = "hostcpucapacity";
|
||||
public static final String HOST_CPU_NUM = "hostcpunum";
|
||||
public static final String HOST_MEM_CAPACITY = "hostmemcapacity";
|
||||
public static final String HOST_MAC = "hostmac";
|
||||
public static final String HOST_TAG = "hosttag";
|
||||
public static final String PXE_SERVER_TYPE = "pxeservertype";
|
||||
public static final String LINMIN_USERNAME = "linminusername";
|
||||
public static final String LINMIN_PASSWORD = "linminpassword";
|
||||
public static final String LINMIN_APID = "linminapid";
|
||||
public static final String DHCP_SERVER_TYPE = "dhcpservertype";
|
||||
public static final String LINK_LOCAL_IP = "linklocalip";
|
||||
public static final String LINK_LOCAL_MAC_ADDRESS = "linklocalmacaddress";
|
||||
public static final String LINK_LOCAL_MAC_NETMASK = "linklocalnetmask";
|
||||
public static final String LINK_LOCAL_NETWORK_ID = "linklocalnetworkid";
|
||||
public static final String PRIVATE_MAC_ADDRESS = "privatemacaddress";
|
||||
public static final String PRIVATE_NETMASK = "privatenetmask";
|
||||
public static final String PRIVATE_NETWORK_ID = "privatenetworkid";
|
||||
public static final String ALLOCATION_STATE = "allocationstate";
|
||||
public static final String MANAGED_STATE = "managedstate";
|
||||
public static final String STORAGE_ID = "storageid";
|
||||
public static final String PING_STORAGE_SERVER_IP = "pingstorageserverip";
|
||||
public static final String PING_DIR = "pingdir";
|
||||
public static final String TFTP_DIR = "tftpdir";
|
||||
public static final String PING_CIFS_USERNAME = "pingcifsusername";
|
||||
public static final String PING_CIFS_PASSWORD = "pingcifspassword";
|
||||
public static final String CHECKSUM = "checksum";
|
||||
public static final String NETWORK_DEVICE_TYPE = "networkdevicetype";
|
||||
public static final String NETWORK_DEVICE_PARAMETER_LIST = "networkdeviceparameterlist";
|
||||
public static final String ZONE_TOKEN = "zonetoken";
|
||||
public static final String DHCP_PROVIDER = "dhcpprovider";
|
||||
public static final String RESULT = "success";
|
||||
public static final String LUN_ID = "lunId";
|
||||
public static final String IQN = "iqn";
|
||||
public static final String AGGREGATE_NAME = "aggregatename";
|
||||
public static final String POOL_NAME = "poolname";
|
||||
public static final String VOLUME_NAME = "volumename";
|
||||
public static final String SNAPSHOT_POLICY = "snapshotpolicy";
|
||||
public static final String SNAPSHOT_RESERVATION = "snapshotreservation";
|
||||
public static final String IP_NETWORK_LIST = "iptonetworklist";
|
||||
public static final String PARAM_LIST = "param";
|
||||
public static final String FOR_LOAD_BALANCING = "forloadbalancing";
|
||||
public static final String KEYBOARD = "keyboard";
|
||||
public static final String OPEN_FIREWALL = "openfirewall";
|
||||
public static final String TEMPLATE_TAG = "templatetag";
|
||||
public static final String HYPERVISOR_VERSION = "hypervisorversion";
|
||||
public static final String MAX_GUESTS_LIMIT = "maxguestslimit";
|
||||
public static final String PROJECT_ID = "projectid";
|
||||
public static final String PROJECT_IDS = "projectids";
|
||||
public static final String PROJECT = "project";
|
||||
public static final String ROLE = "role";
|
||||
public static final String USER = "user";
|
||||
public static final String ACTIVE_ONLY = "activeonly";
|
||||
public static final String TOKEN = "token";
|
||||
public static final String ACCEPT = "accept";
|
||||
public static final String SORT_KEY = "sortkey";
|
||||
public static final String ACCOUNT_DETAILS = "accountdetails";
|
||||
public static final String SERVICE_PROVIDER_LIST = "serviceproviderlist";
|
||||
public static final String SERVICE_CAPABILITY_LIST = "servicecapabilitylist";
|
||||
public static final String CAN_CHOOSE_SERVICE_CAPABILITY = "canchooseservicecapability";
|
||||
public static final String PROVIDER = "provider";
|
||||
public static final String NETWORK_SPEED = "networkspeed";
|
||||
public static final String BROADCAST_DOMAIN_RANGE = "broadcastdomainrange";
|
||||
public static final String ISOLATION_METHODS = "isolationmethods";
|
||||
public static final String PHYSICAL_NETWORK_ID = "physicalnetworkid";
|
||||
public static final String DEST_PHYSICAL_NETWORK_ID = "destinationphysicalnetworkid";
|
||||
public static final String ENABLED = "enabled";
|
||||
public static final String SERVICE_NAME = "servicename";
|
||||
public static final String DHCP_RANGE = "dhcprange";
|
||||
public static final String UUID = "uuid";
|
||||
public static final String SECURITY_GROUP_EANBLED = "securitygroupenabled";
|
||||
public static final String LOCAL_STORAGE_ENABLED = "localstorageenabled";
|
||||
public static final String GUEST_IP_TYPE = "guestiptype";
|
||||
public static final String XEN_NETWORK_LABEL = "xennetworklabel";
|
||||
public static final String KVM_NETWORK_LABEL = "kvmnetworklabel";
|
||||
public static final String VMWARE_NETWORK_LABEL = "vmwarenetworklabel";
|
||||
public static final String NETWORK_SERVICE_PROVIDER_ID = "nspid";
|
||||
public static final String SERVICE_LIST = "servicelist";
|
||||
public static final String CAN_ENABLE_INDIVIDUAL_SERVICE = "canenableindividualservice";
|
||||
public static final String SUPPORTED_SERVICES = "supportedservices";
|
||||
public static final String NSP_ID = "nspid";
|
||||
public static final String ACL_TYPE = "acltype";
|
||||
public static final String SUBDOMAIN_ACCESS = "subdomainaccess";
|
||||
public static final String LOAD_BALANCER_DEVICE_ID = "lbdeviceid";
|
||||
public static final String LOAD_BALANCER_DEVICE_NAME = "lbdevicename";
|
||||
public static final String LOAD_BALANCER_DEVICE_STATE = "lbdevicestate";
|
||||
public static final String LOAD_BALANCER_DEVICE_CAPACITY = "lbdevicecapacity";
|
||||
public static final String LOAD_BALANCER_DEVICE_DEDICATED = "lbdevicededicated";
|
||||
public static final String FIREWALL_DEVICE_ID = "fwdeviceid";
|
||||
public static final String FIREWALL_DEVICE_NAME = "fwdevicename";
|
||||
public static final String FIREWALL_DEVICE_STATE = "fwdevicestate";
|
||||
public static final String FIREWALL_DEVICE_CAPACITY = "fwdevicecapacity";
|
||||
public static final String FIREWALL_DEVICE_DEDICATED = "fwdevicededicated";
|
||||
public static final String SERVICE = "service";
|
||||
public static final String ASSOCIATED_NETWORK_ID = "associatednetworkid";
|
||||
public static final String ASSOCIATED_NETWORK_NAME = "associatednetworkname";
|
||||
public static final String SOURCE_NAT_SUPPORTED = "sourcenatsupported";
|
||||
public static final String RESOURCE_STATE = "resourcestate";
|
||||
public static final String PROJECT_INVITE_REQUIRED = "projectinviterequired";
|
||||
public static final String REQUIRED = "required";
|
||||
public static final String RESTART_REQUIRED = "restartrequired";
|
||||
public static final String ALLOW_USER_CREATE_PROJECTS = "allowusercreateprojects";
|
||||
public static final String CONSERVE_MODE = "conservemode";
|
||||
public static final String TRAFFIC_TYPE_IMPLEMENTOR = "traffictypeimplementor";
|
||||
public static final String KEYWORD = "keyword";
|
||||
public static final String LIST_ALL = "listall";
|
||||
public static final String SPECIFY_IP_RANGES = "specifyipranges";
|
||||
public static final String IS_SOURCE_NAT = "issourcenat";
|
||||
public static final String IS_STATIC_NAT = "isstaticnat";
|
||||
public static final String SORT_BY = "sortby";
|
||||
public static final String CHANGE_CIDR = "changecidr";
|
||||
public static final String PURPOSE = "purpose";
|
||||
public static final String IS_TAGGED = "istagged";
|
||||
public static final String INSTANCE_NAME = "instancename";
|
||||
public static final String START_VM = "startvm";
|
||||
public static final String HA_HOST = "hahost";
|
||||
public static final String CUSTOM_DISK_OFF_MAX_SIZE = "customdiskofferingmaxsize";
|
||||
public static final String DEFAULT_ZONE_ID = "defaultzoneid";
|
||||
public static final String GUID = "guid";
|
||||
|
||||
public static final String EXTERNAL_SWITCH_MGMT_DEVICE_ID = "vsmdeviceid";
|
||||
public static final String EXTERNAL_SWITCH_MGMT_DEVICE_NAME = "vsmdevicename";
|
||||
public static final String EXTERNAL_SWITCH_MGMT_DEVICE_STATE = "vsmdevicestate";
|
||||
// Would we need to have a capacity field for Cisco N1KV VSM? Max hosts managed by it perhaps? May remove this later.
|
||||
public static final String EXTERNAL_SWITCH_MGMT_DEVICE_CAPACITY = "vsmdevicecapacity";
|
||||
public static final String CISCO_NEXUS_VSM_NAME = "vsmname";
|
||||
public static final String VSM_USERNAME = "vsmusername";
|
||||
public static final String VSM_PASSWORD = "vsmpassword";
|
||||
public static final String VSM_IPADDRESS = "vsmipaddress";
|
||||
public static final String VSM_MGMT_VLAN_ID = "vsmmgmtvlanid";
|
||||
public static final String VSM_PKT_VLAN_ID = "vsmpktvlanid";
|
||||
public static final String VSM_CTRL_VLAN_ID = "vsmctrlvlanid";
|
||||
public static final String VSM_STORAGE_VLAN_ID = "vsmstoragevlanid";
|
||||
public static final String VSM_DOMAIN_ID = "vsmdomainid";
|
||||
public static final String VSM_CONFIG_MODE = "vsmconfigmode";
|
||||
public static final String VSM_CONFIG_STATE = "vsmconfigstate";
|
||||
public static final String VSM_DEVICE_STATE = "vsmdevicestate";
|
||||
public static final String ADD_VSM_FLAG = "addvsmflag";
|
||||
public static final String END_POINT = "endpoint";
|
||||
public static final String REGION_ID = "regionid";
|
||||
public static final String IS_PROPAGATE = "ispropagate";
|
||||
public static final String VPC_OFF_ID = "vpcofferingid";
|
||||
public static final String NETWORK = "network";
|
||||
public static final String VPC_ID = "vpcid";
|
||||
public static final String GATEWAY_ID = "gatewayid";
|
||||
public static final String CAN_USE_FOR_DEPLOY = "canusefordeploy";
|
||||
public static final String RESOURCE_IDS = "resourceids";
|
||||
public static final String RESOURCE_ID = "resourceid";
|
||||
public static final String CUSTOMER = "customer";
|
||||
public static final String S2S_VPN_GATEWAY_ID = "s2svpngatewayid";
|
||||
public static final String S2S_CUSTOMER_GATEWAY_ID = "s2scustomergatewayid";
|
||||
public static final String IPSEC_PSK = "ipsecpsk";
|
||||
public static final String GUEST_IP = "guestip";
|
||||
public static final String REMOVED = "removed";
|
||||
public static final String IKE_POLICY = "ikepolicy";
|
||||
public static final String ESP_POLICY = "esppolicy";
|
||||
public static final String IKE_LIFETIME = "ikelifetime";
|
||||
public static final String ESP_LIFETIME = "esplifetime";
|
||||
public static final String DPD = "dpd";
|
||||
public static final String FOR_VPC = "forvpc";
|
||||
public static final String SHRINK_OK = "shrinkok";
|
||||
public static final String NICIRA_NVP_DEVICE_ID = "nvpdeviceid";
|
||||
public static final String NICIRA_NVP_TRANSPORT_ZONE_UUID = "transportzoneuuid";
|
||||
public static final String NICIRA_NVP_DEVICE_NAME = "niciradevicename";
|
||||
public static final String NICIRA_NVP_GATEWAYSERVICE_UUID = "l3gatewayserviceuuid";
|
||||
public static final String S3_ACCESS_KEY = "accesskey";
|
||||
public static final String S3_SECRET_KEY = "secretkey";
|
||||
public static final String S3_END_POINT = "endpoint";
|
||||
public static final String S3_BUCKET_NAME = "bucket";
|
||||
public static final String S3_HTTPS_FLAG = "usehttps";
|
||||
public static final String S3_CONNECTION_TIMEOUT = "connectiontimeout";
|
||||
public static final String S3_MAX_ERROR_RETRY = "maxerrorretry";
|
||||
public static final String S3_SOCKET_TIMEOUT = "sockettimeout";
|
||||
public static final String INCL_ZONES = "includezones";
|
||||
public static final String EXCL_ZONES = "excludezones";
|
||||
public static final String SOURCE = "source";
|
||||
public static final String COUNTER_ID = "counterid";
|
||||
public static final String AGGR_OPERATOR = "aggroperator";
|
||||
public static final String AGGR_FUNCTION = "aggrfunction";
|
||||
public static final String AGGR_VALUE = "aggrvalue";
|
||||
public static final String THRESHOLD = "threshold";
|
||||
public static final String RELATIONAL_OPERATOR = "relationaloperator";
|
||||
public static final String OTHER_DEPLOY_PARAMS = "otherdeployparams";
|
||||
public static final String MIN_MEMBERS = "minmembers";
|
||||
public static final String MAX_MEMBERS = "maxmembers";
|
||||
public static final String AUTOSCALE_VM_DESTROY_TIME = "destroyvmgraceperiod";
|
||||
public static final String VMPROFILE_ID = "vmprofileid";
|
||||
public static final String VMGROUP_ID = "vmgroupid";
|
||||
public static final String CS_URL = "csurl";
|
||||
public static final String SCALEUP_POLICY_IDS = "scaleuppolicyids";
|
||||
public static final String SCALEDOWN_POLICY_IDS = "scaledownpolicyids";
|
||||
public static final String SCALEUP_POLICIES = "scaleuppolicies";
|
||||
public static final String SCALEDOWN_POLICIES = "scaledownpolicies";
|
||||
public static final String INTERVAL = "interval";
|
||||
public static final String QUIETTIME = "quiettime";
|
||||
public static final String ACTION = "action";
|
||||
public static final String CONDITION_ID = "conditionid";
|
||||
public static final String CONDITION_IDS = "conditionids";
|
||||
public static final String COUNTERPARAM_LIST = "counterparam";
|
||||
public static final String AUTOSCALE_USER_ID = "autoscaleuserid";
|
||||
public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername";
|
||||
<<<<<<< HEAD
|
||||
public static final String UCS_DN = "ucsdn";
|
||||
=======
|
||||
public static final String VM_SNAPSHOT_DESCRIPTION = "description";
|
||||
public static final String VM_SNAPSHOT_DISPLAYNAME = "name";
|
||||
public static final String VM_SNAPSHOT_ID = "vmsnapshotid";
|
||||
public static final String VM_SNAPSHOT_DISK_IDS = "vmsnapshotdiskids";
|
||||
public static final String VM_SNAPSHOT_MEMORY = "snapshotmemory";
|
||||
>>>>>>> CLOUDSTACK-684 Support VM Snapshot
|
||||
|
||||
public enum HostDetails {
|
||||
all, capacity, events, stats, min;
|
||||
}
|
||||
|
||||
public enum VMDetails {
|
||||
all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min;
|
||||
}
|
||||
|
||||
public enum LDAPParams {
|
||||
hostname, port, usessl, queryfilter, searchbase, dn, passwd, truststore, truststorepass;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ldap." + name();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -71,6 +71,7 @@ import com.cloud.user.ResourceLimitService;
|
|||
import com.cloud.utils.Pair;
|
||||
import com.cloud.vm.BareMetalVmService;
|
||||
import com.cloud.vm.UserVmService;
|
||||
import com.cloud.vm.snapshot.VMSnapshotService;
|
||||
|
||||
public abstract class BaseCmd {
|
||||
private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName());
|
||||
|
|
@ -128,6 +129,7 @@ public abstract class BaseCmd {
|
|||
@Inject public QueryService _queryService;
|
||||
@Inject public UsageService _usageService;
|
||||
@Inject public NetworkUsageService _networkUsageService;
|
||||
@Inject public VMSnapshotService _vmSnapshotService;
|
||||
|
||||
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException;
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ import org.apache.cloudstack.api.response.TrafficTypeResponse;
|
|||
import org.apache.cloudstack.api.response.UsageRecordResponse;
|
||||
import org.apache.cloudstack.api.response.UserResponse;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.api.response.VMSnapshotResponse;
|
||||
import org.apache.cloudstack.api.response.VirtualRouterProviderResponse;
|
||||
import org.apache.cloudstack.api.response.VlanIpRangeResponse;
|
||||
import org.apache.cloudstack.api.response.VolumeResponse;
|
||||
|
|
@ -163,6 +164,7 @@ import com.cloud.user.UserAccount;
|
|||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.vm.InstanceGroup;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
|
||||
public interface ResponseGenerator {
|
||||
UserResponse createUserResponse(UserAccount user);
|
||||
|
|
@ -381,5 +383,6 @@ public interface ResponseGenerator {
|
|||
|
||||
UsageRecordResponse createUsageResponse(Usage usageRecord);
|
||||
|
||||
TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor);
|
||||
TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor);
|
||||
VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
// 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.api.command.user.vmsnapshot;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseAsyncCreateCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.api.response.VMSnapshotResponse;
|
||||
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
|
||||
@APICommand(name = "createVMSnapshot", description = "Creates snapshot for a vm.", responseObject = VMSnapshotResponse.class)
|
||||
public class CreateVMSnapshotCmd extends BaseAsyncCreateCmd {
|
||||
|
||||
public static final Logger s_logger = Logger
|
||||
.getLogger(CreateVMSnapshotCmd.class.getName());
|
||||
private static final String s_name = "createvmsnapshotresponse";
|
||||
|
||||
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, required = true, entityType=UserVmResponse.class, description = "The ID of the vm")
|
||||
private Long vmId;
|
||||
|
||||
@Parameter(name = ApiConstants.VM_SNAPSHOT_DESCRIPTION, type = CommandType.STRING, required = false, description = "The discription of the snapshot")
|
||||
private String description;
|
||||
|
||||
@Parameter(name = ApiConstants.VM_SNAPSHOT_DISPLAYNAME, type = CommandType.STRING, required = false, description = "The display name of the snapshot")
|
||||
private String displayName;
|
||||
|
||||
@Parameter(name = ApiConstants.VM_SNAPSHOT_MEMORY, type = CommandType.BOOLEAN, required = false, description = "snapshot memory if true")
|
||||
private Boolean snapshotMemory;
|
||||
|
||||
public Boolean snapshotMemory() {
|
||||
if (snapshotMemory == null) {
|
||||
return false;
|
||||
} else {
|
||||
return snapshotMemory;
|
||||
}
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public Long getVmId() {
|
||||
return vmId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create() throws ResourceAllocationException {
|
||||
VMSnapshot vmsnapshot = _vmSnapshotService.allocVMSnapshot(getVmId(),getDisplayName(),getDescription(),snapshotMemory());
|
||||
if (vmsnapshot != null) {
|
||||
this.setEntityId(vmsnapshot.getId());
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
|
||||
"Failed to create vm snapshot");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventDescription() {
|
||||
return "creating snapshot for VM: " + getVmId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType() {
|
||||
return EventTypes.EVENT_VM_SNAPSHOT_CREATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
UserContext.current().setEventDetails("VM Id: " + getVmId());
|
||||
VMSnapshot result = _vmSnapshotService.creatVMSnapshot(getVmId(),getEntityId());
|
||||
if (result != null) {
|
||||
VMSnapshotResponse response = _responseGenerator
|
||||
.createVMSnapshotResponse(result);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(
|
||||
ApiErrorCode.INTERNAL_ERROR,
|
||||
"Failed to create vm snapshot due to an internal error creating snapshot for vm "
|
||||
+ getVmId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
UserVm userVM = _userVmService.getUserVm(vmId);
|
||||
return userVM.getAccountId();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
// 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.api.command.user.vmsnapshot;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseAsyncCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||
import org.apache.cloudstack.api.response.VMSnapshotResponse;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
|
||||
@APICommand(name="deleteVMSnapshot", description = "Deletes a vmsnapshot.", responseObject = SuccessResponse.class)
|
||||
public class DeleteVMSnapshotCmd extends BaseAsyncCmd {
|
||||
public static final Logger s_logger = Logger
|
||||
.getLogger(DeleteVMSnapshotCmd.class.getName());
|
||||
private static final String s_name = "deletevmsnapshotresponse";
|
||||
|
||||
@Parameter(name=ApiConstants.VM_SNAPSHOT_ID, type=CommandType.UUID, entityType=VMSnapshotResponse.class,
|
||||
required=true, description="The ID of the VM snapshot")
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
VMSnapshot vmSnapshot = _entityMgr.findById(VMSnapshot.class, getId());
|
||||
if (vmSnapshot != null) {
|
||||
return vmSnapshot.getAccountId();
|
||||
}
|
||||
return Account.ACCOUNT_ID_SYSTEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
UserContext.current().setEventDetails("vmsnapshot id: " + getId());
|
||||
boolean result = _vmSnapshotService.deleteVMSnapshot(getId());
|
||||
if (result) {
|
||||
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete vm snapshot");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventDescription() {
|
||||
return "Delete VM snapshot: " + getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType() {
|
||||
return EventTypes.EVENT_VM_SNAPSHOT_DELETE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// 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.api.command.user.vmsnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.api.response.VMSnapshotResponse;
|
||||
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
|
||||
@APICommand(name="listVMSnapshot", description = "List virtual machine snapshot by conditions", responseObject = VMSnapshotResponse.class)
|
||||
public class ListVMSnapshotCmd extends BaseListTaggedResourcesCmd {
|
||||
|
||||
private static final String s_name = "listvmsnapshotresponse";
|
||||
|
||||
@Parameter(name=ApiConstants.VM_SNAPSHOT_ID, type=CommandType.UUID, entityType=VMSnapshotResponse.class,
|
||||
description="The ID of the VM snapshot")
|
||||
private Long id;
|
||||
|
||||
@Parameter(name=ApiConstants.STATE, type=CommandType.STRING, description="state of the virtual machine snapshot")
|
||||
private String state;
|
||||
|
||||
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType=UserVmResponse.class, description = "the ID of the vm")
|
||||
private Long vmId;
|
||||
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "lists snapshot by snapshot name or display name")
|
||||
private String vmSnapshotName;
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getVmSnapshotName() {
|
||||
return vmSnapshotName;
|
||||
}
|
||||
|
||||
public Long getVmId() {
|
||||
return vmId;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
List<? extends VMSnapshot> result = _vmSnapshotService
|
||||
.listVMSnapshots(this);
|
||||
ListResponse<VMSnapshotResponse> response = new ListResponse<VMSnapshotResponse>();
|
||||
List<VMSnapshotResponse> snapshotResponses = new ArrayList<VMSnapshotResponse>();
|
||||
for (VMSnapshot r : result) {
|
||||
VMSnapshotResponse vmSnapshotResponse = _responseGenerator
|
||||
.createVMSnapshotResponse(r);
|
||||
vmSnapshotResponse.setObjectName("vmSnapshot");
|
||||
snapshotResponses.add(vmSnapshotResponse);
|
||||
}
|
||||
response.setResponses(snapshotResponses);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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.api.command.user.vmsnapshot;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseAsyncCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||
import org.apache.cloudstack.api.response.VMSnapshotResponse;
|
||||
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
|
||||
@APICommand(name = "revertToSnapshot",description = "Revert VM from a vmsnapshot.", responseObject = UserVmResponse.class)
|
||||
public class RevertToSnapshotCmd extends BaseAsyncCmd {
|
||||
public static final Logger s_logger = Logger
|
||||
.getLogger(RevertToSnapshotCmd.class.getName());
|
||||
private static final String s_name = "reverttosnapshotresponse";
|
||||
|
||||
@Parameter(name = ApiConstants.VM_SNAPSHOT_ID, type = CommandType.UUID, required = true,entityType=VMSnapshotResponse.class,description = "The ID of the vm snapshot")
|
||||
private Long vmSnapShotId;
|
||||
|
||||
public Long getVmSnapShotId() {
|
||||
return vmSnapShotId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
VMSnapshot vmSnapshot = _entityMgr.findById(VMSnapshot.class, getVmSnapShotId());
|
||||
if (vmSnapshot != null) {
|
||||
return vmSnapshot.getAccountId();
|
||||
}
|
||||
return Account.ACCOUNT_ID_SYSTEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException, ConcurrentOperationException {
|
||||
UserContext.current().setEventDetails(
|
||||
"vmsnapshot id: " + getVmSnapShotId());
|
||||
UserVm result = _vmSnapshotService.revertToSnapshot(getVmSnapShotId());
|
||||
if (result != null) {
|
||||
UserVmResponse response = _responseGenerator.createUserVmResponse(
|
||||
"virtualmachine", result).get(0);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,"Failed to revert VM snapshot");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventDescription() {
|
||||
return "Revert from VM snapshot: " + getVmSnapShotId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType() {
|
||||
return EventTypes.EVENT_VM_SNAPSHOT_REVERT;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
// 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.api.response;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseResponse;
|
||||
import org.apache.cloudstack.api.EntityReference;
|
||||
|
||||
import com.cloud.serializer.Param;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
@EntityReference(value=VMSnapshot.class)
|
||||
public class VMSnapshotResponse extends BaseResponse implements ControlledEntityResponse{
|
||||
|
||||
@SerializedName(ApiConstants.ID)
|
||||
@Param(description = "the ID of the vm snapshot")
|
||||
private String id;
|
||||
|
||||
@SerializedName(ApiConstants.NAME)
|
||||
@Param(description = "the name of the vm snapshot")
|
||||
private String name;
|
||||
|
||||
@SerializedName(ApiConstants.STATE)
|
||||
@Param(description = "the state of the vm snapshot")
|
||||
private VMSnapshot.State state;
|
||||
|
||||
@SerializedName(ApiConstants.DESCRIPTION)
|
||||
@Param(description = "the description of the vm snapshot")
|
||||
private String description;
|
||||
|
||||
@SerializedName(ApiConstants.DISPLAY_NAME)
|
||||
@Param(description = "the display name of the vm snapshot")
|
||||
private String displayName;
|
||||
|
||||
@SerializedName(ApiConstants.ZONE_ID)
|
||||
@Param(description = "the Zone ID of the vm snapshot")
|
||||
private String zoneId;
|
||||
|
||||
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
|
||||
@Param(description = "the vm ID of the vm snapshot")
|
||||
private String virtualMachineid;
|
||||
|
||||
@SerializedName("parent")
|
||||
@Param(description = "the parent ID of the vm snapshot")
|
||||
private String parent;
|
||||
|
||||
@SerializedName("parentName")
|
||||
@Param(description = "the parent displayName of the vm snapshot")
|
||||
private String parentName;
|
||||
|
||||
@SerializedName("current")
|
||||
@Param(description = "indiates if this is current snapshot")
|
||||
private Boolean current;
|
||||
|
||||
@SerializedName("type")
|
||||
@Param(description = "VM Snapshot type")
|
||||
private String type;
|
||||
|
||||
@SerializedName(ApiConstants.CREATED)
|
||||
@Param(description = "the create date of the vm snapshot")
|
||||
private Date created;
|
||||
|
||||
@SerializedName(ApiConstants.ACCOUNT)
|
||||
@Param(description = "the account associated with the disk volume")
|
||||
private String accountName;
|
||||
|
||||
@SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id of the vpn")
|
||||
private String projectId;
|
||||
|
||||
@SerializedName(ApiConstants.PROJECT) @Param(description="the project name of the vpn")
|
||||
private String projectName;
|
||||
|
||||
@SerializedName(ApiConstants.DOMAIN_ID)
|
||||
@Param(description = "the ID of the domain associated with the disk volume")
|
||||
private String domainId;
|
||||
|
||||
@SerializedName(ApiConstants.DOMAIN)
|
||||
@Param(description = "the domain associated with the disk volume")
|
||||
private String domainName;
|
||||
|
||||
@Override
|
||||
public String getObjectId() {
|
||||
return getId();
|
||||
}
|
||||
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getZoneId() {
|
||||
return zoneId;
|
||||
}
|
||||
|
||||
public void setZoneId(String zoneId) {
|
||||
this.zoneId = zoneId;
|
||||
}
|
||||
|
||||
public String getVirtualMachineid() {
|
||||
return virtualMachineid;
|
||||
}
|
||||
|
||||
public void setVirtualMachineid(String virtualMachineid) {
|
||||
this.virtualMachineid = virtualMachineid;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setState(VMSnapshot.State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public VMSnapshot.State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public Boolean getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public void setCurrent(Boolean current) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
public void setParentName(String parentName) {
|
||||
this.parentName = parentName;
|
||||
}
|
||||
|
||||
public String getParentName() {
|
||||
return parentName;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAccountName(String accountName) {
|
||||
this.accountName = accountName;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProjectId(String projectId) {
|
||||
this.projectId = projectId;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProjectName(String projectName) {
|
||||
this.projectName = projectName;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDomainId(String domainId) {
|
||||
this.domainId = domainId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDomainName(String domainName) {
|
||||
this.domainName = domainName;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1410,6 +1410,20 @@ label.zone.step.4.title=Step 4: <strong>Add an IP range</strong>
|
|||
label.zone.wide=Zone-Wide
|
||||
label.zone=Zone
|
||||
|
||||
#VM snapshot label
|
||||
label.vmsnapshot=VM Snapshots
|
||||
label.vmsnapshot.type=Type
|
||||
label.vmsnapshot.parentname=Parent
|
||||
label.vmsnapshot.current=isCurrent
|
||||
label.vmsnapshot.memory=Snapshot memory
|
||||
message.action.vmsnapshot.delete=Please confirm that you want to delete this VM snapshot.
|
||||
label.action.vmsnapshot.delete=Delete VM snapshot
|
||||
label.action.vmsnapshot.revert=Revert to VM snapshot
|
||||
message.action.vmsnapshot.revert=Revert VM snapshot
|
||||
label.action.vmsnapshot.create=Take VM Snapshot
|
||||
|
||||
|
||||
|
||||
#Messages
|
||||
message.acquire.public.ip=Please select a zone from which you want to acquire your new IP from.
|
||||
message.action.cancel.maintenance.mode=Please confirm that you want to cancel this maintenance.
|
||||
|
|
|
|||
|
|
@ -537,3 +537,9 @@ addRegion=1
|
|||
updateRegion=1
|
||||
removeRegion=1
|
||||
listRegions=15
|
||||
|
||||
### VM Snapshot commands
|
||||
listVMSnapshot=15
|
||||
createVMSnapshot=15
|
||||
deleteVMSnapshot=15
|
||||
revertToSnapshot=15
|
||||
|
|
|
|||
|
|
@ -20,15 +20,21 @@ import com.cloud.agent.api.Answer;
|
|||
import com.cloud.agent.api.BackupSnapshotCommand;
|
||||
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
|
||||
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
|
||||
import com.cloud.agent.api.CreateVMSnapshotCommand;
|
||||
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
|
||||
import com.cloud.agent.api.DeleteVMSnapshotCommand;
|
||||
import com.cloud.agent.api.RevertToVMSnapshotCommand;
|
||||
import com.cloud.agent.api.storage.CopyVolumeCommand;
|
||||
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
|
||||
|
||||
public interface VmwareStorageManager {
|
||||
Answer execute(VmwareHostService hostService, PrimaryStorageDownloadCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, CreateVMSnapshotCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, DeleteVMSnapshotCommand cmd);
|
||||
Answer execute(VmwareHostService hostService, RevertToVMSnapshotCommand cmd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.io.FileOutputStream;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -32,18 +33,27 @@ import com.cloud.agent.api.BackupSnapshotAnswer;
|
|||
import com.cloud.agent.api.BackupSnapshotCommand;
|
||||
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
|
||||
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
|
||||
import com.cloud.agent.api.CreateVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.CreateVMSnapshotCommand;
|
||||
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
|
||||
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
|
||||
import com.cloud.agent.api.DeleteVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.DeleteVMSnapshotCommand;
|
||||
import com.cloud.agent.api.RevertToVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.RevertToVMSnapshotCommand;
|
||||
import com.cloud.agent.api.storage.CopyVolumeAnswer;
|
||||
import com.cloud.agent.api.storage.CopyVolumeCommand;
|
||||
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
|
||||
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
|
||||
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
|
||||
import com.cloud.agent.api.to.StorageFilerTO;
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.hypervisor.vmware.mo.CustomFieldConstants;
|
||||
import com.cloud.hypervisor.vmware.mo.DatacenterMO;
|
||||
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
|
||||
import com.cloud.hypervisor.vmware.mo.HostMO;
|
||||
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
|
||||
import com.cloud.hypervisor.vmware.mo.TaskMO;
|
||||
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
||||
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
|
||||
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
||||
|
|
@ -57,7 +67,11 @@ import com.cloud.utils.Pair;
|
|||
import com.cloud.utils.StringUtils;
|
||||
import com.cloud.utils.Ternary;
|
||||
import com.cloud.utils.script.Script;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.vmware.vim25.ManagedObjectReference;
|
||||
import com.vmware.vim25.TaskEvent;
|
||||
import com.vmware.vim25.TaskInfo;
|
||||
import com.vmware.vim25.VirtualDeviceConfigSpec;
|
||||
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
|
||||
import com.vmware.vim25.VirtualDisk;
|
||||
|
|
@ -222,8 +236,12 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
|||
}
|
||||
|
||||
} finally {
|
||||
if(vmMo != null)
|
||||
vmMo.removeAllSnapshots();
|
||||
if(vmMo != null){
|
||||
ManagedObjectReference snapshotMor = vmMo.getSnapshotMor(snapshotUuid);
|
||||
if (snapshotMor != null){
|
||||
vmMo.removeSnapshot(snapshotUuid, false);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (workerVm != null) {
|
||||
|
|
@ -377,47 +395,47 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd) {
|
||||
public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd) {
|
||||
|
||||
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
|
||||
Long accountId = cmd.getAccountId();
|
||||
Long volumeId = cmd.getVolumeId();
|
||||
String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
|
||||
String backedUpSnapshotUuid = cmd.getSnapshotUuid();
|
||||
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
|
||||
Long accountId = cmd.getAccountId();
|
||||
Long volumeId = cmd.getVolumeId();
|
||||
String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
|
||||
String backedUpSnapshotUuid = cmd.getSnapshotUuid();
|
||||
|
||||
String details = null;
|
||||
boolean success = false;
|
||||
String newVolumeName = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
String details = null;
|
||||
boolean success = false;
|
||||
String newVolumeName = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
|
||||
VmwareContext context = hostService.getServiceContext(cmd);
|
||||
try {
|
||||
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
|
||||
|
||||
ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStorageNameLabel);
|
||||
if (morPrimaryDs == null) {
|
||||
String msg = "Unable to find datastore: " + primaryStorageNameLabel;
|
||||
s_logger.error(msg);
|
||||
throw new Exception(msg);
|
||||
}
|
||||
VmwareContext context = hostService.getServiceContext(cmd);
|
||||
try {
|
||||
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
|
||||
ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost,
|
||||
primaryStorageNameLabel);
|
||||
if (morPrimaryDs == null) {
|
||||
String msg = "Unable to find datastore: " + primaryStorageNameLabel;
|
||||
s_logger.error(msg);
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs);
|
||||
details = createVolumeFromSnapshot(hyperHost, primaryDsMo,
|
||||
newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid);
|
||||
if (details == null) {
|
||||
success = true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof RemoteException) {
|
||||
hostService.invalidateServiceContext(context);
|
||||
}
|
||||
DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs);
|
||||
details = createVolumeFromSnapshot(hyperHost, primaryDsMo,
|
||||
newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid);
|
||||
if (details == null) {
|
||||
success = true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof RemoteException) {
|
||||
hostService.invalidateServiceContext(context);
|
||||
}
|
||||
|
||||
s_logger.error("Unexpecpted exception ", e);
|
||||
details = "CreateVolumeFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
|
||||
}
|
||||
|
||||
s_logger.error("Unexpecpted exception ", e);
|
||||
details = "CreateVolumeFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
|
||||
}
|
||||
return new CreateVolumeFromSnapshotAnswer(cmd, success, details, newVolumeName);
|
||||
}
|
||||
|
||||
return new CreateVolumeFromSnapshotAnswer(cmd, success, details, newVolumeName);
|
||||
}
|
||||
|
||||
// templateName: name in secondary storage
|
||||
// templateUuid: will be used at hypervisor layer
|
||||
private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl,
|
||||
|
|
@ -881,4 +899,244 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
|||
private static String getSnapshotRelativeDirInSecStorage(long accountId, long volumeId) {
|
||||
return "snapshots/" + accountId + "/" + volumeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateVMSnapshotAnswer execute(VmwareHostService hostService, CreateVMSnapshotCommand cmd) {
|
||||
List<VolumeTO> volumeTOs = cmd.getVolumeTOs();
|
||||
String vmName = cmd.getVmName();
|
||||
String vmSnapshotName = cmd.getTarget().getSnapshotName();
|
||||
String vmSnapshotDesc = cmd.getTarget().getDescription();
|
||||
boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory;
|
||||
VirtualMachineMO vmMo = null;
|
||||
VmwareContext context = hostService.getServiceContext(cmd);
|
||||
Map<String, String> mapNewDisk = new HashMap<String, String>();
|
||||
try {
|
||||
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
|
||||
|
||||
// wait if there are already VM snapshot task running
|
||||
ManagedObjectReference taskmgr = context.getServiceContent().getTaskManager();
|
||||
ManagedObjectReference[] tasks = (ManagedObjectReference[]) context.getServiceUtil().getDynamicProperty(taskmgr, "recentTask");
|
||||
for (ManagedObjectReference taskMor : tasks) {
|
||||
TaskInfo info = (TaskInfo) (context.getServiceUtil().getDynamicProperty(taskMor, "info"));
|
||||
if(info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("CreateSnapshot_Task")){
|
||||
s_logger.debug("There is already a VM snapshot task running, wait for it");
|
||||
context.getServiceUtil().waitForTask(taskMor);
|
||||
}
|
||||
}
|
||||
|
||||
vmMo = hyperHost.findVmOnHyperHost(vmName);
|
||||
if(vmMo == null)
|
||||
vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
|
||||
if (vmMo == null) {
|
||||
String msg = "Unable to find VM for CreateVMSnapshotCommand";
|
||||
s_logger.debug(msg);
|
||||
return new CreateVMSnapshotAnswer(cmd, false, msg);
|
||||
} else {
|
||||
if (vmMo.getSnapshotMor(vmSnapshotName) != null){
|
||||
s_logger.debug("VM snapshot " + vmSnapshotName + " already exists");
|
||||
}else if (!vmMo.createSnapshot(vmSnapshotName, vmSnapshotDesc, snapshotMemory, true)) {
|
||||
return new CreateVMSnapshotAnswer(cmd, false,
|
||||
"Unable to create snapshot due to esxi internal failed");
|
||||
}
|
||||
// find VM disk file path after creating snapshot
|
||||
VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
|
||||
for (int i = 0; i < vdisks.length; i ++){
|
||||
@SuppressWarnings("deprecation")
|
||||
List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i], false);
|
||||
for(Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
|
||||
String vmdkName = fileItem.first().split(" ")[1];
|
||||
if ( vmdkName.endsWith(".vmdk")){
|
||||
vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length());
|
||||
}
|
||||
String[] s = vmdkName.split("-");
|
||||
mapNewDisk.put(s[0], vmdkName);
|
||||
}
|
||||
}
|
||||
|
||||
// update volume path using maps
|
||||
for (VolumeTO volumeTO : volumeTOs) {
|
||||
String parentUUID = volumeTO.getPath();
|
||||
String[] s = parentUUID.split("-");
|
||||
String key = s[0];
|
||||
volumeTO.setPath(mapNewDisk.get(key));
|
||||
}
|
||||
return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), volumeTOs);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = e.getMessage();
|
||||
s_logger.error("failed to create snapshot for vm:" + vmName + " due to " + msg);
|
||||
try {
|
||||
if (vmMo.getSnapshotMor(vmSnapshotName) != null) {
|
||||
vmMo.removeSnapshot(vmSnapshotName, false);
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
}
|
||||
return new CreateVMSnapshotAnswer(cmd, false, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteVMSnapshotAnswer execute(VmwareHostService hostService, DeleteVMSnapshotCommand cmd) {
|
||||
List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
|
||||
VirtualMachineMO vmMo = null;
|
||||
VmwareContext context = hostService.getServiceContext(cmd);
|
||||
Map<String, String> mapNewDisk = new HashMap<String, String>();
|
||||
String vmName = cmd.getVmName();
|
||||
String vmSnapshotName = cmd.getTarget().getSnapshotName();
|
||||
try {
|
||||
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
|
||||
vmMo = hyperHost.findVmOnHyperHost(vmName);
|
||||
if(vmMo == null)
|
||||
vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
|
||||
if (vmMo == null) {
|
||||
String msg = "Unable to find VM for RevertToVMSnapshotCommand";
|
||||
s_logger.debug(msg);
|
||||
return new DeleteVMSnapshotAnswer(cmd, false, msg);
|
||||
} else {
|
||||
if (vmMo.getSnapshotMor(vmSnapshotName) == null) {
|
||||
s_logger.debug("can not find the snapshot " + vmSnapshotName + ", assume it is already removed");
|
||||
} else {
|
||||
if (!vmMo.removeSnapshot(vmSnapshotName, false)) {
|
||||
String msg = "delete vm snapshot " + vmSnapshotName + " due to error occured in vmware";
|
||||
s_logger.error(msg);
|
||||
return new DeleteVMSnapshotAnswer(cmd, false, msg);
|
||||
}
|
||||
}
|
||||
s_logger.debug("snapshot: " + vmSnapshotName + " is removed");
|
||||
// after removed snapshot, the volumes' paths have been changed for the VM, needs to report new paths to manager
|
||||
VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
|
||||
for (int i = 0; i < vdisks.length; i++) {
|
||||
@SuppressWarnings("deprecation")
|
||||
List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i], false);
|
||||
for (Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
|
||||
String vmdkName = fileItem.first().split(" ")[1];
|
||||
if (vmdkName.endsWith(".vmdk")) {
|
||||
vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length());
|
||||
}
|
||||
String[] s = vmdkName.split("-");
|
||||
mapNewDisk.put(s[0], vmdkName);
|
||||
}
|
||||
}
|
||||
for (VolumeTO volumeTo : listVolumeTo) {
|
||||
String key = null;
|
||||
String parentUUID = volumeTo.getPath();
|
||||
String[] s = parentUUID.split("-");
|
||||
key = s[0];
|
||||
volumeTo.setPath(mapNewDisk.get(key));
|
||||
}
|
||||
return new DeleteVMSnapshotAnswer(cmd, listVolumeTo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = e.getMessage();
|
||||
s_logger.error("failed to delete vm snapshot " + vmSnapshotName + " of vm " + vmName + " due to " + msg);
|
||||
return new DeleteVMSnapshotAnswer(cmd, false, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToVMSnapshotCommand cmd) {
|
||||
String snapshotName = cmd.getTarget().getSnapshotName();
|
||||
String vmName = cmd.getVmName();
|
||||
Boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory;
|
||||
List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
|
||||
VirtualMachine.State vmState = VirtualMachine.State.Running;
|
||||
VirtualMachineMO vmMo = null;
|
||||
VmwareContext context = hostService.getServiceContext(cmd);
|
||||
Map<String, String> mapNewDisk = new HashMap<String, String>();
|
||||
try {
|
||||
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
|
||||
|
||||
// wait if there are already VM revert task running
|
||||
ManagedObjectReference taskmgr = context.getServiceContent().getTaskManager();
|
||||
ManagedObjectReference[] tasks = (ManagedObjectReference[]) context.getServiceUtil().getDynamicProperty(taskmgr, "recentTask");
|
||||
for (ManagedObjectReference taskMor : tasks) {
|
||||
TaskInfo info = (TaskInfo) (context.getServiceUtil().getDynamicProperty(taskMor, "info"));
|
||||
if(info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("RevertToSnapshot_Task")){
|
||||
s_logger.debug("There is already a VM snapshot task running, wait for it");
|
||||
context.getServiceUtil().waitForTask(taskMor);
|
||||
}
|
||||
}
|
||||
|
||||
HostMO hostMo = (HostMO) hyperHost;
|
||||
vmMo = hyperHost.findVmOnHyperHost(vmName);
|
||||
if(vmMo == null)
|
||||
vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
|
||||
if (vmMo == null) {
|
||||
String msg = "Unable to find VM for RevertToVMSnapshotCommand";
|
||||
s_logger.debug(msg);
|
||||
return new RevertToVMSnapshotAnswer(cmd, false, msg);
|
||||
} else {
|
||||
boolean result = false;
|
||||
if (snapshotName != null) {
|
||||
ManagedObjectReference morSnapshot = vmMo.getSnapshotMor(snapshotName);
|
||||
result = hostMo.revertToSnapshot(morSnapshot);
|
||||
} else {
|
||||
return new RevertToVMSnapshotAnswer(cmd, false, "Unable to find the snapshot by name " + snapshotName);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
|
||||
// build a map<volumeName, vmdk>
|
||||
for (int i = 0; i < vdisks.length; i++) {
|
||||
@SuppressWarnings("deprecation")
|
||||
List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo.getDiskDatastorePathChain(
|
||||
vdisks[i], false);
|
||||
for (Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
|
||||
String vmdkName = fileItem.first().split(" ")[1];
|
||||
if (vmdkName.endsWith(".vmdk")) {
|
||||
vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length());
|
||||
}
|
||||
String[] s = vmdkName.split("-");
|
||||
mapNewDisk.put(s[0], vmdkName);
|
||||
}
|
||||
}
|
||||
String key = null;
|
||||
for (VolumeTO volumeTo : listVolumeTo) {
|
||||
String parentUUID = volumeTo.getPath();
|
||||
String[] s = parentUUID.split("-");
|
||||
key = s[0];
|
||||
volumeTo.setPath(mapNewDisk.get(key));
|
||||
}
|
||||
if (!snapshotMemory) {
|
||||
vmState = VirtualMachine.State.Stopped;
|
||||
}
|
||||
return new RevertToVMSnapshotAnswer(cmd, listVolumeTo, vmState);
|
||||
} else {
|
||||
return new RevertToVMSnapshotAnswer(cmd, false,
|
||||
"Error while reverting to snapshot due to execute in esxi");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = "revert vm " + vmName + " to snapshot " + snapshotName + " failed due to " + e.getMessage();
|
||||
s_logger.error(msg);
|
||||
return new RevertToVMSnapshotAnswer(cmd, false, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private VirtualMachineMO createWorkingVM(DatastoreMO dsMo, VmwareHypervisorHost hyperHost) throws Exception {
|
||||
String uniqueName = UUID.randomUUID().toString();
|
||||
VirtualMachineMO workingVM = null;
|
||||
VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec();
|
||||
vmConfig.setName(uniqueName);
|
||||
vmConfig.setMemoryMB((long) 4);
|
||||
vmConfig.setNumCPUs(1);
|
||||
vmConfig.setGuestId(VirtualMachineGuestOsIdentifier._otherGuest.toString());
|
||||
VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo();
|
||||
fileInfo.setVmPathName(String.format("[%s]", dsMo.getName()));
|
||||
vmConfig.setFiles(fileInfo);
|
||||
|
||||
VirtualLsiLogicController scsiController = new VirtualLsiLogicController();
|
||||
scsiController.setSharedBus(VirtualSCSISharing.noSharing);
|
||||
scsiController.setBusNumber(0);
|
||||
scsiController.setKey(1);
|
||||
VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec();
|
||||
scsiControllerSpec.setDevice(scsiController);
|
||||
scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.add);
|
||||
|
||||
vmConfig.setDeviceChange(new VirtualDeviceConfigSpec[] { scsiControllerSpec });
|
||||
hyperHost.createVm(vmConfig);
|
||||
workingVM = hyperHost.findVmOnHyperHost(uniqueName);
|
||||
return workingVM;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,9 +65,13 @@ import com.cloud.agent.api.Command;
|
|||
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
|
||||
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
|
||||
import com.cloud.agent.api.CreateStoragePoolCommand;
|
||||
import com.cloud.agent.api.CreateVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.CreateVMSnapshotCommand;
|
||||
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
|
||||
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
|
||||
import com.cloud.agent.api.DeleteStoragePoolCommand;
|
||||
import com.cloud.agent.api.DeleteVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.DeleteVMSnapshotCommand;
|
||||
import com.cloud.agent.api.GetDomRVersionAnswer;
|
||||
import com.cloud.agent.api.GetDomRVersionCmd;
|
||||
import com.cloud.agent.api.GetHostStatsAnswer;
|
||||
|
|
@ -103,6 +107,8 @@ import com.cloud.agent.api.ReadyCommand;
|
|||
import com.cloud.agent.api.RebootAnswer;
|
||||
import com.cloud.agent.api.RebootCommand;
|
||||
import com.cloud.agent.api.RebootRouterCommand;
|
||||
import com.cloud.agent.api.RevertToVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.RevertToVMSnapshotCommand;
|
||||
import com.cloud.agent.api.SetupAnswer;
|
||||
import com.cloud.agent.api.SetupCommand;
|
||||
import com.cloud.agent.api.SetupGuestNetworkAnswer;
|
||||
|
|
@ -445,7 +451,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
answer = execute((SetSourceNatCommand) cmd);
|
||||
} else if (clz == SetNetworkACLCommand.class) {
|
||||
answer = execute((SetNetworkACLCommand) cmd);
|
||||
} else if (clz == SetPortForwardingRulesVpcCommand.class) {
|
||||
} else if (cmd instanceof CreateVMSnapshotCommand) {
|
||||
return execute((CreateVMSnapshotCommand)cmd);
|
||||
} else if(cmd instanceof DeleteVMSnapshotCommand){
|
||||
return execute((DeleteVMSnapshotCommand)cmd);
|
||||
} else if(cmd instanceof RevertToVMSnapshotCommand){
|
||||
return execute((RevertToVMSnapshotCommand)cmd);
|
||||
}else if (clz == SetPortForwardingRulesVpcCommand.class) {
|
||||
answer = execute((SetPortForwardingRulesVpcCommand) cmd);
|
||||
} else if (clz == Site2SiteVpnCfgCommand.class) {
|
||||
answer = execute((Site2SiteVpnCfgCommand) cmd);
|
||||
|
|
@ -2799,7 +2811,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
// before we stop VM, remove all possible snapshots on the VM to let
|
||||
// disk chain be collapsed
|
||||
s_logger.info("Remove all snapshot before stopping VM " + cmd.getVmName());
|
||||
vmMo.removeAllSnapshots();
|
||||
if (vmMo.safePowerOff(_shutdown_waitMs)) {
|
||||
state = State.Stopped;
|
||||
return new StopAnswer(cmd, "Stop VM " + cmd.getVmName() + " Succeed", 0, true);
|
||||
|
|
@ -3351,7 +3362,42 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
}
|
||||
}
|
||||
|
||||
protected Answer execute(CreateVMSnapshotCommand cmd) {
|
||||
try {
|
||||
VmwareContext context = getServiceContext();
|
||||
VmwareManager mgr = context
|
||||
.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
|
||||
|
||||
return mgr.getStorageManager().execute(this, cmd);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new CreateVMSnapshotAnswer(cmd, false, "");
|
||||
}
|
||||
}
|
||||
|
||||
protected Answer execute(DeleteVMSnapshotCommand cmd) {
|
||||
try {
|
||||
VmwareContext context = getServiceContext();
|
||||
VmwareManager mgr = context
|
||||
.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
|
||||
|
||||
return mgr.getStorageManager().execute(this, cmd);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new DeleteVMSnapshotAnswer(cmd, false, "");
|
||||
}
|
||||
}
|
||||
|
||||
protected Answer execute(RevertToVMSnapshotCommand cmd){
|
||||
try{
|
||||
VmwareContext context = getServiceContext();
|
||||
VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
|
||||
return mgr.getStorageManager().execute(this, cmd);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
return new RevertToVMSnapshotAnswer(cmd,false,"");
|
||||
}
|
||||
}
|
||||
protected Answer execute(CreateVolumeFromSnapshotCommand cmd) {
|
||||
if (s_logger.isInfoEnabled()) {
|
||||
s_logger.info("Executing resource CreateVolumeFromSnapshotCommand: " + _gson.toJson(cmd));
|
||||
|
|
|
|||
|
|
@ -90,9 +90,13 @@ import com.cloud.agent.api.Command;
|
|||
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
|
||||
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
|
||||
import com.cloud.agent.api.CreateStoragePoolCommand;
|
||||
import com.cloud.agent.api.CreateVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.CreateVMSnapshotCommand;
|
||||
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
|
||||
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
|
||||
import com.cloud.agent.api.DeleteStoragePoolCommand;
|
||||
import com.cloud.agent.api.DeleteVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.DeleteVMSnapshotCommand;
|
||||
import com.cloud.agent.api.GetDomRVersionAnswer;
|
||||
import com.cloud.agent.api.GetDomRVersionCmd;
|
||||
import com.cloud.agent.api.GetHostStatsAnswer;
|
||||
|
|
@ -129,6 +133,8 @@ import com.cloud.agent.api.ReadyCommand;
|
|||
import com.cloud.agent.api.RebootAnswer;
|
||||
import com.cloud.agent.api.RebootCommand;
|
||||
import com.cloud.agent.api.RebootRouterCommand;
|
||||
import com.cloud.agent.api.RevertToVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.RevertToVMSnapshotCommand;
|
||||
import com.cloud.agent.api.SecurityGroupRuleAnswer;
|
||||
import com.cloud.agent.api.SecurityGroupRulesCmd;
|
||||
import com.cloud.agent.api.SetupAnswer;
|
||||
|
|
@ -237,6 +243,7 @@ import com.cloud.utils.net.NetUtils;
|
|||
import com.cloud.vm.DiskProfile;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.trilead.ssh2.SCPClient;
|
||||
import com.xensource.xenapi.Bond;
|
||||
import com.xensource.xenapi.Connection;
|
||||
|
|
@ -256,6 +263,10 @@ import com.xensource.xenapi.Types;
|
|||
import com.xensource.xenapi.Types.BadServerResponse;
|
||||
import com.xensource.xenapi.Types.ConsoleProtocol;
|
||||
import com.xensource.xenapi.Types.IpConfigurationMode;
|
||||
import com.xensource.xenapi.Types.OperationNotAllowed;
|
||||
import com.xensource.xenapi.Types.SrFull;
|
||||
import com.xensource.xenapi.Types.VbdType;
|
||||
import com.xensource.xenapi.Types.VmBadPowerState;
|
||||
import com.xensource.xenapi.Types.VmPowerState;
|
||||
import com.xensource.xenapi.Types.XenAPIException;
|
||||
import com.xensource.xenapi.VBD;
|
||||
|
|
@ -579,11 +590,109 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||
return execute((CheckS2SVpnConnectionsCommand) cmd);
|
||||
} else if (cmd instanceof StorageSubSystemCommand) {
|
||||
return this.storageResource.handleStorageCommands((StorageSubSystemCommand)cmd);
|
||||
} else if (clazz == CreateVMSnapshotCommand.class) {
|
||||
return execute((CreateVMSnapshotCommand)cmd);
|
||||
} else if (clazz == DeleteVMSnapshotCommand.class) {
|
||||
return execute((DeleteVMSnapshotCommand)cmd);
|
||||
} else if (clazz == RevertToVMSnapshotCommand.class) {
|
||||
return execute((RevertToVMSnapshotCommand)cmd);
|
||||
} else {
|
||||
return Answer.createUnsupportedCommandAnswer(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Answer execute(RevertToVMSnapshotCommand cmd) {
|
||||
String vmName = cmd.getVmName();
|
||||
List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
|
||||
VMSnapshot.Type vmSnapshotType = cmd.getTarget().getType();
|
||||
Boolean snapshotMemory = vmSnapshotType == VMSnapshot.Type.DiskAndMemory;
|
||||
Connection conn = getConnection();
|
||||
VirtualMachine.State vmState = null;
|
||||
VM vm = null;
|
||||
try {
|
||||
|
||||
// remove vm from s_vms, for delta sync
|
||||
s_vms.remove(_cluster, _name, vmName);
|
||||
|
||||
Set<VM> vmSnapshots = VM.getByNameLabel(conn, cmd.getTarget().getSnapshotName());
|
||||
if(vmSnapshots.size() == 0)
|
||||
return new RevertToVMSnapshotAnswer(cmd, false, "Cannot find vmSnapshot with name: " + cmd.getTarget().getSnapshotName());
|
||||
|
||||
VM vmSnapshot = vmSnapshots.iterator().next();
|
||||
|
||||
// find target VM or creating a work VM
|
||||
try {
|
||||
vm = getVM(conn, vmName);
|
||||
} catch (Exception e) {
|
||||
vm = createWorkingVM(conn, vmName, cmd.getGuestOSType(), listVolumeTo);
|
||||
}
|
||||
|
||||
if (vm == null) {
|
||||
return new RevertToVMSnapshotAnswer(cmd, false,
|
||||
"Revert to VM Snapshot Failed due to can not find vm: " + vmName);
|
||||
}
|
||||
|
||||
// call plugin to execute revert
|
||||
revertToSnapshot(conn, vmSnapshot, vmName, vm.getUuid(conn), snapshotMemory, _host.uuid);
|
||||
vm = getVM(conn, vmName);
|
||||
Set<VBD> vbds = vm.getVBDs(conn);
|
||||
Map<String, VDI> vdiMap = new HashMap<String, VDI>();
|
||||
// get vdi:vbdr to a map
|
||||
for (VBD vbd : vbds) {
|
||||
VBD.Record vbdr = vbd.getRecord(conn);
|
||||
if (vbdr.type == Types.VbdType.DISK) {
|
||||
VDI vdi = vbdr.VDI;
|
||||
vdiMap.put(vbdr.userdevice, vdi);
|
||||
}
|
||||
}
|
||||
|
||||
if (!snapshotMemory) {
|
||||
vm.destroy(conn);
|
||||
vmState = VirtualMachine.State.Stopped;
|
||||
} else {
|
||||
s_vms.put(_cluster, _name, vmName, State.Running);
|
||||
vmState = VirtualMachine.State.Running;
|
||||
}
|
||||
|
||||
// after revert, VM's volumes path have been changed, need to report to manager
|
||||
for (VolumeTO volumeTo : listVolumeTo) {
|
||||
Long deviceId = volumeTo.getDeviceId();
|
||||
VDI vdi = vdiMap.get(deviceId.toString());
|
||||
volumeTo.setPath(vdi.getUuid(conn));
|
||||
}
|
||||
|
||||
return new RevertToVMSnapshotAnswer(cmd, listVolumeTo,vmState);
|
||||
} catch (Exception e) {
|
||||
s_logger.error("revert vm " + vmName
|
||||
+ " to snapshot " + cmd.getTarget().getSnapshotName() + " failed due to " + e.getMessage());
|
||||
return new RevertToVMSnapshotAnswer(cmd, false, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String revertToSnapshot(Connection conn, VM vmSnapshot,
|
||||
String vmName, String oldVmUuid, Boolean snapshotMemory, String hostUUID)
|
||||
throws XenAPIException, XmlRpcException {
|
||||
|
||||
String results = callHostPluginAsync(conn, "vmopsSnapshot",
|
||||
"revert_memory_snapshot", 10 * 60 * 1000, "snapshotUUID",
|
||||
vmSnapshot.getUuid(conn), "vmName", vmName, "oldVmUuid",
|
||||
oldVmUuid, "snapshotMemory", snapshotMemory.toString(), "hostUUID", hostUUID);
|
||||
String errMsg = null;
|
||||
if (results == null || results.isEmpty()) {
|
||||
errMsg = "revert_memory_snapshot return null";
|
||||
} else {
|
||||
if (results.equals("0")) {
|
||||
return results;
|
||||
} else {
|
||||
errMsg = "revert_memory_snapshot exception";
|
||||
}
|
||||
}
|
||||
s_logger.warn(errMsg);
|
||||
throw new CloudRuntimeException(errMsg);
|
||||
}
|
||||
|
||||
protected XsLocalNetwork getNativeNetworkForTraffic(Connection conn, TrafficType type, String name) throws XenAPIException, XmlRpcException {
|
||||
if (name != null) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
|
|
@ -6167,6 +6276,199 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||
|
||||
}
|
||||
|
||||
protected Answer execute(final CreateVMSnapshotCommand cmd) {
|
||||
String vmName = cmd.getVmName();
|
||||
String vmSnapshotName = cmd.getTarget().getSnapshotName();
|
||||
List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
|
||||
VirtualMachine.State vmState = cmd.getVmState();
|
||||
String guestOSType = cmd.getGuestOSType();
|
||||
|
||||
boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory;
|
||||
long timeout = 600;
|
||||
|
||||
Connection conn = getConnection();
|
||||
VM vm = null;
|
||||
VM vmSnapshot = null;
|
||||
boolean success = false;
|
||||
|
||||
try {
|
||||
// check if VM snapshot already exists
|
||||
Set<VM> vmSnapshots = VM.getByNameLabel(conn, cmd.getTarget().getSnapshotName());
|
||||
if(vmSnapshots.size() > 0)
|
||||
return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs());
|
||||
|
||||
// check if there is already a task for this VM snapshot
|
||||
Task task = null;
|
||||
Set<Task> tasks = Task.getByNameLabel(conn, "Async.VM.snapshot");
|
||||
tasks.addAll(Task.getByNameLabel(conn, "Async.VM.checkpoint"));
|
||||
for (Task taskItem : tasks) {
|
||||
if(taskItem.getOtherConfig(conn).containsKey("CS_VM_SNAPSHOT_KEY")){
|
||||
String vmSnapshotTaskName = taskItem.getOtherConfig(conn).get("CS_VM_SNAPSHOT_KEY");
|
||||
if(vmSnapshotTaskName != null && vmSnapshotTaskName.equals(cmd.getTarget().getSnapshotName())){
|
||||
task = taskItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create a new task if there is no existing task for this VM snapshot
|
||||
if(task == null){
|
||||
try {
|
||||
vm = getVM(conn, vmName);
|
||||
} catch (Exception e) {
|
||||
if (!snapshotMemory) {
|
||||
vm = createWorkingVM(conn, vmName, guestOSType, listVolumeTo);
|
||||
}
|
||||
}
|
||||
|
||||
if (vm == null) {
|
||||
return new CreateVMSnapshotAnswer(cmd, false,
|
||||
"Creating VM Snapshot Failed due to can not find vm: "
|
||||
+ vmName);
|
||||
}
|
||||
|
||||
// call Xenserver API
|
||||
if (!snapshotMemory) {
|
||||
task = vm.snapshotAsync(conn, vmSnapshotName);
|
||||
} else {
|
||||
Set<VBD> vbds = vm.getVBDs(conn);
|
||||
Pool pool = Pool.getByUuid(conn, _host.pool);
|
||||
for (VBD vbd: vbds){
|
||||
VBD.Record vbdr = vbd.getRecord(conn);
|
||||
if (vbdr.userdevice.equals("0")){
|
||||
VDI vdi = vbdr.VDI;
|
||||
SR sr = vdi.getSR(conn);
|
||||
// store memory image on the same SR with ROOT volume
|
||||
pool.setSuspendImageSR(conn, sr);
|
||||
}
|
||||
}
|
||||
task = vm.checkpointAsync(conn, vmSnapshotName);
|
||||
}
|
||||
task.addToOtherConfig(conn, "CS_VM_SNAPSHOT_KEY", vmSnapshotName);
|
||||
}
|
||||
|
||||
waitForTask(conn, task, 1000, timeout * 1000);
|
||||
checkForSuccess(conn, task);
|
||||
String result = task.getResult(conn);
|
||||
|
||||
// extract VM snapshot ref from result
|
||||
String ref = result.substring("<value>".length(), result.length() - "</value>".length());
|
||||
vmSnapshot = Types.toVM(ref);
|
||||
|
||||
success = true;
|
||||
return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs());
|
||||
} catch (Exception e) {
|
||||
String msg = e.getMessage();
|
||||
s_logger.error("Creating VM Snapshot " + cmd.getTarget().getSnapshotName() + " failed due to: " + msg);
|
||||
return new CreateVMSnapshotAnswer(cmd, false, msg);
|
||||
} finally {
|
||||
try {
|
||||
if (!success) {
|
||||
if (vmSnapshot != null) {
|
||||
s_logger.debug("Delete exsisting VM Snapshot "
|
||||
+ vmSnapshotName
|
||||
+ " after making VolumeTO failed");
|
||||
Set<VBD> vbds = vmSnapshot.getVBDs(conn);
|
||||
for (VBD vbd : vbds) {
|
||||
VBD.Record vbdr = vbd.getRecord(conn);
|
||||
if (vbdr.type == VbdType.DISK) {
|
||||
VDI vdi = vbdr.VDI;
|
||||
vdi.destroy(conn);
|
||||
}
|
||||
}
|
||||
vmSnapshot.destroy(conn);
|
||||
}
|
||||
}
|
||||
if (vmState == VirtualMachine.State.Stopped) {
|
||||
if (vm != null) {
|
||||
vm.destroy(conn);
|
||||
}
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
s_logger.error("delete snapshot error due to "
|
||||
+ e2.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private VM createWorkingVM(Connection conn, String vmName,
|
||||
String guestOSType, List<VolumeTO> listVolumeTo)
|
||||
throws BadServerResponse, VmBadPowerState, SrFull,
|
||||
OperationNotAllowed, XenAPIException, XmlRpcException {
|
||||
String guestOsTypeName = getGuestOsType(guestOSType, false);
|
||||
if (guestOsTypeName == null) {
|
||||
String msg = " Hypervisor " + this.getClass().getName()
|
||||
+ " doesn't support guest OS type " + guestOSType
|
||||
+ ". you can choose 'Other install media' to run it as HVM";
|
||||
s_logger.warn(msg);
|
||||
throw new CloudRuntimeException(msg);
|
||||
}
|
||||
VM template = getVM(conn, guestOsTypeName);
|
||||
VM vm = template.createClone(conn, vmName);
|
||||
vm.setIsATemplate(conn, false);
|
||||
Map<VDI, VolumeTO> vdiMap = new HashMap<VDI, VolumeTO>();
|
||||
for (VolumeTO volume : listVolumeTo) {
|
||||
String vdiUuid = volume.getPath();
|
||||
try {
|
||||
VDI vdi = VDI.getByUuid(conn, vdiUuid);
|
||||
vdiMap.put(vdi, volume);
|
||||
} catch (Types.UuidInvalid e) {
|
||||
s_logger.warn("Unable to find vdi by uuid: " + vdiUuid
|
||||
+ ", skip it");
|
||||
}
|
||||
}
|
||||
for (VDI vdi : vdiMap.keySet()) {
|
||||
VolumeTO volumeTO = vdiMap.get(vdi);
|
||||
VBD.Record vbdr = new VBD.Record();
|
||||
vbdr.VM = vm;
|
||||
vbdr.VDI = vdi;
|
||||
if (volumeTO.getType() == Volume.Type.ROOT) {
|
||||
vbdr.bootable = true;
|
||||
vbdr.unpluggable = false;
|
||||
} else {
|
||||
vbdr.bootable = false;
|
||||
vbdr.unpluggable = true;
|
||||
}
|
||||
vbdr.userdevice = new Long(volumeTO.getDeviceId()).toString();
|
||||
vbdr.mode = Types.VbdMode.RW;
|
||||
vbdr.type = Types.VbdType.DISK;
|
||||
VBD.create(conn, vbdr);
|
||||
}
|
||||
return vm;
|
||||
}
|
||||
|
||||
protected Answer execute(final DeleteVMSnapshotCommand cmd) {
|
||||
String snapshotName = cmd.getTarget().getSnapshotName();
|
||||
Connection conn = getConnection();
|
||||
|
||||
try {
|
||||
List<VDI> vdiList = new ArrayList<VDI>();
|
||||
Set<VM> snapshots = VM.getByNameLabel(conn, snapshotName);
|
||||
if(snapshots.size() == 0){
|
||||
s_logger.warn("VM snapshot with name " + snapshotName + " does not exist, assume it is already deleted");
|
||||
return new DeleteVMSnapshotAnswer(cmd, cmd.getVolumeTOs());
|
||||
}
|
||||
VM snapshot = snapshots.iterator().next();
|
||||
Set<VBD> vbds = snapshot.getVBDs(conn);
|
||||
for (VBD vbd : vbds) {
|
||||
if (vbd.getType(conn) == VbdType.DISK) {
|
||||
VDI vdi = vbd.getVDI(conn);
|
||||
vdiList.add(vdi);
|
||||
}
|
||||
}
|
||||
if(cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory)
|
||||
vdiList.add(snapshot.getSuspendVDI(conn));
|
||||
snapshot.destroy(conn);
|
||||
for (VDI vdi : vdiList) {
|
||||
vdi.destroy(conn);
|
||||
}
|
||||
return new DeleteVMSnapshotAnswer(cmd, cmd.getVolumeTOs());
|
||||
} catch (Exception e) {
|
||||
s_logger.warn("Catch Exception: " + e.getClass().toString()
|
||||
+ " due to " + e.toString(), e);
|
||||
return new DeleteVMSnapshotAnswer(cmd, false, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected Answer execute(final AttachIsoCommand cmd) {
|
||||
Connection conn = getConnection();
|
||||
boolean attach = cmd.isAttach();
|
||||
|
|
|
|||
|
|
@ -556,6 +556,33 @@ def deleteSnapshotBackup(session, args):
|
|||
|
||||
return "1"
|
||||
|
||||
if __name__ == "__main__":
|
||||
XenAPIPlugin.dispatch({"getVhdParent":getVhdParent, "create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "unmountSnapshotsDir": unmountSnapshotsDir})
|
||||
@echo
|
||||
def revert_memory_snapshot(session, args):
|
||||
util.SMlog("Calling revert_memory_snapshot with " + str(args))
|
||||
vmName = args['vmName']
|
||||
snapshotUUID = args['snapshotUUID']
|
||||
oldVmUuid = args['oldVmUuid']
|
||||
snapshotMemory = args['snapshotMemory']
|
||||
hostUUID = args['hostUUID']
|
||||
try:
|
||||
cmd = '''xe vbd-list vm-uuid=%s | grep 'vdi-uuid' | grep -v 'not in database' | sed -e 's/vdi-uuid ( RO)://g' ''' % oldVmUuid
|
||||
vdiUuids = os.popen(cmd).read().split()
|
||||
cmd2 = '''xe vm-param-get param-name=power-state uuid=''' + oldVmUuid
|
||||
if os.popen(cmd2).read().split()[0] != 'halted':
|
||||
os.system("xe vm-shutdown force=true vm=" + vmName)
|
||||
os.system("xe vm-destroy uuid=" + oldVmUuid)
|
||||
os.system("xe snapshot-revert snapshot-uuid=" + snapshotUUID)
|
||||
if snapshotMemory == 'true':
|
||||
os.system("xe vm-resume vm=" + vmName + " on=" + hostUUID)
|
||||
for vdiUuid in vdiUuids:
|
||||
os.system("xe vdi-destroy uuid=" + vdiUuid)
|
||||
except OSError, (errno, strerror):
|
||||
errMsg = "OSError while reverting vm " + vmName + " to snapshot " + snapshotUUID + " with errno: " + str(errno) + " and strerr: " + strerror
|
||||
util.SMlog(errMsg)
|
||||
raise xs_errors.XenError(errMsg)
|
||||
return "0"
|
||||
|
||||
if __name__ == "__main__":
|
||||
XenAPIPlugin.dispatch({"getVhdParent":getVhdParent, "create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "unmountSnapshotsDir": unmountSnapshotsDir, "revert_memory_snapshot":revert_memory_snapshot})
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -209,6 +209,8 @@ import com.cloud.vm.dao.DomainRouterDao;
|
|||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
@Component
|
||||
public class ApiDBUtils {
|
||||
|
|
@ -309,6 +311,7 @@ public class ApiDBUtils {
|
|||
static SnapshotPolicyDao _snapshotPolicyDao;
|
||||
static AsyncJobDao _asyncJobDao;
|
||||
static HostDetailsDao _hostDetailsDao;
|
||||
static VMSnapshotDao _vmSnapshotDao;
|
||||
|
||||
@Inject private ManagementServer ms;
|
||||
@Inject public AsyncJobManager asyncMgr;
|
||||
|
|
@ -407,7 +410,7 @@ public class ApiDBUtils {
|
|||
@Inject private SnapshotPolicyDao snapshotPolicyDao;
|
||||
@Inject private AsyncJobDao asyncJobDao;
|
||||
@Inject private HostDetailsDao hostDetailsDao;
|
||||
|
||||
@Inject private VMSnapshotDao vmSnapshotDao;
|
||||
@PostConstruct
|
||||
void init() {
|
||||
_ms = ms;
|
||||
|
|
@ -505,7 +508,7 @@ public class ApiDBUtils {
|
|||
_snapshotPolicyDao = snapshotPolicyDao;
|
||||
_asyncJobDao = asyncJobDao;
|
||||
_hostDetailsDao = hostDetailsDao;
|
||||
|
||||
_vmSnapshotDao = vmSnapshotDao;
|
||||
// Note: stats collector should already have been initialized by this time, otherwise a null instance is returned
|
||||
_statsCollector = StatsCollector.getInstance();
|
||||
}
|
||||
|
|
@ -1054,6 +1057,11 @@ public class ApiDBUtils {
|
|||
return _networkModel.canUseForDeploy(network);
|
||||
}
|
||||
|
||||
public static VMSnapshot getVMSnapshotById(Long vmSnapshotId) {
|
||||
VMSnapshot vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId);
|
||||
return vmSnapshot;
|
||||
}
|
||||
|
||||
public static String getUuid(String resourceId, TaggedResourceType resourceType) {
|
||||
return _taggedResourceService.getUuid(resourceId, resourceType);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse;
|
|||
import org.apache.cloudstack.api.response.VpcResponse;
|
||||
import org.apache.cloudstack.api.response.VpnUsersResponse;
|
||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||
|
||||
import org.apache.cloudstack.api.response.S3Response;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
|
@ -195,6 +194,13 @@ import org.apache.cloudstack.region.Region;
|
|||
import org.apache.cloudstack.usage.Usage;
|
||||
import org.apache.cloudstack.usage.UsageService;
|
||||
import org.apache.cloudstack.usage.UsageTypes;
|
||||
import com.cloud.vm.VmStats;
|
||||
import com.cloud.vm.dao.UserVmData;
|
||||
import com.cloud.vm.dao.UserVmData.NicData;
|
||||
import com.cloud.vm.dao.UserVmData.SecurityGroupData;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import org.apache.cloudstack.api.ResponseGenerator;
|
||||
import org.apache.cloudstack.api.response.VMSnapshotResponse;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
|
@ -358,6 +364,25 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
return snapshotResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot) {
|
||||
VMSnapshotResponse vmSnapshotResponse = new VMSnapshotResponse();
|
||||
vmSnapshotResponse.setId(vmSnapshot.getUuid());
|
||||
vmSnapshotResponse.setName(vmSnapshot.getName());
|
||||
vmSnapshotResponse.setState(vmSnapshot.getState());
|
||||
vmSnapshotResponse.setCreated(vmSnapshot.getCreated());
|
||||
vmSnapshotResponse.setDescription(vmSnapshot.getDescription());
|
||||
vmSnapshotResponse.setDisplayName(vmSnapshot.getDisplayName());
|
||||
UserVm vm = ApiDBUtils.findUserVmById(vmSnapshot.getVmId());
|
||||
if(vm!=null)
|
||||
vmSnapshotResponse.setVirtualMachineid(vm.getUuid());
|
||||
if(vmSnapshot.getParent() != null)
|
||||
vmSnapshotResponse.setParentName(ApiDBUtils.getVMSnapshotById(vmSnapshot.getParent()).getDisplayName());
|
||||
vmSnapshotResponse.setCurrent(vmSnapshot.getCurrent());
|
||||
vmSnapshotResponse.setType(vmSnapshot.getType().toString());
|
||||
return vmSnapshotResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SnapshotPolicyResponse createSnapshotPolicyResponse(SnapshotPolicy policy) {
|
||||
SnapshotPolicyResponse policyResponse = new SnapshotPolicyResponse();
|
||||
|
|
@ -3093,7 +3118,6 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
response.setObjectName("vpnconnection");
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuestOSResponse createGuestOSResponse(GuestOS guestOS) {
|
||||
GuestOSResponse response = new GuestOSResponse();
|
||||
|
|
@ -3133,7 +3157,6 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public UsageRecordResponse createUsageResponse(Usage usageRecord) {
|
||||
UsageRecordResponse usageRecResponse = new UsageRecordResponse();
|
||||
|
|
|
|||
|
|
@ -62,9 +62,11 @@ import com.cloud.storage.VMTemplateHostVO;
|
|||
import com.cloud.storage.VMTemplateStoragePoolVO;
|
||||
import com.cloud.storage.VMTemplateSwiftVO;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.VMTemplatePoolDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.swift.SwiftManager;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.DateUtil;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.Pair;
|
||||
|
|
@ -78,7 +80,11 @@ import com.cloud.vm.VMInstanceVO;
|
|||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachine.Event;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
@Component
|
||||
@Local(value = CapacityManager.class)
|
||||
|
|
@ -110,7 +116,11 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
|
|||
ConfigurationManager _configMgr;
|
||||
@Inject
|
||||
HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
|
||||
|
||||
@Inject
|
||||
protected VMSnapshotDao _vmSnapshotDao;
|
||||
@Inject
|
||||
protected UserVmDao _userVMDao;
|
||||
|
||||
private int _vmCapacityReleaseInterval;
|
||||
private ScheduledExecutorService _executor;
|
||||
private boolean _stopped;
|
||||
|
|
@ -437,12 +447,43 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
|
|||
|
||||
}
|
||||
|
||||
private long getVMSnapshotAllocatedCapacity(StoragePoolVO pool){
|
||||
List<VolumeVO> volumes = _volumeDao.findByPoolId(pool.getId());
|
||||
long totalSize = 0;
|
||||
for (VolumeVO volume : volumes) {
|
||||
if(volume.getInstanceId() == null)
|
||||
continue;
|
||||
Long vmId = volume.getInstanceId();
|
||||
UserVm vm = _userVMDao.findById(vmId);
|
||||
if(vm == null)
|
||||
continue;
|
||||
ServiceOffering offering = _offeringsDao.findById(vm.getServiceOfferingId());
|
||||
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
|
||||
long pathCount = 0;
|
||||
long memorySnapshotSize = 0;
|
||||
for (VMSnapshotVO vmSnapshotVO : vmSnapshots) {
|
||||
if(_vmSnapshotDao.listByParent(vmSnapshotVO.getId()).size() == 0)
|
||||
pathCount++;
|
||||
if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory)
|
||||
memorySnapshotSize += (offering.getRamSize() * 1024 * 1024);
|
||||
}
|
||||
if(pathCount <= 1)
|
||||
totalSize = totalSize + memorySnapshotSize;
|
||||
else
|
||||
totalSize = totalSize + volume.getSize() * (pathCount - 1) + memorySnapshotSize;
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateForVmCreation){
|
||||
|
||||
// Get size for all the volumes
|
||||
Pair<Long, Long> sizes = _volumeDao.getCountAndTotalByPool(pool.getId());
|
||||
long totalAllocatedSize = sizes.second() + sizes.first() * _extraBytesPerVolume;
|
||||
|
||||
// Get size for VM Snapshots
|
||||
totalAllocatedSize = totalAllocatedSize + getVMSnapshotAllocatedCapacity(pool);
|
||||
|
||||
// Iterate through all templates on this storage pool
|
||||
boolean tmpinstalled = false;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import com.cloud.storage.secondary.SecondaryStorageVmManager;
|
|||
import com.cloud.storage.snapshot.SnapshotManager;
|
||||
import com.cloud.template.TemplateManager;
|
||||
import com.cloud.vm.UserVmManager;
|
||||
import com.cloud.vm.snapshot.VMSnapshotManager;
|
||||
|
||||
public enum Config {
|
||||
|
||||
|
|
@ -371,8 +372,16 @@ public enum Config {
|
|||
|
||||
ApiLimitInterval("Advanced", ManagementServer.class, Integer.class, "api.throttling.interval", "1", "Time interval (in seconds) to reset API count", null),
|
||||
ApiLimitMax("Advanced", ManagementServer.class, Integer.class, "api.throttling.max", "25", "Max allowed number of APIs within fixed interval", null),
|
||||
ApiLimitCacheSize("Advanced", ManagementServer.class, Integer.class, "api.throttling.cachesize", "50000", "Account based API count cache size", null);
|
||||
ApiLimitCacheSize("Advanced", ManagementServer.class, Integer.class, "api.throttling.cachesize", "50000", "Account based API count cache size", null),
|
||||
|
||||
|
||||
// VMSnapshots
|
||||
VMSnapshotMax("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a vm", null),
|
||||
VMSnapshotCreateWait("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.create.wait", "600", "In second, timeout for create vm snapshot", null),
|
||||
VMSnapshotExpungeInterval("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.expunge.interval", "60", "The interval (in seconds) to wait before running the expunge thread.", null),
|
||||
VMSnapshotExpungeWorkers("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.expunge.workers", "1", "Number of workers performing expunge ", null);
|
||||
|
||||
|
||||
private final String _category;
|
||||
private final Class<?> _componentClass;
|
||||
private final Class<?> _type;
|
||||
|
|
|
|||
|
|
@ -99,6 +99,10 @@ import org.apache.cloudstack.api.command.user.tag.*;
|
|||
import org.apache.cloudstack.api.command.user.template.*;
|
||||
import org.apache.cloudstack.api.command.user.vm.*;
|
||||
import org.apache.cloudstack.api.command.user.vmgroup.*;
|
||||
import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd;
|
||||
import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd;
|
||||
import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
|
||||
import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.*;
|
||||
import org.apache.cloudstack.api.command.user.vpc.*;
|
||||
import org.apache.cloudstack.api.command.user.vpn.*;
|
||||
|
|
@ -2143,6 +2147,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||
cmdList.add(ResetVpnConnectionCmd.class);
|
||||
cmdList.add(UpdateVpnCustomerGatewayCmd.class);
|
||||
cmdList.add(ListZonesByCmd.class);
|
||||
cmdList.add(ListVMSnapshotCmd.class);
|
||||
cmdList.add(CreateVMSnapshotCmd.class);
|
||||
cmdList.add(RevertToSnapshotCmd.class);
|
||||
cmdList.add(DeleteVMSnapshotCmd.class);
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ import org.apache.log4j.Logger;
|
|||
import javax.ejb.Local;
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.util.*;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
@Component
|
||||
@Local(value = { SnapshotManager.class, SnapshotService.class })
|
||||
|
|
@ -167,7 +170,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
|||
private ResourceTagDao _resourceTagDao;
|
||||
@Inject
|
||||
private ConfigurationDao _configDao;
|
||||
|
||||
@Inject
|
||||
private VMSnapshotDao _vmSnapshotDao;
|
||||
String _name;
|
||||
private int _totalRetries;
|
||||
private int _pauseInterval;
|
||||
private int _deltaSnapshotMax;
|
||||
|
|
@ -395,6 +400,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
|||
}
|
||||
|
||||
// if volume is attached to a vm in destroyed or expunging state; disallow
|
||||
// if volume is attached to a vm in taking vm snapshot; disallow
|
||||
if (volume.getInstanceId() != null) {
|
||||
UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
|
||||
if (userVm != null) {
|
||||
|
|
@ -408,6 +414,12 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
|||
if(activeSnapshots.size() > 1)
|
||||
throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later");
|
||||
}
|
||||
List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(),
|
||||
VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
|
||||
if (activeVMSnapshots.size() > 0) {
|
||||
throw new CloudRuntimeException(
|
||||
"There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ import com.cloud.utils.db.Transaction;
|
|||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.uuididentity.dao.IdentityDao;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
|
||||
@Component
|
||||
|
|
@ -121,6 +122,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
|
|||
VpcDao _vpcDao;
|
||||
@Inject
|
||||
StaticRouteDao _staticRouteDao;
|
||||
@Inject
|
||||
VMSnapshotDao _vmSnapshotDao;
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
|
|
@ -139,6 +142,7 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
|
|||
_daoMap.put(TaggedResourceType.Vpc, _vpcDao);
|
||||
_daoMap.put(TaggedResourceType.NetworkACL, _firewallDao);
|
||||
_daoMap.put(TaggedResourceType.StaticRoute, _staticRouteDao);
|
||||
_daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,12 +249,37 @@ import com.cloud.utils.exception.ExecutionException;
|
|||
import com.cloud.utils.fsm.NoTransitionException;
|
||||
import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.dao.*;
|
||||
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
|
||||
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.*;
|
||||
import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
|
||||
import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import com.cloud.vm.dao.InstanceGroupDao;
|
||||
import com.cloud.vm.dao.InstanceGroupVMMapDao;
|
||||
import com.cloud.vm.dao.NicDao;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.VMSnapshotManager;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
@Local(value = { UserVmManager.class, UserVmService.class })
|
||||
public class UserVmManagerImpl extends ManagerBase implements UserVmManager, UserVmService {
|
||||
|
|
@ -392,7 +417,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
|||
protected GuestOSCategoryDao _guestOSCategoryDao;
|
||||
@Inject
|
||||
UsageEventDao _usageEventDao;
|
||||
|
||||
@Inject
|
||||
protected VMSnapshotDao _vmSnapshotDao;
|
||||
@Inject
|
||||
protected VMSnapshotManager _vmSnapshotMgr;
|
||||
|
||||
protected ScheduledExecutorService _executor = null;
|
||||
protected int _expungeInterval;
|
||||
protected int _expungeDelay;
|
||||
|
|
@ -813,7 +842,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
|||
// permission check
|
||||
_accountMgr.checkAccess(caller, null, true, volume, vm);
|
||||
|
||||
// Check if volume is stored on secondary Storage.
|
||||
//check if vm has snapshot, if true: can't attache volume
|
||||
boolean attach = true;
|
||||
checkVMSnapshots(vm, volumeId, attach);
|
||||
|
||||
// Check if volume is stored on secondary Storage.
|
||||
//Check if volume is stored on secondary Storage.
|
||||
boolean isVolumeOnSec = false;
|
||||
VolumeHostVO volHostVO = _volumeHostDao.findByVolumeId(volume.getId());
|
||||
if (volHostVO != null) {
|
||||
|
|
@ -1106,8 +1140,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
|||
}
|
||||
}
|
||||
|
||||
private void checkVMSnapshots(UserVmVO vm, Long volumeId, boolean attach) {
|
||||
// Check that if vm has any VM snapshot
|
||||
Long vmId = vm.getId();
|
||||
List<VMSnapshotVO> listSnapshot = _vmSnapshotDao.listByInstanceId(vmId,
|
||||
VMSnapshot.State.Ready, VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
|
||||
if (listSnapshot != null && listSnapshot.size() != 0) {
|
||||
throw new InvalidParameterValueException(
|
||||
"The VM has VM snapshots, do not allowed to attach volume. Please delete the VM snapshots first.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true)
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "event_detaching_volume1", async = true)
|
||||
public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) {
|
||||
Account caller = UserContext.current().getCaller();
|
||||
if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd
|
||||
|
|
@ -1167,8 +1212,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
|||
"Please specify a VM that is either running or stopped.");
|
||||
}
|
||||
|
||||
AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor
|
||||
.getCurrentExecutor();
|
||||
// Check that if the volume has snapshot
|
||||
boolean attach = false;
|
||||
checkVMSnapshots(vm, volumeId, attach);
|
||||
AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor();
|
||||
if (asyncExecutor != null) {
|
||||
AsyncJobVO job = asyncExecutor.getJob();
|
||||
|
||||
|
|
@ -1314,12 +1361,25 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
|||
throw new InvalidParameterValueException(
|
||||
"unable to find a virtual machine with id " + vmId);
|
||||
}
|
||||
|
||||
|
||||
_accountMgr.checkAccess(caller, null, true, vmInstance);
|
||||
|
||||
// Check that the specified service offering ID is valid
|
||||
_itMgr.checkIfCanUpgrade(vmInstance, svcOffId);
|
||||
|
||||
// remove diskAndMemory VM snapshots
|
||||
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
|
||||
for (VMSnapshotVO vmSnapshotVO : vmSnapshots) {
|
||||
if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory){
|
||||
if(!_vmSnapshotMgr.deleteAllVMSnapshots(vmId, VMSnapshot.Type.DiskAndMemory)){
|
||||
String errMsg = "Failed to remove VM snapshot during upgrading, snapshot id " + vmSnapshotVO.getId();
|
||||
s_logger.debug(errMsg);
|
||||
throw new CloudRuntimeException(errMsg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_itMgr.upgradeVmDb(vmId, svcOffId);
|
||||
|
||||
return _vmDao.findById(vmInstance.getId());
|
||||
|
|
@ -1997,8 +2057,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
|||
}
|
||||
|
||||
volume = _volsDao.findById(snapshot.getVolumeId());
|
||||
VolumeVO snapshotVolume = _volsDao
|
||||
.findByIdIncludingRemoved(snapshot.getVolumeId());
|
||||
|
||||
// check permissions
|
||||
_accountMgr.checkAccess(caller, null, true, snapshot);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,10 @@ import com.cloud.vm.dao.NicDao;
|
|||
import com.cloud.vm.dao.SecondaryStorageVmDao;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.VMSnapshotManager;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
@Local(value = VirtualMachineManager.class)
|
||||
public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, Listener {
|
||||
|
|
@ -227,6 +231,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
protected HypervisorGuruManager _hvGuruMgr;
|
||||
@Inject
|
||||
protected NetworkDao _networkDao;
|
||||
@Inject
|
||||
protected VMSnapshotDao _vmSnapshotDao;
|
||||
|
||||
@Inject
|
||||
protected List<DeploymentPlanner> _planners;
|
||||
|
|
@ -236,6 +242,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
|
||||
@Inject
|
||||
protected ResourceManager _resourceMgr;
|
||||
|
||||
@Inject
|
||||
protected VMSnapshotManager _vmSnapshotMgr = null;
|
||||
|
||||
@Inject
|
||||
protected ConfigurationDao _configDao;
|
||||
|
|
@ -590,7 +599,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
ConcurrentOperationException, ResourceUnavailableException {
|
||||
return advanceStart(vm, params, caller, account, null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends VMInstanceVO> T advanceStart(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account, DeploymentPlan planToDeploy)
|
||||
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
|
||||
|
|
@ -1143,6 +1152,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
|
||||
@Override
|
||||
public boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId) throws NoTransitionException {
|
||||
// if there are active vm snapshots task, state change is not allowed
|
||||
if(_vmSnapshotMgr.hasActiveVMSnapshotTasks(vm.getId())){
|
||||
s_logger.error("State transit with event: " + e + " failed due to: " + vm.getInstanceName() + " has active VM snapshots tasks");
|
||||
return false;
|
||||
}
|
||||
|
||||
State oldState = vm.getState();
|
||||
if (oldState == State.Starting) {
|
||||
if (e == Event.OperationSucceeded) {
|
||||
|
|
@ -1177,7 +1192,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
s_logger.debug("Unable to stop " + vm);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!_vmSnapshotMgr.deleteAllVMSnapshots(vm.getId(),null)){
|
||||
s_logger.debug("Unable to delete all snapshots for " + vm);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!stateTransitTo(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId())) {
|
||||
s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm);
|
||||
|
|
@ -1626,6 +1646,19 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
s_logger.debug("Found " + vms.size() + " VMs for host " + hostId);
|
||||
for (VMInstanceVO vm : vms) {
|
||||
AgentVmInfo info = infos.remove(vm.getId());
|
||||
|
||||
// sync VM Snapshots related transient states
|
||||
List<VMSnapshotVO> vmSnapshotsInTrasientStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging,VMSnapshot.State.Reverting, VMSnapshot.State.Creating);
|
||||
if(vmSnapshotsInTrasientStates.size() > 1){
|
||||
s_logger.info("Found vm " + vm.getInstanceName() + " with VM snapshots in transient states, needs to sync VM snapshot state");
|
||||
if(!_vmSnapshotMgr.syncVMSnapshot(vm, hostId)){
|
||||
s_logger.warn("Failed to sync VM in a transient snapshot related state: " + vm.getInstanceName());
|
||||
continue;
|
||||
}else{
|
||||
s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName());
|
||||
}
|
||||
}
|
||||
|
||||
VMInstanceVO castedVm = null;
|
||||
if (info == null) {
|
||||
info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);
|
||||
|
|
@ -1743,8 +1776,27 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
for (VMInstanceVO vm : set_vms) {
|
||||
AgentVmInfo info = infos.remove(vm.getId());
|
||||
VMInstanceVO castedVm = null;
|
||||
if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting))
|
||||
|| (info != null && (info.state == State.Running && vm.getState() == State.Starting)))
|
||||
|
||||
// sync VM Snapshots related transient states
|
||||
List<VMSnapshotVO> vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Creating,VMSnapshot.State.Reverting);
|
||||
if(vmSnapshotsInExpungingStates.size() > 0){
|
||||
s_logger.info("Found vm " + vm.getInstanceName() + " in state. " + vm.getState() + ", needs to sync VM snapshot state");
|
||||
Long hostId = null;
|
||||
Host host = null;
|
||||
if(info != null && info.getHostUuid() != null){
|
||||
host = _hostDao.findByGuid(info.getHostUuid());
|
||||
}
|
||||
hostId = host == null ? (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId()) : host.getId();
|
||||
if(!_vmSnapshotMgr.syncVMSnapshot(vm, hostId)){
|
||||
s_logger.warn("Failed to sync VM with transient snapshot: " + vm.getInstanceName());
|
||||
continue;
|
||||
}else{
|
||||
s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName());
|
||||
}
|
||||
}
|
||||
|
||||
if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting ))
|
||||
|| (info != null && (info.state == State.Running && vm.getState() == State.Starting)))
|
||||
{
|
||||
s_logger.info("Found vm " + vm.getInstanceName() + " in inconsistent state. " + vm.getState() + " on CS while " + (info == null ? "Stopped" : "Running") + " on agent");
|
||||
info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);
|
||||
|
|
@ -1785,7 +1837,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
}
|
||||
}
|
||||
else if (info != null && (vm.getState() == State.Stopped || vm.getState() == State.Stopping
|
||||
|| vm.isRemoved() || vm.getState() == State.Destroyed || vm.getState() == State.Expunging)) {
|
||||
|| vm.isRemoved() || vm.getState() == State.Destroyed || vm.getState() == State.Expunging )) {
|
||||
Host host = _hostDao.findByGuid(info.getHostUuid());
|
||||
if (host != null){
|
||||
s_logger.warn("Stopping a VM which is stopped/stopping/destroyed/expunging " + info.name);
|
||||
|
|
@ -2260,6 +2312,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
|
||||
Long clusterId = agent.getClusterId();
|
||||
long agentId = agent.getId();
|
||||
|
||||
if (agent.getHypervisorType() == HypervisorType.XenServer) { // only for Xen
|
||||
StartupRoutingCommand startup = (StartupRoutingCommand) cmd;
|
||||
HashMap<String, Pair<String, State>> allStates = startup.getClusterVMStateChanges();
|
||||
|
|
@ -2375,7 +2428,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
if (newServiceOffering == null) {
|
||||
throw new InvalidParameterValueException("Unable to find a service offering with id " + newServiceOfferingId);
|
||||
}
|
||||
|
||||
|
||||
// Check that the VM is stopped
|
||||
if (!vmInstance.getState().equals(State.Stopped)) {
|
||||
s_logger.warn("Unable to upgrade virtual machine " + vmInstance.toString() + " in state " + vmInstance.getState());
|
||||
|
|
|
|||
|
|
@ -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 com.cloud.vm.snapshot;
|
||||
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
|
||||
public interface VMSnapshotManager extends VMSnapshotService, Manager {
|
||||
public static final int VMSNAPSHOTMAX = 10;
|
||||
|
||||
|
||||
/**
|
||||
* Delete all VM snapshots belonging to one VM
|
||||
* @param id, VM id
|
||||
* @param type,
|
||||
* @return true for success, false for failure
|
||||
*/
|
||||
boolean deleteAllVMSnapshots(long id, VMSnapshot.Type type);
|
||||
|
||||
/**
|
||||
* Sync VM snapshot state when VM snapshot in reverting or snapshoting or expunging state
|
||||
* Used for fullsync after agent connects
|
||||
*
|
||||
* @param vm, the VM in question
|
||||
* @param hostId
|
||||
* @return true if succeeds, false if fails
|
||||
*/
|
||||
boolean syncVMSnapshot(VMInstanceVO vm, Long hostId);
|
||||
|
||||
boolean hasActiveVMSnapshotTasks(Long vmId);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,833 @@
|
|||
// 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 com.cloud.vm.snapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.CreateVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.CreateVMSnapshotCommand;
|
||||
import com.cloud.agent.api.DeleteVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.DeleteVMSnapshotCommand;
|
||||
import com.cloud.agent.api.RevertToVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.RevertToVMSnapshotCommand;
|
||||
import com.cloud.agent.api.VMSnapshotTO;
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.configuration.dao.ConfigurationDao;
|
||||
import com.cloud.event.ActionEvent;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.AgentUnavailableException;
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.OperationTimedoutException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.hypervisor.HypervisorGuruManager;
|
||||
import com.cloud.projects.Project.ListProjectResourcesCriteria;
|
||||
import com.cloud.storage.GuestOSVO;
|
||||
import com.cloud.storage.Snapshot;
|
||||
import com.cloud.storage.SnapshotVO;
|
||||
import com.cloud.storage.StoragePoolVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.GuestOSDao;
|
||||
import com.cloud.storage.dao.SnapshotDao;
|
||||
import com.cloud.storage.dao.StoragePoolDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.user.UserVO;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.user.dao.UserDao;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.DateUtil;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.Ternary;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
import com.cloud.utils.db.DB;
|
||||
import com.cloud.utils.db.Filter;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import com.cloud.utils.db.Transaction;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.fsm.NoTransitionException;
|
||||
import com.cloud.utils.fsm.StateMachine2;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.VirtualMachineManager;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
@Component
|
||||
@Local(value = { VMSnapshotManager.class, VMSnapshotService.class })
|
||||
public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotManager, VMSnapshotService {
|
||||
private static final Logger s_logger = Logger.getLogger(VMSnapshotManagerImpl.class);
|
||||
String _name;
|
||||
@Inject VMSnapshotDao _vmSnapshotDao;
|
||||
@Inject VolumeDao _volumeDao;
|
||||
@Inject AccountDao _accountDao;
|
||||
@Inject VMInstanceDao _vmInstanceDao;
|
||||
@Inject UserVmDao _userVMDao;
|
||||
@Inject HostDao _hostDao;
|
||||
@Inject UserDao _userDao;
|
||||
@Inject AgentManager _agentMgr;
|
||||
@Inject HypervisorGuruManager _hvGuruMgr;
|
||||
@Inject AccountManager _accountMgr;
|
||||
@Inject GuestOSDao _guestOSDao;
|
||||
@Inject StoragePoolDao _storagePoolDao;
|
||||
@Inject SnapshotDao _snapshotDao;
|
||||
@Inject VirtualMachineManager _itMgr;
|
||||
@Inject ConfigurationDao _configDao;
|
||||
int _vmSnapshotMax;
|
||||
StateMachine2<VMSnapshot.State, VMSnapshot.Event, VMSnapshot> _vmSnapshottateMachine ;
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
_name = name;
|
||||
if (_configDao == null) {
|
||||
throw new ConfigurationException(
|
||||
"Unable to get the configuration dao.");
|
||||
}
|
||||
|
||||
_vmSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("vmsnapshot.max"), VMSNAPSHOTMAX);
|
||||
|
||||
_vmSnapshottateMachine = VMSnapshot.State.getStateMachine();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stop() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VMSnapshotVO> listVMSnapshots(ListVMSnapshotCmd cmd) {
|
||||
Account caller = getCaller();
|
||||
List<Long> permittedAccounts = new ArrayList<Long>();
|
||||
|
||||
boolean listAll = cmd.listAll();
|
||||
Long id = cmd.getId();
|
||||
Long vmId = cmd.getVmId();
|
||||
|
||||
String state = cmd.getState();
|
||||
String keyword = cmd.getKeyword();
|
||||
String name = cmd.getVmSnapshotName();
|
||||
String accountName = cmd.getAccountName();
|
||||
|
||||
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(
|
||||
cmd.getDomainId(), cmd.isRecursive(), null);
|
||||
_accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, listAll,
|
||||
false);
|
||||
Long domainId = domainIdRecursiveListProject.first();
|
||||
Boolean isRecursive = domainIdRecursiveListProject.second();
|
||||
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
|
||||
|
||||
Filter searchFilter = new Filter(VMSnapshotVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||
SearchBuilder<VMSnapshotVO> sb = _vmSnapshotDao.createSearchBuilder();
|
||||
_accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
||||
|
||||
sb.and("vm_id", sb.entity().getVmId(), SearchCriteria.Op.EQ);
|
||||
sb.and("domain_id", sb.entity().getDomainId(), SearchCriteria.Op.EQ);
|
||||
sb.and("status", sb.entity().getState(), SearchCriteria.Op.IN);
|
||||
sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
|
||||
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
|
||||
sb.and("display_name", sb.entity().getDisplayName(), SearchCriteria.Op.EQ);
|
||||
sb.and("account_id", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||
sb.done();
|
||||
|
||||
SearchCriteria<VMSnapshotVO> sc = sb.create();
|
||||
_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
||||
|
||||
if (accountName != null && cmd.getDomainId() != null) {
|
||||
Account account = _accountMgr.getActiveAccountByName(accountName, cmd.getDomainId());
|
||||
sc.setParameters("account_id", account.getId());
|
||||
}
|
||||
|
||||
if (vmId != null) {
|
||||
sc.setParameters("vm_id", vmId);
|
||||
}
|
||||
|
||||
if (domainId != null) {
|
||||
sc.setParameters("domain_id", domainId);
|
||||
}
|
||||
|
||||
if (state == null) {
|
||||
VMSnapshot.State[] status = { VMSnapshot.State.Ready, VMSnapshot.State.Creating, VMSnapshot.State.Allocated,
|
||||
VMSnapshot.State.Error, VMSnapshot.State.Expunging, VMSnapshot.State.Reverting };
|
||||
sc.setParameters("status", (Object[]) status);
|
||||
} else {
|
||||
sc.setParameters("state", state);
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
sc.setParameters("display_name", name);
|
||||
}
|
||||
|
||||
if (keyword != null) {
|
||||
SearchCriteria<VMSnapshotVO> ssc = _vmSnapshotDao.createSearchCriteria();
|
||||
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
|
||||
ssc.addOr("display_name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
|
||||
ssc.addOr("description", SearchCriteria.Op.LIKE, "%" + keyword + "%");
|
||||
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
|
||||
}
|
||||
|
||||
if (id != null) {
|
||||
sc.setParameters("id", id);
|
||||
}
|
||||
|
||||
return _vmSnapshotDao.search(sc, searchFilter);
|
||||
|
||||
}
|
||||
|
||||
protected Account getCaller(){
|
||||
return UserContext.current().getCaller();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDescription, Boolean snapshotMemory)
|
||||
throws ResourceAllocationException {
|
||||
|
||||
Account caller = getCaller();
|
||||
|
||||
// check if VM exists
|
||||
UserVmVO userVmVo = _userVMDao.findById(vmId);
|
||||
if (userVmVo == null) {
|
||||
throw new InvalidParameterValueException("Creating VM snapshot failed due to VM:" + vmId + " is a system VM or does not exist");
|
||||
}
|
||||
|
||||
// parameter length check
|
||||
if(vsDisplayName != null && vsDisplayName.length()>255)
|
||||
throw new InvalidParameterValueException("Creating VM snapshot failed due to length of VM snapshot vsDisplayName should not exceed 255");
|
||||
if(vsDescription != null && vsDescription.length()>255)
|
||||
throw new InvalidParameterValueException("Creating VM snapshot failed due to length of VM snapshot vsDescription should not exceed 255");
|
||||
|
||||
// VM snapshot display name must be unique for a VM
|
||||
String timeString = DateUtil.getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(), DateUtil.YYYYMMDD_FORMAT);
|
||||
String vmSnapshotName = userVmVo.getInstanceName() + "_VS_" + timeString;
|
||||
if (vsDisplayName == null) {
|
||||
vsDisplayName = vmSnapshotName;
|
||||
}
|
||||
if(_vmSnapshotDao.findByName(vmId,vsDisplayName) != null){
|
||||
throw new InvalidParameterValueException("Creating VM snapshot failed due to VM snapshot with name" + vsDisplayName + " already exists");
|
||||
}
|
||||
|
||||
// check VM state
|
||||
if (userVmVo.getState() != VirtualMachine.State.Running && userVmVo.getState() != VirtualMachine.State.Stopped) {
|
||||
throw new InvalidParameterValueException("Creating vm snapshot failed due to VM:" + vmId + " is not in the running or Stopped state");
|
||||
}
|
||||
|
||||
if(snapshotMemory && userVmVo.getState() == VirtualMachine.State.Stopped){
|
||||
throw new InvalidParameterValueException("Can not snapshot memory when VM is in stopped state");
|
||||
}
|
||||
|
||||
// for KVM, only allow snapshot with memory when VM is in running state
|
||||
if(userVmVo.getHypervisorType() == HypervisorType.KVM && userVmVo.getState() == State.Running && !snapshotMemory){
|
||||
throw new InvalidParameterValueException("KVM VM does not allow to take a disk-only snapshot when VM is in running state");
|
||||
}
|
||||
|
||||
// check access
|
||||
_accountMgr.checkAccess(caller, null, true, userVmVo);
|
||||
|
||||
// check max snapshot limit for per VM
|
||||
if (_vmSnapshotDao.findByVm(vmId).size() >= _vmSnapshotMax) {
|
||||
throw new CloudRuntimeException("Creating vm snapshot failed due to a VM can just have : " + _vmSnapshotMax
|
||||
+ " VM snapshots. Please delete old ones");
|
||||
}
|
||||
|
||||
// check if there are active volume snapshots tasks
|
||||
List<VolumeVO> listVolumes = _volumeDao.findByInstance(vmId);
|
||||
for (VolumeVO volume : listVolumes) {
|
||||
List<SnapshotVO> activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating,
|
||||
Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp);
|
||||
if (activeSnapshots.size() > 0) {
|
||||
throw new CloudRuntimeException(
|
||||
"There is other active volume snapshot tasks on the instance to which the volume is attached, please try again later.");
|
||||
}
|
||||
}
|
||||
|
||||
// check if there are other active VM snapshot tasks
|
||||
if (hasActiveVMSnapshotTasks(vmId)) {
|
||||
throw new CloudRuntimeException("There is other active vm snapshot tasks on the instance, please try again later");
|
||||
}
|
||||
|
||||
VMSnapshot.Type vmSnapshotType = VMSnapshot.Type.Disk;
|
||||
if(snapshotMemory && userVmVo.getState() == VirtualMachine.State.Running)
|
||||
vmSnapshotType = VMSnapshot.Type.DiskAndMemory;
|
||||
|
||||
try {
|
||||
VMSnapshotVO vmSnapshotVo = new VMSnapshotVO(userVmVo.getAccountId(), userVmVo.getDomainId(), vmId, vsDescription, vmSnapshotName,
|
||||
vsDisplayName, userVmVo.getServiceOfferingId(), vmSnapshotType, null);
|
||||
VMSnapshot vmSnapshot = _vmSnapshotDao.persist(vmSnapshotVo);
|
||||
if (vmSnapshot == null) {
|
||||
throw new CloudRuntimeException("Failed to create snapshot for vm: " + vmId);
|
||||
}
|
||||
return vmSnapshot;
|
||||
} catch (Exception e) {
|
||||
String msg = e.getMessage();
|
||||
s_logger.error("Create vm snapshot record failed for vm: " + vmId + " due to: " + msg);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return _name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_CREATE, eventDescription = "creating VM snapshot", async = true)
|
||||
public VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId) {
|
||||
UserVmVO userVm = _userVMDao.findById(vmId);
|
||||
if (userVm == null) {
|
||||
throw new InvalidParameterValueException("Create vm to snapshot failed due to vm: " + vmId + " is not found");
|
||||
}
|
||||
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId);
|
||||
if(vmSnapshot == null){
|
||||
throw new CloudRuntimeException("VM snapshot id: " + vmSnapshotId + " can not be found");
|
||||
}
|
||||
Long hostId = pickRunningHost(vmId);
|
||||
try {
|
||||
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.CreateRequested);
|
||||
} catch (NoTransitionException e) {
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
}
|
||||
return createVmSnapshotInternal(userVm, vmSnapshot, hostId);
|
||||
}
|
||||
|
||||
protected VMSnapshot createVmSnapshotInternal(UserVmVO userVm, VMSnapshotVO vmSnapshot, Long hostId) {
|
||||
try {
|
||||
CreateVMSnapshotAnswer answer = null;
|
||||
GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
|
||||
|
||||
// prepare snapshotVolumeTos
|
||||
List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
|
||||
|
||||
// prepare target snapshotTO and its parent snapshot (current snapshot)
|
||||
VMSnapshotTO current = null;
|
||||
VMSnapshotVO currentSnapshot = _vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId());
|
||||
if (currentSnapshot != null)
|
||||
current = getSnapshotWithParents(currentSnapshot);
|
||||
VMSnapshotTO target = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(), null, vmSnapshot.getDescription(), false,
|
||||
current);
|
||||
if (current == null)
|
||||
vmSnapshot.setParent(null);
|
||||
else
|
||||
vmSnapshot.setParent(current.getId());
|
||||
|
||||
CreateVMSnapshotCommand ccmd = new CreateVMSnapshotCommand(userVm.getInstanceName(),target ,volumeTOs, guestOS.getDisplayName(),userVm.getState());
|
||||
|
||||
answer = (CreateVMSnapshotAnswer) sendToPool(hostId, ccmd);
|
||||
if (answer != null && answer.getResult()) {
|
||||
processAnswer(vmSnapshot, userVm, answer, hostId);
|
||||
s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
|
||||
}else{
|
||||
String errMsg = answer.getDetails();
|
||||
s_logger.error("Agent reports creating vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + errMsg);
|
||||
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
|
||||
}
|
||||
return vmSnapshot;
|
||||
} catch (Exception e) {
|
||||
if(e instanceof AgentUnavailableException){
|
||||
try {
|
||||
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed);
|
||||
} catch (NoTransitionException e1) {
|
||||
s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
|
||||
}
|
||||
}
|
||||
String msg = e.getMessage();
|
||||
s_logger.error("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + msg);
|
||||
throw new CloudRuntimeException(msg);
|
||||
} finally{
|
||||
if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
|
||||
s_logger.warn("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName());
|
||||
_vmSnapshotDao.remove(vmSnapshot.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<VolumeTO> getVolumeTOList(Long vmId) {
|
||||
List<VolumeTO> volumeTOs = new ArrayList<VolumeTO>();
|
||||
List<VolumeVO> volumeVos = _volumeDao.findByInstance(vmId);
|
||||
|
||||
for (VolumeVO volume : volumeVos) {
|
||||
StoragePoolVO pool = _storagePoolDao.findById(volume.getPoolId());
|
||||
VolumeTO volumeTO = new VolumeTO(volume, pool);
|
||||
volumeTOs.add(volumeTO);
|
||||
}
|
||||
return volumeTOs;
|
||||
}
|
||||
|
||||
// get snapshot and its parents recursively
|
||||
private VMSnapshotTO getSnapshotWithParents(VMSnapshotVO snapshot) {
|
||||
Map<Long, VMSnapshotVO> snapshotMap = new HashMap<Long, VMSnapshotVO>();
|
||||
List<VMSnapshotVO> allSnapshots = _vmSnapshotDao.findByVm(snapshot.getVmId());
|
||||
for (VMSnapshotVO vmSnapshotVO : allSnapshots) {
|
||||
snapshotMap.put(vmSnapshotVO.getId(), vmSnapshotVO);
|
||||
}
|
||||
|
||||
VMSnapshotTO currentTO = convert2VMSnapshotTO(snapshot);
|
||||
VMSnapshotTO result = currentTO;
|
||||
VMSnapshotVO current = snapshot;
|
||||
while (current.getParent() != null) {
|
||||
VMSnapshotVO parent = snapshotMap.get(current.getParent());
|
||||
currentTO.setParent(convert2VMSnapshotTO(parent));
|
||||
current = snapshotMap.get(current.getParent());
|
||||
currentTO = currentTO.getParent();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private VMSnapshotTO convert2VMSnapshotTO(VMSnapshotVO vo) {
|
||||
return new VMSnapshotTO(vo.getId(), vo.getName(), vo.getType(), vo.getCreated().getTime(), vo.getDescription(),
|
||||
vo.getCurrent(), null);
|
||||
}
|
||||
|
||||
protected boolean vmSnapshotStateTransitTo(VMSnapshotVO vsnp, VMSnapshot.Event event) throws NoTransitionException {
|
||||
return _vmSnapshottateMachine.transitTo(vsnp, event, null, _vmSnapshotDao);
|
||||
}
|
||||
|
||||
@DB
|
||||
protected void processAnswer(VMSnapshotVO vmSnapshot, UserVmVO userVm, Answer as, Long hostId) {
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
try {
|
||||
txn.start();
|
||||
if (as instanceof CreateVMSnapshotAnswer) {
|
||||
CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as;
|
||||
finalizeCreate(vmSnapshot, answer.getVolumeTOs());
|
||||
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
|
||||
} else if (as instanceof RevertToVMSnapshotAnswer) {
|
||||
RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as;
|
||||
finalizeRevert(vmSnapshot, answer.getVolumeTOs());
|
||||
vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded);
|
||||
} else if (as instanceof DeleteVMSnapshotAnswer) {
|
||||
DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as;
|
||||
finalizeDelete(vmSnapshot, answer.getVolumeTOs());
|
||||
_vmSnapshotDao.remove(vmSnapshot.getId());
|
||||
}
|
||||
txn.commit();
|
||||
} catch (Exception e) {
|
||||
String errMsg = "Error while process answer: " + as.getClass() + " due to " + e.getMessage();
|
||||
s_logger.error(errMsg, e);
|
||||
txn.rollback();
|
||||
throw new CloudRuntimeException(errMsg);
|
||||
} finally {
|
||||
txn.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalizeDelete(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
|
||||
// update volumes path
|
||||
updateVolumePath(VolumeTOs);
|
||||
|
||||
// update children's parent snapshots
|
||||
List<VMSnapshotVO> children= _vmSnapshotDao.listByParent(vmSnapshot.getId());
|
||||
for (VMSnapshotVO child : children) {
|
||||
child.setParent(vmSnapshot.getParent());
|
||||
_vmSnapshotDao.persist(child);
|
||||
}
|
||||
|
||||
// update current snapshot
|
||||
VMSnapshotVO current = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
|
||||
if(current != null && current.getId() == vmSnapshot.getId() && vmSnapshot.getParent() != null){
|
||||
VMSnapshotVO parent = _vmSnapshotDao.findById(vmSnapshot.getParent());
|
||||
parent.setCurrent(true);
|
||||
_vmSnapshotDao.persist(parent);
|
||||
}
|
||||
vmSnapshot.setCurrent(false);
|
||||
_vmSnapshotDao.persist(vmSnapshot);
|
||||
}
|
||||
|
||||
protected void finalizeCreate(VMSnapshotVO vmSnapshot, List<VolumeTO> VolumeTOs) {
|
||||
// update volumes path
|
||||
updateVolumePath(VolumeTOs);
|
||||
|
||||
vmSnapshot.setCurrent(true);
|
||||
|
||||
// change current snapshot
|
||||
if (vmSnapshot.getParent() != null) {
|
||||
VMSnapshotVO previousCurrent = _vmSnapshotDao.findById(vmSnapshot.getParent());
|
||||
previousCurrent.setCurrent(false);
|
||||
_vmSnapshotDao.persist(previousCurrent);
|
||||
}
|
||||
_vmSnapshotDao.persist(vmSnapshot);
|
||||
}
|
||||
|
||||
protected void finalizeRevert(VMSnapshotVO vmSnapshot, List<VolumeTO> volumeToList) {
|
||||
// update volumes path
|
||||
updateVolumePath(volumeToList);
|
||||
|
||||
// update current snapshot, current snapshot is the one reverted to
|
||||
VMSnapshotVO previousCurrent = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId());
|
||||
if(previousCurrent != null){
|
||||
previousCurrent.setCurrent(false);
|
||||
_vmSnapshotDao.persist(previousCurrent);
|
||||
}
|
||||
vmSnapshot.setCurrent(true);
|
||||
_vmSnapshotDao.persist(vmSnapshot);
|
||||
}
|
||||
|
||||
private void updateVolumePath(List<VolumeTO> volumeTOs) {
|
||||
for (VolumeTO volume : volumeTOs) {
|
||||
if (volume.getPath() != null) {
|
||||
VolumeVO volumeVO = _volumeDao.findById(volume.getId());
|
||||
volumeVO.setPath(volume.getPath());
|
||||
_volumeDao.persist(volumeVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public VMSnapshotManagerImpl() {
|
||||
|
||||
}
|
||||
|
||||
protected Answer sendToPool(Long hostId, Command cmd) throws AgentUnavailableException, OperationTimedoutException {
|
||||
long targetHostId = _hvGuruMgr.getGuruProcessedCommandTargetHost(hostId, cmd);
|
||||
Answer answer = _agentMgr.send(targetHostId, cmd);
|
||||
return answer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActiveVMSnapshotTasks(Long vmId){
|
||||
List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(vmId,
|
||||
VMSnapshot.State.Creating, VMSnapshot.State.Expunging,VMSnapshot.State.Reverting,VMSnapshot.State.Allocated);
|
||||
return activeVMSnapshots.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_DELETE, eventDescription = "delete vm snapshots", async=true)
|
||||
public boolean deleteVMSnapshot(Long vmSnapshotId) {
|
||||
Account caller = getCaller();
|
||||
|
||||
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId);
|
||||
if (vmSnapshot == null) {
|
||||
throw new InvalidParameterValueException("unable to find the vm snapshot with id " + vmSnapshotId);
|
||||
}
|
||||
|
||||
_accountMgr.checkAccess(caller, null, true, vmSnapshot);
|
||||
|
||||
// check VM snapshot states, only allow to delete vm snapshots in created and error state
|
||||
if (VMSnapshot.State.Ready != vmSnapshot.getState() && VMSnapshot.State.Expunging != vmSnapshot.getState() && VMSnapshot.State.Error != vmSnapshot.getState()) {
|
||||
throw new InvalidParameterValueException("Can't delete the vm snapshotshot " + vmSnapshotId + " due to it is not in Created or Error, or Expunging State");
|
||||
}
|
||||
|
||||
// check if there are other active VM snapshot tasks
|
||||
if (hasActiveVMSnapshotTasks(vmSnapshot.getVmId())) {
|
||||
List<VMSnapshotVO> expungingSnapshots = _vmSnapshotDao.listByInstanceId(vmSnapshot.getVmId(), VMSnapshot.State.Expunging);
|
||||
if(expungingSnapshots.size() > 0 && expungingSnapshots.get(0).getId() == vmSnapshot.getId())
|
||||
s_logger.debug("Target VM snapshot already in expunging state, go on deleting it: " + vmSnapshot.getDisplayName());
|
||||
else
|
||||
throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
|
||||
}
|
||||
|
||||
if(vmSnapshot.getState() == VMSnapshot.State.Allocated){
|
||||
return _vmSnapshotDao.remove(vmSnapshot.getId());
|
||||
}else{
|
||||
return deleteSnapshotInternal(vmSnapshot);
|
||||
}
|
||||
}
|
||||
|
||||
@DB
|
||||
protected boolean deleteSnapshotInternal(VMSnapshotVO vmSnapshot) {
|
||||
UserVmVO userVm = _userVMDao.findById(vmSnapshot.getVmId());
|
||||
|
||||
try {
|
||||
vmSnapshotStateTransitTo(vmSnapshot,VMSnapshot.Event.ExpungeRequested);
|
||||
Long hostId = pickRunningHost(vmSnapshot.getVmId());
|
||||
|
||||
// prepare snapshotVolumeTos
|
||||
List<VolumeTO> volumeTOs = getVolumeTOList(vmSnapshot.getVmId());
|
||||
|
||||
// prepare DeleteVMSnapshotCommand
|
||||
String vmInstanceName = userVm.getInstanceName();
|
||||
VMSnapshotTO parent = getSnapshotWithParents(vmSnapshot).getParent();
|
||||
VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(),
|
||||
vmSnapshot.getCreated().getTime(), vmSnapshot.getDescription(), vmSnapshot.getCurrent(), parent);
|
||||
GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
|
||||
DeleteVMSnapshotCommand deleteSnapshotCommand = new DeleteVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs,guestOS.getDisplayName());
|
||||
|
||||
DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) sendToPool(hostId, deleteSnapshotCommand);
|
||||
|
||||
if (answer != null && answer.getResult()) {
|
||||
processAnswer(vmSnapshot, userVm, answer, hostId);
|
||||
s_logger.debug("Delete VM snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
|
||||
return true;
|
||||
} else {
|
||||
s_logger.error("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + answer.getDetails());
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = "Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + e.getMessage();
|
||||
s_logger.error(msg , e);
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_REVERT, eventDescription = "revert to VM snapshot", async = true)
|
||||
public UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException {
|
||||
|
||||
// check if VM snapshot exists in DB
|
||||
VMSnapshotVO vmSnapshotVo = _vmSnapshotDao.findById(vmSnapshotId);
|
||||
if (vmSnapshotVo == null) {
|
||||
throw new InvalidParameterValueException(
|
||||
"unable to find the vm snapshot with id " + vmSnapshotId);
|
||||
}
|
||||
Long vmId = vmSnapshotVo.getVmId();
|
||||
UserVmVO userVm = _userVMDao.findById(vmId);
|
||||
// check if VM exists
|
||||
if (userVm == null) {
|
||||
throw new InvalidParameterValueException("Revert vm to snapshot: "
|
||||
+ vmSnapshotId + " failed due to vm: " + vmId
|
||||
+ " is not found");
|
||||
}
|
||||
|
||||
// check if there are other active VM snapshot tasks
|
||||
if (hasActiveVMSnapshotTasks(vmId)) {
|
||||
throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
|
||||
}
|
||||
|
||||
Account caller = getCaller();
|
||||
_accountMgr.checkAccess(caller, null, true, vmSnapshotVo);
|
||||
|
||||
// VM should be in running or stopped states
|
||||
if (userVm.getState() != VirtualMachine.State.Running
|
||||
&& userVm.getState() != VirtualMachine.State.Stopped) {
|
||||
throw new InvalidParameterValueException(
|
||||
"VM Snapshot reverting failed due to vm is not in the state of Running or Stopped.");
|
||||
}
|
||||
|
||||
// if snapshot is not created, error out
|
||||
if (vmSnapshotVo.getState() != VMSnapshot.State.Ready) {
|
||||
throw new InvalidParameterValueException(
|
||||
"VM Snapshot reverting failed due to vm snapshot is not in the state of Created.");
|
||||
}
|
||||
|
||||
UserVO callerUser = _userDao.findById(UserContext.current().getCallerUserId());
|
||||
|
||||
UserVmVO vm = null;
|
||||
Long hostId = null;
|
||||
Account owner = _accountDao.findById(vmSnapshotVo.getAccountId());
|
||||
|
||||
// start or stop VM first, if revert from stopped state to running state, or from running to stopped
|
||||
if(userVm.getState() == VirtualMachine.State.Stopped && vmSnapshotVo.getType() == VMSnapshot.Type.DiskAndMemory){
|
||||
try {
|
||||
vm = _itMgr.advanceStart(userVm, new HashMap<VirtualMachineProfile.Param, Object>(), callerUser, owner);
|
||||
hostId = vm.getHostId();
|
||||
} catch (Exception e) {
|
||||
s_logger.error("Start VM " + userVm.getInstanceName() + " before reverting failed due to " + e.getMessage());
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
}
|
||||
}else {
|
||||
if(userVm.getState() == VirtualMachine.State.Running && vmSnapshotVo.getType() == VMSnapshot.Type.Disk){
|
||||
try {
|
||||
_itMgr.advanceStop(userVm, true, callerUser, owner);
|
||||
} catch (Exception e) {
|
||||
s_logger.error("Stop VM " + userVm.getInstanceName() + " before reverting failed due to " + e.getMessage());
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
hostId = pickRunningHost(userVm.getId());
|
||||
}
|
||||
|
||||
if(hostId == null)
|
||||
throw new CloudRuntimeException("Can not find any host to revert snapshot " + vmSnapshotVo.getName());
|
||||
|
||||
// check if there are other active VM snapshot tasks
|
||||
if (hasActiveVMSnapshotTasks(userVm.getId())) {
|
||||
throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
|
||||
}
|
||||
|
||||
userVm = _userVMDao.findById(userVm.getId());
|
||||
try {
|
||||
vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.RevertRequested);
|
||||
} catch (NoTransitionException e) {
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
}
|
||||
return revertInternal(userVm, vmSnapshotVo, hostId);
|
||||
}
|
||||
|
||||
private UserVm revertInternal(UserVmVO userVm, VMSnapshotVO vmSnapshotVo, Long hostId) {
|
||||
try {
|
||||
VMSnapshotVO snapshot = _vmSnapshotDao.findById(vmSnapshotVo.getId());
|
||||
// prepare RevertToSnapshotCommand
|
||||
List<VolumeTO> volumeTOs = getVolumeTOList(userVm.getId());
|
||||
String vmInstanceName = userVm.getInstanceName();
|
||||
VMSnapshotTO parent = getSnapshotWithParents(snapshot).getParent();
|
||||
VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(snapshot.getId(), snapshot.getName(), snapshot.getType(),
|
||||
snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(), parent);
|
||||
|
||||
GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId());
|
||||
RevertToVMSnapshotCommand revertToSnapshotCommand = new RevertToVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs, guestOS.getDisplayName());
|
||||
|
||||
RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) sendToPool(hostId, revertToSnapshotCommand);
|
||||
if (answer != null && answer.getResult()) {
|
||||
processAnswer(vmSnapshotVo, userVm, answer, hostId);
|
||||
s_logger.debug("RevertTo " + vmSnapshotVo.getName() + " succeeded for vm: " + userVm.getInstanceName());
|
||||
} else {
|
||||
String errMsg = "Revert VM: " + userVm.getInstanceName() + " to snapshot: "+ vmSnapshotVo.getName() + " failed";
|
||||
if(answer != null && answer.getDetails() != null)
|
||||
errMsg = errMsg + " due to " + answer.getDetails();
|
||||
s_logger.error(errMsg);
|
||||
// agent report revert operation fails
|
||||
vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
|
||||
throw new CloudRuntimeException(errMsg);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if(e instanceof AgentUnavailableException){
|
||||
try {
|
||||
vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed);
|
||||
} catch (NoTransitionException e1) {
|
||||
s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage());
|
||||
}
|
||||
}
|
||||
// for other exceptions, do not change VM snapshot state, leave it for snapshotSync
|
||||
String errMsg = "revert vm: " + userVm.getInstanceName() + " to snapshot " + vmSnapshotVo.getName() + " failed due to " + e.getMessage();
|
||||
s_logger.error(errMsg);
|
||||
throw new CloudRuntimeException(e.getMessage());
|
||||
}
|
||||
return userVm;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public VMSnapshot getVMSnapshotById(Long id) {
|
||||
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
|
||||
return vmSnapshot;
|
||||
}
|
||||
|
||||
protected Long pickRunningHost(Long vmId) {
|
||||
UserVmVO vm = _userVMDao.findById(vmId);
|
||||
// use VM's host if VM is running
|
||||
if(vm.getState() == State.Running)
|
||||
return vm.getHostId();
|
||||
|
||||
// check if lastHostId is available
|
||||
if(vm.getLastHostId() != null){
|
||||
HostVO lastHost = _hostDao.findById(vm.getLastHostId());
|
||||
if(lastHost.getStatus() == com.cloud.host.Status.Up && !lastHost.isInMaintenanceStates())
|
||||
return lastHost.getId();
|
||||
}
|
||||
|
||||
List<VolumeVO> listVolumes = _volumeDao.findByInstance(vmId);
|
||||
if (listVolumes == null || listVolumes.size() == 0) {
|
||||
throw new InvalidParameterValueException("vmInstance has no volumes");
|
||||
}
|
||||
VolumeVO volume = listVolumes.get(0);
|
||||
Long poolId = volume.getPoolId();
|
||||
if (poolId == null) {
|
||||
throw new InvalidParameterValueException("pool id is not found");
|
||||
}
|
||||
StoragePoolVO storagePool = _storagePoolDao.findById(poolId);
|
||||
if (storagePool == null) {
|
||||
throw new InvalidParameterValueException("storage pool is not found");
|
||||
}
|
||||
List<HostVO> listHost = _hostDao.listAllUpAndEnabledNonHAHosts(Host.Type.Routing, storagePool.getClusterId(), storagePool.getPodId(),
|
||||
storagePool.getDataCenterId(), null);
|
||||
if (listHost == null || listHost.size() == 0) {
|
||||
throw new InvalidParameterValueException("no host in up state is found");
|
||||
}
|
||||
return listHost.get(0).getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualMachine getVMBySnapshotId(Long id) {
|
||||
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
|
||||
if(vmSnapshot == null){
|
||||
throw new InvalidParameterValueException("unable to find the vm snapshot with id " + id);
|
||||
}
|
||||
Long vmId = vmSnapshot.getVmId();
|
||||
UserVmVO vm = _userVMDao.findById(vmId);
|
||||
return vm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteAllVMSnapshots(long vmId, VMSnapshot.Type type) {
|
||||
boolean result = true;
|
||||
List<VMSnapshotVO> listVmSnapshots = _vmSnapshotDao.findByVm(vmId);
|
||||
if (listVmSnapshots == null || listVmSnapshots.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (VMSnapshotVO snapshot : listVmSnapshots) {
|
||||
VMSnapshotVO target = _vmSnapshotDao.findById(snapshot.getId());
|
||||
if(type != null && target.getType() != type)
|
||||
continue;
|
||||
if (!deleteSnapshotInternal(target)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean syncVMSnapshot(VMInstanceVO vm, Long hostId) {
|
||||
try{
|
||||
|
||||
UserVmVO userVm = _userVMDao.findById(vm.getId());
|
||||
if(userVm == null)
|
||||
return false;
|
||||
|
||||
List<VMSnapshotVO> vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Reverting, VMSnapshot.State.Creating);
|
||||
for (VMSnapshotVO vmSnapshotVO : vmSnapshotsInExpungingStates) {
|
||||
if(vmSnapshotVO.getState() == VMSnapshot.State.Expunging){
|
||||
return deleteSnapshotInternal(vmSnapshotVO);
|
||||
}else if(vmSnapshotVO.getState() == VMSnapshot.State.Creating){
|
||||
return createVmSnapshotInternal(userVm, vmSnapshotVO, hostId) != null;
|
||||
}else if(vmSnapshotVO.getState() == VMSnapshot.State.Reverting){
|
||||
return revertInternal(userVm, vmSnapshotVO, hostId) != null;
|
||||
}
|
||||
}
|
||||
}catch (Exception e) {
|
||||
s_logger.error(e.getMessage(),e);
|
||||
if(_vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging).size() == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// 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 com.cloud.vm.snapshot.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import com.cloud.utils.fsm.StateDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
|
||||
public interface VMSnapshotDao extends GenericDao<VMSnapshotVO, Long>, StateDao<VMSnapshot.State, VMSnapshot.Event, VMSnapshot> {
|
||||
|
||||
List<VMSnapshotVO> findByVm(Long vmId);
|
||||
|
||||
List<VMSnapshotVO> listExpungingSnapshot();
|
||||
|
||||
List<VMSnapshotVO> listByInstanceId(Long vmId, VMSnapshot.State... status);
|
||||
|
||||
VMSnapshotVO findCurrentSnapshotByVmId(Long vmId);
|
||||
|
||||
List<VMSnapshotVO> listByParent(Long vmSnapshotId);
|
||||
|
||||
VMSnapshotVO findByName(Long vm_id, String name);
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
// 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 com.cloud.vm.snapshot.dao;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Local;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import com.cloud.utils.db.SearchCriteria.Op;
|
||||
import com.cloud.utils.db.UpdateBuilder;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.VMSnapshot.Event;
|
||||
import com.cloud.vm.snapshot.VMSnapshot.State;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
@Component
|
||||
@Local(value = { VMSnapshotDao.class })
|
||||
public class VMSnapshotDaoImpl extends GenericDaoBase<VMSnapshotVO, Long>
|
||||
implements VMSnapshotDao {
|
||||
private static final Logger s_logger = Logger.getLogger(VMSnapshotDaoImpl.class);
|
||||
private final SearchBuilder<VMSnapshotVO> SnapshotSearch;
|
||||
private final SearchBuilder<VMSnapshotVO> ExpungingSnapshotSearch;
|
||||
private final SearchBuilder<VMSnapshotVO> SnapshotStatusSearch;
|
||||
private final SearchBuilder<VMSnapshotVO> AllFieldsSearch;
|
||||
|
||||
protected VMSnapshotDaoImpl() {
|
||||
AllFieldsSearch = createSearchBuilder();
|
||||
AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ);
|
||||
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ);
|
||||
AllFieldsSearch.and("vm_id", AllFieldsSearch.entity().getVmId(), Op.EQ);
|
||||
AllFieldsSearch.and("deviceId", AllFieldsSearch.entity().getVmId(), Op.EQ);
|
||||
AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ);
|
||||
AllFieldsSearch.and("removed", AllFieldsSearch.entity().getState(), Op.EQ);
|
||||
AllFieldsSearch.and("parent", AllFieldsSearch.entity().getParent(), Op.EQ);
|
||||
AllFieldsSearch.and("current", AllFieldsSearch.entity().getCurrent(), Op.EQ);
|
||||
AllFieldsSearch.and("vm_snapshot_type", AllFieldsSearch.entity().getType(), Op.EQ);
|
||||
AllFieldsSearch.and("updatedCount", AllFieldsSearch.entity().getUpdatedCount(), Op.EQ);
|
||||
AllFieldsSearch.and("display_name", AllFieldsSearch.entity().getDisplayName(), SearchCriteria.Op.EQ);
|
||||
AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), SearchCriteria.Op.EQ);
|
||||
AllFieldsSearch.done();
|
||||
|
||||
SnapshotSearch = createSearchBuilder();
|
||||
SnapshotSearch.and("vm_id", SnapshotSearch.entity().getVmId(),
|
||||
SearchCriteria.Op.EQ);
|
||||
SnapshotSearch.done();
|
||||
|
||||
ExpungingSnapshotSearch = createSearchBuilder();
|
||||
ExpungingSnapshotSearch.and("state", ExpungingSnapshotSearch.entity()
|
||||
.getState(), SearchCriteria.Op.EQ);
|
||||
ExpungingSnapshotSearch.and("removed", ExpungingSnapshotSearch.entity()
|
||||
.getRemoved(), SearchCriteria.Op.NULL);
|
||||
ExpungingSnapshotSearch.done();
|
||||
|
||||
SnapshotStatusSearch = createSearchBuilder();
|
||||
SnapshotStatusSearch.and("vm_id", SnapshotStatusSearch.entity()
|
||||
.getVmId(), SearchCriteria.Op.EQ);
|
||||
SnapshotStatusSearch.and("state", SnapshotStatusSearch.entity()
|
||||
.getState(), SearchCriteria.Op.IN);
|
||||
SnapshotStatusSearch.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VMSnapshotVO> findByVm(Long vmId) {
|
||||
SearchCriteria<VMSnapshotVO> sc = SnapshotSearch.create();
|
||||
sc.setParameters("vm_id", vmId);
|
||||
return listBy(sc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VMSnapshotVO> listExpungingSnapshot() {
|
||||
SearchCriteria<VMSnapshotVO> sc = ExpungingSnapshotSearch.create();
|
||||
sc.setParameters("state", State.Expunging);
|
||||
return listBy(sc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VMSnapshotVO> listByInstanceId(Long vmId, State... status) {
|
||||
SearchCriteria<VMSnapshotVO> sc = SnapshotStatusSearch.create();
|
||||
sc.setParameters("vm_id", vmId);
|
||||
sc.setParameters("state", (Object[]) status);
|
||||
return listBy(sc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VMSnapshotVO findCurrentSnapshotByVmId(Long vmId) {
|
||||
SearchCriteria<VMSnapshotVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("vm_id", vmId);
|
||||
sc.setParameters("current", 1);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VMSnapshotVO> listByParent(Long vmSnapshotId) {
|
||||
SearchCriteria<VMSnapshotVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("parent", vmSnapshotId);
|
||||
sc.setParameters("state", State.Ready );
|
||||
return listBy(sc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VMSnapshotVO findByName(Long vm_id, String name) {
|
||||
SearchCriteria<VMSnapshotVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("vm_id", vm_id);
|
||||
sc.setParameters("display_name", name );
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateState(State currentState, Event event, State nextState, VMSnapshot vo, Object data) {
|
||||
|
||||
Long oldUpdated = vo.getUpdatedCount();
|
||||
Date oldUpdatedTime = vo.getUpdated();
|
||||
|
||||
SearchCriteria<VMSnapshotVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("id", vo.getId());
|
||||
sc.setParameters("state", currentState);
|
||||
sc.setParameters("updatedCount", vo.getUpdatedCount());
|
||||
|
||||
vo.incrUpdatedCount();
|
||||
|
||||
UpdateBuilder builder = getUpdateBuilder(vo);
|
||||
builder.set(vo, "state", nextState);
|
||||
builder.set(vo, "updated", new Date());
|
||||
|
||||
int rows = update((VMSnapshotVO)vo, sc);
|
||||
if (rows == 0 && s_logger.isDebugEnabled()) {
|
||||
VMSnapshotVO dbVol = findByIdIncludingRemoved(vo.getId());
|
||||
if (dbVol != null) {
|
||||
StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString());
|
||||
str.append(": DB Data={id=").append(dbVol.getId()).append("; state=").append(dbVol.getState()).append("; updatecount=").append(dbVol.getUpdatedCount()).append(";updatedTime=").append(dbVol.getUpdated());
|
||||
str.append(": New Data={id=").append(vo.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(vo.getUpdatedCount()).append("; updatedTime=").append(vo.getUpdated());
|
||||
str.append(": stale Data={id=").append(vo.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated).append("; updatedTime=").append(oldUpdatedTime);
|
||||
} else {
|
||||
s_logger.debug("Unable to update VM snapshot: id=" + vo.getId() + ", as there is no such snapshot exists in the database anymore");
|
||||
}
|
||||
}
|
||||
return rows > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
// 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 com.cloud.vm.snapshot;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.CreateVMSnapshotAnswer;
|
||||
import com.cloud.agent.api.CreateVMSnapshotCommand;
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.configuration.dao.ConfigurationDao;
|
||||
import com.cloud.exception.AgentUnavailableException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.OperationTimedoutException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.hypervisor.HypervisorGuruManager;
|
||||
import com.cloud.storage.GuestOSVO;
|
||||
import com.cloud.storage.Snapshot;
|
||||
import com.cloud.storage.SnapshotVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.GuestOSDao;
|
||||
import com.cloud.storage.dao.SnapshotDao;
|
||||
import com.cloud.storage.dao.StoragePoolDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.user.dao.UserDao;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.fsm.NoTransitionException;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.VirtualMachineManager;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
|
||||
|
||||
public class VMSnapshotManagerTest {
|
||||
@Spy VMSnapshotManagerImpl _vmSnapshotMgr = new VMSnapshotManagerImpl();
|
||||
@Mock Account admin;
|
||||
@Mock VMSnapshotDao _vmSnapshotDao;
|
||||
@Mock VolumeDao _volumeDao;
|
||||
@Mock AccountDao _accountDao;
|
||||
@Mock VMInstanceDao _vmInstanceDao;
|
||||
@Mock UserVmDao _userVMDao;
|
||||
@Mock HostDao _hostDao;
|
||||
@Mock UserDao _userDao;
|
||||
@Mock AgentManager _agentMgr;
|
||||
@Mock HypervisorGuruManager _hvGuruMgr;
|
||||
@Mock AccountManager _accountMgr;
|
||||
@Mock GuestOSDao _guestOSDao;
|
||||
@Mock StoragePoolDao _storagePoolDao;
|
||||
@Mock SnapshotDao _snapshotDao;
|
||||
@Mock VirtualMachineManager _itMgr;
|
||||
@Mock ConfigurationDao _configDao;
|
||||
int _vmSnapshotMax = 10;
|
||||
|
||||
private static long TEST_VM_ID = 3L;
|
||||
@Mock UserVmVO vmMock;
|
||||
@Mock VolumeVO volumeMock;
|
||||
|
||||
@Before
|
||||
public void setup(){
|
||||
MockitoAnnotations.initMocks(this);
|
||||
doReturn(admin).when(_vmSnapshotMgr).getCaller();
|
||||
_vmSnapshotMgr._accountDao = _accountDao;
|
||||
_vmSnapshotMgr._userVMDao = _userVMDao;
|
||||
_vmSnapshotMgr._vmSnapshotDao = _vmSnapshotDao;
|
||||
_vmSnapshotMgr._volumeDao = _volumeDao;
|
||||
_vmSnapshotMgr._accountMgr = _accountMgr;
|
||||
_vmSnapshotMgr._snapshotDao = _snapshotDao;
|
||||
_vmSnapshotMgr._guestOSDao = _guestOSDao;
|
||||
|
||||
doNothing().when(_accountMgr).checkAccess(any(Account.class), any(AccessType.class),
|
||||
any(Boolean.class), any(ControlledEntity.class));
|
||||
|
||||
_vmSnapshotMgr._vmSnapshotMax = _vmSnapshotMax;
|
||||
|
||||
when(_userVMDao.findById(anyLong())).thenReturn(vmMock);
|
||||
when(_vmSnapshotDao.findByName(anyLong(), anyString())).thenReturn(null);
|
||||
when(_vmSnapshotDao.findByVm(anyLong())).thenReturn(new ArrayList<VMSnapshotVO>());
|
||||
|
||||
List<VolumeVO> mockVolumeList = new ArrayList<VolumeVO>();
|
||||
mockVolumeList.add(volumeMock);
|
||||
when(volumeMock.getInstanceId()).thenReturn(TEST_VM_ID);
|
||||
when(_volumeDao.findByInstance(anyLong())).thenReturn(mockVolumeList);
|
||||
|
||||
when(vmMock.getInstanceName()).thenReturn("i-3-VM-TEST");
|
||||
when(vmMock.getState()).thenReturn(State.Running);
|
||||
|
||||
when(_guestOSDao.findById(anyLong())).thenReturn(mock(GuestOSVO.class));
|
||||
}
|
||||
|
||||
// vmId null case
|
||||
@Test(expected=InvalidParameterValueException.class)
|
||||
public void testAllocVMSnapshotF1() throws ResourceAllocationException{
|
||||
when(_userVMDao.findById(TEST_VM_ID)).thenReturn(null);
|
||||
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
|
||||
}
|
||||
|
||||
// vm state not in [running, stopped] case
|
||||
@Test(expected=InvalidParameterValueException.class)
|
||||
public void testAllocVMSnapshotF2() throws ResourceAllocationException{
|
||||
when(vmMock.getState()).thenReturn(State.Starting);
|
||||
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
|
||||
}
|
||||
|
||||
// VM in stopped state & snapshotmemory case
|
||||
@Test(expected=InvalidParameterValueException.class)
|
||||
public void testCreateVMSnapshotF3() throws AgentUnavailableException, OperationTimedoutException, ResourceAllocationException{
|
||||
when(vmMock.getState()).thenReturn(State.Stopped);
|
||||
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
|
||||
}
|
||||
|
||||
// max snapshot limit case
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test(expected=CloudRuntimeException.class)
|
||||
public void testAllocVMSnapshotF4() throws ResourceAllocationException{
|
||||
List<VMSnapshotVO> mockList = mock(List.class);
|
||||
when(mockList.size()).thenReturn(10);
|
||||
when(_vmSnapshotDao.findByVm(TEST_VM_ID)).thenReturn(mockList);
|
||||
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
|
||||
}
|
||||
|
||||
// active volume snapshots case
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test(expected=CloudRuntimeException.class)
|
||||
public void testAllocVMSnapshotF5() throws ResourceAllocationException{
|
||||
List<SnapshotVO> mockList = mock(List.class);
|
||||
when(mockList.size()).thenReturn(1);
|
||||
when(_snapshotDao.listByInstanceId(TEST_VM_ID,Snapshot.State.Creating,
|
||||
Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp)).thenReturn(mockList);
|
||||
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
|
||||
}
|
||||
|
||||
// successful creation case
|
||||
@Test
|
||||
public void testCreateVMSnapshot() throws AgentUnavailableException, OperationTimedoutException, ResourceAllocationException, NoTransitionException{
|
||||
when(vmMock.getState()).thenReturn(State.Running);
|
||||
_vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true);
|
||||
|
||||
when(_vmSnapshotDao.findCurrentSnapshotByVmId(anyLong())).thenReturn(null);
|
||||
doReturn(new ArrayList<VolumeTO>()).when(_vmSnapshotMgr).getVolumeTOList(anyLong());
|
||||
doReturn(new CreateVMSnapshotAnswer(null,true,"")).when(_vmSnapshotMgr).sendToPool(anyLong(), any(CreateVMSnapshotCommand.class));
|
||||
doNothing().when(_vmSnapshotMgr).processAnswer(any(VMSnapshotVO.class),
|
||||
any(UserVmVO.class), any(Answer.class), anyLong());
|
||||
doReturn(true).when(_vmSnapshotMgr).vmSnapshotStateTransitTo(any(VMSnapshotVO.class),any(VMSnapshot.Event.class));
|
||||
_vmSnapshotMgr.createVmSnapshotInternal(vmMock, mock(VMSnapshotVO.class), 5L);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2625,6 +2625,36 @@ INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (1,
|
|||
INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (2, UUID(), 'snmp','Linux System CPU - percentage', '1.3.6.1.4.1.2021.11.10.0', now());
|
||||
INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (3, UUID(), 'snmp','Linux CPU Idle - percentage', '1.3.6.1.4.1.2021.11.11.0', now());
|
||||
INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (100, UUID(), 'netscaler','Response Time - microseconds', 'RESPTIME', now());
|
||||
CREATE TABLE `cloud`.`vm_snapshots` (
|
||||
`id` bigint(20) unsigned NOT NULL auto_increment COMMENT 'Primary Key',
|
||||
`uuid` varchar(40) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`display_name` varchar(255) default NULL,
|
||||
`description` varchar(255) default NULL,
|
||||
`vm_id` bigint(20) unsigned NOT NULL,
|
||||
`account_id` bigint(20) unsigned NOT NULL,
|
||||
`domain_id` bigint(20) unsigned NOT NULL,
|
||||
`vm_snapshot_type` varchar(32) default NULL,
|
||||
`state` varchar(32) NOT NULL,
|
||||
`parent` bigint unsigned default NULL,
|
||||
`current` int(1) unsigned default NULL,
|
||||
`update_count` bigint unsigned NOT NULL DEFAULT 0,
|
||||
`updated` datetime default NULL,
|
||||
`created` datetime default NULL,
|
||||
`removed` datetime default NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT UNIQUE KEY `uc_vm_snapshots_uuid` (`uuid`),
|
||||
INDEX `vm_snapshots_name` (`name`),
|
||||
INDEX `vm_snapshots_vm_id` (`vm_id`),
|
||||
INDEX `vm_snapshots_account_id` (`account_id`),
|
||||
INDEX `vm_snapshots_display_name` (`display_name`),
|
||||
INDEX `vm_snapshots_removed` (`removed`),
|
||||
INDEX `vm_snapshots_parent` (`parent`),
|
||||
CONSTRAINT `fk_vm_snapshots_vm_id__vm_instance_id` FOREIGN KEY `fk_vm_snapshots_vm_id__vm_instance_id` (`vm_id`) REFERENCES `vm_instance` (`id`),
|
||||
CONSTRAINT `fk_vm_snapshots_account_id__account_id` FOREIGN KEY `fk_vm_snapshots_account_id__account_id` (`account_id`) REFERENCES `account` (`id`),
|
||||
CONSTRAINT `fk_vm_snapshots_domain_id__domain_id` FOREIGN KEY `fk_vm_snapshots_domain_id__domain_id` (`domain_id`) REFERENCES `domain` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE `cloud`.`user_ipv6_address` (
|
||||
`id` bigint unsigned NOT NULL UNIQUE auto_increment,
|
||||
|
|
|
|||
|
|
@ -1931,7 +1931,7 @@ div.detail-group.actions td {
|
|||
}
|
||||
|
||||
.detail-group table td.detail-actions {
|
||||
width: 55%;
|
||||
width: 59%;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1437,6 +1437,16 @@ dictionary = {
|
|||
'label.resize.new.size': '<fmt:message key="label.resize.new.size" />',
|
||||
'label.action.resize.volume': '<fmt:message key="label.action.resize.volume" />',
|
||||
'label.resize.new.offering.id': '<fmt:message key="label.resize.new.offering.id" />',
|
||||
'label.resize.shrink.ok': '<fmt:message key="label.resize.shrink.ok" />'
|
||||
'label.resize.shrink.ok': '<fmt:message key="label.resize.shrink.ok" />',
|
||||
'label.vmsnapshot.current': '<fmt:message key="label.vmsnapshot.current" />',
|
||||
'label.vmsnapshot.parentname': '<fmt:message key="label.vmsnapshot.parentname" />',
|
||||
'label.vmsnapshot.type': '<fmt:message key="label.vmsnapshot.type" />',
|
||||
'label.vmsnapshot.memory': '<fmt:message key="label.vmsnapshot.memory" />',
|
||||
'label.vmsnapshot': '<fmt:message key="label.vmsnapshot" />',
|
||||
'label.action.vmsnapshot.create': '<fmt:message key="label.action.vmsnapshot.create" />',
|
||||
'label.action.vmsnapshot.delete': '<fmt:message key="label.action.vmsnapshot.delete" />',
|
||||
'label.action.vmsnapshot.revert': '<fmt:message key="label.action.vmsnapshot.revert" />',
|
||||
'message.action.vmsnapshot.delete': '<fmt:message key="message.action.vmsnapshot.delete" />',
|
||||
'message.action.vmsnapshot.revert': '<fmt:message key="message.action.vmsnapshot.revert" />'
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1674,6 +1674,8 @@ under the License.
|
|||
<script type="text/javascript" src="scripts/system.js?t=<%=now%>"></script>
|
||||
<script type="text/javascript" src="scripts/domains.js?t=<%=now%>"></script>
|
||||
<script type="text/javascript" src="scripts/docs.js?t=<%=now%>"></script>
|
||||
<script type="text/javascript" src="scripts/domains.js?t=<%=now%>"></script>
|
||||
<script type="text/javascript" src="scripts/vm_snapshots.js?t=<%=now%>"></script>
|
||||
</body>
|
||||
</html>
|
||||
<jsp:include page="dictionary.jsp" />
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
displayname: { label: 'label.display.name' },
|
||||
zonename: { label: 'label.zone.name' },
|
||||
state: {
|
||||
label: 'label.state',
|
||||
label: 'label.state',
|
||||
indicator: {
|
||||
'Running': 'on',
|
||||
'Stopped': 'off',
|
||||
|
|
@ -153,6 +153,194 @@
|
|||
notification: {
|
||||
poll: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
start: {
|
||||
label: 'label.action.start.instance' ,
|
||||
action: function(args) {
|
||||
$.ajax({
|
||||
url: createURL("startVirtualMachine&id=" + args.context.instances[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.startvirtualmachineresponse.jobid;
|
||||
args.response.success(
|
||||
{_custom:
|
||||
{jobId: jid,
|
||||
getUpdatedItem: function(json) {
|
||||
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
|
||||
},
|
||||
getActionFilter: function() {
|
||||
return vmActionfilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
messages: {
|
||||
confirm: function(args) {
|
||||
return 'message.action.start.instance';
|
||||
},
|
||||
notification: function(args) {
|
||||
return 'label.action.start.instance';
|
||||
},
|
||||
complete: function(args) {
|
||||
if(args.password != null) {
|
||||
alert('Password of the VM is ' + args.password);
|
||||
}
|
||||
return 'label.action.start.instance';
|
||||
}
|
||||
},
|
||||
notification: {
|
||||
poll: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
stop: {
|
||||
label: 'label.action.stop.instance',
|
||||
addRow: 'false',
|
||||
createForm: {
|
||||
title: 'label.action.stop.instance',
|
||||
desc: 'message.action.stop.instance',
|
||||
fields: {
|
||||
forced: {
|
||||
label: 'force.stop',
|
||||
isBoolean: true,
|
||||
isChecked: false
|
||||
}
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
var array1 = [];
|
||||
array1.push("&forced=" + (args.data.forced == "on"));
|
||||
$.ajax({
|
||||
url: createURL("stopVirtualMachine&id=" + args.context.instances[0].id + array1.join("")),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.stopvirtualmachineresponse.jobid;
|
||||
args.response.success(
|
||||
{_custom:
|
||||
{jobId: jid,
|
||||
getUpdatedItem: function(json) {
|
||||
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
|
||||
},
|
||||
getActionFilter: function() {
|
||||
return vmActionfilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
messages: {
|
||||
confirm: function(args) {
|
||||
return 'message.action.stop.instance';
|
||||
},
|
||||
|
||||
notification: function(args) {
|
||||
return 'label.action.stop.instance';
|
||||
}
|
||||
},
|
||||
notification: {
|
||||
poll: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
restart: {
|
||||
label: 'instances.actions.reboot.label',
|
||||
action: function(args) {
|
||||
$.ajax({
|
||||
url: createURL("rebootVirtualMachine&id=" + args.context.instances[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.rebootvirtualmachineresponse.jobid;
|
||||
args.response.success(
|
||||
{_custom:
|
||||
{jobId: jid,
|
||||
getUpdatedItem: function(json) {
|
||||
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
|
||||
},
|
||||
getActionFilter: function() {
|
||||
return vmActionfilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
messages: {
|
||||
confirm: function(args) {
|
||||
return 'message.action.reboot.instance';
|
||||
},
|
||||
notification: function(args) {
|
||||
return 'instances.actions.reboot.label';
|
||||
}
|
||||
},
|
||||
notification: {
|
||||
poll: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
|
||||
destroy: {
|
||||
label: 'label.action.destroy.instance',
|
||||
messages: {
|
||||
confirm: function(args) {
|
||||
return 'message.action.destroy.instance';
|
||||
},
|
||||
notification: function(args) {
|
||||
return 'label.action.destroy.instance';
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
$.ajax({
|
||||
url: createURL("destroyVirtualMachine&id=" + args.context.instances[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.destroyvirtualmachineresponse.jobid;
|
||||
args.response.success(
|
||||
{_custom:
|
||||
{jobId: jid,
|
||||
getUpdatedItem: function(json) {
|
||||
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
|
||||
},
|
||||
getActionFilter: function() {
|
||||
return vmActionfilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
notification: {
|
||||
poll: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
restore: {
|
||||
label: 'label.action.restore.instance',
|
||||
messages: {
|
||||
confirm: function(args) {
|
||||
return 'message.action.restore.instance';
|
||||
},
|
||||
notification: function(args) {
|
||||
return 'label.action.restore.instance';
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
$.ajax({
|
||||
url: createURL("recoverVirtualMachine&id=" + args.context.instances[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var item = json.recovervirtualmachineresponse.virtualmachine;
|
||||
args.response.success({data:item});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -231,7 +419,7 @@
|
|||
|
||||
detailView: {
|
||||
name: 'Instance details',
|
||||
viewAll: { path: 'storage.volumes', label: 'label.volumes' },
|
||||
viewAll: [{ path: 'storage.volumes', label: 'label.volumes' }, { path: 'vmsnapshots', label: 'Snapshots' } ],
|
||||
tabFilter: function(args) {
|
||||
var hiddenTabs = [];
|
||||
|
||||
|
|
@ -409,6 +597,70 @@
|
|||
poll: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
|
||||
snapshot: {
|
||||
messages: {
|
||||
notification: function(args) {
|
||||
return 'label.action.vmsnapshot.create';
|
||||
}
|
||||
},
|
||||
label: 'label.action.vmsnapshot.create',
|
||||
addRow: 'false',
|
||||
createForm: {
|
||||
title: 'label.action.vmsnapshot.create',
|
||||
fields: {
|
||||
name: {
|
||||
label: 'label.name',
|
||||
isInput: true
|
||||
},
|
||||
description: {
|
||||
label: 'label.description',
|
||||
isTextarea: true
|
||||
},
|
||||
snapshotMemory: {
|
||||
label: 'label.vmsnapshot.memory',
|
||||
isBoolean: true,
|
||||
isChecked: false
|
||||
}
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
var array1 = [];
|
||||
array1.push("&snapshotmemory=" + (args.data.snapshotMemory == "on"));
|
||||
var displayname = args.data.name;
|
||||
if (displayname != null && displayname.length > 0) {
|
||||
array1.push("&name=" + todb(displayname));
|
||||
}
|
||||
var description = args.data.description;
|
||||
if (description != null && description.length > 0) {
|
||||
array1.push("&description=" + todb(description));
|
||||
}
|
||||
$.ajax({
|
||||
url: createURL("createVMSnapshot&virtualmachineid=" + args.context.instances[0].id + array1.join("")),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.createvmsnapshotresponse.jobid;
|
||||
args.response.success({
|
||||
_custom: {
|
||||
jobId: jid,
|
||||
getUpdatedItem: function(json) {
|
||||
return json.queryasyncjobresultresponse.jobresult.virtualmachine;
|
||||
},
|
||||
getActionFilter: function() {
|
||||
return vmActionfilter;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
notification: {
|
||||
pool: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
|
||||
destroy: {
|
||||
label: 'label.action.destroy.instance',
|
||||
compactLabel: 'label.destroy',
|
||||
|
|
@ -1232,6 +1484,7 @@
|
|||
else if (jsonObj.state == 'Running') {
|
||||
allowedActions.push("stop");
|
||||
allowedActions.push("restart");
|
||||
allowedActions.push("snapshot");
|
||||
allowedActions.push("destroy");
|
||||
allowedActions.push("changeService");
|
||||
allowedActions.push("reset");
|
||||
|
|
@ -1257,7 +1510,7 @@
|
|||
allowedActions.push("start");
|
||||
allowedActions.push("destroy");
|
||||
allowedActions.push("reset");
|
||||
|
||||
allowedActions.push("snapshot");
|
||||
if(isAdmin())
|
||||
allowedActions.push("migrateToAnotherStorage");
|
||||
|
||||
|
|
|
|||
|
|
@ -892,14 +892,20 @@
|
|||
$actions.prependTo($firstRow.closest('div.detail-group').closest('.details'));
|
||||
}
|
||||
if (detailViewArgs.viewAll && showViewAll) {
|
||||
|
||||
if( !(detailViewArgs.viewAll instanceof Array)){
|
||||
detailViewArgs.viewAll = [detailViewArgs.viewAll];
|
||||
}
|
||||
$.each(detailViewArgs.viewAll, function(n, view){
|
||||
$('<div>')
|
||||
.addClass('view-all')
|
||||
.append(
|
||||
$('<a>')
|
||||
.attr({ href: '#' })
|
||||
.data('detail-view-link-view-all', detailViewArgs.viewAll)
|
||||
.css('padding','0 1px')
|
||||
.data('detail-view-link-view-all', view)
|
||||
.append(
|
||||
$('<span>').html(_l('label.view') + ' ' + _l(detailViewArgs.viewAll.label))
|
||||
$('<span>').html(_l('label.view') + ' ' + _l(view.label))
|
||||
)
|
||||
)
|
||||
.append(
|
||||
|
|
@ -908,9 +914,10 @@
|
|||
.appendTo(
|
||||
$('<td>')
|
||||
.addClass('view-all')
|
||||
.css('padding','9px 3px 8px 0')
|
||||
.appendTo($actions.find('tr'))
|
||||
);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,196 @@
|
|||
// 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.
|
||||
(function($, cloudStack) {
|
||||
cloudStack.sections.vmsnapshots = {
|
||||
title: 'label.vmsnapshot',
|
||||
id: 'vmsnapshots',
|
||||
listView: {
|
||||
id: 'vmsnapshots',
|
||||
isMaximized: true,
|
||||
fields: {
|
||||
displayname: {
|
||||
label: 'label.name'
|
||||
},
|
||||
state: {
|
||||
label: 'label.state',
|
||||
indicator: {
|
||||
'Ready': 'on',
|
||||
'Error': 'off'
|
||||
}
|
||||
},
|
||||
type:{
|
||||
label: 'label.vmsnapshot.type'
|
||||
},
|
||||
current:{
|
||||
label: 'label.vmsnapshot.current',
|
||||
converter: cloudStack.converters.toBooleanText
|
||||
},
|
||||
parentName:{
|
||||
label: 'label.vmsnapshot.parentname'
|
||||
},
|
||||
created: {
|
||||
label: 'label.date',
|
||||
converter: cloudStack.converters.toLocalDate
|
||||
}
|
||||
},
|
||||
|
||||
dataProvider: function(args) {
|
||||
var apiCmd = "listVMSnapshot&listAll=true";
|
||||
if (args.context != null) {
|
||||
if ("instances" in args.context) {
|
||||
apiCmd += "&virtualmachineid=" + args.context.instances[0].id;
|
||||
}
|
||||
}
|
||||
$.ajax({
|
||||
url: createURL(apiCmd),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jsonObj;
|
||||
jsonObj = json.listvmsnapshotresponse.vmSnapshot;
|
||||
args.response.success({
|
||||
data: jsonObj
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
//dataProvider end
|
||||
detailView: {
|
||||
tabs: {
|
||||
details: {
|
||||
title: 'label.details',
|
||||
fields: {
|
||||
id: {
|
||||
label: 'label.id'
|
||||
},
|
||||
name: {
|
||||
label: 'label.name'
|
||||
},
|
||||
displayname: {
|
||||
label: 'label.display.name',
|
||||
},
|
||||
type: {
|
||||
label: 'label.vmsnapshot.type',
|
||||
},
|
||||
description: {
|
||||
label: 'label.description',
|
||||
},
|
||||
state: {
|
||||
label: 'label.state',
|
||||
indicator: {
|
||||
'Ready': 'on',
|
||||
'Error': 'off'
|
||||
}
|
||||
},
|
||||
current: {
|
||||
label: 'label.vmsnapshot.current',
|
||||
converter: cloudStack.converters.toBooleanText
|
||||
},
|
||||
parentName: {
|
||||
label: 'label.vmsnapshot.parentname'
|
||||
},
|
||||
created: {
|
||||
label: 'label.date',
|
||||
converter: cloudStack.converters.toLocalDate
|
||||
},
|
||||
|
||||
},
|
||||
dataProvider: function(args) {
|
||||
$.ajax({
|
||||
url: createURL("listVMSnapshot&listAll=true&id=" + args.context.vmsnapshots[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jsonObj;
|
||||
jsonObj = json.listvmsnapshotresponse.vmSnapshot[0];
|
||||
args.response.success({
|
||||
//actionFilter: vmActionfilter,
|
||||
data: jsonObj
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
tags: cloudStack.api.tags({ resourceType: 'VMSnapshot', contextId: 'vmsnapshots' })
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
//delete a snapshot
|
||||
remove: {
|
||||
label: 'label.action.vmsnapshot.delete',
|
||||
messages: {
|
||||
confirm: function(args) {
|
||||
return 'message.action.vmsnapshot.delete';
|
||||
},
|
||||
notification: function(args) {
|
||||
return 'label.action.vmsnapshot.delete';
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
$.ajax({
|
||||
url: createURL("deleteVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.deletevmsnapshotresponse.jobid;
|
||||
args.response.success(
|
||||
{_custom:
|
||||
{jobId: jid}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
notification: {
|
||||
poll: pollAsyncJobResult
|
||||
}
|
||||
},
|
||||
restart: {
|
||||
label: 'label.action.vmsnapshot.revert',
|
||||
messages: {
|
||||
confirm: function(args) {
|
||||
return 'label.action.vmsnapshot.revert';
|
||||
},
|
||||
notification: function(args) {
|
||||
return 'message.action.vmsnapshot.revert';
|
||||
}
|
||||
},
|
||||
action: function(args) {
|
||||
$.ajax({
|
||||
url: createURL("revertToSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
|
||||
dataType: "json",
|
||||
async: true,
|
||||
success: function(json) {
|
||||
var jid = json.reverttosnapshotresponse.jobid;
|
||||
args.response.success({
|
||||
_custom: {
|
||||
jobId: jid
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
notification: {
|
||||
poll: pollAsyncJobResult
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//detailview end
|
||||
}
|
||||
}
|
||||
})(jQuery, cloudStack);
|
||||
|
|
@ -58,6 +58,8 @@ import com.vmware.vim25.PropertySpec;
|
|||
import com.vmware.vim25.SelectionSpec;
|
||||
import com.vmware.vim25.TraversalSpec;
|
||||
import com.vmware.vim25.VirtualMachineConfigSpec;
|
||||
import com.vmware.vim25.VirtualMachineSnapshotInfo;
|
||||
import com.vmware.vim25.VirtualMachineSnapshotTree;
|
||||
import com.vmware.vim25.VirtualNicManagerNetConfig;
|
||||
import com.vmware.vim25.NasDatastoreInfo;
|
||||
|
||||
|
|
@ -949,4 +951,20 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost {
|
|||
HostRuntimeInfo runtimeInfo = (HostRuntimeInfo)_context.getServiceUtil().getDynamicProperty(_mor, "runtime");
|
||||
return runtimeInfo.getConnectionState() == HostSystemConnectionState.connected;
|
||||
}
|
||||
|
||||
public boolean revertToSnapshot(ManagedObjectReference morSnapshot)
|
||||
throws Exception {
|
||||
ManagedObjectReference morTask = _context.getService()
|
||||
.revertToSnapshot_Task(morSnapshot, _mor, false);
|
||||
String result = _context.getServiceUtil().waitForTask(morTask);
|
||||
if (result.equals("sucess")) {
|
||||
_context.waitForTaskProgressDone(morTask);
|
||||
return true;
|
||||
} else {
|
||||
s_logger.error("VMware revert to snapshot failed due to "
|
||||
+ TaskMO.getTaskFailureInfo(_context, morTask));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -405,6 +405,26 @@ public class VirtualMachineMO extends BaseMO {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean revertToSnapshot(String snapshotName) throws Exception {
|
||||
ManagedObjectReference morSnapshot = getSnapshotMor(snapshotName);
|
||||
if (morSnapshot == null) {
|
||||
s_logger.warn("Unable to find snapshot: " + snapshotName);
|
||||
return false;
|
||||
}
|
||||
ManagedObjectReference morTask = _context.getService()
|
||||
.revertToSnapshot_Task(morSnapshot, _mor, null);
|
||||
String result = _context.getServiceUtil().waitForTask(morTask);
|
||||
if (result.equals("sucess")) {
|
||||
_context.waitForTaskProgressDone(morTask);
|
||||
return true;
|
||||
} else {
|
||||
s_logger.error("VMware revert to snapshot failed due to "
|
||||
+ TaskMO.getTaskFailureInfo(_context, morTask));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean removeAllSnapshots() throws Exception {
|
||||
VirtualMachineSnapshotInfo snapshotInfo = getSnapshotInfo();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue