mirror of https://github.com/apache/cloudstack.git
CLOUDSTACK-684 Support VM Snapshot
This commit is contained in:
parent
1f7eaf3d61
commit
bb7cd90b61
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -123,6 +123,10 @@ public class VolumeTO implements InternalIdentity {
|
|||
public String getOsType() {
|
||||
return guestOsType;
|
||||
}
|
||||
|
||||
public void setPath(String path){
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
|
|
|||
|
|
@ -291,6 +291,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.REVERT";
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -42,7 +42,11 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
|
|||
Migrating(true, "VM is being migrated. host id holds to from host"),
|
||||
Error(false, "VM is in error"),
|
||||
Unknown(false, "VM state is unknown."),
|
||||
Shutdowned(false, "VM is shutdowned from inside");
|
||||
Shutdowned(false, "VM is shutdowned from inside"),
|
||||
RunningSnapshotting(true, "VM is taking a snapshot in running state"),
|
||||
StoppedSnapshotting(true, "VM is taking a snapshot in stopped state"),
|
||||
RevertingToRunning(true, "VM is reverting to snapshot"),
|
||||
RevertingToStopped(true, "VM is reverting to snapshot");
|
||||
|
||||
private final boolean _transitional;
|
||||
String _description;
|
||||
|
|
@ -110,8 +114,24 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
|
|||
s_fsm.addTransition(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging);
|
||||
s_fsm.addTransition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging);
|
||||
s_fsm.addTransition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging);
|
||||
}
|
||||
|
||||
s_fsm.addTransition(State.Running, VirtualMachine.Event.SnapshotRequested, State.RunningSnapshotting);
|
||||
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.SnapshotRequested, State.StoppedSnapshotting);
|
||||
s_fsm.addTransition(State.RunningSnapshotting, VirtualMachine.Event.OperationSucceeded, State.Running);
|
||||
s_fsm.addTransition(State.StoppedSnapshotting, VirtualMachine.Event.OperationSucceeded, State.Stopped);
|
||||
s_fsm.addTransition(State.RunningSnapshotting, VirtualMachine.Event.OperationFailed, State.Running);
|
||||
s_fsm.addTransition(State.StoppedSnapshotting, VirtualMachine.Event.OperationFailed, State.Stopped);
|
||||
|
||||
s_fsm.addTransition(State.Running, VirtualMachine.Event.RevertRequested, State.RevertingToRunning);
|
||||
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.RevertRequested, State.RevertingToStopped);
|
||||
s_fsm.addTransition(State.RevertingToRunning, VirtualMachine.Event.OperationFailed, State.Running);
|
||||
s_fsm.addTransition(State.RevertingToStopped, VirtualMachine.Event.OperationFailed, State.Stopped);
|
||||
s_fsm.addTransition(State.RevertingToRunning, VirtualMachine.Event.OperationSucceeded, State.Running);
|
||||
s_fsm.addTransition(State.RevertingToStopped, VirtualMachine.Event.OperationSucceeded, State.Stopped);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static boolean isVmStarted(State oldState, Event e, State newState) {
|
||||
if (oldState == State.Starting && newState == State.Running) {
|
||||
return true;
|
||||
|
|
@ -173,7 +193,9 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
|
|||
OperationFailedToError,
|
||||
OperationRetry,
|
||||
AgentReportShutdowned,
|
||||
AgentReportMigrated
|
||||
AgentReportMigrated,
|
||||
RevertRequested,
|
||||
SnapshotRequested
|
||||
};
|
||||
|
||||
public enum Type {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
// 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.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,51 @@
|
|||
// 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.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 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(CreateVMSnapshotCmd cmd);
|
||||
|
||||
VMSnapshot allocVMSnapshot(CreateVMSnapshotCmd cmd)
|
||||
throws ResourceAllocationException;
|
||||
|
||||
boolean deleteVMSnapshot(DeleteVMSnapshotCmd cmd);
|
||||
|
||||
UserVm revertToSnapshot(RevertToSnapshotCmd cmd) throws InsufficientServerCapacityException, InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException;
|
||||
|
||||
VirtualMachine getVMBySnapshotId(Long id);
|
||||
}
|
||||
|
|
@ -428,6 +428,11 @@ public class ApiConstants {
|
|||
public static final String COUNTERPARAM_LIST = "counterparam";
|
||||
public static final String AUTOSCALE_USER_ID = "autoscaleuserid";
|
||||
public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername";
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ import com.cloud.utils.Pair;
|
|||
import com.cloud.utils.component.ComponentLocator;
|
||||
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());
|
||||
|
|
@ -122,6 +123,7 @@ public abstract class BaseCmd {
|
|||
public static VpcService _vpcService;
|
||||
public static NetworkACLService _networkACLService;
|
||||
public static Site2SiteVpnService _s2sVpnService;
|
||||
public static VMSnapshotService _vmSnapshotService;
|
||||
|
||||
public static QueryService _queryService;
|
||||
|
||||
|
|
@ -157,6 +159,7 @@ public abstract class BaseCmd {
|
|||
_networkACLService = locator.getManager(NetworkACLService.class);
|
||||
_s2sVpnService = locator.getManager(Site2SiteVpnService.class);
|
||||
_queryService = locator.getManager(QueryService.class);
|
||||
_vmSnapshotService = locator.getManager(VMSnapshotService.class);
|
||||
}
|
||||
|
||||
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ import org.apache.cloudstack.api.response.RemoteAccessVpnResponse;
|
|||
import org.apache.cloudstack.api.response.ResourceCountResponse;
|
||||
import org.apache.cloudstack.api.response.ResourceLimitResponse;
|
||||
import org.apache.cloudstack.api.response.ResourceTagResponse;
|
||||
import org.apache.cloudstack.api.response.S3Response;
|
||||
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||
import org.apache.cloudstack.api.response.ServiceResponse;
|
||||
|
|
@ -84,6 +85,7 @@ import org.apache.cloudstack.api.response.TemplateResponse;
|
|||
import org.apache.cloudstack.api.response.TrafficTypeResponse;
|
||||
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;
|
||||
|
|
@ -92,8 +94,6 @@ 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 com.cloud.async.AsyncJob;
|
||||
import com.cloud.capacity.Capacity;
|
||||
import com.cloud.configuration.Configuration;
|
||||
|
|
@ -159,6 +159,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);
|
||||
|
|
@ -372,4 +373,6 @@ public interface ResponseGenerator {
|
|||
GuestOSResponse createGuestOSResponse(GuestOS os);
|
||||
|
||||
SnapshotScheduleResponse createSnapshotScheduleResponse(SnapshotSchedule sched);
|
||||
|
||||
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, since="4.1.0")
|
||||
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(this);
|
||||
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(this);
|
||||
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,99 @@
|
|||
// 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.log4j.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.BaseCmd;
|
||||
import org.apache.cloudstack.api.BaseCmd.CommandType;
|
||||
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||
import org.apache.cloudstack.api.response.VolumeResponse;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
|
||||
import org.apache.cloudstack.api.response.VMSnapshotResponse;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.storage.Snapshot;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
//import com.cloud.api.ApiDBUtils;
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
public static String getResultObjectName() {
|
||||
return "vm_snapshots";
|
||||
}
|
||||
|
||||
@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(this);
|
||||
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,105 @@
|
|||
// 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 java.util.logging.Logger;
|
||||
|
||||
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.command.admin.host.ListHostsCmd;
|
||||
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, since = "4.1.0")
|
||||
public class ListVMSnapshotCmd extends BaseListTaggedResourcesCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(ListHostsCmd.class
|
||||
.getName());
|
||||
|
||||
private static final String s_name = "listvmsnapshotresponse";
|
||||
|
||||
// ///////////////////////////////////////////////////
|
||||
// ////////////// API parameters /////////////////////
|
||||
// ///////////////////////////////////////////////////
|
||||
|
||||
@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;
|
||||
|
||||
// ///////////////////////////////////////////////////
|
||||
// ///////////////// Accessors ///////////////////////
|
||||
// ///////////////////////////////////////////////////
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getVmSnapshotName() {
|
||||
return vmSnapshotName;
|
||||
}
|
||||
|
||||
public Long getVmId() {
|
||||
return vmId;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
// ///////////////////////////////////////////////////
|
||||
// ///////////// API Implementation///////////////////
|
||||
// ///////////////////////////////////////////////////
|
||||
|
||||
@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,98 @@
|
|||
// 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.InvalidParameterValueException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
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;
|
||||
}
|
||||
|
||||
public static String getResultObjectName() {
|
||||
return "vm_snapshots";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
VMSnapshot vmSnapshot = _vmSnapshotService.getVMSnapshotById(getVmSnapShotId());
|
||||
if (vmSnapshot == null) {
|
||||
throw new InvalidParameterValueException(
|
||||
"Unable to find the snapshot by id=" + getVmSnapShotId());
|
||||
}
|
||||
UserVm userVM = _userVmService.getUserVm(vmSnapshot.getVmId());
|
||||
return userVM.getAccountId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException, ConcurrentOperationException {
|
||||
UserContext.current().setEventDetails(
|
||||
"vmsnapshot id: " + getVmSnapShotId());
|
||||
UserVm result = _vmSnapshotService.revertToSnapshot(this);
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1408,6 +1408,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.
|
||||
|
|
|
|||
|
|
@ -514,3 +514,9 @@ listApis=15
|
|||
|
||||
getApiLimit=15
|
||||
resetApiLimit=1
|
||||
|
||||
### VM Snapshot commands
|
||||
listVMSnapshot=15
|
||||
createVMSnapshot=15
|
||||
deleteVMSnapshot=15
|
||||
revertToSnapshot=15
|
||||
|
|
|
|||
|
|
@ -0,0 +1,224 @@
|
|||
// 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 java.util.UUID;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.TableGenerator;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
@Entity
|
||||
@Table(name = "vm_snapshots")
|
||||
public class VMSnapshotVO implements VMSnapshot {
|
||||
@Id
|
||||
@TableGenerator(name = "vm_snapshots_sq", table = "sequence", pkColumnName = "name", valueColumnName = "value", pkColumnValue = "vm_snapshots_seq", allocationSize = 1)
|
||||
@GeneratedValue(strategy = GenerationType.TABLE)
|
||||
@Column(name = "id")
|
||||
long id;
|
||||
|
||||
@Column(name = "uuid")
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
|
||||
@Column(name = "name")
|
||||
String name;
|
||||
|
||||
@Column(name = "display_name")
|
||||
String displayName;
|
||||
|
||||
@Column(name = "description")
|
||||
String description;
|
||||
|
||||
@Column(name = "vm_id")
|
||||
long vmId;
|
||||
|
||||
@Column(name = "account_id")
|
||||
long accountId;
|
||||
|
||||
@Column(name = "domain_id")
|
||||
long domainId;
|
||||
|
||||
@Column(name = "vm_snapshot_type")
|
||||
@Enumerated(EnumType.STRING)
|
||||
VMSnapshot.Type type;
|
||||
|
||||
@Column(name = "state", updatable = true, nullable = false)
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
private State state;
|
||||
|
||||
@Column(name = GenericDao.CREATED_COLUMN)
|
||||
Date created;
|
||||
|
||||
@Column(name = GenericDao.REMOVED_COLUMN)
|
||||
Date removed;
|
||||
|
||||
@Column(name = "current")
|
||||
Boolean current;
|
||||
|
||||
@Column(name = "parent")
|
||||
Long parent;
|
||||
|
||||
@Column(name = "updated")
|
||||
@Temporal(value = TemporalType.TIMESTAMP)
|
||||
Date updated;
|
||||
|
||||
@Column(name="update_count", updatable = true, nullable=false)
|
||||
protected long updatedCount;
|
||||
|
||||
public Long getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(Long parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public VMSnapshotVO() {
|
||||
|
||||
}
|
||||
|
||||
public Date getRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
public VMSnapshotVO(Long accountId, Long domainId, Long vmId,
|
||||
String description, String vmSnapshotName, String vsDisplayName,
|
||||
Long serviceOfferingId, Type type, Boolean current) {
|
||||
this.accountId = accountId;
|
||||
this.domainId = domainId;
|
||||
this.vmId = vmId;
|
||||
this.state = State.Allocated;
|
||||
this.description = description;
|
||||
this.name = vmSnapshotName;
|
||||
this.displayName = vsDisplayName;
|
||||
this.type = type;
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getVmId() {
|
||||
return vmId;
|
||||
}
|
||||
|
||||
public void setVmId(Long vmId) {
|
||||
this.vmId = vmId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDomainId() {
|
||||
return domainId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public Boolean getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public void setCurrent(Boolean current) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUpdatedCount() {
|
||||
return updatedCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrUpdatedCount() {
|
||||
this.updatedCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getUpdated() {
|
||||
return updated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setRemoved(Date removed) {
|
||||
this.removed = removed;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -138,8 +144,8 @@ import com.cloud.agent.api.routing.SetNetworkACLCommand;
|
|||
import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer;
|
||||
import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
|
||||
import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand;
|
||||
import com.cloud.agent.api.routing.SetSourceNatCommand;
|
||||
import com.cloud.agent.api.routing.SetSourceNatAnswer;
|
||||
import com.cloud.agent.api.routing.SetSourceNatCommand;
|
||||
import com.cloud.agent.api.routing.SetStaticNatRulesAnswer;
|
||||
import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
|
||||
import com.cloud.agent.api.routing.Site2SiteVpnCfgCommand;
|
||||
|
|
@ -442,7 +448,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);
|
||||
|
|
@ -2718,7 +2730,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);
|
||||
|
|
@ -3270,7 +3281,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));
|
||||
|
|
|
|||
|
|
@ -87,9 +87,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;
|
||||
|
|
@ -126,6 +130,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;
|
||||
|
|
@ -234,6 +240,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;
|
||||
|
|
@ -253,6 +260,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;
|
||||
|
|
@ -570,11 +581,109 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||
return execute((Site2SiteVpnCfgCommand) cmd);
|
||||
} else if (clazz == CheckS2SVpnConnectionsCommand.class) {
|
||||
return execute((CheckS2SVpnConnectionsCommand) 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()) {
|
||||
|
|
@ -6138,6 +6247,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})
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.util.EnumSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.apache.cloudstack.api.ApiConstants.HostDetails;
|
||||
import org.apache.cloudstack.api.ApiConstants.VMDetails;
|
||||
|
|
@ -259,6 +260,8 @@ import com.cloud.vm.dao.UserVmDao;
|
|||
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
public class ApiDBUtils {
|
||||
private static ManagementServer _ms;
|
||||
|
|
@ -357,7 +360,7 @@ public class ApiDBUtils {
|
|||
private static VpcOfferingDao _vpcOfferingDao;
|
||||
private static SnapshotPolicyDao _snapshotPolicyDao;
|
||||
private static AsyncJobDao _asyncJobDao;
|
||||
|
||||
private static VMSnapshotDao _vmSnapshotDao;
|
||||
static {
|
||||
_ms = (ManagementServer) ComponentLocator.getComponent(ManagementServer.Name);
|
||||
ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name);
|
||||
|
|
@ -454,7 +457,7 @@ public class ApiDBUtils {
|
|||
_diskOfferingJoinDao = locator.getDao(DiskOfferingJoinDao.class);
|
||||
_srvOfferingJoinDao = locator.getDao(ServiceOfferingJoinDao.class);
|
||||
_dcJoinDao = locator.getDao(DataCenterJoinDao.class);
|
||||
|
||||
_vmSnapshotDao = locator.getDao(VMSnapshotDao.class);
|
||||
// Note: stats collector should already have been initialized by this time, otherwise a null instance is returned
|
||||
_statsCollector = StatsCollector.getInstance();
|
||||
}
|
||||
|
|
@ -1003,6 +1006,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,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 com.cloud.async.AsyncJob;
|
||||
import com.cloud.capacity.Capacity;
|
||||
|
|
@ -242,8 +241,15 @@ import com.cloud.vm.InstanceGroup;
|
|||
import com.cloud.vm.NicProfile;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachine.Type;
|
||||
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;
|
||||
|
||||
public class ApiResponseHelper implements ResponseGenerator {
|
||||
public class ApiResponseHelper implements ResponseGenerator{
|
||||
|
||||
public final Logger s_logger = Logger.getLogger(ApiResponseHelper.class);
|
||||
private static final DecimalFormat s_percentFormat = new DecimalFormat("##.##");
|
||||
|
|
@ -393,6 +399,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();
|
||||
|
|
@ -3098,7 +3123,6 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public GuestOSResponse createGuestOSResponse(GuestOS guestOS) {
|
||||
GuestOSResponse response = new GuestOSResponse();
|
||||
|
|
@ -3136,6 +3160,4 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
response.setObjectName("snapshot");
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,9 +60,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;
|
||||
|
|
@ -76,7 +78,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;
|
||||
|
||||
@Local(value = CapacityManager.class)
|
||||
public class CapacityManagerImpl implements CapacityManager, StateListener<State, VirtualMachine.Event, VirtualMachine>, Listener, ResourceListener {
|
||||
|
|
@ -108,7 +114,11 @@ public class CapacityManagerImpl implements CapacityManager, StateListener<State
|
|||
ConfigurationManager _configMgr;
|
||||
@Inject
|
||||
HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
|
||||
|
||||
@Inject
|
||||
protected VMSnapshotDao _vmSnapshotDao;
|
||||
@Inject
|
||||
protected UserVmDao _userVMDao;
|
||||
|
||||
private int _vmCapacityReleaseInterval;
|
||||
private ScheduledExecutorService _executor;
|
||||
private boolean _stopped;
|
||||
|
|
@ -441,12 +451,43 @@ public class CapacityManagerImpl implements CapacityManager, StateListener<State
|
|||
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
|
|
@ -364,8 +365,17 @@ public enum Config {
|
|||
ExternalBaremetalResourceClassName("Advanced", ManagementServer.class, String.class, "external,baremetal.resource.classname", null, "class name for handling external baremetal resource", null),
|
||||
EnableBaremetalSecurityGroupAgentEcho("Advanced", ManagementServer.class, Boolean.class, "enable.baremetal.securitygroup.agent.echo", "false", "After starting provision process, periodcially echo security agent installed in the template. Treat provisioning as success only if echo successfully", null),
|
||||
IntervalToEchoBaremetalSecurityGroupAgent("Advanced", ManagementServer.class, Integer.class, "interval.baremetal.securitygroup.agent.echo", "10", "Interval to echo baremetal security group agent, in seconds", null),
|
||||
TimeoutToEchoBaremetalSecurityGroupAgent("Advanced", ManagementServer.class, Integer.class, "timeout.baremetal.securitygroup.agent.echo", "3600", "Timeout to echo baremetal security group agent, in seconds, the provisioning process will be treated as a failure", null);
|
||||
TimeoutToEchoBaremetalSecurityGroupAgent("Advanced", ManagementServer.class, Integer.class, "timeout.baremetal.securitygroup.agent.echo", "3600", "Timeout to echo baremetal security group agent, in seconds, the provisioning process will be treated as a failure", 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;
|
||||
|
|
|
|||
|
|
@ -229,8 +229,8 @@ import com.cloud.vm.dao.UserVmDaoImpl;
|
|||
import com.cloud.vm.dao.UserVmDetailsDaoImpl;
|
||||
import com.cloud.vm.dao.VMInstanceDaoImpl;
|
||||
import com.cloud.event.dao.EventJoinDaoImpl;
|
||||
|
||||
|
||||
import com.cloud.vm.snapshot.VMSnapshotManagerImpl;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl;
|
||||
|
||||
public class DefaultComponentLibrary extends ComponentLibraryBase implements ComponentLibrary {
|
||||
protected void populateDaos() {
|
||||
|
|
@ -380,7 +380,6 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
|
|||
addDao("Site2SiteVpnGatewayDao", Site2SiteVpnGatewayDaoImpl.class);
|
||||
addDao("Site2SiteCustomerGatewayDao", Site2SiteCustomerGatewayDaoImpl.class);
|
||||
addDao("Site2SiteVpnConnnectionDao", Site2SiteVpnConnectionDaoImpl.class);
|
||||
|
||||
addDao("UserVmJoinDao", UserVmJoinDaoImpl.class);
|
||||
addDao("DomainRouterJoinDao", DomainRouterJoinDaoImpl.class);
|
||||
addDao("SecurityGroupJoinDao", SecurityGroupJoinDaoImpl.class);
|
||||
|
|
@ -398,6 +397,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
|
|||
addDao("DiskOfferingJoinDao", DiskOfferingJoinDaoImpl.class);
|
||||
addDao("ServiceOfferingJoinDao", ServiceOfferingJoinDaoImpl.class);
|
||||
addDao("DataCenterJoinDao", DataCenterJoinDaoImpl.class);
|
||||
addDao("VMSnapshotDao", VMSnapshotDaoImpl.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -462,6 +462,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
|
|||
addManager("TaggedResourcesManager", TaggedResourceManagerImpl.class);
|
||||
addManager("Site2SiteVpnManager", Site2SiteVpnManagerImpl.class);
|
||||
addManager("QueryManager", QueryManagerImpl.class);
|
||||
addManager("VMSnapshot Manager", VMSnapshotManagerImpl.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1292,7 +1292,7 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma
|
|||
|
||||
for (ClusterVO cluster : clustersForZone) {
|
||||
HypervisorType hType = cluster.getHypervisorType();
|
||||
if (!forVirtualRouter || (forVirtualRouter && hType != HypervisorType.BareMetal && hType != HypervisorType.Ovm)) {
|
||||
if ( (cluster.getAllocationState() == AllocationState.Enabled) && (!forVirtualRouter || (forVirtualRouter && hType != HypervisorType.BareMetal && hType != HypervisorType.Ovm))) {
|
||||
hypervisorTypes.add(hType);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,9 @@ import com.cloud.vm.VMInstanceVO;
|
|||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshot;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
@Local(value = { SnapshotManager.class, SnapshotService.class })
|
||||
public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Manager {
|
||||
|
|
@ -188,7 +191,8 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
|
|||
private VolumeDao _volumeDao;
|
||||
@Inject
|
||||
private ResourceTagDao _resourceTagDao;
|
||||
|
||||
@Inject
|
||||
protected VMSnapshotDao _vmSnapshotDao;
|
||||
String _name;
|
||||
private int _totalRetries;
|
||||
private int _pauseInterval;
|
||||
|
|
@ -401,6 +405,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
|
|||
}
|
||||
|
||||
// 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) {
|
||||
|
|
@ -414,6 +419,12 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
|
|||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,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;
|
||||
|
||||
|
||||
@Local(value = { TaggedResourceService.class})
|
||||
|
|
@ -119,6 +120,8 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager
|
|||
VpcDao _vpcDao;
|
||||
@Inject
|
||||
StaticRouteDao _staticRouteDao;
|
||||
@Inject
|
||||
VMSnapshotDao _vmSnapshotDao;
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
|
|
@ -138,6 +141,7 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager
|
|||
_daoMap.put(TaggedResourceType.Vpc, _vpcDao);
|
||||
_daoMap.put(TaggedResourceType.NetworkACL, _firewallDao);
|
||||
_daoMap.put(TaggedResourceType.StaticRoute, _staticRouteDao);
|
||||
_daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,16 @@ 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 implements UserVmManager, UserVmService, Manager {
|
||||
|
|
@ -275,7 +285,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
PhysicalNetworkDao _physicalNetworkDao;
|
||||
@Inject
|
||||
VpcManager _vpcMgr;
|
||||
|
||||
@Inject
|
||||
VMSnapshotDao _vmSnapshotDao;
|
||||
@Inject
|
||||
protected VMSnapshotManager _vmSnapshotMgr;
|
||||
|
||||
protected ScheduledExecutorService _executor = null;
|
||||
protected int _expungeInterval;
|
||||
protected int _expungeDelay;
|
||||
|
|
@ -517,6 +531,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
//permission check
|
||||
_accountMgr.checkAccess(caller, null, true, volume, vm);
|
||||
|
||||
//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.
|
||||
boolean isVolumeOnSec = false;
|
||||
VolumeHostVO volHostVO = _volumeHostDao.findByVolumeId(volume.getId());
|
||||
|
|
@ -725,8 +742,19 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true)
|
||||
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 = "event_detaching_volume1", async = true)
|
||||
public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) {
|
||||
Account caller = UserContext.current().getCaller();
|
||||
if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd.getVirtualMachineId() == null) || (cmmd.getId() != null && (cmmd.getDeviceId() != null || cmmd.getVirtualMachineId() != null))
|
||||
|
|
@ -775,6 +803,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
throw new InvalidParameterValueException("Please specify a VM that is either running or stopped.");
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
|
@ -905,12 +936,25 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
if (vmInstance == null) {
|
||||
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());
|
||||
|
|
@ -1293,7 +1337,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
}
|
||||
|
||||
volume = _volsDao.findById(snapshot.getVolumeId());
|
||||
VolumeVO snapshotVolume = _volsDao.findByIdIncludingRemoved(snapshot.getVolumeId());
|
||||
|
||||
//check permissions
|
||||
_accountMgr.checkAccess(caller, null, true, snapshot);
|
||||
|
|
|
|||
|
|
@ -154,12 +154,17 @@ import com.cloud.utils.fsm.StateMachine2;
|
|||
import com.cloud.vm.ItWorkVO.Step;
|
||||
import com.cloud.vm.VirtualMachine.Event;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.VirtualMachineProfile.Param;
|
||||
import com.cloud.vm.dao.ConsoleProxyDao;
|
||||
import com.cloud.vm.dao.DomainRouterDao;
|
||||
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 implements VirtualMachineManager, Listener {
|
||||
|
|
@ -230,6 +235,8 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
protected HypervisorGuruManager _hvGuruMgr;
|
||||
@Inject
|
||||
protected NetworkDao _networkDao;
|
||||
@Inject
|
||||
protected VMSnapshotDao _vmSnapshotDao;
|
||||
|
||||
@Inject(adapter = DeploymentPlanner.class)
|
||||
protected Adapters<DeploymentPlanner> _planners;
|
||||
|
|
@ -239,6 +246,9 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
|
||||
@Inject
|
||||
protected ResourceManager _resourceMgr;
|
||||
|
||||
@Inject
|
||||
protected VMSnapshotManager _vmSnapshotMgr = null;
|
||||
|
||||
Map<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>> _vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>>();
|
||||
protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
|
||||
|
|
@ -599,7 +609,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
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 {
|
||||
|
|
@ -1186,7 +1196,12 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
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);
|
||||
|
|
@ -1633,6 +1648,23 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
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> expungingVMSnapshot = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging);
|
||||
if( vm.getState() == State.RevertingToRunning || vm.getState() == State.RevertingToStopped
|
||||
|| vm.getState() == State.RunningSnapshotting || vm.getState() == State.StoppedSnapshotting
|
||||
|| expungingVMSnapshot.size() == 1){
|
||||
s_logger.info("Found vm " + vm.getInstanceName() + " in state. " + vm.getState() + ", needs to sync VM snapshot state");
|
||||
if(!_vmSnapshotMgr.syncVMSnapshot(vm, null, hostId)){
|
||||
s_logger.warn("Failed to sync VM in a transient snapshot related state: " + vm.getInstanceName());
|
||||
continue;
|
||||
}else{
|
||||
s_logger.info("Successfully sync VM in a transient snapshot related state: " + vm.getInstanceName() + " to " + vm.getState());
|
||||
}
|
||||
if(expungingVMSnapshot.size() == 1)
|
||||
_vmSnapshotMgr.syncVMSnapshot(vm, expungingVMSnapshot.get(0), hostId);
|
||||
}
|
||||
|
||||
VMInstanceVO castedVm = null;
|
||||
if (info == null) {
|
||||
info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);
|
||||
|
|
@ -1750,8 +1782,31 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
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> expungingVMSnapshot = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging);
|
||||
if( vm.getState() == State.RevertingToRunning || vm.getState() == State.RevertingToStopped
|
||||
|| vm.getState() == State.RunningSnapshotting || vm.getState() == State.StoppedSnapshotting
|
||||
|| expungingVMSnapshot.size() == 1){
|
||||
s_logger.info("Found vm " + vm.getInstanceName() + " in state. " + vm.getState() + ", needs to sync VM snapshot state");
|
||||
Long hostId = null;
|
||||
if(info != null && info.getHostUuid() != null){
|
||||
Host host = _hostDao.findByGuid(info.getHostUuid());
|
||||
hostId = host == null ? (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId()) : host.getId();
|
||||
}
|
||||
if(!_vmSnapshotMgr.syncVMSnapshot(vm, null, hostId)){
|
||||
s_logger.warn("Failed to sync VM in a transient snapshot related state: " + vm.getInstanceName());
|
||||
continue;
|
||||
}else{
|
||||
s_logger.info("Successfully sync VM in a transient snapshot related state: " + vm.getInstanceName() + " to " + vm.getState());
|
||||
}
|
||||
if(expungingVMSnapshot.size() == 1)
|
||||
_vmSnapshotMgr.syncVMSnapshot(vm, expungingVMSnapshot.get(0), hostId);
|
||||
}
|
||||
|
||||
if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting ))
|
||||
|| (info != null && (info.state == State.Running && vm.getState() == State.Starting))
|
||||
|| (info != null && (info.state == State.Running && vm.getState() == State.RevertingToRunning)))
|
||||
{
|
||||
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);
|
||||
|
|
@ -1792,7 +1847,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
}
|
||||
}
|
||||
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);
|
||||
|
|
@ -2267,6 +2322,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
|
||||
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();
|
||||
|
|
@ -2383,7 +2439,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
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,46 @@
|
|||
// 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's state when VM in reverting or snapshotting, or VM snapshot in expunging state
|
||||
* Used for fullsync after agent connects
|
||||
*
|
||||
* @param vm, the VM in question
|
||||
* @param vmSnapshot, if this is not null, sync an VM snapshot in expunging state
|
||||
* @param hostId
|
||||
* @return true if succeeds, false if fails
|
||||
*/
|
||||
boolean syncVMSnapshot(VMInstanceVO vm, VMSnapshotVO vmSnapshot, Long hostId);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,828 @@
|
|||
// 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.naming.ConfigurationException;
|
||||
|
||||
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.log4j.Logger;
|
||||
|
||||
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.service.dao.ServiceOfferingDao;
|
||||
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.Pair;
|
||||
import com.cloud.utils.Ternary;
|
||||
import com.cloud.utils.component.ComponentLocator;
|
||||
import com.cloud.utils.component.Inject;
|
||||
import com.cloud.utils.component.Manager;
|
||||
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;
|
||||
|
||||
@Local(value = { VMSnapshotManager.class, VMSnapshotService.class })
|
||||
public class VMSnapshotManagerImpl implements VMSnapshotManager, VMSnapshotService, Manager {
|
||||
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<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
|
||||
StateMachine2<VMSnapshot.State, VMSnapshot.Event, VMSnapshot> _vmSnapshottateMachine ;
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
_name = name;
|
||||
|
||||
ComponentLocator locator = ComponentLocator.getCurrentLocator();
|
||||
_configDao = locator.getDao(ConfigurationDao.class);
|
||||
if (_configDao == null) {
|
||||
throw new ConfigurationException("Unable to get the configuration dao.");
|
||||
}
|
||||
s_logger.info("Snapshot Manager is configured.");
|
||||
|
||||
_vmSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("vmsnapshot.max"), VMSNAPSHOTMAX);
|
||||
|
||||
_stateMachine = VirtualMachine.State.getStateMachine();
|
||||
_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(CreateVMSnapshotCmd cmd) throws ResourceAllocationException {
|
||||
Long vmId = cmd.getVmId();
|
||||
String vsDisplayName = cmd.getDisplayName();
|
||||
String vsDescription = cmd.getDescription();
|
||||
Boolean snapshotMemory = cmd.snapshotMemory();
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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.Status.Creating,
|
||||
Snapshot.Status.CreatedOnPrimary, Snapshot.Status.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 (checkActiveVMSnapshotTasks(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(CreateVMSnapshotCmd cmd) {
|
||||
Long vmId = cmd.getVmId();
|
||||
UserVmVO userVm = _userVMDao.findById(vmId);
|
||||
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(cmd.getEntityId());
|
||||
Long hostId = pickRunningHost(vmId);
|
||||
transitState(vmSnapshot, VMSnapshot.Event.CreateRequested, userVm, VirtualMachine.Event.SnapshotRequested, hostId);
|
||||
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);
|
||||
transitState(vmSnapshot, VMSnapshot.Event.OperationSucceeded, userVm, VirtualMachine.Event.OperationSucceeded, 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);
|
||||
transitState(vmSnapshot, VMSnapshot.Event.OperationFailed, userVm, VirtualMachine.Event.OperationFailed, hostId);
|
||||
}
|
||||
return vmSnapshot;
|
||||
} catch (Exception e) {
|
||||
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);
|
||||
}
|
||||
|
||||
private boolean vmSnapshotStateTransitTo(VMSnapshotVO vsnp, VMSnapshot.Event event) throws NoTransitionException {
|
||||
return _vmSnapshottateMachine.transitTo(vsnp, event, null, _vmSnapshotDao);
|
||||
}
|
||||
|
||||
@DB
|
||||
protected boolean transitState(VMSnapshotVO vsnp, VMSnapshot.Event e1, VMInstanceVO vm, VirtualMachine.Event e2, Long hostId){
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
try {
|
||||
txn.start();
|
||||
vmSnapshotStateTransitTo(vsnp, e1);
|
||||
vmStateTransitTo(vm, e2, hostId, null);
|
||||
return txn.commit();
|
||||
} catch (NoTransitionException e) {
|
||||
txn.rollback();
|
||||
return false;
|
||||
}finally{
|
||||
txn.close();
|
||||
}
|
||||
}
|
||||
|
||||
@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());
|
||||
} else if (as instanceof RevertToVMSnapshotAnswer) {
|
||||
RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as;
|
||||
finalizeRevert(vmSnapshot, answer.getVolumeTOs());
|
||||
} 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());
|
||||
previousCurrent.setCurrent(false);
|
||||
vmSnapshot.setCurrent(true);
|
||||
_vmSnapshotDao.persist(previousCurrent);
|
||||
_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;
|
||||
}
|
||||
|
||||
private boolean checkActiveVMSnapshotTasks(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_snapshot", async=true)
|
||||
public boolean deleteVMSnapshot(DeleteVMSnapshotCmd cmd) {
|
||||
Long vmSnapshotId = cmd.getId();
|
||||
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.Error != vmSnapshot.getState()) {
|
||||
throw new InvalidParameterValueException("Can't delete the vm snapshotshot " + vmSnapshotId + " due to it is not in Created or Error State");
|
||||
}
|
||||
|
||||
// check if there are other active VM snapshot tasks
|
||||
if (checkActiveVMSnapshotTasks(vmSnapshot.getVmId())) {
|
||||
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);
|
||||
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_vm", async = true)
|
||||
public UserVm revertToSnapshot(RevertToSnapshotCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException {
|
||||
|
||||
Long vmSnapshotId = cmd.getVmSnapShotId();
|
||||
|
||||
// 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 (checkActiveVMSnapshotTasks(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 (checkActiveVMSnapshotTasks(userVm.getId())) {
|
||||
throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later");
|
||||
}
|
||||
|
||||
userVm = _userVMDao.findById(userVm.getId());
|
||||
transitState(vmSnapshotVo, VMSnapshot.Event.RevertRequested, userVm, VirtualMachine.Event.RevertRequested, hostId);
|
||||
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.getResult()) {
|
||||
processAnswer(vmSnapshotVo, userVm, answer, hostId);
|
||||
transitState(vmSnapshotVo, VMSnapshot.Event.OperationSucceeded, userVm, VirtualMachine.Event.OperationSucceeded, hostId);
|
||||
} 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
|
||||
transitState(vmSnapshotVo, VMSnapshot.Event.OperationFailed, userVm, VirtualMachine.Event.OperationFailed, hostId);
|
||||
throw new CloudRuntimeException(errMsg);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// for other exceptions, do not change VM 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;
|
||||
}
|
||||
|
||||
private boolean vmStateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId, String reservationId) throws NoTransitionException {
|
||||
vm.setReservationId(reservationId);
|
||||
return _stateMachine.transitTo(vm, e, new Pair<Long, Long>(vm.getHostId(), hostId), _vmInstanceDao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VMSnapshot getVMSnapshotById(long id) {
|
||||
VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id);
|
||||
return vmSnapshot;
|
||||
}
|
||||
|
||||
private 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);
|
||||
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) {
|
||||
if(type != null && snapshot.getType() != type)
|
||||
continue;
|
||||
if (!deleteSnapshotInternal(snapshot)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean syncVMSnapshot(VMInstanceVO vm, VMSnapshotVO vmSnapshot, Long hostId) {
|
||||
try{
|
||||
|
||||
UserVmVO userVm = _userVMDao.findById(vm.getId());
|
||||
if(userVm == null)
|
||||
return false;
|
||||
if(userVm.getState() == State.RevertingToRunning || userVm.getState() == State.RevertingToStopped){
|
||||
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(), VMSnapshot.State.Reverting);
|
||||
if(vmSnapshots.size() != 1){
|
||||
s_logger.error("VM:" + userVm.getInstanceName()+ " expected to have one VM snapshot in reverting state but actually has " + vmSnapshots.size());
|
||||
return false;
|
||||
}
|
||||
// send revert command again
|
||||
revertInternal(userVm, vmSnapshots.get(0), hostId);
|
||||
return true;
|
||||
}else if (userVm.getState() == State.RunningSnapshotting || userVm.getState() == State.StoppedSnapshotting){
|
||||
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(), VMSnapshot.State.Creating);
|
||||
if(vmSnapshots.size() != 1){
|
||||
s_logger.error("VM:" + userVm.getInstanceName()+ " expected to have one VM snapshot in creating state but actually has " + vmSnapshots.size());
|
||||
return false;
|
||||
}
|
||||
// send create vm snapshot command again
|
||||
createVmSnapshotInternal(userVm, vmSnapshots.get(0), hostId);
|
||||
return true;
|
||||
|
||||
}else if (vmSnapshot != null && vmSnapshot.getState() == VMSnapshot.State.Expunging){
|
||||
return deleteSnapshotInternal(vmSnapshot);
|
||||
}
|
||||
}catch (Exception e) {
|
||||
s_logger.error(e.getMessage(),e);
|
||||
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,160 @@
|
|||
// 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 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;
|
||||
|
||||
@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,182 @@
|
|||
// 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.List;
|
||||
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd;
|
||||
import org.junit.Test;
|
||||
|
||||
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.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.uservm.UserVm;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
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.VirtualMachineManager;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import org.junit.Before;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
@Mock CreateVMSnapshotCmd createCmd;
|
||||
|
||||
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(createCmd.getVmId()).thenReturn(TEST_VM_ID);
|
||||
when(createCmd.getDisplayName()).thenReturn("testName");
|
||||
|
||||
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(createCmd);
|
||||
}
|
||||
|
||||
// vm state not in [running, stopped] case
|
||||
@Test(expected=InvalidParameterValueException.class)
|
||||
public void testAllocVMSnapshotF2() throws ResourceAllocationException{
|
||||
when(vmMock.getState()).thenReturn(State.Starting);
|
||||
_vmSnapshotMgr.allocVMSnapshot(createCmd);
|
||||
}
|
||||
|
||||
// max snapshot limit case
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test(expected=CloudRuntimeException.class)
|
||||
public void testAllocVMSnapshotF3() throws ResourceAllocationException{
|
||||
List<VMSnapshotVO> mockList = mock(List.class);
|
||||
when(mockList.size()).thenReturn(10);
|
||||
when(_vmSnapshotDao.findByVm(TEST_VM_ID)).thenReturn(mockList);
|
||||
_vmSnapshotMgr.allocVMSnapshot(createCmd);
|
||||
}
|
||||
|
||||
// active volume snapshots case
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test(expected=CloudRuntimeException.class)
|
||||
public void testAllocVMSnapshotF4() throws ResourceAllocationException{
|
||||
List<SnapshotVO> mockList = mock(List.class);
|
||||
when(mockList.size()).thenReturn(1);
|
||||
when(_snapshotDao.listByInstanceId(TEST_VM_ID,Snapshot.Status.Creating,
|
||||
Snapshot.Status.CreatedOnPrimary, Snapshot.Status.BackingUp)).thenReturn(mockList);
|
||||
_vmSnapshotMgr.allocVMSnapshot(createCmd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateVMSnapshot() throws AgentUnavailableException, OperationTimedoutException{
|
||||
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));
|
||||
doReturn(true).when(_vmSnapshotMgr).transitState(any(VMSnapshotVO.class),
|
||||
any(VMSnapshot.Event.class), any(VMInstanceVO.class), any(VirtualMachine.Event.class), anyLong());
|
||||
doNothing().when(_vmSnapshotMgr).processAnswer(any(VMSnapshotVO.class),
|
||||
any(UserVmVO.class), any(Answer.class), anyLong());
|
||||
_vmSnapshotMgr.createVmSnapshotInternal(vmMock, mock(VMSnapshotVO.class), 5L);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2543,6 +2543,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;
|
||||
|
||||
|
||||
SET foreign_key_checks = 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -1931,7 +1931,7 @@ div.detail-group.actions td {
|
|||
}
|
||||
|
||||
.detail-group table td.detail-actions {
|
||||
width: 55%;
|
||||
width: 59%;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1431,6 +1431,16 @@ dictionary = {
|
|||
'label.delete.NiciraNvp': '<fmt:message key="label.delete.NiciraNvp" />',
|
||||
'label.nicira.controller.address': '<fmt:message key="label.nicira.controller.address" />',
|
||||
'label.nicira.transportzoneuuid': '<fmt:message key="label.nicira.transportzoneuuid" />',
|
||||
'label.nicira.l3gatewayserviceuuid': '<fmt:message key="label.nicira.l3gatewayserviceuuid" />'
|
||||
'label.nicira.l3gatewayserviceuuid': '<fmt:message key="label.nicira.l3gatewayserviceuuid" />',
|
||||
'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>
|
||||
|
|
|
|||
|
|
@ -1673,6 +1673,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,15 @@
|
|||
displayname: { label: 'label.display.name' },
|
||||
zonename: { label: 'label.zone.name' },
|
||||
state: {
|
||||
label: 'label.state',
|
||||
label: 'label.state',
|
||||
converter: function(data) {
|
||||
if(data == 'StoppedSnapshotting' || data == 'RunningSnapshotting')
|
||||
return 'Snapshotting';
|
||||
if(data == 'RevertingToRunning' || data == 'RevertingToStopped'){
|
||||
return 'Reverting';
|
||||
}
|
||||
return data;
|
||||
},
|
||||
indicator: {
|
||||
'Running': 'on',
|
||||
'Stopped': 'off',
|
||||
|
|
@ -153,6 +161,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 +427,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 +605,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 +1492,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 +1518,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