diff --git a/LICENSE b/LICENSE index 73bc738391f..5e29e2b12bc 100644 --- a/LICENSE +++ b/LICENSE @@ -180,7 +180,6 @@ Copyright (c) 2013 The Apache Software Foundation This distribution contains third party resources. - Within the . directory licensed under the BSD (3-clause) http://www.opensource.org/licenses/BSD-3-Clause (as follows) @@ -209,10 +208,9 @@ Within the . directory CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - + from Thomas Nagy http://code.google.com/p/waf/ - waf - + waf Within the awsapi directory licensed under the BSD (3-clause) http://www.opensource.org/licenses/BSD-3-Clause (as follows) @@ -242,10 +240,9 @@ Within the awsapi directory CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - + from Thomas Nagy http://code.google.com/p/waf/ - waf - + waf Within the console-proxy/js directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -270,10 +267,9 @@ Within the console-proxy/js directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from John Resig - jquery.js - + jquery.js Within the deps directory licensed under the BSD (2-clause) for XenServerJava http://www.opensource.org/licenses/BSD-2-Clause (as follows) @@ -304,28 +300,27 @@ Within the deps directory THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - + from Citrix Systems, Inc http://www.citrix.com/ - XenServerJava http://community.citrix.com/cdn/xs/sdks/ - + XenServerJava from http://community.citrix.com/cdn/xs/sdks/ Within the patches/systemvm/debian/config/etc directory placed in the public domain + by Adiscon GmbH http://www.adiscon.com/ + rsyslog.conf by Simon Kelley - dnsmasq.conf - vpcdnsmasq.conf - + dnsmasq.conf + vpcdnsmasq.conf Within the patches/systemvm/debian/config/etc/apache2 directory licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above) Copyright (c) 2012 The Apache Software Foundation from The Apache Software Foundation http://www.apache.org/ - httpd.conf - ports.conf - sites-available/default - sites-available/default-ssl - vhostexample.conf - + httpd.conf + ports.conf + sites-available/default + sites-available/default-ssl + vhostexample.conf Within the patches/systemvm/debian/config/etc/ssh/ directory licensed under the BSD (2-clause) http://www.opensource.org/licenses/BSD-2-Clause (as follows) @@ -354,40 +349,95 @@ Within the patches/systemvm/debian/config/etc/ssh/ directory ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - + from OpenSSH Project http://www.openssh.org/ - sshd_config - + sshd_config Within the patches/systemvm/debian/config/root/redundant_router directory placed in the public domain by The netfilter.org project http://www.netfilter.org/ - conntrackd.conf.templ - + conntrackd.conf.templ Within the scripts/storage/secondary directory licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above) Copyright (c) 2010-2011 OpenStack, LLC. from OpenStack, LLC http://www.openstack.org - swift - + swift Within the scripts/vm/hypervisor/xenserver directory licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above) Copyright (c) 2010-2011 OpenStack, LLC. from OpenStack, LLC http://www.openstack.org - swift + swift +Within the tools/appliance/definitions/systemvmtemplate directory + licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) + + Copyright (c) 2010-2012 Patrick Debois + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + from Patrick Debois http://www.jedi.be/blog/ + base.sh from https://github.com/jedi4ever/veewee + cleanup.sh from https://github.com/jedi4ever/veewee + definition.rb from https://github.com/jedi4ever/veewee + preseed.cfg from https://github.com/jedi4ever/veewee + zerodisk.sh from https://github.com/jedi4ever/veewee + +Within the tools/devcloud/src/deps/boxes/basebox-build directory + licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) + + Copyright (c) 2010-2012 Patrick Debois + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + from Patrick Debois http://www.jedi.be/blog/ + definition.rb from https://github.com/jedi4ever/veewee + preseed.cfg from https://github.com/jedi4ever/veewee Within the ui/lib directory placed in the public domain by Eric Meyer http://meyerweb.com/eric/ - reset.css + reset.css from http://meyerweb.com/eric/tools/css/reset/ licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above) Copyright (c) 2006 Google Inc. from Google Inc. http://google.com - excanvas.js http://code.google.com/p/explorercanvas/ + excanvas.js from http://code.google.com/p/explorercanvas/ licensed under the BSD (2-clause) http://www.opensource.org/licenses/BSD-2-Clause (as follows) @@ -417,9 +467,34 @@ Within the ui/lib directory ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - + from George McGinley Smith - jquery.easing.js + jquery.easing.js + + licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) + + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + from The Dojo Foundation http://dojofoundation.org/ + require.js from http://github.com/jrburke/requirejs licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -443,9 +518,9 @@ Within the ui/lib directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from John Resig - jquery.js + jquery.js licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -469,9 +544,9 @@ Within the ui/lib directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from Jorn Zaefferer - jquery.validate.js + jquery.validate.js licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -495,9 +570,9 @@ Within the ui/lib directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from Sebastian Tschan https://blueimp.net - jquery.md5.js + jquery.md5.js licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -521,10 +596,9 @@ Within the ui/lib directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from Klaus Hartl http://stilbuero.de - jquery.cookies.js - + jquery.cookies.js Within the ui/lib/flot directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -549,18 +623,18 @@ Within the ui/lib/flot directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from IOLA http://www.iola.dk/ - jquery.flot.crosshair.js - jquery.flot.fillbetween.js - jquery.flot.image.js - jquery.flot.js - jquery.flot.navigate.js - jquery.flot.resize.js - jquery.flot.selection.js - jquery.flot.stack.js - jquery.flot.symbol.js - jquery.flot.threshold.js + jquery.flot.crosshair.js + jquery.flot.fillbetween.js + jquery.flot.image.js + jquery.flot.js + jquery.flot.navigate.js + jquery.flot.resize.js + jquery.flot.selection.js + jquery.flot.stack.js + jquery.flot.symbol.js + jquery.flot.threshold.js licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -585,9 +659,9 @@ Within the ui/lib/flot directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from Brian Medendorp - jquery.pie.js + jquery.pie.js licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -610,10 +684,9 @@ Within the ui/lib/flot directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from Ole Laursen - jquery.colorhelpers.js - + jquery.colorhelpers.js Within the ui/lib/jquery-ui directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -637,12 +710,11 @@ Within the ui/lib/jquery-ui directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from jQuery UI Developers http://jqueryui.com/about - css/jquery-ui.css - index.html - js/jquery-ui.js - + css/jquery-ui.css + index.html + js/jquery-ui.js Within the ui/lib/qunit directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) @@ -667,14 +739,14 @@ Within the ui/lib/qunit directory LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + from Jorn Zaefferer - qunit.css http://docs.jquery.com/QUnit - qunit.js http://docs.jquery.com/QUnit - + qunit.css from http://docs.jquery.com/QUnit + qunit.js from http://docs.jquery.com/QUnit Within the utils/src/com/cloud/utils/db directory licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above) Copyright (c) 2004 Clinton Begin from Clinton Begin http://code.google.com/p/mybatis/ - ScriptRunner.java http://code.google.com/p/mybatis/ + ScriptRunner.java from http://code.google.com/p/mybatis/ + diff --git a/NOTICE b/NOTICE index 5cdd9fcee19..d36048aabda 100644 --- a/NOTICE +++ b/NOTICE @@ -6,30 +6,7 @@ - Source code distribution if this software contains third party resources requiring - the following notices: - - - For - jquery.md5.js - - - jQuery MD5 Plugin 1.2.1 - https://github.com/blueimp/jQuery-MD5 - - Copyright 2010, Sebastian Tschan - https://blueimp.net - - Licensed under the MIT license: - http://creativecommons.org/licenses/MIT/ - - Based on - A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - Digest Algorithm, as defined in RFC 1321. - Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 - Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - Distributed under the BSD License - See http://pajhome.org.uk/crypt/md5 for more info. + This distribution contains third party resources requiring the following notices: For @@ -66,6 +43,28 @@ Date: Thu May 12 15:04:36 2011 -0400 + For + jquery.md5.js + + + jQuery MD5 Plugin 1.2.1 + https://github.com/blueimp/jQuery-MD5 + + Copyright 2010, Sebastian Tschan + https://blueimp.net + + Licensed under the MIT license: + http://creativecommons.org/licenses/MIT/ + + Based on + A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + Digest Algorithm, as defined in RFC 1321. + Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 + Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + Distributed under the BSD License + See http://pajhome.org.uk/crypt/md5 for more info. + + For jquery.colorhelpers.js @@ -76,4 +75,4 @@ Inspiration from jQuery color animation plugin by John Resig. - Released under the MIT license by Ole Laursen, October 2009. \ No newline at end of file + Released under the MIT license by Ole Laursen, October 2009. diff --git a/agent/pom.xml b/agent/pom.xml index 810f33fc572..a3d071b1c6a 100644 --- a/agent/pom.xml +++ b/agent/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/api/pom.xml b/api/pom.xml index 7461c67aaa2..8ca258f12e3 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/api/src/com/cloud/agent/api/CreateVMSnapshotAnswer.java b/api/src/com/cloud/agent/api/CreateVMSnapshotAnswer.java new file mode 100644 index 00000000000..f9fb1642b3f --- /dev/null +++ b/api/src/com/cloud/agent/api/CreateVMSnapshotAnswer.java @@ -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 volumeTOs; + private VMSnapshotTO vmSnapshotTo; + + + public List getVolumeTOs() { + return volumeTOs; + } + + public void setVolumeTOs(List 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 volumeTOs) { + super(cmd, true, ""); + this.vmSnapshotTo = vmSnapshotTo; + this.volumeTOs = volumeTOs; + } + +} diff --git a/core/src/com/cloud/vm/VirtualEnvironment.java b/api/src/com/cloud/agent/api/CreateVMSnapshotCommand.java similarity index 56% rename from core/src/com/cloud/vm/VirtualEnvironment.java rename to api/src/com/cloud/agent/api/CreateVMSnapshotCommand.java index 79d4a59bbfc..478987d993b 100644 --- a/core/src/com/cloud/vm/VirtualEnvironment.java +++ b/api/src/com/cloud/agent/api/CreateVMSnapshotCommand.java @@ -14,33 +14,29 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.vm; +package com.cloud.agent.api; import java.util.List; -/** - * - * be an information carrier within one thread only. - * - */ -public class VirtualEnvironment { - /** - * The actual machine - */ - public VirtualMachine machine; +import com.cloud.agent.api.to.VolumeTO; +import com.cloud.vm.VirtualMachine; + +public class CreateVMSnapshotCommand extends VMSnapshotBaseCommand { + + public CreateVMSnapshotCommand(String vmName, VMSnapshotTO snapshot, List 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; + } - /** - * Disks to assign to the machine in order. - */ - public List disks; - - /** - * Networks to assign to the machine. - */ - public List networks; - - /** - * Boot options to assign to the machine. - */ - public String bootOptions; } diff --git a/api/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java b/api/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java index a19d34436f7..fbf6121f543 100644 --- a/api/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java +++ b/api/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java @@ -18,6 +18,7 @@ package com.cloud.agent.api; import com.cloud.storage.StoragePool; + /** * This currently assumes that both primary and secondary storage are mounted on the XenServer. */ diff --git a/api/src/com/cloud/agent/api/CreateVolumeFromVMSnapshotAnswer.java b/api/src/com/cloud/agent/api/CreateVolumeFromVMSnapshotAnswer.java new file mode 100644 index 00000000000..ed3bc62ccba --- /dev/null +++ b/api/src/com/cloud/agent/api/CreateVolumeFromVMSnapshotAnswer.java @@ -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); + } +} diff --git a/api/src/com/cloud/agent/api/CreateVolumeFromVMSnapshotCommand.java b/api/src/com/cloud/agent/api/CreateVolumeFromVMSnapshotCommand.java new file mode 100644 index 00000000000..634e15c9f04 --- /dev/null +++ b/api/src/com/cloud/agent/api/CreateVolumeFromVMSnapshotCommand.java @@ -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; + } +} diff --git a/server/src/com/cloud/baremetal/DhcpServerResponse.java b/api/src/com/cloud/agent/api/DeleteVMSnapshotAnswer.java similarity index 53% rename from server/src/com/cloud/baremetal/DhcpServerResponse.java rename to api/src/com/cloud/agent/api/DeleteVMSnapshotAnswer.java index db46ccd1a1d..8f4ecad3d80 100644 --- a/server/src/com/cloud/baremetal/DhcpServerResponse.java +++ b/api/src/com/cloud/agent/api/DeleteVMSnapshotAnswer.java @@ -14,22 +14,36 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.baremetal; +package com.cloud.agent.api; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; -import com.cloud.serializer.Param; -import com.google.gson.annotations.SerializedName; +import java.util.List; -public class DhcpServerResponse extends BaseResponse { - @SerializedName(ApiConstants.ID) @Param(description="the ID of the Dhcp server") - private String id; +import com.cloud.agent.api.to.VolumeTO; - public String getId() { - return id; +public class DeleteVMSnapshotAnswer extends Answer { + private List volumeTOs; + + public DeleteVMSnapshotAnswer() { } - public void setId(String id) { - this.id = id; + public DeleteVMSnapshotAnswer(DeleteVMSnapshotCommand cmd, boolean result, + String message) { + super(cmd, result, message); } + + public DeleteVMSnapshotAnswer(DeleteVMSnapshotCommand cmd, + List volumeTOs) { + super(cmd, true, ""); + this.volumeTOs = volumeTOs; + } + + public List getVolumeTOs() { + return volumeTOs; + } + + public void setVolumeTOs(List volumeTOs) { + this.volumeTOs = volumeTOs; + } + + } diff --git a/api/src/com/cloud/agent/api/DeleteVMSnapshotCommand.java b/api/src/com/cloud/agent/api/DeleteVMSnapshotCommand.java new file mode 100644 index 00000000000..c213448bf9c --- /dev/null +++ b/api/src/com/cloud/agent/api/DeleteVMSnapshotCommand.java @@ -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 volumeTOs, String guestOSType) { + super( vmName, snapshot, volumeTOs, guestOSType); + } +} diff --git a/api/src/com/cloud/agent/api/RevertToVMSnapshotAnswer.java b/api/src/com/cloud/agent/api/RevertToVMSnapshotAnswer.java new file mode 100644 index 00000000000..848ffc0ebf8 --- /dev/null +++ b/api/src/com/cloud/agent/api/RevertToVMSnapshotAnswer.java @@ -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 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 volumeTOs, + VirtualMachine.State vmState) { + super(cmd, true, ""); + this.volumeTOs = volumeTOs; + this.vmState = vmState; + } + + public VirtualMachine.State getVmState() { + return vmState; + } + + public List getVolumeTOs() { + return volumeTOs; + } + + public void setVolumeTOs(List volumeTOs) { + this.volumeTOs = volumeTOs; + } + + public void setVmState(VirtualMachine.State vmState) { + this.vmState = vmState; + } + +} diff --git a/api/src/com/cloud/agent/api/RevertToVMSnapshotCommand.java b/api/src/com/cloud/agent/api/RevertToVMSnapshotCommand.java new file mode 100644 index 00000000000..429a186e0dc --- /dev/null +++ b/api/src/com/cloud/agent/api/RevertToVMSnapshotCommand.java @@ -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 volumeTOs, String guestOSType) { + super(vmName, snapshot, volumeTOs, guestOSType); + } + +} diff --git a/api/src/com/cloud/agent/api/VMSnapshotBaseCommand.java b/api/src/com/cloud/agent/api/VMSnapshotBaseCommand.java new file mode 100644 index 00000000000..2120f2f73b1 --- /dev/null +++ b/api/src/com/cloud/agent/api/VMSnapshotBaseCommand.java @@ -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 volumeTOs; + protected VMSnapshotTO target; + protected String vmName; + protected String guestOSType; + + + public VMSnapshotBaseCommand(String vmName, VMSnapshotTO snapshot, List volumeTOs, String guestOSType) { + this.vmName = vmName; + this.target = snapshot; + this.volumeTOs = volumeTOs; + this.guestOSType = guestOSType; + } + + public List getVolumeTOs() { + return volumeTOs; + } + + public void setVolumeTOs(List 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; + } +} diff --git a/api/src/com/cloud/agent/api/VMSnapshotTO.java b/api/src/com/cloud/agent/api/VMSnapshotTO.java new file mode 100644 index 00000000000..c7b42d25bc9 --- /dev/null +++ b/api/src/com/cloud/agent/api/VMSnapshotTO.java @@ -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; + } + +} diff --git a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java index 8f3f0eb39d6..bdd636e727b 100644 --- a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java +++ b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java @@ -28,7 +28,8 @@ public class VirtualMachineTO { private BootloaderType bootloader; Type type; int cpus; - Integer speed; + Integer minSpeed; + Integer maxSpeed; long minRam; long maxRam; String hostName; @@ -47,12 +48,13 @@ public class VirtualMachineTO { VolumeTO[] disks; NicTO[] nics; - public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader, String os, boolean enableHA, boolean limitCpuUse, String vncPassword) { + public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer minSpeed, Integer maxSpeed, long minRam, long maxRam, BootloaderType bootloader, String os, boolean enableHA, boolean limitCpuUse, String vncPassword) { this.id = id; this.name = instanceName; this.type = type; this.cpus = cpus; - this.speed = speed; + this.minSpeed = minSpeed; + this.maxSpeed = maxSpeed; this.minRam = minRam; this.maxRam = maxRam; this.bootloader = bootloader; @@ -101,10 +103,13 @@ public class VirtualMachineTO { this.cpus = cpus; } - public Integer getSpeed() { - return speed; + public Integer getMinSpeed() { + return minSpeed; } + public Integer getMaxSpeed() { + return maxSpeed; + } public boolean getLimitCpuUse() { return limitCpuUse; } diff --git a/api/src/com/cloud/agent/api/to/VolumeTO.java b/api/src/com/cloud/agent/api/to/VolumeTO.java index a8846b96261..4cbe82b357b 100644 --- a/api/src/com/cloud/agent/api/to/VolumeTO.java +++ b/api/src/com/cloud/agent/api/to/VolumeTO.java @@ -124,6 +124,10 @@ public class VolumeTO implements InternalIdentity { public String getOsType() { return guestOsType; } + + public void setPath(String path){ + this.path = path; + } @Override public String toString() { diff --git a/api/src/com/cloud/configuration/ConfigurationService.java b/api/src/com/cloud/configuration/ConfigurationService.java index a9595fe7574..e63fcece525 100644 --- a/api/src/com/cloud/configuration/ConfigurationService.java +++ b/api/src/com/cloud/configuration/ConfigurationService.java @@ -264,6 +264,8 @@ public interface ConfigurationService { boolean removeLDAP(LDAPRemoveCmd cmd); + LDAPConfigCmd listLDAPConfig(LDAPConfigCmd cmd); + /** * @param offering * @return diff --git a/api/src/com/cloud/configuration/Resource.java b/api/src/com/cloud/configuration/Resource.java index 7f551d6b52c..7614c8a4b43 100644 --- a/api/src/com/cloud/configuration/Resource.java +++ b/api/src/com/cloud/configuration/Resource.java @@ -28,7 +28,9 @@ public interface Resource { template("template", 4, ResourceOwnerType.Account, ResourceOwnerType.Domain), project("project", 5, ResourceOwnerType.Account, ResourceOwnerType.Domain), network("network", 6, ResourceOwnerType.Account, ResourceOwnerType.Domain), - vpc("vpc", 7, ResourceOwnerType.Account, ResourceOwnerType.Domain); + vpc("vpc", 7, ResourceOwnerType.Account, ResourceOwnerType.Domain), + cpu("cpu", 8, ResourceOwnerType.Account, ResourceOwnerType.Domain), + memory("memory", 9, ResourceOwnerType.Account, ResourceOwnerType.Domain); private String name; private ResourceOwnerType[] supportedOwners; diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 0dd97cb438c..0087edca743 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -331,6 +331,11 @@ public class EventTypes { // tag related events public static final String EVENT_TAGS_CREATE = "CREATE_TAGS"; public static final String EVENT_TAGS_DELETE = "DELETE_TAGS"; + + // vm snapshot events + public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE"; + public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE"; + public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERTTO"; // external network device events public static final String EVENT_EXTERNAL_NVP_CONTROLLER_ADD = "PHYSICAL.NVPCONTROLLER.ADD"; diff --git a/api/src/com/cloud/exception/RequestLimitException.java b/api/src/com/cloud/exception/RequestLimitException.java index 0142f8e8726..ebaac802649 100644 --- a/api/src/com/cloud/exception/RequestLimitException.java +++ b/api/src/com/cloud/exception/RequestLimitException.java @@ -21,7 +21,6 @@ import com.cloud.utils.exception.CloudRuntimeException; /** * Exception thrown if number of requests is over api rate limit set. - * @author minc * */ public class RequestLimitException extends CloudRuntimeException { diff --git a/api/src/com/cloud/hypervisor/HypervisorCapabilities.java b/api/src/com/cloud/hypervisor/HypervisorCapabilities.java index d52c36b12f5..aff81b0018d 100644 --- a/api/src/com/cloud/hypervisor/HypervisorCapabilities.java +++ b/api/src/com/cloud/hypervisor/HypervisorCapabilities.java @@ -46,4 +46,10 @@ public interface HypervisorCapabilities extends Identity, InternalIdentity{ * @return the max. data volumes per VM supported by hypervisor */ Integer getMaxDataVolumesLimit(); + + /** + * @return the max. hosts per cluster supported by hypervisor + */ + Integer getMaxHostsPerCluster(); + } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 2bf7b7f8000..e584e8de925 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -138,6 +138,7 @@ public interface Network extends ControlledEntity, StateObject, I // NiciraNvp is not an "External" provider, otherwise we get in trouble with NetworkServiceImpl.providersConfiguredForExternalNetworking public static final Provider NiciraNvp = new Provider("NiciraNvp", false); public static final Provider MidokuraMidonet = new Provider("MidokuraMidonet", true); + public static final Provider VPCNetscaler = new Provider("VPCNetscaler", true); private String name; private boolean isExternal; @@ -283,12 +284,21 @@ public interface Network extends ControlledEntity, StateObject, I String getGateway(); + // "cidr" is the Cloudstack managed address space, all CloudStack managed vms get IP address from "cidr", + // In general "cidr" also serves as the network CIDR + // But in case IP reservation is configured for a Guest network, "networkcidr" is the Effective network CIDR for that network, + // "cidr" will still continue to be the effective address space for CloudStack managed vms in that Guest network String getCidr(); + // "networkcidr" is the network CIDR of the guest network which uses IP reservation. + // It is the summation of "cidr" and the reservedIPrange(the address space used for non CloudStack purposes). + // For networks not configured with IP reservation, "networkcidr" is always null + String getNetworkCidr(); + String getIp6Gateway(); - + String getIp6Cidr(); - + long getDataCenterId(); long getNetworkOfferingId(); diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java index 783e5cc9c85..9731a61667d 100644 --- a/api/src/com/cloud/network/NetworkModel.java +++ b/api/src/com/cloud/network/NetworkModel.java @@ -255,4 +255,6 @@ public interface NetworkModel { boolean isIP6AddressAvailableInVlan(long vlanId); void checkIp6Parameters(String startIPv6, String endIPv6, String ip6Gateway, String ip6Cidr) throws InvalidParameterValueException; + + void checkRequestedIpAddresses(long networkId, String ip4, String ip6) throws InvalidParameterValueException; } \ No newline at end of file diff --git a/api/src/com/cloud/network/NetworkProfile.java b/api/src/com/cloud/network/NetworkProfile.java index 37d46ac8395..2f56645139c 100644 --- a/api/src/com/cloud/network/NetworkProfile.java +++ b/api/src/com/cloud/network/NetworkProfile.java @@ -38,6 +38,7 @@ public class NetworkProfile implements Network { private TrafficType trafficType; private String gateway; private String cidr; + private String networkCidr; private String ip6Gateway; private String ip6Cidr; private long networkOfferingId; @@ -65,6 +66,7 @@ public class NetworkProfile implements Network { this.trafficType = network.getTrafficType(); this.gateway = network.getGateway(); this.cidr = network.getCidr(); + this.networkCidr = network.getNetworkCidr(); this.ip6Gateway = network.getIp6Gateway(); this.ip6Cidr = network.getIp6Cidr(); this.networkOfferingId = network.getNetworkOfferingId(); @@ -162,6 +164,11 @@ public class NetworkProfile implements Network { return cidr; } + @Override + public String getNetworkCidr() { + return networkCidr; + } + @Override public long getNetworkOfferingId() { return networkOfferingId; diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index ace1bb6c45e..95bcc42b17a 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -66,10 +66,8 @@ public interface NetworkService { IpAddress getIp(long id); - Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, - String domainSuffix, Long networkOfferingId, Boolean changeCidr); - + String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr); PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String networkSpeed, List isolationMethods, String broadcastDomainRange, Long domainId, List tags, String name); diff --git a/api/src/com/cloud/network/vpc/VpcService.java b/api/src/com/cloud/network/vpc/VpcService.java index cc66b58fe64..9bf1beea5f0 100644 --- a/api/src/com/cloud/network/vpc/VpcService.java +++ b/api/src/com/cloud/network/vpc/VpcService.java @@ -41,7 +41,7 @@ public interface VpcService { public VpcOffering getVpcOffering(long vpcOfferingId); - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices); + public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders); public Vpc getVpc(long vpcId); @@ -246,5 +246,5 @@ public interface VpcService { InsufficientAddressCapacityException, ConcurrentOperationException; public Network updateVpcGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long ntwkOffId, Boolean changeCidr); + User callerUser, String domainSuffix, Long ntwkOffId, Boolean changeCidr, String guestVmCidr); } diff --git a/api/src/com/cloud/offering/ServiceOffering.java b/api/src/com/cloud/offering/ServiceOffering.java index 4d715898a75..d6c215f42f0 100755 --- a/api/src/com/cloud/offering/ServiceOffering.java +++ b/api/src/com/cloud/offering/ServiceOffering.java @@ -77,6 +77,11 @@ public interface ServiceOffering extends InfrastructureEntity, InternalIdentity, */ boolean getLimitCpuUse(); + /** + * @return Does this service plan support Volatile VM that is, discard VM's root disk and create a new one on reboot? + */ + boolean getVolatileVm(); + /** * @return the rate in megabits per sec to which a VM's network interface is throttled to */ diff --git a/api/src/com/cloud/resource/ResourceService.java b/api/src/com/cloud/resource/ResourceService.java index 1e77cc8a4e2..08e2585d1a7 100755 --- a/api/src/com/cloud/resource/ResourceService.java +++ b/api/src/com/cloud/resource/ResourceService.java @@ -71,7 +71,7 @@ public interface ResourceService { boolean deleteCluster(DeleteClusterCmd cmd); - Cluster updateCluster(Cluster cluster, String clusterType, String hypervisor, String allocationState, String managedstate); + Cluster updateCluster(Cluster cluster, String clusterType, String hypervisor, String allocationState, String managedstate,Float memoryOvercommitRatio, Float cpuOvercommitRatio); List discoverHosts(AddHostCmd cmd) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException; diff --git a/api/src/com/cloud/server/ResourceTag.java b/api/src/com/cloud/server/ResourceTag.java index 5ec9f0171cc..ee56748640c 100644 --- a/api/src/com/cloud/server/ResourceTag.java +++ b/api/src/com/cloud/server/ResourceTag.java @@ -37,7 +37,8 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit Project, Vpc, NetworkACL, - StaticRoute + StaticRoute, + VMSnapshot } /** diff --git a/api/src/com/cloud/storage/Snapshot.java b/api/src/com/cloud/storage/Snapshot.java index 3f6b8f5a8e4..f71265cd230 100644 --- a/api/src/com/cloud/storage/Snapshot.java +++ b/api/src/com/cloud/storage/Snapshot.java @@ -19,7 +19,6 @@ package com.cloud.storage; import java.util.Date; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.fsm.StateObject; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.api.Identity; @@ -55,28 +54,13 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity, } public enum State { + Allocated, Creating, CreatedOnPrimary, BackingUp, BackedUp, Error; - private final static StateMachine2 s_fsm = new StateMachine2(); - - public static StateMachine2 getStateMachine() { - return s_fsm; - } - - static { - s_fsm.addTransition(null, Event.CreateRequested, Creating); - s_fsm.addTransition(Creating, Event.OperationSucceeded, CreatedOnPrimary); - s_fsm.addTransition(Creating, Event.OperationNotPerformed, BackedUp); - s_fsm.addTransition(Creating, Event.OperationFailed, Error); - s_fsm.addTransition(CreatedOnPrimary, Event.BackupToSecondary, BackingUp); - s_fsm.addTransition(BackingUp, Event.OperationSucceeded, BackedUp); - s_fsm.addTransition(BackingUp, Event.OperationFailed, Error); - } - public String toString() { return this.name(); } @@ -107,7 +91,7 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity, Date getCreated(); - Type getType(); + Type getRecurringType(); State getState(); diff --git a/api/src/com/cloud/storage/StoragePool.java b/api/src/com/cloud/storage/StoragePool.java index f517927eac1..091eef182cc 100644 --- a/api/src/com/cloud/storage/StoragePool.java +++ b/api/src/com/cloud/storage/StoragePool.java @@ -99,10 +99,7 @@ public interface StoragePool extends Identity, InternalIdentity { /** * @return */ - String getStorageProvider(); - - /** - * @return - */ - String getStorageType(); + Long getStorageProviderId(); + + boolean isInMaintenance(); } diff --git a/api/src/com/cloud/storage/StoragePoolStatus.java b/api/src/com/cloud/storage/StoragePoolStatus.java index 94dd686a8f0..a35f706d702 100644 --- a/api/src/com/cloud/storage/StoragePoolStatus.java +++ b/api/src/com/cloud/storage/StoragePoolStatus.java @@ -17,11 +17,6 @@ package com.cloud.storage; public enum StoragePoolStatus { - Creating, - Up, - PrepareForMaintenance, - ErrorInMaintenance, - CancelMaintenance, - Maintenance, - Removed; + Initial, Initialized, Creating, Attaching, Up, PrepareForMaintenance, + ErrorInMaintenance, CancelMaintenance, Maintenance, Removed; } diff --git a/api/src/com/cloud/storage/StorageService.java b/api/src/com/cloud/storage/StorageService.java index bd7dfd3a67a..63c5023ee91 100644 --- a/api/src/com/cloud/storage/StorageService.java +++ b/api/src/com/cloud/storage/StorageService.java @@ -22,17 +22,10 @@ import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaint import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd; -import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; -import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceInUseException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.user.Account; public interface StorageService{ /** @@ -51,37 +44,6 @@ public interface StorageService{ StoragePool createPool(CreateStoragePoolCmd cmd) throws ResourceInUseException, IllegalArgumentException, UnknownHostException, ResourceUnavailableException; - /** - * Creates the database object for a volume based on the given criteria - * - * @param cmd - * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, - * name) - * @return the volume object - * @throws PermissionDeniedException - */ - Volume allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationException; - - /** - * Creates the volume based on the given criteria - * - * @param cmd - * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, - * name) - * @return the volume object - */ - Volume createVolume(CreateVolumeCmd cmd); - - - /** - * Resizes the volume based on the given criteria - * - * @param cmd - * the API command wrapping the criteria - * @return the volume object - */ - Volume resizeVolume(ResizeVolumeCmd cmd); - /** * Delete the storage pool * @@ -120,19 +82,4 @@ public interface StorageService{ public StoragePool updateStoragePool(UpdateStoragePoolCmd cmd) throws IllegalArgumentException; public StoragePool getStoragePool(long id); - - Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException; - - - /** - * Uploads the volume to secondary storage - * - * @param UploadVolumeCmd cmd - * - * @return Volume object - */ - Volume uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException; - - boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException; - } diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java index 284c83d9e93..4903594f0af 100755 --- a/api/src/com/cloud/storage/Volume.java +++ b/api/src/com/cloud/storage/Volume.java @@ -39,9 +39,12 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"), Resizing("The volume is being resized"), Expunging("The volume is being expunging"), + Expunged("The volume is being expunging"), Destroy("The volume is destroyed, and can't be recovered."), Destroying("The volume is destroying, and can't be recovered."), - UploadOp ("The volume upload operation is in progress or in short the volume is on secondary storage"); + UploadOp ("The volume upload operation is in progress or in short the volume is on secondary storage"), + Uploading("volume is uploading"), + Uploaded("volume is uploaded"); String _description; @@ -70,12 +73,15 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba s_fsm.addTransition(Resizing, Event.OperationSucceeded, Ready); s_fsm.addTransition(Resizing, Event.OperationFailed, Ready); s_fsm.addTransition(Allocated, Event.UploadRequested, UploadOp); - s_fsm.addTransition(UploadOp, Event.CopyRequested, Creating);// CopyRequested for volume from sec to primary storage + s_fsm.addTransition(Uploaded, Event.CopyRequested, Creating);// CopyRequested for volume from sec to primary storage s_fsm.addTransition(Creating, Event.CopySucceeded, Ready); - s_fsm.addTransition(Creating, Event.CopyFailed, UploadOp);// Copying volume from sec to primary failed. + s_fsm.addTransition(Creating, Event.CopyFailed, Uploaded);// Copying volume from sec to primary failed. s_fsm.addTransition(UploadOp, Event.DestroyRequested, Destroy); s_fsm.addTransition(Ready, Event.DestroyRequested, Destroy); s_fsm.addTransition(Destroy, Event.ExpungingRequested, Expunging); + s_fsm.addTransition(Expunging, Event.ExpungingRequested, Expunging); + s_fsm.addTransition(Expunging, Event.OperationSucceeded, Expunged); + s_fsm.addTransition(Expunging, Event.OperationFailed, Expunging); s_fsm.addTransition(Ready, Event.SnapshotRequested, Snapshotting); s_fsm.addTransition(Snapshotting, Event.OperationSucceeded, Ready); s_fsm.addTransition(Snapshotting, Event.OperationFailed, Ready); @@ -83,6 +89,9 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba s_fsm.addTransition(Migrating, Event.OperationSucceeded, Ready); s_fsm.addTransition(Migrating, Event.OperationFailed, Ready); s_fsm.addTransition(Destroy, Event.OperationSucceeded, Destroy); + s_fsm.addTransition(UploadOp, Event.OperationSucceeded, Uploaded); + s_fsm.addTransition(UploadOp, Event.OperationFailed, Allocated); + s_fsm.addTransition(Uploaded, Event.DestroyRequested, Destroy); } } @@ -110,7 +119,7 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba /** * @return total size of the partition */ - long getSize(); + Long getSize(); /** * @return the vm instance id diff --git a/api/src/com/cloud/storage/VolumeApiService.java b/api/src/com/cloud/storage/VolumeApiService.java new file mode 100644 index 00000000000..8517988dfc6 --- /dev/null +++ b/api/src/com/cloud/storage/VolumeApiService.java @@ -0,0 +1,81 @@ +/* + * 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.storage; + +import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.user.Account; + +public interface VolumeApiService { + /** + * Creates the database object for a volume based on the given criteria + * + * @param cmd + * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, + * name) + * @return the volume object + * @throws PermissionDeniedException + */ + Volume allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationException; + + /** + * Creates the volume based on the given criteria + * + * @param cmd + * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, + * name) + * @return the volume object + */ + Volume createVolume(CreateVolumeCmd cmd); + + + /** + * Resizes the volume based on the given criteria + * + * @param cmd + * the API command wrapping the criteria + * @return the volume object + */ + Volume resizeVolume(ResizeVolumeCmd cmd); + + Volume migrateVolume(MigrateVolumeCmd cmd) throws ConcurrentOperationException; + + /** + * Uploads the volume to secondary storage + * + * @param UploadVolumeCmd cmd + * + * @return Volume object + */ + Volume uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException; + + boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException; + + Volume attachVolumeToVM(AttachVolumeCmd command); + + Volume detachVolumeFromVM(DetachVolumeCmd cmmd); +} diff --git a/api/src/com/cloud/template/TemplateService.java b/api/src/com/cloud/template/TemplateService.java index 11475d46b8a..7e831fb0055 100755 --- a/api/src/com/cloud/template/TemplateService.java +++ b/api/src/com/cloud/template/TemplateService.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.ExtractIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.CopyTemplateCmd; +import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; @@ -32,6 +33,8 @@ import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import com.cloud.exception.InternalErrorException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.user.Account; +import com.cloud.utils.exception.CloudRuntimeException; public interface TemplateService { @@ -87,4 +90,11 @@ public interface TemplateService { List listTemplatePermissions(BaseListTemplateOrIsoPermissionsCmd cmd); boolean updateTemplateOrIsoPermissions(BaseUpdateTemplateOrIsoPermissionsCmd cmd); + + VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, + Account templateOwner) throws ResourceAllocationException; + + VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) + throws CloudRuntimeException; + } diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index fb574fa5848..ea89eda89d2 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -23,7 +23,6 @@ import javax.naming.InsufficientResourcesException; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; @@ -103,24 +102,6 @@ public interface UserVmService { */ UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException; - /** - * Attaches the specified volume to the specified VM - * - * @param cmd - * - the command specifying volumeId and vmId - * @return the Volume object if attach worked successfully. - */ - Volume attachVolumeToVM(AttachVolumeCmd cmd); - - /** - * Detaches the specified volume from the VM it is currently attached to. - * - * @param cmd - * - the command specifying volumeId - * @return the Volume object if detach worked successfully. - */ - Volume detachVolumeFromVM(DetachVolumeCmd cmmd); - UserVm startVirtualMachine(StartVMCmd cmd) throws StorageUnavailableException, ExecutionException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException; @@ -151,28 +132,6 @@ public interface UserVmService { UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationException; - /** - * Create a template database record in preparation for creating a private template. - * - * @param cmd - * the command object that defines the name, display text, snapshot/volume, bits, public/private, etc. - * for the - * private template - * @param templateOwner - * TODO - * @return the vm template object if successful, null otherwise - * @throws ResourceAllocationException - */ - VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException; - - /** - * Creates a private template from a snapshot of a VM - * - * @param cmd - * - the command specifying snapshotId, name, description - * @return a template if successfully created, null otherwise - */ - VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd cmd); /** * Creates a Basic Zone User VM in the database and returns the VM to the caller. diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index 248b98247e3..4300dd548c1 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -112,7 +112,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I s_fsm.addTransition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging); s_fsm.addTransition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging); } - + public static boolean isVmStarted(State oldState, Event e, State newState) { if (oldState == State.Starting && newState == State.Running) { return true; @@ -174,7 +174,9 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I OperationFailedToError, OperationRetry, AgentReportShutdowned, - AgentReportMigrated + AgentReportMigrated, + RevertRequested, + SnapshotRequested }; public enum Type { diff --git a/api/src/com/cloud/vm/VirtualMachineProfile.java b/api/src/com/cloud/vm/VirtualMachineProfile.java index 0fab4436807..33a9171e732 100644 --- a/api/src/com/cloud/vm/VirtualMachineProfile.java +++ b/api/src/com/cloud/vm/VirtualMachineProfile.java @@ -136,4 +136,10 @@ public interface VirtualMachineProfile { BootloaderType getBootLoaderType(); Map getParameters(); + + Float getCpuOvercommitRatio(); + + Float getMemoryOvercommitRatio(); + + } diff --git a/api/src/com/cloud/vm/snapshot/VMSnapshot.java b/api/src/com/cloud/vm/snapshot/VMSnapshot.java new file mode 100644 index 00000000000..f0ee7ee7e8a --- /dev/null +++ b/api/src/com/cloud/vm/snapshot/VMSnapshot.java @@ -0,0 +1,110 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.vm.snapshot; + +import java.util.Date; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +import org.apache.cloudstack.acl.ControlledEntity; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.utils.fsm.StateObject; + +public interface VMSnapshot extends ControlledEntity, Identity, InternalIdentity,StateObject { + + 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 getStateMachine() { + return s_fsm; + } + + public String getDescription() { + return _description; + } + + private final static StateMachine2 s_fsm = new StateMachine2(); + static { + s_fsm.addTransition(Allocated, Event.CreateRequested, Creating); + s_fsm.addTransition(Creating, Event.OperationSucceeded, Ready); + s_fsm.addTransition(Creating, Event.OperationFailed, Error); + s_fsm.addTransition(Ready, Event.RevertRequested, Reverting); + s_fsm.addTransition(Reverting, Event.OperationSucceeded, Ready); + s_fsm.addTransition(Reverting, Event.OperationFailed, Ready); + s_fsm.addTransition(Ready, Event.ExpungeRequested, Expunging); + s_fsm.addTransition(Error, Event.ExpungeRequested, Expunging); + s_fsm.addTransition(Expunging, Event.ExpungeRequested, Expunging); + s_fsm.addTransition(Expunging, Event.OperationSucceeded, Removed); + } + } + + enum Type{ + Disk, DiskAndMemory + } + + enum Event { + CreateRequested, + OperationFailed, + OperationSucceeded, + RevertRequested, + ExpungeRequested, + } + + long getId(); + + public String getName(); + + public Long getVmId(); + + public State getState(); + + public Date getCreated(); + + public String getDescription(); + + public String getDisplayName(); + + public Long getParent(); + + public Boolean getCurrent(); + + public Type getType(); + + public long getUpdatedCount(); + + public void incrUpdatedCount(); + + public Date getUpdated(); + + public Date getRemoved(); + + public long getAccountId(); +} diff --git a/api/src/com/cloud/vm/snapshot/VMSnapshotService.java b/api/src/com/cloud/vm/snapshot/VMSnapshotService.java new file mode 100644 index 00000000000..83f86bc90db --- /dev/null +++ b/api/src/com/cloud/vm/snapshot/VMSnapshotService.java @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.vm.snapshot; + +import java.util.List; + +import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.uservm.UserVm; +import com.cloud.vm.VirtualMachine; + +public interface VMSnapshotService { + + List listVMSnapshots(ListVMSnapshotCmd cmd); + + VMSnapshot getVMSnapshotById(Long id); + + VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId); + + VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDescription, Boolean snapshotMemory) + throws ResourceAllocationException; + + boolean deleteVMSnapshot(Long vmSnapshotId); + + UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientServerCapacityException, InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException; + + VirtualMachine getVMBySnapshotId(Long id); +} diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index d29408e66f2..8b4bb98e06c 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -46,6 +46,7 @@ public class ApiConstants { public static final String COMPONENT = "component"; public static final String CPU_NUMBER = "cpunumber"; public static final String CPU_SPEED = "cpuspeed"; + public static final String CPU_OVERCOMMIT_RATIO="cpuovercommitratio"; public static final String CREATED = "created"; public static final String CUSTOMIZED = "customized"; public static final String DESCRIPTION = "description"; @@ -119,6 +120,7 @@ public class ApiConstants { public static final String MAX = "max"; public static final String MAX_SNAPS = "maxsnaps"; public static final String MEMORY = "memory"; + public static final String MEMORY_OVERCOMMIT_RATIO="memoryovercommitratio"; public static final String MODE = "mode"; public static final String NAME = "name"; public static final String METHOD_NAME = "methodname"; @@ -218,6 +220,7 @@ public class ApiConstants { public static final String VM_LIMIT = "vmlimit"; public static final String VM_TOTAL = "vmtotal"; public static final String VNET = "vnet"; + public static final String IS_VOLATILE = "isvolatile"; public static final String VOLUME_ID = "volumeid"; public static final String ZONE_ID = "zoneid"; public static final String ZONE_NAME = "zonename"; @@ -438,6 +441,15 @@ public class ApiConstants { public static final String AUTOSCALE_USER_ID = "autoscaleuserid"; public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername"; public static final String UCS_DN = "ucsdn"; + public static final String VM_SNAPSHOT_DESCRIPTION = "description"; + public static final String VM_SNAPSHOT_DISPLAYNAME = "name"; + public static final String VM_SNAPSHOT_ID = "vmsnapshotid"; + public static final String VM_SNAPSHOT_DISK_IDS = "vmsnapshotdiskids"; + public static final String VM_SNAPSHOT_MEMORY = "snapshotmemory"; + public static final String IMAGE_STORE_UUID = "imagestoreuuid"; + public static final String GUEST_VM_CIDR = "guestvmcidr"; + public static final String NETWORK_CIDR = "networkcidr"; + public static final String RESERVED_IP_RANGE = "reservediprange"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java.orig b/api/src/org/apache/cloudstack/api/ApiConstants.java.orig new file mode 100644 index 00000000000..3801506ffaa --- /dev/null +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java.orig @@ -0,0 +1,468 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api; + + +public class ApiConstants { + public static final String ACCOUNT = "account"; + public static final String ACCOUNTS = "accounts"; + public static final String ACCOUNT_TYPE = "accounttype"; + public static final String ACCOUNT_ID = "accountid"; + public static final String ALGORITHM = "algorithm"; + public static final String ALLOCATED_ONLY = "allocatedonly"; + public static final String API_KEY = "userapikey"; + public static final String APPLIED = "applied"; + public static final String AVAILABLE = "available"; + public static final String BITS = "bits"; + public static final String BOOTABLE = "bootable"; + public static final String BIND_DN = "binddn"; + public static final String BIND_PASSWORD = "bindpass"; + public static final String CATEGORY = "category"; + public static final String CERTIFICATE = "certificate"; + public static final String PRIVATE_KEY = "privatekey"; + public static final String DOMAIN_SUFFIX = "domainsuffix"; + public static final String DNS_SEARCH_ORDER = "dnssearchorder"; + public static final String CIDR = "cidr"; + public static final String IP6_CIDR = "ip6cidr"; + public static final String CIDR_LIST = "cidrlist"; + public static final String CLEANUP = "cleanup"; + public static final String CLUSTER_ID = "clusterid"; + public static final String CLUSTER_NAME = "clustername"; + public static final String CLUSTER_TYPE = "clustertype"; + public static final String COMPONENT = "component"; + public static final String CPU_NUMBER = "cpunumber"; + public static final String CPU_SPEED = "cpuspeed"; + public static final String CREATED = "created"; + public static final String CUSTOMIZED = "customized"; + public static final String DESCRIPTION = "description"; + public static final String DESTINATION_ZONE_ID = "destzoneid"; + public static final String DETAILS = "details"; + public static final String DEVICE_ID = "deviceid"; + public static final String DISK_OFFERING_ID = "diskofferingid"; + public static final String DISK_SIZE = "disksize"; + public static final String DISPLAY_NAME = "displayname"; + public static final String DISPLAY_TEXT = "displaytext"; + public static final String DNS1 = "dns1"; + public static final String DNS2 = "dns2"; + public static final String DOMAIN = "domain"; + public static final String DOMAIN_ID = "domainid"; + public static final String DURATION = "duration"; + public static final String EMAIL = "email"; + public static final String END_DATE = "enddate"; + public static final String END_IP = "endip"; + public static final String END_IPV6 = "endipv6"; + public static final String END_PORT = "endport"; + public static final String ENTRY_TIME = "entrytime"; + public static final String FETCH_LATEST = "fetchlatest"; + public static final String FIRSTNAME = "firstname"; + public static final String FORCED = "forced"; + public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage"; + public static final String FORMAT = "format"; + public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork"; + public static final String GATEWAY = "gateway"; + public static final String IP6_GATEWAY = "ip6gateway"; + public static final String GROUP = "group"; + public static final String GROUP_ID = "groupid"; + public static final String GUEST_CIDR_ADDRESS = "guestcidraddress"; + public static final String HA_ENABLE = "haenable"; + public static final String HOST_ID = "hostid"; + public static final String HOST_NAME = "hostname"; + public static final String HYPERVISOR = "hypervisor"; + public static final String INLINE = "inline"; + public static final String INSTANCE = "instance"; + public static final String ICMP_CODE = "icmpcode"; + public static final String ICMP_TYPE = "icmptype"; + public static final String ID = "id"; + public static final String IDS = "ids"; + public static final String INTERNAL_DNS1 = "internaldns1"; + public static final String INTERNAL_DNS2 = "internaldns2"; + public static final String INTERVAL_TYPE = "intervaltype"; + public static final String IP_ADDRESS = "ipaddress"; + public static final String IP6_ADDRESS = "ip6address"; + public static final String IP_ADDRESS_ID = "ipaddressid"; + public static final String IS_ASYNC = "isasync"; + public static final String IP_AVAILABLE = "ipavailable"; + public static final String IP_LIMIT = "iplimit"; + public static final String IP_TOTAL = "iptotal"; + public static final String IS_CLEANUP_REQUIRED = "iscleanuprequired"; + public static final String IS_EXTRACTABLE = "isextractable"; + public static final String IS_FEATURED = "isfeatured"; + public static final String IS_PUBLIC = "ispublic"; + public static final String IS_PERSISTENT = "ispersistent"; + public static final String IS_READY = "isready"; + public static final String IS_RECURSIVE = "isrecursive"; + public static final String ISO_FILTER = "isofilter"; + public static final String ISO_GUEST_OS_NONE = "None"; + public static final String JOB_ID = "jobid"; + public static final String JOB_STATUS = "jobstatus"; + public static final String LASTNAME = "lastname"; + public static final String LEVEL = "level"; + public static final String LENGTH = "length"; + public static final String LIMIT_CPU_USE = "limitcpuuse"; + public static final String LOCK = "lock"; + public static final String LUN = "lun"; + public static final String LBID = "lbruleid"; + public static final String MAX = "max"; + public static final String MAX_SNAPS = "maxsnaps"; + public static final String MEMORY = "memory"; + public static final String MODE = "mode"; + public static final String NAME = "name"; + public static final String METHOD_NAME = "methodname"; + public static final String NETWORK_DOMAIN = "networkdomain"; + public static final String NETMASK = "netmask"; + public static final String NEW_NAME = "newname"; + public static final String NUM_RETRIES = "numretries"; + public static final String OFFER_HA = "offerha"; + public static final String IS_SYSTEM_OFFERING = "issystem"; + public static final String IS_DEFAULT_USE = "defaultuse"; + public static final String OP = "op"; + public static final String OS_CATEGORY_ID = "oscategoryid"; + public static final String OS_TYPE_ID = "ostypeid"; + public static final String PARAMS = "params"; + public static final String PARENT_DOMAIN_ID = "parentdomainid"; + public static final String PASSWORD = "password"; + public static final String NEW_PASSWORD = "new_password"; + public static final String PASSWORD_ENABLED = "passwordenabled"; + public static final String SSHKEY_ENABLED = "sshkeyenabled"; + public static final String PATH = "path"; + public static final String POD_ID = "podid"; + public static final String POD_IDS = "podids"; + public static final String POLICY_ID = "policyid"; + public static final String PORT = "port"; + public static final String PORTAL = "portal"; + public static final String PORT_FORWARDING_SERVICE_ID = "portforwardingserviceid"; + public static final String PRIVATE_INTERFACE = "privateinterface"; + public static final String PRIVATE_IP = "privateip"; + public static final String PRIVATE_PORT = "privateport"; + public static final String PRIVATE_START_PORT = "privateport"; + public static final String PRIVATE_END_PORT = "privateendport"; + public static final String PRIVATE_ZONE = "privatezone"; + public static final String PROTOCOL = "protocol"; + public static final String PUBLIC_INTERFACE = "publicinterface"; + public static final String PUBLIC_IP_ID = "publicipid"; + public static final String PUBLIC_IP = "publicip"; + public static final String PUBLIC_PORT = "publicport"; + public static final String PUBLIC_START_PORT = "publicport"; + public static final String PUBLIC_END_PORT = "publicendport"; + public static final String PUBLIC_ZONE = "publiczone"; + public static final String RECEIVED_BYTES = "receivedbytes"; + public static final String REQUIRES_HVM = "requireshvm"; + public static final String RESOURCE_TYPE = "resourcetype"; + public static final String RESPONSE = "response"; + public static final String QUERY_FILTER = "queryfilter"; + public static final String SCHEDULE = "schedule"; + public static final String SCOPE = "scope"; + public static final String SECRET_KEY = "usersecretkey"; + public static final String SINCE = "since"; + public static final String KEY = "key"; + public static final String SEARCH_BASE = "searchbase"; + public static final String SECURITY_GROUP_IDS = "securitygroupids"; + public static final String SECURITY_GROUP_NAMES = "securitygroupnames"; + public static final String SECURITY_GROUP_NAME = "securitygroupname"; + public static final String SECURITY_GROUP_ID = "securitygroupid"; + public static final String SENT = "sent"; + public static final String SENT_BYTES = "sentbytes"; + public static final String SERVICE_OFFERING_ID = "serviceofferingid"; + public static final String SHOW_CAPACITIES = "showcapacities"; + public static final String SIZE = "size"; + public static final String SNAPSHOT_ID = "snapshotid"; + public static final String SNAPSHOT_POLICY_ID = "snapshotpolicyid"; + public static final String SNAPSHOT_TYPE = "snapshottype"; + public static final String SOURCE_ZONE_ID = "sourcezoneid"; + public static final String START_DATE = "startdate"; + public static final String START_IP = "startip"; + public static final String START_IPV6 = "startipv6"; + public static final String START_PORT = "startport"; + public static final String STATE = "state"; + public static final String STATUS = "status"; + public static final String STORAGE_TYPE = "storagetype"; + public static final String SYSTEM_VM_TYPE = "systemvmtype"; + public static final String TAGS = "tags"; + public static final String TARGET_IQN = "targetiqn"; + public static final String TEMPLATE_FILTER = "templatefilter"; + public static final String TEMPLATE_ID = "templateid"; + public static final String ISO_ID = "isoid"; + public static final String TIMEOUT = "timeout"; + public static final String TIMEZONE = "timezone"; + public static final String TYPE = "type"; + public static final String TRUST_STORE = "truststore"; + public static final String TRUST_STORE_PASSWORD = "truststorepass"; + public static final String URL = "url"; + public static final String USAGE_INTERFACE = "usageinterface"; + public static final String USER_DATA = "userdata"; + public static final String USER_ID = "userid"; + public static final String USE_SSL = "ssl"; + public static final String USERNAME = "username"; + public static final String USER_SECURITY_GROUP_LIST = "usersecuritygrouplist"; + public static final String USE_VIRTUAL_NETWORK = "usevirtualnetwork"; + public static final String VALUE = "value"; + public static final String VIRTUAL_MACHINE_ID = "virtualmachineid"; + public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids"; + public static final String VLAN = "vlan"; + public static final String VLAN_ID = "vlanid"; + public static final String VM_AVAILABLE = "vmavailable"; + public static final String VM_LIMIT = "vmlimit"; + public static final String VM_TOTAL = "vmtotal"; + public static final String VNET = "vnet"; + public static final String VOLUME_ID = "volumeid"; + public static final String ZONE_ID = "zoneid"; + public static final String ZONE_NAME = "zonename"; + public static final String NETWORK_TYPE = "networktype"; + public static final String PAGE = "page"; + public static final String PAGE_SIZE = "pagesize"; + public static final String COUNT = "count"; + public static final String TRAFFIC_TYPE = "traffictype"; + public static final String NETWORK_OFFERING_ID = "networkofferingid"; + public static final String NETWORK_IDS = "networkids"; + public static final String NETWORK_ID = "networkid"; + public static final String NIC_ID = "nicid"; + public static final String SPECIFY_VLAN = "specifyvlan"; + public static final String IS_DEFAULT = "isdefault"; + public static final String IS_SYSTEM = "issystem"; + public static final String AVAILABILITY = "availability"; + public static final String NETWORKRATE = "networkrate"; + public static final String HOST_TAGS = "hosttags"; + public static final String SSH_KEYPAIR = "keypair"; + public static final String HOST_CPU_CAPACITY = "hostcpucapacity"; + public static final String HOST_CPU_NUM = "hostcpunum"; + public static final String HOST_MEM_CAPACITY = "hostmemcapacity"; + public static final String HOST_MAC = "hostmac"; + public static final String HOST_TAG = "hosttag"; + public static final String PXE_SERVER_TYPE = "pxeservertype"; + public static final String LINMIN_USERNAME = "linminusername"; + public static final String LINMIN_PASSWORD = "linminpassword"; + public static final String LINMIN_APID = "linminapid"; + public static final String DHCP_SERVER_TYPE = "dhcpservertype"; + public static final String LINK_LOCAL_IP = "linklocalip"; + public static final String LINK_LOCAL_MAC_ADDRESS = "linklocalmacaddress"; + public static final String LINK_LOCAL_MAC_NETMASK = "linklocalnetmask"; + public static final String LINK_LOCAL_NETWORK_ID = "linklocalnetworkid"; + public static final String PRIVATE_MAC_ADDRESS = "privatemacaddress"; + public static final String PRIVATE_NETMASK = "privatenetmask"; + public static final String PRIVATE_NETWORK_ID = "privatenetworkid"; + public static final String ALLOCATION_STATE = "allocationstate"; + public static final String MANAGED_STATE = "managedstate"; + public static final String STORAGE_ID = "storageid"; + public static final String PING_STORAGE_SERVER_IP = "pingstorageserverip"; + public static final String PING_DIR = "pingdir"; + public static final String TFTP_DIR = "tftpdir"; + public static final String PING_CIFS_USERNAME = "pingcifsusername"; + public static final String PING_CIFS_PASSWORD = "pingcifspassword"; + public static final String CHECKSUM = "checksum"; + public static final String NETWORK_DEVICE_TYPE = "networkdevicetype"; + public static final String NETWORK_DEVICE_PARAMETER_LIST = "networkdeviceparameterlist"; + public static final String ZONE_TOKEN = "zonetoken"; + public static final String DHCP_PROVIDER = "dhcpprovider"; + public static final String RESULT = "success"; + public static final String LUN_ID = "lunId"; + public static final String IQN = "iqn"; + public static final String AGGREGATE_NAME = "aggregatename"; + public static final String POOL_NAME = "poolname"; + public static final String VOLUME_NAME = "volumename"; + public static final String SNAPSHOT_POLICY = "snapshotpolicy"; + public static final String SNAPSHOT_RESERVATION = "snapshotreservation"; + public static final String IP_NETWORK_LIST = "iptonetworklist"; + public static final String PARAM_LIST = "param"; + public static final String FOR_LOAD_BALANCING = "forloadbalancing"; + public static final String KEYBOARD = "keyboard"; + public static final String OPEN_FIREWALL = "openfirewall"; + public static final String TEMPLATE_TAG = "templatetag"; + public static final String HYPERVISOR_VERSION = "hypervisorversion"; + public static final String MAX_GUESTS_LIMIT = "maxguestslimit"; + public static final String PROJECT_ID = "projectid"; + public static final String PROJECT_IDS = "projectids"; + public static final String PROJECT = "project"; + public static final String ROLE = "role"; + public static final String USER = "user"; + public static final String ACTIVE_ONLY = "activeonly"; + public static final String TOKEN = "token"; + public static final String ACCEPT = "accept"; + public static final String SORT_KEY = "sortkey"; + public static final String ACCOUNT_DETAILS = "accountdetails"; + public static final String SERVICE_PROVIDER_LIST = "serviceproviderlist"; + public static final String SERVICE_CAPABILITY_LIST = "servicecapabilitylist"; + public static final String CAN_CHOOSE_SERVICE_CAPABILITY = "canchooseservicecapability"; + public static final String PROVIDER = "provider"; + public static final String NETWORK_SPEED = "networkspeed"; + public static final String BROADCAST_DOMAIN_RANGE = "broadcastdomainrange"; + public static final String ISOLATION_METHODS = "isolationmethods"; + public static final String PHYSICAL_NETWORK_ID = "physicalnetworkid"; + public static final String DEST_PHYSICAL_NETWORK_ID = "destinationphysicalnetworkid"; + public static final String ENABLED = "enabled"; + public static final String SERVICE_NAME = "servicename"; + public static final String DHCP_RANGE = "dhcprange"; + public static final String UUID = "uuid"; + public static final String SECURITY_GROUP_EANBLED = "securitygroupenabled"; + public static final String LOCAL_STORAGE_ENABLED = "localstorageenabled"; + public static final String GUEST_IP_TYPE = "guestiptype"; + public static final String XEN_NETWORK_LABEL = "xennetworklabel"; + public static final String KVM_NETWORK_LABEL = "kvmnetworklabel"; + public static final String VMWARE_NETWORK_LABEL = "vmwarenetworklabel"; + public static final String NETWORK_SERVICE_PROVIDER_ID = "nspid"; + public static final String SERVICE_LIST = "servicelist"; + public static final String CAN_ENABLE_INDIVIDUAL_SERVICE = "canenableindividualservice"; + public static final String SUPPORTED_SERVICES = "supportedservices"; + public static final String NSP_ID = "nspid"; + public static final String ACL_TYPE = "acltype"; + public static final String SUBDOMAIN_ACCESS = "subdomainaccess"; + public static final String LOAD_BALANCER_DEVICE_ID = "lbdeviceid"; + public static final String LOAD_BALANCER_DEVICE_NAME = "lbdevicename"; + public static final String LOAD_BALANCER_DEVICE_STATE = "lbdevicestate"; + public static final String LOAD_BALANCER_DEVICE_CAPACITY = "lbdevicecapacity"; + public static final String LOAD_BALANCER_DEVICE_DEDICATED = "lbdevicededicated"; + public static final String FIREWALL_DEVICE_ID = "fwdeviceid"; + public static final String FIREWALL_DEVICE_NAME = "fwdevicename"; + public static final String FIREWALL_DEVICE_STATE = "fwdevicestate"; + public static final String FIREWALL_DEVICE_CAPACITY = "fwdevicecapacity"; + public static final String FIREWALL_DEVICE_DEDICATED = "fwdevicededicated"; + public static final String SERVICE = "service"; + public static final String ASSOCIATED_NETWORK_ID = "associatednetworkid"; + public static final String ASSOCIATED_NETWORK_NAME = "associatednetworkname"; + public static final String SOURCE_NAT_SUPPORTED = "sourcenatsupported"; + public static final String RESOURCE_STATE = "resourcestate"; + public static final String PROJECT_INVITE_REQUIRED = "projectinviterequired"; + public static final String REQUIRED = "required"; + public static final String RESTART_REQUIRED = "restartrequired"; + public static final String ALLOW_USER_CREATE_PROJECTS = "allowusercreateprojects"; + public static final String CONSERVE_MODE = "conservemode"; + public static final String TRAFFIC_TYPE_IMPLEMENTOR = "traffictypeimplementor"; + public static final String KEYWORD = "keyword"; + public static final String LIST_ALL = "listall"; + public static final String SPECIFY_IP_RANGES = "specifyipranges"; + public static final String IS_SOURCE_NAT = "issourcenat"; + public static final String IS_STATIC_NAT = "isstaticnat"; + public static final String SORT_BY = "sortby"; + public static final String CHANGE_CIDR = "changecidr"; + public static final String PURPOSE = "purpose"; + public static final String IS_TAGGED = "istagged"; + public static final String INSTANCE_NAME = "instancename"; + public static final String START_VM = "startvm"; + public static final String HA_HOST = "hahost"; + public static final String CUSTOM_DISK_OFF_MAX_SIZE = "customdiskofferingmaxsize"; + public static final String DEFAULT_ZONE_ID = "defaultzoneid"; + public static final String GUID = "guid"; + + public static final String EXTERNAL_SWITCH_MGMT_DEVICE_ID = "vsmdeviceid"; + public static final String EXTERNAL_SWITCH_MGMT_DEVICE_NAME = "vsmdevicename"; + public static final String EXTERNAL_SWITCH_MGMT_DEVICE_STATE = "vsmdevicestate"; + // Would we need to have a capacity field for Cisco N1KV VSM? Max hosts managed by it perhaps? May remove this later. + public static final String EXTERNAL_SWITCH_MGMT_DEVICE_CAPACITY = "vsmdevicecapacity"; + public static final String CISCO_NEXUS_VSM_NAME = "vsmname"; + public static final String VSM_USERNAME = "vsmusername"; + public static final String VSM_PASSWORD = "vsmpassword"; + public static final String VSM_IPADDRESS = "vsmipaddress"; + public static final String VSM_MGMT_VLAN_ID = "vsmmgmtvlanid"; + public static final String VSM_PKT_VLAN_ID = "vsmpktvlanid"; + public static final String VSM_CTRL_VLAN_ID = "vsmctrlvlanid"; + public static final String VSM_STORAGE_VLAN_ID = "vsmstoragevlanid"; + public static final String VSM_DOMAIN_ID = "vsmdomainid"; + public static final String VSM_CONFIG_MODE = "vsmconfigmode"; + public static final String VSM_CONFIG_STATE = "vsmconfigstate"; + public static final String VSM_DEVICE_STATE = "vsmdevicestate"; + public static final String ADD_VSM_FLAG = "addvsmflag"; + public static final String END_POINT = "endpoint"; + public static final String REGION_ID = "regionid"; + public static final String IS_PROPAGATE = "ispropagate"; + public static final String VPC_OFF_ID = "vpcofferingid"; + public static final String NETWORK = "network"; + public static final String VPC_ID = "vpcid"; + public static final String GATEWAY_ID = "gatewayid"; + public static final String CAN_USE_FOR_DEPLOY = "canusefordeploy"; + public static final String RESOURCE_IDS = "resourceids"; + public static final String RESOURCE_ID = "resourceid"; + public static final String CUSTOMER = "customer"; + public static final String S2S_VPN_GATEWAY_ID = "s2svpngatewayid"; + public static final String S2S_CUSTOMER_GATEWAY_ID = "s2scustomergatewayid"; + public static final String IPSEC_PSK = "ipsecpsk"; + public static final String GUEST_IP = "guestip"; + public static final String REMOVED = "removed"; + public static final String IKE_POLICY = "ikepolicy"; + public static final String ESP_POLICY = "esppolicy"; + public static final String IKE_LIFETIME = "ikelifetime"; + public static final String ESP_LIFETIME = "esplifetime"; + public static final String DPD = "dpd"; + public static final String FOR_VPC = "forvpc"; + public static final String SHRINK_OK = "shrinkok"; + public static final String NICIRA_NVP_DEVICE_ID = "nvpdeviceid"; + public static final String NICIRA_NVP_TRANSPORT_ZONE_UUID = "transportzoneuuid"; + public static final String NICIRA_NVP_DEVICE_NAME = "niciradevicename"; + public static final String NICIRA_NVP_GATEWAYSERVICE_UUID = "l3gatewayserviceuuid"; + public static final String S3_ACCESS_KEY = "accesskey"; + public static final String S3_SECRET_KEY = "secretkey"; + public static final String S3_END_POINT = "endpoint"; + public static final String S3_BUCKET_NAME = "bucket"; + public static final String S3_HTTPS_FLAG = "usehttps"; + public static final String S3_CONNECTION_TIMEOUT = "connectiontimeout"; + public static final String S3_MAX_ERROR_RETRY = "maxerrorretry"; + public static final String S3_SOCKET_TIMEOUT = "sockettimeout"; + public static final String INCL_ZONES = "includezones"; + public static final String EXCL_ZONES = "excludezones"; + public static final String SOURCE = "source"; + public static final String COUNTER_ID = "counterid"; + public static final String AGGR_OPERATOR = "aggroperator"; + public static final String AGGR_FUNCTION = "aggrfunction"; + public static final String AGGR_VALUE = "aggrvalue"; + public static final String THRESHOLD = "threshold"; + public static final String RELATIONAL_OPERATOR = "relationaloperator"; + public static final String OTHER_DEPLOY_PARAMS = "otherdeployparams"; + public static final String MIN_MEMBERS = "minmembers"; + public static final String MAX_MEMBERS = "maxmembers"; + public static final String AUTOSCALE_VM_DESTROY_TIME = "destroyvmgraceperiod"; + public static final String VMPROFILE_ID = "vmprofileid"; + public static final String VMGROUP_ID = "vmgroupid"; + public static final String CS_URL = "csurl"; + public static final String SCALEUP_POLICY_IDS = "scaleuppolicyids"; + public static final String SCALEDOWN_POLICY_IDS = "scaledownpolicyids"; + public static final String SCALEUP_POLICIES = "scaleuppolicies"; + public static final String SCALEDOWN_POLICIES = "scaledownpolicies"; + public static final String INTERVAL = "interval"; + public static final String QUIETTIME = "quiettime"; + public static final String ACTION = "action"; + public static final String CONDITION_ID = "conditionid"; + public static final String CONDITION_IDS = "conditionids"; + public static final String COUNTERPARAM_LIST = "counterparam"; + public static final String AUTOSCALE_USER_ID = "autoscaleuserid"; + public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername"; +<<<<<<< HEAD + public static final String UCS_DN = "ucsdn"; +======= + public static final String VM_SNAPSHOT_DESCRIPTION = "description"; + public static final String VM_SNAPSHOT_DISPLAYNAME = "name"; + public static final String VM_SNAPSHOT_ID = "vmsnapshotid"; + public static final String VM_SNAPSHOT_DISK_IDS = "vmsnapshotdiskids"; + public static final String VM_SNAPSHOT_MEMORY = "snapshotmemory"; +>>>>>>> CLOUDSTACK-684 Support VM Snapshot + + public enum HostDetails { + all, capacity, events, stats, min; + } + + public enum VMDetails { + all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min; + } + + public enum LDAPParams { + hostname, port, usessl, queryfilter, searchbase, dn, passwd, truststore, truststorepass; + + @Override + public String toString() { + return "ldap." + name(); + } + } + + +} diff --git a/api/src/org/apache/cloudstack/api/ApiErrorCode.java b/api/src/org/apache/cloudstack/api/ApiErrorCode.java index ee28fa05878..69bd0284cef 100644 --- a/api/src/org/apache/cloudstack/api/ApiErrorCode.java +++ b/api/src/org/apache/cloudstack/api/ApiErrorCode.java @@ -18,7 +18,6 @@ package org.apache.cloudstack.api; /** * Enum class for various API error code used in CloudStack - * @author minc * */ public enum ApiErrorCode { diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index a9ac489671b..816b6deed77 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -62,6 +62,7 @@ import com.cloud.resource.ResourceService; import com.cloud.server.ManagementService; import com.cloud.server.TaggedResourceService; import com.cloud.storage.StorageService; +import com.cloud.storage.VolumeApiService; import com.cloud.storage.snapshot.SnapshotService; import com.cloud.template.TemplateService; import com.cloud.user.Account; @@ -69,8 +70,8 @@ import com.cloud.user.AccountService; import com.cloud.user.DomainService; import com.cloud.user.ResourceLimitService; import com.cloud.utils.Pair; -import com.cloud.vm.BareMetalVmService; import com.cloud.vm.UserVmService; +import com.cloud.vm.snapshot.VMSnapshotService; public abstract class BaseCmd { private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName()); @@ -101,6 +102,7 @@ public abstract class BaseCmd { @Inject public UserVmService _userVmService; @Inject public ManagementService _mgr; @Inject public StorageService _storageService; + @Inject public VolumeApiService _volumeService; @Inject public ResourceService _resourceService; @Inject public NetworkService _networkService; @Inject public TemplateService _templateService; @@ -128,6 +130,7 @@ public abstract class BaseCmd { @Inject public QueryService _queryService; @Inject public UsageService _usageService; @Inject public NetworkUsageService _networkUsageService; + @Inject public VMSnapshotService _vmSnapshotService; public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException; diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index 0dc85de1647..267238af37b 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -88,6 +88,7 @@ import org.apache.cloudstack.api.response.TrafficTypeResponse; import org.apache.cloudstack.api.response.UsageRecordResponse; import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VMSnapshotResponse; import org.apache.cloudstack.api.response.VirtualRouterProviderResponse; import org.apache.cloudstack.api.response.VlanIpRangeResponse; import org.apache.cloudstack.api.response.VolumeResponse; @@ -163,6 +164,7 @@ import com.cloud.user.UserAccount; import com.cloud.uservm.UserVm; import com.cloud.vm.InstanceGroup; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.snapshot.VMSnapshot; public interface ResponseGenerator { UserResponse createUserResponse(UserAccount user); @@ -381,5 +383,6 @@ public interface ResponseGenerator { UsageRecordResponse createUsageResponse(Usage usageRecord); - TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor); + TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor); + VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot); } diff --git a/api/src/org/apache/cloudstack/api/ServerApiException.java b/api/src/org/apache/cloudstack/api/ServerApiException.java index 682e5b7e774..4b0fae58548 100644 --- a/api/src/org/apache/cloudstack/api/ServerApiException.java +++ b/api/src/org/apache/cloudstack/api/ServerApiException.java @@ -43,7 +43,7 @@ public class ServerApiException extends CloudRuntimeException { super(description, cause); _errorCode = errorCode; _description = description; - if (cause instanceof CloudRuntimeException || cause instanceof CloudException ) { + if (cause instanceof CloudRuntimeException) { CloudRuntimeException rt = (CloudRuntimeException) cause; ArrayList idList = rt.getIdProxyList(); if (idList != null) { @@ -52,6 +52,15 @@ public class ServerApiException extends CloudRuntimeException { } } setCSErrorCode(rt.getCSErrorCode()); + } else if (cause instanceof CloudException) { + CloudException rt = (CloudException) cause; + ArrayList idList = rt.getIdProxyList(); + if (idList != null) { + for (int i = 0; i < idList.size(); i++) { + addProxyObject(idList.get(i)); + } + } + setCSErrorCode(rt.getCSErrorCode()); } } diff --git a/api/src/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java index 912c396bf4f..7b1cd067eb1 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java @@ -20,6 +20,10 @@ package org.apache.cloudstack.api.command.admin.cluster; import java.util.ArrayList; import java.util.List; +import com.cloud.exception.InvalidParameterValueException; +import org.apache.cloudstack.api.*; +import org.apache.log4j.Logger; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -81,6 +85,12 @@ public class AddClusterCmd extends BaseCmd { @Parameter(name = ApiConstants.VSM_IPADDRESS, type = CommandType.STRING, required = false, description = "the ipaddress of the VSM associated with this cluster") private String vsmipaddress; + @Parameter (name=ApiConstants.CPU_OVERCOMMIT_RATIO, type = CommandType.STRING, required = false , description = "value of the cpu overcommit ratio, defaults to 1") + private String cpuovercommitRatio; + + @Parameter(name = ApiConstants.MEMORY_OVERCOMMIT_RATIO, type = CommandType.STRING, required = false ,description = "value of the default ram overcommit ratio, defaults to 1") + private String memoryovercommitratio; + public String getVSMIpaddress() { return vsmipaddress; } @@ -147,9 +157,26 @@ public class AddClusterCmd extends BaseCmd { this.allocationState = allocationState; } + public Float getCpuOvercommitRatio (){ + if(cpuovercommitRatio != null){ + return Float.parseFloat(cpuovercommitRatio); + } + return 1.0f; + } + + public Float getMemoryOvercommitRaito (){ + if (memoryovercommitratio != null){ + return Float.parseFloat(memoryovercommitratio); + } + return 1.0f; + } + @Override public void execute(){ try { + if ((getMemoryOvercommitRaito().compareTo(1f) < 0) | (getCpuOvercommitRatio().compareTo(1f) < 0)) { + throw new InvalidParameterValueException("Cpu and ram overcommit ratios should not be less than 1"); + } List result = _resourceService.discoverCluster(this); ListResponse response = new ListResponse(); List clusterResponses = new ArrayList(); diff --git a/api/src/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java index 058c7ebc952..95728dd184d 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java @@ -54,6 +54,13 @@ public class UpdateClusterCmd extends BaseCmd { @Parameter(name=ApiConstants.MANAGED_STATE, type=CommandType.STRING, description="whether this cluster is managed by cloudstack") private String managedState; + @Parameter(name=ApiConstants.CPU_OVERCOMMIT_RATIO, type = CommandType.STRING, description = "Value of cpu overcommit ratio") + private String cpuovercommitratio; + + @Parameter(name=ApiConstants.MEMORY_OVERCOMMIT_RATIO, type = CommandType.STRING, description = "Value of ram overcommit ratio") + private String memoryovercommitratio; + + public String getClusterName() { return clusterName; } @@ -100,6 +107,20 @@ public class UpdateClusterCmd extends BaseCmd { this.managedState = managedstate; } + public Float getCpuOvercommitRatio (){ + if(cpuovercommitratio != null){ + return Float.parseFloat(cpuovercommitratio); + } + return 1.0f; + } + + public Float getMemoryOvercommitRaito (){ + if (memoryovercommitratio != null){ + return Float.parseFloat(memoryovercommitratio); + } + return 1.0f; + } + @Override public void execute(){ Cluster cluster = _resourceService.getCluster(getId()); @@ -107,7 +128,11 @@ public class UpdateClusterCmd extends BaseCmd { throw new InvalidParameterValueException("Unable to find the cluster by id=" + getId()); } - Cluster result = _resourceService.updateCluster(cluster, getClusterType(), getHypervisor(), getAllocationState(), getManagedstate()); + if ((getMemoryOvercommitRaito().compareTo(1f) < 0) | (getCpuOvercommitRatio().compareTo(1f) < 0)) { + throw new InvalidParameterValueException("Cpu and ram overcommit ratios should be greater than one"); + } + + Cluster result = _resourceService.updateCluster(cluster, getClusterType(), getHypervisor(), getAllocationState(), getManagedstate(), getMemoryOvercommitRaito(), getCpuOvercommitRatio()); if (result != null) { ClusterResponse clusterResponse = _responseGenerator.createClusterResponse(cluster, false); clusterResponse.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPConfigCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPConfigCmd.java index fbe8ab000e6..2976de4bf28 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPConfigCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPConfigCmd.java @@ -31,6 +31,7 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.user.Account; @APICommand(name = "ldapConfig", description="Configure the LDAP context for this site.", responseObject=LDAPConfigResponse.class, since="3.0.0") @@ -43,7 +44,10 @@ public class LDAPConfigCmd extends BaseCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name=ApiConstants.HOST_NAME, type=CommandType.STRING, required=true, description="Hostname or ip address of the ldap server eg: my.ldap.com") + @Parameter(name=ApiConstants.LIST_ALL, type=CommandType.STRING, description="Hostname or ip address of the ldap server eg: my.ldap.com") + private String listall; + + @Parameter(name=ApiConstants.HOST_NAME, type=CommandType.STRING, description="Hostname or ip address of the ldap server eg: my.ldap.com") private String hostname; @Parameter(name=ApiConstants.PORT, type=CommandType.INTEGER, description="Specify the LDAP port if required, default is 389.") @@ -52,10 +56,10 @@ public class LDAPConfigCmd extends BaseCmd { @Parameter(name=ApiConstants.USE_SSL, type=CommandType.BOOLEAN, description="Check Use SSL if the external LDAP server is configured for LDAP over SSL.") private Boolean useSSL; - @Parameter(name=ApiConstants.SEARCH_BASE, type=CommandType.STRING, required=true, description="The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com.") + @Parameter(name=ApiConstants.SEARCH_BASE, type=CommandType.STRING, description="The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com.") private String searchBase; - @Parameter(name=ApiConstants.QUERY_FILTER, type=CommandType.STRING, required=true, description="You specify a query filter here, which narrows down the users, who can be part of this domain.") + @Parameter(name=ApiConstants.QUERY_FILTER, type=CommandType.STRING, description="You specify a query filter here, which narrows down the users, who can be part of this domain.") private String queryFilter; @Parameter(name=ApiConstants.BIND_DN, type=CommandType.STRING, description="Specify the distinguished name of a user with the search permission on the directory.") @@ -74,6 +78,10 @@ public class LDAPConfigCmd extends BaseCmd { /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// + public String getListAll() { + return listall == null ? "false" : listall; + } + public String getBindPassword() { return bindPassword; } @@ -82,30 +90,56 @@ public class LDAPConfigCmd extends BaseCmd { return bindDN; } + public void setBindDN(String bdn) { + this.bindDN=bdn; + } + public String getQueryFilter() { return queryFilter; } + public void setQueryFilter(String queryFilter) { + this.queryFilter=queryFilter; + } public String getSearchBase() { return searchBase; } + public void setSearchBase(String searchBase) { + this.searchBase=searchBase; + } + public Boolean getUseSSL() { - return useSSL == null ? Boolean.FALSE : Boolean.TRUE; + return useSSL == null ? Boolean.FALSE : useSSL; + } + + public void setUseSSL(Boolean useSSL) { + this.useSSL=useSSL; } public String getHostname() { return hostname; } + public void setHostname(String hostname) { + this.hostname=hostname; + } + public Integer getPort() { return port <= 0 ? 389 : port; } + public void setPort(Integer port) { + this.port=port; + } + public String getTrustStore() { return trustStore; } + public void setTrustStore(String trustStore) { + this.trustStore=trustStore; + } public String getTrustStorePassword() { return trustStorePassword; @@ -122,12 +156,25 @@ public class LDAPConfigCmd extends BaseCmd { InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { try { - boolean result = _configService.updateLDAP(this); - if (result){ - LDAPConfigResponse lr = _responseGenerator.createLDAPConfigResponse(getHostname(), getPort(), getUseSSL(), getQueryFilter(), getSearchBase(), getBindDN()); + if ("true".equalsIgnoreCase(getListAll())){ + // return the existing conf + LDAPConfigCmd cmd = _configService.listLDAPConfig(this); + LDAPConfigResponse lr = _responseGenerator.createLDAPConfigResponse(cmd.getHostname(), cmd.getPort(), cmd.getUseSSL(), + cmd.getQueryFilter(), cmd.getSearchBase(), cmd.getBindDN()); lr.setResponseName(getCommandName()); this.setResponseObject(lr); } + else if (getHostname()==null || getSearchBase() == null || getQueryFilter() == null) { + throw new InvalidParameterValueException("You need to provide hostname, serachbase and queryfilter to configure your LDAP server"); + } + else { + boolean result = _configService.updateLDAP(this); + if (result){ + LDAPConfigResponse lr = _responseGenerator.createLDAPConfigResponse(getHostname(), getPort(), getUseSSL(), getQueryFilter(), getSearchBase(), getBindDN()); + lr.setResponseName(getCommandName()); + this.setResponseObject(lr); + } + } } catch (NamingException ne){ ne.printStackTrace(); diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index ee1e1b20bfc..e915c48e9b6 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -59,6 +59,9 @@ public class CreateServiceOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.LIMIT_CPU_USE, type=CommandType.BOOLEAN, description="restrict the CPU usage to committed service offering") private Boolean limitCpuUse; + @Parameter(name=ApiConstants.IS_VOLATILE, type=CommandType.BOOLEAN, description="true if the virtual machine needs to be volatile so that on every reboot of VM, original root disk is dettached then destroyed and a fresh root disk is created and attached to VM") + private Boolean isVolatile; + @Parameter(name=ApiConstants.STORAGE_TYPE, type=CommandType.STRING, description="the storage type of the service offering. Values are local and shared.") private String storageType; @@ -106,11 +109,15 @@ public class CreateServiceOfferingCmd extends BaseCmd { } public Boolean getOfferHa() { - return offerHa; + return offerHa == null ? false : offerHa; } public Boolean GetLimitCpuUse() { - return limitCpuUse; + return limitCpuUse == null ? false : limitCpuUse; + } + + public Boolean getVolatileVm() { + return isVolatile == null ? false : isVolatile; } public String getStorageType() { diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/UpgradeRouterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/UpgradeRouterCmd.java index c2cde163eba..b049f66f648 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/UpgradeRouterCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/UpgradeRouterCmd.java @@ -22,8 +22,8 @@ import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainRouterResponse; +import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.log4j.Logger; import com.cloud.network.router.VirtualRouter; @@ -42,7 +42,7 @@ public class UpgradeRouterCmd extends BaseCmd { required=true, description="The ID of the router") private Long id; - @Parameter(name=ApiConstants.SERVICE_OFFERING_ID, type=CommandType.UUID, entityType = DiskOfferingResponse.class, + @Parameter(name=ApiConstants.SERVICE_OFFERING_ID, type=CommandType.UUID, entityType = ServiceOfferingResponse.class, required=true, description="the service offering ID to apply to the domain router") private Long serviceOfferingId; diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java index a3497a89f98..da9d3467792 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java @@ -36,6 +36,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.storage.StoragePool; import com.cloud.user.Account; + @SuppressWarnings("rawtypes") @APICommand(name = "createStoragePool", description="Creates a storage pool.", responseObject=StoragePoolResponse.class) public class CreateStoragePoolCmd extends BaseCmd { @@ -70,6 +71,14 @@ public class CreateStoragePoolCmd extends BaseCmd { @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, required=true, description="the Zone ID for the storage pool") private Long zoneId; + + @Parameter(name=ApiConstants.PROVIDER, type=CommandType.STRING, + required=false, description="the storage provider uuid") + private String storageProviderUuid; + + @Parameter(name=ApiConstants.SCOPE, type=CommandType.STRING, + required=false, description="the scope of the storage: cluster or zone") + private String scope; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -102,6 +111,14 @@ public class CreateStoragePoolCmd extends BaseCmd { public Long getZoneId() { return zoneId; } + + public String getStorageProviderUuid() { + return this.storageProviderUuid; + } + + public String getScope() { + return this.scope; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/systemvm/UpgradeSystemVMCmd.java b/api/src/org/apache/cloudstack/api/command/admin/systemvm/UpgradeSystemVMCmd.java index a70d927f020..e91d0053c64 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/systemvm/UpgradeSystemVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/systemvm/UpgradeSystemVMCmd.java @@ -23,7 +23,7 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; -import org.apache.cloudstack.api.response.DiskOfferingResponse; +import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.SystemVmResponse; import org.apache.log4j.Logger; @@ -48,7 +48,7 @@ public class UpgradeSystemVMCmd extends BaseCmd { required=true, description="The ID of the system vm") private Long id; - @Parameter(name=ApiConstants.SERVICE_OFFERING_ID, type=CommandType.UUID, entityType=DiskOfferingResponse.class, + @Parameter(name=ApiConstants.SERVICE_OFFERING_ID, type=CommandType.UUID, entityType=ServiceOfferingResponse.class, required=true, description="the service offering ID to apply to the system vm") private Long serviceOfferingId; diff --git a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java index f08cb16b23d..3c7956b7d7e 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java @@ -16,7 +16,7 @@ // under the License. package org.apache.cloudstack.api.command.admin.vpc; -import java.util.List; +import java.util.*; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -52,6 +52,10 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd{ description="services supported by the vpc offering") private List supportedServices; + @Parameter(name = ApiConstants.SERVICE_PROVIDER_LIST, type = CommandType.MAP, description = "provider to service mapping. " + + "If not specified, the provider for the service will be mapped to the default provider on the physical network") + private Map serviceProviderList; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -68,10 +72,33 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd{ return supportedServices; } + public Map> getServiceProviders() { + Map> serviceProviderMap = null; + if (serviceProviderList != null && !serviceProviderList.isEmpty()) { + serviceProviderMap = new HashMap>(); + Collection servicesCollection = serviceProviderList.values(); + Iterator iter = servicesCollection.iterator(); + while (iter.hasNext()) { + HashMap services = (HashMap) iter.next(); + String service = services.get("service"); + String provider = services.get("provider"); + List providerList = null; + if (serviceProviderMap.containsKey(service)) { + providerList = serviceProviderMap.get(service); + } else { + providerList = new ArrayList(); + } + providerList.add(provider); + serviceProviderMap.put(service, providerList); + } + } + + return serviceProviderMap; + } @Override public void create() throws ResourceAllocationException { - VpcOffering vpcOff = _vpcService.createVpcOffering(getVpcOfferingName(), getDisplayText(), getSupportedServices()); + VpcOffering vpcOff = _vpcService.createVpcOffering(getVpcOfferingName(), getDisplayText(), getSupportedServices(), getServiceProviders()); if (vpcOff != null) { this.setEntityId(vpcOff.getId()); this.setEntityUuid(vpcOff.getUuid()); diff --git a/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java b/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java index ecfd8df0ceb..87d4466e79a 100644 --- a/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmProfileCmd.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.BaseAsyncCreateCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse; -import org.apache.cloudstack.api.response.DiskOfferingResponse; +import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.TemplateResponse; import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.ZoneResponse; @@ -56,7 +56,7 @@ public class CreateAutoScaleVmProfileCmd extends BaseAsyncCreateCmd { required = true, description = "availability zone for the auto deployed virtual machine") private Long zoneId; - @Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = DiskOfferingResponse.class, + @Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = ServiceOfferingResponse.class, required = true, description = "the service offering of the auto deployed virtual machine") private Long serviceOfferingId; diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java index a4a37c8fd58..284d5530846 100644 --- a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java @@ -88,6 +88,10 @@ public class RegisterIsoCmd extends BaseCmd { @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, description="Register iso for the project") private Long projectId; + + @Parameter(name=ApiConstants.IMAGE_STORE_UUID, type=CommandType.STRING, + description="Image store uuid") + private String imageStoreUuid; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -140,6 +144,10 @@ public class RegisterIsoCmd extends BaseCmd { public String getChecksum() { return checksum; } + + public String getImageStoreUuid() { + return this.imageStoreUuid; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index 5ec7cefb052..fc7bd9fdd3f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -268,10 +268,6 @@ public class CreateNetworkCmd extends BaseCmd { @Override // an exception thrown by createNetwork() will be caught by the dispatcher. public void execute() throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException{ - if (getStartIpv6() != null && getStartIp() != null) { - throw new InvalidParameterValueException("Cannot support dualstack at this moment!"); - } - Network result = _networkService.createGuestNetwork(this); if (result != null) { NetworkResponse response = _responseGenerator.createNetworkResponse(result); diff --git a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java index 67774075774..41aaaaada12 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java @@ -64,6 +64,9 @@ public class UpdateNetworkCmd extends BaseAsyncCmd { description="network offering ID") private Long networkOfferingId; + @Parameter(name=ApiConstants.GUEST_VM_CIDR, type=CommandType.STRING, description="CIDR for Guest VMs,Cloudstack allocates IPs to Guest VMs only from this CIDR") + private String guestVmCidr; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -94,6 +97,10 @@ public class UpdateNetworkCmd extends BaseAsyncCmd { } return false; } + + private String getGuestVmCidr() { + return guestVmCidr; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -125,10 +132,10 @@ public class UpdateNetworkCmd extends BaseAsyncCmd { Network result = null; if (network.getVpcId() != null) { result = _vpcService.updateVpcGuestNetwork(getId(), getNetworkName(), getDisplayText(), callerAccount, - callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr()); + callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr(), getGuestVmCidr()); } else { result = _networkService.updateGuestNetwork(getId(), getNetworkName(), getDisplayText(), callerAccount, - callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr()); + callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr(), getGuestVmCidr()); } if (result != null) { diff --git a/api/src/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java b/api/src/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java index 91728ee9cf6..f6d3a98a05d 100644 --- a/api/src/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java @@ -53,12 +53,17 @@ public class UpdateResourceCountCmd extends BaseCmd { required=true, description="If account parameter specified then updates resource counts for a specified account in this domain else update resource counts for all accounts & child domains in specified domain.") private Long domainId; - @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.INTEGER, description= "Type of resource to update. If specifies valid values are 0, 1, 2, 3, and 4. If not specified will update all resource counts" + + @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.INTEGER, description= "Type of resource to update. If specifies valid values are 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9. If not specified will update all resource counts" + "0 - Instance. Number of instances a user can create. " + "1 - IP. Number of public IP addresses a user can own. " + "2 - Volume. Number of disk volumes a user can create." + "3 - Snapshot. Number of snapshots a user can create." + - "4 - Template. Number of templates that a user can register/create.") + "4 - Template. Number of templates that a user can register/create." + + "5 - Project. Number of projects that a user can create." + + "6 - Network. Number of guest network a user can create." + + "7 - VPC. Number of VPC a user can create." + + "8 - CPU. Total number of CPU cores a user can use." + + "9 - Memory. Total Memory (in MB) a user can use." ) private Integer resourceType; @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, diff --git a/api/src/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java b/api/src/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java index 33f2574d3e1..0039f6293f7 100644 --- a/api/src/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java @@ -54,11 +54,15 @@ public class UpdateResourceLimitCmd extends BaseCmd { @Parameter(name=ApiConstants.MAX, type=CommandType.LONG, description=" Maximum resource limit.") private Long max; - @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.INTEGER, required=true, description="Type of resource to update. Values are 0, 1, 2, 3, and 4. 0 - Instance. Number of instances a user can create. " + + @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.INTEGER, required=true, description="Type of resource to update. Values are 0, 1, 2, 3, 4, 6, 7, 8 and 9. 0 - Instance. Number of instances a user can create. " + "1 - IP. Number of public IP addresses a user can own. " + "2 - Volume. Number of disk volumes a user can create." + "3 - Snapshot. Number of snapshots a user can create." + - "4 - Template. Number of templates that a user can register/create.") + "4 - Template. Number of templates that a user can register/create." + + "6 - Network. Number of guest network a user can create." + + "7 - VPC. Number of VPC a user can create." + + "8 - CPU. Total number of CPU cores a user can use." + + "9 - Memory. Total Memory (in MB) a user can use." ) private Integer resourceType; ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java index 84fa197d12c..ba1f924fe02 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java @@ -240,7 +240,7 @@ import com.cloud.user.UserContext; @Override public void create() throws ResourceAllocationException { VirtualMachineTemplate template = null; - template = _userVmService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); + template = this._templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); if (template != null) { this.setEntityId(template.getId()); this.setEntityUuid(template.getUuid()); @@ -255,7 +255,7 @@ import com.cloud.user.UserContext; public void execute() { UserContext.current().setEventDetails("Template Id: "+getEntityId()+((getSnapshotId() == null) ? " from volume Id: " + getVolumeId() : " from snapshot Id: " + getSnapshotId())); VirtualMachineTemplate template = null; - template = _userVmService.createPrivateTemplate(this); + template = this._templateService.createPrivateTemplate(this); if (template != null){ List templateResponses; diff --git a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java index 3e98ca624ab..c9da0c28cd6 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java @@ -110,7 +110,11 @@ public class RegisterTemplateCmd extends BaseCmd { @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, description="Register template for the project") private Long projectId; - + + @Parameter(name=ApiConstants.IMAGE_STORE_UUID, type=CommandType.STRING, + description="Image store uuid") + private String imageStoreUuid; + @Parameter(name=ApiConstants.DETAILS, type=CommandType.MAP, description="Template details in key/value pairs.") protected Map details; @@ -189,6 +193,10 @@ public class RegisterTemplateCmd extends BaseCmd { public String getTemplateTag() { return templateTag; } + + public String getImageStoreUuid() { + return this.imageStoreUuid; + } public Map getDetails() { if (details == null || details.isEmpty()) { diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java old mode 100644 new mode 100755 index 70a263d06d2..0ac6476cf43 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -306,9 +306,6 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { if (requestedIpv6 != null) { requestedIpv6 = requestedIpv6.toLowerCase(); } - if (requestedIpv6 != null) { - throw new InvalidParameterValueException("Cannot support specified IPv6 address!"); - } IpAddresses addrs = new IpAddresses(requestedIp, requestedIpv6); ipToNetworkMap.put(networkId, addrs); } @@ -388,7 +385,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); } catch (InsufficientCapacityException ex) { s_logger.info(ex); - s_logger.trace(ex); + s_logger.info(ex.getMessage(), ex); throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage()); } } else { @@ -407,10 +404,6 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ try { - if (getIp6Address() != null) { - throw new InvalidParameterValueException("Cannot support specified IPv6 address!"); - } - //Verify that all objects exist before passing them to the service Account owner = _accountService.getActiveAccountById(getEntityOwnerId()); @@ -477,7 +470,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { } } catch (InsufficientCapacityException ex) { s_logger.info(ex); - s_logger.trace(ex); + s_logger.trace(ex.getMessage(), ex); throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage()); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/RestoreVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/RestoreVMCmd.java index e98c2f2eddc..9c33f97c317 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/RestoreVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/RestoreVMCmd.java @@ -22,6 +22,7 @@ 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.TemplateResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.log4j.Logger; @@ -34,7 +35,7 @@ import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; -@APICommand(name = "restoreVirtualMachine", description="Restore a VM to original template or specific snapshot", responseObject=UserVmResponse.class, since="3.0.0") +@APICommand(name = "restoreVirtualMachine", description="Restore a VM to original template or new template", responseObject=UserVmResponse.class, since="3.0.0") public class RestoreVMCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(RestoreVMCmd.class); private static final String s_name = "restorevmresponse"; @@ -43,6 +44,9 @@ public class RestoreVMCmd extends BaseAsyncCmd { required=true, description="Virtual Machine ID") private Long vmId; + @Parameter(name=ApiConstants.TEMPLATE_ID, type=CommandType.UUID, entityType = TemplateResponse.class, description="an optional template Id to restore vm from the new template") + private Long templateId; + @Override public String getEventType() { return EventTypes.EVENT_VM_RESTORE; @@ -85,4 +89,8 @@ public class RestoreVMCmd extends BaseAsyncCmd { public long getVmId() { return vmId; } + + public Long getTemplateId() { + return templateId; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/CreateVMSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/CreateVMSnapshotCmd.java new file mode 100644 index 00000000000..f0dbf16b250 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/CreateVMSnapshotCmd.java @@ -0,0 +1,125 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.user.vmsnapshot; + +import java.util.logging.Logger; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VMSnapshotResponse; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.user.UserContext; +import com.cloud.uservm.UserVm; +import com.cloud.vm.snapshot.VMSnapshot; + +@APICommand(name = "createVMSnapshot", description = "Creates snapshot for a vm.", responseObject = VMSnapshotResponse.class) +public class CreateVMSnapshotCmd extends BaseAsyncCreateCmd { + + public static final Logger s_logger = Logger + .getLogger(CreateVMSnapshotCmd.class.getName()); + private static final String s_name = "createvmsnapshotresponse"; + + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, required = true, entityType=UserVmResponse.class, description = "The ID of the vm") + private Long vmId; + + @Parameter(name = ApiConstants.VM_SNAPSHOT_DESCRIPTION, type = CommandType.STRING, required = false, description = "The discription of the snapshot") + private String description; + + @Parameter(name = ApiConstants.VM_SNAPSHOT_DISPLAYNAME, type = CommandType.STRING, required = false, description = "The display name of the snapshot") + private String displayName; + + @Parameter(name = ApiConstants.VM_SNAPSHOT_MEMORY, type = CommandType.BOOLEAN, required = false, description = "snapshot memory if true") + private Boolean snapshotMemory; + + public Boolean snapshotMemory() { + if (snapshotMemory == null) { + return false; + } else { + return snapshotMemory; + } + } + + public String getDisplayName() { + return displayName; + } + + public String getDescription() { + return description; + } + + public Long getVmId() { + return vmId; + } + + @Override + public void create() throws ResourceAllocationException { + VMSnapshot vmsnapshot = _vmSnapshotService.allocVMSnapshot(getVmId(),getDisplayName(),getDescription(),snapshotMemory()); + if (vmsnapshot != null) { + this.setEntityId(vmsnapshot.getId()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, + "Failed to create vm snapshot"); + } + } + + @Override + public String getEventDescription() { + return "creating snapshot for VM: " + getVmId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VM_SNAPSHOT_CREATE; + } + + @Override + public void execute() { + UserContext.current().setEventDetails("VM Id: " + getVmId()); + VMSnapshot result = _vmSnapshotService.creatVMSnapshot(getVmId(),getEntityId()); + if (result != null) { + VMSnapshotResponse response = _responseGenerator + .createVMSnapshotResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException( + ApiErrorCode.INTERNAL_ERROR, + "Failed to create vm snapshot due to an internal error creating snapshot for vm " + + getVmId()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + UserVm userVM = _userVmService.getUserVm(vmId); + return userVM.getAccountId(); + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/DeleteVMSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/DeleteVMSnapshotCmd.java new file mode 100644 index 00000000000..a2b2c08b381 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/DeleteVMSnapshotCmd.java @@ -0,0 +1,85 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.user.vmsnapshot; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.VMSnapshotResponse; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import com.cloud.vm.snapshot.VMSnapshot; + +@APICommand(name="deleteVMSnapshot", description = "Deletes a vmsnapshot.", responseObject = SuccessResponse.class) +public class DeleteVMSnapshotCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger + .getLogger(DeleteVMSnapshotCmd.class.getName()); + private static final String s_name = "deletevmsnapshotresponse"; + + @Parameter(name=ApiConstants.VM_SNAPSHOT_ID, type=CommandType.UUID, entityType=VMSnapshotResponse.class, + required=true, description="The ID of the VM snapshot") + private Long id; + + public Long getId() { + return id; + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + VMSnapshot vmSnapshot = _entityMgr.findById(VMSnapshot.class, getId()); + if (vmSnapshot != null) { + return vmSnapshot.getAccountId(); + } + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + UserContext.current().setEventDetails("vmsnapshot id: " + getId()); + boolean result = _vmSnapshotService.deleteVMSnapshot(getId()); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete vm snapshot"); + } + } + + @Override + public String getEventDescription() { + return "Delete VM snapshot: " + getId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VM_SNAPSHOT_DELETE; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java new file mode 100644 index 00000000000..936d348950d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java @@ -0,0 +1,89 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.user.vmsnapshot; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VMSnapshotResponse; + +import com.cloud.vm.snapshot.VMSnapshot; + +@APICommand(name="listVMSnapshot", description = "List virtual machine snapshot by conditions", responseObject = VMSnapshotResponse.class) +public class ListVMSnapshotCmd extends BaseListTaggedResourcesCmd { + + private static final String s_name = "listvmsnapshotresponse"; + + @Parameter(name=ApiConstants.VM_SNAPSHOT_ID, type=CommandType.UUID, entityType=VMSnapshotResponse.class, + description="The ID of the VM snapshot") + private Long id; + + @Parameter(name=ApiConstants.STATE, type=CommandType.STRING, description="state of the virtual machine snapshot") + private String state; + + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType=UserVmResponse.class, description = "the ID of the vm") + private Long vmId; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "lists snapshot by snapshot name or display name") + private String vmSnapshotName; + + public String getState() { + return state; + } + + public String getVmSnapshotName() { + return vmSnapshotName; + } + + public Long getVmId() { + return vmId; + } + + public Long getId() { + return id; + } + + @Override + public void execute() { + List result = _vmSnapshotService + .listVMSnapshots(this); + ListResponse response = new ListResponse(); + List snapshotResponses = new ArrayList(); + 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; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java new file mode 100644 index 00000000000..d7b4599d6c4 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java @@ -0,0 +1,92 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.vmsnapshot; + +import java.util.logging.Logger; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VMSnapshotResponse; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import com.cloud.uservm.UserVm; +import com.cloud.vm.snapshot.VMSnapshot; + +@APICommand(name = "revertToSnapshot",description = "Revert VM from a vmsnapshot.", responseObject = UserVmResponse.class) +public class RevertToSnapshotCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger + .getLogger(RevertToSnapshotCmd.class.getName()); + private static final String s_name = "reverttosnapshotresponse"; + + @Parameter(name = ApiConstants.VM_SNAPSHOT_ID, type = CommandType.UUID, required = true,entityType=VMSnapshotResponse.class,description = "The ID of the vm snapshot") + private Long vmSnapShotId; + + public Long getVmSnapShotId() { + return vmSnapShotId; + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + VMSnapshot vmSnapshot = _entityMgr.findById(VMSnapshot.class, getVmSnapShotId()); + if (vmSnapshot != null) { + return vmSnapshot.getAccountId(); + } + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException, ConcurrentOperationException { + UserContext.current().setEventDetails( + "vmsnapshot id: " + getVmSnapShotId()); + UserVm result = _vmSnapshotService.revertToSnapshot(getVmSnapShotId()); + if (result != null) { + UserVmResponse response = _responseGenerator.createUserVmResponse( + "virtualmachine", result).get(0); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,"Failed to revert VM snapshot"); + } + } + + @Override + public String getEventDescription() { + return "Revert from VM snapshot: " + getVmSnapShotId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VM_SNAPSHOT_REVERT; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/AttachVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/AttachVolumeCmd.java index 4d82534c2b2..e577e35795e 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/AttachVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/AttachVolumeCmd.java @@ -119,7 +119,7 @@ public class AttachVolumeCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("Volume Id: "+getId()+" VmId: "+getVirtualMachineId()); - Volume result = _userVmService.attachVolumeToVM(this); + Volume result = _volumeService.attachVolumeToVM(this); if (result != null) { VolumeResponse response = _responseGenerator.createVolumeResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java index 2f77862b3b9..5db06bcd47f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java @@ -153,7 +153,7 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ - Volume volume = _storageService.allocVolume(this); + Volume volume = this._volumeService.allocVolume(this); if (volume != null) { this.setEntityId(volume.getId()); this.setEntityUuid(volume.getUuid()); @@ -165,7 +165,7 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { @Override public void execute(){ UserContext.current().setEventDetails("Volume Id: "+getEntityId()+((getSnapshotId() == null) ? "" : " from snapshot: " + getSnapshotId())); - Volume volume = _storageService.createVolume(this); + Volume volume = _volumeService.createVolume(this); if (volume != null) { VolumeResponse response = _responseGenerator.createVolumeResponse(volume); //FIXME - have to be moved to ApiResponseHelper diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java index 39c3de3fac9..394b0092123 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java @@ -80,7 +80,7 @@ public class DeleteVolumeCmd extends BaseCmd { @Override public void execute() throws ConcurrentOperationException { UserContext.current().setEventDetails("Volume Id: "+getId()); - boolean result = _storageService.deleteVolume(id, UserContext.current().getCaller()); + boolean result = this._volumeService.deleteVolume(id, UserContext.current().getCaller()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/DetachVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/DetachVolumeCmd.java index 6153e17448b..9a5929eccca 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/DetachVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/DetachVolumeCmd.java @@ -130,7 +130,7 @@ public class DetachVolumeCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("Volume Id: "+getId()+" VmId: "+getVirtualMachineId()); - Volume result = _userVmService.detachVolumeFromVM(this); + Volume result = _volumeService.detachVolumeFromVM(this); if (result != null){ VolumeResponse response = _responseGenerator.createVolumeResponse(result); response.setResponseName("volume"); diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java index d43ad5500e1..287241a8d90 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java @@ -92,7 +92,7 @@ public class MigrateVolumeCmd extends BaseAsyncCmd { public void execute(){ Volume result; try { - result = _storageService.migrateVolume(getVolumeId(), getStoragePoolId()); + result = _volumeService.migrateVolume(this); if (result != null) { VolumeResponse response = _responseGenerator.createVolumeResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ResizeVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ResizeVolumeCmd.java index 52863444507..955727a7d82 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ResizeVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ResizeVolumeCmd.java @@ -133,7 +133,7 @@ public class ResizeVolumeCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("Volume Id: " + getEntityId() + " to size " + getSize() + "G"); - Volume volume = _storageService.resizeVolume(this); + Volume volume = _volumeService.resizeVolume(this); if (volume != null) { VolumeResponse response = _responseGenerator.createVolumeResponse(volume); //FIXME - have to be moved to ApiResponseHelper diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java index 107d938b106..3b00ba0d4bb 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java @@ -67,6 +67,10 @@ public class UploadVolumeCmd extends BaseAsyncCmd { @Parameter(name=ApiConstants.CHECKSUM, type=CommandType.STRING, description="the MD5 checksum value of this volume") private String checksum; + + @Parameter(name=ApiConstants.IMAGE_STORE_UUID, type=CommandType.STRING, + description="Image store uuid") + private String imageStoreUuid; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -99,6 +103,10 @@ public class UploadVolumeCmd extends BaseAsyncCmd { public String getChecksum() { return checksum; } + + public String getImageStoreUuid() { + return this.imageStoreUuid; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -110,7 +118,7 @@ public class UploadVolumeCmd extends BaseAsyncCmd { ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { - Volume volume = _storageService.uploadVolume(this); + Volume volume = _volumeService.uploadVolume(this); if (volume != null){ VolumeResponse response = _responseGenerator.createVolumeResponse(volume); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java index 71d134bb149..38b40b54c5f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java @@ -34,7 +34,7 @@ import com.cloud.user.UserContext; public class CreateVpnCustomerGatewayCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(CreateVpnCustomerGatewayCmd.class.getName()); - private static final String s_name = "createcustomergatewayresponse"; + private static final String s_name = "createvpncustomergatewayresponse"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// diff --git a/api/src/org/apache/cloudstack/api/response/AccountResponse.java b/api/src/org/apache/cloudstack/api/response/AccountResponse.java index 0277d5b6fe9..9a98a356492 100644 --- a/api/src/org/apache/cloudstack/api/response/AccountResponse.java +++ b/api/src/org/apache/cloudstack/api/response/AccountResponse.java @@ -132,6 +132,24 @@ public class AccountResponse extends BaseResponse { @SerializedName("vpcavailable") @Param(description="the total number of vpcs available to be created for this account", since="4.0.0") private String vpcAvailable; + @SerializedName("cpulimit") @Param(description="the total number of cpu cores the account can own", since="4.1.0") + private String cpuLimit; + + @SerializedName("cputotal") @Param(description="the total number of cpu cores owned by account", since="4.1.0") + private Long cpuTotal; + + @SerializedName("cpuavailable") @Param(description="the total number of cpu cores available to be created for this account", since="4.1.0") + private String cpuAvailable; + + @SerializedName("memorylimit") @Param(description="the total memory (in MB) the account can own", since="4.1.0") + private String memoryLimit; + + @SerializedName("memorytotal") @Param(description="the total memory (in MB) owned by account", since="4.1.0") + private Long memoryTotal; + + @SerializedName("memoryavailable") @Param(description="the total memory (in MB) available to be created for this account", since="4.1.0") + private String memoryAvailable; + @SerializedName(ApiConstants.STATE) @Param(description="the state of the account") private String state; @@ -294,6 +312,30 @@ public class AccountResponse extends BaseResponse { this.networkAvailable = networkAvailable; } + public void setCpuLimit(String cpuLimit) { + this.cpuLimit = cpuLimit; + } + + public void setCpuTotal(Long cpuTotal) { + this.cpuTotal = cpuTotal; + } + + public void setCpuAvailable(String cpuAvailable) { + this.cpuAvailable = cpuAvailable; + } + + public void setMemoryLimit(String memoryLimit) { + this.memoryLimit = memoryLimit; + } + + public void setMemoryTotal(Long memoryTotal) { + this.memoryTotal = memoryTotal; + } + + public void setMemoryAvailable(String memoryAvailable) { + this.memoryAvailable = memoryAvailable; + } + public void setDefaultZone(String defaultZoneId) { this.defaultZoneId = defaultZoneId; } diff --git a/api/src/org/apache/cloudstack/api/response/ClusterResponse.java b/api/src/org/apache/cloudstack/api/response/ClusterResponse.java index 551e530cc38..a90acde6145 100644 --- a/api/src/org/apache/cloudstack/api/response/ClusterResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ClusterResponse.java @@ -62,6 +62,12 @@ public class ClusterResponse extends BaseResponse { @SerializedName("capacity") @Param(description="the capacity of the Cluster", responseObject = CapacityResponse.class) private List capacitites; + @SerializedName("cpuovercommitratio") @Param(description = "The cpu overcommit ratio of the cluster") + private String cpuovercommitratio; + + @SerializedName("memoryovercommitratio") @Param (description = "The ram overcommit ratio of the cluster") + private String memoryovercommitratio; + public String getId() { return id; } @@ -149,4 +155,18 @@ public class ClusterResponse extends BaseResponse { public void setCapacitites(ArrayList arrayList) { this.capacitites = arrayList; } + public void setCpuovercommitratio(String cpuovercommitratio){ + this.cpuovercommitratio= cpuovercommitratio; + } + public void setRamovercommitratio (String memoryOvercommitRatio){ + this.memoryovercommitratio= memoryOvercommitRatio; + } + + public String getCpuovercommitratio (){ + return cpuovercommitratio; + } + + public String getRamovercommitratio (){ + return memoryovercommitratio; + } } diff --git a/api/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java b/api/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java index aa10229f2bd..bbeec630d81 100644 --- a/api/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java +++ b/api/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java @@ -30,7 +30,7 @@ public class LDAPConfigResponse extends BaseResponse { @SerializedName(ApiConstants.PORT) @Param(description="Specify the LDAP port if required, default is 389") private String port; - @SerializedName(ApiConstants.PORT) @Param(description="Check Use SSL if the external LDAP server is configured for LDAP over SSL") + @SerializedName(ApiConstants.USE_SSL) @Param(description="Check Use SSL if the external LDAP server is configured for LDAP over SSL") private String useSSL; @SerializedName(ApiConstants.SEARCH_BASE) @Param(description="The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com") diff --git a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java index 7b29efbf4d9..cd32dede3c8 100644 --- a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java @@ -52,9 +52,15 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes @SerializedName(ApiConstants.NETMASK) @Param(description="the network's netmask") private String netmask; - @SerializedName(ApiConstants.CIDR) @Param(description="the cidr the network") + @SerializedName(ApiConstants.CIDR) @Param(description="Cloudstack managed address space, all CloudStack managed VMs get IP address from CIDR") private String cidr; + @SerializedName(ApiConstants.NETWORK_CIDR) @Param(description="the network CIDR of the guest network configured with IP reservation. It is the summation of CIDR and RESERVED_IP_RANGE") + private String networkCidr; + + @SerializedName(ApiConstants.RESERVED_IP_RANGE) @Param(description="the network's IP range not to be used by CloudStack guest VMs and can be used for non CloudStack purposes") + private String reservedIpRange; + @SerializedName(ApiConstants.ZONE_ID) @Param(description="zone id of the network") private String zoneId; @@ -289,6 +295,14 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes this.cidr = cidr; } + public void setNetworkCidr(String networkCidr) { + this.networkCidr = networkCidr; + } + + public void setReservedIpRange(String reservedIpRange) { + this.reservedIpRange = reservedIpRange; + } + public void setRestartRequired(Boolean restartRequired) { this.restartRequired = restartRequired; } diff --git a/api/src/org/apache/cloudstack/api/response/ResourceCountResponse.java b/api/src/org/apache/cloudstack/api/response/ResourceCountResponse.java index 9d4f6c5aad2..a7fbbf2630b 100644 --- a/api/src/org/apache/cloudstack/api/response/ResourceCountResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ResourceCountResponse.java @@ -40,7 +40,7 @@ public class ResourceCountResponse extends BaseResponse implements ControlledEnt @SerializedName(ApiConstants.DOMAIN) @Param(description="the domain name for which resource count's are updated") private String domainName; - @SerializedName(ApiConstants.RESOURCE_TYPE) @Param(description="resource type. Values include 0, 1, 2, 3, 4. See the resourceType parameter for more information on these values.") + @SerializedName(ApiConstants.RESOURCE_TYPE) @Param(description="resource type. Values include 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. See the resourceType parameter for more information on these values.") private String resourceType; @SerializedName("resourcecount") @Param(description="resource count") diff --git a/api/src/org/apache/cloudstack/api/response/ResourceLimitResponse.java b/api/src/org/apache/cloudstack/api/response/ResourceLimitResponse.java index beead247b23..b444e7a68a7 100644 --- a/api/src/org/apache/cloudstack/api/response/ResourceLimitResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ResourceLimitResponse.java @@ -36,7 +36,7 @@ public class ResourceLimitResponse extends BaseResponse implements ControlledEnt @SerializedName(ApiConstants.DOMAIN) @Param(description="the domain name of the resource limit") private String domainName; - @SerializedName(ApiConstants.RESOURCE_TYPE) @Param(description="resource type. Values include 0, 1, 2, 3, 4. See the resourceType parameter for more information on these values.") + @SerializedName(ApiConstants.RESOURCE_TYPE) @Param(description="resource type. Values include 0, 1, 2, 3, 4, 6, 7, 8, 9. See the resourceType parameter for more information on these values.") private String resourceType; @SerializedName("max") @Param(description="the maximum number of the resource. A -1 means the resource currently has no limit.") diff --git a/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java b/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java new file mode 100644 index 00000000000..3b30ab61a8f --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java @@ -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; + + } +} diff --git a/api/src/org/apache/cloudstack/query/QueryService.java b/api/src/org/apache/cloudstack/query/QueryService.java index bfe7b855c81..c3f86aabb7f 100644 --- a/api/src/org/apache/cloudstack/query/QueryService.java +++ b/api/src/org/apache/cloudstack/query/QueryService.java @@ -58,7 +58,6 @@ import com.cloud.exception.PermissionDeniedException; /** * Service used for list api query. - * @author minc * */ public interface QueryService { diff --git a/api/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java b/api/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java index 7836b6d6e8e..71004977d89 100644 --- a/api/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java +++ b/api/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java @@ -133,15 +133,15 @@ public class BackupSnapshotCommandTest { } @Override - public String getStorageProvider() { + public Long getStorageProviderId() { // TODO Auto-generated method stub return null; } @Override - public String getStorageType() { + public boolean isInMaintenance() { // TODO Auto-generated method stub - return null; + return false; }; }; diff --git a/api/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java b/api/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java index 3545d0f1c29..767d7c37c5e 100644 --- a/api/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java +++ b/api/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java @@ -115,16 +115,16 @@ public class SnapshotCommandTest { } @Override - public String getStorageProvider() { + public Long getStorageProviderId() { // TODO Auto-generated method stub return null; } - @Override - public String getStorageType() { - // TODO Auto-generated method stub - return null; - }; + @Override + public boolean isInMaintenance() { + // TODO Auto-generated method stub + return false; + }; }; SnapshotCommand ssc = new SnapshotCommand(pool, diff --git a/api/test/org/apache/cloudstack/api/command/test/UsageCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/UsageCmdTest.java new file mode 100644 index 00000000000..1f218f47e2a --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/UsageCmdTest.java @@ -0,0 +1,69 @@ +// 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.test; + +import junit.framework.TestCase; +import org.apache.cloudstack.api.command.admin.usage.GetUsageRecordsCmd; +import org.apache.cloudstack.usage.Usage; +import org.apache.cloudstack.usage.UsageService; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; + +public class UsageCmdTest extends TestCase { + + private GetUsageRecordsCmd getUsageRecordsCmd; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setUp() { + + getUsageRecordsCmd = new GetUsageRecordsCmd() { + + }; + } + + @Test + public void testExecuteSuccess() { + UsageService usageService = Mockito.mock(UsageService.class); + getUsageRecordsCmd._usageService = usageService; + getUsageRecordsCmd.execute(); + } + + @Test + public void testExecuteEmptyResult() { + + UsageService usageService = Mockito.mock(UsageService.class); + + List usageRecords = new ArrayList(); + + Mockito.when(usageService.getUsageRecords(getUsageRecordsCmd)).thenReturn( + usageRecords); + + getUsageRecordsCmd._usageService = usageService; + getUsageRecordsCmd.execute(); + + } + +} diff --git a/api/test/src/com/cloud/agent/api/test/ResizeVolumeCommandTest.java b/api/test/src/com/cloud/agent/api/test/ResizeVolumeCommandTest.java index 7f5540fa4d3..852e52b1b86 100644 --- a/api/test/src/com/cloud/agent/api/test/ResizeVolumeCommandTest.java +++ b/api/test/src/com/cloud/agent/api/test/ResizeVolumeCommandTest.java @@ -134,15 +134,15 @@ public class ResizeVolumeCommandTest { } @Override - public String getStorageProvider() { + public Long getStorageProviderId() { // TODO Auto-generated method stub return null; } @Override - public String getStorageType() { + public boolean isInMaintenance() { // TODO Auto-generated method stub - return null; + return false; }; }; diff --git a/awsapi/pom.xml b/awsapi/pom.xml index 5a0ad7b0cb4..8e07f9e2124 100644 --- a/awsapi/pom.xml +++ b/awsapi/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java b/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java index 5d151bac7e4..29a002cebaf 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java +++ b/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java @@ -707,12 +707,20 @@ public class EC2RestServlet extends HttpServlet { else break; String[] fromPort = request.getParameterValues( "IpPermissions." + nCount + ".FromPort" ); - if ( null != fromPort && 0 < fromPort.length) - perm.setFromPort( Integer.parseInt( fromPort[0])); + if ( null != fromPort && 0 < fromPort.length ) { + if ( protocol[0].equalsIgnoreCase("icmp") ) + perm.setIcmpType( fromPort[0] ) ; + else + perm.setFromPort( Integer.parseInt( fromPort[0]) ); + } String[] toPort = request.getParameterValues( "IpPermissions." + nCount + ".ToPort" ); - if ( null != toPort && 0 < toPort.length) - perm.setToPort( Integer.parseInt( toPort[0])); + if ( null != toPort && 0 < toPort.length ) { + if ( protocol[0].equalsIgnoreCase("icmp") ) + perm.setIcmpCode( toPort[0] ); + else + perm.setToPort( Integer.parseInt( toPort[0]) ); + } // -> list: IpPermissions.n.IpRanges.m.CidrIp mCount = 1; @@ -780,12 +788,20 @@ public class EC2RestServlet extends HttpServlet { else break; String[] fromPort = request.getParameterValues( "IpPermissions." + nCount + ".FromPort" ); - if ( null != fromPort && 0 < fromPort.length) - perm.setFromPort( Integer.parseInt( fromPort[0])); + if ( null != fromPort && 0 < fromPort.length ) { + if ( protocol[0].equalsIgnoreCase("icmp") ) + perm.setIcmpType( fromPort[0] ) ; + else + perm.setFromPort( Integer.parseInt( fromPort[0]) ); + } String[] toPort = request.getParameterValues( "IpPermissions." + nCount + ".ToPort" ); - if ( null != toPort && 0 < toPort.length) - perm.setToPort( Integer.parseInt( toPort[0])); + if ( null != toPort && 0 < toPort.length ) { + if ( protocol[0].equalsIgnoreCase("icmp") ) + perm.setIcmpCode( toPort[0] ); + else + perm.setToPort( Integer.parseInt( toPort[0]) ); + } // -> list: IpPermissions.n.IpRanges.m.CidrIp int mCount = 1; @@ -1142,14 +1158,26 @@ public class EC2RestServlet extends HttpServlet { else { response.sendError(530, "Missing ImageId parameter" ); return; } String[] minCount = request.getParameterValues( "MinCount" ); - if ( null != minCount && 0 < minCount.length ) - EC2request.setMinCount( Integer.parseInt( minCount[0] )); - else { response.sendError(530, "Missing MinCount parameter" ); return; } + if ( minCount == null || minCount.length < 1) { + response.sendError(530, "Missing MinCount parameter" ); + return; + } else if ( Integer.parseInt(minCount[0]) < 1) { + throw new EC2ServiceException(ClientError.InvalidParameterValue, + "Value of parameter MinCount should be greater than 0"); + } else { + EC2request.setMinCount( Integer.parseInt( minCount[0]) ); + } String[] maxCount = request.getParameterValues( "MaxCount" ); - if ( null != maxCount && 0 < maxCount.length ) - EC2request.setMaxCount( Integer.parseInt( maxCount[0] )); - else { response.sendError(530, "Missing MaxCount parameter" ); return; } + if ( maxCount == null || maxCount.length < 1) { + response.sendError(530, "Missing MaxCount parameter" ); + return; + } else if ( Integer.parseInt(maxCount[0]) < 1) { + throw new EC2ServiceException(ClientError.InvalidParameterValue, + "Value of parameter MaxCount should be greater than 0"); + } else { + EC2request.setMaxCount( Integer.parseInt( maxCount[0]) ); + } String[] instanceType = request.getParameterValues( "InstanceType" ); if ( null != instanceType && 0 < instanceType.length ) @@ -1257,6 +1285,11 @@ public class EC2RestServlet extends HttpServlet { } if (0 == count) { response.sendError(530, "Missing InstanceId parameter" ); return; } + String[] force = request.getParameterValues("Force"); + if ( force != null) { + EC2request.setForce( Boolean.parseBoolean(force[0])); + } + // -> execute the request StopInstancesResponse EC2response = EC2SoapServiceImpl.toStopInstancesResponse( ServiceProvider.getInstance().getEC2Engine().stopInstances( EC2request )); serializeResponse(response, EC2response); @@ -1899,10 +1932,14 @@ public class EC2RestServlet extends HttpServlet { String paramName = (String) params.nextElement(); // exclude the signature string obviously. ;) if (paramName.equalsIgnoreCase("Signature")) continue; + // URLEncoder performs application/x-www-form-urlencoded-type encoding and not Percent encoding + // according to RFC 3986 as required by Amazon, we need to Percent-encode (URL Encode) + String encodedValue = URLEncoder.encode(request.getParameter(paramName), "UTF-8") + .replace("+", "%20").replace("*", "%2A"); if (queryString == null) - queryString = paramName + "=" + URLEncoder.encode(request.getParameter(paramName), "UTF-8"); + queryString = paramName + "=" + encodedValue; else - queryString = queryString + "&" + paramName + "=" + URLEncoder.encode(request.getParameter(paramName), "UTF-8"); + queryString = queryString + "&" + paramName + "=" + encodedValue; } } } diff --git a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java index bf3c13eda9c..cebac0b159e 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java +++ b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java @@ -41,6 +41,7 @@ import com.cloud.bridge.service.core.ec2.EC2DescribeAvailabilityZones; import com.cloud.bridge.service.core.ec2.EC2DescribeAvailabilityZonesResponse; import com.cloud.bridge.service.core.ec2.EC2DescribeImageAttribute; +import com.cloud.bridge.service.core.ec2.EC2AvailabilityZone; import com.cloud.bridge.service.core.ec2.EC2DescribeImages; import com.cloud.bridge.service.core.ec2.EC2DescribeImagesResponse; import com.cloud.bridge.service.core.ec2.EC2DescribeInstances; @@ -730,8 +731,17 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { EC2RunInstances request = new EC2RunInstances(); request.setTemplateId(rit.getImageId()); - request.setMinCount(rit.getMinCount()); - request.setMaxCount(rit.getMaxCount()); + + if (rit.getMinCount() < 1) { + throw new EC2ServiceException(ClientError.InvalidParameterValue, + "Value of parameter MinCount should be greater than 0"); + } else request.setMinCount( rit.getMinCount() ); + + if (rit.getMaxCount() < 1) { + throw new EC2ServiceException(ClientError.InvalidParameterValue, + "Value of parameter MaxCount should be greater than 0"); + } else request.setMaxCount(rit.getMaxCount()); + if (null != type) request.setInstanceType(type); if (null != prt) request.setZoneName(prt.getAvailabilityZone()); if (null != userData) request.setUserData(userData.getData()); @@ -763,6 +773,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { public StopInstancesResponse stopInstances(StopInstances stopInstances) { EC2StopInstances request = new EC2StopInstances(); StopInstancesType sit = stopInstances.getStopInstances(); + Boolean force = sit.getForce(); // -> toEC2StopInstances InstanceIdSetType iist = sit.getInstancesSet(); @@ -770,6 +781,8 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { if (null != items) { // -> should not be empty for( int i=0; i < items.length; i++ ) request.addInstanceId( items[i].getInstanceId()); } + + if (force) request.setForce(sit.getForce()); return toStopInstancesResponse( engine.stopInstances( request )); } @@ -1289,7 +1302,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { param5.setInstanceId(vol.getInstanceId().toString()); String devicePath = engine.cloudDeviceIdToDevicePath( vol.getHypervisor(), vol.getDeviceId()); param5.setDevice( devicePath ); - param5.setStatus( toVolumeAttachmentState( vol.getInstanceId(), vol.getVMState())); + param5.setStatus(vol.getAttachmentState()); if (vol.getAttached() == null) { param5.setAttachTime( cal ); } else { @@ -1545,25 +1558,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { else if (cloudState.equalsIgnoreCase( "Expunging" )) return new String( "terminated"); else return new String( "running" ); } - - /** - * We assume a state for the volume based on what its associated VM is doing. - * - * @param vmId - * @param vmState - * @return - */ - public static String toVolumeAttachmentState(String instanceId, String vmState ) { - if (null == instanceId || null == vmState) return "detached"; - - if (vmState.equalsIgnoreCase( "Destroyed" )) return "detached"; - else if (vmState.equalsIgnoreCase( "Stopped" )) return "attached"; - else if (vmState.equalsIgnoreCase( "Running" )) return "attached"; - else if (vmState.equalsIgnoreCase( "Starting" )) return "attaching"; - else if (vmState.equalsIgnoreCase( "Stopping" )) return "attached"; - else if (vmState.equalsIgnoreCase( "Error" )) return "detached"; - else return "detached"; - } + public static StopInstancesResponse toStopInstancesResponse(EC2StopInstancesResponse engineResponse) { StopInstancesResponse response = new StopInstancesResponse(); @@ -1775,14 +1770,18 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { DescribeAvailabilityZonesResponse response = new DescribeAvailabilityZonesResponse(); DescribeAvailabilityZonesResponseType param1 = new DescribeAvailabilityZonesResponseType(); AvailabilityZoneSetType param2 = new AvailabilityZoneSetType(); - - String[] zones = engineResponse.getZoneSet(); - for (String zone : zones) { + + EC2AvailabilityZone[] zones = engineResponse.getAvailabilityZoneSet(); + for (EC2AvailabilityZone zone : zones) { AvailabilityZoneItemType param3 = new AvailabilityZoneItemType(); - AvailabilityZoneMessageSetType param4 = new AvailabilityZoneMessageSetType(); - param3.setZoneName( zone ); + param3.setZoneName( zone.getName() ); param3.setZoneState( "available" ); param3.setRegionName( "" ); + + AvailabilityZoneMessageSetType param4 = new AvailabilityZoneMessageSetType(); + AvailabilityZoneMessageType param5 = new AvailabilityZoneMessageType(); + param5.setMessage(zone.getMessage()); + param4.addItem(param5); param3.setMessageSet( param4 ); param2.addItem( param3 ); } @@ -1803,10 +1802,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { param1.setVolumeId( engineResponse.getId().toString()); param1.setInstanceId( engineResponse.getInstanceId().toString()); param1.setDevice( engineResponse.getDevice()); - if ( null != engineResponse.getState()) - param1.setStatus( engineResponse.getState()); - else param1.setStatus( "" ); // ToDo - throw an Soap Fault - + param1.setStatus(engineResponse.getAttachmentState()); param1.setAttachTime( cal ); param1.setRequestId( UUID.randomUUID().toString()); @@ -1823,10 +1819,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { param1.setVolumeId( engineResponse.getId().toString()); param1.setInstanceId( (null == engineResponse.getInstanceId() ? "" : engineResponse.getInstanceId().toString())); param1.setDevice( (null == engineResponse.getDevice() ? "" : engineResponse.getDevice())); - if ( null != engineResponse.getState()) - param1.setStatus( engineResponse.getState()); - else param1.setStatus( "" ); // ToDo - throw an Soap Fault - + param1.setStatus(engineResponse.getAttachmentState()); param1.setAttachTime( cal ); param1.setRequestId( UUID.randomUUID().toString()); @@ -1912,7 +1905,10 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { param3.setStartTime( cal ); param3.setOwnerId(ownerId); - param3.setVolumeSize( snap.getVolumeSize().toString()); + if ( snap.getVolumeSize() == null ) + param3.setVolumeSize("0"); + else + param3.setVolumeSize( snap.getVolumeSize().toString() ); param3.setDescription( snap.getName()); param3.setOwnerAlias( snap.getAccountName() ); diff --git a/server/src/com/cloud/baremetal/PxeServerResponse.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AvailabilityZone.java similarity index 54% rename from server/src/com/cloud/baremetal/PxeServerResponse.java rename to awsapi/src/com/cloud/bridge/service/core/ec2/EC2AvailabilityZone.java index 32fcc7fb5b9..457c6efd069 100644 --- a/server/src/com/cloud/baremetal/PxeServerResponse.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AvailabilityZone.java @@ -14,22 +14,42 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.baremetal; +package com.cloud.bridge.service.core.ec2; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; -import com.cloud.serializer.Param; -import com.google.gson.annotations.SerializedName; +public class EC2AvailabilityZone { -public class PxeServerResponse extends BaseResponse { - @SerializedName(ApiConstants.ID) @Param(description="the ID of the PXE server") - private String id; + private String id; + private String name; + private String message; - public String getId() { - return id; + public EC2AvailabilityZone() { + id = null; + name = null; + message = null; + } + + public void setId( String id ) { + this.id = id; } - public void setId(String id) { - this.id = id; + public String getId() { + return this.id; } + + public void setName( String name ) { + this.name = name; + } + + public String getName() { + return this.name; + } + + public void setMessage( String message ) { + this.message = message; + } + + public String getMessage() { + return this.message; + } + } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AvailabilityZonesFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AvailabilityZonesFilterSet.java index 994b721203a..aa3897a4bf6 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AvailabilityZonesFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AvailabilityZonesFilterSet.java @@ -36,6 +36,7 @@ public class EC2AvailabilityZonesFilterSet { public EC2AvailabilityZonesFilterSet() { // -> use these values to check that the proper filter is passed to this type of filter set filterTypes.put( "zone-name", "String" ); + filterTypes.put( "message", "String"); } public void addFilter( EC2Filter param ) { @@ -55,13 +56,14 @@ public class EC2AvailabilityZonesFilterSet { return filterSet.toArray(new EC2Filter[0]); } - public List evaluate( EC2DescribeAvailabilityZonesResponse availabilityZones) throws ParseException { - List resultList = new ArrayList(); + public EC2DescribeAvailabilityZonesResponse evaluate( EC2DescribeAvailabilityZonesResponse availabilityZones) + throws ParseException { + EC2DescribeAvailabilityZonesResponse resultList = new EC2DescribeAvailabilityZonesResponse(); boolean matched; EC2Filter[] filterSet = getFilterSet(); - for ( String availableZone : availabilityZones.getZoneSet() ) { + for ( EC2AvailabilityZone availableZone : availabilityZones.getAvailabilityZoneSet() ) { matched = true; if (filterSet != null) { for (EC2Filter filter : filterSet) { @@ -71,19 +73,22 @@ public class EC2AvailabilityZonesFilterSet { } } } - if (matched == true) - resultList.add(availableZone); + if (matched) + resultList.addAvailabilityZone(availableZone); } return resultList; } - private boolean filterMatched( String availableZone, EC2Filter filter ) throws ParseException { + private boolean filterMatched( EC2AvailabilityZone availableZone, EC2Filter filter ) throws ParseException { String filterName = filter.getName(); String[] valueSet = filter.getValueSet(); if ( filterName.equalsIgnoreCase("zone-name")) { - return containsString(availableZone, valueSet); - } + return containsString(availableZone.getName(), valueSet); + } + else if (filterName.equalsIgnoreCase("message")) { + return containsString(availableZone.getMessage(), valueSet); + } return false; } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeAvailabilityZonesResponse.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeAvailabilityZonesResponse.java index ae0c233f83f..f9bc6b66d83 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeAvailabilityZonesResponse.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeAvailabilityZonesResponse.java @@ -20,31 +20,17 @@ import java.util.ArrayList; import java.util.List; public class EC2DescribeAvailabilityZonesResponse { + private List availabilityZoneSet = new ArrayList(); - private List zoneIds = new ArrayList(); - private List zoneNames = new ArrayList(); + public EC2DescribeAvailabilityZonesResponse() { + } + + public void addAvailabilityZone( EC2AvailabilityZone param ) { + availabilityZoneSet.add( param ); + } + + public EC2AvailabilityZone[] getAvailabilityZoneSet() { + return availabilityZoneSet.toArray(new EC2AvailabilityZone[0]); + } - public EC2DescribeAvailabilityZonesResponse() { - } - - public void addZone(String id, String name) { - zoneIds.add(id); - zoneNames.add(name); - } - - /** - * The Amazon API only cares about the names of zones not their ID value. - * - * @return an array containing a set of zone names - */ - public String[] getZoneSet() { - return zoneNames.toArray(new String[0]); - } - - public String getZoneIdAt(int index) { - if (zoneIds.isEmpty() || index >= zoneIds.size()) { - return null; - } - return zoneIds.get(index); - } } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java index b729f778ed3..e92f845f2b1 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java @@ -25,9 +25,12 @@ import java.security.SignatureException; import java.sql.SQLException; import java.text.ParseException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.UUID; import javax.inject.Inject; @@ -443,25 +446,35 @@ public class EC2Engine extends ManagerBase { */ public EC2DescribeSnapshotsResponse handleRequest( EC2DescribeSnapshots request ) { - EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse(); EC2SnapshotFilterSet sfs = request.getFilterSet(); EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet(); try { - // -> query to get the volume size for each snapshot EC2DescribeSnapshotsResponse response = listSnapshots( request.getSnapshotSet(), getResourceTags(tagKeyValueSet)); if (response == null) { return new EC2DescribeSnapshotsResponse(); } EC2Snapshot[] snapshots = response.getSnapshotSet(); - for (EC2Snapshot snap : snapshots) { - volumes = listVolumes(snap.getVolumeId(), null, volumes, null); - EC2Volume[] volSet = volumes.getVolumeSet(); - if (0 < volSet.length) snap.setVolumeSize(volSet[0].getSize()); - volumes.reset(); + // -> query to get the volume size for each snapshot + HashMap volumeIdSize = new HashMap(); + for( EC2Snapshot snap : snapshots ) { + Boolean duplicateVolume = false; + Long size = null; + if ( volumeIdSize.containsKey(snap.getVolumeId()) ) { + size = volumeIdSize.get(snap.getVolumeId()); + duplicateVolume = true; + break; + } + if ( !duplicateVolume ) { + EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse(); + volumes = listVolumes(snap.getVolumeId(), null, volumes, null); + EC2Volume[] volumeSet = volumes.getVolumeSet(); + if (volumeSet.length > 0) size = volumeSet[0].getSize(); + volumeIdSize.put(snap.getVolumeId(), size); + } + snap.setVolumeSize(size); } - if ( null == sfs ) return response; else return sfs.evaluate( response ); @@ -1060,12 +1073,8 @@ public class EC2Engine extends ManagerBase { EC2AvailabilityZonesFilterSet azfs = request.getFilterSet(); if ( null == azfs ) return availableZones; - else { - List matchedAvailableZones = azfs.evaluate(availableZones); - if (matchedAvailableZones.isEmpty()) - return new EC2DescribeAvailabilityZonesResponse(); - return listZones(matchedAvailableZones.toArray(new String[0]), null); - } + else + return azfs.evaluate(availableZones); } catch( EC2ServiceException error ) { logger.error( "EC2 DescribeAvailabilityZones - ", error); throw error; @@ -1129,6 +1138,7 @@ public class EC2Engine extends ManagerBase { resp.setState(vol.getState()); resp.setType(vol.getVolumeType()); resp.setVMState(vol.getVirtualMachineState()); + resp.setAttachmentState(mapToAmazonVolumeAttachmentState(vol.getVirtualMachineState())); resp.setZoneName(vol.getZoneName()); return resp; } @@ -1215,6 +1225,7 @@ public class EC2Engine extends ManagerBase { resp.setState(vol.getState()); resp.setType(vol.getVolumeType()); resp.setVMState(vol.getVirtualMachineState()); + resp.setAttachmentState("detached"); resp.setZoneName(vol.getZoneName()); return resp; } @@ -1412,47 +1423,53 @@ public class EC2Engine extends ManagerBase { // now actually deploy the vms for( int i=0; i < createInstances; i++ ) { - CloudStackUserVm resp = getApi().deployVirtualMachine(svcOffering.getId(), - request.getTemplateId(), zoneId, null, null, null, null, - null, null, null, request.getKeyName(), null, (network != null ? network.getId() : null), - null, constructList(request.getGroupSet()), request.getSize().longValue(), request.getUserData()); - EC2Instance vm = new EC2Instance(); - vm.setId(resp.getId().toString()); - vm.setName(resp.getName()); - vm.setZoneName(resp.getZoneName()); - vm.setTemplateId(resp.getTemplateId().toString()); - if (resp.getSecurityGroupList() != null && resp.getSecurityGroupList().size() > 0) { - List securityGroupList = resp.getSecurityGroupList(); - for (CloudStackSecurityGroup securityGroup : securityGroupList) { - EC2SecurityGroup param = new EC2SecurityGroup(); - param.setId(securityGroup.getId()); - param.setName(securityGroup.getName()); - vm.addGroupName(param); + try{ + CloudStackUserVm resp = getApi().deployVirtualMachine(svcOffering.getId(), + request.getTemplateId(), zoneId, null, null, null, null, + null, null, null, request.getKeyName(), null, (network != null ? network.getId() : null), + null, constructList(request.getGroupSet()), request.getSize().longValue(), request.getUserData()); + EC2Instance vm = new EC2Instance(); + vm.setId(resp.getId().toString()); + vm.setName(resp.getName()); + vm.setZoneName(resp.getZoneName()); + vm.setTemplateId(resp.getTemplateId().toString()); + if (resp.getSecurityGroupList() != null && resp.getSecurityGroupList().size() > 0) { + List securityGroupList = resp.getSecurityGroupList(); + for (CloudStackSecurityGroup securityGroup : securityGroupList) { + EC2SecurityGroup param = new EC2SecurityGroup(); + param.setId(securityGroup.getId()); + param.setName(securityGroup.getName()); + vm.addGroupName(param); + } } - } - vm.setState(resp.getState()); - vm.setCreated(resp.getCreated()); - List nicList = resp.getNics(); - for (CloudStackNic nic : nicList) { - if (nic.getIsDefault()) { - vm.setPrivateIpAddress(nic.getIpaddress()); - break; + vm.setState(resp.getState()); + vm.setCreated(resp.getCreated()); + List nicList = resp.getNics(); + for (CloudStackNic nic : nicList) { + if (nic.getIsDefault()) { + vm.setPrivateIpAddress(nic.getIpaddress()); + break; + } } + vm.setIpAddress(resp.getIpAddress()); + vm.setAccountName(resp.getAccountName()); + vm.setDomainId(resp.getDomainId()); + vm.setHypervisor(resp.getHypervisor()); + vm.setServiceOffering( svcOffering.getName()); + vm.setKeyPairName(resp.getKeyPairName()); + instances.addInstance(vm); + countCreated++; + }catch(Exception e){ + logger.error("Failed to deploy VM number: "+ (i+1) +" due to error: "+e.getMessage()); + break; } - vm.setIpAddress(resp.getIpAddress()); - vm.setAccountName(resp.getAccountName()); - vm.setDomainId(resp.getDomainId()); - vm.setHypervisor(resp.getHypervisor()); - vm.setServiceOffering( svcOffering.getName()); - vm.setKeyPairName(resp.getKeyPairName()); - instances.addInstance(vm); - countCreated++; } if (0 == countCreated) { // TODO, we actually need to destroy left-over VMs when the exception is thrown - throw new EC2ServiceException(ServerError.InsufficientInstanceCapacity, "Insufficient Instance Capacity" ); + throw new EC2ServiceException(ServerError.InternalError, "Failed to deploy instances" ); } + logger.debug("Could deploy "+ countCreated + " VM's successfully"); return instances; } catch( Exception e ) { @@ -1514,6 +1531,7 @@ public class EC2Engine extends ManagerBase { // -> first determine the current state of each VM (becomes it previous state) try { String[] instanceSet = request.getInstancesSet(); + Boolean forced = request.getForce(); EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null, null ); virtualMachines = previousState.getInstanceSet(); @@ -1535,7 +1553,7 @@ public class EC2Engine extends ManagerBase { instances.addInstance(vm); continue; } - resp = getApi().stopVirtualMachine(vm.getId(), false); + resp = getApi().stopVirtualMachine(vm.getId(), forced); if(logger.isDebugEnabled()) logger.debug("Stopping VM " + vm.getId() + " job " + resp.getJobId()); } @@ -1643,11 +1661,16 @@ public class EC2Engine extends ManagerBase { ec2Vol.setSize(vol.getSize()); ec2Vol.setType(vol.getVolumeType()); - if(vol.getVirtualMachineId() != null) + if(vol.getVirtualMachineId() != null) { ec2Vol.setInstanceId(vol.getVirtualMachineId()); + if (vol.getVirtualMachineState() != null) { + ec2Vol.setVMState(vol.getVirtualMachineState()); + ec2Vol.setAttachmentState(mapToAmazonVolumeAttachmentState(vol.getVirtualMachineState())); + } + } else { + ec2Vol.setAttachmentState("detached"); + } - if(vol.getVirtualMachineState() != null) - ec2Vol.setVMState(vol.getVirtualMachineState()); ec2Vol.setZoneName(vol.getZoneName()); List resourceTags = vol.getTags(); @@ -1691,9 +1714,11 @@ public class EC2Engine extends ManagerBase { zones = listZones(interestedZones, domainId); - if (zones == null || zones.getZoneIdAt( 0 ) == null) + if (zones == null || zones.getAvailabilityZoneSet().length == 0) throw new EC2ServiceException(ClientError.InvalidParameterValue, "Unknown zoneName value - " + zoneName); - return zones.getZoneIdAt(0); + + EC2AvailabilityZone[] zoneSet = zones.getAvailabilityZoneSet(); + return zoneSet[0].getId(); } @@ -1768,24 +1793,31 @@ public class EC2Engine extends ManagerBase { * * @return EC2DescribeAvailabilityZonesResponse */ - private EC2DescribeAvailabilityZonesResponse listZones(String[] interestedZones, String domainId) throws Exception - { + private EC2DescribeAvailabilityZonesResponse listZones(String[] interestedZones, String domainId) + throws Exception { EC2DescribeAvailabilityZonesResponse zones = new EC2DescribeAvailabilityZonesResponse(); List cloudZones = getApi().listZones(true, domainId, null, null); - - if(cloudZones != null) { + if(cloudZones != null && cloudZones.size() > 0) { for(CloudStackZone cloudZone : cloudZones) { - if ( null != interestedZones && 0 < interestedZones.length ) { - for( int j=0; j < interestedZones.length; j++ ) { - if (interestedZones[j].equalsIgnoreCase( cloudZone.getName())) { - zones.addZone(cloudZone.getId().toString(), cloudZone.getName()); + boolean matched = false; + if (interestedZones.length > 0) { + for (String zoneName : interestedZones){ + if (zoneName.equalsIgnoreCase( cloudZone.getName())) { + matched = true; break; } } - } else { - zones.addZone(cloudZone.getId().toString(), cloudZone.getName()); + } else { + matched = true; } + if (!matched) continue; + EC2AvailabilityZone ec2Zone = new EC2AvailabilityZone(); + ec2Zone.setId(cloudZone.getId().toString()); + ec2Zone.setMessage(cloudZone.getAllocationState()); + ec2Zone.setName(cloudZone.getName()); + + zones.addAvailabilityZone(ec2Zone); } } return zones; @@ -1952,7 +1984,7 @@ public class EC2Engine extends ManagerBase { * @throws ParserConfigurationException * @throws ParseException */ - public EC2DescribeSecurityGroupsResponse listSecurityGroups( String[] interestedGroups ) throws Exception { + private EC2DescribeSecurityGroupsResponse listSecurityGroups( String[] interestedGroups ) throws Exception { try { EC2DescribeSecurityGroupsResponse groupSet = new EC2DescribeSecurityGroupsResponse(); @@ -2399,6 +2431,25 @@ public class EC2Engine extends ManagerBase { return "error"; } + /** + * Map CloudStack VM state to Amazon volume attachment state + * + * @param CloudStack VM state + * @return Amazon Volume attachment state + */ + private String mapToAmazonVolumeAttachmentState (String vmState) { + if ( vmState.equalsIgnoreCase("Running") || vmState.equalsIgnoreCase("Stopping") || + vmState.equalsIgnoreCase("Stopped") ) { + return "attached"; + } + else if (vmState.equalsIgnoreCase("Starting")) { + return "attaching"; + } + else { // VM state is 'destroyed' or 'error' or other + return "detached"; + } + } + /** * Map Amazon resourceType to CloudStack resourceType * diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java index e0aae7364d9..b5b7c7840df 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java @@ -50,6 +50,7 @@ public class EC2InstanceFilterSet { filterTypes.put( "group-id", "string" ); filterTypes.put( "tag-key", "string" ); filterTypes.put( "tag-value", "string" ); + filterTypes.put( "dns-name", "string" ); } @@ -184,6 +185,8 @@ public class EC2InstanceFilterSet { } } return false; + }else if (filterName.equalsIgnoreCase( "dns-name" )){ + return containsString( vm.getName(), valueSet ); } else return false; } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2StopInstances.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2StopInstances.java index 13e23d1a51f..be140008019 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2StopInstances.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2StopInstances.java @@ -23,6 +23,7 @@ public class EC2StopInstances { private List instancesSet = new ArrayList(); // a list of strings identifying instances private boolean destroyInstances; // we are destroying the instances rather than stopping them + private Boolean force = false; public EC2StopInstances() { destroyInstances = false; @@ -43,5 +44,13 @@ public class EC2StopInstances { public boolean getDestroyInstances() { return this.destroyInstances; } + + public void setForce( Boolean force ) { + this.force = force; + } + + public Boolean getForce() { + return this.force; + } } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Volume.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Volume.java index 23d6d701646..79bc6e88911 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Volume.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Volume.java @@ -35,6 +35,7 @@ public class EC2Volume { private String hypervisor; private String created; private String attached; + private String attachmentState; private List tagsSet; public EC2Volume() { @@ -50,6 +51,7 @@ public class EC2Volume { hypervisor = null; created = null; attached = null; + attachmentState = null; tagsSet = new ArrayList(); } @@ -236,6 +238,20 @@ public class EC2Volume { this.attached = attached; } + /** + * @param state of the attached VM to set + */ + public void setAttachmentState(String attachedState) { + this.attachmentState = attachedState; + } + + /** + * @return state of the vm + */ + public String getAttachmentState() { + return attachmentState; + } + public void addResourceTag( EC2TagKeyValue param ) { tagsSet.add( param ); } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java index 0594231413e..b8021f3d4ba 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java @@ -43,7 +43,7 @@ public class EC2VolumeFilterSet { filterTypes.put( "attachment.delete-on-termination", "null" ); filterTypes.put( "attachment.device", "string" ); filterTypes.put( "attachment.instance-id", "string" ); - filterTypes.put( "attachment.status", "null" ); + filterTypes.put( "attachment.status", "set:attached|attaching|detached|detaching" ); filterTypes.put( "availability-zone", "string" ); filterTypes.put( "create-time", "xsd:dateTime" ); filterTypes.put( "size", "integer" ); @@ -136,6 +136,9 @@ public class EC2VolumeFilterSet { return containsDevice(vol.getDeviceId(), valueSet ); else if (filterName.equalsIgnoreCase( "attachment.instance-id" )) return containsString(String.valueOf(vol.getInstanceId()), valueSet ); + else if ( filterName.equalsIgnoreCase( "attachment.status" ) ) { + return containsString(vol.getAttachmentState(), valueSet ); + } else if (filterName.equalsIgnoreCase("tag-key")) { EC2TagKeyValue[] tagSet = vol.getResourceTags(); diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 9c4fcb35554..a0ed7c9a277 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -17,6 +17,11 @@ #new labels (begin) ********************************************************************************************** +label.plugins=Plugins +label.plugin.details=Plugin details +label.author.name=Author name +label.author.email=Author e-mail +label.external.link=External link label.egress.rules=Egress rules message.acquire.new.ip.vpc=Please confirm that you would like to acquire a new IP for this VPC. label.zoneWizard.trafficType.management=Management: Traffic between CloudStack\'s internal resources, including any components that communicate with the Management Server, such as hosts and CloudStack system VMs @@ -1410,6 +1415,20 @@ label.zone.step.4.title=Step 4: Add an IP range 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. diff --git a/client/WEB-INF/web.xml b/client/WEB-INF/web.xml index 0d75165659e..626305b82fa 100644 --- a/client/WEB-INF/web.xml +++ b/client/WEB-INF/web.xml @@ -19,6 +19,14 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> + + + log4jConfigLocation + /WEB-INF/classes/log4j-cloud.xml + + + org.springframework.web.util.Log4jConfigListener + org.springframework.web.context.ContextLoaderListener diff --git a/client/pom.xml b/client/pom.xml index 3651b79bbb3..d532a4248b1 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT @@ -90,6 +90,16 @@ cloud-plugin-hypervisor-ovm ${project.version} + + org.apache.cloudstack + cloud-plugin-hypervisor-baremetal + ${project.version} + + + org.apache.cloudstack + cloud-plugin-hypervisor-ucs + ${project.version} + org.apache.cloudstack cloud-plugin-hypervisor-kvm @@ -229,9 +239,12 @@ -XX:MaxPermSize=512m -Xmx2g - /client ${project.build.directory}/${project.build.finalName}/WEB-INF/web.xml ${project.build.directory}/${project.build.finalName} + + /client + ${project.build.directory}/utilities/scripts/db/;${project.build.directory}/utilities/scripts/db/db/ + @@ -255,6 +268,12 @@ + + + + + + @@ -267,13 +286,8 @@ - - - - - + + @@ -368,8 +382,8 @@ test + match="classpath:componentContext.xml" + replace="classpath:nonossComponentContext.xml" byline="true" /> @@ -392,14 +406,14 @@ org.jasypt jasypt - 1.9.0` + 1.9.0 false ${project.build.directory}/pythonlibs org.jasypt jasypt - 1.8` + 1.8 false ${project.build.directory}/pythonlibs diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index d70649bf318..f03e8d50adb 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -537,3 +537,12 @@ addRegion=1 updateRegion=1 removeRegion=1 listRegions=15 + +### VM Snapshot commands +listVMSnapshot=15 +createVMSnapshot=15 +deleteVMSnapshot=15 +revertToSnapshot=15 + +#### Baremetal commands +addBaremetalHost=1 diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index fc6c3e346c0..5f77cdab25c 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -44,7 +44,6 @@ - @@ -53,6 +52,11 @@ + + + + + @@ -186,7 +197,14 @@ - + + + + @@ -210,10 +228,18 @@ - + + + + + + + + + + + + + + diff --git a/client/tomcatconf/log4j-cloud.xml.in b/client/tomcatconf/log4j-cloud.xml.in index 02f70998d53..086669376aa 100755 --- a/client/tomcatconf/log4j-cloud.xml.in +++ b/client/tomcatconf/log4j-cloud.xml.in @@ -105,7 +105,7 @@ under the License. - + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 57f7ad5516f..d862d4eab0b 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -58,18 +58,25 @@ - + + + + + - - + + - - + + + + + @@ -136,6 +143,10 @@ + + + + @@ -201,10 +212,14 @@ - + + + + + @@ -232,11 +247,10 @@ - + - @@ -282,14 +296,6 @@ - - - - - - - - @@ -298,6 +304,10 @@ + + + + diff --git a/client/tomcatconf/tomcat6-nonssl.conf.in b/client/tomcatconf/tomcat6-nonssl.conf.in index d69d6ed94c0..4a9a70f619e 100644 --- a/client/tomcatconf/tomcat6-nonssl.conf.in +++ b/client/tomcatconf/tomcat6-nonssl.conf.in @@ -41,7 +41,7 @@ CATALINA_TMPDIR="@MSENVIRON@/temp" # Use JAVA_OPTS to set java.library.path for libtcnative.so #JAVA_OPTS="-Djava.library.path=/usr/lib64" -JAVA_OPTS="-Djava.awt.headless=true -Dcom.sun.management.jmxremote.port=45219 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=@MSLOGDIR@ -XX:PermSize=256M" +JAVA_OPTS="-Djava.awt.headless=true -Dcom.sun.management.jmxremote.port=45219 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=@MSLOGDIR@ -XX:PermSize=512M -XX:MaxPermSize=800m" # What user should run tomcat TOMCAT_USER="@MSUSER@" diff --git a/client/tomcatconf/tomcat6-ssl.conf.in b/client/tomcatconf/tomcat6-ssl.conf.in index ecb93b23abc..84b6d6275bb 100644 --- a/client/tomcatconf/tomcat6-ssl.conf.in +++ b/client/tomcatconf/tomcat6-ssl.conf.in @@ -40,7 +40,7 @@ CATALINA_TMPDIR="@MSENVIRON@/temp" # Use JAVA_OPTS to set java.library.path for libtcnative.so #JAVA_OPTS="-Djava.library.path=/usr/lib64" -JAVA_OPTS="-Djava.awt.headless=true -Djavax.net.ssl.trustStore=/etc/cloud/management/cloudmanagementserver.keystore -Djavax.net.ssl.trustStorePassword=vmops.com -Dcom.sun.management.jmxremote.port=45219 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=@MSLOGDIR@ -XX:PermSize=256M" +JAVA_OPTS="-Djava.awt.headless=true -Djavax.net.ssl.trustStore=/etc/cloud/management/cloudmanagementserver.keystore -Djavax.net.ssl.trustStorePassword=vmops.com -Dcom.sun.management.jmxremote.port=45219 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=@MSLOGDIR@ -XX:MaxPermSize=800m -XX:PermSize=512M" # What user should run tomcat TOMCAT_USER="@MSUSER@" diff --git a/core/pom.xml b/core/pom.xml index 3d6356e561e..0da69529400 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT @@ -31,7 +31,11 @@ cloud-api ${project.version} - + + org.apache.cloudstack + cloud-engine-api + ${project.version} + commons-httpclient commons-httpclient diff --git a/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java b/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java index 56e8e0a734d..b525a2d05d5 100644 --- a/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java +++ b/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java @@ -59,6 +59,9 @@ public class HypervisorCapabilitiesVO implements HypervisorCapabilities { @Column(name="max_data_volumes_limit") private Integer maxDataVolumesLimit; + @Column(name="max_hosts_per_cluster") + private Integer maxHostsPerCluster; + protected HypervisorCapabilitiesVO() { this.uuid = UUID.randomUUID().toString(); } @@ -157,6 +160,15 @@ public class HypervisorCapabilitiesVO implements HypervisorCapabilities { this.maxDataVolumesLimit = maxDataVolumesLimit; } + @Override + public Integer getMaxHostsPerCluster() { + return maxHostsPerCluster; + } + + public void setMaxHostsPerCluster(Integer maxHostsPerCluster) { + this.maxHostsPerCluster = maxHostsPerCluster; + } + @Override public boolean equals(Object obj) { if (obj instanceof HypervisorCapabilitiesVO) { diff --git a/core/src/com/cloud/resource/storage/PrimaryStorageHeadResource.java b/core/src/com/cloud/resource/storage/PrimaryStorageHeadResource.java deleted file mode 100644 index 65297a39b96..00000000000 --- a/core/src/com/cloud/resource/storage/PrimaryStorageHeadResource.java +++ /dev/null @@ -1,52 +0,0 @@ -// 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.resource.storage; - -import com.cloud.agent.api.storage.CreateAnswer; -import com.cloud.agent.api.storage.CreateCommand; -import com.cloud.agent.api.storage.DestroyAnswer; -import com.cloud.agent.api.storage.DestroyCommand; -import com.cloud.agent.api.storage.DownloadAnswer; -import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; -import com.cloud.resource.ServerResource; - -/** - * a primary storage. - * - */ -public interface PrimaryStorageHeadResource extends ServerResource { - /** - * Downloads the template to the primary storage. - * @param cmd - * @return - */ - DownloadAnswer execute(PrimaryStorageDownloadCommand cmd); - - /** - * Creates volumes for the VM. - * @param cmd - * @return - */ - CreateAnswer execute(CreateCommand cmd); - - /** - * Destroys volumes for the VM. - * @param cmd - * @return - */ - DestroyAnswer execute(DestroyCommand cmd); -} diff --git a/core/src/com/cloud/storage/SnapshotVO.java b/core/src/com/cloud/storage/SnapshotVO.java index 68336cb97ec..78b96ec9779 100644 --- a/core/src/com/cloud/storage/SnapshotVO.java +++ b/core/src/com/cloud/storage/SnapshotVO.java @@ -117,7 +117,7 @@ public class SnapshotVO implements Snapshot { this.snapshotType = snapshotType; this.typeDescription = typeDescription; this.size = size; - this.state = State.Creating; + this.state = State.Allocated; this.prevSnapshotId = 0; this.hypervisorType = hypervisorType; this.version = "2.2"; @@ -175,7 +175,7 @@ public class SnapshotVO implements Snapshot { } @Override - public Type getType() { + public Type getRecurringType() { if (snapshotType < 0 || snapshotType >= Type.values().length) { return null; } @@ -248,6 +248,7 @@ public class SnapshotVO implements Snapshot { return state; } + public void setState(State state) { this.state = state; } diff --git a/core/src/com/cloud/storage/StoragePoolDiscoverer.java b/core/src/com/cloud/storage/StoragePoolDiscoverer.java index 816e899f941..c7dd362a5c3 100644 --- a/core/src/com/cloud/storage/StoragePoolDiscoverer.java +++ b/core/src/com/cloud/storage/StoragePoolDiscoverer.java @@ -19,6 +19,8 @@ package com.cloud.storage; import java.net.URI; import java.util.Map; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.exception.DiscoveryException; import com.cloud.utils.component.Adapter; diff --git a/core/src/com/cloud/storage/StoragePoolVO.java b/core/src/com/cloud/storage/StoragePoolVO.java deleted file mode 100644 index af6e4e2905c..00000000000 --- a/core/src/com/cloud/storage/StoragePoolVO.java +++ /dev/null @@ -1,346 +0,0 @@ -// 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.storage; - -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.Id; -import javax.persistence.Table; -import javax.persistence.TableGenerator; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; - -import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.utils.db.GenericDao; - -@Entity -@Table(name="storage_pool") -public class StoragePoolVO implements StoragePool { - @Id - @TableGenerator(name="storage_pool_sq", table="sequence", pkColumnName="name", valueColumnName="value", pkColumnValue="storage_pool_seq", allocationSize=1) - @Column(name="id", updatable=false, nullable = false) - private long id; - - @Column(name="name", updatable=false, nullable=false, length=255) - private String name = null; - - @Column(name="uuid", length=255) - private String uuid = null; - - @Column(name="pool_type", updatable=false, nullable=false, length=32) - @Enumerated(value=EnumType.STRING) - private StoragePoolType poolType; - - @Column(name=GenericDao.CREATED_COLUMN) - Date created; - - @Column(name=GenericDao.REMOVED_COLUMN) - private Date removed; - - @Column(name="update_time", updatable=true) - @Temporal(value=TemporalType.TIMESTAMP) - private Date updateTime; - - @Column(name="data_center_id", updatable=true, nullable=false) - private long dataCenterId; - - @Column(name="pod_id", updatable=true) - private Long podId; - - @Column(name="available_bytes", updatable=true, nullable=true) - private long availableBytes; - - @Column(name="capacity_bytes", updatable=true, nullable=true) - private long capacityBytes; - - @Column(name="status", updatable=true, nullable=false) - @Enumerated(value=EnumType.STRING) - private StoragePoolStatus status; - - // TODO, disable persisency of storageProvider and storageType, javelin new code not - // sync with the schema! - - // @Column(name="storage_provider", updatable=true, nullable=false) - @Transient private String storageProvider; - - // Column(name="storage_type", nullable=false) - @Transient private String storageType; - - @Override - public long getId() { - return id; - } - - @Override - public StoragePoolStatus getStatus() { - return status; - } - - public StoragePoolVO() { - // TODO Auto-generated constructor stub - } - - @Override - public String getName() { - return name; - } - - @Override - public String getUuid() { - return uuid; - } - - @Override - public StoragePoolType getPoolType() { - return poolType; - } - - @Override - public Date getCreated() { - return created; - } - - public Date getRemoved() { - return removed; - } - - @Override - public Date getUpdateTime() { - return updateTime; - } - - @Override - public long getDataCenterId() { - return dataCenterId; - } - - @Override - public long getAvailableBytes() { - return availableBytes; - } - - @Override - public String getStorageProvider() { - return storageProvider; - } - - public void setStorageProvider(String provider) { - storageProvider = provider; - } - - @Override - public String getStorageType() { - return storageType; - } - - public void setStorageType(String type) { - storageType = type; - } - - @Override - public long getCapacityBytes() { - return capacityBytes; - } - - public void setAvailableBytes(long available) { - availableBytes = available; - } - - public void setCapacityBytes(long capacity) { - capacityBytes = capacity; - } - - @Column(name="host_address") - private String hostAddress; - - @Column(name="path") - private String path; - - @Column(name="port") - private int port; - - @Column(name="user_info") - private String userInfo; - - @Column(name="cluster_id") - private Long clusterId; - - - @Override - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - @Override - public String getHostAddress() { - return hostAddress; - } - - @Override - public String getPath() { - return path; - } - - @Override - public String getUserInfo() { - return userInfo; - } - - public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type, - long dataCenterId, Long podId, long availableBytes, long capacityBytes, String hostAddress, int port, String hostPath) { - this.name = name; - this.id = poolId; - this.uuid = uuid; - this.poolType = type; - this.dataCenterId = dataCenterId; - this.availableBytes = availableBytes; - this.capacityBytes = capacityBytes; - this.hostAddress = hostAddress; - this.path = hostPath; - this.port = port; - this.podId = podId; - this.setStatus(StoragePoolStatus.Creating); - } - - public StoragePoolVO(StoragePoolVO that) { - this(that.id, that.name, that.uuid, that.poolType, that.dataCenterId, that.podId, that.availableBytes, that.capacityBytes, that.hostAddress, that.port, that.path); - } - - public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path) { - this.poolType = type; - this.hostAddress = hostAddress; - this.port = port; - this.path = path; - this.setStatus(StoragePoolStatus.Creating); - this.uuid = UUID.randomUUID().toString(); - } - - public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path, String userInfo) { - this.poolType = type; - this.hostAddress = hostAddress; - this.port = port; - this.path = path; - this.userInfo = userInfo; - this.setStatus(StoragePoolStatus.Creating); - this.uuid = UUID.randomUUID().toString(); - } - - public void setStatus(StoragePoolStatus status) - { - this.status = status; - } - - public void setId(long id) { - this.id = id; - } - - public void setDataCenterId(long dcId) { - this.dataCenterId = dcId; - } - - public void setPodId(Long podId) { - this.podId = podId; - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public void setPath(String path) { - this.path = path; - } - - public void setUserInfo(String userInfo) { - this.userInfo = userInfo; - } - - @Override - public int getPort() { - return port; - } - - @Override - public boolean isShared() { - return poolType.isShared(); - } - - @Override - public boolean isLocal() { - return !poolType.isShared(); - } - - @Transient - public String toUri() { - /* - URI uri = new URI(); - try { - if (type == StoragePoolType.Filesystem) { - uri.setScheme("file"); - } else if (type == StoragePoolType.NetworkFilesystem) { - uri.setScheme("nfs"); - } else if (type == StoragePoolType.IscsiLUN) { - } - } catch (MalformedURIException e) { - throw new VmopsRuntimeException("Unable to form the uri " + id); - } - return uri.toString(); - */ - return null; - } - - @Override - public Long getPodId() { - return podId; - } - - public void setName(String name) { - this.name = name; - } - - public boolean isInMaintenance() { - return status == StoragePoolStatus.PrepareForMaintenance || status == StoragePoolStatus.Maintenance || status == StoragePoolStatus.ErrorInMaintenance || removed != null; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof StoragePoolVO) || obj == null) { - return false; - } - StoragePoolVO that = (StoragePoolVO)obj; - return this.id == that.id; - } - - @Override - public int hashCode() { - return new Long(id).hashCode(); - } - - @Override - public String toString() { - return new StringBuilder("Pool[").append(id).append("|").append(poolType).append("]").toString(); - } -} diff --git a/core/src/com/cloud/storage/VMTemplateHostVO.java b/core/src/com/cloud/storage/VMTemplateHostVO.java index 9eae1a00303..b8dfc41d51b 100755 --- a/core/src/com/cloud/storage/VMTemplateHostVO.java +++ b/core/src/com/cloud/storage/VMTemplateHostVO.java @@ -29,8 +29,10 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.utils.db.GenericDaoBase; -import org.apache.cloudstack.api.InternalIdentity; /** * Join table for storage hosts and templates @@ -38,7 +40,7 @@ import org.apache.cloudstack.api.InternalIdentity; */ @Entity @Table(name="template_host_ref") -public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc { +public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc, DataObjectInStore { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) Long id; @@ -90,6 +92,18 @@ public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc { @Column(name="destroyed") boolean destroyed = false; + @Column(name="update_count", updatable = true, nullable=false) + protected long updatedCount; + + @Column(name = "updated") + @Temporal(value = TemporalType.TIMESTAMP) + Date updated; + + @Column(name = "state") + @Enumerated(EnumType.STRING) + ObjectInDataStoreStateMachine.State state; + + @Override public String getInstallPath() { return installPath; @@ -162,6 +176,7 @@ public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc { super(); this.hostId = hostId; this.templateId = templateId; + this.state = ObjectInDataStoreStateMachine.State.Allocated; } public VMTemplateHostVO(long hostId, long templateId, Date lastUpdated, @@ -282,4 +297,26 @@ public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc { return new StringBuilder("TmplHost[").append(id).append("-").append(templateId).append("-").append(hostId).append(installPath).append("]").toString(); } + @Override + public ObjectInDataStoreStateMachine.State getState() { + // TODO Auto-generated method stub + return this.state; + } + + public long getUpdatedCount() { + return this.updatedCount; + } + + public void incrUpdatedCount() { + this.updatedCount++; + } + + public void decrUpdatedCount() { + this.updatedCount--; + } + + public Date getUpdated() { + return updated; + } + } diff --git a/core/src/com/cloud/storage/VMTemplateStoragePoolVO.java b/core/src/com/cloud/storage/VMTemplateStoragePoolVO.java index 32c9dd2ece5..9b761764359 100644 --- a/core/src/com/cloud/storage/VMTemplateStoragePoolVO.java +++ b/core/src/com/cloud/storage/VMTemplateStoragePoolVO.java @@ -29,8 +29,11 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; + import com.cloud.utils.db.GenericDaoBase; -import org.apache.cloudstack.api.InternalIdentity; /** * Join table for storage pools and templates @@ -38,7 +41,7 @@ import org.apache.cloudstack.api.InternalIdentity; */ @Entity @Table(name="template_spool_ref") -public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc { +public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc, DataObjectInStore { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) long id; @@ -69,7 +72,18 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc { @Column (name="template_size") long templateSize; @Column (name="marked_for_gc") boolean markedForGC; - + + @Column(name="update_count", updatable = true, nullable=false) + protected long updatedCount; + + @Column(name = "updated") + @Temporal(value = TemporalType.TIMESTAMP) + Date updated; + + @Column(name = "state") + @Enumerated(EnumType.STRING) + ObjectInDataStoreStateMachine.State state; + @Override public String getInstallPath() { return installPath; @@ -148,6 +162,7 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc { this.poolId = poolId; this.templateId = templateId; this.downloadState = Status.NOT_DOWNLOADED; + this.state = ObjectInDataStoreStateMachine.State.Allocated; this.markedForGC = false; } @@ -235,4 +250,26 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc { return new StringBuilder("TmplPool[").append(id).append("-").append(templateId).append("-").append("poolId").append("-").append(installPath).append("]").toString(); } + @Override + public State getState() { + return this.state; + } + + public long getUpdatedCount() { + return this.updatedCount; + } + + public void incrUpdatedCount() { + this.updatedCount++; + } + + public void decrUpdatedCount() { + this.updatedCount--; + } + + public Date getUpdated() { + return updated; + } + + } diff --git a/core/src/com/cloud/storage/VMTemplateVO.java b/core/src/com/cloud/storage/VMTemplateVO.java index fcfdd0067e1..e643d75bf1e 100755 --- a/core/src/com/cloud/storage/VMTemplateVO.java +++ b/core/src/com/cloud/storage/VMTemplateVO.java @@ -31,17 +31,18 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; -import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; + import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.template.VirtualMachineTemplate; import com.cloud.utils.db.GenericDao; -import org.apache.cloudstack.api.InternalIdentity; +import com.cloud.utils.fsm.StateObject; @Entity @Table(name="vm_template") -public class VMTemplateVO implements VirtualMachineTemplate { +public class VMTemplateVO implements VirtualMachineTemplate, StateObject { @Id @TableGenerator(name="vm_template_sq", table="sequence", pkColumnName="name", valueColumnName="value", pkColumnValue="vm_template_seq", allocationSize=1) @Column(name="id", nullable = false) @@ -127,6 +128,22 @@ public class VMTemplateVO implements VirtualMachineTemplate { @Column(name="enable_sshkey") private boolean enableSshKey; + + @Column(name = "image_data_store_id") + private long imageDataStoreId; + + @Column(name = "size") + private Long size; + + @Column(name = "state") + private TemplateState state; + + @Column(name="update_count", updatable = true) + protected long updatedCount; + + @Column(name = "updated") + @Temporal(value = TemporalType.TIMESTAMP) + Date updated; @Transient Map details; @@ -140,8 +157,9 @@ public class VMTemplateVO implements VirtualMachineTemplate { this.uniqueName = uniqueName; } - protected VMTemplateVO() { + public VMTemplateVO() { this.uuid = UUID.randomUUID().toString(); + this.state = TemplateState.Allocated; } /** @@ -150,12 +168,14 @@ public class VMTemplateVO implements VirtualMachineTemplate { public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType, Map details) { this(id, generateUniqueName(id, accountId, name), name, format, isPublic, featured, isExtractable, type, url, null, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType, details); this.uuid = UUID.randomUUID().toString(); + this.state = TemplateState.Allocated; } public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType, String templateTag, Map details, boolean sshKeyEnabled) { this(id, name, format, isPublic, featured, isExtractable, type, url, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType, details); this.templateTag = templateTag; this.uuid = UUID.randomUUID().toString(); + this.state = TemplateState.Allocated; this.enableSshKey = sshKeyEnabled; } @@ -179,6 +199,7 @@ public class VMTemplateVO implements VirtualMachineTemplate { this.bootable = bootable; this.hypervisorType = hyperType; this.uuid = UUID.randomUUID().toString(); + this.state = TemplateState.Allocated; } // Has an extra attribute - isExtractable @@ -468,5 +489,46 @@ public class VMTemplateVO implements VirtualMachineTemplate { public void setEnableSshKey(boolean enable) { enableSshKey = enable; } + + public Long getImageDataStoreId() { + return this.imageDataStoreId; + } + + public void setImageDataStoreId(long dataStoreId) { + this.imageDataStoreId = dataStoreId; + } + + public void setSize(Long size) { + this.size = size; + } + + public Long getSize() { + return this.size; + } + + public TemplateState getState() { + return this.state; + } + + public long getUpdatedCount() { + return this.updatedCount; + } + + public void incrUpdatedCount() { + this.updatedCount++; + } + + public void decrUpdatedCount() { + this.updatedCount--; + } + + public Date getUpdated() { + return updated; + } + + public void setUpdated(Date updated) { + this.updated = updated; + } + } diff --git a/core/src/com/cloud/storage/VolumeHostVO.java b/core/src/com/cloud/storage/VolumeHostVO.java index f4fc7abc4ee..40bae499122 100755 --- a/core/src/com/cloud/storage/VolumeHostVO.java +++ b/core/src/com/cloud/storage/VolumeHostVO.java @@ -29,11 +29,13 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; -//import com.cloud.storage.VMVolumeStorageResourceAssoc.Status; +import org.apache.cloudstack.api.InternalIdentity; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.utils.db.GenericDaoBase; -import org.apache.cloudstack.api.InternalIdentity; /** * Join table for storage hosts and volumes @@ -41,7 +43,7 @@ import org.apache.cloudstack.api.InternalIdentity; */ @Entity @Table(name="volume_host_ref") -public class VolumeHostVO implements InternalIdentity { +public class VolumeHostVO implements InternalIdentity, DataObjectInStore { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) Long id; @@ -99,6 +101,16 @@ public class VolumeHostVO implements InternalIdentity { @Column(name="destroyed") boolean destroyed = false; + @Column(name="update_count", updatable = true, nullable=false) + protected long updatedCount; + + @Column(name = "updated") + @Temporal(value = TemporalType.TIMESTAMP) + Date updated; + + @Column(name = "state") + @Enumerated(EnumType.STRING) + ObjectInDataStoreStateMachine.State state; public String getInstallPath() { return installPath; @@ -187,6 +199,7 @@ public class VolumeHostVO implements InternalIdentity { super(); this.hostId = hostId; this.volumeId = volumeId; + this.state = ObjectInDataStoreStateMachine.State.Allocated; } public VolumeHostVO(long hostId, long volumeId, long zoneId, Date lastUpdated, @@ -308,5 +321,27 @@ public class VolumeHostVO implements InternalIdentity { public String toString() { return new StringBuilder("VolumeHost[").append(id).append("-").append(volumeId).append("-").append(hostId).append(installPath).append("]").toString(); } + + public long getUpdatedCount() { + return this.updatedCount; + } + + public void incrUpdatedCount() { + this.updatedCount++; + } + + public void decrUpdatedCount() { + this.updatedCount--; + } + + public Date getUpdated() { + return updated; + } + + @Override + public ObjectInDataStoreStateMachine.State getState() { + // TODO Auto-generated method stub + return this.state; + } } diff --git a/core/src/com/cloud/storage/VolumeVO.java b/core/src/com/cloud/storage/VolumeVO.java index defc841e1e3..a287c26348b 100755 --- a/core/src/com/cloud/storage/VolumeVO.java +++ b/core/src/com/cloud/storage/VolumeVO.java @@ -32,11 +32,9 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; -import org.apache.cloudstack.api.Identity; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.GenericDao; -import org.apache.cloudstack.api.InternalIdentity; @Entity @Table(name = "volumes") @@ -69,7 +67,7 @@ public class VolumeVO implements Volume { Long deviceId = null; @Column(name = "size") - long size; + Long size; @Column(name = "folder") String folder; @@ -257,11 +255,11 @@ public class VolumeVO implements Volume { } @Override - public long getSize() { + public Long getSize() { return size; } - public void setSize(long size) { + public void setSize(Long size) { this.size = size; } diff --git a/core/src/com/cloud/vm/VirtualNetwork.java b/core/src/com/cloud/vm/VirtualNetwork.java deleted file mode 100644 index ace3b80769f..00000000000 --- a/core/src/com/cloud/vm/VirtualNetwork.java +++ /dev/null @@ -1,72 +0,0 @@ -// 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; - -import com.cloud.network.Networks.IsolationType; -import com.cloud.network.Networks.Mode; - -/** - * VirtualNetwork describes from a management level the - * machine. - */ -public class VirtualNetwork { - /** - * The gateway for this network. - */ - public String gateway; - - /** - * Netmask - */ - public String netmask; - - /** - * ip address. null if mode is DHCP. - */ - public String ip; - - /** - * Mac Address. - */ - public String mac; - - /** - * rate limit on this network. -1 if no limit. - */ - public long rate; - - /** - * tag for virtualization. - */ - public String tag; - - /** - * mode to acquire ip address. - */ - public Mode mode; - - /** - * Isolation method for networking. - */ - public IsolationType method; - - public boolean firewalled; - - public int[] openPorts; - - public int[] closedPorts; -} diff --git a/core/src/com/cloud/vm/snapshot/VMSnapshotVO.java b/core/src/com/cloud/vm/snapshot/VMSnapshotVO.java new file mode 100644 index 00000000000..03d4945fda0 --- /dev/null +++ b/core/src/com/cloud/vm/snapshot/VMSnapshotVO.java @@ -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; + } +} diff --git a/debian/control b/debian/control index 380b2e4a78d..e9697ea5e26 100644 --- a/debian/control +++ b/debian/control @@ -48,7 +48,7 @@ Description: CloudStack server library Package: cloud-scripts Replaces: cloud-agent-scripts Architecture: any -Depends: openjdk-6-jre, python, bash, bzip2, gzip, unzip, nfs-common, openssh-client +Depends: openjdk-6-jre, python, bash, bzip2, gzip, unzip, nfs-common, openssh-client, lsb-release Description: CloudStack scripts This package contains a number of scripts needed for the CloudStack Agent and Management Server. Both the CloudStack Agent and Management server depend on this package diff --git a/debian/rules b/debian/rules index 36b611ddc04..69fba7a07ba 100755 --- a/debian/rules +++ b/debian/rules @@ -60,7 +60,7 @@ install: mkdir -p debian/tmp/usr/share/cloud/management/webapps/client cp -r client/target/utilities/scripts/db/* debian/tmp/usr/share/cloud/setup/ - cp -r client/target/cloud-client-ui-4.1.0-SNAPSHOT/* debian/tmp/usr/share/cloud/management/webapps/client/ + cp -r client/target/cloud-client-ui-*-SNAPSHOT/* debian/tmp/usr/share/cloud/management/webapps/client/ dh_installdirs -s dh_install -s diff --git a/deps/XenServerJava/pom.xml b/deps/XenServerJava/pom.xml index 18ba54f56a3..0f2cdf427c8 100644 --- a/deps/XenServerJava/pom.xml +++ b/deps/XenServerJava/pom.xml @@ -21,7 +21,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml xapi diff --git a/developer/developer-prefill.sql b/developer/developer-prefill.sql index 8713d731645..6300d35df64 100644 --- a/developer/developer-prefill.sql +++ b/developer/developer-prefill.sql @@ -18,25 +18,25 @@ -- Add a default ROOT domain use cloud; -INSERT INTO `cloud`.`domain` (id, uuid, name, parent, path, owner, region_id) VALUES - (1, UUID(), 'ROOT', NULL, '/', 2, 1); +INSERT INTO `cloud`.`domain` (id, uuid, name, parent, path, owner) VALUES + (1, UUID(), 'ROOT', NULL, '/', 2); -- Add system and admin accounts -INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, state, region_id) VALUES - (1, UUID(), 'system', 1, 1, 'enabled', 1); +INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, state) VALUES + (1, UUID(), 'system', 1, 1, 'enabled'); -INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, state, region_id) VALUES - (2, UUID(), 'admin', 1, 1, 'enabled', 1); +INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, state) VALUES + (2, UUID(), 'admin', 1, 1, 'enabled'); -- Add system user INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, - lastname, email, state, created, region_id) VALUES (1, UUID(), 'system', RAND(), - '1', 'system', 'cloud', NULL, 'enabled', NOW(), 1); + lastname, email, state, created) VALUES (1, UUID(), 'system', RAND(), + '1', 'system', 'cloud', NULL, 'enabled', NOW()); -- Add system user with encrypted password=password INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, - lastname, email, state, created, region_id) VALUES (2, UUID(), 'admin', '5f4dcc3b5aa765d61d8327deb882cf99', - '2', 'Admin', 'User', 'admin@mailprovider.com', 'enabled', NOW(), 1); + lastname, email, state, created) VALUES (2, UUID(), 'admin', '5f4dcc3b5aa765d61d8327deb882cf99', + '2', 'Admin', 'User', 'admin@mailprovider.com', 'enabled', NOW()); -- Add configurations INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) diff --git a/developer/pom.xml b/developer/pom.xml index dba7b383d69..ff47b143093 100644 --- a/developer/pom.xml +++ b/developer/pom.xml @@ -18,7 +18,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT @@ -27,7 +27,12 @@ 5.1.21 runtime - + + org.apache.cloudstack + cloud-plugin-hypervisor-simulator + ${project.version} + compile + install @@ -130,7 +135,7 @@ - process-test-resources + process-resources create-schema java @@ -152,10 +157,6 @@ ${basedir}/target/db/create-schema.sql ${basedir}/target/db/create-schema-premium.sql - - ${basedir}/target/db/create-schema-view.sql - - ${basedir}/target/db/4.1-new-db-schema.sql ${basedir}/target/db/templates.sql @@ -182,115 +183,9 @@ catalina.home ${project.parent.basedir}/utils - - - - - - - - - - simulator - - - deploydb-simulator - - - - - - org.codehaus.mojo - properties-maven-plugin - 1.0-alpha-2 - - - initialize - - read-project-properties - - - - ${project.parent.basedir}/utils/conf/db.properties - ${project.parent.basedir}/utils/conf/db.properties.override - - true - - - - - - - org.codehaus.mojo - exec-maven-plugin - 1.2.1 - - - - mysql - mysql-connector-java - ${cs.mysql.version} - - - commons-dbcp - commons-dbcp - ${cs.dbcp.version} - - - commons-pool - commons-pool - ${cs.pool.version} - - - org.jasypt - jasypt - ${cs.jasypt.version} - - - org.apache.cloudstack - cloud-utils - ${project.version} - - - org.apache.cloudstack - cloud-server - ${project.version} - - - - - process-test-resources - create-schema - - java - - - - - false - true - - org.apache.cloudstack - cloud-server - - com.cloud.upgrade.DatabaseCreator - - - ${project.parent.basedir}/utils/conf/db.properties - ${project.parent.basedir}/utils/conf/db.properties.override - - ${basedir}/target/db/create-schema-simulator.sql - ${basedir}/target/db/templates.simulator.sql - - com.cloud.upgrade.DatabaseUpgradeChecker - --database=simulator - --rootpassword=${db.root.password} - - - - catalina.home - ${project.parent.basedir}/utils + paths.script + ${basedir}/target/db diff --git a/docs/en-US/added-API-commands-4-1.xml b/docs/en-US/added-API-commands-4-1.xml new file mode 100644 index 00000000000..f635e9dfdd8 --- /dev/null +++ b/docs/en-US/added-API-commands-4-1.xml @@ -0,0 +1,41 @@ + + +%BOOK_ENTITIES; +]> + +
+ Added API Commands in 4.1-incubating + + + createEgressFirewallRules (creates an egress firewall rule on the guest network.) + + + deleteEgressFirewallRules (deletes a egress firewall rule on the guest network.) + + + listEgressFirewallRules (lists the egress firewall rules configured for a guest + network.) + + + resetSSHKeyForVirtualMachine (Resets the SSHkey for virtual machine.) + + + addBaremetalHost (Adds a new host.) + + +
diff --git a/docs/en-US/changed-apicommands-4.1.xml b/docs/en-US/changed-apicommands-4.1.xml new file mode 100644 index 00000000000..42bd088afb3 --- /dev/null +++ b/docs/en-US/changed-apicommands-4.1.xml @@ -0,0 +1,106 @@ + + +%BOOK_ENTITIES; +]> + +
+ Changed API Commands in 4.1-incubating + + + + + + + API Commands + Description + + + + + + createNetworkOffering + listNetworkOfferings + listNetworks + + + The following request parameters is added: isPersistent. + This parameter determines if the network or network offering created or listed by + using this offering are persistent or not. + + + + + addF5LoadBalancer + configureNetscalerLoadBalancer + addNetscalerLoadBalancer + listF5LoadBalancers + configureF5LoadBalancer + listNetscalerLoadBalancers + + + The following response parameter is removed: inline. + + + + listFirewallRules + createFirewallRule + + The following request parameter is added: traffictype (optional). + + + + listUsageRecords + The following response parameter is added: virtualsize. + + + + + deleteIso + + + The following request parameter is added: forced (optional). + + + + + createStoragePool + + + The following request parameters are made mandatory: + + + podid + + + clusterid + + + + + + + listZones + + + The following request parameters is added: securitygroupenabled + + + + + +
diff --git a/docs/en-US/console-proxy.xml b/docs/en-US/console-proxy.xml index 3dd7b9fd692..697ee2e2146 100644 --- a/docs/en-US/console-proxy.xml +++ b/docs/en-US/console-proxy.xml @@ -24,11 +24,11 @@ console view via the web UI. It connects the user’s browser to the VNC port made available via the hypervisor for the console of the guest. Both the administrator and end user web UIs offer a console connection. - Clicking on a console icon brings up a new window. The AJAX code downloaded into that window + Clicking a console icon brings up a new window. The AJAX code downloaded into that window refers to the public IP address of a console proxy VM. There is exactly one public IP address allocated per console proxy VM. The AJAX application connects to this IP. The console proxy then - proxies the connection to the VNC port for the requested VM on the Host hosting the guest. - . + proxies the connection to the VNC port for the requested VM on the Host hosting the + guest. The hypervisors will have many ports assigned to VNC usage so that multiple VNC sessions can occur simultaneously. diff --git a/docs/en-US/creating-network-offerings.xml b/docs/en-US/creating-network-offerings.xml index 0269ce024cb..1f79fb166ce 100644 --- a/docs/en-US/creating-network-offerings.xml +++ b/docs/en-US/creating-network-offerings.xml @@ -22,146 +22,208 @@ under the License. -->
- Creating a New Network Offering - To create a network offering: - - Log in with admin privileges to the &PRODUCT; UI. - In the left navigation bar, click Service Offerings. - In Select Offering, choose Network Offering. - Click Add Network Offering. - In the dialog, make the following choices: - - Name. Any desired name for the network offering - Description. A short description of the offering that can be - displayed to users - Network Rate. Allowed data transfer rate in MB per - second - Guest Type. Choose whether the guest network is isolated or - shared. For a description of these terms, see - - Specify VLAN. (Isolated guest networks only) Indicate whether - a VLAN should be specified when this offering is used - Supported Services. Select one or more of the possible - network services. For some services, you must also choose the service - provider; for example, if you select Load Balancer, you can choose the - &PRODUCT; virtual router or any other load balancers that have been - configured in the cloud. Depending on which services you choose, additional - fields may appear in the rest of the dialog box.Based on the guest network type selected, you can see the following supported services: - - - - Supported Services - Description - Isolated - Shared - - - - - DHCP - For more information, see . - Supported - Supported - - - DNS - For more information, see . - Supported - Supported - - - Load Balancer - If you select Load Balancer, you can choose the &PRODUCT; virtual router or any other load - balancers that have been configured in the cloud. - Supported - Supported - - - Source NAT - If you select Source NAT, you can choose the &PRODUCT; virtual router or any other Source - NAT providers that have been configured in the - cloud. - Supported - Supported - - - Static NAT - If you select Static NAT, you can choose the &PRODUCT; virtual router or any other Static - NAT providers that have been configured in the - cloud. - Supported - Supported - - - Port Forwarding - If you select Port Forwarding, you can choose the &PRODUCT; virtual router or any other - Port Forwarding providers that have been configured in - the cloud. - Supported - Not Supported - - - VPN - For more information, see . - Supported - Not Supported - - - User Data - For more information, see . - Not Supported - Supported - - - Network ACL - For more information, see . - Supported - Not Supported - - - Security Groups - For more information, see . - Not Supported - Supported - - - - - - System Offering. If the service provider for any of the - services selected in Supported Services is a virtual router, the System - Offering field appears. Choose the system service offering that you want - virtual routers to use in this network. For example, if you selected Load - Balancer in Supported Services and selected a virtual router to provide load - balancing, the System Offering field appears so you can choose between the - &PRODUCT; default system service offering and any custom system service - offerings that have been defined by the &PRODUCT; root administrator. - For more information, see System Service Offerings. - Redundant router capability. Available - only when Virtual Router is selected as the Source NAT provider. Select this - option if you want to use two virtual routers in the network for - uninterrupted connection: one operating as the master virtual router and the - other as the backup. The master virtual router receives requests from and - sends responses to the user’s VM. The backup virtual router is activated - only when the master is down. After the failover, the backup becomes the - master virtual router. &PRODUCT; deploys the routers on different hosts - to ensure reliability if one host is down. - Conserve mode. Indicate whether to use conserve mode. In this - mode, network resources are allocated only when the first virtual machine - starts in the network. When the conservative mode is off, the public IP can - only be used for a single service. For example, a public IP used for a port - forwarding rule cannot be used for defining other services, such as SaticNAT - or load balancing. When the conserve mode is on, you can define more than - one service on the same public IP. - If StaticNAT is enabled, irrespective of the status of the conserve mode, no port forwarding - or load balancing rule can be created for the IP. However, you can add - the firewall rules by using the createFirewallRule command. - Tags. Network tag to specify which physical network to - use. - - Click Add. - - - + Creating a New Network Offering + To create a network offering: + + + Log in with admin privileges to the &PRODUCT; UI. + + + In the left navigation bar, click Service Offerings. + + + In Select Offering, choose Network Offering. + + + Click Add Network Offering. + + + In the dialog, make the following choices: + + + Name. Any desired name for the network + offering. + + + Description. A short description of the offering + that can be displayed to users. + + + Network Rate. Allowed data transfer rate in MB per + second. + + + Guest Type. Choose whether the guest network is + isolated or shared. + For a description of this term, see . + For a description of this term, see the Administration Guide. + + + + Persistent. Indicate whether the guest network is + persistent or not. The network that you can provision without having to deploy a VM on + it is termed persistent network. For more information, see . + + + Specify VLAN. (Isolated guest networks only) + Indicate whether a VLAN should be specified when this offering is used. + + + VPC. This option indicate whether the guest network + is Virtual Private Cloud-enabled. A Virtual Private Cloud (VPC) is a private, isolated + part of &PRODUCT;. A VPC can have its own virtual network topology that resembles a + traditional physical network. For more information on VPCs, see . + + + Supported Services. Select one or more of the + possible network services. For some services, you must also choose the service provider; + for example, if you select Load Balancer, you can choose the &PRODUCT; virtual router or + any other load balancers that have been configured in the cloud. Depending on which + services you choose, additional fields may appear in the rest of the dialog box. + Based on the guest network type selected, you can see the following supported + services: + + + + + Supported Services + Description + Isolated + Shared + + + + + DHCP + For more information, see . + Supported + Supported + + + DNS + For more information, see . + Supported + Supported + + + Load Balancer + If you select Load Balancer, you can choose the &PRODUCT; virtual + router or any other load balancers that have been configured in the + cloud. + Supported + Supported + + + Firewall + For more information, see . + For more information, see the Administration + Guide. + Supported + Supported + + + Source NAT + If you select Source NAT, you can choose the &PRODUCT; virtual router + or any other Source NAT providers that have been configured in the + cloud. + Supported + Supported + + + Static NAT + If you select Static NAT, you can choose the &PRODUCT; virtual router + or any other Static NAT providers that have been configured in the + cloud. + Supported + Supported + + + Port Forwarding + If you select Port Forwarding, you can choose the &PRODUCT; virtual + router or any other Port Forwarding providers that have been configured in the + cloud. + Supported + Not Supported + + + VPN + For more information, see . + Supported + Not Supported + + + User Data + For more information, see . + For more information, see the Administration + Guide. + Not Supported + Supported + + + Network ACL + For more information, see . + Supported + Not Supported + + + Security Groups + For more information, see . + Not Supported + Supported + + + + + + + System Offering. If the service provider for any of + the services selected in Supported Services is a virtual router, the System Offering + field appears. Choose the system service offering that you want virtual routers to use + in this network. For example, if you selected Load Balancer in Supported Services and + selected a virtual router to provide load balancing, the System Offering field appears + so you can choose between the &PRODUCT; default system service offering and any custom + system service offerings that have been defined by the &PRODUCT; root + administrator. + For more information, see . + For more information, see the Administration Guide. + + + Redundant router capability. Available only when + Virtual Router is selected as the Source NAT provider. Select this option if you want to + use two virtual routers in the network for uninterrupted connection: one operating as + the master virtual router and the other as the backup. The master virtual router + receives requests from and sends responses to the user’s VM. The backup virtual router + is activated only when the master is down. After the failover, the backup becomes the + master virtual router. &PRODUCT; deploys the routers on different hosts to ensure + reliability if one host is down. + + + Conserve mode. Indicate whether to use conserve + mode. In this mode, network resources are allocated only when the first virtual machine + starts in the network. When conservative mode is off, the public IP can only be used for + a single service. For example, a public IP used for a port forwarding rule cannot be + used for defining other services, such as SaticNAT or load balancing. When the conserve + mode is on, you can define more than one service on the same public IP. + + If StaticNAT is enabled, irrespective of the status of the conserve mode, no port + forwarding or load balancing rule can be created for the IP. However, you can add the + firewall rules by using the createFirewallRule command. + + + + Tags. Network tag to specify which physical network + to use. + + + + + Click Add. + +
diff --git a/docs/en-US/egress-firewall-rule.xml b/docs/en-US/egress-firewall-rule.xml new file mode 100644 index 00000000000..ef0e25efd03 --- /dev/null +++ b/docs/en-US/egress-firewall-rule.xml @@ -0,0 +1,98 @@ + + +%BOOK_ENTITIES; +]> + +
+ Creating Egress Firewall Rules in an Advanced Zone + + The egress firewall rules are supported only on virtual routers. + + + The egress traffic originates from a private network to a public network, such as the + Internet. By default, the egress traffic is blocked, so no outgoing traffic is allowed from a + guest network to the Internet. However, you can control the egress traffic in an Advanced zone + by creating egress firewall rules. When an egress firewall rule is applied, the traffic specific + to the rule is allowed and the remaining traffic is blocked. When all the firewall rules are + removed the default policy, Block, is applied. + Consider the following scenarios to apply egress firewall rules: + + + Allow the egress traffic from specified source CIDR. The Source CIDR is part of guest + network CIDR. + + + Allow the egress traffic with destination protocol TCP,UDP,ICMP, or ALL. + + + Allow the egress traffic with destination protocol and port range. The port range is + specified for TCP, UDP or for ICMP type and code. + + + To configure an egress firewall rule: + + + Log in to the &PRODUCT; UI as an administrator or end user. + + + In the left navigation, choose Network. + + + In Select view, choose Guest networks, then click the Guest network you want. + + + To add an egress rule, click the Egress rules tab and fill out the following fields to + specify what type of traffic is allowed to be sent out of VM instances in this guest + network: + + + + + + egress-firewall-rule.png: adding an egress firewall rule + + + + + CIDR: (Add by CIDR only) To send traffic only to + the IP addresses within a particular address block, enter a CIDR or a comma-separated + list of CIDRs. The CIDR is the base IP address of the destination. For example, + 192.168.0.0/22. To allow all CIDRs, set to 0.0.0.0/0. + + + Protocol: The networking protocol that VMs uses to + send outgoing traffic. The TCP and UDP protocols are typically used for data exchange + and end-user communications. The ICMP protocol is typically used to send error messages + or network monitoring data. + + + Start Port, End Port: (TCP, UDP only) A range of + listening ports that are the destination for the outgoing traffic. If you are opening a + single port, use the same number in both fields. + + + ICMP Type, ICMP Code: (ICMP only) The type of + message and error code that are sent. + + + + + Click Add. + + +
diff --git a/docs/en-US/firewall-rules.xml b/docs/en-US/firewall-rules.xml index 01d072bbcc4..837a4c6f9d0 100644 --- a/docs/en-US/firewall-rules.xml +++ b/docs/en-US/firewall-rules.xml @@ -3,53 +3,80 @@ %BOOK_ENTITIES; ]> -
- Firewall Rules - By default, all incoming traffic to the public IP address is rejected by the firewall. To allow external traffic, you can open firewall ports by specifying firewall rules. You can optionally specify one or more CIDRs to filter the source IPs. This is useful when you want to allow only incoming requests from certain IP addresses. - You cannot use firewall rules to open ports for an elastic IP address. When elastic IP is used, outside access is instead controlled through the use of security groups. See . - Firewall rules can be created using the Firewall tab in the Management Server UI. This tab is not displayed by default when &PRODUCT; is installed. To display the Firewall tab, the &PRODUCT; administrator must set the global configuration parameter firewall.rule.ui.enabled to "true." - To create a firewall rule: - - Log in to the &PRODUCT; UI as an administrator or end user. - In the left navigation, choose Network. - Click the name of the network where you want to work with. - Click View IP Addresses. - Click the IP address you want to work with. - - Click the Configuration tab and fill in the following values. - - Source CIDR. (Optional) To accept only traffic from IP - addresses within a particular address block, enter a CIDR or a - comma-separated list of CIDRs. Example: 192.168.0.0/22. Leave empty to allow - all CIDRs. - Protocol. The communication protocol in use on the opened - port(s). - Start Port and End Port. The port(s) you want to open on the - firewall. If you are opening a single port, use the same number in both - fields - ICMP Type and ICMP Code. Used only if Protocol is set to - ICMP. Provide the type and code required by the ICMP protocol to fill out - the ICMP header. Refer to ICMP documentation for more details if you are not - sure what to enter - - Click Add. - + Firewall Rules + By default, all incoming traffic to the public IP address is rejected by the firewall. To + allow external traffic, you can open firewall ports by specifying firewall rules. You can + optionally specify one or more CIDRs to filter the source IPs. This is useful when you want to + allow only incoming requests from certain IP addresses. + You cannot use firewall rules to open ports for an elastic IP address. When elastic IP is + used, outside access is instead controlled through the use of security groups. See . + In an advanced zone, you can also create egress firewall rules by using the virtual router. + For more information, see . + Firewall rules can be created using the Firewall tab in the Management Server UI. This tab + is not displayed by default when &PRODUCT; is installed. To display the Firewall tab, the + &PRODUCT; administrator must set the global configuration parameter firewall.rule.ui.enabled to + "true." + To create a firewall rule: + + + Log in to the &PRODUCT; UI as an administrator or end user. + + + In the left navigation, choose Network. + + + Click the name of the network where you want to work with. + + + Click View IP Addresses. + + + Click the IP address you want to work with. + + + Click the Configuration tab and fill in the following values. + + + Source CIDR. (Optional) To accept only traffic from + IP addresses within a particular address block, enter a CIDR or a comma-separated list + of CIDRs. Example: 192.168.0.0/22. Leave empty to allow all CIDRs. + + + Protocol. The communication protocol in use on the + opened port(s). + + + Start Port and End Port. The port(s) you want to + open on the firewall. If you are opening a single port, use the same number in both + fields + + + ICMP Type and ICMP Code. Used only if Protocol is + set to ICMP. Provide the type and code required by the ICMP protocol to fill out the + ICMP header. Refer to ICMP documentation for more details if you are not sure what to + enter + + + + + Click Add. + +
diff --git a/docs/en-US/images/egress-firewall-rule.png b/docs/en-US/images/egress-firewall-rule.png new file mode 100644 index 00000000000..fa1d8ecd0bd Binary files /dev/null and b/docs/en-US/images/egress-firewall-rule.png differ diff --git a/docs/en-US/images/resize-volume-icon.png b/docs/en-US/images/resize-volume-icon.png new file mode 100644 index 00000000000..48499021f06 Binary files /dev/null and b/docs/en-US/images/resize-volume-icon.png differ diff --git a/docs/en-US/images/resize-volume.png b/docs/en-US/images/resize-volume.png new file mode 100644 index 00000000000..6195623ab49 Binary files /dev/null and b/docs/en-US/images/resize-volume.png differ diff --git a/docs/en-US/ip-forwarding-firewalling.xml b/docs/en-US/ip-forwarding-firewalling.xml index c154b078da3..54e18b7cfbc 100644 --- a/docs/en-US/ip-forwarding-firewalling.xml +++ b/docs/en-US/ip-forwarding-firewalling.xml @@ -3,28 +3,30 @@ %BOOK_ENTITIES; ]> -
- IP Forwarding and Firewalling - By default, all incoming traffic to the public IP address is rejected. All outgoing traffic from the guests is translated via NAT to the public IP address and is allowed. - To allow incoming traffic, users may set up firewall rules and/or port forwarding rules. For example, you can use a firewall rule to open a range of ports on the public IP address, such as 33 through 44. Then use port forwarding rules to direct traffic from individual ports within that range to specific ports on user VMs. For example, one port forwarding rule could route incoming traffic on the public IP's port 33 to port 100 on one user VM's private IP. - - + IP Forwarding and Firewalling + By default, all incoming traffic to the public IP address is rejected. All outgoing traffic + from the guests is translated via NAT to the public IP address and is allowed. + To allow incoming traffic, users may set up firewall rules and/or port forwarding rules. For + example, you can use a firewall rule to open a range of ports on the public IP address, such as + 33 through 44. Then use port forwarding rules to direct traffic from individual ports within + that range to specific ports on user VMs. For example, one port forwarding rule could route + incoming traffic on the public IP's port 33 to port 100 on one user VM's private IP. + +
diff --git a/docs/en-US/management-server-install-db-external.xml b/docs/en-US/management-server-install-db-external.xml index 3bba45f3ee1..a28dee56934 100644 --- a/docs/en-US/management-server-install-db-external.xml +++ b/docs/en-US/management-server-install-db-external.xml @@ -127,12 +127,17 @@ bind-address = 0.0.0.0 recommended that you replace this with a more secure value. See . + + (Optional) For management_server_ip, you may explicitly specify cluster management + server node IP. If not specified, the local IP address will be used. + cloud-setup-databases cloud:<dbpassword>@<ip address mysql server> \ --deploy-as=root:<password> \ -e <encryption_type> \ -m <management_server_key> \ --k <database_key> +-k <database_key> \ +-i <management_server_ip> When this script is finished, you should see a message like “Successfully initialized the database.” diff --git a/docs/en-US/management-server-install-db-local.xml b/docs/en-US/management-server-install-db-local.xml index 3e09c554df0..242249040b1 100644 --- a/docs/en-US/management-server-install-db-local.xml +++ b/docs/en-US/management-server-install-db-local.xml @@ -98,12 +98,17 @@ binlog-format = 'ROW' recommended that you replace this with a more secure value. See . + + (Optional) For management_server_ip, you may explicitly specify cluster management + server node IP. If not specified, the local IP address will be used. + cloud-setup-databases cloud:<dbpassword>@localhost \ --deploy-as=root:<password> \ -e <encryption_type> \ -m <management_server_key> \ --k <database_key> +-k <database_key> \ +-i <management_server_ip> When this script is finished, you should see a message like “Successfully initialized the database.” @@ -118,7 +123,7 @@ binlog-format = 'ROW' Now that the database is set up, you can finish configuring the OS for the Management Server. This command will set up iptables, sudoers, and start the Management Server. - # cloud-setup-management + # cloud-setup-management You should see the message “&PRODUCT; Management Server setup is done.” diff --git a/docs/en-US/management-server-install-multi-node.xml b/docs/en-US/management-server-install-multi-node.xml index e61f6230ff0..3f011b83b87 100644 --- a/docs/en-US/management-server-install-multi-node.xml +++ b/docs/en-US/management-server-install-multi-node.xml @@ -53,7 +53,7 @@ linkend="sect-source-buildrpm"/> or as Configure the database client. Note the absence of the --deploy-as argument in this case. (For more details about the arguments to this command, see .) - # cloud-setup-databases cloud:dbpassword@dbhost -e encryption_type -m management_server_key -k database_key + # cloud-setup-databases cloud:dbpassword@dbhost -e encryption_type -m management_server_key -k database_key -i management_server_ip @@ -69,4 +69,4 @@ linkend="sect-source-buildrpm"/> or as Load Balancing. - \ No newline at end of file + diff --git a/docs/en-US/networks.xml b/docs/en-US/networks.xml index a7b9ea12466..830576902b1 100644 --- a/docs/en-US/networks.xml +++ b/docs/en-US/networks.xml @@ -45,4 +45,5 @@ - \ No newline at end of file + + diff --git a/docs/en-US/persistent-network.xml b/docs/en-US/persistent-network.xml new file mode 100644 index 00000000000..1ccc99c59a6 --- /dev/null +++ b/docs/en-US/persistent-network.xml @@ -0,0 +1,100 @@ + + +%BOOK_ENTITIES; +]> + + +
+ Persistent Networks + The network that you can provision without having to deploy any VMs on it is called a + persistent network. A persistent network can be part of a VPC or a non-VPC environment. + When you create other types of network, a network is only a database entry until the first + VM is created on that network. When the first VM is created, a VLAN ID is assigned and the + network is provisioned. Also, when the last VM is destroyed, the VLAN ID is released and the + network is no longer available. With the addition of persistent network, you will have the + ability to create a network in &PRODUCT; in which physical devices can be deployed without + having to run any VMs. Additionally, you can deploy physical devices on that network. + One of the advantages of having a persistent network is that you can create a VPC with a tier + consisting of only physical devices. For example, you might create a VPC for a three-tier + application, deploy VMs for Web and Application tier, and use physical machines for the + Database tier. Another use case is that if you are providing services by using physical + hardware, you can define the network as persistent and therefore even if all its VMs are + destroyed the services will not be discontinued. +
+ Persistent Network Considerations + + + Persistent network is designed for isolated networks. + + + All default network offerings are non-persistent. + + + A network offering cannot be editable because changing it affects the behavior of the + existing networks that were created using this network offering. + + + When you create a guest network, the network offering that you select defines the + network persistence. This in turn depends on whether persistent network is enabled in the + selected network offering. + + + An existing network can be made persistent by changing its network offering to an + offering that has the Persistent option enabled. While setting this property, even if the + network has no running VMs, the network is provisioned. + + + An existing network can be made non-persistent by changing its network offering to an + offering that has the Persistent option disabled. If the network has no running VMs, + during the next network garbage collection run the network is shut down. + + + When the last VM on a network is destroyed, the network garbage collector checks if + the network offering associated with the network is persistent, and shuts down the network + only if it is non-persistent. + + +
+
+ Creating a Persistent Guest Network + To create a persistent network, perform the following: + + + Create a network offering with the Persistent option enabled. + See . + See the Administration Guide. + + + Select Network from the left navigation pane. + + + Select the guest network that you want to offer this network service to. + + + Click the Edit button. + + + From the Network Offering drop-down, select the persistent network offering you have + just created. + + + Click OK. + + +
+
diff --git a/docs/en-US/plugin-niciranvp-devicemanagement.xml b/docs/en-US/plugin-niciranvp-devicemanagement.xml index 2423ce3925d..57b8eee9d7d 100644 --- a/docs/en-US/plugin-niciranvp-devicemanagement.xml +++ b/docs/en-US/plugin-niciranvp-devicemanagement.xml @@ -22,7 +22,7 @@ -->
Device-management - In CloudStack 4.0.x each Nicira NVP setup is considered a "device" that can be added and removed from a physical network. To complete the configuration of the Nicira NVP plugin a device needs to be added to the physical network using the "addNiciraNVPDevice" API call. The plugin is now enabled on the physical network and any guest networks created on that network will be provisioned using the Nicra NVP Controller. + In &PRODUCT; 4.0.x each Nicira NVP setup is considered a "device" that can be added and removed from a physical network. To complete the configuration of the Nicira NVP plugin a device needs to be added to the physical network using the "addNiciraNVPDevice" API call. The plugin is now enabled on the physical network and any guest networks created on that network will be provisioned using the Nicira NVP Controller. The plugin introduces a set of new API calls to manage the devices, see below or refer to the API reference. addNiciraNvpDevice @@ -44,4 +44,4 @@ listNiciraNVPDevices -
\ No newline at end of file + diff --git a/docs/en-US/plugin-niciranvp-features.xml b/docs/en-US/plugin-niciranvp-features.xml index b71e67f4199..c346bfb64e3 100644 --- a/docs/en-US/plugin-niciranvp-features.xml +++ b/docs/en-US/plugin-niciranvp-features.xml @@ -22,12 +22,12 @@ -->
Features of the Nicira NVP Plugin - In CloudStack release 4.0.0-incubating this plugin supports the Connectivity service. This service is responsible for creating Layer 2 networks supporting the networks created by Guests. In other words when an tennant creates a new network, instead of the traditional VLAN a logical network will be created by sending the appropriate calls to the Nicira NVP Controller. + In &PRODUCT; release 4.0.0-incubating this plugin supports the Connectivity service. This service is responsible for creating Layer 2 networks supporting the networks created by Guests. In other words when an tenant creates a new network, instead of the traditional VLAN a logical network will be created by sending the appropriate calls to the Nicira NVP Controller. The plugin has been tested with Nicira NVP versions 2.1.0, 2.2.0 and 2.2.1 - In CloudStack 4.0.0-incubating only the XenServer hypervisor is supported for use in + In &PRODUCT; 4.0.0-incubating only the XenServer hypervisor is supported for use in combination with Nicira NVP. - In CloudStack 4.1.0-incubating both KVM and XenServer hypervisors are + In &PRODUCT; 4.1.0-incubating both KVM and XenServer hypervisors are supported. - In CloudStack 4.0.0-incubating the UI components for this plugin are not complete, + In &PRODUCT; 4.0.0-incubating the UI components for this plugin are not complete, configuration is done by sending commands to the API.
diff --git a/docs/en-US/plugin-niciranvp-preparations.xml b/docs/en-US/plugin-niciranvp-preparations.xml index 86b795ccd0b..762c941fd13 100644 --- a/docs/en-US/plugin-niciranvp-preparations.xml +++ b/docs/en-US/plugin-niciranvp-preparations.xml @@ -23,7 +23,7 @@
Prerequisites Before enabling the Nicira NVP plugin the NVP Controller needs to be configured. Please review the NVP User Guide on how to do that. - CloudStack needs to have at least one physical network with the isolation method set to "STT". This network should be enabled for the Guest traffic type. + &PRODUCT; needs to have at least one physical network with the isolation method set to "STT". This network should be enabled for the Guest traffic type. The Guest traffic type should be configured with the traffic label that matches the name of the Integration Bridge on the hypervisor. See the Nicira NVP User Guide for more details on how to set this up in XenServer or KVM. @@ -33,6 +33,6 @@ The username to access the API The password to access the API The UUID of the Transport Zone that contains the hypervisors in this Zone - The UUID of the Physical Network that will used for the Guest networks + The UUID of the Physical Network that will be used for the Guest networks -
\ No newline at end of file + diff --git a/docs/en-US/plugin-niciranvp-uuidreferences.xml b/docs/en-US/plugin-niciranvp-uuidreferences.xml index c912971736b..cb5f1cae834 100644 --- a/docs/en-US/plugin-niciranvp-uuidreferences.xml +++ b/docs/en-US/plugin-niciranvp-uuidreferences.xml @@ -22,9 +22,9 @@ -->
UUID References - The plugin maintains several references in the CloudStack database to items created on the NVP Controller. - Every guest network this is created will have its broadcast type set to Lswitch and if the network is in state "Implemented", the broadcast URI will have the UUID of the Logical Switch that was created for this network on the NVP Controller. + The plugin maintains several references in the &PRODUCT; database to items created on the NVP Controller. + Every guest network that is created will have its broadcast type set to Lswitch and if the network is in state "Implemented", the broadcast URI will have the UUID of the Logical Switch that was created for this network on the NVP Controller. The Nics that are connected to one of the Logical Switches will have their Logical Switch Port UUID listed in the nicira_nvp_nic_map table All devices created on the NVP Controller will have a tag set to domain-account of the owner of the network, this string can be used to search for items in the NVP Controller. -
\ No newline at end of file + diff --git a/docs/en-US/reset-ssh-key-dev.xml b/docs/en-US/reset-ssh-key-dev.xml new file mode 100644 index 00000000000..1a904e566ef --- /dev/null +++ b/docs/en-US/reset-ssh-key-dev.xml @@ -0,0 +1,27 @@ + + +%BOOK_ENTITIES; +]> + +
+ Resetting SSH Keys to Access VMs + Use the resetSSHKeyForVirtualMachine API to set or reset the SSH keypair assigned to a + virtual machine. With the addition of this feature, a lost or compromised SSH keypair can be + changed, and the user can access the VM by using the new keypair. Just create or register a new + keypair, then call resetSSHKeyForVirtualMachine. +
diff --git a/docs/en-US/resizing-volumes.xml b/docs/en-US/resizing-volumes.xml index 471411df5fe..42b584bf6c6 100644 --- a/docs/en-US/resizing-volumes.xml +++ b/docs/en-US/resizing-volumes.xml @@ -11,9 +11,7 @@ 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 - + 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 @@ -21,18 +19,80 @@ specific language governing permissions and limitations under the License. --> -
- Resizing Volumes - &PRODUCT; does not provide the ability to resize root disks or data disks; the disk size is fixed based on the template used to create the VM. However, the tool VHD Resizer), while not officially supported by Cloud.com or Citrix, might provide a workaround. To increase disk size with VHD Resizer: - - Get the VHD from the secondary storage. - Import it into VHD Resizer. - Resize the VHD. - Upload the new VHD. - Create a new VM. - Take a snapshot, then create a new template from that snapshot. - For more information, see How to Resize a Provisioning Server 5 Virtual Disk at the Citrix Knowledge Center - + Resizing Volumes + &PRODUCT; provides the ability to resize data disks; &PRODUCT; controls volume size by using + disk offerings. This provides &PRODUCT; administrators with the flexibility to choose how much + space they want to make available to the end users. Volumes within the disk offerings with the + same storage tag can be resized. For example, if you only want to offer 10, 50, and 100 GB + offerings, the allowed resize should stay within those limits. That implies if you define a 10 + GB, a 50 GB and a 100 GB disk offerings, a user can upgrade from 10 GB to 50 GB, or 50 GB to 100 + GB. If you create a custom-sized disk offering, then you have the option to resize the volume by + specifying a new, larger size. + Additionally, using the resizeVolume API, a data volume can be moved from a static disk + offering to a custom disk offering with the size specified. This functionality allows those who + might be billing by certain volume sizes or disk offerings to stick to that model, while + providing the flexibility to migrate to whatever custom size necessary. + This feature is supported on KVM, XenServer, and VMware hosts. However, shrinking volumes is + not supported on VMware hosts. + Before you try to resize a volume, consider the following: + + + The VMs associated with the volume are stopped. + + + The data disks associated with the volume are removed. + + + When a volume is shrunk, the disk associated with it is simply truncated, and doing so + would put its content at risk of data loss. Therefore, resize any partitions or file systems + before you shrink a data disk so that all the data is moved off from that disk. + + + To resize a volume: + + + Log in to the &PRODUCT; UI as a user or admin. + + + In the left navigation bar, click Storage. + + + In Select View, choose Volumes. + + + Select the volume name in the Volumes list, then click the Resize Volume button + + + + + resize-volume-icon.png: button to display the resize volume option. + + + + + In the Resize Volume pop-up, choose desired characteristics for the storage. + + + + + + resize-volume.png: option to resize a volume. + + + + + If you select Custom Disk, specify a custom size. + + + Click Shrink OK to confirm that you are reducing the size of a volume. + This parameter protects against inadvertent shrinking of a disk, which might lead to + the risk of data loss. You must sign off that you know what you are doing. + + + + + Click OK. + +
- diff --git a/docs/en-US/site-to-site-vpn.xml b/docs/en-US/site-to-site-vpn.xml index 6570aabe0bd..a5899eac4f1 100644 --- a/docs/en-US/site-to-site-vpn.xml +++ b/docs/en-US/site-to-site-vpn.xml @@ -55,6 +55,9 @@ Create VPN connection from the VPC VPN gateway to the customer VPN gateway. + Appropriate events are generated on the &PRODUCT; UI when status of a Site-to-Site VPN + connection changes from connected to disconnected, or vice versa. Currently no events are generated + when establishing a VPN connection fails or pending. diff --git a/docs/en-US/verifying-source.xml b/docs/en-US/verifying-source.xml index f8bd102379d..b445aa4bd67 100644 --- a/docs/en-US/verifying-source.xml +++ b/docs/en-US/verifying-source.xml @@ -32,7 +32,7 @@ Getting the KEYS To enable you to verify the GPG signature, you will need to download the - KEYS + KEYS file. diff --git a/docs/en-US/vmx-settings-dev.xml b/docs/en-US/vmx-settings-dev.xml new file mode 100644 index 00000000000..a0fdf7f7825 --- /dev/null +++ b/docs/en-US/vmx-settings-dev.xml @@ -0,0 +1,40 @@ + + +%BOOK_ENTITIES; +]> + +
+ Additional VMX Settings + A VMX (.vmx) file is the primary configuration file for a virtual machine. When a new VM is + created, information on the operating system, disk sizes, and networking is stored in this file. + The VM actively writes to its .vmx file for all the configuration changes. The VMX file is + typically located in the directory where the VM is created. In Windows Vista / Windows 7 / + Windows Server 2008, the default location is C:\Users\<your_user_name>\My + Documents\Virtual Machines\<virtual_machine_name>.vmx. In Linux, vmware-cmd -l lists the + full path to all the registered VMX files. Any manual additions to the .vmx file from ESX/ESXi + are overwritten by the entries stored in the vCenter Server database. Therefore, before you edit + a .vmx file, first remove the VM from the vCenter server's inventory and register the VM again + after editing. + The CloudStack API that supports passing some of the VMX settings is registerTemplate. The + supported parameters are rootDiskController, nicAdapter, and keyboard. In addition to these + existing VMX parameters, you can now use the keyboard.typematicMinDelay parameter in the + registerTemplate API call. This parameter controls the amount of delay for the repeated key + strokes on remote consoles. For more information on keyboard.typematicMinDelay, see keyboard.typematicMinDelay. +
diff --git a/docs/en-US/whats-new.xml b/docs/en-US/whats-new.xml index 77b3ec3df22..29ae1f68903 100644 --- a/docs/en-US/whats-new.xml +++ b/docs/en-US/whats-new.xml @@ -3,40 +3,45 @@ %BOOK_ENTITIES; ]> - - - What's New in the API? - The following describes any new major features of each &PRODUCT; version as it applies to API usage. -
- What's New in the API for 4.0 - - -
-
- What's New in the API for 3.0 - - - - - - -
+ What's New in the API? + The following describes any new major features of each &PRODUCT; version as it applies to + API usage. +
+ What's New in the API for 4.1 + + + + +
+
+ What's New in the API for 4.0 + + +
+
+ What's New in the API for 3.0 + + + + + + +
diff --git a/docs/en-US/working-with-system-vm.xml b/docs/en-US/working-with-system-vm.xml index 97459f947bf..70f7dd1aa4e 100644 --- a/docs/en-US/working-with-system-vm.xml +++ b/docs/en-US/working-with-system-vm.xml @@ -1,33 +1,39 @@ - %BOOK_ENTITIES; ]> - - - Working with System Virtual Machines - &PRODUCT; uses several types of system virtual machines to perform tasks in the cloud. In general &PRODUCT; manages these system VMs and creates, starts, and stops them as needed based on scale and immediate needs. However, the administrator should be aware of them and their roles to assist in debugging issues. - - - - - + Working with System Virtual Machines + &PRODUCT; uses several types of system virtual machines to perform tasks in the cloud. In + general &PRODUCT; manages these system VMs and creates, starts, and stops them as needed based + on scale and immediate needs. However, the administrator should be aware of them and their roles + to assist in debugging issues. + + You can configure the system.vm.random.password parameter to create a random system VM + password to ensure higher security. If you reset the value for system.vm.random.password to + true and restart the Management Server, a random password is generated and stored encrypted in + the database. You can view the decrypted password under the system.vm.password global + parameter on the &PRODUCT; UI or by calling the listConfigurations API. + + + + + + diff --git a/docs/pot/verifying-source.pot b/docs/pot/verifying-source.pot index 9c1effe6bf5..9b2d586aacf 100644 --- a/docs/pot/verifying-source.pot +++ b/docs/pot/verifying-source.pot @@ -40,7 +40,7 @@ msgstr "" #. Tag: para #, no-c-format -msgid "To enable you to verify the GPG signature, you will need to download the KEYS file." +msgid "To enable you to verify the GPG signature, you will need to download the KEYS file." msgstr "" #. Tag: para diff --git a/engine/api/pom.xml b/engine/api/pom.xml index cbb83e46add..7fc612f5d6c 100644 --- a/engine/api/pom.xml +++ b/engine/api/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml @@ -32,7 +32,7 @@
org.apache.cloudstack - cloud-framework-ipc + cloud-framework-api ${project.version} diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ClusterScope.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ClusterScope.java index 50d5444233b..fce7d82cb99 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ClusterScope.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ClusterScope.java @@ -21,11 +21,11 @@ package org.apache.cloudstack.engine.subsystem.api.storage; public class ClusterScope implements Scope { private ScopeType type = ScopeType.CLUSTER; - private long clusterId; - private long podId; - private long zoneId; + private Long clusterId; + private Long podId; + private Long zoneId; - public ClusterScope(long clusterId, long podId, long zoneId) { + public ClusterScope(Long clusterId, Long podId, Long zoneId) { this.clusterId = clusterId; this.podId = podId; this.zoneId = zoneId; @@ -37,15 +37,15 @@ public class ClusterScope implements Scope { } @Override - public long getScopeId() { + public Long getScopeId() { return this.clusterId; } - public long getPodId() { + public Long getPodId() { return this.podId; } - public long getZoneId() { + public Long getZoneId() { return this.zoneId; } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CopyCommandResult.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CopyCommandResult.java index 100fd4edba3..571a77c3786 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CopyCommandResult.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CopyCommandResult.java @@ -18,14 +18,22 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; +import com.cloud.agent.api.Answer; + public class CopyCommandResult extends CommandResult { private final String path; - public CopyCommandResult(String path) { + private final Answer answer; + public CopyCommandResult(String path, Answer answer) { super(); this.path = path; + this.answer = answer; } public String getPath() { return this.path; } + + public Answer getAnswer() { + return this.answer; + } } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java index 812db48cf8c..0827cf6b674 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java @@ -28,4 +28,5 @@ public interface DataObject { public DataObjectType getType(); public DiskFormat getFormat(); public String getUuid(); + public void processEvent(ObjectInDataStoreStateMachine.Event event); } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectInStore.java similarity index 51% rename from engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManager.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectInStore.java index f27753dd2d7..32ea996e638 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectInStore.java @@ -16,30 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.volume; +package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeProfile; -import org.apache.cloudstack.storage.volume.db.VolumeVO; +import com.cloud.utils.fsm.StateObject; -import com.cloud.storage.Volume; -import com.cloud.storage.Volume.Event; -import com.cloud.storage.Volume.State; -import com.cloud.utils.fsm.NoTransitionException; -import com.cloud.utils.fsm.StateMachine2; -public interface VolumeManager { - VolumeVO allocateDuplicateVolume(VolumeVO oldVol); - - VolumeVO processEvent(Volume vol, Volume.Event event) throws NoTransitionException; - - VolumeProfile getProfile(long volumeId); - - VolumeVO getVolume(long volumeId); - - VolumeVO updateVolume(VolumeVO volume); - - /** - * @return - */ - StateMachine2 getStateMachine(); +public interface DataObjectInStore extends StateObject { + public String getInstallPath(); + public void setInstallPath(String path); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStore.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStore.java index 03f2b0408ae..f101f243047 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStore.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStore.java @@ -20,6 +20,9 @@ public interface DataStore { DataStoreDriver getDriver(); DataStoreRole getRole(); long getId(); + String getUuid(); String getUri(); Scope getScope(); + DataObject create(DataObject obj); + boolean delete(DataObject obj); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java index 4aba9bfdbff..cf5759b2924 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java @@ -30,4 +30,5 @@ public interface DataStoreDriver { public void deleteAsync(DataObject data, AsyncCompletionCallback callback); public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback callback); public boolean canCopy(DataObject srcData, DataObject destData); + public void resize(DataObject data, AsyncCompletionCallback callback); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java index ef578a7b0d8..95e3d0b2ef8 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java @@ -20,23 +20,23 @@ package org.apache.cloudstack.engine.subsystem.api.storage; import java.util.Map; +import com.cloud.agent.api.StoragePoolInfo; + public interface DataStoreLifeCycle { - public DataStore initialize(Map dsInfos); + public DataStore initialize(Map dsInfos); public boolean attachCluster(DataStore store, ClusterScope scope); - + public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo); boolean attachZone(DataStore dataStore, ZoneScope scope); public boolean dettach(); public boolean unmanaged(); - public boolean maintain(); - - public boolean cancelMaintain(); - - public boolean deleteDataStore(); + public boolean maintain(long storeId); + public boolean cancelMaintain(long storeId); + public boolean deleteDataStore(long storeId); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java similarity index 79% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManager.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java index 829be506ccc..15e49e133fb 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java @@ -16,14 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.datastore; +package org.apache.cloudstack.engine.subsystem.api.storage; +import java.util.List; import java.util.Map; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; public interface DataStoreManager { public DataStore getDataStore(long storeId, DataStoreRole role); + public DataStore getPrimaryDataStore(long storeId); + public DataStore getDataStore(String uuid, DataStoreRole role); + public List getImageStores(Scope scope); public DataStore registerDataStore(Map params, String providerUuid); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProvider.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java similarity index 83% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProvider.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java index 0d38f34f1c7..d29c4828713 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProvider.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java @@ -16,12 +16,10 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.datastore.provider; +package org.apache.cloudstack.engine.subsystem.api.storage; import java.util.Map; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; public interface DataStoreProvider { public DataStoreLifeCycle getLifeCycle(); diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java similarity index 90% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManager.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java index cbe045c5bc8..94998133196 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.datastore.provider; +package org.apache.cloudstack.engine.subsystem.api.storage; import java.util.List; @@ -26,5 +26,6 @@ public interface DataStoreProviderManager extends Manager { public DataStoreProvider getDataStoreProviderByUuid(String uuid); public DataStoreProvider getDataStoreProviderById(long id); public DataStoreProvider getDataStoreProvider(String name); + public DataStoreProvider getDefaultPrimaryDataStoreProvider(); public List getDataStoreProviders(); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreStatus.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreStatus.java similarity index 94% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreStatus.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreStatus.java index 23551e4d0ac..2388795410c 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreStatus.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreStatus.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.datastore; +package org.apache.cloudstack.engine.subsystem.api.storage; public enum DataStoreStatus { Initial, Initialized, Creating, Attaching, Up, PrepareForMaintenance, ErrorInMaintenance, CancelMaintenance, Maintenance, Removed; diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HostScope.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HostScope.java index da36e439376..71d1952c625 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HostScope.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HostScope.java @@ -21,8 +21,8 @@ package org.apache.cloudstack.engine.subsystem.api.storage; public class HostScope implements Scope { private ScopeType type = ScopeType.HOST; - private long hostId; - public HostScope(long hostId) { + private Long hostId; + public HostScope(Long hostId) { this.hostId = hostId; } @Override @@ -31,7 +31,7 @@ public class HostScope implements Scope { } @Override - public long getScopeId() { + public Long getScopeId() { return this.hostId; } } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java new file mode 100644 index 00000000000..3ac17598bb0 --- /dev/null +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java @@ -0,0 +1,24 @@ +/* + * 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.engine.subsystem.api.storage; + +public interface HypervisorHostListener { + boolean hostConnect(long hostId, long poolId); + boolean hostDisconnected(long hostId, long poolId); +} diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/ImageDataFactory.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageDataFactory.java similarity index 84% rename from engine/storage/src/org/apache/cloudstack/storage/image/ImageDataFactory.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageDataFactory.java index 7c7c2a8c530..f0d69887c7d 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/ImageDataFactory.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageDataFactory.java @@ -16,10 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.image; +package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; public interface ImageDataFactory { TemplateInfo getTemplate(long templateId, DataStore store); + TemplateInfo getTemplate(DataObject obj, DataStore store); + TemplateInfo getTemplate(long templateId); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageService.java similarity index 77% rename from engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageService.java index 319406d5001..119f3b1d32f 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageService.java @@ -16,13 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.image; +package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.framework.async.AsyncCallFuture; public interface ImageService { AsyncCallFuture createTemplateAsync(TemplateInfo template, DataStore store); + AsyncCallFuture createTemplateFromSnapshotAsync(SnapshotInfo snapshot, TemplateInfo template, DataStore store); + AsyncCallFuture createTemplateFromVolumeAsync(VolumeInfo volume, TemplateInfo template, DataStore store); AsyncCallFuture deleteTemplateAsync(TemplateInfo template); + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/ObjectInDataStoreStateMachine.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java similarity index 94% rename from engine/storage/src/org/apache/cloudstack/storage/volume/ObjectInDataStoreStateMachine.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java index d0530d1934a..726ce0821c5 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/ObjectInDataStoreStateMachine.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.volume; +package org.apache.cloudstack.engine.subsystem.api.storage; import com.cloud.utils.fsm.StateObject; @@ -49,6 +49,8 @@ public interface ObjectInDataStoreStateMachine extends StateObject callback); + public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java index ec87cb5aa01..3497f7a894f 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java @@ -19,21 +19,19 @@ package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -public interface PrimaryDataStoreInfo { +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePool; + +public interface PrimaryDataStoreInfo extends StoragePool { public boolean isHypervisorSupported(HypervisorType hypervisor); public boolean isLocalStorageSupported(); public boolean isVolumeDiskTypeSupported(DiskFormat diskType); - public long getCapacity(); - public long getAvailableCapacity(); - public long getId(); public String getUuid(); - public DataCenterResourceEntity.State getManagedState(); - public String getName(); - public String getType(); + + public StoragePoolType getPoolType(); public PrimaryDataStoreLifeCycle getLifeCycle(); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/Scope.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/Scope.java index a9601a138bf..c1596d4f5f7 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/Scope.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/Scope.java @@ -20,5 +20,5 @@ package org.apache.cloudstack.engine.subsystem.api.storage; public interface Scope { public ScopeType getScopeType(); - public long getScopeId(); + public Long getScopeId(); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactory.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java similarity index 83% rename from engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactory.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java index 22d328f4932..1ff3ff25065 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactory.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotDataFactory.java @@ -16,10 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.snapshot; +package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; public interface SnapshotDataFactory { public SnapshotInfo getSnapshot(long snapshotId, DataStore store); + public SnapshotInfo getSnapshot(DataObject obj, DataStore store); + public SnapshotInfo getSnapshot(long snapshotId); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotInfo.java similarity index 79% rename from engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotInfo.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotInfo.java index 755531d99b2..b90404c5667 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotInfo.java @@ -14,13 +14,15 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.storage.snapshot; +package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import com.cloud.storage.Snapshot; -public interface SnapshotInfo extends DataObject { + +public interface SnapshotInfo extends DataObject, Snapshot { public SnapshotInfo getParent(); public SnapshotInfo getChild(); public VolumeInfo getBaseVolume(); + Long getDataCenterId(); + public Long getPrevSnapshotId(); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java similarity index 75% rename from engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategy.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java index 4e311862e50..e9492c4afc6 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategy.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java @@ -14,10 +14,14 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.storage.snapshot; + +package org.apache.cloudstack.engine.subsystem.api.storage; + public interface SnapshotStrategy { - public boolean takeSnapshot(SnapshotInfo snapshot); + public boolean canHandle(SnapshotInfo snapshot); + public SnapshotInfo takeSnapshot(VolumeInfo volume, Long snapshotId); + public SnapshotInfo backupSnapshot(SnapshotInfo snapshot); + public boolean deleteSnapshot(SnapshotInfo snapshot); public boolean revertSnapshot(SnapshotInfo snapshot); - public boolean deleteSnapshot(SnapshotInfo snapshot); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/TemplateEvent.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateEvent.java similarity index 93% rename from engine/storage/src/org/apache/cloudstack/storage/image/TemplateEvent.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateEvent.java index 44d0005ac80..c677166b39a 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/TemplateEvent.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateEvent.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.image; +package org.apache.cloudstack.engine.subsystem.api.storage; public enum TemplateEvent { CreateRequested, diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/TemplateInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateInfo.java similarity index 78% rename from engine/storage/src/org/apache/cloudstack/storage/image/TemplateInfo.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateInfo.java index d91be6c62e8..8e03503911e 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/TemplateInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateInfo.java @@ -16,12 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.image; - -import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; - -import com.cloud.utils.fsm.NoTransitionException; +package org.apache.cloudstack.engine.subsystem.api.storage; public interface TemplateInfo extends DataObject { } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/TemplateState.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateState.java similarity index 93% rename from engine/storage/src/org/apache/cloudstack/storage/image/TemplateState.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateState.java index c5981e38ac0..ef2488080f8 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/TemplateState.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateState.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.image; +package org.apache.cloudstack.engine.subsystem.api.storage; public enum TemplateState { Allocated, diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/VolumeDataFactory.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeDataFactory.java similarity index 82% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/VolumeDataFactory.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeDataFactory.java index 0cffc055ee4..1518fd2eb43 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/VolumeDataFactory.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeDataFactory.java @@ -16,11 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.datastore; +package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; public interface VolumeDataFactory { VolumeInfo getVolume(long volumeId, DataStore store); + VolumeInfo getVolume(DataObject volume, DataStore store); + VolumeInfo getVolume(long volumeId); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java index bedb9e72e07..349325af45d 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java @@ -18,6 +18,13 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; -public interface VolumeInfo extends DataObject { +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Volume; + +public interface VolumeInfo extends DataObject, Volume { public boolean isAttachedVM(); + public void addPayload(Object data); + public Object getpayload(); + public HypervisorType getHypervisorType(); + public Long getLastPoolId(); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java similarity index 63% rename from engine/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java index 19a4c3a881c..102c47174b1 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/VolumeService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java @@ -16,17 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.volume; +package org.apache.cloudstack.engine.subsystem.api.storage; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; -import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; -import org.apache.cloudstack.engine.subsystem.api.storage.type.VolumeType; import org.apache.cloudstack.framework.async.AsyncCallFuture; -import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.image.TemplateInfo; + +import com.cloud.exception.ConcurrentOperationException; + public interface VolumeService { @@ -40,10 +36,6 @@ public interface VolumeService { return this.volume; } } - /** - * - */ - VolumeEntity allocateVolumeInDb(long size, VolumeType type, String volName, Long templateId); /** * Creates the volume based on the given criteria @@ -52,7 +44,7 @@ public interface VolumeService { * * @return the volume object */ - AsyncCallFuture createVolumeAsync(VolumeInfo volume, long dataStoreId); + AsyncCallFuture createVolumeAsync(VolumeInfo volume, DataStore store); /** * Delete volume @@ -61,7 +53,7 @@ public interface VolumeService { * @return * @throws ConcurrentOperationException */ - AsyncCallFuture deleteVolumeAsync(VolumeInfo volume); + AsyncCallFuture expungeVolumeAsync(VolumeInfo volume); /** * @@ -71,21 +63,18 @@ public interface VolumeService { /** * */ - boolean createVolumeFromSnapshot(long volumeId, long snapshotId); + AsyncCallFuture createVolumeFromSnapshot(VolumeInfo volume, DataStore store, SnapshotInfo snapshot); - /** - * - */ - String grantAccess(VolumeInfo volume, EndPoint endpointId); - - TemplateOnPrimaryDataStoreInfo grantAccess(TemplateOnPrimaryDataStoreInfo template, EndPoint endPoint); - - /** - * - */ - boolean rokeAccess(long volumeId, long endpointId); VolumeEntity getVolumeEntity(long volumeId); AsyncCallFuture createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template); + AsyncCallFuture copyVolume(VolumeInfo srcVolume, DataStore destStore); + + boolean destroyVolume(long volumeId) throws ConcurrentOperationException; + + AsyncCallFuture registerVolume(VolumeInfo volume, DataStore store); + + AsyncCallFuture resize(VolumeInfo volume); + } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ZoneScope.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ZoneScope.java index 7f211f4f9e9..ac277af36de 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ZoneScope.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ZoneScope.java @@ -21,9 +21,9 @@ package org.apache.cloudstack.engine.subsystem.api.storage; public class ZoneScope implements Scope { private ScopeType type = ScopeType.ZONE; - private long zoneId; + private Long zoneId; - public ZoneScope(long zoneId) { + public ZoneScope(Long zoneId) { this.zoneId = zoneId; } @@ -33,7 +33,7 @@ public class ZoneScope implements Scope { } @Override - public long getScopeId() { + public Long getScopeId() { return this.zoneId; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDao.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDao.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDao.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDao.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDaoImpl.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDaoImpl.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDaoImpl.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDaoImpl.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderVO.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderVO.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderVO.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java similarity index 65% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java index 24a5c790688..1530ced30fd 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java +++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java @@ -21,23 +21,23 @@ package org.apache.cloudstack.storage.datastore.db; import java.util.List; import java.util.Map; -import org.apache.cloudstack.storage.datastore.DataStoreStatus; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreStatus; import com.cloud.utils.db.GenericDao; -public interface PrimaryDataStoreDao extends GenericDao { +public interface PrimaryDataStoreDao extends GenericDao { /** * @param datacenterId * -- the id of the datacenter (availability zone) */ - List listByDataCenterId(long datacenterId); + List listByDataCenterId(long datacenterId); /** * @param datacenterId * -- the id of the datacenter (availability zone) */ - List listBy(long datacenterId, long podId, Long clusterId); + List listBy(long datacenterId, long podId, Long clusterId); /** * Set capacity of storage pool in bytes @@ -59,7 +59,7 @@ public interface PrimaryDataStoreDao extends GenericDao details); + StoragePoolVO persist(StoragePoolVO pool, Map details); /** * Find pool by name. @@ -68,7 +68,7 @@ public interface PrimaryDataStoreDao extends GenericDao findPoolByName(String name); + List findPoolByName(String name); /** * Find pools by the pod that matches the details. @@ -79,9 +79,9 @@ public interface PrimaryDataStoreDao extends GenericDao findPoolsByDetails(long dcId, long podId, Long clusterId, Map details); + List findPoolsByDetails(long dcId, long podId, Long clusterId, Map details); - List findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, Boolean shared); + List findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, Boolean shared); /** * Find pool by UUID. @@ -90,13 +90,13 @@ public interface PrimaryDataStoreDao extends GenericDao listByStorageHost(String hostFqdnOrIp); + List listByStorageHost(String hostFqdnOrIp); - PrimaryDataStoreVO findPoolByHostPath(long dcId, Long podId, String host, String path, String uuid); + StoragePoolVO findPoolByHostPath(long dcId, Long podId, String host, String path, String uuid); - List listPoolByHostPath(String host, String path); + List listPoolByHostPath(String host, String path); void updateDetails(long poolId, Map details); @@ -104,13 +104,13 @@ public interface PrimaryDataStoreDao extends GenericDao searchForStoragePoolDetails(long poolId, String value); - List findIfDuplicatePoolsExistByUUID(String uuid); + List findIfDuplicatePoolsExistByUUID(String uuid); - List listByStatus(DataStoreStatus status); + List listByStatus(DataStoreStatus status); long countPoolsByStatus(DataStoreStatus... statuses); - List listByStatusInZone(long dcId, DataStoreStatus status); + List listByStatusInZone(long dcId, DataStoreStatus status); - List listPoolsByCluster(long clusterId); + List listPoolsByCluster(long clusterId); } \ No newline at end of file diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java similarity index 77% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java index faca54b569a..023b42bda9d 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java +++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java @@ -29,7 +29,7 @@ import java.util.Map; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.storage.datastore.DataStoreStatus; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreStatus; import org.springframework.stereotype.Component; import com.cloud.utils.db.DB; @@ -43,12 +43,12 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; @Component -public class PrimaryDataStoreDaoImpl extends GenericDaoBase implements PrimaryDataStoreDao { - protected final SearchBuilder AllFieldSearch; - protected final SearchBuilder DcPodSearch; - protected final SearchBuilder DcPodAnyClusterSearch; - protected final SearchBuilder DeleteLvmSearch; - protected final GenericSearchBuilder StatusCountSearch; +public class PrimaryDataStoreDaoImpl extends GenericDaoBase implements PrimaryDataStoreDao { + protected final SearchBuilder AllFieldSearch; + protected final SearchBuilder DcPodSearch; + protected final SearchBuilder DcPodAnyClusterSearch; + protected final SearchBuilder DeleteLvmSearch; + protected final GenericSearchBuilder StatusCountSearch; @Inject protected PrimaryDataStoreDetailsDao _detailsDao; @@ -99,73 +99,73 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase findPoolByName(String name) { - SearchCriteria sc = AllFieldSearch.create(); + public List findPoolByName(String name) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("name", name); return listIncludingRemovedBy(sc); } @Override - public PrimaryDataStoreVO findPoolByUUID(String uuid) { - SearchCriteria sc = AllFieldSearch.create(); + public StoragePoolVO findPoolByUUID(String uuid) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("uuid", uuid); return findOneIncludingRemovedBy(sc); } @Override - public List findIfDuplicatePoolsExistByUUID(String uuid) { - SearchCriteria sc = AllFieldSearch.create(); + public List findIfDuplicatePoolsExistByUUID(String uuid) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("uuid", uuid); return listBy(sc); } @Override - public List listByDataCenterId(long datacenterId) { - SearchCriteria sc = AllFieldSearch.create(); + public List listByDataCenterId(long datacenterId) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("datacenterId", datacenterId); return listBy(sc); } @Override public void updateAvailable(long id, long available) { - PrimaryDataStoreVO pool = createForUpdate(id); + StoragePoolVO pool = createForUpdate(id); pool.setAvailableBytes(available); update(id, pool); } @Override public void updateCapacity(long id, long capacity) { - PrimaryDataStoreVO pool = createForUpdate(id); + StoragePoolVO pool = createForUpdate(id); pool.setCapacityBytes(capacity); update(id, pool); } @Override - public List listByStorageHost(String hostFqdnOrIp) { - SearchCriteria sc = AllFieldSearch.create(); + public List listByStorageHost(String hostFqdnOrIp) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("hostAddress", hostFqdnOrIp); return listIncludingRemovedBy(sc); } @Override - public List listByStatus(DataStoreStatus status) { - SearchCriteria sc = AllFieldSearch.create(); + public List listByStatus(DataStoreStatus status) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("status", status); return listBy(sc); } @Override - public List listByStatusInZone(long dcId, DataStoreStatus status) { - SearchCriteria sc = AllFieldSearch.create(); + public List listByStatusInZone(long dcId, DataStoreStatus status) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("status", status); sc.setParameters("datacenterId", dcId); return listBy(sc); } @Override - public PrimaryDataStoreVO findPoolByHostPath(long datacenterId, Long podId, String host, String path, String uuid) { - SearchCriteria sc = AllFieldSearch.create(); + public StoragePoolVO findPoolByHostPath(long datacenterId, Long podId, String host, String path, String uuid) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("hostAddress", host); sc.setParameters("path", path); sc.setParameters("datacenterId", datacenterId); @@ -176,16 +176,16 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase listBy(long datacenterId, long podId, Long clusterId) { + public List listBy(long datacenterId, long podId, Long clusterId) { if (clusterId != null) { - SearchCriteria sc = DcPodSearch.create(); + SearchCriteria sc = DcPodSearch.create(); sc.setParameters("datacenterId", datacenterId); sc.setParameters("podId", podId); sc.setParameters("cluster", clusterId); return listBy(sc); } else { - SearchCriteria sc = DcPodAnyClusterSearch.create(); + SearchCriteria sc = DcPodAnyClusterSearch.create(); sc.setParameters("datacenterId", datacenterId); sc.setParameters("podId", podId); return listBy(sc); @@ -193,16 +193,16 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase listPoolByHostPath(String host, String path) { - SearchCriteria sc = AllFieldSearch.create(); + public List listPoolByHostPath(String host, String path) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("hostAddress", host); sc.setParameters("path", path); return listBy(sc); } - public PrimaryDataStoreVO listById(Integer id) { - SearchCriteria sc = AllFieldSearch.create(); + public StoragePoolVO listById(Integer id) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("id", id); return findOneIncludingRemovedBy(sc); @@ -210,7 +210,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase details) { + public StoragePoolVO persist(StoragePoolVO pool, Map details) { Transaction txn = Transaction.currentTxn(); txn.start(); pool = super.persist(pool); @@ -226,7 +226,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase findPoolsByDetails(long dcId, long podId, Long clusterId, Map details) { + public List findPoolsByDetails(long dcId, long podId, Long clusterId, Map details) { StringBuilder sql = new StringBuilder(DetailsSqlPrefix); if (clusterId != null) { sql.append("storage_pool.cluster_id = ? OR storage_pool.cluster_id IS NULL) AND ("); @@ -248,7 +248,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase pools = new ArrayList(); + List pools = new ArrayList(); while (rs.next()) { pools.add(toEntityBean(rs, false)); } @@ -267,8 +267,8 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, Boolean shared) { - List storagePools = null; + public List findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, Boolean shared) { + List storagePools = null; if (tags == null || tags.length == 0) { storagePools = listBy(dcId, podId, clusterId); } else { @@ -279,8 +279,8 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase filteredStoragePools = new ArrayList(storagePools); - for (PrimaryDataStoreVO pool : storagePools) { + List filteredStoragePools = new ArrayList(storagePools); + for (StoragePoolVO pool : storagePools) { /* * if (shared != pool.isShared()) { * filteredStoragePools.remove(pool); } @@ -351,8 +351,8 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase listPoolsByCluster(long clusterId) { - SearchCriteria sc = AllFieldSearch.create(); + public List listPoolsByCluster(long clusterId) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("clusterId", clusterId); return listBy(sc); diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailVO.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailVO.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailVO.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java similarity index 95% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java index 906742bb3f0..c2b109a959e 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java +++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java @@ -18,7 +18,6 @@ package org.apache.cloudstack.storage.datastore.db; import java.util.Map; -import com.cloud.storage.StoragePoolDetailVO; import com.cloud.utils.db.GenericDao; public interface PrimaryDataStoreDetailsDao extends GenericDao { diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDaoImpl.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDaoImpl.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDaoImpl.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDaoImpl.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java similarity index 64% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreVO.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java index 3e37ec7abe8..1782f16a4c1 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreVO.java +++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java @@ -1,24 +1,23 @@ -/* - * 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. - */ +// 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.storage.datastore.db; import java.util.Date; +import java.util.UUID; import javax.persistence.Column; import javax.persistence.Entity; @@ -30,15 +29,15 @@ import javax.persistence.TableGenerator; import javax.persistence.Temporal; import javax.persistence.TemporalType; -import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; -import org.apache.cloudstack.storage.datastore.DataStoreStatus; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePoolStatus; import com.cloud.utils.db.GenericDao; @Entity -@Table(name = "storage_pool") -public class PrimaryDataStoreVO implements Identity { +@Table(name="storage_pool") +public class StoragePoolVO { @Id @TableGenerator(name = "storage_pool_sq", table = "sequence", pkColumnName = "name", valueColumnName = "value", pkColumnValue = "storage_pool_seq", allocationSize = 1) @Column(name = "id", updatable = false, nullable = false) @@ -51,7 +50,8 @@ public class PrimaryDataStoreVO implements Identity { private String uuid = null; @Column(name = "pool_type", updatable = false, nullable = false, length = 32) - private String poolType; + @Enumerated(value = EnumType.STRING) + private StoragePoolType poolType; @Column(name = GenericDao.CREATED_COLUMN) Date created; @@ -77,7 +77,7 @@ public class PrimaryDataStoreVO implements Identity { @Column(name = "status", updatable = true, nullable = false) @Enumerated(value = EnumType.STRING) - private DataStoreStatus status; + private StoragePoolStatus status; @Column(name = "storage_provider_id", updatable = true, nullable = false) private Long storageProviderId; @@ -105,28 +105,57 @@ public class PrimaryDataStoreVO implements Identity { return id; } - public DataStoreStatus getStatus() { + public StoragePoolStatus getStatus() { return status; } - public PrimaryDataStoreVO() { - this.status = DataStoreStatus.Initial; + public StoragePoolVO() { + this.status = StoragePoolStatus.Initial; } + + public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type, + long dataCenterId, Long podId, long availableBytes, long capacityBytes, String hostAddress, int port, String hostPath) { + this.name = name; + this.id = poolId; + this.uuid = uuid; + this.poolType = type; + this.dataCenterId = dataCenterId; + this.availableBytes = availableBytes; + this.capacityBytes = capacityBytes; + this.hostAddress = hostAddress; + this.path = hostPath; + this.port = port; + this.podId = podId; + this.setStatus(StoragePoolStatus.Initial); + } + + public StoragePoolVO(StoragePoolVO that) { + this(that.id, that.name, that.uuid, that.poolType, that.dataCenterId, that.podId, that.availableBytes, that.capacityBytes, that.hostAddress, that.port, that.path); + } + + public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path) { + this.poolType = type; + this.hostAddress = hostAddress; + this.port = port; + this.path = path; + this.setStatus(StoragePoolStatus.Initial); + this.uuid = UUID.randomUUID().toString(); + } + public String getName() { return name; } - @Override public String getUuid() { return uuid; } - public String getPoolType() { + public StoragePoolType getPoolType() { return poolType; } - public void setPoolType(String protocol) { + public void setPoolType(StoragePoolType protocol) { this.poolType = protocol; } @@ -194,7 +223,7 @@ public class PrimaryDataStoreVO implements Identity { return userInfo; } - public void setStatus(DataStoreStatus status) { + public void setStatus(StoragePoolStatus status) { this.status = status; } @@ -248,10 +277,10 @@ public class PrimaryDataStoreVO implements Identity { @Override public boolean equals(Object obj) { - if (!(obj instanceof PrimaryDataStoreVO) || obj == null) { + if (!(obj instanceof StoragePoolVO) || obj == null) { return false; } - PrimaryDataStoreVO that = (PrimaryDataStoreVO) obj; + StoragePoolVO that = (StoragePoolVO) obj; return this.id == that.id; } @@ -264,4 +293,12 @@ public class PrimaryDataStoreVO implements Identity { public String toString() { return new StringBuilder("Pool[").append(id).append("|").append(poolType).append("]").toString(); } -} \ No newline at end of file + + public boolean isShared() { + return this.scope == ScopeType.HOST ? false : true; + } + + public boolean isLocal() { + return !isShared(); + } +} diff --git a/engine/components-api/pom.xml b/engine/components-api/pom.xml index a4f8a44fa2a..6d6ad4d14b9 100644 --- a/engine/components-api/pom.xml +++ b/engine/components-api/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml diff --git a/engine/compute/pom.xml b/engine/compute/pom.xml index 8fb3ab4fb2b..0875bb63f39 100644 --- a/engine/compute/pom.xml +++ b/engine/compute/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml diff --git a/engine/network/pom.xml b/engine/network/pom.xml index 3396a42321c..60cb7e950ec 100644 --- a/engine/network/pom.xml +++ b/engine/network/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml diff --git a/engine/orchestration/pom.xml b/engine/orchestration/pom.xml index 95426eae9dd..c98373aa353 100755 --- a/engine/orchestration/pom.xml +++ b/engine/orchestration/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java old mode 100644 new mode 100755 index b91a2cabd62..552aba43cca --- a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import javax.inject.Inject; @@ -28,6 +27,7 @@ import org.apache.cloudstack.engine.cloud.entity.api.db.VMEntityVO; import org.apache.cloudstack.engine.cloud.entity.api.db.VMReservationVO; import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMEntityDao; import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMReservationDao; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.springframework.stereotype.Component; import com.cloud.dc.DataCenter; @@ -42,25 +42,22 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.dao.NetworkDao; import com.cloud.org.Cluster; import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.storage.StoragePoolVO; +import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; -import com.cloud.user.Account; -import com.cloud.user.User; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.utils.component.ComponentContext; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachineManager; -import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfileImpl; import com.cloud.vm.dao.VMInstanceDao; @@ -104,6 +101,8 @@ public class VMEntityManagerImpl implements VMEntityManager { @Inject protected StoragePoolDao _storagePoolDao; + @Inject + DataStoreManager dataStoreMgr; @Override public VMEntityVO loadVirtualMachine(String vmId) { @@ -134,7 +133,8 @@ public class VMEntityManagerImpl implements VMEntityManager { List vols = _volsDao.findReadyRootVolumesByInstance(vm.getId()); if(!vols.isEmpty()){ VolumeVO vol = vols.get(0); - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); + StoragePool pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(vol.getPoolId()); + if (!pool.isInMaintenance()) { long rootVolDcId = pool.getDataCenterId(); Long rootVolPodId = pool.getPodId(); @@ -169,10 +169,13 @@ public class VMEntityManagerImpl implements VMEntityManager { //save destination with VMEntityVO VMReservationVO vmReservation = new VMReservationVO(vm.getId(), dest.getDataCenter().getId(), dest.getPod().getId(), dest.getCluster().getId(), dest.getHost().getId()); Map volumeReservationMap = new HashMap(); - for(Volume vo : dest.getStorageForDisks().keySet()){ - volumeReservationMap.put(vo.getId(), dest.getStorageForDisks().get(vo).getId()); + + if (vm.getHypervisorType() != HypervisorType.BareMetal) { + for(Volume vo : dest.getStorageForDisks().keySet()){ + volumeReservationMap.put(vo.getId(), dest.getStorageForDisks().get(vo).getId()); + } + vmReservation.setVolumeReservation(volumeReservationMap); } - vmReservation.setVolumeReservation(volumeReservationMap); vmEntityVO.setVmReservation(vmReservation); _vmEntityDao.persist(vmEntityVO); diff --git a/engine/pom.xml b/engine/pom.xml index 9a5f6d57987..1a3d896d50d 100644 --- a/engine/pom.xml +++ b/engine/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml index 3e38a840571..da40d9cc4a3 100644 --- a/engine/schema/pom.xml +++ b/engine/schema/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml diff --git a/engine/service/pom.xml b/engine/service/pom.xml index 38ff81591f2..47c0edcefc0 100644 --- a/engine/service/pom.xml +++ b/engine/service/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT cloud-engine-service war diff --git a/engine/storage/backup/pom.xml b/engine/storage/backup/pom.xml index 8b4fd277055..019e09c7204 100644 --- a/engine/storage/backup/pom.xml +++ b/engine/storage/backup/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/backup/src/org/apache/cloudstack/storage/backup/BackupService.java b/engine/storage/backup/src/org/apache/cloudstack/storage/backup/BackupService.java index e4cb0c7031e..67924d2ce73 100644 --- a/engine/storage/backup/src/org/apache/cloudstack/storage/backup/BackupService.java +++ b/engine/storage/backup/src/org/apache/cloudstack/storage/backup/BackupService.java @@ -18,7 +18,7 @@ */ package org.apache.cloudstack.storage.backup; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; public interface BackupService { public boolean backupSnapshot(SnapshotInfo snapshot, long backupStoreId); diff --git a/engine/storage/image/pom.xml b/engine/storage/image/pom.xml index c05714b9b54..c4cf14ca9b5 100644 --- a/engine/storage/image/pom.xml +++ b/engine/storage/image/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java index b6a45b5f6bb..616e4789a27 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java @@ -20,38 +20,74 @@ package org.apache.cloudstack.storage.image; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.storage.datastore.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.db.ImageDataDao; -import org.apache.cloudstack.storage.image.db.ImageDataVO; import org.apache.cloudstack.storage.image.store.TemplateObject; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplatePoolDao; + @Component public class ImageDataFactoryImpl implements ImageDataFactory { + private static final Logger s_logger = Logger + .getLogger(ImageDataFactoryImpl.class); @Inject - ImageDataDao imageDataDao; + VMTemplateDao imageDataDao; @Inject ObjectInDataStoreManager objMap; @Inject DataStoreManager storeMgr; + @Inject + VMTemplatePoolDao templatePoolDao; @Override public TemplateInfo getTemplate(long templateId, DataStore store) { - ImageDataVO templ = imageDataDao.findById(templateId); + VMTemplateVO templ = imageDataDao.findById(templateId); if (store == null) { TemplateObject tmpl = TemplateObject.getTemplate(templ, null); return tmpl; } - ObjectInDataStoreVO obj = objMap.findObject(templateId, DataObjectType.TEMPLATE, store.getId(), store.getRole()); - if (obj == null) { - TemplateObject tmpl = TemplateObject.getTemplate(templ, null); - return tmpl; + boolean found = false; + if (store.getRole() == DataStoreRole.Primary) { + VMTemplateStoragePoolVO templatePoolVO = templatePoolDao.findByPoolTemplate(store.getId(), templateId); + if (templatePoolVO != null) { + found = true; + } + } else { + DataObjectInStore obj = objMap.findObject(templ.getUuid(), DataObjectType.TEMPLATE, store.getUuid(), store.getRole()); + if (obj != null) { + found = true; + } + } + + if (!found) { + s_logger.debug("template " + templateId + " is not in store:" + store.getId() + ", type:" + store.getRole()); } TemplateObject tmpl = TemplateObject.getTemplate(templ, store); return tmpl; } + @Override + public TemplateInfo getTemplate(long templateId) { + VMTemplateVO templ = imageDataDao.findById(templateId); + if (templ.getImageDataStoreId() == null) { + return this.getTemplate(templateId, null); + } + DataStore store = this.storeMgr.getDataStore(templ.getImageDataStoreId(), DataStoreRole.Image); + return this.getTemplate(templateId, store); + } + @Override + public TemplateInfo getTemplate(DataObject obj, DataStore store) { + return this.getTemplate(obj.getId(), store); + } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java index 82d0d71db9c..5898b1b0794 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java @@ -22,15 +22,21 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.storage.datastore.DataObjectManager; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; import org.apache.cloudstack.storage.image.store.TemplateObject; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -41,21 +47,25 @@ public class ImageServiceImpl implements ImageService { private static final Logger s_logger = Logger.getLogger(ImageServiceImpl.class); @Inject ObjectInDataStoreManager objectInDataStoreMgr; + @Inject + DataObjectManager dataObjectMgr; class CreateTemplateContext extends AsyncRpcConext { final TemplateInfo srcTemplate; - final TemplateInfo templateOnStore; + final DataStore store; final AsyncCallFuture future; - final ObjectInDataStoreVO obj; + final DataObject templateOnStore; + public CreateTemplateContext(AsyncCompletionCallback callback, TemplateInfo srcTemplate, - TemplateInfo templateOnStore, AsyncCallFuture future, - ObjectInDataStoreVO obj) { + DataStore store, + DataObject templateOnStore + ) { super(callback); this.srcTemplate = srcTemplate; - this.templateOnStore = templateOnStore; this.future = future; - this.obj = obj; + this.store = store; + this.templateOnStore = templateOnStore; } } @@ -74,31 +84,15 @@ public class ImageServiceImpl implements ImageService { return future; } - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject(template.getId(), template.getType(), store.getId(), store.getRole()); - TemplateInfo templateOnStore = null; - if (obj == null) { - templateOnStore = (TemplateInfo)objectInDataStoreMgr.create(template, store); - obj = objectInDataStoreMgr.findObject(template.getId(), template.getType(), store.getId(), store.getRole()); - } else { - CommandResult result = new CommandResult(); - result.setResult("duplicate template on the storage"); - future.complete(result); - return future; - } + DataObject templateOnStore = store.create(template); + templateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.CreateOnlyRequested); - try { - objectInDataStoreMgr.update(obj, Event.CreateOnlyRequested); - } catch (NoTransitionException e) { - s_logger.debug("failed to transit", e); - CommandResult result = new CommandResult(); - result.setResult(e.toString()); - future.complete(result); - return future; - } CreateTemplateContext context = new CreateTemplateContext(null, - template, templateOnStore, + template, future, - obj); + store, + templateOnStore + ); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().createTemplateCallback(null, null)) .setContext(context); @@ -108,42 +102,25 @@ public class ImageServiceImpl implements ImageService { protected Void createTemplateCallback(AsyncCallbackDispatcher callback, CreateTemplateContext context) { - - TemplateInfo templateOnStore = context.templateOnStore; TemplateObject template = (TemplateObject)context.srcTemplate; AsyncCallFuture future = context.future; CommandResult result = new CommandResult(); - + DataObject templateOnStore = context.templateOnStore; CreateCmdResult callbackResult = callback.getResult(); if (callbackResult.isFailed()) { try { - objectInDataStoreMgr.update(templateOnStore, Event.OperationFailed); + templateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + template.stateTransit(TemplateEvent.OperationFailed); } catch (NoTransitionException e) { - s_logger.debug("failed to transit state", e); + s_logger.debug("Failed to update template state", e); } result.setResult(callbackResult.getResult()); future.complete(result); return null; } - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject(templateOnStore.getId(), templateOnStore.getType(), templateOnStore.getDataStore().getId(), templateOnStore.getDataStore().getRole()); - obj.setInstallPath(callbackResult.getPath()); - - if (callbackResult.getSize() != null) { - obj.setSize(callbackResult.getSize()); - } try { - objectInDataStoreMgr.update(obj, Event.OperationSuccessed); - } catch (NoTransitionException e) { - s_logger.debug("Failed to transit state", e); - result.setResult(e.toString()); - future.complete(result); - return null; - } - - template.setImageStoreId(templateOnStore.getDataStore().getId()); - template.setSize(callbackResult.getSize()); - try { + templateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed); template.stateTransit(TemplateEvent.OperationSucceeded); } catch (NoTransitionException e) { s_logger.debug("Failed to transit state", e); @@ -162,4 +139,18 @@ public class ImageServiceImpl implements ImageService { // TODO Auto-generated method stub return null; } + + @Override + public AsyncCallFuture createTemplateFromSnapshotAsync( + SnapshotInfo snapshot, TemplateInfo template, DataStore store) { + // TODO Auto-generated method stub + return null; + } + + @Override + public AsyncCallFuture createTemplateFromVolumeAsync( + VolumeInfo volume, TemplateInfo template, DataStore store) { + // TODO Auto-generated method stub + return null; + } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java index adb247afd0f..af572d49a5e 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java @@ -18,7 +18,7 @@ */ package org.apache.cloudstack.storage.image.downloader; -import org.apache.cloudstack.storage.image.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; public interface ImageDownloader { public void downloadImage(TemplateInfo template); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java new file mode 100644 index 00000000000..97ea6c48c79 --- /dev/null +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java @@ -0,0 +1,250 @@ +/* + * 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.storage.image.driver; + +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.storage.image.ImageDataStoreDriver; +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.DeleteSnapshotBackupCommand; +import com.cloud.agent.api.storage.DeleteVolumeCommand; +import com.cloud.agent.api.to.S3TO; +import com.cloud.agent.api.to.SwiftTO; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.storage.RegisterVolumePayload; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplateZoneDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; +import com.cloud.storage.download.DownloadMonitor; +import com.cloud.storage.s3.S3Manager; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.storage.swift.SwiftManager; +import com.cloud.utils.exception.CloudRuntimeException; + +public class AncientImageDataStoreDriverImpl implements ImageDataStoreDriver { + private static final Logger s_logger = Logger + .getLogger(AncientImageDataStoreDriverImpl.class); + @Inject + VMTemplateZoneDao templateZoneDao; + @Inject + VMTemplateDao templateDao; + @Inject DownloadMonitor _downloadMonitor; + @Inject + VMTemplateHostDao _vmTemplateHostDao; + @Inject VolumeDao volumeDao; + @Inject VolumeHostDao volumeHostDao; + @Inject HostDao hostDao; + @Inject SnapshotDao snapshotDao; + @Inject AgentManager agentMgr; + @Inject SnapshotManager snapshotMgr; + @Inject + private SwiftManager _swiftMgr; + @Inject + private S3Manager _s3Mgr; + @Override + public String grantAccess(DataObject data, EndPoint ep) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean revokeAccess(DataObject data, EndPoint ep) { + // TODO Auto-generated method stub + return false; + } + + @Override + public Set listObjects(DataStore store) { + // TODO Auto-generated method stub + return null; + } + + class CreateContext extends AsyncRpcConext { + final DataObject data; + public CreateContext(AsyncCompletionCallback callback, DataObject data) { + super(callback); + this.data = data; + } + } + + @Override + public void createAsync(DataObject data, + AsyncCompletionCallback callback) { + if (data.getType() == DataObjectType.TEMPLATE) { + List templateZones = this.templateZoneDao.listByTemplateId(data.getId()); + for (VMTemplateZoneVO templateZone : templateZones) { + VMTemplateVO template = this.templateDao.findById(data.getId()); + _downloadMonitor.downloadTemplateToStorage(template, templateZone.getZoneId()); + } + } else if (data.getType() == DataObjectType.VOLUME) { + VolumeVO vol = this.volumeDao.findById(data.getId()); + VolumeInfo volInfo = (VolumeInfo)data; + RegisterVolumePayload payload = (RegisterVolumePayload)volInfo.getpayload(); + _downloadMonitor.downloadVolumeToStorage(vol, vol.getDataCenterId(), payload.getUrl(), + payload.getChecksum(), ImageFormat.valueOf(payload.getFormat().toUpperCase())); + } + + CreateCmdResult result = new CreateCmdResult(null, null); + callback.complete(result); + } + + private void deleteVolume(DataObject data, AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + VolumeVO vol = volumeDao.findById(data.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Expunging " + vol); + } + + // Find out if the volume is present on secondary storage + VolumeHostVO volumeHost = volumeHostDao.findByVolumeId(vol.getId()); + if (volumeHost != null) { + if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { + HostVO ssHost = hostDao.findById(volumeHost.getHostId()); + DeleteVolumeCommand dtCommand = new DeleteVolumeCommand( + ssHost.getStorageUrl(), volumeHost.getInstallPath()); + Answer answer = agentMgr.sendToSecStorage(ssHost, dtCommand); + if (answer == null || !answer.getResult()) { + s_logger.debug("Failed to delete " + + volumeHost + + " due to " + + ((answer == null) ? "answer is null" : answer + .getDetails())); + return; + } + } else if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) { + s_logger.debug("Volume: " + vol.getName() + + " is currently being uploaded; cant' delete it."); + throw new CloudRuntimeException( + "Please specify a volume that is not currently being uploaded."); + } + volumeHostDao.remove(volumeHost.getId()); + volumeDao.remove(vol.getId()); + CommandResult result = new CommandResult(); + callback.complete(result); + return; + } + } + + private void deleteTemplate(DataObject data, AsyncCompletionCallback callback) { + + } + + private void deleteSnapshot(DataObject data, AsyncCompletionCallback callback) { + Long snapshotId = data.getId(); + SnapshotVO snapshot = this.snapshotDao.findByIdIncludingRemoved(snapshotId); + CommandResult result = new CommandResult(); + if (snapshot == null) { + s_logger.debug("Destroying snapshot " + snapshotId + " backup failed due to unable to find snapshot "); + result.setResult("Unable to find snapshot: " + snapshotId); + callback.complete(result); + return; + } + + try { + String secondaryStoragePoolUrl = this.snapshotMgr.getSecondaryStorageURL(snapshot); + Long dcId = snapshot.getDataCenterId(); + Long accountId = snapshot.getAccountId(); + Long volumeId = snapshot.getVolumeId(); + + String backupOfSnapshot = snapshot.getBackupSnapshotId(); + if (backupOfSnapshot == null) { + callback.complete(result); + return; + } + SwiftTO swift = _swiftMgr.getSwiftTO(snapshot.getSwiftId()); + S3TO s3 = _s3Mgr.getS3TO(); + + DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand( + swift, s3, secondaryStoragePoolUrl, dcId, accountId, volumeId, + backupOfSnapshot, false); + Answer answer = agentMgr.sendToSSVM(dcId, cmd); + + if ((answer != null) && answer.getResult()) { + snapshot.setBackupSnapshotId(null); + snapshotDao.update(snapshotId, snapshot); + } else if (answer != null) { + result.setResult(answer.getDetails()); + } + } catch (Exception e) { + s_logger.debug("failed to delete snapshot: " + snapshotId + ": " + e.toString()); + result.setResult(e.toString()); + } + callback.complete(result); + } + + @Override + public void deleteAsync(DataObject data, + AsyncCompletionCallback callback) { + if (data.getType() == DataObjectType.VOLUME) { + deleteVolume(data, callback); + } else if (data.getType() == DataObjectType.TEMPLATE) { + deleteTemplate(data, callback); + } else if (data.getType() == DataObjectType.SNAPSHOT) { + deleteSnapshot(data, callback); + } + } + + @Override + public void copyAsync(DataObject srcdata, DataObject destData, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + + @Override + public boolean canCopy(DataObject srcData, DataObject destData) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void resize(DataObject data, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + +} diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java index dce5a939413..3d46c73cde2 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java @@ -34,15 +34,15 @@ import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.endpoint.EndPointSelector; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; -import org.apache.cloudstack.storage.image.db.ImageDataDao; -import org.apache.cloudstack.storage.image.db.ImageDataVO; + +import com.cloud.storage.dao.VMTemplateDao; //http-read-only based image store public class DefaultImageDataStoreDriverImpl implements ImageDataStoreDriver { @Inject EndPointSelector selector; @Inject - ImageDataDao imageDataDao; + VMTemplateDao imageDataDao; public DefaultImageDataStoreDriverImpl() { } @@ -116,4 +116,11 @@ public class DefaultImageDataStoreDriverImpl implements ImageDataStoreDriver { // TODO Auto-generated method stub } + + @Override + public void resize(DataObject data, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManager.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManager.java index e5a6863a58b..e1fd46b76df 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManager.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManager.java @@ -18,13 +18,13 @@ */ package org.apache.cloudstack.storage.image.manager; -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateState; -import org.apache.cloudstack.storage.image.db.ImageDataVO; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; +import com.cloud.storage.VMTemplateVO; import com.cloud.utils.fsm.StateMachine2; public interface ImageDataManager { - StateMachine2 getStateMachine(); + StateMachine2 getStateMachine(); } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java index d90f2b64e24..83e98878158 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java @@ -18,17 +18,17 @@ */ package org.apache.cloudstack.storage.image.manager; -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateState; -import org.apache.cloudstack.storage.image.db.ImageDataVO; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; import org.springframework.stereotype.Component; +import com.cloud.storage.VMTemplateVO; import com.cloud.utils.fsm.StateMachine2; @Component public class ImageDataManagerImpl implements ImageDataManager { - private final StateMachine2 - stateMachine = new StateMachine2(); + private final StateMachine2 + stateMachine = new StateMachine2(); public ImageDataManagerImpl() { stateMachine.addTransition(TemplateState.Allocated, TemplateEvent.CreateRequested, TemplateState.Creating); @@ -44,7 +44,7 @@ public class ImageDataManagerImpl implements ImageDataManager { } @Override - public StateMachine2 getStateMachine() { + public StateMachine2 getStateMachine() { return stateMachine; } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataStoreManagerImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataStoreManagerImpl.java index 68a2770c549..2771f78e381 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataStoreManagerImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataStoreManagerImpl.java @@ -18,38 +18,48 @@ */ package org.apache.cloudstack.storage.image.manager; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import javax.annotation.PostConstruct; import javax.inject.Inject; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; import org.apache.cloudstack.storage.datastore.provider.ImageDataStoreProvider; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; import org.apache.cloudstack.storage.image.datastore.ImageDataStore; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; -import org.apache.cloudstack.storage.image.db.ImageDataDao; import org.apache.cloudstack.storage.image.db.ImageDataStoreDao; import org.apache.cloudstack.storage.image.db.ImageDataStoreVO; -import org.apache.cloudstack.storage.image.store.HttpDataStoreImpl; +import org.apache.cloudstack.storage.image.store.DefaultImageDataStoreImpl; import org.springframework.stereotype.Component; +import com.cloud.storage.dao.VMTemplateDao; + @Component public class ImageDataStoreManagerImpl implements ImageDataStoreManager { @Inject ImageDataStoreDao dataStoreDao; @Inject - ImageDataDao imageDataDao; + VMTemplateDao imageDataDao; @Inject DataStoreProviderManager providerManager; - Map driverMaps = new HashMap(); + Map driverMaps; + @PostConstruct + public void config() { + driverMaps = new HashMap(); + } + @Override public ImageDataStore getImageDataStore(long dataStoreId) { ImageDataStoreVO dataStore = dataStoreDao.findById(dataStoreId); long providerId = dataStore.getProvider(); ImageDataStoreProvider provider = (ImageDataStoreProvider)providerManager.getDataStoreProviderById(providerId); - ImageDataStore imgStore = HttpDataStoreImpl.getDataStore(dataStore, + ImageDataStore imgStore = DefaultImageDataStoreImpl.getDataStore(dataStore, driverMaps.get(provider.getUuid()), provider ); // TODO Auto-generated method stub @@ -65,4 +75,20 @@ public class ImageDataStoreManagerImpl implements ImageDataStoreManager { return true; } + @Override + public ImageDataStore getImageDataStore(String uuid) { + ImageDataStoreVO dataStore = dataStoreDao.findByUuid(uuid); + return getImageDataStore(dataStore.getId()); + } + + @Override + public List getList() { + List stores = dataStoreDao.listAll(); + List imageStores = new ArrayList(); + for (ImageDataStoreVO store : stores) { + imageStores.add(getImageDataStore(store.getId())); + } + return imageStores; + } + } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/AncientImageDataStoreProvider.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/AncientImageDataStoreProvider.java new file mode 100644 index 00000000000..b2ee9ab853d --- /dev/null +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/AncientImageDataStoreProvider.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.image.store; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.storage.datastore.provider.ImageDataStoreProvider; +import org.apache.cloudstack.storage.image.ImageDataStoreDriver; +import org.apache.cloudstack.storage.image.datastore.ImageDataStoreHelper; +import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; +import org.apache.cloudstack.storage.image.driver.AncientImageDataStoreDriverImpl; +import org.apache.cloudstack.storage.image.store.lifecycle.DefaultImageDataStoreLifeCycle; +import org.apache.cloudstack.storage.image.store.lifecycle.ImageDataStoreLifeCycle; +import org.springframework.stereotype.Component; + +import com.cloud.utils.component.ComponentContext; + +@Component +public class AncientImageDataStoreProvider implements ImageDataStoreProvider { + + private final String name = "ancient image data store"; + protected ImageDataStoreLifeCycle lifeCycle; + protected ImageDataStoreDriver driver; + @Inject + ImageDataStoreManager storeMgr; + @Inject + ImageDataStoreHelper helper; + long id; + String uuid; + @Override + public DataStoreLifeCycle getLifeCycle() { + return lifeCycle; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getUuid() { + return this.uuid; + } + + @Override + public long getId() { + return this.id; + } + + @Override + public boolean configure(Map params) { + lifeCycle = ComponentContext.inject(DefaultImageDataStoreLifeCycle.class); + driver = ComponentContext.inject(AncientImageDataStoreDriverImpl.class); + uuid = (String)params.get("uuid"); + id = (Long)params.get("id"); + storeMgr.registerDriver(uuid, driver); + + Map infos = new HashMap(); + String dataStoreName = UUID.nameUUIDFromBytes(this.name.getBytes()).toString(); + infos.put("name", dataStoreName); + infos.put("uuid", dataStoreName); + infos.put("protocol", "http"); + infos.put("scope", ScopeType.GLOBAL); + infos.put("provider", this.getId()); + DataStoreLifeCycle lifeCycle = this.getLifeCycle(); + lifeCycle.initialize(infos); + return true; + } + +} diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreImpl.java similarity index 79% rename from engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java rename to engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreImpl.java index 34b4ff27f1a..d159f741584 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreImpl.java @@ -26,24 +26,24 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.provider.ImageDataStoreProvider; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.image.datastore.ImageDataStore; -import org.apache.cloudstack.storage.image.db.ImageDataDao; import org.apache.cloudstack.storage.image.db.ImageDataStoreVO; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; +import com.cloud.storage.dao.VMTemplateDao; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.storage.encoding.EncodingType; -public class HttpDataStoreImpl implements ImageDataStore { +public class DefaultImageDataStoreImpl implements ImageDataStore { @Inject - ImageDataDao imageDao; + VMTemplateDao imageDao; @Inject private ObjectInDataStoreManager objectInStoreMgr; protected ImageDataStoreDriver driver; @@ -51,7 +51,7 @@ public class HttpDataStoreImpl implements ImageDataStore { protected ImageDataStoreProvider provider; boolean needDownloadToCacheStorage = false; - protected HttpDataStoreImpl() { + protected DefaultImageDataStoreImpl() { } @@ -62,9 +62,9 @@ public class HttpDataStoreImpl implements ImageDataStore { this.provider = provider; } - public static HttpDataStoreImpl getDataStore(ImageDataStoreVO dataStoreVO, ImageDataStoreDriver imageDataStoreDriver, + public static ImageDataStore getDataStore(ImageDataStoreVO dataStoreVO, ImageDataStoreDriver imageDataStoreDriver, ImageDataStoreProvider provider) { - HttpDataStoreImpl instance = (HttpDataStoreImpl)ComponentContext.inject(HttpDataStoreImpl.class); + DefaultImageDataStoreImpl instance = (DefaultImageDataStoreImpl)ComponentContext.inject(DefaultImageDataStoreImpl.class); instance.configure(dataStoreVO, imageDataStoreDriver, provider); return instance; } @@ -81,24 +81,17 @@ public class HttpDataStoreImpl implements ImageDataStore { return this.driver; } - - @Override public DataStoreRole getRole() { // TODO Auto-generated method stub return DataStoreRole.Image; } - - - @Override public long getId() { // TODO Auto-generated method stub return this.imageDataStoreVO.getId(); } - - @Override public String getUri() { return this.imageDataStoreVO.getProtocol() + "://" + "?" + EncodingType.ROLE + "=" + this.getRole(); @@ -106,39 +99,47 @@ public class HttpDataStoreImpl implements ImageDataStore { @Override public Scope getScope() { - // TODO Auto-generated method stub return new ZoneScope(imageDataStoreVO.getDcId()); } - - @Override public TemplateInfo getTemplate(long templateId) { // TODO Auto-generated method stub return null; } - - @Override public VolumeInfo getVolume(long volumeId) { // TODO Auto-generated method stub return null; } - - @Override public SnapshotInfo getSnapshot(long snapshotId) { // TODO Auto-generated method stub return null; } - - @Override public boolean exists(DataObject object) { - return (objectInStoreMgr.findObject(object.getId(), object.getType(), - this.getId(), this.getRole()) != null) ? true : false; + return (objectInStoreMgr.findObject(object, + this) != null) ? true : false; + } + + @Override + public String getUuid() { + return this.imageDataStoreVO.getUuid(); + } + + @Override + public DataObject create(DataObject obj) { + DataObject object = objectInStoreMgr.create(obj, this); + return object; + } + + @Override + public boolean delete(DataObject obj) { + // TODO Auto-generated method stub + return false; } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreProvider.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreProvider.java index 3569fe803d5..efbb999bdcf 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreProvider.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreProvider.java @@ -29,11 +29,9 @@ import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; import org.apache.cloudstack.storage.image.driver.DefaultImageDataStoreDriverImpl; import org.apache.cloudstack.storage.image.store.lifecycle.DefaultImageDataStoreLifeCycle; import org.apache.cloudstack.storage.image.store.lifecycle.ImageDataStoreLifeCycle; -import org.springframework.stereotype.Component; import com.cloud.utils.component.ComponentContext; -@Component public class DefaultImageDataStoreProvider implements ImageDataStoreProvider { private final String name = "default image data store"; protected ImageDataStoreLifeCycle lifeCycle; diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java index 1b0661c7691..85bc0c118a0 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java @@ -20,44 +20,48 @@ package org.apache.cloudstack.storage.image.store; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.image.db.ImageDataDao; -import org.apache.cloudstack.storage.image.db.ImageDataVO; import org.apache.cloudstack.storage.image.manager.ImageDataManager; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; import org.apache.log4j.Logger; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.storage.encoding.EncodingType; public class TemplateObject implements TemplateInfo { private static final Logger s_logger = Logger .getLogger(TemplateObject.class); - private ImageDataVO imageVO; + private VMTemplateVO imageVO; private DataStore dataStore; @Inject ImageDataManager imageMgr; @Inject - ImageDataDao imageDao; + VMTemplateDao imageDao; @Inject ObjectInDataStoreManager ojbectInStoreMgr; + @Inject VMTemplatePoolDao templatePoolDao; protected TemplateObject() { } - protected void configure(ImageDataVO template, DataStore dataStore) { + protected void configure(VMTemplateVO template, DataStore dataStore) { this.imageVO = template; this.dataStore = dataStore; } - public static TemplateObject getTemplate(ImageDataVO vo, DataStore store) { + public static TemplateObject getTemplate(VMTemplateVO vo, DataStore store) { TemplateObject to = ComponentContext.inject(TemplateObject.class); to.configure(vo, store); return to; @@ -66,12 +70,12 @@ public class TemplateObject implements TemplateInfo { public void setImageStoreId(long id) { this.imageVO.setImageDataStoreId(id); } - + public void setSize(Long size) { this.imageVO.setSize(size); } - public ImageDataVO getImage() { + public VMTemplateVO getImage() { return this.imageVO; } @@ -87,23 +91,20 @@ public class TemplateObject implements TemplateInfo { @Override public String getUuid() { - // TODO Auto-generated method stub - return null; + return this.imageVO.getUuid(); } @Override public String getUri() { - ImageDataVO image = imageDao.findById(this.imageVO.getId()); + VMTemplateVO image = imageDao.findById(this.imageVO.getId()); if (this.dataStore == null) { return image.getUrl(); } else { - ObjectInDataStoreVO obj = ojbectInStoreMgr.findObject( - this.imageVO.getId(), DataObjectType.TEMPLATE, - this.dataStore.getId(), this.dataStore.getRole()); + DataObjectInStore obj = ojbectInStoreMgr.findObject(this, this.dataStore); StringBuilder builder = new StringBuilder(); if (obj.getState() == ObjectInDataStoreStateMachine.State.Ready || obj.getState() == ObjectInDataStoreStateMachine.State.Copying) { - + builder.append(this.dataStore.getUri()); builder.append("&" + EncodingType.OBJTYPE + "=" + DataObjectType.TEMPLATE); builder.append("&" + EncodingType.PATH + "=" + obj.getInstallPath()); @@ -124,10 +125,33 @@ public class TemplateObject implements TemplateInfo { if (this.dataStore == null) { return this.imageVO.getSize(); } - ObjectInDataStoreVO obj = ojbectInStoreMgr.findObject( - this.imageVO.getId(), DataObjectType.TEMPLATE, - this.dataStore.getId(), this.dataStore.getRole()); - return obj.getSize(); + + /* + +// If the template that was passed into this allocator is not installed in the storage pool, + // add 3 * (template size on secondary storage) to the running total + VMTemplateHostVO templateHostVO = _storageMgr.findVmTemplateHost(templateForVmCreation.getId(), null); + + if (templateHostVO == null) { + VMTemplateSwiftVO templateSwiftVO = _swiftMgr.findByTmpltId(templateForVmCreation.getId()); + if (templateSwiftVO != null) { + long templateSize = templateSwiftVO.getPhysicalSize(); + if (templateSize == 0) { + templateSize = templateSwiftVO.getSize(); + } + totalAllocatedSize += (templateSize + _extraBytesPerVolume); + } + } else { + long templateSize = templateHostVO.getPhysicalSize(); + if ( templateSize == 0 ){ + templateSize = templateHostVO.getSize(); + } + totalAllocatedSize += (templateSize + _extraBytesPerVolume); + } + + */ + VMTemplateVO image = imageDao.findById(this.imageVO.getId()); + return image.getSize(); } @Override @@ -137,7 +161,7 @@ public class TemplateObject implements TemplateInfo { @Override public DiskFormat getFormat() { - return DiskFormat.getFormat(this.imageVO.getFormat()); + return DiskFormat.valueOf(this.imageVO.getFormat().toString()); } public boolean stateTransit(TemplateEvent e) throws NoTransitionException { @@ -146,4 +170,14 @@ public class TemplateObject implements TemplateInfo { this.imageVO = imageDao.findById(this.imageVO.getId()); return result; } + + @Override + public void processEvent(Event event) { + try { + ojbectInStoreMgr.update(this, event); + } catch (NoTransitionException e) { + s_logger.debug("failed to update state", e); + throw new CloudRuntimeException("Failed to update state" + e.toString()); + } + } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java index 07d52b40682..17aabca3921 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java @@ -22,12 +22,15 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreHelper; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; import org.apache.cloudstack.storage.image.db.ImageDataStoreDao; import org.apache.cloudstack.storage.image.db.ImageDataStoreVO; +import com.cloud.agent.api.StoragePoolInfo; + public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle { @Inject protected ImageDataStoreDao imageStoreDao; @@ -40,7 +43,7 @@ public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle { @Override - public DataStore initialize(Map dsInfos) { + public DataStore initialize(Map dsInfos) { ImageDataStoreVO ids = imageStoreHelper.createImageDataStore(dsInfos); return imageStoreMgr.getImageDataStore(ids.getId()); } @@ -53,6 +56,14 @@ public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle { } + @Override + public boolean attachHost(DataStore store, HostScope scope, + StoragePoolInfo existingInfo) { + // TODO Auto-generated method stub + return false; + } + + @Override public boolean attachZone(DataStore dataStore, ZoneScope scope) { // TODO Auto-generated method stub @@ -75,23 +86,27 @@ public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle { @Override - public boolean maintain() { + public boolean maintain(long storeId) { // TODO Auto-generated method stub return false; } @Override - public boolean cancelMaintain() { + public boolean cancelMaintain(long storeId) { // TODO Auto-generated method stub return false; } @Override - public boolean deleteDataStore() { + public boolean deleteDataStore(long storeId) { // TODO Auto-generated method stub return false; } + + + + } diff --git a/engine/storage/imagemotion/pom.xml b/engine/storage/imagemotion/pom.xml index 856b9d995e5..9a7f3e017a2 100644 --- a/engine/storage/imagemotion/pom.xml +++ b/engine/storage/imagemotion/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java index 390b0fd7e34..c49a521a3ca 100644 --- a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java +++ b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java @@ -23,7 +23,6 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; @@ -32,12 +31,11 @@ import org.apache.cloudstack.storage.command.CopyCmd; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.endpoint.EndPointSelector; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; -import org.springframework.stereotype.Component; import com.cloud.agent.api.Answer; //At least one of datastore is coming from image store or image cache store -@Component + public class DefaultImageMotionStrategy implements ImageMotionStrategy { @Inject EndPointSelector selector; @@ -86,14 +84,15 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy { @Override public boolean canHandle(DataObject srcData, DataObject destData) { + /* DataStore destStore = destData.getDataStore(); DataStore srcStore = srcData.getDataStore(); if (destStore.getRole() == DataStoreRole.Image || destStore.getRole() == DataStoreRole.ImageCache || srcStore.getRole() == DataStoreRole.Image || srcStore.getRole() == DataStoreRole.ImageCache) { return true; - } - return true; + }*/ + return false; } @Override @@ -102,7 +101,7 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy { DataStore destStore = destData.getDataStore(); DataStore srcStore = srcData.getDataStore(); EndPoint ep = selector.select(srcData, destData); - CopyCommandResult result = new CopyCommandResult(""); + CopyCommandResult result = new CopyCommandResult("", null); if (ep == null) { result.setResult("can't find end point"); callback.complete(result); @@ -126,12 +125,12 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy { AsyncCompletionCallback parentCall = context.getParentCallback(); Answer answer = (Answer)callback.getResult(); if (!answer.getResult()) { - CopyCommandResult result = new CopyCommandResult(""); + CopyCommandResult result = new CopyCommandResult("", null); result.setResult(answer.getDetails()); parentCall.complete(result); } else { CopyCmdAnswer ans = (CopyCmdAnswer)answer; - CopyCommandResult result = new CopyCommandResult(ans.getPath()); + CopyCommandResult result = new CopyCommandResult(ans.getPath(), null); parentCall.complete(result); } return null; diff --git a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java index 0e3636e3886..93ba4a5ad64 100644 --- a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java +++ b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java @@ -23,18 +23,12 @@ import java.util.List; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.ImageService; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; -import org.apache.cloudstack.storage.volume.VolumeService; -import org.springframework.stereotype.Component; -import com.cloud.utils.exception.CloudRuntimeException; -@Component public class ImageMotionServiceImpl implements ImageMotionService { @Inject List motionStrategies; diff --git a/engine/storage/integration-test/pom.xml b/engine/storage/integration-test/pom.xml index 782bc7d218e..368a4e301ab 100644 --- a/engine/storage/integration-test/pom.xml +++ b/engine/storage/integration-test/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java index 9c30a2e8269..2ad52159afc 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java @@ -16,14 +16,25 @@ // under the License. package org.apache.cloudstack.storage.test; +import java.io.IOException; + import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.engine.service.api.OrchestrationService; import org.apache.cloudstack.storage.HostEndpointRpcServer; import org.apache.cloudstack.storage.endpoint.EndPointSelector; +import org.apache.cloudstack.storage.test.ChildTestConfiguration.Library; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; import com.cloud.agent.AgentManager; +import com.cloud.alert.AlertManager; import com.cloud.cluster.ClusteredAgentRebalanceService; import com.cloud.cluster.agentlb.dao.HostTransferMapDao; import com.cloud.cluster.agentlb.dao.HostTransferMapDaoImpl; @@ -50,11 +61,35 @@ import com.cloud.host.dao.HostTagsDaoImpl; import com.cloud.server.auth.UserAuthenticator; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.StoragePoolHostDaoImpl; +import com.cloud.storage.dao.VMTemplateDaoImpl; import com.cloud.storage.dao.VMTemplateDetailsDao; import com.cloud.storage.dao.VMTemplateDetailsDaoImpl; +import com.cloud.storage.dao.VMTemplateHostDaoImpl; +import com.cloud.storage.dao.VMTemplatePoolDaoImpl; import com.cloud.storage.dao.VMTemplateZoneDao; import com.cloud.storage.dao.VMTemplateZoneDaoImpl; - +import com.cloud.storage.dao.VolumeDaoImpl; +import com.cloud.storage.dao.VolumeHostDaoImpl; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.tags.dao.ResourceTagsDaoImpl; +import com.cloud.utils.component.SpringComponentScanUtils; +import com.cloud.vm.dao.NicDaoImpl; +import com.cloud.vm.dao.VMInstanceDaoImpl; +@Configuration +@ComponentScan(basePackageClasses={ + NicDaoImpl.class, + VMInstanceDaoImpl.class, + VMTemplateHostDaoImpl.class, + VolumeHostDaoImpl.class, + VolumeDaoImpl.class, + VMTemplatePoolDaoImpl.class, + ResourceTagsDaoImpl.class, + VMTemplateDaoImpl.class, + MockStorageMotionStrategy.class +}, +includeFilters={@Filter(value=Library.class, type=FilterType.CUSTOM)}, +useDefaultFilters=false +) public class ChildTestConfiguration extends TestConfiguration { @Override @@ -148,6 +183,27 @@ public class ChildTestConfiguration extends TestConfiguration { public APIChecker apiChecker() { return Mockito.mock(APIChecker.class); } + + @Bean + public SnapshotManager snapshotMgr() { + return Mockito.mock(SnapshotManager.class); + } + + @Bean + public AlertManager alertMgr() { + return Mockito.mock(AlertManager.class); + } + + public static class Library implements TypeFilter { + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = ChildTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + + } /* @Override @Bean public PrimaryDataStoreDao primaryDataStoreDao() { diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java new file mode 100644 index 00000000000..b619ee9240f --- /dev/null +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java @@ -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 org.apache.cloudstack.storage.test; + +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.motion.DataMotionStrategy; + +public class MockStorageMotionStrategy implements DataMotionStrategy { + + @Override + public boolean canHandle(DataObject srcData, DataObject destData) { + // TODO Auto-generated method stub + return true; + } + + @Override + public Void copyAsync(DataObject srcData, DataObject destData, + AsyncCompletionCallback callback) { + CopyCommandResult result = new CopyCommandResult("something", null); + callback.complete(result); + return null; + } + +} diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java index 0e88f733e08..85421a53b56 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java @@ -28,33 +28,30 @@ import java.util.UUID; import java.util.concurrent.ExecutionException; import javax.inject.Inject; -import javax.naming.ConfigurationException; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.type.RootDisk; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.storage.HypervisorHostEndPoint; -import org.apache.cloudstack.storage.datastore.VolumeDataFactory; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProvider; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProviderManager; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.endpoint.EndPointSelector; -import org.apache.cloudstack.storage.image.ImageDataFactory; -import org.apache.cloudstack.storage.image.ImageService; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.image.db.ImageDataDao; -import org.apache.cloudstack.storage.image.db.ImageDataVO; -import org.apache.cloudstack.storage.volume.VolumeService; -import org.apache.cloudstack.storage.volume.VolumeService.VolumeApiResult; import org.apache.cloudstack.storage.volume.db.VolumeDao2; import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.mockito.Mockito; @@ -78,7 +75,11 @@ import com.cloud.org.Cluster.ClusterType; import com.cloud.org.Managed.ManagedState; import com.cloud.resource.ResourceState; import com.cloud.storage.Storage; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.utils.component.ComponentContext; @ContextConfiguration(locations={"classpath:/storageContext.xml"}) public class volumeServiceTest extends CloudStackTestNGBase { @@ -89,7 +90,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { @Inject VolumeService volumeService; @Inject - ImageDataDao imageDataDao; + VMTemplateDao imageDataDao; @Inject VolumeDao2 volumeDao; @Inject @@ -121,12 +122,13 @@ public class volumeServiceTest extends CloudStackTestNGBase { @Test(priority = -1) public void setUp() { - try { + ComponentContext.initComponentsLifeCycle(); + /* try { dataStoreProviderMgr.configure(null, new HashMap()); } catch (ConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); - } + }*/ host = hostDao.findByGuid(this.getHostGuid()); if (host != null) { dcId = host.getDataCenterId(); @@ -205,18 +207,17 @@ public class volumeServiceTest extends CloudStackTestNGBase { Mockito.when(selector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(eps.get(0)); } - private ImageDataVO createImageData() { - ImageDataVO image = new ImageDataVO(); + private VMTemplateVO createImageData() { + VMTemplateVO image = new VMTemplateVO(); image.setTemplateType(TemplateType.USER); image.setUrl(this.getTemplateUrl()); image.setUniqueName(UUID.randomUUID().toString()); image.setName(UUID.randomUUID().toString()); image.setPublicTemplate(true); image.setFeatured(true); - image.setRequireHvm(true); + image.setRequiresHvm(true); image.setBits(64); - image.setFormat(Storage.ImageFormat.VHD.toString()); - image.setAccountId(1); + image.setFormat(Storage.ImageFormat.VHD); image.setEnablePassword(true); image.setEnableSshKey(true); image.setGuestOSId(1); @@ -234,13 +235,13 @@ public class volumeServiceTest extends CloudStackTestNGBase { private TemplateInfo createTemplate() { try { DataStore store = createImageStore(); - ImageDataVO image = createImageData(); + VMTemplateVO image = createImageData(); TemplateInfo template = imageDataFactory.getTemplate(image.getId(), store); AsyncCallFuture future = imageService.createTemplateAsync(template, store); future.get(); template = imageDataFactory.getTemplate(image.getId(), store); /*imageProviderMgr.configure("image Provider", new HashMap()); - ImageDataVO image = createImageData(); + VMTemplateVO image = createImageData(); ImageDataStoreProvider defaultProvider = imageProviderMgr.getProvider("DefaultProvider"); ImageDataStoreLifeCycle lifeCycle = defaultProvider.getLifeCycle(); ImageDataStore store = lifeCycle.registerDataStore("defaultHttpStore", new HashMap()); @@ -262,7 +263,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { @Test public void testCreatePrimaryStorage() { DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("default primary data store provider"); - Map params = new HashMap(); + Map params = new HashMap(); URI uri = null; try { uri = new URI(this.getPrimaryStorageUrl()); @@ -273,7 +274,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { params.put("url", this.getPrimaryStorageUrl()); params.put("server", uri.getHost()); params.put("path", uri.getPath()); - params.put("protocol", uri.getScheme()); + params.put("protocol", StoragePoolType.NetworkFilesystem); params.put("dcId", dcId.toString()); params.put("clusterId", clusterId.toString()); params.put("name", this.primaryName); @@ -290,7 +291,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { private DataStore createImageStore() { DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("default image data store"); - Map params = new HashMap(); + Map params = new HashMap(); String name = UUID.randomUUID().toString(); params.put("name", name); params.put("uuid", name); @@ -310,12 +311,12 @@ public class volumeServiceTest extends CloudStackTestNGBase { public DataStore createPrimaryDataStore() { try { DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("default primary data store provider"); - Map params = new HashMap(); + Map params = new HashMap(); URI uri = new URI(this.getPrimaryStorageUrl()); params.put("url", this.getPrimaryStorageUrl()); params.put("server", uri.getHost()); params.put("path", uri.getPath()); - params.put("protocol", uri.getScheme()); + params.put("protocol", Storage.StoragePoolType.NetworkFilesystem); params.put("dcId", dcId.toString()); params.put("clusterId", clusterId.toString()); params.put("name", this.primaryName); @@ -390,7 +391,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { DataStore primaryStore = this.primaryStore; VolumeVO volume = createVolume(null, primaryStore.getId()); VolumeInfo vol = volumeFactory.getVolume(volume.getId(), primaryStore); - AsyncCallFuture future = volumeService.createVolumeAsync(vol, primaryStore.getId()); + AsyncCallFuture future = volumeService.createVolumeAsync(vol, primaryStore); try { future.get(); } catch (InterruptedException e) { @@ -407,7 +408,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { DataStore primaryStore = this.primaryStore; VolumeVO volume = createVolume(null, primaryStore.getId()); VolumeInfo vol = volumeFactory.getVolume(volume.getId(), primaryStore); - AsyncCallFuture future = volumeService.createVolumeAsync(vol, primaryStore.getId()); + AsyncCallFuture future = volumeService.createVolumeAsync(vol, primaryStore); try { future.get(); } catch (InterruptedException e) { @@ -420,7 +421,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { //delete the volume vol = volumeFactory.getVolume(volume.getId(), primaryStore); - future = volumeService.deleteVolumeAsync(vol); + future = volumeService.expungeVolumeAsync(vol); try { future.get(); } catch (InterruptedException e) { @@ -434,9 +435,9 @@ public class volumeServiceTest extends CloudStackTestNGBase { //@Test(priority=3) public void tearDown() { - List ds = primaryStoreDao.findPoolByName(this.primaryName); + List ds = primaryStoreDao.findPoolByName(this.primaryName); for (int i = 0; i < ds.size(); i++) { - PrimaryDataStoreVO store = ds.get(i); + StoragePoolVO store = ds.get(i); store.setUuid(null); primaryStoreDao.remove(ds.get(i).getId()); primaryStoreDao.expunge(ds.get(i).getId()); diff --git a/engine/storage/integration-test/test/resource/component.xml b/engine/storage/integration-test/test/resource/component.xml new file mode 100644 index 00000000000..0368ad41425 --- /dev/null +++ b/engine/storage/integration-test/test/resource/component.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/storage/integration-test/test/resource/storageContext.xml b/engine/storage/integration-test/test/resource/storageContext.xml index 0127c96a734..4f55e243bac 100644 --- a/engine/storage/integration-test/test/resource/storageContext.xml +++ b/engine/storage/integration-test/test/resource/storageContext.xml @@ -45,6 +45,7 @@ + diff --git a/engine/storage/pom.xml b/engine/storage/pom.xml index e8a2eb75193..270fe47c743 100644 --- a/engine/storage/pom.xml +++ b/engine/storage/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml diff --git a/engine/storage/snapshot/pom.xml b/engine/storage/snapshot/pom.xml index 45439c4726a..211cdac574e 100644 --- a/engine/storage/snapshot/pom.xml +++ b/engine/storage/snapshot/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml @@ -44,7 +44,11 @@ install - src - test + ${project.basedir}/test + + + ${project.basedir}/test/resource + + diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java index 487e2d53eff..fa7772a979d 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java @@ -20,28 +20,65 @@ package org.apache.cloudstack.storage.snapshot; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.storage.datastore.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.snapshot.db.SnapshotDao2; -import org.apache.cloudstack.storage.snapshot.db.SnapshotVO; import org.springframework.stereotype.Component; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.utils.exception.CloudRuntimeException; + @Component public class SnapshotDataFactoryImpl implements SnapshotDataFactory { @Inject - SnapshotDao2 snapshotDao; + SnapshotDao snapshotDao; @Inject ObjectInDataStoreManager objMap; @Inject DataStoreManager storeMgr; + @Inject + VolumeDataFactory volumeFactory; @Override public SnapshotInfo getSnapshot(long snapshotId, DataStore store) { - SnapshotVO snapshot = snapshotDao.findById(snapshotId); - ObjectInDataStoreVO obj = objMap.findObject(snapshotId, DataObjectType.SNAPSHOT, store.getId(), store.getRole()); - SnapshotObject so = new SnapshotObject(snapshot, store); + SnapshotVO snapshot = snapshotDao.findByIdIncludingRemoved(snapshotId); + DataObjectInStore obj = objMap.findObject(snapshot.getUuid(), DataObjectType.SNAPSHOT, store.getUuid(), store.getRole()); + if (obj == null) { + return null; + } + SnapshotObject so = SnapshotObject.getSnapshotObject(snapshot, store); + return so; + } + @Override + public SnapshotInfo getSnapshot(long snapshotId) { + SnapshotVO snapshot = snapshotDao.findByIdIncludingRemoved(snapshotId); + SnapshotObject so = null; + if (snapshot.getState() == Snapshot.State.BackedUp) { + DataStore store = objMap.findStore(snapshot.getUuid(), DataObjectType.SNAPSHOT, DataStoreRole.Image); + so = SnapshotObject.getSnapshotObject(snapshot, store); + } else { + VolumeInfo volume = this.volumeFactory.getVolume(snapshot.getVolumeId()); + so = SnapshotObject.getSnapshotObject(snapshot, volume.getDataStore()); + } + return so; + } + + @Override + public SnapshotInfo getSnapshot(DataObject obj, DataStore store) { + SnapshotVO snapshot = snapshotDao.findByIdIncludingRemoved(obj.getId()); + if (snapshot == null) { + throw new CloudRuntimeException("Can't find snapshot: " + obj.getId()); + } + SnapshotObject so = SnapshotObject.getSnapshotObject(snapshot, store); return so; } } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java index 6ce17973375..a82be6de01d 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java @@ -18,19 +18,54 @@ */ package org.apache.cloudstack.storage.snapshot; +import java.util.Date; + +import javax.inject.Inject; + import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; -import org.apache.cloudstack.storage.snapshot.db.SnapshotVO; +import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; +import org.apache.log4j.Logger; + +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; public class SnapshotObject implements SnapshotInfo { + private static final Logger s_logger = Logger.getLogger(SnapshotObject.class); private SnapshotVO snapshot; private DataStore store; - - public SnapshotObject(SnapshotVO snapshot, DataStore store) { - this.snapshot = snapshot; - this.store = store; + @Inject + protected SnapshotDao snapshotDao; + @Inject + protected VolumeDao volumeDao; + @Inject protected VolumeDataFactory volFactory; + @Inject protected SnapshotStateMachineManager stateMachineMgr; + @Inject + ObjectInDataStoreManager ojbectInStoreMgr; + protected SnapshotObject() { + + } + + protected void configure(SnapshotVO snapshot, DataStore store) { + this.snapshot = snapshot; + this.store = store; + } + + public static SnapshotObject getSnapshotObject(SnapshotVO snapshot, DataStore store) { + SnapshotObject snapObj = ComponentContext.inject(SnapshotObject.class); + snapObj.configure(snapshot, store); + return snapObj; } public DataStore getStore() { @@ -51,50 +86,138 @@ public class SnapshotObject implements SnapshotInfo { @Override public VolumeInfo getBaseVolume() { - // TODO Auto-generated method stub - return null; + return volFactory.getVolume(this.snapshot.getVolumeId()); } @Override public long getId() { - // TODO Auto-generated method stub - return 0; + return this.snapshot.getId(); } @Override public String getUri() { - // TODO Auto-generated method stub - return null; + return this.snapshot.getUuid(); } @Override public DataStore getDataStore() { - // TODO Auto-generated method stub - return null; + return this.store; } @Override public Long getSize() { - // TODO Auto-generated method stub - return 0L; + return this.getSize(); } @Override public DataObjectType getType() { - // TODO Auto-generated method stub - return null; + return DataObjectType.SNAPSHOT; } @Override public DiskFormat getFormat() { - // TODO Auto-generated method stub return null; } @Override public String getUuid() { - // TODO Auto-generated method stub - return null; + return this.snapshot.getUuid(); } + @Override + public void processEvent( + ObjectInDataStoreStateMachine.Event event) { + try { + ojbectInStoreMgr.update(this, event); + } catch (Exception e) { + s_logger.debug("Failed to update state:" + e.toString()); + throw new CloudRuntimeException("Failed to update state: " + e.toString()); + } + } + + @Override + public long getAccountId() { + return this.snapshot.getAccountId(); + } + + @Override + public long getVolumeId() { + return this.snapshot.getVolumeId(); + } + + @Override + public String getPath() { + return this.snapshot.getPath(); + } + + public void setPath(String path) { + this.snapshot.setPath(path); + } + + @Override + public String getName() { + return this.snapshot.getName(); + } + + @Override + public Date getCreated() { + return this.snapshot.getCreated(); + } + + @Override + public Type getRecurringType() { + return this.snapshot.getRecurringType(); + } + + @Override + public State getState() { + return this.snapshot.getState(); + } + + @Override + public HypervisorType getHypervisorType() { + return this.snapshot.getHypervisorType(); + } + + @Override + public boolean isRecursive() { + return this.snapshot.isRecursive(); + } + + @Override + public short getsnapshotType() { + return this.snapshot.getsnapshotType(); + } + + @Override + public long getDomainId() { + return this.snapshot.getDomainId(); + } + + public void setPrevSnapshotId(Long id) { + this.snapshot.setPrevSnapshotId(id); + } + + @Override + public Long getDataCenterId() { + return this.snapshot.getDataCenterId(); + } + + public void processEvent(Snapshot.Event event) + throws NoTransitionException { + stateMachineMgr.processEvent(this.snapshot, event); + } + + @Override + public Long getPrevSnapshotId() { + return this.snapshot.getPrevSnapshotId(); + } + + public void setBackupSnapshotId(String id) { + this.snapshot.setBackupSnapshotId(id); + } + + public String getBackupSnapshotId() { + return this.snapshot.getBackupSnapshotId(); + } } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java index 80b1918665d..1b64fd0cae3 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java @@ -17,10 +17,15 @@ package org.apache.cloudstack.storage.snapshot; import org.apache.cloudstack.engine.cloud.entity.api.SnapshotEntity; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.springframework.stereotype.Component; @Component public class SnapshotServiceImpl implements SnapshotService { + + public SnapshotServiceImpl() { + + } @Override public SnapshotEntity getSnapshotEntity(long snapshotId) { @@ -45,5 +50,7 @@ public class SnapshotServiceImpl implements SnapshotService { // TODO Auto-generated method stub return false; } + + } diff --git a/server/src/com/cloud/baremetal/HttpCallException.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManager.java similarity index 72% rename from server/src/com/cloud/baremetal/HttpCallException.java rename to engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManager.java index d21a37cbb74..c6057704cd8 100644 --- a/server/src/com/cloud/baremetal/HttpCallException.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManager.java @@ -14,15 +14,13 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.baremetal; -import com.cloud.utils.SerialVersionUID; +package org.apache.cloudstack.storage.snapshot; -import com.cloud.exception.CloudException; +import com.cloud.storage.Snapshot.Event; +import com.cloud.storage.SnapshotVO; +import com.cloud.utils.fsm.NoTransitionException; -public class HttpCallException extends CloudException { - private static final long serialVersionUID= SerialVersionUID.HttpCallException; - public HttpCallException(String msg) { - super(msg); - } +public interface SnapshotStateMachineManager { + public void processEvent(SnapshotVO snapshot, Event event) throws NoTransitionException; } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java new file mode 100644 index 00000000000..aa1cf684d7a --- /dev/null +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java @@ -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 org.apache.cloudstack.storage.snapshot; + +import javax.inject.Inject; + +import org.springframework.stereotype.Component; + +import com.cloud.storage.Snapshot; +import com.cloud.storage.Snapshot.Event; +import com.cloud.storage.Snapshot.State; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.listener.SnapshotStateListener; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; + +@Component +public class SnapshotStateMachineManagerImpl implements +SnapshotStateMachineManager { + private StateMachine2 stateMachine = new StateMachine2(); + @Inject + protected SnapshotDao snapshotDao; + public SnapshotStateMachineManagerImpl() { + stateMachine.addTransition(Snapshot.State.Allocated, Event.CreateRequested, Snapshot.State.Creating); + stateMachine.addTransition(Snapshot.State.Creating, Event.OperationSucceeded, Snapshot.State.CreatedOnPrimary); + stateMachine.addTransition(Snapshot.State.Creating, Event.OperationNotPerformed, Snapshot.State.BackedUp); + stateMachine.addTransition(Snapshot.State.Creating, Event.OperationFailed, Snapshot.State.Error); + stateMachine.addTransition(Snapshot.State.CreatedOnPrimary, Event.BackupToSecondary, Snapshot.State.BackingUp); + stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationSucceeded, Snapshot.State.BackedUp); + stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationFailed, Snapshot.State.CreatedOnPrimary); + + stateMachine.registerListener(new SnapshotStateListener()); + } + + public void processEvent(SnapshotVO snapshot, Event event) throws NoTransitionException { + stateMachine.transitTo(snapshot, event, null, snapshotDao); + } +} diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/AncientSnasphotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/AncientSnasphotStrategy.java new file mode 100644 index 00000000000..5cbe2243faa --- /dev/null +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/AncientSnasphotStrategy.java @@ -0,0 +1,608 @@ +// 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.storage.snapshot.strategy; + +import java.util.List; +import java.util.concurrent.ExecutionException; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.framework.async.AsyncCallFuture; +import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; +import org.apache.cloudstack.storage.motion.DataMotionService; +import org.apache.cloudstack.storage.snapshot.SnapshotObject; +import org.apache.cloudstack.storage.snapshot.SnapshotStateMachineManager; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.BackupSnapshotAnswer; +import com.cloud.agent.api.DeleteSnapshotBackupCommand; +import com.cloud.agent.api.to.S3TO; +import com.cloud.agent.api.to.SwiftTO; +import com.cloud.configuration.Resource.ResourceType; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventUtils; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.HostVO; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.resource.ResourceManager; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.StoragePool; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.s3.S3Manager; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.storage.swift.SwiftManager; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.VMSnapshotVO; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; + +@Component +public class AncientSnasphotStrategy implements SnapshotStrategy { + private static final Logger s_logger = Logger.getLogger(AncientSnasphotStrategy.class); + @Inject + protected VolumeDao _volsDao; + @Inject + protected UserVmDao _vmDao; + @Inject + protected StoragePoolDao _storagePoolDao; + @Inject + protected ClusterDao _clusterDao; + @Inject + protected SnapshotDao snapshotDao; + @Inject + private ResourceManager _resourceMgr; + @Inject + protected SnapshotDao _snapshotDao; + @Inject + protected SnapshotManager snapshotMgr; + @Inject + protected VolumeManager volumeMgr; + @Inject + private ConfigurationDao _configDao; + @Inject + protected SnapshotStateMachineManager stateMachineManager; + @Inject + private VolumeDao volumeDao; + @Inject + SnapshotDataFactory snapshotfactory; + @Inject + DataStoreManager dataStoreMgr; + @Inject + DataMotionService motionSrv; + @Inject + ObjectInDataStoreManager objInStoreMgr; + @Inject + VMSnapshotDao _vmSnapshotDao; + + + @Override + public boolean canHandle(SnapshotInfo snapshot) { + return true; + } + + static private class CreateSnapshotContext extends AsyncRpcConext { + final VolumeInfo volume; + final SnapshotInfo snapshot; + final AsyncCallFuture future; + public CreateSnapshotContext(AsyncCompletionCallback callback, VolumeInfo volume, + SnapshotInfo snapshot, + AsyncCallFuture future) { + super(callback); + this.volume = volume; + this.snapshot = snapshot; + this.future = future; + } + } + + static private class DeleteSnapshotContext extends AsyncRpcConext { + final SnapshotInfo snapshot; + final AsyncCallFuture future; + public DeleteSnapshotContext(AsyncCompletionCallback callback, SnapshotInfo snapshot, + AsyncCallFuture future) { + super(callback); + this.snapshot = snapshot; + this.future = future; + } + + } + + static private class CopySnapshotContext extends AsyncRpcConext { + final SnapshotInfo srcSnapshot; + final SnapshotInfo destSnapshot; + final AsyncCallFuture future; + public CopySnapshotContext(AsyncCompletionCallback callback, + SnapshotInfo srcSnapshot, + SnapshotInfo destSnapshot, + AsyncCallFuture future) { + super(callback); + this.srcSnapshot = srcSnapshot; + this.destSnapshot = destSnapshot; + this.future = future; + } + + } + + protected Void createSnapshotAsyncCallback(AsyncCallbackDispatcher callback, + CreateSnapshotContext context) { + CreateCmdResult result = callback.getResult(); + SnapshotObject snapshot = (SnapshotObject)context.snapshot; + VolumeInfo volume = context.volume; + AsyncCallFuture future = context.future; + SnapshotResult snapResult = new SnapshotResult(snapshot); + if (result.isFailed()) { + s_logger.debug("create snapshot " + context.snapshot.getName() + " failed: " + result.getResult()); + try { + snapshot.processEvent(Snapshot.Event.OperationFailed); + } catch (NoTransitionException nte) { + s_logger.debug("Failed to update snapshot state due to " + nte.getMessage()); + } + + + snapResult.setResult(result.getResult()); + future.complete(snapResult); + return null; + } + + try { + SnapshotVO preSnapshotVO = this.snapshotMgr.getParentSnapshot(volume, snapshot); + String preSnapshotPath = null; + if (preSnapshotVO != null) { + preSnapshotPath = preSnapshotVO.getPath(); + } + SnapshotVO snapshotVO = this.snapshotDao.findById(snapshot.getId()); + // The snapshot was successfully created + if (preSnapshotPath != null && preSnapshotPath.equals(result.getPath())) { + // empty snapshot + s_logger.debug("CreateSnapshot: this is empty snapshot "); + + snapshotVO.setPath(preSnapshotPath); + snapshotVO.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId()); + snapshotVO.setSwiftId(preSnapshotVO.getSwiftId()); + snapshotVO.setPrevSnapshotId(preSnapshotVO.getId()); + snapshotVO.setSecHostId(preSnapshotVO.getSecHostId()); + snapshot.processEvent(Snapshot.Event.OperationNotPerformed); + } else { + long preSnapshotId = 0; + + if (preSnapshotVO != null && preSnapshotVO.getBackupSnapshotId() != null) { + preSnapshotId = preSnapshotVO.getId(); + int _deltaSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("snapshot.delta.max"), SnapshotManager.DELTAMAX); + int deltaSnap = _deltaSnapshotMax; + + int i; + for (i = 1; i < deltaSnap; i++) { + String prevBackupUuid = preSnapshotVO.getBackupSnapshotId(); + // previous snapshot doesn't have backup, create a full snapshot + if (prevBackupUuid == null) { + preSnapshotId = 0; + break; + } + long preSSId = preSnapshotVO.getPrevSnapshotId(); + if (preSSId == 0) { + break; + } + preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preSSId); + } + if (i >= deltaSnap) { + preSnapshotId = 0; + } + } + + //If the volume is moved around, backup a full snapshot to secondary storage + if (volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId())) { + preSnapshotId = 0; + //TODO: fix this hack + VolumeVO volumeVO = this.volumeDao.findById(volume.getId()); + volumeVO.setLastPoolId(volume.getPoolId()); + this.volumeDao.update(volume.getId(), volumeVO); + } + + snapshot.setPath(result.getPath()); + snapshot.setPrevSnapshotId(preSnapshotId); + + snapshot.processEvent(Snapshot.Event.OperationSucceeded); + snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(snapshot.getId())); + } + } catch (Exception e) { + s_logger.debug("Failed to create snapshot: ", e); + snapResult.setResult(e.toString()); + try { + snapshot.processEvent(Snapshot.Event.OperationFailed); + } catch (NoTransitionException e1) { + s_logger.debug("Failed to change snapshot state: " + e1.toString()); + } + } + + future.complete(snapResult); + return null; + } + + class SnapshotResult extends CommandResult { + SnapshotInfo snashot; + public SnapshotResult(SnapshotInfo snapshot) { + this.snashot = snapshot; + } + } + + protected SnapshotInfo createSnapshotOnPrimary(VolumeInfo volume, Long snapshotId) { + SnapshotObject snapshot = (SnapshotObject)this.snapshotfactory.getSnapshot(snapshotId); + if (snapshot == null) { + throw new CloudRuntimeException("Can not find snapshot " + snapshotId); + } + + try { + snapshot.processEvent(Snapshot.Event.CreateRequested); + } catch (NoTransitionException nte) { + s_logger.debug("Failed to update snapshot state due to " + nte.getMessage()); + throw new CloudRuntimeException("Failed to update snapshot state due to " + nte.getMessage()); + } + + AsyncCallFuture future = new AsyncCallFuture(); + try { + CreateSnapshotContext context = new CreateSnapshotContext( + null, volume, snapshot, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher + .create(this); + caller.setCallback( + caller.getTarget().createSnapshotAsyncCallback(null, null)) + .setContext(context); + PrimaryDataStoreDriver primaryStore = (PrimaryDataStoreDriver)volume.getDataStore().getDriver(); + primaryStore.takeSnapshot(snapshot, caller); + } catch (Exception e) { + s_logger.debug("Failed to take snapshot: " + snapshot.getId(), e); + try { + snapshot.processEvent(Snapshot.Event.OperationFailed); + } catch (NoTransitionException e1) { + s_logger.debug("Failed to change state for event: OperationFailed" , e); + } + throw new CloudRuntimeException("Failed to take snapshot" + snapshot.getId()); + } + + SnapshotResult result; + + try { + result = future.get(); + if (result.isFailed()) { + s_logger.debug("Failed to create snapshot:" + result.getResult()); + throw new CloudRuntimeException(result.getResult()); + } + return result.snashot; + } catch (InterruptedException e) { + s_logger.debug("Failed to create snapshot", e); + throw new CloudRuntimeException("Failed to create snapshot", e); + } catch (ExecutionException e) { + s_logger.debug("Failed to create snapshot", e); + throw new CloudRuntimeException("Failed to create snapshot", e); + } + + } + + private boolean hostSupportSnapsthot(HostVO host) { + if (host.getHypervisorType() != HypervisorType.KVM) { + return true; + } + // Determine host capabilities + String caps = host.getCapabilities(); + + if (caps != null) { + String[] tokens = caps.split(","); + for (String token : tokens) { + if (token.contains("snapshot")) { + return true; + } + } + } + return false; + } + + protected boolean supportedByHypervisor(VolumeInfo volume) { + if (volume.getHypervisorType().equals(HypervisorType.KVM)) { + StoragePool storagePool = (StoragePool)volume.getDataStore(); + ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId()); + List hosts = _resourceMgr.listAllHostsInCluster(cluster.getId()); + if (hosts != null && !hosts.isEmpty()) { + HostVO host = hosts.get(0); + if (!hostSupportSnapsthot(host)) { + throw new CloudRuntimeException("KVM Snapshot is not supported on cluster: " + host.getId()); + } + } + } + + // if volume is attached to a vm in destroyed or expunging state; disallow + if (volume.getInstanceId() != null) { + UserVmVO userVm = _vmDao.findById(volume.getInstanceId()); + if (userVm != null) { + if (userVm.getState().equals(State.Destroyed) || userVm.getState().equals(State.Expunging)) { + throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volume.getId() + " is associated with vm:" + userVm.getInstanceName() + " is in " + + userVm.getState().toString() + " state"); + } + + if(userVm.getHypervisorType() == HypervisorType.VMware || userVm.getHypervisorType() == HypervisorType.KVM) { + List activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp); + 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 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"); + } + } + } + + return true; + } + + @Override + public SnapshotInfo takeSnapshot(VolumeInfo volume, Long snapshotId) { + + supportedByHypervisor(volume); + + SnapshotInfo snapshot = createSnapshotOnPrimary(volume, snapshotId); + return snapshot; + } + + @Override + public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) { + SnapshotObject snapObj = (SnapshotObject)snapshot; + AsyncCallFuture future = new AsyncCallFuture(); + SnapshotResult result = new SnapshotResult(snapshot); + try { + + snapObj.processEvent(Snapshot.Event.BackupToSecondary); + + ZoneScope scope = new ZoneScope(snapshot.getDataCenterId()); + List stores = this.dataStoreMgr.getImageStores(scope); + if (stores.size() != 1) { + throw new CloudRuntimeException("find out more than one image stores"); + } + + DataStore imageStore = stores.get(0); + SnapshotInfo snapshotOnImageStore = (SnapshotInfo)imageStore.create(snapshot); + + snapshotOnImageStore.processEvent(Event.CreateOnlyRequested); + CopySnapshotContext context = new CopySnapshotContext(null, snapshot, + snapshotOnImageStore, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher + .create(this); + caller.setCallback( + caller.getTarget().copySnapshotAsyncCallback(null, null)) + .setContext(context); + this.motionSrv.copyAsync(snapshot, snapshotOnImageStore, caller); + } catch (Exception e) { + s_logger.debug("Failed to copy snapshot", e); + result.setResult("Failed to copy snapshot:" +e.toString()); + try { + snapObj.processEvent(Snapshot.Event.OperationFailed); + } catch (NoTransitionException e1) { + s_logger.debug("Failed to change state: " + e1.toString()); + } + future.complete(result); + } + + try { + SnapshotResult res = future.get(); + SnapshotInfo destSnapshot = res.snashot; + return destSnapshot; + } catch (InterruptedException e) { + s_logger.debug("failed copy snapshot", e); + throw new CloudRuntimeException("Failed to copy snapshot" , e); + } catch (ExecutionException e) { + s_logger.debug("Failed to copy snapshot", e); + throw new CloudRuntimeException("Failed to copy snapshot" , e); + } + + } + + protected Void copySnapshotAsyncCallback(AsyncCallbackDispatcher callback, + CopySnapshotContext context) { + CopyCommandResult result = callback.getResult(); + SnapshotInfo destSnapshot = context.destSnapshot; + SnapshotObject srcSnapshot = (SnapshotObject)context.srcSnapshot; + AsyncCallFuture future = context.future; + SnapshotResult snapResult = new SnapshotResult(destSnapshot); + if (result.isFailed()) { + snapResult.setResult(result.getResult()); + future.complete(snapResult); + return null; + } + + try { + BackupSnapshotAnswer answer = (BackupSnapshotAnswer)result.getAnswer(); + + DataObjectInStore dataInStore = objInStoreMgr.findObject(destSnapshot, destSnapshot.getDataStore()); + dataInStore.setInstallPath(answer.getBackupSnapshotName()); + objInStoreMgr.update(destSnapshot, Event.OperationSuccessed); + + srcSnapshot.processEvent(Snapshot.Event.OperationSucceeded); + snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(destSnapshot.getId())); + future.complete(snapResult); + } catch (Exception e) { + s_logger.debug("Failed to update snapshot state", e); + snapResult.setResult(e.toString()); + future.complete(snapResult); + } + return null; + } + + @DB + protected boolean destroySnapshotBackUp(SnapshotVO snapshot) { + DataStore store = objInStoreMgr.findStore(snapshot.getUuid(), DataObjectType.SNAPSHOT, DataStoreRole.Image); + if (store == null) { + s_logger.debug("Can't find snapshot" + snapshot.getId() + " backed up into image store"); + return false; + } + + try { + SnapshotInfo snapshotInfo = this.snapshotfactory.getSnapshot(snapshot.getId(), store); + snapshotInfo.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested); + + AsyncCallFuture future = new AsyncCallFuture(); + DeleteSnapshotContext context = new DeleteSnapshotContext(null, + snapshotInfo, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher + .create(this); + caller.setCallback( + caller.getTarget().deleteSnapshotCallback(null, null)) + .setContext(context); + + store.getDriver().deleteAsync(snapshotInfo, caller); + + SnapshotResult result = future.get(); + if (result.isFailed()) { + s_logger.debug("Failed to delete snapsoht: " + result.getResult()); + } + return result.isSuccess(); + } catch (Exception e) { + s_logger.debug("Failed to delete snapshot", e); + return false; + } + } + + protected Void deleteSnapshotCallback(AsyncCallbackDispatcher callback, + DeleteSnapshotContext context) { + CommandResult result = callback.getResult(); + AsyncCallFuture future = context.future; + SnapshotInfo snapshot = context.snapshot; + if (result.isFailed()) { + s_logger.debug("delete snapshot failed" + result.getResult()); + snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + SnapshotResult res = new SnapshotResult(context.snapshot); + future.complete(res); + return null; + } + snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed); + SnapshotResult res = new SnapshotResult(context.snapshot); + future.complete(res); + return null; + } + + @Override + public boolean deleteSnapshot(SnapshotInfo snapInfo) { + Long snapshotId = snapInfo.getId(); + SnapshotObject snapshot = (SnapshotObject)snapInfo; + + if (!Snapshot.State.BackedUp.equals(snapshot.getState())) { + throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status"); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId); + } + SnapshotVO lastSnapshot = null; + if (snapshot.getBackupSnapshotId() != null) { + List snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId()); + if (snaps != null && snaps.size() > 1) { + snapshot.setBackupSnapshotId(null); + SnapshotVO snapshotVO = this._snapshotDao.findById(snapshotId); + _snapshotDao.update(snapshot.getId(), snapshotVO); + } + } + + _snapshotDao.remove(snapshotId); + + long lastId = snapshotId; + boolean destroy = false; + while (true) { + lastSnapshot = _snapshotDao.findNextSnapshot(lastId); + if (lastSnapshot == null) { + // if all snapshots after this snapshot in this chain are removed, remove those snapshots. + destroy = true; + break; + } + if (lastSnapshot.getRemoved() == null) { + // if there is one child not removed, then can not remove back up snapshot. + break; + } + lastId = lastSnapshot.getId(); + } + if (destroy) { + lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId); + while (lastSnapshot.getRemoved() != null) { + String BackupSnapshotId = lastSnapshot.getBackupSnapshotId(); + if (BackupSnapshotId != null) { + List snaps = _snapshotDao.listByBackupUuid(lastSnapshot.getVolumeId(), BackupSnapshotId); + if (snaps != null && snaps.size() > 1) { + lastSnapshot.setBackupSnapshotId(null); + _snapshotDao.update(lastSnapshot.getId(), lastSnapshot); + } else { + if (destroySnapshotBackUp(lastSnapshot)) { + + } else { + s_logger.debug("Destroying snapshot backup failed " + lastSnapshot); + break; + } + } + } + lastId = lastSnapshot.getPrevSnapshotId(); + if (lastId == 0) { + break; + } + lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId); + } + } + return true; + + } + + @Override + public boolean revertSnapshot(SnapshotInfo snapshot) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/StorageBasedSnapshot.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/StorageBasedSnapshot.java deleted file mode 100644 index fa9c5aeaa08..00000000000 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/StorageBasedSnapshot.java +++ /dev/null @@ -1,42 +0,0 @@ -// 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.storage.snapshot.strategy; - -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.snapshot.SnapshotStrategy; - -public class StorageBasedSnapshot implements SnapshotStrategy { - - @Override - public boolean takeSnapshot(SnapshotInfo snapshot) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean revertSnapshot(SnapshotInfo snapshot) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean deleteSnapshot(SnapshotInfo snapshot) { - // TODO Auto-generated method stub - return false; - } - -} diff --git a/engine/storage/snapshot/test/resource/SnapshotManagerTestContext.xml b/engine/storage/snapshot/test/resource/SnapshotManagerTestContext.xml new file mode 100644 index 00000000000..d99c2e2dbac --- /dev/null +++ b/engine/storage/snapshot/test/resource/SnapshotManagerTestContext.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/storage/snapshot/test/src/SnapshotDataFactoryTest.java b/engine/storage/snapshot/test/src/SnapshotDataFactoryTest.java new file mode 100644 index 00000000000..e722ab55c70 --- /dev/null +++ b/engine/storage/snapshot/test/src/SnapshotDataFactoryTest.java @@ -0,0 +1,50 @@ +/* + * 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 src; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.utils.component.ComponentContext; + +import junit.framework.TestCase; + +//@RunWith(SpringJUnit4ClassRunner.class) +//@ContextConfiguration(locations = "classpath:/SnapshotManagerTestContext.xml") +public class SnapshotDataFactoryTest extends TestCase { + //@Inject SnapshotDataFactory snapshotFactory; + + @Before + public void setup() throws Exception { + //ComponentContext.initComponentsLifeCycle(); + + } + + @Test + public void testGestSnapshot() { + //snapshotFactory.getSnapshot(snapshotId); + } + +} diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java index 657d32c7877..218f9013a17 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java @@ -24,14 +24,14 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcConext; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; import org.apache.cloudstack.storage.motion.DataMotionService; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -52,7 +52,7 @@ public class DataObjectManagerImpl implements DataObjectManager { protected DataObject waitingForCreated(DataObject dataObj, DataStore dataStore) { long retries = this.waitingRetries; - ObjectInDataStoreVO obj = null; + DataObjectInStore obj = null; do { try { Thread.sleep(waitingTime); @@ -61,8 +61,8 @@ public class DataObjectManagerImpl implements DataObjectManager { throw new CloudRuntimeException("sleep interrupted", e); } - obj = objectInDataStoreMgr.findObject(dataObj.getId(), - dataObj.getType(), dataStore.getId(), dataStore.getRole()); + obj = objectInDataStoreMgr.findObject(dataObj, + dataStore); if (obj == null) { s_logger.debug("can't find object in db, maybe it's cleaned up already, exit waiting"); break; @@ -92,11 +92,10 @@ public class DataObjectManagerImpl implements DataObjectManager { } @Override - public void createAsync(DataObject data, DataStore store, + public void createAsync(DataObject data, DataStore store, AsyncCompletionCallback callback, boolean noCopy) { - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - data.getId(), data.getType(), store.getId(), - store.getRole()); + DataObjectInStore obj = objectInDataStoreMgr.findObject( + data, store); DataObject objInStore = null; boolean freshNewTemplate = false; if (obj == null) { @@ -105,8 +104,8 @@ public class DataObjectManagerImpl implements DataObjectManager { data, store); freshNewTemplate = true; } catch (Throwable e) { - obj = objectInDataStoreMgr.findObject(data.getId(), - data.getType(), store.getId(), store.getRole()); + obj = objectInDataStoreMgr.findObject(data, + store); if (obj == null) { CreateCmdResult result = new CreateCmdResult( null, null); @@ -184,20 +183,12 @@ public class DataObjectManagerImpl implements DataObjectManager { return null; } - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - objInStrore.getId(), objInStrore - .getType(), objInStrore.getDataStore() - .getId(), objInStrore.getDataStore() - .getRole()); - - obj.setInstallPath(result.getPath()); - obj.setSize(result.getSize()); try { - objectInDataStoreMgr.update(obj, + objectInDataStoreMgr.update(objInStrore, ObjectInDataStoreStateMachine.Event.OperationSuccessed); } catch (NoTransitionException e) { try { - objectInDataStoreMgr.update(obj, + objectInDataStoreMgr.update(objInStrore, ObjectInDataStoreStateMachine.Event.OperationFailed); } catch (NoTransitionException e1) { s_logger.debug("failed to change state", e1); @@ -259,14 +250,10 @@ public class DataObjectManagerImpl implements DataObjectManager { CopyContext context) { CopyCommandResult result = callback.getResult(); DataObject destObj = context.destObj; - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - destObj.getId(), destObj - .getType(), destObj.getDataStore() - .getId(), destObj.getDataStore() - .getRole()); + if (result.isFailed()) { try { - objectInDataStoreMgr.update(obj, Event.OperationFailed); + objectInDataStoreMgr.update(destObj, Event.OperationFailed); } catch (NoTransitionException e) { s_logger.debug("Failed to update copying state", e); } @@ -276,10 +263,8 @@ public class DataObjectManagerImpl implements DataObjectManager { context.getParentCallback().complete(res); } - obj.setInstallPath(result.getPath()); - try { - objectInDataStoreMgr.update(obj, + objectInDataStoreMgr.update(destObj, ObjectInDataStoreStateMachine.Event.OperationSuccessed); } catch (NoTransitionException e) { s_logger.debug("Failed to update copying state: ", e); @@ -311,11 +296,8 @@ public class DataObjectManagerImpl implements DataObjectManager { @Override public void deleteAsync(DataObject data, AsyncCompletionCallback callback) { - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - data.getId(), data.getType(), data.getDataStore().getId(), - data.getDataStore().getRole()); try { - objectInDataStoreMgr.update(obj, Event.DestroyRequested); + objectInDataStoreMgr.update(data, Event.DestroyRequested); } catch (NoTransitionException e) { s_logger.debug("destroy failed", e); CreateCmdResult res = new CreateCmdResult( @@ -338,23 +320,18 @@ public class DataObjectManagerImpl implements DataObjectManager { protected Void deleteAsynCallback(AsyncCallbackDispatcher callback, DeleteContext context) { DataObject destObj = context.obj; - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - destObj.getId(), destObj - .getType(), destObj.getDataStore() - .getId(), destObj.getDataStore() - .getRole()); - + CommandResult res = callback.getResult(); if (res.isFailed()) { try { - objectInDataStoreMgr.update(obj, Event.OperationFailed); + objectInDataStoreMgr.update(destObj, Event.OperationFailed); } catch (NoTransitionException e) { s_logger.debug("delete failed", e); } } else { try { - objectInDataStoreMgr.update(obj, Event.OperationSuccessed); + objectInDataStoreMgr.update(destObj, Event.OperationSuccessed); } catch (NoTransitionException e) { s_logger.debug("delete failed", e); } @@ -366,9 +343,8 @@ public class DataObjectManagerImpl implements DataObjectManager { @Override public DataObject createInternalStateOnly(DataObject data, DataStore store) { - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - data.getId(), data.getType(), store.getId(), - store.getRole()); + DataObjectInStore obj = objectInDataStoreMgr.findObject( + data, store); DataObject objInStore = null; if (obj == null) { objInStore = objectInDataStoreMgr.create( @@ -391,12 +367,6 @@ public class DataObjectManagerImpl implements DataObjectManager { @Override public void update(DataObject data, String path, Long size) { - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - data.getId(), data.getType(), data.getDataStore().getId(), - data.getDataStore().getRole()); - - obj.setInstallPath(path); - obj.setSize(size); - objectInDataStoreMgr.update(obj); + throw new CloudRuntimeException("not implemented"); } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java index f857ac5db1a..a2fd08d1e8f 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java @@ -18,12 +18,15 @@ */ package org.apache.cloudstack.storage.datastore; +import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; import org.springframework.stereotype.Component; @@ -50,5 +53,22 @@ public class DataStoreManagerImpl implements DataStoreManager { String providerUuid) { return null; } + @Override + public DataStore getDataStore(String uuid, DataStoreRole role) { + if (role == DataStoreRole.Primary) { + return primaryStorMgr.getPrimaryDataStore(uuid); + } else if (role == DataStoreRole.Image) { + return imageDataStoreMgr.getImageDataStore(uuid); + } + throw new CloudRuntimeException("un recognized type" + role); + } + @Override + public List getImageStores(Scope scope) { + return imageDataStoreMgr.getList(); + } + @Override + public DataStore getPrimaryDataStore(long storeId) { + return primaryStorMgr.getPrimaryDataStore(storeId); + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java index e707de6b8bd..d170f5c707a 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java @@ -17,26 +17,20 @@ package org.apache.cloudstack.storage.datastore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import com.cloud.utils.fsm.NoTransitionException; public interface ObjectInDataStoreManager { public DataObject create(DataObject template, DataStore dataStore); - public VolumeInfo create(VolumeInfo volume, DataStore dataStore); - public SnapshotInfo create(SnapshotInfo snapshot, DataStore dataStore); - public ObjectInDataStoreVO findObject(long objectId, DataObjectType type, - long dataStoreId, DataStoreRole role); public DataObject get(DataObject dataObj, DataStore store); public boolean update(DataObject vo, Event event) throws NoTransitionException; - boolean update(ObjectInDataStoreVO obj, Event event) - throws NoTransitionException; - - boolean update(ObjectInDataStoreVO obj); + DataObjectInStore findObject(String uuid, DataObjectType type, + String dataStoreUuid, DataStoreRole role); + DataObjectInStore findObject(DataObject obj, DataStore store); + DataStore findStore(String objUuid, DataObjectType type, DataStoreRole role); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java index 7eb4932348f..87ba1d216c5 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java @@ -19,19 +19,25 @@ package org.apache.cloudstack.storage.datastore; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.storage.db.ObjectInDataStoreDao; import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.ImageDataFactory; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.State; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VolumeHostDao; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria2; import com.cloud.utils.db.SearchCriteriaService; @@ -41,16 +47,28 @@ import com.cloud.utils.fsm.StateMachine2; @Component public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager { + private static final Logger s_logger = Logger + .getLogger(ObjectInDataStoreManagerImpl.class); @Inject ImageDataFactory imageFactory; @Inject + DataStoreManager storeMgr; + @Inject VolumeDataFactory volumeFactory; @Inject ObjectInDataStoreDao objectDataStoreDao; - protected StateMachine2 stateMachines; + @Inject + VolumeHostDao volumeHostDao; + @Inject + VMTemplateHostDao templateHostDao; + @Inject + VMTemplatePoolDao templatePoolDao; + @Inject + SnapshotDataFactory snapshotFactory; + protected StateMachine2 stateMachines; public ObjectInDataStoreManagerImpl() { - stateMachines = new StateMachine2(); + stateMachines = new StateMachine2(); stateMachines.addTransition(State.Allocated, Event.CreateRequested, State.Creating); stateMachines.addTransition(State.Creating, Event.OperationSuccessed, @@ -76,101 +94,122 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager { stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested, State.Creating2); stateMachines.addTransition(State.Creating2, Event.OperationFailed, - State.Failed); + State.Allocated); stateMachines.addTransition(State.Creating2, Event.OperationSuccessed, State.Ready); } @Override public DataObject create(DataObject obj, DataStore dataStore) { - - ObjectInDataStoreVO vo = new ObjectInDataStoreVO(); - vo.setDataStoreId(dataStore.getId()); - vo.setDataStoreRole(dataStore.getRole()); - vo.setObjectId(obj.getId()); - vo.setSize(obj.getSize()); - - vo.setObjectType(obj.getType()); - vo = objectDataStoreDao.persist(vo); + if (obj.getType() == DataObjectType.TEMPLATE && dataStore.getRole() == DataStoreRole.Primary) { + VMTemplateStoragePoolVO vo = new VMTemplateStoragePoolVO(dataStore.getId(), obj.getId()); + vo = templatePoolDao.persist(vo); + } else { + ObjectInDataStoreVO vo = new ObjectInDataStoreVO(); + vo.setDataStoreRole(dataStore.getRole()); + vo.setDataStoreUuid(dataStore.getUuid()); + vo.setObjectType(obj.getType()); + vo.setObjectUuid(obj.getUuid()); + vo = objectDataStoreDao.persist(vo); + } if (obj.getType() == DataObjectType.TEMPLATE) { - return imageFactory.getTemplate(obj.getId(), dataStore); + return imageFactory.getTemplate(obj, dataStore); } else if (obj.getType() == DataObjectType.VOLUME) { - return volumeFactory.getVolume(obj.getId(), dataStore); + return volumeFactory.getVolume(obj, dataStore); + } else if (obj.getType() == DataObjectType.SNAPSHOT) { + return snapshotFactory.getSnapshot(obj, dataStore); } throw new CloudRuntimeException("unknown type"); } - - @Override - public VolumeInfo create(VolumeInfo volume, DataStore dataStore) { - ObjectInDataStoreVO vo = new ObjectInDataStoreVO(); - vo.setDataStoreId(dataStore.getId()); - vo.setDataStoreRole(dataStore.getRole()); - vo.setObjectId(volume.getId()); - vo.setObjectType(volume.getType()); - vo = objectDataStoreDao.persist(vo); - - return volumeFactory.getVolume(volume.getId(), dataStore); - } - - @Override - public SnapshotInfo create(SnapshotInfo snapshot, DataStore dataStore) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ObjectInDataStoreVO findObject(long objectId, DataObjectType type, - long dataStoreId, DataStoreRole role) { - SearchCriteriaService sc = SearchCriteria2 - .create(ObjectInDataStoreVO.class); - sc.addAnd(sc.getEntity().getObjectId(), Op.EQ, objectId); - sc.addAnd(sc.getEntity().getDataStoreId(), Op.EQ, dataStoreId); - sc.addAnd(sc.getEntity().getObjectType(), Op.EQ, type); - sc.addAnd(sc.getEntity().getDataStoreRole(), Op.EQ, role); - sc.addAnd(sc.getEntity().getState(), Op.NIN, - ObjectInDataStoreStateMachine.State.Destroyed, - ObjectInDataStoreStateMachine.State.Failed); - ObjectInDataStoreVO objectStoreVO = sc.find(); - return objectStoreVO; - - } - + @Override public boolean update(DataObject data, Event event) throws NoTransitionException { - ObjectInDataStoreVO obj = this.findObject(data.getId(), data.getType(), - data.getDataStore().getId(), data.getDataStore().getRole()); + DataObjectInStore obj = this.findObject(data, data.getDataStore()); if (obj == null) { throw new CloudRuntimeException( "can't find mapping in ObjectInDataStore table for: " + data); } - return this.stateMachines.transitTo(obj, event, null, - objectDataStoreDao); - - } - - @Override - public boolean update(ObjectInDataStoreVO obj, Event event) - throws NoTransitionException { - return this.stateMachines.transitTo(obj, event, null, - objectDataStoreDao); - + + if (data.getType() == DataObjectType.TEMPLATE && data.getDataStore().getRole() == DataStoreRole.Primary) { + try { + this.stateMachines.transitTo(obj, event, null, + templatePoolDao); + } catch (NoTransitionException e) { + if (event == Event.CreateOnlyRequested || event == Event.OperationSuccessed) { + s_logger.debug("allow muliple create requests"); + } else { + throw e; + } + } + } else { + this.stateMachines.transitTo(obj, event, null, objectDataStoreDao); + } + return true; } @Override public DataObject get(DataObject dataObj, DataStore store) { if (dataObj.getType() == DataObjectType.TEMPLATE) { - return imageFactory.getTemplate(dataObj.getId(), store); + return imageFactory.getTemplate(dataObj, store); } else if (dataObj.getType() == DataObjectType.VOLUME) { - return volumeFactory.getVolume(dataObj.getId(), store); + return volumeFactory.getVolume(dataObj, store); } throw new CloudRuntimeException("unknown type"); } @Override - public boolean update(ObjectInDataStoreVO obj) { - return objectDataStoreDao.update(obj.getId(), obj); + public DataObjectInStore findObject(DataObject obj, DataStore store) { + DataObjectInStore vo = null; + SearchCriteriaService sc = SearchCriteria2.create(ObjectInDataStoreVO.class); + + if (store.getRole() == DataStoreRole.Image) { + sc.addAnd(sc.getEntity().getDataStoreUuid(), Op.EQ, store.getUuid()); + sc.addAnd(sc.getEntity().getDataStoreRole(), Op.EQ, store.getRole()); + sc.addAnd(sc.getEntity().getObjectUuid(), Op.EQ, obj.getUuid()); + sc.addAnd(sc.getEntity().getObjectType(), Op.EQ, obj.getType()); + vo = sc.find(); + } else if (obj.getType() == DataObjectType.TEMPLATE && store.getRole() == DataStoreRole.Primary) { + vo = templatePoolDao.findByPoolTemplate(store.getId(), obj.getId()); + } else { + s_logger.debug("unknown type: " + obj.getType() + " " + store.getRole()); + throw new CloudRuntimeException("unknown type"); + } + return vo; } + + @Override + public DataObjectInStore findObject(String uuid, DataObjectType type, + String dataStoreUuid, DataStoreRole role) { + DataObjectInStore vo = null; + SearchCriteriaService sc = SearchCriteria2.create(ObjectInDataStoreVO.class); + + if (role == DataStoreRole.Image) { + sc.addAnd(sc.getEntity().getDataStoreUuid(), Op.EQ, dataStoreUuid); + sc.addAnd(sc.getEntity().getDataStoreRole(), Op.EQ, role); + sc.addAnd(sc.getEntity().getObjectUuid(), Op.EQ, uuid); + sc.addAnd(sc.getEntity().getObjectType(), Op.EQ, type); + vo = sc.find(); + } + return vo; + } + + @Override + public DataStore findStore(String objUuid, DataObjectType type, DataStoreRole role) { + DataStore store = null; + if (role == DataStoreRole.Image) { + SearchCriteriaService sc = SearchCriteria2.create(ObjectInDataStoreVO.class); + sc.addAnd(sc.getEntity().getDataStoreRole(), Op.EQ, role); + sc.addAnd(sc.getEntity().getObjectUuid(), Op.EQ, objUuid); + sc.addAnd(sc.getEntity().getObjectType(), Op.EQ, type); + ObjectInDataStoreVO vo = sc.find(); + if (vo != null) { + store = this.storeMgr.getDataStore(vo.getDataStoreUuid(), vo.getDataStoreRole()); + } + } + return store; + } + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java index a6ba9bc1f60..fdaaace49d7 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java @@ -20,31 +20,19 @@ package org.apache.cloudstack.storage.datastore; import java.util.List; -import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; -import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; -import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; public interface PrimaryDataStore extends DataStore, PrimaryDataStoreInfo { VolumeInfo getVolume(long id); List getVolumes(); -/* void deleteVolumeAsync(VolumeInfo volume, AsyncCompletionCallback callback); - - void createVolumeAsync(VolumeInfo vo, VolumeDiskType diskType, AsyncCompletionCallback callback); - - void createVoluemFromBaseImageAsync(VolumeInfo volume, TemplateInfo templateStore, AsyncCompletionCallback callback); - */ - boolean exists(DataObject data); TemplateInfo getTemplate(long templateId); @@ -53,13 +41,4 @@ public interface PrimaryDataStore extends DataStore, PrimaryDataStoreInfo { DiskFormat getDefaultDiskType(); - -/* void takeSnapshot(SnapshotInfo snapshot, - AsyncCompletionCallback callback); - - void revertSnapshot(SnapshotInfo snapshot, - AsyncCompletionCallback callback); - - void deleteSnapshot(SnapshotInfo snapshot, - AsyncCompletionCallback callback);*/ } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java index 0ac57f445aa..e70f803ee81 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java @@ -26,8 +26,8 @@ import java.util.Map; import org.apache.cloudstack.engine.datacenter.entity.api.StorageEntity; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; -import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePoolStatus; public class PrimaryDataStoreEntityImpl implements StorageEntity { private PrimaryDataStoreInfo dataStore; @@ -132,7 +132,8 @@ public class PrimaryDataStoreEntityImpl implements StorageEntity { @Override public State getState() { - return this.dataStore.getManagedState(); + //return this.dataStore.getManagedState(); + return null; } @Override @@ -229,13 +230,7 @@ public class PrimaryDataStoreEntityImpl implements StorageEntity { return null; } - @Override - public String getStorageProvider() { - // TODO Auto-generated method stub - return null; - } - @Override public String getStorageType() { // TODO Auto-generated method stub return null; @@ -247,4 +242,16 @@ public class PrimaryDataStoreEntityImpl implements StorageEntity { } + @Override + public Long getStorageProviderId() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isInMaintenance() { + // TODO Auto-generated method stub + return false; + } + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreProviderManager.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreProviderManager.java index a60ec7a6e65..d1c26e1a272 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreProviderManager.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreProviderManager.java @@ -18,11 +18,14 @@ */ package org.apache.cloudstack.storage.datastore; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; public interface PrimaryDataStoreProviderManager { public PrimaryDataStore getPrimaryDataStore(long dataStoreId); + public PrimaryDataStore getPrimaryDataStore(String uuid); boolean registerDriver(String uuid, PrimaryDataStoreDriver driver); + boolean registerHostListener(String uuid, HypervisorHostListener listener); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java index 3634b52908a..96d2da357f5 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java @@ -26,14 +26,19 @@ import java.util.UUID; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; import org.apache.cloudstack.storage.datastore.db.DataStoreProviderDao; import org.apache.cloudstack.storage.datastore.db.DataStoreProviderVO; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.utils.component.ManagerBase; @Component public class DataStoreProviderManagerImpl extends ManagerBase implements DataStoreProviderManager { + private static final Logger s_logger = Logger + .getLogger(DataStoreProviderManagerImpl.class); @Inject List providers; @Inject @@ -59,8 +64,8 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto @Override public boolean configure(String name, Map params) throws ConfigurationException { - -/* + Map copyParams = new HashMap(params); + //TODO: hold global lock List providerVos = providerDao.listAll(); for (DataStoreProvider provider : providers) { @@ -83,12 +88,20 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto } else { uuid = providerVO.getUuid(); } - params.put("uuid", uuid); - params.put("id", providerVO.getId()); - provider.configure(params); + copyParams.put("uuid", uuid); + copyParams.put("id", providerVO.getId()); providerMap.put(uuid, provider); + try { + boolean registrationResult = provider.configure(copyParams); + if (!registrationResult) { + providerMap.remove(uuid); + } + } catch(Exception e) { + s_logger.debug("configure provider failed", e); + providerMap.remove(uuid); + } } - */ + return true; } @@ -97,4 +110,9 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto DataStoreProviderVO provider = providerDao.findById(id); return providerMap.get(provider.getUuid()); } + + @Override + public DataStoreProvider getDefaultPrimaryDataStoreProvider() { + return this.getDataStoreProvider("ancient primary data store provider"); + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/ImageDataStoreProvider.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/ImageDataStoreProvider.java index 502158cdaaa..d44a40e971f 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/ImageDataStoreProvider.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/ImageDataStoreProvider.java @@ -18,6 +18,8 @@ */ package org.apache.cloudstack.storage.datastore.provider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; + public interface ImageDataStoreProvider extends DataStoreProvider { } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProvider.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProvider.java index dbca549212c..fdf5958f1ab 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProvider.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProvider.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.storage.datastore.provider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; + public interface PrimaryDataStoreProvider extends DataStoreProvider { } diff --git a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDao.java b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDao.java index 08f9182f237..fb7dec0fa41 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDao.java +++ b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDao.java @@ -16,10 +16,12 @@ // under the License. package org.apache.cloudstack.storage.db; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.utils.db.GenericDao; import com.cloud.utils.fsm.StateDao; -public interface ObjectInDataStoreDao extends GenericDao, StateDao { +public interface ObjectInDataStoreDao extends GenericDao, StateDao { } diff --git a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java index 4a5a913adca..50dc984d49b 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java @@ -20,17 +20,17 @@ import java.util.Map; import javax.naming.ConfigurationException; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.State; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.storage.VolumeVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.UpdateBuilder; @Component public class ObjectInDataStoreDaoImpl extends GenericDaoBase implements ObjectInDataStoreDao { @@ -47,7 +47,8 @@ public class ObjectInDataStoreDaoImpl extends GenericDaoBase { +public class ObjectInDataStoreVO implements StateObject, DataObjectInStore { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) long id; - @Column(name = "datastore_id") - private long dataStoreId; + @Column(name = "datastore_uuid") + private String dataStoreUuid; @Column(name = "datastore_role") @Enumerated(EnumType.STRING) private DataStoreRole dataStoreRole; - @Column(name = "object_id") - long objectId; + @Column(name = "object_uuid") + String objectUuid; @Column(name = "object_type") @Enumerated(EnumType.STRING) @@ -74,6 +76,15 @@ public class ObjectInDataStoreVO implements StateObject params) { - ImageDataStoreVO store = imageStoreDao.findByUuid(params.get("uuid")); + public ImageDataStoreVO createImageDataStore(Map params) { + ImageDataStoreVO store = imageStoreDao.findByUuid((String)params.get("uuid")); if (store != null) { - throw new CloudRuntimeException("duplicate uuid"); + return store; } store = new ImageDataStoreVO(); - store.setName(params.get("name")); - store.setProtocol(params.get("protocol")); - store.setProvider(Long.parseLong(params.get("provider"))); - store.setScope(Enum.valueOf(ScopeType.class, params.get("scope"))); - store.setUuid(params.get("uuid")); + store.setName((String)params.get("name")); + store.setProtocol((String)params.get("protocol")); + store.setProvider((Long)params.get("provider")); + store.setScope((ScopeType)params.get("scope")); + store.setUuid((String)params.get("uuid")); store = imageStoreDao.persist(store); return store; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageDataStoreManager.java b/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageDataStoreManager.java index 2bd361f05e9..b6d84cdcef2 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageDataStoreManager.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageDataStoreManager.java @@ -18,9 +18,14 @@ */ package org.apache.cloudstack.storage.image.datastore; +import java.util.List; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; public interface ImageDataStoreManager { ImageDataStore getImageDataStore(long dataStoreId); + ImageDataStore getImageDataStore(String uuid); + List getList(); boolean registerDriver(String uuid, ImageDataStoreDriver driver); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java deleted file mode 100644 index b5db164055d..00000000000 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.storage.image.db; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateState; - -import com.cloud.domain.DomainVO; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.projects.Project.ListProjectResourcesCriteria; -import com.cloud.template.VirtualMachineTemplate.TemplateFilter; -import com.cloud.user.Account; -import com.cloud.utils.Pair; -import com.cloud.utils.db.GenericDao; -import com.cloud.utils.fsm.StateDao; - -public interface ImageDataDao extends GenericDao, StateDao { - public List listByPublic(); - - public ImageDataVO findByName(String templateName); - - public ImageDataVO findByTemplateName(String templateName); - - // public void update(ImageDataVO template); - - public List listAllSystemVMTemplates(); - - public List listDefaultBuiltinTemplates(); - - public String getRoutingTemplateUniqueName(); - - public List findIsosByIdAndPath(Long domainId, Long accountId, String path); - - public List listReadyTemplates(); - - public List listByAccountId(long accountId); - - public Set> searchTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, - Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, - ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags); - - public Set> searchSwiftTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, - Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, Map tags); - - public long addTemplateToZone(ImageDataVO tmplt, long zoneId); - - public List listAllInZone(long dataCenterId); - - public List listByHypervisorType(List hyperTypes); - - public List publicIsoSearch(Boolean bootable, boolean listRemoved, Map tags); - - public List userIsoSearch(boolean listRemoved); - - ImageDataVO findSystemVMTemplate(long zoneId); - - ImageDataVO findSystemVMTemplate(long zoneId, HypervisorType hType); - - ImageDataVO findRoutingTemplate(HypervisorType type); - - List listPrivateTemplatesByHost(Long hostId); - - public Long countTemplatesForAccount(long accountId); - -} diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java deleted file mode 100644 index 301b5861f8c..00000000000 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java +++ /dev/null @@ -1,975 +0,0 @@ -/* - * 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.storage.image.db; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateState; -import org.apache.cloudstack.storage.image.format.ISO; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.domain.DomainVO; -import com.cloud.domain.dao.DomainDao; -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.projects.Project.ListProjectResourcesCriteria; -import com.cloud.server.ResourceTag.TaggedResourceType; -import com.cloud.storage.Storage; -import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.VMTemplateZoneVO; -import com.cloud.storage.dao.VMTemplateDaoImpl; -import com.cloud.storage.dao.VMTemplateDetailsDao; -import com.cloud.storage.dao.VMTemplateZoneDao; -import com.cloud.tags.ResourceTagVO; -import com.cloud.tags.dao.ResourceTagsDaoImpl; -import com.cloud.template.VirtualMachineTemplate.TemplateFilter; -import com.cloud.user.Account; -import com.cloud.utils.Pair; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Filter; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.GenericSearchBuilder; -import com.cloud.utils.db.JoinBuilder; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.SearchCriteria.Func; -import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.UpdateBuilder; -import com.cloud.utils.exception.CloudRuntimeException; - -@Component -public class ImageDataDaoImpl extends GenericDaoBase implements ImageDataDao { - private static final Logger s_logger = Logger.getLogger(VMTemplateDaoImpl.class); - - @Inject - VMTemplateZoneDao templateZoneDao; - @Inject - VMTemplateDetailsDao templateDetailsDao; - - @Inject - ConfigurationDao configDao; - @Inject - HostDao hostDao; - @Inject - DomainDao domainDao; - @Inject - DataCenterDao dcDao; - - private final String SELECT_TEMPLATE_HOST_REF = "SELECT t.id, h.data_center_id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " - + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t"; - - private final String SELECT_TEMPLATE_ZONE_REF = "SELECT t.id, tzr.zone_id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " - + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t INNER JOIN template_zone_ref tzr on (t.id = tzr.template_id) "; - - private final String SELECT_TEMPLATE_SWIFT_REF = "SELECT t.id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " - + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t"; - protected SearchBuilder TemplateNameSearch; - protected SearchBuilder UniqueNameSearch; - protected SearchBuilder tmpltTypeSearch; - protected SearchBuilder tmpltTypeHyperSearch; - protected SearchBuilder tmpltTypeHyperSearch2; - - protected SearchBuilder AccountIdSearch; - protected SearchBuilder NameSearch; - protected SearchBuilder TmpltsInZoneSearch; - private SearchBuilder PublicSearch; - private SearchBuilder NameAccountIdSearch; - private SearchBuilder PublicIsoSearch; - private SearchBuilder UserIsoSearch; - private GenericSearchBuilder CountTemplatesByAccount; - private SearchBuilder updateStateSearch; - - //ResourceTagsDaoImpl _tagsDao = ComponentInject.inject(ResourceTagsDaoImpl.class); - @Inject - ResourceTagsDaoImpl _tagsDao = null; - private String routerTmpltName; - private String consoleProxyTmpltName; - - protected ImageDataDaoImpl() { - } - - @Override - public List listByPublic() { - SearchCriteria sc = PublicSearch.create(); - sc.setParameters("public", 1); - return listBy(sc); - } - - @Override - public ImageDataVO findByName(String templateName) { - SearchCriteria sc = UniqueNameSearch.create(); - sc.setParameters("uniqueName", templateName); - return findOneIncludingRemovedBy(sc); - } - - @Override - public ImageDataVO findByTemplateName(String templateName) { - SearchCriteria sc = NameSearch.create(); - sc.setParameters("name", templateName); - return findOneIncludingRemovedBy(sc); - } - - @Override - public List publicIsoSearch(Boolean bootable, boolean listRemoved, Map tags) { - - SearchBuilder sb = null; - if (tags == null || tags.isEmpty()) { - sb = PublicIsoSearch; - } else { - sb = createSearchBuilder(); - sb.and("public", sb.entity().isPublicTemplate(), SearchCriteria.Op.EQ); - sb.and("format", sb.entity().getFormat(), SearchCriteria.Op.EQ); - sb.and("type", sb.entity().getTemplateType(), SearchCriteria.Op.EQ); - sb.and("bootable", sb.entity().isBootable(), SearchCriteria.Op.EQ); - sb.and("removed", sb.entity().getRemoved(), SearchCriteria.Op.EQ); - - SearchBuilder tagSearch = _tagsDao.createSearchBuilder(); - for (int count = 0; count < tags.size(); count++) { - tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); - tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); - tagSearch.cp(); - } - tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); - sb.groupBy(sb.entity().getId()); - sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); - } - - SearchCriteria sc = sb.create(); - - sc.setParameters("public", 1); - sc.setParameters("format", "ISO"); - sc.setParameters("type", TemplateType.PERHOST.toString()); - if (bootable != null) { - sc.setParameters("bootable", bootable); - } - - if (!listRemoved) { - sc.setParameters("removed", (Object) null); - } - - if (tags != null && !tags.isEmpty()) { - int count = 0; - sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.ISO.toString()); - for (String key : tags.keySet()) { - sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key); - sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key)); - count++; - } - } - - return listBy(sc); - } - - @Override - public List userIsoSearch(boolean listRemoved) { - - SearchBuilder sb = null; - sb = UserIsoSearch; - SearchCriteria sc = sb.create(); - - sc.setParameters("format", Storage.ImageFormat.ISO); - sc.setParameters("type", TemplateType.USER.toString()); - - if (!listRemoved) { - sc.setParameters("removed", (Object) null); - } - - return listBy(sc); - } - - @Override - public List listAllSystemVMTemplates() { - SearchCriteria sc = tmpltTypeSearch.create(); - sc.setParameters("templateType", Storage.TemplateType.SYSTEM); - - Filter filter = new Filter(ImageDataVO.class, "id", false, null, null); - return listBy(sc, filter); - } - - @Override - public List listPrivateTemplatesByHost(Long hostId) { - - String sql = "select * from template_host_ref as thr INNER JOIN vm_template as t ON t.id=thr.template_id " - + "where thr.host_id=? and t.public=0 and t.featured=0 and t.type='USER' and t.removed is NULL"; - - List l = new ArrayList(); - - Transaction txn = Transaction.currentTxn(); - - PreparedStatement pstmt = null; - try { - pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setLong(1, hostId); - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - l.add(rs.getLong(1)); - } - } catch (SQLException e) { - } catch (Throwable e) { - } - return l; - } - - @Override - public List listReadyTemplates() { - SearchCriteria sc = createSearchCriteria(); - sc.addAnd("ready", SearchCriteria.Op.EQ, true); - sc.addAnd("format", SearchCriteria.Op.NEQ, Storage.ImageFormat.ISO); - return listIncludingRemovedBy(sc); - } - - @Override - public List findIsosByIdAndPath(Long domainId, Long accountId, String path) { - SearchCriteria sc = createSearchCriteria(); - sc.addAnd("iso", SearchCriteria.Op.EQ, true); - if (domainId != null) { - sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); - } - if (accountId != null) { - sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); - } - if (path != null) { - sc.addAnd("path", SearchCriteria.Op.EQ, path); - } - return listIncludingRemovedBy(sc); - } - - @Override - public List listByAccountId(long accountId) { - SearchCriteria sc = AccountIdSearch.create(); - sc.setParameters("accountId", accountId); - return listBy(sc); - } - - @Override - public List listByHypervisorType(List hyperTypes) { - SearchCriteria sc = createSearchCriteria(); - hyperTypes.add(HypervisorType.None); - sc.addAnd("hypervisorType", SearchCriteria.Op.IN, hyperTypes.toArray()); - return listBy(sc); - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - boolean result = super.configure(name, params); - - PublicSearch = createSearchBuilder(); - PublicSearch.and("public", PublicSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); - - routerTmpltName = (String) params.get("routing.uniquename"); - - s_logger.debug("Found parameter routing unique name " + routerTmpltName); - if (routerTmpltName == null) { - routerTmpltName = "routing"; - } - - consoleProxyTmpltName = (String) params.get("consoleproxy.uniquename"); - if (consoleProxyTmpltName == null) { - consoleProxyTmpltName = "routing"; - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Use console proxy template : " + consoleProxyTmpltName); - } - - UniqueNameSearch = createSearchBuilder(); - UniqueNameSearch.and("uniqueName", UniqueNameSearch.entity().getUniqueName(), SearchCriteria.Op.EQ); - NameSearch = createSearchBuilder(); - NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ); - - NameAccountIdSearch = createSearchBuilder(); - NameAccountIdSearch.and("name", NameAccountIdSearch.entity().getName(), SearchCriteria.Op.EQ); - NameAccountIdSearch.and("accountId", NameAccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); - - PublicIsoSearch = createSearchBuilder(); - PublicIsoSearch.and("public", PublicIsoSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); - PublicIsoSearch.and("format", PublicIsoSearch.entity().getFormat(), SearchCriteria.Op.EQ); - PublicIsoSearch.and("type", PublicIsoSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); - PublicIsoSearch.and("bootable", PublicIsoSearch.entity().isBootable(), SearchCriteria.Op.EQ); - PublicIsoSearch.and("removed", PublicIsoSearch.entity().getRemoved(), SearchCriteria.Op.EQ); - - UserIsoSearch = createSearchBuilder(); - UserIsoSearch.and("format", UserIsoSearch.entity().getFormat(), SearchCriteria.Op.EQ); - UserIsoSearch.and("type", UserIsoSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); - UserIsoSearch.and("removed", UserIsoSearch.entity().getRemoved(), SearchCriteria.Op.EQ); - - tmpltTypeHyperSearch = createSearchBuilder(); - tmpltTypeHyperSearch.and("templateType", tmpltTypeHyperSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); - SearchBuilder hostHyperSearch = hostDao.createSearchBuilder(); - hostHyperSearch.and("type", hostHyperSearch.entity().getType(), SearchCriteria.Op.EQ); - hostHyperSearch.and("zoneId", hostHyperSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); - hostHyperSearch.groupBy(hostHyperSearch.entity().getHypervisorType()); - - tmpltTypeHyperSearch.join("tmplHyper", hostHyperSearch, hostHyperSearch.entity().getHypervisorType(), tmpltTypeHyperSearch.entity().getHypervisorType(), JoinBuilder.JoinType.INNER); - hostHyperSearch.done(); - tmpltTypeHyperSearch.done(); - - tmpltTypeHyperSearch2 = createSearchBuilder(); - tmpltTypeHyperSearch2.and("templateType", tmpltTypeHyperSearch2.entity().getTemplateType(), SearchCriteria.Op.EQ); - tmpltTypeHyperSearch2.and("hypervisorType", tmpltTypeHyperSearch2.entity().getHypervisorType(), SearchCriteria.Op.EQ); - - tmpltTypeSearch = createSearchBuilder(); - tmpltTypeSearch.and("removed", tmpltTypeSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - tmpltTypeSearch.and("templateType", tmpltTypeSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); - - AccountIdSearch = createSearchBuilder(); - AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); - AccountIdSearch.and("publicTemplate", AccountIdSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); - AccountIdSearch.done(); - - SearchBuilder tmpltZoneSearch = templateZoneDao.createSearchBuilder(); - tmpltZoneSearch.and("removed", tmpltZoneSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - tmpltZoneSearch.and("zoneId", tmpltZoneSearch.entity().getZoneId(), SearchCriteria.Op.EQ); - - TmpltsInZoneSearch = createSearchBuilder(); - TmpltsInZoneSearch.and("removed", TmpltsInZoneSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - TmpltsInZoneSearch.and().op("avoidtype", TmpltsInZoneSearch.entity().getTemplateType(), SearchCriteria.Op.NEQ); - TmpltsInZoneSearch.or("templateType", TmpltsInZoneSearch.entity().getTemplateType(), SearchCriteria.Op.NULL); - TmpltsInZoneSearch.cp(); - TmpltsInZoneSearch.join("tmpltzone", tmpltZoneSearch, tmpltZoneSearch.entity().getTemplateId(), TmpltsInZoneSearch.entity().getId(), JoinBuilder.JoinType.INNER); - tmpltZoneSearch.done(); - TmpltsInZoneSearch.done(); - - CountTemplatesByAccount = createSearchBuilder(Long.class); - CountTemplatesByAccount.select(null, Func.COUNT, null); - CountTemplatesByAccount.and("account", CountTemplatesByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); - CountTemplatesByAccount.and("removed", CountTemplatesByAccount.entity().getRemoved(), SearchCriteria.Op.NULL); - CountTemplatesByAccount.done(); - - updateStateSearch = this.createSearchBuilder(); - updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); - updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); - updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); - updateStateSearch.done(); - return result; - } - - @Override - public String getRoutingTemplateUniqueName() { - return routerTmpltName; - } - - @Override - public Set> searchSwiftTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, - Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, Map tags) { - - StringBuilder builder = new StringBuilder(); - if (!permittedAccounts.isEmpty()) { - for (Account permittedAccount : permittedAccounts) { - builder.append(permittedAccount.getAccountId() + ","); - } - } - - String permittedAccountsStr = builder.toString(); - - if (permittedAccountsStr.length() > 0) { - // chop the "," off - permittedAccountsStr = permittedAccountsStr.substring(0, permittedAccountsStr.length() - 1); - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - Set> templateZonePairList = new HashSet>(); - PreparedStatement pstmt = null; - ResultSet rs = null; - String sql = SELECT_TEMPLATE_SWIFT_REF; - try { - String joinClause = ""; - String whereClause = " WHERE t.removed IS NULL"; - - if (isIso) { - whereClause += " AND t.format = 'ISO'"; - if (!hyperType.equals(HypervisorType.None)) { - joinClause = " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) "; - whereClause += " AND goh.hypervisor_type = '" + hyperType.toString() + "'"; - } - } else { - whereClause += " AND t.format <> 'ISO'"; - if (hypers.isEmpty()) { - return templateZonePairList; - } else { - StringBuilder relatedHypers = new StringBuilder(); - for (HypervisorType hyper : hypers) { - relatedHypers.append("'"); - relatedHypers.append(hyper.toString()); - relatedHypers.append("'"); - relatedHypers.append(","); - } - relatedHypers.setLength(relatedHypers.length() - 1); - whereClause += " AND t.hypervisor_type IN (" + relatedHypers + ")"; - } - } - joinClause += " INNER JOIN template_swift_ref tsr on (t.id = tsr.template_id)"; - if (keyword != null) { - whereClause += " AND t.name LIKE \"%" + keyword + "%\""; - } else if (name != null) { - whereClause += " AND t.name LIKE \"%" + name + "%\""; - } - - if (bootable != null) { - whereClause += " AND t.bootable = " + bootable; - } - - if (!showDomr) { - whereClause += " AND t.type != '" + Storage.TemplateType.SYSTEM.toString() + "'"; - } - - if (templateFilter == TemplateFilter.featured) { - whereClause += " AND t.public = 1 AND t.featured = 1"; - } else if ((templateFilter == TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { - if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { - joinClause += " INNER JOIN account a on (t.account_id = a.id) INNER JOIN domain d on (a.domain_id = d.id)"; - whereClause += " AND d.path LIKE '" + domain.getPath() + "%'"; - } else { - whereClause += " AND t.account_id IN (" + permittedAccountsStr + ")"; - } - } else if (templateFilter == TemplateFilter.sharedexecutable && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { - if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) { - joinClause += " LEFT JOIN launch_permission lp ON t.id = lp.template_id WHERE" + " (t.account_id IN (" + permittedAccountsStr + ") OR" + " lp.account_id IN (" - + permittedAccountsStr + "))"; - } else { - joinClause += " INNER JOIN account a on (t.account_id = a.id) "; - } - } else if (templateFilter == TemplateFilter.executable && !permittedAccounts.isEmpty()) { - whereClause += " AND (t.public = 1 OR t.account_id IN (" + permittedAccountsStr + "))"; - } else if (templateFilter == TemplateFilter.community) { - whereClause += " AND t.public = 1 AND t.featured = 0"; - } else if (templateFilter == TemplateFilter.all && caller.getType() == Account.ACCOUNT_TYPE_ADMIN) { - } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { - return templateZonePairList; - } - - sql += joinClause + whereClause + getOrderByLimit(pageSize, startIndex); - pstmt = txn.prepareStatement(sql); - rs = pstmt.executeQuery(); - while (rs.next()) { - Pair templateZonePair = new Pair(rs.getLong(1), -1L); - templateZonePairList.add(templateZonePair); - } - - } catch (Exception e) { - s_logger.warn("Error listing templates", e); - } finally { - try { - if (rs != null) { - rs.close(); - } - if (pstmt != null) { - pstmt.close(); - } - txn.commit(); - } catch (SQLException sqle) { - s_logger.warn("Error in cleaning up", sqle); - } - } - - return templateZonePairList; - } - - @Override - public Set> searchTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, - Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, - ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags) { - StringBuilder builder = new StringBuilder(); - if (!permittedAccounts.isEmpty()) { - for (Account permittedAccount : permittedAccounts) { - builder.append(permittedAccount.getAccountId() + ","); - } - } - - String permittedAccountsStr = builder.toString(); - - if (permittedAccountsStr.length() > 0) { - // chop the "," off - permittedAccountsStr = permittedAccountsStr.substring(0, permittedAccountsStr.length() - 1); - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - /* Use LinkedHashSet here to guarantee iteration order */ - Set> templateZonePairList = new LinkedHashSet>(); - PreparedStatement pstmt = null; - ResultSet rs = null; - StringBuilder relatedDomainIds = new StringBuilder(); - String sql = SELECT_TEMPLATE_ZONE_REF; - String groupByClause = ""; - try { - // short accountType; - // String accountId = null; - String guestOSJoin = ""; - StringBuilder templateHostRefJoin = new StringBuilder(); - String dataCenterJoin = "", lpjoin = ""; - String tagsJoin = ""; - - if (isIso && !hyperType.equals(HypervisorType.None)) { - guestOSJoin = " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) "; - } - if (onlyReady) { - templateHostRefJoin.append(" INNER JOIN template_host_ref thr on (t.id = thr.template_id) INNER JOIN host h on (thr.host_id = h.id)"); - sql = SELECT_TEMPLATE_HOST_REF; - groupByClause = " GROUP BY t.id, h.data_center_id "; - } - if ((templateFilter == TemplateFilter.featured) || (templateFilter == TemplateFilter.community)) { - dataCenterJoin = " INNER JOIN data_center dc on (h.data_center_id = dc.id)"; - } - - if (templateFilter == TemplateFilter.sharedexecutable) { - lpjoin = " INNER JOIN launch_permission lp ON t.id = lp.template_id "; - } - - if (tags != null && !tags.isEmpty()) { - tagsJoin = " INNER JOIN resource_tags r ON t.id = r.resource_id "; - } - - sql += guestOSJoin + templateHostRefJoin + dataCenterJoin + lpjoin + tagsJoin; - String whereClause = ""; - - // All joins have to be made before we start setting the condition - // settings - if ((listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources || (!permittedAccounts.isEmpty() && !(templateFilter == TemplateFilter.community || templateFilter == TemplateFilter.featured))) - && !(caller.getType() != Account.ACCOUNT_TYPE_NORMAL && templateFilter == TemplateFilter.all)) { - whereClause += " INNER JOIN account a on (t.account_id = a.id)"; - if ((templateFilter == TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) - && (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN)) { - whereClause += " INNER JOIN domain d on (a.domain_id = d.id) WHERE d.path LIKE '" + domain.getPath() + "%'"; - if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) { - whereClause += " AND a.type != " + Account.ACCOUNT_TYPE_PROJECT; - } - } else if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) { - whereClause += " WHERE a.type != " + Account.ACCOUNT_TYPE_PROJECT; - } - } - - if (!permittedAccounts.isEmpty()) { - for (Account account : permittedAccounts) { - // accountType = account.getType(); - // accountId = Long.toString(account.getId()); - DomainVO accountDomain = domainDao.findById(account.getDomainId()); - - // get all parent domain ID's all the way till root domain - DomainVO domainTreeNode = accountDomain; - while (true) { - relatedDomainIds.append(domainTreeNode.getId()); - relatedDomainIds.append(","); - if (domainTreeNode.getParent() != null) { - domainTreeNode = domainDao.findById(domainTreeNode.getParent()); - } else { - break; - } - } - - // get all child domain ID's - if (isAdmin(account.getType())) { - List allChildDomains = domainDao.findAllChildren(accountDomain.getPath(), accountDomain.getId()); - for (DomainVO childDomain : allChildDomains) { - relatedDomainIds.append(childDomain.getId()); - relatedDomainIds.append(","); - } - } - relatedDomainIds.setLength(relatedDomainIds.length() - 1); - } - } - - String attr = " AND "; - if (whereClause.endsWith(" WHERE ")) { - attr += " WHERE "; - } - - if (!isIso) { - if (hypers.isEmpty()) { - return templateZonePairList; - } else { - StringBuilder relatedHypers = new StringBuilder(); - for (HypervisorType hyper : hypers) { - relatedHypers.append("'"); - relatedHypers.append(hyper.toString()); - relatedHypers.append("'"); - relatedHypers.append(","); - } - relatedHypers.setLength(relatedHypers.length() - 1); - whereClause += attr + " t.hypervisor_type IN (" + relatedHypers + ")"; - } - } - - if (!permittedAccounts.isEmpty() && !(templateFilter == TemplateFilter.featured || templateFilter == TemplateFilter.community || templateFilter == TemplateFilter.executable) - && !isAdmin(caller.getType())) { - whereClause += attr + "t.account_id IN (" + permittedAccountsStr + ")"; - } - - if (templateFilter == TemplateFilter.featured) { - whereClause += attr + "t.public = 1 AND t.featured = 1"; - if (!permittedAccounts.isEmpty()) { - whereClause += attr + "(dc.domain_id IN (" + relatedDomainIds + ") OR dc.domain_id is NULL)"; - } - } else if (templateFilter == TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) { - whereClause += " AND t.account_id IN (" + permittedAccountsStr + ")"; - } else if (templateFilter == TemplateFilter.sharedexecutable) { - whereClause += " AND " + " (t.account_id IN (" + permittedAccountsStr + ") OR" + " lp.account_id IN (" + permittedAccountsStr + "))"; - } else if (templateFilter == TemplateFilter.executable && !permittedAccounts.isEmpty()) { - whereClause += attr + "(t.public = 1 OR t.account_id IN (" + permittedAccountsStr + "))"; - } else if (templateFilter == TemplateFilter.community) { - whereClause += attr + "t.public = 1 AND t.featured = 0"; - if (!permittedAccounts.isEmpty()) { - whereClause += attr + "(dc.domain_id IN (" + relatedDomainIds + ") OR dc.domain_id is NULL)"; - } - } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && !isIso) { - return templateZonePairList; - } - - if (tags != null && !tags.isEmpty()) { - whereClause += " AND ("; - boolean first = true; - for (String key : tags.keySet()) { - if (!first) { - whereClause += " OR "; - } - whereClause += "(r.key=\"" + key + "\" and r.value=\"" + tags.get(key) + "\")"; - first = false; - } - whereClause += ")"; - } - - if (whereClause.equals("")) { - whereClause += " WHERE "; - } else if (!whereClause.equals(" WHERE ")) { - whereClause += " AND "; - } - - sql += whereClause + getExtrasWhere(templateFilter, name, keyword, isIso, bootable, hyperType, zoneId, onlyReady, showDomr) + groupByClause + getOrderByLimit(pageSize, startIndex); - - pstmt = txn.prepareStatement(sql); - rs = pstmt.executeQuery(); - - while (rs.next()) { - Pair templateZonePair = new Pair(rs.getLong(1), rs.getLong(2)); - templateZonePairList.add(templateZonePair); - } - // for now, defaulting pageSize to a large val if null; may need to - // revisit post 2.2RC2 - if (isIso && - templateZonePairList.size() < (pageSize != null ? pageSize : 500) && - templateFilter != TemplateFilter.community && - !(templateFilter == TemplateFilter.self) /* TODO: Fix this! && !BaseCmd.isRootAdmin(caller.getType())*/) { // evaluates - // to - // true - // If - // root - // admin - // and - // filter=self - - List publicIsos = publicIsoSearch(bootable, false, tags); - List userIsos = userIsoSearch(false); - - // Listing the ISOs according to the page size.Restricting the - // total no. of ISOs on a page - // to be less than or equal to the pageSize parameter - - int i = 0; - - if (startIndex > userIsos.size()) { - i = (int) (startIndex - userIsos.size()); - } - - for (; i < publicIsos.size(); i++) { - if (templateZonePairList.size() >= pageSize) { - break; - } else { - if (keyword != null && publicIsos.get(i).getName().contains(keyword)) { - templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); - continue; - } else if (name != null && publicIsos.get(i).getName().contains(name)) { - templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); - continue; - } else if (keyword == null && name == null) { - templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); - } - } - } - } - } catch (Exception e) { - s_logger.warn("Error listing templates", e); - } finally { - try { - if (rs != null) { - rs.close(); - } - if (pstmt != null) { - pstmt.close(); - } - txn.commit(); - } catch (SQLException sqle) { - s_logger.warn("Error in cleaning up", sqle); - } - } - - return templateZonePairList; - } - - private String getExtrasWhere(TemplateFilter templateFilter, String name, String keyword, boolean isIso, Boolean bootable, HypervisorType hyperType, Long zoneId, boolean onlyReady, - boolean showDomr) { - String sql = ""; - if (keyword != null) { - sql += " t.name LIKE \"%" + keyword + "%\" AND"; - } else if (name != null) { - sql += " t.name LIKE \"%" + name + "%\" AND"; - } - - if (isIso) { - sql += " t.format = 'ISO'"; - if (!hyperType.equals(HypervisorType.None)) { - sql += " AND goh.hypervisor_type = '" + hyperType.toString() + "'"; - } - } else { - sql += " t.format <> 'ISO'"; - if (!hyperType.equals(HypervisorType.None)) { - sql += " AND t.hypervisor_type = '" + hyperType.toString() + "'"; - } - } - - if (bootable != null) { - sql += " AND t.bootable = " + bootable; - } - - if (onlyReady) { - sql += " AND thr.download_state = '" + Status.DOWNLOADED.toString() + "'" + " AND thr.destroyed=0 "; - if (zoneId != null) { - sql += " AND h.data_center_id = " + zoneId; - } - } else if (zoneId != null) { - sql += " AND tzr.zone_id = " + zoneId + " AND tzr.removed is null"; - } else { - sql += " AND tzr.removed is null "; - } - if (!showDomr) { - sql += " AND t.type != '" + Storage.TemplateType.SYSTEM.toString() + "'"; - } - - sql += " AND t.removed IS NULL"; - - return sql; - } - - private String getOrderByLimit(Long pageSize, Long startIndex) { - Boolean isAscending = Boolean.parseBoolean(configDao.getValue("sortkey.algorithm")); - isAscending = (isAscending == null ? true : isAscending); - - String sql; - if (isAscending) { - sql = " ORDER BY t.sort_key ASC"; - } else { - sql = " ORDER BY t.sort_key DESC"; - } - - if ((pageSize != null) && (startIndex != null)) { - sql += " LIMIT " + startIndex.toString() + "," + pageSize.toString(); - } - return sql; - } - - @Override - @DB - public long addTemplateToZone(ImageDataVO tmplt, long zoneId) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - ImageDataVO tmplt2 = findById(tmplt.getId()); - if (tmplt2 == null) { - if (persist(tmplt) == null) { - throw new CloudRuntimeException("Failed to persist the template " + tmplt); - } - if (tmplt.getDetails() != null) { - templateDetailsDao.persist(tmplt.getId(), tmplt.getDetails()); - } - } - VMTemplateZoneVO tmpltZoneVO = templateZoneDao.findByZoneTemplate(zoneId, tmplt.getId()); - if (tmpltZoneVO == null) { - tmpltZoneVO = new VMTemplateZoneVO(zoneId, tmplt.getId(), new Date()); - templateZoneDao.persist(tmpltZoneVO); - } else { - tmpltZoneVO.setRemoved(null); - tmpltZoneVO.setLastUpdated(new Date()); - templateZoneDao.update(tmpltZoneVO.getId(), tmpltZoneVO); - } - txn.commit(); - - return tmplt.getId(); - } - - @Override - @DB - public List listAllInZone(long dataCenterId) { - SearchCriteria sc = TmpltsInZoneSearch.create(); - sc.setParameters("avoidtype", TemplateType.PERHOST.toString()); - sc.setJoinParameters("tmpltzone", "zoneId", dataCenterId); - return listBy(sc); - } - - @Override - public List listDefaultBuiltinTemplates() { - SearchCriteria sc = tmpltTypeSearch.create(); - sc.setParameters("templateType", Storage.TemplateType.BUILTIN); - return listBy(sc); - } - - @Override - public ImageDataVO findSystemVMTemplate(long zoneId) { - SearchCriteria sc = tmpltTypeHyperSearch.create(); - sc.setParameters("templateType", Storage.TemplateType.SYSTEM); - sc.setJoinParameters("tmplHyper", "type", Host.Type.Routing); - sc.setJoinParameters("tmplHyper", "zoneId", zoneId); - - // order by descending order of id and select the first (this is going - // to be the latest) - List tmplts = listBy(sc, new Filter(ImageDataVO.class, "id", false, null, 1l)); - - if (tmplts.size() > 0) { - return tmplts.get(0); - } else { - return null; - } - } - - @Override - public ImageDataVO findSystemVMTemplate(long zoneId, HypervisorType hType) { - SearchCriteria sc = tmpltTypeHyperSearch.create(); - sc.setParameters("templateType", Storage.TemplateType.SYSTEM); - sc.setJoinParameters("tmplHyper", "type", Host.Type.Routing); - sc.setJoinParameters("tmplHyper", "zoneId", zoneId); - - // order by descending order of id - List tmplts = listBy(sc, new Filter(ImageDataVO.class, "id", false, null, null)); - - for (ImageDataVO tmplt : tmplts) { - if (tmplt.getHypervisorType() == hType) { - return tmplt; - } - } - if (tmplts.size() > 0 && hType == HypervisorType.Any) { - return tmplts.get(0); - } - return null; - } - - @Override - public ImageDataVO findRoutingTemplate(HypervisorType hType) { - SearchCriteria sc = tmpltTypeHyperSearch2.create(); - sc.setParameters("templateType", Storage.TemplateType.SYSTEM); - sc.setParameters("hypervisorType", hType); - - // order by descending order of id and select the first (this is going - // to be the latest) - List tmplts = listBy(sc, new Filter(ImageDataVO.class, "id", false, null, 1l)); - - if (tmplts.size() > 0) { - return tmplts.get(0); - } else { - return null; - } - } - - @Override - public Long countTemplatesForAccount(long accountId) { - SearchCriteria sc = CountTemplatesByAccount.create(); - sc.setParameters("account", accountId); - return customSearch(sc, null).get(0); - } - - @Override - @DB - public boolean remove(Long id) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - ImageDataVO template = createForUpdate(); - template.setRemoved(new Date()); - - ImageDataVO vo = findById(id); - if (vo != null) { - if (vo.getFormat().equalsIgnoreCase(new ISO().toString())) { - _tagsDao.removeByIdAndType(id, TaggedResourceType.ISO); - } else { - _tagsDao.removeByIdAndType(id, TaggedResourceType.Template); - } - } - - boolean result = update(id, template); - txn.commit(); - return result; - } - - private boolean isAdmin(short accountType) { - return ((accountType == Account.ACCOUNT_TYPE_ADMIN) || (accountType == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) || (accountType == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) || (accountType == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)); - } - - @Override - public boolean updateState(TemplateState currentState, TemplateEvent event, - TemplateState nextState, ImageDataVO vo, Object data) { - Long oldUpdated = vo.getUpdatedCount(); - Date oldUpdatedTime = vo.getUpdated(); - - - SearchCriteria sc = updateStateSearch.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((ImageDataVO) vo, sc); - if (rows == 0 && s_logger.isDebugEnabled()) { - ImageDataVO 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 objectIndatastore: id=" + vo.getId() + ", as there is no such object exists in the database anymore"); - } - } - return rows > 0; - } -} \ No newline at end of file diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java deleted file mode 100644 index e3ddaed721a..00000000000 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java +++ /dev/null @@ -1,450 +0,0 @@ -/* - * 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.storage.image.db; - -import java.util.Date; -import java.util.Map; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.TableGenerator; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; - -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.storage.image.TemplateState; - -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.storage.Storage; -import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateVO; -import com.cloud.utils.db.GenericDao; -import com.cloud.utils.fsm.StateObject; - -@Entity -@Table(name = "vm_template") -public class ImageDataVO implements Identity, StateObject { - @Id - @TableGenerator(name = "vm_template_sq", table = "sequence", pkColumnName = "name", valueColumnName = "value", pkColumnValue = "vm_template_seq", allocationSize = 1) - @Column(name = "id", nullable = false) - private long id; - - @Column(name = "format") - private String format; - - @Column(name = "unique_name") - private String uniqueName; - - @Column(name = "name") - private String name = null; - - @Column(name = "public") - private boolean publicTemplate = true; - - @Column(name = "featured") - private boolean featured; - - @Column(name = "type") - private Storage.TemplateType templateType; - - @Column(name = "url") - private String url = null; - - @Column(name = "hvm") - private boolean requiresHvm; - - @Column(name = "bits") - private int bits; - - @Temporal(value = TemporalType.TIMESTAMP) - @Column(name = GenericDao.CREATED_COLUMN) - private Date created = null; - - @Column(name = GenericDao.REMOVED) - @Temporal(TemporalType.TIMESTAMP) - private Date removed; - - @Column(name = "account_id") - private long accountId; - - @Column(name = "checksum") - private String checksum; - - @Column(name = "display_text", length = 4096) - private String displayText; - - @Column(name = "enable_password") - private boolean enablePassword; - - @Column(name = "guest_os_id") - private long guestOSId; - - @Column(name = "bootable") - private boolean bootable = true; - - @Column(name = "prepopulate") - private boolean prepopulate = false; - - @Column(name = "cross_zones") - private boolean crossZones = false; - - @Column(name = "hypervisor_type") - @Enumerated(value = EnumType.STRING) - private HypervisorType hypervisorType; - - @Column(name = "extractable") - private boolean extractable = true; - - @Column(name = "source_template_id") - private Long sourceTemplateId; - - @Column(name = "template_tag") - private String templateTag; - - @Column(name = "uuid") - private String uuid; - - @Column(name = "sort_key") - private int sortKey; - - @Column(name = "enable_sshkey") - private boolean enableSshKey; - - @Column(name = "image_data_store_id") - private long imageDataStoreId; - - @Column(name = "size") - private Long size; - - @Column(name = "state") - private TemplateState state; - - @Column(name="update_count", updatable = true) - protected long updatedCount; - - @Column(name = "updated") - @Temporal(value = TemporalType.TIMESTAMP) - Date updated; - - @Transient - Map details; - - public String getUniqueName() { - return uniqueName; - } - - public void setUniqueName(String uniqueName) { - this.uniqueName = uniqueName; - } - - public ImageDataVO() { - this.uuid = UUID.randomUUID().toString(); - this.state = TemplateState.Allocated; - this.created = new Date(); - } - - public boolean getEnablePassword() { - return enablePassword; - } - - public String getFormat() { - return format; - } - - public void setEnablePassword(boolean enablePassword) { - this.enablePassword = enablePassword; - } - - public void setFormat(String format) { - this.format = format; - } - - public long getId() { - return id; - } - - public TemplateType getTemplateType() { - return templateType; - } - - public void setTemplateType(TemplateType type) { - this.templateType = type; - } - - public boolean requiresHvm() { - return requiresHvm; - } - - public void setRequireHvm(boolean hvm) { - this.requiresHvm = hvm; - } - - public int getBits() { - return bits; - } - - public void setBits(int bits) { - this.bits = bits; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Date getRemoved() { - return removed; - } - - public boolean isPublicTemplate() { - return publicTemplate; - } - - public void setPublicTemplate(boolean publicTemplate) { - this.publicTemplate = publicTemplate; - } - - public boolean isFeatured() { - return featured; - } - - public void setFeatured(boolean featured) { - this.featured = featured; - } - - public Date getCreated() { - return created; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public long getAccountId() { - return accountId; - } - - public void setAccountId(long accountId) { - this.accountId = accountId; - } - - public String getChecksum() { - return checksum; - } - - public void setChecksum(String checksum) { - this.checksum = checksum; - } - - public String getDisplayText() { - return displayText; - } - - public void setDisplayText(String displayText) { - this.displayText = displayText; - } - - public long getGuestOSId() { - return guestOSId; - } - - public void setGuestOSId(long guestOSId) { - this.guestOSId = guestOSId; - } - - public boolean isBootable() { - return bootable; - } - - public void setBootable(boolean bootable) { - this.bootable = bootable; - } - - public void setPrepopulate(boolean prepopulate) { - this.prepopulate = prepopulate; - } - - public boolean isPrepopulate() { - return prepopulate; - } - - public void setCrossZones(boolean crossZones) { - this.crossZones = crossZones; - } - - public boolean isCrossZones() { - return crossZones; - } - - public HypervisorType getHypervisorType() { - return hypervisorType; - } - - public void setHypervisorType(HypervisorType hyperType) { - hypervisorType = hyperType; - } - - public boolean isExtractable() { - return extractable; - } - - public void setExtractable(boolean extractable) { - this.extractable = extractable; - } - - public Long getSourceTemplateId() { - return sourceTemplateId; - } - - public void setSourceTemplateId(Long sourceTemplateId) { - this.sourceTemplateId = sourceTemplateId; - } - - public String getTemplateTag() { - return templateTag; - } - - public void setTemplateTag(String templateTag) { - this.templateTag = templateTag; - } - - public long getDomainId() { - return -1; - } - - @Override - public String getUuid() { - return this.uuid; - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public Map getDetails() { - return this.details; - } - - public void setDetails(Map details) { - this.details = details; - } - - @Override - public boolean equals(Object that) { - if (this == that) { - return true; - } - if (!(that instanceof VMTemplateVO)) { - return false; - } - VMTemplateVO other = (VMTemplateVO) that; - - return ((this.getUniqueName().equals(other.getUniqueName()))); - } - - @Override - public int hashCode() { - return uniqueName.hashCode(); - } - - @Transient - String toString; - - @Override - public String toString() { - if (toString == null) { - toString = new StringBuilder("Tmpl[").append(id).append("-").append(format).append("-").append(uniqueName).toString(); - } - return toString; - } - - public void setRemoved(Date removed) { - this.removed = removed; - } - - public void setSortKey(int key) { - sortKey = key; - } - - public int getSortKey() { - return sortKey; - } - - public boolean getEnableSshKey() { - return enableSshKey; - } - - public void setEnableSshKey(boolean enable) { - enableSshKey = enable; - } - - public Long getImageDataStoreId() { - return this.imageDataStoreId; - } - - public void setImageDataStoreId(long dataStoreId) { - this.imageDataStoreId = dataStoreId; - } - - public void setSize(Long size) { - this.size = size; - } - - public Long getSize() { - return this.size; - } - - public TemplateState getState() { - return this.state; - } - - public long getUpdatedCount() { - return this.updatedCount; - } - - public void incrUpdatedCount() { - this.updatedCount++; - } - - public void decrUpdatedCount() { - this.updatedCount--; - } - - public Date getUpdated() { - return updated; - } - - public void setUpdated(Date updated) { - this.updated = updated; - } - -} diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java b/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java index 422bc066211..908d6d52c20 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java @@ -19,9 +19,9 @@ package org.apache.cloudstack.storage.image.motion; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; public interface ImageMotionService { diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java new file mode 100644 index 00000000000..c067a1b651c --- /dev/null +++ b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -0,0 +1,725 @@ +/* + * 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.storage.motion; + +import java.util.Date; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.BackupSnapshotAnswer; +import com.cloud.agent.api.BackupSnapshotCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; +import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; +import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer; +import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; +import com.cloud.agent.api.UpgradeSnapshotCommand; +import com.cloud.agent.api.storage.CopyVolumeAnswer; +import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.CreateAnswer; +import com.cloud.agent.api.storage.CreateCommand; +import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; +import com.cloud.agent.api.to.S3TO; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.agent.api.to.SwiftTO; +import com.cloud.configuration.Config; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; +import com.cloud.storage.s3.S3Manager; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.storage.swift.SwiftManager; +import com.cloud.template.TemplateManager; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.DiskProfile; + +@Component +public class AncientDataMotionStrategy implements DataMotionStrategy { + private static final Logger s_logger = Logger + .getLogger(AncientDataMotionStrategy.class); + @Inject + TemplateManager templateMgr; + @Inject + VolumeHostDao volumeHostDao; + @Inject + HostDao hostDao; + @Inject + ConfigurationDao configDao; + @Inject + StorageManager storagMgr; + @Inject + VolumeDao volDao; + @Inject + VMTemplateDao templateDao; + @Inject + SnapshotManager snapshotMgr; + @Inject + SnapshotDao snapshotDao; + @Inject + PrimaryDataStoreDao primaryDataStoreDao; + @Inject + DataStoreManager dataStoreMgr; + @Inject + VMTemplateHostDao templateHostDao; + @Inject DiskOfferingDao diskOfferingDao; + @Inject VMTemplatePoolDao templatePoolDao; + @Inject + VolumeManager volumeMgr; + @Inject + private SwiftManager _swiftMgr; + @Inject + private S3Manager _s3Mgr; + + @Override + public boolean canHandle(DataObject srcData, DataObject destData) { + // TODO Auto-generated method stub + return true; + } + + @DB + protected Answer copyVolumeFromImage(DataObject srcData, DataObject destData) { + String value = configDao.getValue(Config.RecreateSystemVmEnabled.key()); + int _copyvolumewait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); + + VolumeHostVO volumeHostVO = volumeHostDao.findByVolumeId(srcData + .getId()); + HostVO secStorage = hostDao.findById(volumeHostVO.getHostId()); + String secondaryStorageURL = secStorage.getStorageUrl(); + String[] volumePath = volumeHostVO.getInstallPath().split("/"); + String volumeUUID = volumePath[volumePath.length - 1].split("\\.")[0]; + StoragePool destPool = (StoragePool) destData.getDataStore(); + CopyVolumeCommand cvCmd = new CopyVolumeCommand(srcData.getId(), + volumeUUID, destPool, secondaryStorageURL, false, + _copyvolumewait); + CopyVolumeAnswer cvAnswer = null; + String errMsg = null; + try { + cvAnswer = (CopyVolumeAnswer) this.storagMgr.sendToPool(destPool, + cvCmd); + } catch (StorageUnavailableException e1) { + s_logger.debug("Failed to copy volume " + srcData.getId() + " to " + + destData.getId(), e1); + errMsg = e1.toString(); + } + + if (cvAnswer == null || !cvAnswer.getResult()) { + errMsg = cvAnswer.getDetails(); + } + + VolumeVO vol = this.volDao.findById(destData.getId()); + Transaction txn = Transaction.currentTxn(); + txn.start(); + vol.setPath(cvAnswer.getVolumePath()); + vol.setFolder(destPool.getPath()); + vol.setPodId(destPool.getPodId()); + vol.setPoolId(destPool.getId()); + vol.setPodId(destPool.getPodId()); + + this.volDao.update(vol.getId(), vol); + volumeHostDao.remove(volumeHostVO.getId()); + txn.commit(); + return cvAnswer; + } + + private Answer copyTemplate(DataObject srcData, DataObject destData) { + VMTemplateVO template = this.templateDao.findById(srcData.getId()); + templateMgr.prepareTemplateForCreate(template, + (StoragePool) destData.getDataStore()); + return null; + } + + protected Answer copyFromSnapshot(DataObject snapObj, DataObject volObj) { + SnapshotVO snapshot = this.snapshotDao.findById(snapObj.getId()); + StoragePool pool = (StoragePool) volObj.getDataStore(); + String vdiUUID = null; + Long snapshotId = snapshot.getId(); + Long volumeId = snapshot.getVolumeId(); + Long dcId = snapshot.getDataCenterId(); + String secondaryStoragePoolUrl = this.snapshotMgr + .getSecondaryStorageURL(snapshot); + long accountId = snapshot.getAccountId(); + + String backedUpSnapshotUuid = snapshot.getBackupSnapshotId(); + snapshot = snapshotDao.findById(snapshotId); + if (snapshot.getVersion().trim().equals("2.1")) { + VolumeVO volume = this.volDao.findByIdIncludingRemoved(volumeId); + if (volume == null) { + throw new CloudRuntimeException("failed to upgrade snapshot " + + snapshotId + " due to unable to find orignal volume:" + + volumeId + ", try it later "); + } + if (volume.getTemplateId() == null) { + snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); + } else { + VMTemplateVO template = templateDao + .findByIdIncludingRemoved(volume.getTemplateId()); + if (template == null) { + throw new CloudRuntimeException( + "failed to upgrade snapshot " + + snapshotId + + " due to unalbe to find orignal template :" + + volume.getTemplateId() + + ", try it later "); + } + Long templateId = template.getId(); + Long tmpltAccountId = template.getAccountId(); + if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { + throw new CloudRuntimeException( + "failed to upgrade snapshot " + + snapshotId + + " due to this snapshot is being used, try it later "); + } + UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null, + secondaryStoragePoolUrl, dcId, accountId, volumeId, + templateId, tmpltAccountId, null, + snapshot.getBackupSnapshotId(), snapshot.getName(), + "2.1"); + Answer answer = null; + try { + answer = this.storagMgr.sendToPool(pool, cmd); + } catch (StorageUnavailableException e) { + } finally { + snapshotDao.unlockFromLockTable(snapshotId.toString()); + } + if ((answer != null) && answer.getResult()) { + snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); + } else { + throw new CloudRuntimeException("Unable to upgrade snapshot from 2.1 to 2.2 for " + + snapshot.getId()); + } + } + } + String basicErrMsg = "Failed to create volume from " + + snapshot.getName() + " on pool " + pool; + + try { + if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) { + snapshotMgr.downloadSnapshotsFromSwift(snapshot); + } else if (snapshot.getS3Id() != null && snapshot.getS3Id() != 0) { + snapshotMgr.downloadSnapshotsFromS3(snapshot); + } + String value = configDao + .getValue(Config.CreateVolumeFromSnapshotWait.toString()); + int _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CreateVolumeFromSnapshotWait + .getDefaultValue())); + CreateVolumeFromSnapshotCommand createVolumeFromSnapshotCommand = new CreateVolumeFromSnapshotCommand( + pool, secondaryStoragePoolUrl, dcId, accountId, volumeId, + backedUpSnapshotUuid, snapshot.getName(), + _createVolumeFromSnapshotWait); + CreateVolumeFromSnapshotAnswer answer; + if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { + throw new CloudRuntimeException("failed to create volume from " + + snapshotId + + " due to this snapshot is being used, try it later "); + } + answer = (CreateVolumeFromSnapshotAnswer) this.storagMgr + .sendToPool(pool, createVolumeFromSnapshotCommand); + if (answer != null && answer.getResult()) { + vdiUUID = answer.getVdi(); + VolumeVO vol = this.volDao.findById(volObj.getId()); + vol.setPath(vdiUUID); + this.volDao.update(vol.getId(), vol); + return null; + } else { + s_logger.error(basicErrMsg + " due to " + + ((answer == null) ? "null" : answer.getDetails())); + throw new CloudRuntimeException(basicErrMsg); + } + } catch (StorageUnavailableException e) { + s_logger.error(basicErrMsg, e); + throw new CloudRuntimeException(basicErrMsg); + } finally { + if (snapshot.getSwiftId() != null) { + snapshotMgr.deleteSnapshotsDirForVolume( + secondaryStoragePoolUrl, dcId, accountId, volumeId); + } + } + } + + protected Answer cloneVolume(DataObject template, DataObject volume) { + VolumeInfo volInfo = (VolumeInfo)volume; + DiskOfferingVO offering = diskOfferingDao.findById(volInfo.getDiskOfferingId()); + VMTemplateStoragePoolVO tmpltStoredOn = templatePoolDao.findByPoolTemplate(template.getDataStore().getId(), template.getId()); + + DiskProfile diskProfile = new DiskProfile(volInfo, offering, + null); + CreateCommand cmd = new CreateCommand(diskProfile, + tmpltStoredOn.getLocalDownloadPath(), + new StorageFilerTO((StoragePool)template.getDataStore())); + Answer answer = null; + StoragePool pool = (StoragePool)volume.getDataStore(); + String errMsg = null; + try { + answer = storagMgr.sendToPool(pool, null, cmd); + } catch (StorageUnavailableException e) { + s_logger.debug("Failed to send to storage pool", e); + throw new CloudRuntimeException("Failed to send to storage pool", e); + } + + if (answer.getResult()) { + VolumeVO vol = this.volDao.findById(volume.getId()); + CreateAnswer createAnswer = (CreateAnswer) answer; + vol.setFolder(pool.getPath()); + vol.setPath(createAnswer.getVolume().getPath()); + vol.setSize(createAnswer.getVolume().getSize()); + vol.setPoolType(pool.getPoolType()); + vol.setPoolId(pool.getId()); + vol.setPodId(pool.getPodId()); + this.volDao.update(vol.getId(), vol); + + } else { + if (tmpltStoredOn != null + && (answer instanceof CreateAnswer) + && ((CreateAnswer) answer) + .templateReloadRequested()) { + if (!templateMgr + .resetTemplateDownloadStateOnPool(tmpltStoredOn + .getId())) { + + } + } + errMsg = answer.getDetails(); + } + + return answer; + } + + protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) { + VolumeInfo volume = (VolumeInfo)srcData; + VolumeInfo destVolume = (VolumeInfo)destData; + String secondaryStorageURL = this.templateMgr.getSecondaryStorageURL(volume + .getDataCenterId()); + StoragePool srcPool = (StoragePool)this.dataStoreMgr.getDataStore(volume + .getPoolId(), DataStoreRole.Primary); + + StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(destVolume.getPoolId(), DataStoreRole.Primary); + + String value = this.configDao.getValue(Config.CopyVolumeWait.toString()); + int _copyvolumewait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); + CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), + volume.getPath(), srcPool, secondaryStorageURL, true, + _copyvolumewait); + CopyVolumeAnswer cvAnswer; + try { + cvAnswer = (CopyVolumeAnswer) this.storagMgr.sendToPool(srcPool, cvCmd); + } catch (StorageUnavailableException e1) { + throw new CloudRuntimeException( + "Failed to copy the volume from the source primary storage pool to secondary storage.", + e1); + } + + if (cvAnswer == null || !cvAnswer.getResult()) { + throw new CloudRuntimeException( + "Failed to copy the volume from the source primary storage pool to secondary storage."); + } + + String secondaryStorageVolumePath = cvAnswer.getVolumePath(); + + cvCmd = new CopyVolumeCommand(volume.getId(), + secondaryStorageVolumePath, destPool, + secondaryStorageURL, false, _copyvolumewait); + try { + cvAnswer = (CopyVolumeAnswer) this.storagMgr.sendToPool(destPool, cvCmd); + } catch (StorageUnavailableException e1) { + throw new CloudRuntimeException( + "Failed to copy the volume from secondary storage to the destination primary storage pool."); + } + + if (cvAnswer == null || !cvAnswer.getResult()) { + throw new CloudRuntimeException( + "Failed to copy the volume from secondary storage to the destination primary storage pool."); + } + + VolumeVO destVol = this.volDao.findById(destVolume.getId()); + destVol.setPath(cvAnswer.getVolumePath()); + this.volDao.update(destVol.getId(), destVol); + return cvAnswer; + } + + @Override + public Void copyAsync(DataObject srcData, DataObject destData, + AsyncCompletionCallback callback) { + Answer answer = null; + String errMsg = null; + try { + if (destData.getType() == DataObjectType.VOLUME + && srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Image) { + answer = copyVolumeFromImage(srcData, destData); + } else if (destData.getType() == DataObjectType.TEMPLATE + && srcData.getType() == DataObjectType.TEMPLATE) { + answer = copyTemplate(srcData, destData); + } else if (srcData.getType() == DataObjectType.SNAPSHOT + && destData.getType() == DataObjectType.VOLUME) { + answer = copyFromSnapshot(srcData, destData); + } else if (srcData.getType() == DataObjectType.SNAPSHOT + && destData.getType() == DataObjectType.TEMPLATE) { + answer = createTemplateFromSnashot(srcData, destData); + } else if (srcData.getType() == DataObjectType.VOLUME + && destData.getType() == DataObjectType.TEMPLATE) { + answer = createTemplateFromVolume(srcData, destData); + } else if (srcData.getType() == DataObjectType.TEMPLATE + && destData.getType() == DataObjectType.VOLUME) { + answer = cloneVolume(srcData, destData); + } else if (destData.getType() == DataObjectType.VOLUME + && srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) { + answer = copyVolumeBetweenPools(srcData, destData); + } else if (srcData.getType() == DataObjectType.SNAPSHOT && + destData.getType() == DataObjectType.SNAPSHOT) { + answer = copySnapshot(srcData, destData); + } + } catch (Exception e) { + s_logger.debug("copy failed", e); + errMsg = e.toString(); + } + CopyCommandResult result = new CopyCommandResult(null, answer); + result.setResult(errMsg); + callback.complete(result); + + return null; + } + + @DB + protected Answer createTemplateFromSnashot(DataObject srcData, + DataObject destData) { + long snapshotId = srcData.getId(); + SnapshotVO snapshot = snapshotDao.findById(snapshotId); + if (snapshot == null) { + throw new CloudRuntimeException("Unable to find Snapshot for Id " + + srcData.getId()); + } + Long zoneId = snapshot.getDataCenterId(); + HostVO secondaryStorageHost = this.templateMgr + .getSecondaryStorageHost(zoneId); + String secondaryStorageURL = snapshotMgr + .getSecondaryStorageURL(snapshot); + VMTemplateVO template = this.templateDao.findById(destData.getId()); + String name = template.getName(); + String backupSnapshotUUID = snapshot.getBackupSnapshotId(); + if (backupSnapshotUUID == null) { + throw new CloudRuntimeException( + "Unable to create private template from snapshot " + + snapshotId + + " due to there is no backupSnapshotUUID for this snapshot"); + } + + Long dcId = snapshot.getDataCenterId(); + Long accountId = snapshot.getAccountId(); + Long volumeId = snapshot.getVolumeId(); + + String origTemplateInstallPath = null; + List pools = this.storagMgr + .ListByDataCenterHypervisor(zoneId, + snapshot.getHypervisorType()); + if (pools == null || pools.size() == 0) { + throw new CloudRuntimeException( + "Unable to find storage pools in zone " + zoneId); + } + StoragePoolVO poolvo = pools.get(0); + StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore( + poolvo.getId(), DataStoreRole.Primary); + if (snapshot.getVersion() != null + && snapshot.getVersion().equalsIgnoreCase("2.1")) { + VolumeVO volume = this.volDao.findByIdIncludingRemoved(volumeId); + if (volume == null) { + throw new CloudRuntimeException("failed to upgrade snapshot " + + snapshotId + " due to unable to find orignal volume:" + + volumeId + ", try it later "); + } + if (volume.getTemplateId() == null) { + snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); + } else { + template = templateDao.findByIdIncludingRemoved(volume + .getTemplateId()); + if (template == null) { + throw new CloudRuntimeException( + "failed to upgrade snapshot " + + snapshotId + + " due to unalbe to find orignal template :" + + volume.getTemplateId() + + ", try it later "); + } + Long origTemplateId = template.getId(); + Long origTmpltAccountId = template.getAccountId(); + if (!this.volDao.lockInLockTable(volumeId.toString(), 10)) { + throw new CloudRuntimeException( + "failed to upgrade snapshot " + snapshotId + + " due to volume:" + volumeId + + " is being used, try it later "); + } + UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null, + secondaryStorageURL, dcId, accountId, volumeId, + origTemplateId, origTmpltAccountId, null, + snapshot.getBackupSnapshotId(), snapshot.getName(), + "2.1"); + if (!this.volDao.lockInLockTable(volumeId.toString(), 10)) { + throw new CloudRuntimeException( + "Creating template failed due to volume:" + + volumeId + + " is being used, try it later "); + } + Answer answer = null; + try { + answer = this.storagMgr.sendToPool(pool, cmd); + cmd = null; + } catch (StorageUnavailableException e) { + } finally { + this.volDao.unlockFromLockTable(volumeId.toString()); + } + if ((answer != null) && answer.getResult()) { + snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); + } else { + throw new CloudRuntimeException( + "Unable to upgrade snapshot"); + } + } + } + if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) { + snapshotMgr.downloadSnapshotsFromSwift(snapshot); + } + String value = configDao + .getValue(Config.CreatePrivateTemplateFromSnapshotWait + .toString()); + int _createprivatetemplatefromsnapshotwait = NumbersUtil.parseInt( + value, Integer + .parseInt(Config.CreatePrivateTemplateFromSnapshotWait + .getDefaultValue())); + + CreatePrivateTemplateFromSnapshotCommand cmd = new CreatePrivateTemplateFromSnapshotCommand( + pool, secondaryStorageURL, dcId, accountId, + snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(), + origTemplateInstallPath, template.getId(), name, + _createprivatetemplatefromsnapshotwait); + + return sendCommand(cmd, pool, template.getId(), dcId, + secondaryStorageHost.getId()); + } + + @DB + protected Answer sendCommand(Command cmd, StoragePool pool, + long templateId, long zoneId, long hostId) { + + CreatePrivateTemplateAnswer answer = null; + try { + answer = (CreatePrivateTemplateAnswer) this.storagMgr.sendToPool( + pool, cmd); + } catch (StorageUnavailableException e) { + throw new CloudRuntimeException( + "Failed to execute CreatePrivateTemplateFromSnapshotCommand", + e); + } + + if (answer == null || !answer.getResult()) { + return answer; + } + + VMTemplateVO privateTemplate = templateDao.findById(templateId); + String answerUniqueName = answer.getUniqueName(); + if (answerUniqueName != null) { + privateTemplate.setUniqueName(answerUniqueName); + } + ImageFormat format = answer.getImageFormat(); + if (format != null) { + privateTemplate.setFormat(format); + } else { + // This never occurs. + // Specify RAW format makes it unusable for snapshots. + privateTemplate.setFormat(ImageFormat.RAW); + } + + String checkSum = this.templateMgr + .getChecksum(hostId, answer.getPath()); + + Transaction txn = Transaction.currentTxn(); + + txn.start(); + + privateTemplate.setChecksum(checkSum); + templateDao.update(privateTemplate.getId(), privateTemplate); + + // add template zone ref for this template + templateDao.addTemplateToZone(privateTemplate, zoneId); + VMTemplateHostVO templateHostVO = new VMTemplateHostVO(hostId, + privateTemplate.getId()); + templateHostVO.setDownloadPercent(100); + templateHostVO.setDownloadState(Status.DOWNLOADED); + templateHostVO.setInstallPath(answer.getPath()); + templateHostVO.setLastUpdated(new Date()); + templateHostVO.setSize(answer.getVirtualSize()); + templateHostVO.setPhysicalSize(answer.getphysicalSize()); + templateHostDao.persist(templateHostVO); + txn.close(); + return answer; + } + + private Answer createTemplateFromVolume(DataObject srcObj, + DataObject destObj) { + long volumeId = srcObj.getId(); + VolumeVO volume = this.volDao.findById(volumeId); + if (volume == null) { + throw new CloudRuntimeException("Unable to find volume for Id " + + volumeId); + } + long accountId = volume.getAccountId(); + + String vmName = this.volumeMgr.getVmNameOnVolume(volume); + Long zoneId = volume.getDataCenterId(); + HostVO secondaryStorageHost = this.templateMgr + .getSecondaryStorageHost(zoneId); + if (secondaryStorageHost == null) { + throw new CloudRuntimeException( + "Can not find the secondary storage for zoneId " + zoneId); + } + String secondaryStorageURL = secondaryStorageHost.getStorageUrl(); + VMTemplateVO template = this.templateDao.findById(destObj.getId()); + StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore( + volume.getPoolId(), DataStoreRole.Primary); + String value = configDao + .getValue(Config.CreatePrivateTemplateFromVolumeWait.toString()); + int _createprivatetemplatefromvolumewait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CreatePrivateTemplateFromVolumeWait + .getDefaultValue())); + + CreatePrivateTemplateFromVolumeCommand cmd = new CreatePrivateTemplateFromVolumeCommand( + pool, secondaryStorageURL, destObj.getId(), accountId, + template.getName(), template.getUniqueName(), volume.getPath(), + vmName, _createprivatetemplatefromvolumewait); + + return sendCommand(cmd, pool, template.getId(), zoneId, + secondaryStorageHost.getId()); + } + + private HostVO getSecHost(long volumeId, long dcId) { + Long id = snapshotDao.getSecHostId(volumeId); + if ( id != null) { + return hostDao.findById(id); + } + return this.templateMgr.getSecondaryStorageHost(dcId); + } + + protected Answer copySnapshot(DataObject srcObject, DataObject destObject) { + SnapshotInfo srcSnapshot = (SnapshotInfo)srcObject; + VolumeInfo baseVolume = srcSnapshot.getBaseVolume(); + Long dcId = baseVolume.getDataCenterId(); + Long accountId = baseVolume.getAccountId(); + + HostVO secHost = getSecHost(baseVolume.getId(), baseVolume.getDataCenterId()); + + String secondaryStoragePoolUrl = secHost.getStorageUrl(); + String snapshotUuid = srcSnapshot.getPath(); + // In order to verify that the snapshot is not empty, + // we check if the parent of the snapshot is not the same as the parent of the previous snapshot. + // We pass the uuid of the previous snapshot to the plugin to verify this. + SnapshotVO prevSnapshot = null; + String prevSnapshotUuid = null; + String prevBackupUuid = null; + + + SwiftTO swift = _swiftMgr.getSwiftTO(); + S3TO s3 = _s3Mgr.getS3TO(); + + long prevSnapshotId = srcSnapshot.getPrevSnapshotId(); + if (prevSnapshotId > 0) { + prevSnapshot = snapshotDao.findByIdIncludingRemoved(prevSnapshotId); + if ( prevSnapshot.getBackupSnapshotId() != null && swift == null) { + if (prevSnapshot.getVersion() != null && prevSnapshot.getVersion().equals("2.2")) { + prevBackupUuid = prevSnapshot.getBackupSnapshotId(); + prevSnapshotUuid = prevSnapshot.getPath(); + } + } else if ((prevSnapshot.getSwiftId() != null && swift != null) + || (prevSnapshot.getS3Id() != null && s3 != null)) { + prevBackupUuid = prevSnapshot.getBackupSnapshotId(); + prevSnapshotUuid = prevSnapshot.getPath(); + } + } + boolean isVolumeInactive = this.volumeMgr.volumeInactive(baseVolume); + String vmName = this.volumeMgr.getVmNameOnVolume(baseVolume); + StoragePool srcPool = (StoragePool)dataStoreMgr.getPrimaryDataStore(baseVolume.getPoolId()); + String value = configDao.getValue(Config.BackupSnapshotWait.toString()); + int _backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue())); + BackupSnapshotCommand backupSnapshotCommand = new BackupSnapshotCommand(secondaryStoragePoolUrl, dcId, accountId, baseVolume.getId(), srcSnapshot.getId(), baseVolume.getPath(), srcPool, snapshotUuid, + srcSnapshot.getName(), prevSnapshotUuid, prevBackupUuid, isVolumeInactive, vmName, _backupsnapshotwait); + + if ( swift != null ) { + backupSnapshotCommand.setSwift(swift); + } else if (s3 != null) { + backupSnapshotCommand.setS3(s3); + } + BackupSnapshotAnswer answer = (BackupSnapshotAnswer) this.snapshotMgr.sendToPool(baseVolume, backupSnapshotCommand); + if (answer != null && answer.getResult()) { + SnapshotVO snapshotVO = this.snapshotDao.findById(srcSnapshot.getId()); + if (backupSnapshotCommand.getSwift() != null ) { + snapshotVO.setSwiftId(swift.getId()); + snapshotVO.setBackupSnapshotId(answer.getBackupSnapshotName()); + } else if (backupSnapshotCommand.getS3() != null) { + snapshotVO.setS3Id(s3.getId()); + snapshotVO.setBackupSnapshotId(answer.getBackupSnapshotName()); + } else { + snapshotVO.setSecHostId(secHost.getId()); + snapshotVO.setBackupSnapshotId(answer.getBackupSnapshotName()); + } + if (answer.isFull()) { + snapshotVO.setPrevSnapshotId(0L); + } + this.snapshotDao.update(srcSnapshot.getId(), snapshotVO); + } + return answer; + } + +} diff --git a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java index 6a7d78a972a..0a91186aaab 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java @@ -105,13 +105,6 @@ public class SnapshotEntityImpl implements SnapshotEntity { return null; } - @Override - public Type getType() { - // TODO Auto-generated method stub - return null; - } - - @Override public HypervisorType getHypervisorType() { // TODO Auto-generated method stub @@ -190,4 +183,10 @@ public class SnapshotEntityImpl implements SnapshotEntity { return null; } + @Override + public Type getRecurringType() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotService.java b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotService.java index d50c9a0c8f3..f3e5c4aea50 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotService.java +++ b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotService.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.storage.snapshot; import org.apache.cloudstack.engine.cloud.entity.api.SnapshotEntity; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; public interface SnapshotService { public SnapshotEntity getSnapshotEntity(long snapshotId); diff --git a/engine/storage/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/engine/storage/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java index cd67b97b02c..aa47e8f4977 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java @@ -21,12 +21,12 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; public class PrimaryDataStoreTO { private final String uuid; private final String name; - private final String type; + private String type; private final long id; public PrimaryDataStoreTO(PrimaryDataStoreInfo dataStore) { this.uuid = dataStore.getUuid(); this.name = dataStore.getName(); - this.type = dataStore.getType(); + // this.type = dataStore.getType(); this.id = dataStore.getId(); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/to/TemplateTO.java b/engine/storage/src/org/apache/cloudstack/storage/to/TemplateTO.java index ed5990986e5..bc55ea8c3ea 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/to/TemplateTO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/to/TemplateTO.java @@ -16,8 +16,8 @@ // under the License. package org.apache.cloudstack.storage.to; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreInfo; public class TemplateTO { diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/TemplateOnPrimaryDataStoreInfo.java b/engine/storage/src/org/apache/cloudstack/storage/volume/TemplateOnPrimaryDataStoreInfo.java index 368c33a32bf..b8d0857d495 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/TemplateOnPrimaryDataStoreInfo.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/TemplateOnPrimaryDataStoreInfo.java @@ -18,8 +18,8 @@ */ package org.apache.cloudstack.storage.volume; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; -import org.apache.cloudstack.storage.image.TemplateInfo; public interface TemplateOnPrimaryDataStoreInfo { public String getPath(); diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java index 20ceaa303fc..c6ca90d1641 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java @@ -23,40 +23,38 @@ import java.util.Map; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; -import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.exception.CloudRuntimeException; @Component public class PrimaryDataStoreHelper { @Inject private PrimaryDataStoreDao dataStoreDao; - public PrimaryDataStoreVO createPrimaryDataStore(Map params) { - PrimaryDataStoreVO dataStoreVO = dataStoreDao.findPoolByUUID(params.get("uuid")); + public StoragePoolVO createPrimaryDataStore(Map params) { + StoragePoolVO dataStoreVO = dataStoreDao.findPoolByUUID((String)params.get("uuid")); if (dataStoreVO != null) { throw new CloudRuntimeException("duplicate uuid: " + params.get("uuid")); } - dataStoreVO = new PrimaryDataStoreVO(); - dataStoreVO.setStorageProviderId(Long.parseLong(params.get("providerId"))); - dataStoreVO.setHostAddress(params.get("server")); - dataStoreVO.setPath(params.get("path")); - dataStoreVO.setPoolType(params.get("protocol")); - dataStoreVO.setPort(Integer.parseInt(params.get("port"))); - dataStoreVO.setName(params.get("name")); - dataStoreVO.setUuid(params.get("uuid")); + dataStoreVO = new StoragePoolVO(); + dataStoreVO.setStorageProviderId(Long.parseLong((String)params.get("providerId"))); + dataStoreVO.setHostAddress((String)params.get("server")); + dataStoreVO.setPath((String)params.get("path")); + dataStoreVO.setPoolType((StoragePoolType)params.get("protocol")); + dataStoreVO.setPort(Integer.parseInt((String)params.get("port"))); + dataStoreVO.setName((String)params.get("name")); + dataStoreVO.setUuid((String)params.get("uuid")); dataStoreVO = dataStoreDao.persist(dataStoreVO); return dataStoreVO; } public boolean deletePrimaryDataStore(long id) { - PrimaryDataStoreVO dataStoreVO = dataStoreDao.findById(id); + StoragePoolVO dataStoreVO = dataStoreDao.findById(id); if (dataStoreVO == null) { throw new CloudRuntimeException("can't find store: " + id); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDao.java b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDao.java index 45ff1ec2258..63cdb16c596 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDao.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDao.java @@ -18,7 +18,7 @@ */ package org.apache.cloudstack.storage.volume.db; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import com.cloud.utils.db.GenericDao; import com.cloud.utils.fsm.StateDao; diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDaoImpl.java index b47f08881e1..ad561502266 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDaoImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDaoImpl.java @@ -20,9 +20,9 @@ package org.apache.cloudstack.storage.volume.db; import java.util.Date; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.State; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreVO.java b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreVO.java index 2d355df7e2a..48a9f334a19 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreVO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreVO.java @@ -32,7 +32,9 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; + +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.fsm.StateObject; diff --git a/engine/storage/volume/pom.xml b/engine/storage/volume/pom.xml index e424cab5d0e..19357ab11e4 100644 --- a/engine/storage/volume/pom.xml +++ b/engine/storage/volume/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java index 9c009c95623..f2a999330ad 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java @@ -18,45 +18,50 @@ package org.apache.cloudstack.storage.datastore; import java.io.File; import java.util.ArrayList; +import java.util.Date; import java.util.List; import javax.inject.Inject; -import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProvider; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.ImageDataFactory; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.snapshot.SnapshotDataFactory; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.volume.VolumeObject; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.apache.log4j.Logger; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.storage.encoding.EncodingType; public class DefaultPrimaryDataStore implements PrimaryDataStore { private static final Logger s_logger = Logger .getLogger(DefaultPrimaryDataStore.class); protected PrimaryDataStoreDriver driver; - protected PrimaryDataStoreVO pdsv; + protected StoragePoolVO pdsv; @Inject protected PrimaryDataStoreDao dataStoreDao; protected PrimaryDataStoreLifeCycle lifeCycle; @@ -67,15 +72,16 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Inject SnapshotDataFactory snapshotFactory; protected DataStoreProvider provider; - @Inject - private VolumeDao2 volumeDao; + VMTemplatePoolDao templatePoolDao; + + private VolumeDao volumeDao; protected DefaultPrimaryDataStore() { } - public void configure(PrimaryDataStoreVO pdsv, + public void configure(StoragePoolVO pdsv, PrimaryDataStoreDriver driver, DataStoreProvider provider) { this.pdsv = pdsv; this.driver = driver; @@ -83,7 +89,7 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { } public static DefaultPrimaryDataStore createDataStore( - PrimaryDataStoreVO pdsv, PrimaryDataStoreDriver driver, + StoragePoolVO pdsv, PrimaryDataStoreDriver driver, DataStoreProvider provider) { DefaultPrimaryDataStore dataStore = (DefaultPrimaryDataStore)ComponentContext.inject(DefaultPrimaryDataStore.class); dataStore.configure(pdsv, driver, provider); @@ -109,19 +115,16 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Override public DataStoreDriver getDriver() { - // TODO Auto-generated method stub return this.driver; } @Override public DataStoreRole getRole() { - // TODO Auto-generated method stub return DataStoreRole.Primary; } @Override public long getId() { - // TODO Auto-generated method stub return this.pdsv.getId(); } @@ -143,7 +146,7 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Override public Scope getScope() { - PrimaryDataStoreVO vo = dataStoreDao.findById(this.pdsv.getId()); + StoragePoolVO vo = dataStoreDao.findById(this.pdsv.getId()); if (vo.getScope() == ScopeType.CLUSTER) { return new ClusterScope(vo.getClusterId(), vo.getPodId(), vo.getDataCenterId()); @@ -156,7 +159,7 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Override public boolean isHypervisorSupported(HypervisorType hypervisor) { // TODO Auto-generated method stub - return false; + return true; } @Override @@ -171,28 +174,10 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { return false; } - @Override - public long getCapacity() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public long getAvailableCapacity() { - // TODO Auto-generated method stub - return 0; - } @Override public String getUuid() { - // TODO Auto-generated method stub - return null; - } - - @Override - public State getManagedState() { - // TODO Auto-generated method stub - return null; + return this.pdsv.getUuid(); } @Override @@ -201,12 +186,6 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { return null; } - @Override - public String getType() { - // TODO Auto-generated method stub - return null; - } - @Override public PrimaryDataStoreLifeCycle getLifeCycle() { return this.lifeCycle; @@ -214,14 +193,13 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Override public boolean exists(DataObject data) { - return (objectInStoreMgr.findObject(data.getId(), data.getType(), - this.getId(), this.getRole()) != null) ? true : false; + return (objectInStoreMgr.findObject(data, data.getDataStore()) != null) ? true : false; } @Override public TemplateInfo getTemplate(long templateId) { - ObjectInDataStoreVO obj = objectInStoreMgr.findObject(templateId, DataObjectType.TEMPLATE, this.getId(), this.getRole()); - if (obj == null) { + VMTemplateStoragePoolVO template = templatePoolDao.findByPoolTemplate(this.getId(), templateId); + if (template == null || template.getState() != ObjectInDataStoreStateMachine.State.Ready) { return null; } return imageDataFactory.getTemplate(templateId, this); @@ -238,4 +216,117 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { // TODO Auto-generated method stub return null; } + + @Override + public DataObject create(DataObject obj) { + //create template on primary storage + if (obj.getType() == DataObjectType.TEMPLATE) { + VMTemplateStoragePoolVO templateStoragePoolRef = templatePoolDao.findByPoolTemplate(this.getId(), obj.getId()); + if (templateStoragePoolRef == null) { + try { + templateStoragePoolRef = new VMTemplateStoragePoolVO(this.getId(), obj.getId()); + templateStoragePoolRef = templatePoolDao.persist(templateStoragePoolRef); + } catch (Throwable t) { + templateStoragePoolRef = templatePoolDao.findByPoolTemplate(this.getId(), obj.getId()); + if (templateStoragePoolRef == null) { + throw new CloudRuntimeException("Failed to create template storage pool entry"); + } + } + } + + } + + return objectInStoreMgr.get(obj, this); + } + + @Override + public boolean delete(DataObject obj) { + // TODO Auto-generated method stub + return false; + } + + @Override + public long getDataCenterId() { + return this.pdsv.getDataCenterId(); + } + + @Override + public String getPath() { + return this.pdsv.getPath(); + } + + @Override + public StoragePoolType getPoolType() { + return this.pdsv.getPoolType(); + } + + @Override + public Date getCreated() { + return this.pdsv.getCreated(); + } + + @Override + public Date getUpdateTime() { + return this.pdsv.getUpdateTime(); + } + + @Override + public long getCapacityBytes() { + return this.pdsv.getCapacityBytes(); + } + + @Override + public long getAvailableBytes() { + return this.pdsv.getAvailableBytes(); + } + + @Override + public Long getClusterId() { + return this.pdsv.getClusterId(); + } + + @Override + public String getHostAddress() { + return this.pdsv.getHostAddress(); + } + + @Override + public String getUserInfo() { + return this.pdsv.getUserInfo(); + } + + @Override + public boolean isShared() { + return this.pdsv.getScope() == ScopeType.HOST ? false : true; + } + + @Override + public boolean isLocal() { + return !this.isShared(); + } + + @Override + public StoragePoolStatus getStatus() { + return this.pdsv.getStatus(); + } + + @Override + public int getPort() { + return this.pdsv.getPort(); + } + + @Override + public Long getPodId() { + return this.pdsv.getPodId(); + } + + @Override + public Long getStorageProviderId() { + return this.pdsv.getStorageProviderId(); + } + + @Override + public boolean isInMaintenance() { + return this.getStatus() == StoragePoolStatus.Maintenance ? true : false; + } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/AncientPrimaryDataStoreDriverImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/AncientPrimaryDataStoreDriverImpl.java new file mode 100644 index 00000000000..440cb8c5ea0 --- /dev/null +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/AncientPrimaryDataStoreDriverImpl.java @@ -0,0 +1,362 @@ +/* + * 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.storage.datastore.driver; + +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.volume.VolumeObject; +import org.apache.log4j.Logger; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ManageSnapshotAnswer; +import com.cloud.agent.api.ManageSnapshotCommand; +import com.cloud.agent.api.storage.CreateAnswer; +import com.cloud.agent.api.storage.CreateCommand; +import com.cloud.agent.api.storage.DestroyCommand; +import com.cloud.agent.api.storage.ResizeVolumeAnswer; +import com.cloud.agent.api.storage.ResizeVolumeCommand; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.ResizeVolumePayload; +import com.cloud.storage.Storage; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.template.TemplateManager; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.dao.VMInstanceDao; + +public class AncientPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver { + private static final Logger s_logger = Logger + .getLogger(AncientPrimaryDataStoreDriverImpl.class); + @Inject DiskOfferingDao diskOfferingDao; + @Inject VMTemplateDao templateDao; + @Inject VolumeDao volumeDao; + @Inject TemplateManager templateMgr; + @Inject HostDao hostDao; + @Inject StorageManager storageMgr; + @Inject VolumeManager volumeMgr; + @Inject VMInstanceDao vmDao; + @Inject SnapshotDao snapshotDao; + @Inject PrimaryDataStoreDao primaryStoreDao; + @Inject SnapshotManager snapshotMgr; + @Override + public String grantAccess(DataObject data, EndPoint ep) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean revokeAccess(DataObject data, EndPoint ep) { + // TODO Auto-generated method stub + return false; + } + + @Override + public Set listObjects(DataStore store) { + // TODO Auto-generated method stub + return null; + } + + public boolean createVolume( + VolumeInfo volume) throws StorageUnavailableException { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating volume: " + volume); + } + + DiskOfferingVO offering = diskOfferingDao.findById(volume.getDiskOfferingId()); + DiskProfile diskProfile = new DiskProfile(volume, offering, + null); + + VMTemplateVO template = null; + if (volume.getTemplateId() != null) { + template = templateDao.findById(volume.getTemplateId()); + } + + StoragePool pool = (StoragePool)volume.getDataStore(); + VolumeVO vol = volumeDao.findById(volume.getId()); + if (pool != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Trying to create in " + pool); + } + vol.setPoolId(pool.getId()); + + CreateCommand cmd = null; + VMTemplateStoragePoolVO tmpltStoredOn = null; + + for (int i = 0; i < 2; i++) { + if (template != null + && template.getFormat() != Storage.ImageFormat.ISO) { + if (pool.getPoolType() == StoragePoolType.CLVM) { + // prepareISOForCreate does what we need, which is to + // tell us where the template is + VMTemplateHostVO tmpltHostOn = templateMgr + .prepareISOForCreate(template, pool); + if (tmpltHostOn == null) { + s_logger.debug("cannot find template " + + template.getId() + " " + + template.getName()); + throw new CloudRuntimeException("cannot find template" + + template.getId() + + template.getName()); + } + HostVO secondaryStorageHost = hostDao + .findById(tmpltHostOn.getHostId()); + String tmpltHostUrl = secondaryStorageHost + .getStorageUrl(); + String fullTmpltUrl = tmpltHostUrl + "/" + + tmpltHostOn.getInstallPath(); + cmd = new CreateCommand(diskProfile, fullTmpltUrl, + new StorageFilerTO(pool)); + } else { + tmpltStoredOn = templateMgr.prepareTemplateForCreate( + template, pool); + if (tmpltStoredOn == null) { + s_logger.debug("Cannot use this pool " + pool + + " because we can't propagate template " + + template); + throw new CloudRuntimeException("Cannot use this pool " + pool + + " because we can't propagate template " + + template); + } + cmd = new CreateCommand(diskProfile, + tmpltStoredOn.getLocalDownloadPath(), + new StorageFilerTO(pool)); + } + } else { + if (template != null + && Storage.ImageFormat.ISO == template.getFormat()) { + VMTemplateHostVO tmpltHostOn = templateMgr + .prepareISOForCreate(template, pool); + if (tmpltHostOn == null) { + throw new CloudRuntimeException( + "Did not find ISO in secondry storage in zone " + + pool.getDataCenterId()); + } + } + cmd = new CreateCommand(diskProfile, new StorageFilerTO( + pool)); + } + + Answer answer = storageMgr.sendToPool(pool, null, cmd); + if (answer.getResult()) { + CreateAnswer createAnswer = (CreateAnswer) answer; + vol.setFolder(pool.getPath()); + vol.setPath(createAnswer.getVolume().getPath()); + vol.setSize(createAnswer.getVolume().getSize()); + vol.setPoolType(pool.getPoolType()); + vol.setPoolId(pool.getId()); + vol.setPodId(pool.getPodId()); + this.volumeDao.update(vol.getId(), vol); + return true; + } else { + if (tmpltStoredOn != null + && (answer instanceof CreateAnswer) + && ((CreateAnswer) answer) + .templateReloadRequested()) { + if (!templateMgr + .resetTemplateDownloadStateOnPool(tmpltStoredOn + .getId())) { + break; // break out of template-redeploy retry loop + } + } else { + break; + } + } + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Unable to create volume " + volume.getId()); + } + return false; + } + + @Override + public void createAsync(DataObject data, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + String errMsg = null; + if (data.getType() == DataObjectType.VOLUME) { + try { + createVolume((VolumeInfo)data); + } catch (StorageUnavailableException e) { + s_logger.debug("failed to create volume", e); + errMsg = e.toString(); + } catch (Exception e) { + s_logger.debug("failed to create volume", e); + errMsg = e.toString(); + } + } + CreateCmdResult result = new CreateCmdResult(null, null); + if (errMsg != null) { + result.setResult(errMsg); + } + + callback.complete(result); + + } + + @Override + public void deleteAsync(DataObject data, + AsyncCompletionCallback callback) { + + String vmName = null; + VolumeVO vol = this.volumeDao.findById(data.getId()); + + + StoragePool pool = (StoragePool)data.getDataStore(); + + DestroyCommand cmd = new DestroyCommand(pool, vol, vmName); + + CommandResult result = new CommandResult(); + try { + Answer answer = this.storageMgr.sendToPool(pool, cmd); + if (answer != null && !answer.getResult()) { + result.setResult(answer.getDetails()); + s_logger.info("Will retry delete of " + vol + " from " + pool.getId()); + } + } catch (StorageUnavailableException e) { + s_logger.error("Storage is unavailable currently. Will retry delete of " + + vol + " from " + pool.getId(), e); + result.setResult(e.toString()); + } catch (Exception ex) { + s_logger.debug("Unable to destoy volume" + vol + " from " + pool.getId(), ex); + result.setResult(ex.toString()); + } + callback.complete(result); + } + + @Override + public void copyAsync(DataObject srcdata, DataObject destData, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + + @Override + public boolean canCopy(DataObject srcData, DataObject destData) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void takeSnapshot(SnapshotInfo snapshot, + AsyncCompletionCallback callback) { + CreateCmdResult result = null; + try { + VolumeInfo volume = snapshot.getBaseVolume(); + String vmName = this.volumeMgr.getVmNameOnVolume(volume); + SnapshotVO preSnapshotVO = this.snapshotMgr.getParentSnapshot(volume, snapshot); + String parentSnapshotPath = null; + if (preSnapshotVO != null) { + parentSnapshotPath = preSnapshotVO.getPath(); + } + StoragePool srcPool = (StoragePool)volume.getDataStore(); + + ManageSnapshotCommand cmd = new ManageSnapshotCommand(snapshot.getId(), volume.getPath(), srcPool, parentSnapshotPath, snapshot.getName(), vmName); + + ManageSnapshotAnswer answer = (ManageSnapshotAnswer) this.snapshotMgr.sendToPool(volume, cmd); + + if ((answer != null) && answer.getResult()) { + result = new CreateCmdResult(answer.getSnapshotPath(), null); + } else { + result = new CreateCmdResult(null, null); + } + } catch (Exception e) { + s_logger.debug("Failed to take snapshot: " + snapshot.getId(), e); + result = new CreateCmdResult(null, null); + result.setResult(e.toString()); + } + callback.complete(result); + } + + @Override + public void revertSnapshot(SnapshotInfo snapshot, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + + @Override + public void resize(DataObject data, + AsyncCompletionCallback callback) { + VolumeObject vol = (VolumeObject)data; + StoragePool pool = (StoragePool)data.getDataStore(); + ResizeVolumePayload resizeParameter = (ResizeVolumePayload)vol.getpayload(); + + ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand( + vol.getPath(), new StorageFilerTO(pool), vol.getSize(), + resizeParameter.newSize, resizeParameter.shrinkOk, resizeParameter.instanceName); + CreateCmdResult result = new CreateCmdResult(null, null); + try { + ResizeVolumeAnswer answer = (ResizeVolumeAnswer) this.storageMgr.sendToPool(pool, + resizeParameter.hosts, resizeCmd); + if (answer != null && answer.getResult()) { + long finalSize = answer.getNewSize(); + s_logger.debug("Resize: volume started at size " + vol.getSize() + + " and ended at size " + finalSize); + + vol.setSize(finalSize); + vol.update(); + } else if (answer != null) { + result.setResult(answer.getDetails()); + } else { + s_logger.debug("return a null answer, mark it as failed for unknown reason"); + result.setResult("return a null answer, mark it as failed for unknown reason"); + } + + } catch (Exception e) { + s_logger.debug("sending resize command failed", e); + result.setResult(e.toString()); + } + + callback.complete(result); + } + +} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java index dfe4518edab..6d0c2c6862b 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java @@ -27,6 +27,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcConext; @@ -35,8 +37,6 @@ import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.datastore.DataObjectManager; import org.apache.cloudstack.storage.endpoint.EndPointSelector; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; @@ -210,13 +210,6 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver return null; } - @Override - public void takeSnapshot(SnapshotInfo snapshot, - AsyncCompletionCallback callback) { - // TODO Auto-generated method stub - - } - @Override public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback) { @@ -238,5 +231,19 @@ public class DefaultPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver // TODO Auto-generated method stub } + + @Override + public void resize(DataObject data, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + + @Override + public void takeSnapshot(SnapshotInfo snapshot, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/AncientPrimaryDataStoreLifeCyclImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/AncientPrimaryDataStoreLifeCyclImpl.java new file mode 100644 index 00000000000..2167ba19a32 --- /dev/null +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/AncientPrimaryDataStoreLifeCyclImpl.java @@ -0,0 +1,958 @@ +/* + * 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.storage.datastore.lifecycle; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreStatus; +import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CreateStoragePoolCommand; +import com.cloud.agent.api.DeleteStoragePoolCommand; +import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.alert.AlertManager; +import com.cloud.capacity.Capacity; +import com.cloud.capacity.CapacityVO; +import com.cloud.capacity.dao.CapacityDao; +import com.cloud.exception.DiscoveryException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.Status; +import com.cloud.resource.ResourceManager; +import com.cloud.server.ManagementServer; +import com.cloud.storage.OCFS2Manager; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolDiscoverer; +import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.StoragePoolWorkVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.StoragePoolWorkDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.User; +import com.cloud.user.UserContext; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.UriUtils; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.exception.ExecutionException; +import com.cloud.vm.ConsoleProxyVO; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.SecondaryStorageVmVO; +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.dao.ConsoleProxyDao; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.SecondaryStorageVmDao; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + +public class AncientPrimaryDataStoreLifeCyclImpl implements + PrimaryDataStoreLifeCycle { + private static final Logger s_logger = Logger + .getLogger(AncientPrimaryDataStoreLifeCyclImpl.class); + @Inject + protected ResourceManager _resourceMgr; + protected List _discoverers; + @Inject + PrimaryDataStoreDao primaryDataStoreDao; + @Inject + protected OCFS2Manager _ocfs2Mgr; + @Inject + DataStoreManager dataStoreMgr; + @Inject + AgentManager agentMgr; + @Inject + StorageManager storageMgr; + @Inject + protected CapacityDao _capacityDao; + + @Inject + VolumeDao volumeDao; + @Inject + VMInstanceDao vmDao; + @Inject + ManagementServer server; + @Inject + protected VirtualMachineManager vmMgr; + @Inject + protected SecondaryStorageVmDao _secStrgDao; + @Inject + UserVmDao userVmDao; + @Inject + protected UserDao _userDao; + @Inject + protected DomainRouterDao _domrDao; + @Inject + protected StoragePoolHostDao _storagePoolHostDao; + @Inject + protected AlertManager _alertMgr; + + + + @Inject + protected ConsoleProxyDao _consoleProxyDao; + + @Inject + protected StoragePoolWorkDao _storagePoolWorkDao; + + @Override + public DataStore initialize(Map dsInfos) { + Long clusterId = (Long) dsInfos.get("clusterId"); + Long podId = (Long) dsInfos.get("podId"); + Long zoneId = (Long) dsInfos.get("zoneId"); + String url = (String) dsInfos.get("url"); + Long providerId = (Long)dsInfos.get("providerId"); + if (clusterId != null && podId == null) { + throw new InvalidParameterValueException( + "Cluster id requires pod id"); + } + + URI uri = null; + try { + uri = new URI(UriUtils.encodeURIComponent(url)); + if (uri.getScheme() == null) { + throw new InvalidParameterValueException("scheme is null " + + url + ", add nfs:// as a prefix"); + } else if (uri.getScheme().equalsIgnoreCase("nfs")) { + String uriHost = uri.getHost(); + String uriPath = uri.getPath(); + if (uriHost == null || uriPath == null + || uriHost.trim().isEmpty() || uriPath.trim().isEmpty()) { + throw new InvalidParameterValueException( + "host or path is null, should be nfs://hostname/path"); + } + } else if (uri.getScheme().equalsIgnoreCase("sharedMountPoint")) { + String uriPath = uri.getPath(); + if (uriPath == null) { + throw new InvalidParameterValueException( + "host or path is null, should be sharedmountpoint://localhost/path"); + } + } else if (uri.getScheme().equalsIgnoreCase("rbd")) { + String uriPath = uri.getPath(); + if (uriPath == null) { + throw new InvalidParameterValueException( + "host or path is null, should be rbd://hostname/pool"); + } + } + } catch (URISyntaxException e) { + throw new InvalidParameterValueException(url + + " is not a valid uri"); + } + + String tags = (String) dsInfos.get("tags"); + Map details = (Map) dsInfos + .get("details"); + if (tags != null) { + String[] tokens = tags.split(","); + + for (String tag : tokens) { + tag = tag.trim(); + if (tag.length() == 0) { + continue; + } + details.put(tag, "true"); + } + } + + String scheme = uri.getScheme(); + String storageHost = uri.getHost(); + String hostPath = uri.getPath(); + Object localStorage = dsInfos.get("localStorage"); + if (localStorage != null) { + hostPath = hostPath.replace("/", ""); + } + String userInfo = uri.getUserInfo(); + int port = uri.getPort(); + StoragePoolVO pool = null; + if (s_logger.isDebugEnabled()) { + s_logger.debug("createPool Params @ scheme - " + scheme + + " storageHost - " + storageHost + " hostPath - " + + hostPath + " port - " + port); + } + if (scheme.equalsIgnoreCase("nfs")) { + if (port == -1) { + port = 2049; + } + pool = new StoragePoolVO(StoragePoolType.NetworkFilesystem, + storageHost, port, hostPath); + if (clusterId == null) { + throw new IllegalArgumentException( + "NFS need to have clusters specified for XenServers"); + } + } else if (scheme.equalsIgnoreCase("file")) { + if (port == -1) { + port = 0; + } + pool = new StoragePoolVO(StoragePoolType.Filesystem, + "localhost", 0, hostPath); + } else if (scheme.equalsIgnoreCase("sharedMountPoint")) { + pool = new StoragePoolVO(StoragePoolType.SharedMountPoint, + storageHost, 0, hostPath); + } else if (scheme.equalsIgnoreCase("clvm")) { + pool = new StoragePoolVO(StoragePoolType.CLVM, storageHost, 0, + hostPath.replaceFirst("/", "")); + } else if (scheme.equalsIgnoreCase("rbd")) { + if (port == -1) { + port = 6789; + } + pool = new StoragePoolVO(StoragePoolType.RBD, storageHost, + port, hostPath.replaceFirst("/", "")); + pool.setUserInfo(userInfo); + } else if (scheme.equalsIgnoreCase("PreSetup")) { + pool = new StoragePoolVO(StoragePoolType.PreSetup, + storageHost, 0, hostPath); + } else if (scheme.equalsIgnoreCase("iscsi")) { + String[] tokens = hostPath.split("/"); + int lun = NumbersUtil.parseInt(tokens[tokens.length - 1], -1); + if (port == -1) { + port = 3260; + } + if (lun != -1) { + if (clusterId == null) { + throw new IllegalArgumentException( + "IscsiLUN need to have clusters specified"); + } + hostPath.replaceFirst("/", ""); + pool = new StoragePoolVO(StoragePoolType.IscsiLUN, + storageHost, port, hostPath); + } else { + for (StoragePoolDiscoverer discoverer : _discoverers) { + Map> pools; + try { + pools = discoverer.find(zoneId, podId, uri, details); + } catch (DiscoveryException e) { + throw new IllegalArgumentException( + "Not enough information for discovery " + uri, + e); + } + if (pools != null) { + Map.Entry> entry = pools + .entrySet().iterator().next(); + pool = entry.getKey(); + details = entry.getValue(); + break; + } + } + } + } else if (scheme.equalsIgnoreCase("iso")) { + if (port == -1) { + port = 2049; + } + pool = new StoragePoolVO(StoragePoolType.ISO, storageHost, + port, hostPath); + } else if (scheme.equalsIgnoreCase("vmfs")) { + pool = new StoragePoolVO(StoragePoolType.VMFS, + "VMFS datastore: " + hostPath, 0, hostPath); + } else if (scheme.equalsIgnoreCase("ocfs2")) { + port = 7777; + pool = new StoragePoolVO(StoragePoolType.OCFS2, "clustered", + port, hostPath); + } else { + StoragePoolType type = Enum.valueOf(StoragePoolType.class, scheme); + + if (type != null) { + pool = new StoragePoolVO(type, storageHost, + 0, hostPath); + } else { + s_logger.warn("Unable to figure out the scheme for URI: " + uri); + throw new IllegalArgumentException( + "Unable to figure out the scheme for URI: " + uri); + } + } + + if (pool == null) { + s_logger.warn("Unable to figure out the scheme for URI: " + uri); + throw new IllegalArgumentException( + "Unable to figure out the scheme for URI: " + uri); + } + + if (localStorage == null) { + List pools = primaryDataStoreDao + .listPoolByHostPath(storageHost, hostPath); + if (!pools.isEmpty() && !scheme.equalsIgnoreCase("sharedmountpoint")) { + Long oldPodId = pools.get(0).getPodId(); + throw new CloudRuntimeException("Storage pool " + uri + + " already in use by another pod (id=" + oldPodId + ")"); + } + } + + long poolId = primaryDataStoreDao.getNextInSequence(Long.class, "id"); + Object existingUuid = dsInfos.get("uuid"); + String uuid = null; + + if (existingUuid != null) { + uuid = (String)existingUuid; + } else if (scheme.equalsIgnoreCase("sharedmountpoint") + || scheme.equalsIgnoreCase("clvm")) { + uuid = UUID.randomUUID().toString(); + } else if (scheme.equalsIgnoreCase("PreSetup")) { + uuid = hostPath.replace("/", ""); + } else { + uuid = UUID.nameUUIDFromBytes( + new String(storageHost + hostPath).getBytes()).toString(); + } + + List spHandles = primaryDataStoreDao + .findIfDuplicatePoolsExistByUUID(uuid); + if ((spHandles != null) && (spHandles.size() > 0)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Another active pool with the same uuid already exists"); + } + throw new CloudRuntimeException( + "Another active pool with the same uuid already exists"); + } + + String poolName = (String) dsInfos.get("name"); + if (s_logger.isDebugEnabled()) { + s_logger.debug("In createPool Setting poolId - " + poolId + + " uuid - " + uuid + " zoneId - " + zoneId + " podId - " + + podId + " poolName - " + poolName); + } + + pool.setId(poolId); + pool.setUuid(uuid); + pool.setDataCenterId(zoneId); + pool.setPodId(podId); + pool.setName(poolName); + pool.setClusterId(clusterId); + pool.setStorageProviderId(providerId); + pool.setStatus(StoragePoolStatus.Initialized); + pool = primaryDataStoreDao.persist(pool, details); + + return dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); + } + + protected boolean createStoragePool(long hostId, StoragePool pool) { + s_logger.debug("creating pool " + pool.getName() + " on host " + + hostId); + if (pool.getPoolType() != StoragePoolType.NetworkFilesystem + && pool.getPoolType() != StoragePoolType.Filesystem + && pool.getPoolType() != StoragePoolType.IscsiLUN + && pool.getPoolType() != StoragePoolType.Iscsi + && pool.getPoolType() != StoragePoolType.VMFS + && pool.getPoolType() != StoragePoolType.SharedMountPoint + && pool.getPoolType() != StoragePoolType.PreSetup + && pool.getPoolType() != StoragePoolType.OCFS2 + && pool.getPoolType() != StoragePoolType.RBD + && pool.getPoolType() != StoragePoolType.CLVM) { + s_logger.warn(" Doesn't support storage pool type " + + pool.getPoolType()); + return false; + } + CreateStoragePoolCommand cmd = new CreateStoragePoolCommand(true, pool); + final Answer answer = agentMgr.easySend(hostId, cmd); + if (answer != null && answer.getResult()) { + return true; + } else { + primaryDataStoreDao.expunge(pool.getId()); + String msg = ""; + if (answer != null) { + msg = "Can not create storage pool through host " + hostId + + " due to " + answer.getDetails(); + s_logger.warn(msg); + } else { + msg = "Can not create storage pool through host " + hostId + + " due to CreateStoragePoolCommand returns null"; + s_logger.warn(msg); + } + throw new CloudRuntimeException(msg); + } + } + + @Override + public boolean attachCluster(DataStore store, ClusterScope scope) { + PrimaryDataStoreInfo primarystore = (PrimaryDataStoreInfo) store; + // Check if there is host up in this cluster + List allHosts = _resourceMgr.listAllUpAndEnabledHosts( + Host.Type.Routing, primarystore.getClusterId(), + primarystore.getPodId(), primarystore.getDataCenterId()); + if (allHosts.isEmpty()) { + throw new CloudRuntimeException( + "No host up to associate a storage pool with in cluster " + + primarystore.getClusterId()); + } + + if (primarystore.getPoolType() == StoragePoolType.OCFS2 + && !_ocfs2Mgr.prepareNodes(allHosts, primarystore)) { + s_logger.warn("Can not create storage pool " + primarystore + + " on cluster " + primarystore.getClusterId()); + primaryDataStoreDao.expunge(primarystore.getId()); + return false; + } + + boolean success = false; + for (HostVO h : allHosts) { + success = createStoragePool(h.getId(), primarystore); + if (success) { + break; + } + } + + s_logger.debug("In createPool Adding the pool to each of the hosts"); + List poolHosts = new ArrayList(); + for (HostVO h : allHosts) { + try { + this.storageMgr.connectHostToSharedPool(h.getId(), + primarystore.getId()); + poolHosts.add(h); + } catch (Exception e) { + s_logger.warn("Unable to establish a connection between " + h + + " and " + primarystore, e); + } + } + + if (poolHosts.isEmpty()) { + s_logger.warn("No host can access storage pool " + primarystore + + " on cluster " + primarystore.getClusterId()); + primaryDataStoreDao.expunge(primarystore.getId()); + return false; + } else { + storageMgr.createCapacityEntry(primarystore.getId()); + } + StoragePoolVO pool = this.primaryDataStoreDao.findById(store.getId()); + pool.setScope(ScopeType.CLUSTER); + pool.setStatus(StoragePoolStatus.Up); + this.primaryDataStoreDao.update(pool.getId(), pool); + return true; + } + + @Override + public boolean attachZone(DataStore dataStore, ZoneScope scope) { + StoragePoolVO pool = this.primaryDataStoreDao.findById(dataStore.getId()); + pool.setScope(ScopeType.ZONE); + pool.setStatus(StoragePoolStatus.Up); + this.primaryDataStoreDao.update(pool.getId(), pool); + return true; + } + + @Override + public boolean dettach() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean unmanaged() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean maintain(long storeId) { + Long userId = UserContext.current().getCallerUserId(); + User user = _userDao.findById(userId); + Account account = UserContext.current().getCaller(); + StoragePoolVO pool = this.primaryDataStoreDao.findById(storeId); + try { + StoragePool storagePool = (StoragePool) this.dataStoreMgr + .getDataStore(storeId, DataStoreRole.Primary); + List hosts = _resourceMgr.listHostsInClusterByStatus( + pool.getClusterId(), Status.Up); + if (hosts == null || hosts.size() == 0) { + pool.setStatus(StoragePoolStatus.Maintenance); + primaryDataStoreDao.update(pool.getId(), pool); + return true; + } else { + // set the pool state to prepare for maintenance + pool.setStatus(StoragePoolStatus.PrepareForMaintenance); + primaryDataStoreDao.update(pool.getId(), pool); + } + // remove heartbeat + for (HostVO host : hosts) { + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand( + false, storagePool); + final Answer answer = agentMgr.easySend(host.getId(), cmd); + if (answer == null || !answer.getResult()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("ModifyStoragePool false failed due to " + + ((answer == null) ? "answer null" : answer + .getDetails())); + } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("ModifyStoragePool false secceeded"); + } + } + } + // check to see if other ps exist + // if they do, then we can migrate over the system vms to them + // if they dont, then just stop all vms on this one + List upPools = primaryDataStoreDao + .listByStatusInZone(pool.getDataCenterId(), + DataStoreStatus.Up); + boolean restart = true; + if (upPools == null || upPools.size() == 0) { + restart = false; + } + + // 2. Get a list of all the ROOT volumes within this storage pool + List allVolumes = this.volumeDao.findByPoolId(pool + .getId()); + + // 3. Enqueue to the work queue + for (VolumeVO volume : allVolumes) { + VMInstanceVO vmInstance = vmDao + .findById(volume.getInstanceId()); + + if (vmInstance == null) { + continue; + } + + // enqueue sp work + if (vmInstance.getState().equals(State.Running) + || vmInstance.getState().equals(State.Starting) + || vmInstance.getState().equals(State.Stopping)) { + + try { + StoragePoolWorkVO work = new StoragePoolWorkVO( + vmInstance.getId(), pool.getId(), false, false, + server.getId()); + _storagePoolWorkDao.persist(work); + } catch (Exception e) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Work record already exists, re-using by re-setting values"); + } + StoragePoolWorkVO work = _storagePoolWorkDao + .findByPoolIdAndVmId(pool.getId(), + vmInstance.getId()); + work.setStartedAfterMaintenance(false); + work.setStoppedForMaintenance(false); + work.setManagementServerId(server.getId()); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + + // 4. Process the queue + List pendingWork = _storagePoolWorkDao + .listPendingWorkForPrepareForMaintenanceByPoolId(pool + .getId()); + + for (StoragePoolWorkVO work : pendingWork) { + // shut down the running vms + VMInstanceVO vmInstance = vmDao.findById(work.getVmId()); + + if (vmInstance == null) { + continue; + } + + // if the instance is of type consoleproxy, call the console + // proxy + if (vmInstance.getType().equals( + VirtualMachine.Type.ConsoleProxy)) { + // call the consoleproxymanager + ConsoleProxyVO consoleProxy = _consoleProxyDao + .findById(vmInstance.getId()); + if (!vmMgr.advanceStop(consoleProxy, true, user, account)) { + String errorMsg = "There was an error stopping the console proxy id: " + + vmInstance.getId() + + " ,cannot enable storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + // update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + + if (restart) { + + if (this.vmMgr.advanceStart(consoleProxy, null, user, + account) == null) { + String errorMsg = "There was an error starting the console proxy id: " + + vmInstance.getId() + + " on another storage pool, cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + } else { + // update work status + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + + // if the instance is of type uservm, call the user vm manager + if (vmInstance.getType().equals(VirtualMachine.Type.User)) { + UserVmVO userVm = userVmDao.findById(vmInstance.getId()); + if (!vmMgr.advanceStop(userVm, true, user, account)) { + String errorMsg = "There was an error stopping the user vm id: " + + vmInstance.getId() + + " ,cannot enable storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + // update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + + // if the instance is of type secondary storage vm, call the + // secondary storage vm manager + if (vmInstance.getType().equals( + VirtualMachine.Type.SecondaryStorageVm)) { + SecondaryStorageVmVO secStrgVm = _secStrgDao + .findById(vmInstance.getId()); + if (!vmMgr.advanceStop(secStrgVm, true, user, account)) { + String errorMsg = "There was an error stopping the ssvm id: " + + vmInstance.getId() + + " ,cannot enable storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + // update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + + if (restart) { + if (vmMgr.advanceStart(secStrgVm, null, user, account) == null) { + String errorMsg = "There was an error starting the ssvm id: " + + vmInstance.getId() + + " on another storage pool, cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + } else { + // update work status + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + + // if the instance is of type domain router vm, call the network + // manager + if (vmInstance.getType().equals( + VirtualMachine.Type.DomainRouter)) { + DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); + if (!vmMgr.advanceStop(domR, true, user, account)) { + String errorMsg = "There was an error stopping the domain router id: " + + vmInstance.getId() + + " ,cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + // update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + + if (restart) { + if (vmMgr.advanceStart(domR, null, user, account) == null) { + String errorMsg = "There was an error starting the domain router id: " + + vmInstance.getId() + + " on another storage pool, cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + } else { + // update work status + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + } + + // 5. Update the status + pool.setStatus(StoragePoolStatus.Maintenance); + this.primaryDataStoreDao.update(pool.getId(), pool); + + return true; + } catch (Exception e) { + s_logger.error( + "Exception in enabling primary storage maintenance:", e); + setPoolStateToError(pool); + throw new CloudRuntimeException(e.getMessage()); + } + } + + private void setPoolStateToError(StoragePoolVO primaryStorage) { + primaryStorage.setStatus(StoragePoolStatus.ErrorInMaintenance); + this.primaryDataStoreDao.update(primaryStorage.getId(), primaryStorage); + } + + @Override + public boolean cancelMaintain(long storageId) { + // Change the storage state back to up + Long userId = UserContext.current().getCallerUserId(); + User user = _userDao.findById(userId); + Account account = UserContext.current().getCaller(); + StoragePoolVO poolVO = this.primaryDataStoreDao + .findById(storageId); + StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore( + storageId, DataStoreRole.Primary); + poolVO.setStatus(StoragePoolStatus.Up); + primaryDataStoreDao.update(storageId, poolVO); + + List hosts = _resourceMgr.listHostsInClusterByStatus( + pool.getClusterId(), Status.Up); + if (hosts == null || hosts.size() == 0) { + return true; + } + // add heartbeat + for (HostVO host : hosts) { + ModifyStoragePoolCommand msPoolCmd = new ModifyStoragePoolCommand( + true, pool); + final Answer answer = agentMgr.easySend(host.getId(), msPoolCmd); + if (answer == null || !answer.getResult()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("ModifyStoragePool add failed due to " + + ((answer == null) ? "answer null" : answer + .getDetails())); + } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("ModifyStoragePool add secceeded"); + } + } + } + + // 2. Get a list of pending work for this queue + List pendingWork = _storagePoolWorkDao + .listPendingWorkForCancelMaintenanceByPoolId(poolVO.getId()); + + // 3. work through the queue + for (StoragePoolWorkVO work : pendingWork) { + try { + VMInstanceVO vmInstance = vmDao.findById(work.getVmId()); + + if (vmInstance == null) { + continue; + } + + // if the instance is of type consoleproxy, call the console + // proxy + if (vmInstance.getType().equals( + VirtualMachine.Type.ConsoleProxy)) { + + ConsoleProxyVO consoleProxy = _consoleProxyDao + .findById(vmInstance.getId()); + if (vmMgr.advanceStart(consoleProxy, null, user, account) == null) { + String msg = "There was an error starting the console proxy id: " + + vmInstance.getId() + + " on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + // update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + + // if the instance is of type ssvm, call the ssvm manager + if (vmInstance.getType().equals( + VirtualMachine.Type.SecondaryStorageVm)) { + SecondaryStorageVmVO ssVm = _secStrgDao.findById(vmInstance + .getId()); + if (vmMgr.advanceStart(ssVm, null, user, account) == null) { + String msg = "There was an error starting the ssvm id: " + + vmInstance.getId() + + " on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + // update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + + // if the instance is of type ssvm, call the ssvm manager + if (vmInstance.getType().equals( + VirtualMachine.Type.DomainRouter)) { + DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); + if (vmMgr.advanceStart(domR, null, user, account) == null) { + String msg = "There was an error starting the domR id: " + + vmInstance.getId() + + " on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + // update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + + // if the instance is of type user vm, call the user vm manager + if (vmInstance.getType().equals(VirtualMachine.Type.User)) { + UserVmVO userVm = userVmDao.findById(vmInstance.getId()); + + if (vmMgr.advanceStart(userVm, null, user, account) == null) { + + String msg = "There was an error starting the user vm id: " + + vmInstance.getId() + + " on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + // update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } catch (Exception e) { + s_logger.debug("Failed start vm", e); + throw new CloudRuntimeException(e.toString()); + } + } + return true; + } + + @DB + @Override + public boolean deleteDataStore(long storeId) { + // for the given pool id, find all records in the storage_pool_host_ref + List hostPoolRecords = this._storagePoolHostDao + .listByPoolId(storeId); + StoragePoolVO poolVO = this.primaryDataStoreDao.findById(storeId); + StoragePool pool = (StoragePool)this.dataStoreMgr.getDataStore(storeId, DataStoreRole.Primary); + boolean deleteFlag = false; + Transaction txn = Transaction.currentTxn(); + try { + // if not records exist, delete the given pool (base case) + if (hostPoolRecords.size() == 0) { + + txn.start(); + poolVO.setUuid(null); + this.primaryDataStoreDao.update(poolVO.getId(), poolVO); + primaryDataStoreDao.remove(poolVO.getId()); + deletePoolStats(poolVO.getId()); + txn.commit(); + + deleteFlag = true; + return true; + } else { + // Remove the SR associated with the Xenserver + for (StoragePoolHostVO host : hostPoolRecords) { + DeleteStoragePoolCommand deleteCmd = new DeleteStoragePoolCommand( + pool); + final Answer answer = agentMgr.easySend(host.getHostId(), + deleteCmd); + + if (answer != null && answer.getResult()) { + deleteFlag = true; + break; + } + } + } + } finally { + if (deleteFlag) { + // now delete the storage_pool_host_ref and storage_pool records + txn.start(); + for (StoragePoolHostVO host : hostPoolRecords) { + _storagePoolHostDao.deleteStoragePoolHostDetails( + host.getHostId(), host.getPoolId()); + } + poolVO.setUuid(null); + this.primaryDataStoreDao.update(poolVO.getId(), poolVO); + primaryDataStoreDao.remove(poolVO.getId()); + deletePoolStats(poolVO.getId()); + // Delete op_host_capacity entries + this._capacityDao.removeBy(Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, + null, null, null, poolVO.getId()); + txn.commit(); + + s_logger.debug("Storage pool id=" + poolVO.getId() + + " is removed successfully"); + return true; + } else { + // alert that the storage cleanup is required + s_logger.warn("Failed to Delete storage pool id: " + poolVO.getId()); + _alertMgr + .sendAlert(AlertManager.ALERT_TYPE_STORAGE_DELETE, + poolVO.getDataCenterId(), poolVO.getPodId(), + "Unable to delete storage pool id= " + poolVO.getId(), + "Delete storage pool command failed. Please check logs."); + } + } + return false; + } + + @DB + private boolean deletePoolStats(Long poolId) { + CapacityVO capacity1 = _capacityDao.findByHostIdType(poolId, + CapacityVO.CAPACITY_TYPE_STORAGE); + CapacityVO capacity2 = _capacityDao.findByHostIdType(poolId, + CapacityVO.CAPACITY_TYPE_STORAGE_ALLOCATED); + Transaction txn = Transaction.currentTxn(); + txn.start(); + if (capacity1 != null) { + _capacityDao.remove(capacity1.getId()); + } + + if (capacity2 != null) { + _capacityDao.remove(capacity2.getId()); + } + + txn.commit(); + return true; + } + + @Override + public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) { + StoragePoolHostVO poolHost = _storagePoolHostDao.findByPoolHost(store.getId(), scope.getScopeId()); + if (poolHost == null) { + poolHost = new StoragePoolHostVO(store.getId(), scope.getScopeId(), existingInfo.getLocalPath()); + _storagePoolHostDao.persist(poolHost); + } + + StoragePoolVO pool = this.primaryDataStoreDao.findById(store.getId()); + pool.setScope(scope.getScopeType()); + pool.setAvailableBytes(existingInfo.getAvailableBytes()); + pool.setCapacityBytes(existingInfo.getCapacityBytes()); + pool.setStatus(StoragePoolStatus.Up); + this.primaryDataStoreDao.update(pool.getId(), pool); + this.storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getCapacityBytes() - pool.getAvailableBytes()); + + return true; + } + +} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java index ffe7efdcda7..5e8727a316a 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java @@ -26,22 +26,22 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd; -import org.apache.cloudstack.storage.datastore.DataStoreStatus; -import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.endpoint.EndPointSelector; -import org.apache.cloudstack.storage.image.datastore.ImageDataStoreHelper; import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper; +import com.cloud.agent.api.StoragePoolInfo; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.StoragePoolStatus; public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle { @Inject @@ -58,9 +58,9 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif } @Override - public DataStore initialize(Map dsInfos) { + public DataStore initialize(Map dsInfos) { - PrimaryDataStoreVO storeVO = primaryStoreHelper.createPrimaryDataStore(dsInfos); + StoragePoolVO storeVO = primaryStoreHelper.createPrimaryDataStore(dsInfos); return providerMgr.getPrimaryDataStore(storeVO.getId()); } @@ -83,11 +83,11 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif @Override public boolean attachCluster(DataStore dataStore, ClusterScope scope) { - PrimaryDataStoreVO dataStoreVO = dataStoreDao.findById(dataStore.getId()); + StoragePoolVO dataStoreVO = dataStoreDao.findById(dataStore.getId()); dataStoreVO.setDataCenterId(scope.getZoneId()); dataStoreVO.setPodId(scope.getPodId()); dataStoreVO.setClusterId(scope.getScopeId()); - dataStoreVO.setStatus(DataStoreStatus.Attaching); + dataStoreVO.setStatus(StoragePoolStatus.Attaching); dataStoreVO.setScope(scope.getScopeType()); dataStoreDao.update(dataStoreVO.getId(), dataStoreVO); @@ -95,7 +95,7 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif attachCluster(dataStore); dataStoreVO = dataStoreDao.findById(dataStore.getId()); - dataStoreVO.setStatus(DataStoreStatus.Up); + dataStoreVO.setStatus(StoragePoolStatus.Up); dataStoreDao.update(dataStoreVO.getId(), dataStoreVO); return true; @@ -114,19 +114,19 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif } @Override - public boolean maintain() { + public boolean maintain(long storeId) { // TODO Auto-generated method stub return false; } @Override - public boolean cancelMaintain() { + public boolean cancelMaintain(long storeId) { // TODO Auto-generated method stub return false; } @Override - public boolean deleteDataStore() { + public boolean deleteDataStore(long storeId) { // TODO Auto-generated method stub return false; } @@ -139,4 +139,11 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif return false; } + @Override + public boolean attachHost(DataStore store, HostScope scope, + StoragePoolInfo existingInfo) { + // TODO Auto-generated method stub + return false; + } + } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreProviderManagerImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreProviderManagerImpl.java index 1a24d87346e..e181adabb5b 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreProviderManagerImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreProviderManagerImpl.java @@ -21,20 +21,22 @@ package org.apache.cloudstack.storage.datastore.manager; import java.util.HashMap; import java.util.Map; +import javax.annotation.PostConstruct; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.storage.datastore.DefaultPrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; import org.apache.cloudstack.storage.datastore.db.DataStoreProviderDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProvider; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProviderManager; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; -import com.cloud.utils.component.ComponentContext; +import com.cloud.storage.StorageManager; @Component public class DefaultPrimaryDataStoreProviderManagerImpl implements PrimaryDataStoreProviderManager { @@ -44,16 +46,19 @@ public class DefaultPrimaryDataStoreProviderManagerImpl implements PrimaryDataSt DataStoreProviderManager providerManager; @Inject PrimaryDataStoreDao dataStoreDao; - Map driverMaps = new HashMap(); + Map driverMaps; + @Inject StorageManager storageMgr; + @PostConstruct + public void config() { + driverMaps = new HashMap(); + } + @Override public PrimaryDataStore getPrimaryDataStore(long dataStoreId) { - PrimaryDataStoreVO dataStoreVO = dataStoreDao.findById(dataStoreId); + StoragePoolVO dataStoreVO = dataStoreDao.findById(dataStoreId); long providerId = dataStoreVO.getStorageProviderId(); DataStoreProvider provider = providerManager.getDataStoreProviderById(providerId); - /*DefaultPrimaryDataStore dataStore = DefaultPrimaryDataStore.createDataStore(dataStoreVO, - driverMaps.get(provider.getUuid()), - provider);*/ DefaultPrimaryDataStore dataStore = DefaultPrimaryDataStore.createDataStore(dataStoreVO, driverMaps.get(provider.getUuid()), provider); return dataStore; } @@ -66,4 +71,15 @@ public class DefaultPrimaryDataStoreProviderManagerImpl implements PrimaryDataSt driverMaps.put(uuid, driver); return true; } + + @Override + public PrimaryDataStore getPrimaryDataStore(String uuid) { + StoragePoolVO dataStoreVO = dataStoreDao.findByUuid(uuid); + return getPrimaryDataStore(dataStoreVO.getId()); + } + + @Override + public boolean registerHostListener(String uuid, HypervisorHostListener listener) { + return storageMgr.registerHostListener(uuid, listener); + } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/data model.ucls b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/data model.ucls index 9386454efb3..8d7a696957d 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/data model.ucls +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/data model.ucls @@ -1,20 +1,20 @@ @@ -36,18 +36,18 @@ - + - + diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/AncientPrimaryDataStoreProviderImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/AncientPrimaryDataStoreProviderImpl.java new file mode 100644 index 00000000000..e7d65167eac --- /dev/null +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/AncientPrimaryDataStoreProviderImpl.java @@ -0,0 +1,78 @@ +/* + * 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.storage.datastore.provider; + +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; +import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; +import org.apache.cloudstack.storage.datastore.driver.AncientPrimaryDataStoreDriverImpl; +import org.apache.cloudstack.storage.datastore.lifecycle.AncientPrimaryDataStoreLifeCyclImpl; +import org.springframework.stereotype.Component; + +import com.cloud.utils.component.ComponentContext; + +@Component +public class AncientPrimaryDataStoreProviderImpl implements + PrimaryDataStoreProvider { + + private final String providerName = "ancient primary data store provider"; + protected PrimaryDataStoreDriver driver; + @Inject + PrimaryDataStoreProviderManager storeMgr; + protected DataStoreLifeCycle lifecyle; + protected String uuid; + protected long id; + @Override + public String getName() { + return providerName; + } + + @Override + public DataStoreLifeCycle getLifeCycle() { + return this.lifecyle; + } + + @Override + public boolean configure(Map params) { + lifecyle = ComponentContext.inject(AncientPrimaryDataStoreLifeCyclImpl.class); + driver = ComponentContext.inject(AncientPrimaryDataStoreDriverImpl.class); + uuid = (String)params.get("uuid"); + id = (Long)params.get("id"); + storeMgr.registerDriver(uuid, this.driver); + HypervisorHostListener listener = ComponentContext.inject(DefaultHostListener.class); + storeMgr.registerHostListener(uuid, listener); + return true; + } + + @Override + public String getUuid() { + return this.uuid; + } + + @Override + public long getId() { + return this.id; + } + +} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java new file mode 100644 index 00000000000..f2cb1c45c82 --- /dev/null +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -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 org.apache.cloudstack.storage.datastore.provider; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ModifyStoragePoolAnswer; +import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.alert.AlertManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.utils.exception.CloudRuntimeException; + +public class DefaultHostListener implements HypervisorHostListener { + private static final Logger s_logger = Logger + .getLogger(DefaultHostListener.class); + @Inject AgentManager agentMgr; + @Inject DataStoreManager dataStoreMgr; + @Inject AlertManager alertMgr; + @Inject StoragePoolHostDao storagePoolHostDao; + @Inject PrimaryDataStoreDao primaryStoreDao; + @Override + public boolean hostConnect(long hostId, long poolId) { + StoragePool pool = (StoragePool)this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary); + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool); + final Answer answer = agentMgr.easySend(hostId, cmd); + + if (answer == null) { + throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command" + pool.getId()); + } + + if (!answer.getResult()) { + String msg = "Add host failed due to ModifyStoragePoolCommand failed" + answer.getDetails(); + alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg); + throw new CloudRuntimeException("Unable establish connection from storage head to storage pool " + pool.getId() + " due to " + answer.getDetails() + pool.getId()); + } + + assert (answer instanceof ModifyStoragePoolAnswer) : "Well, now why won't you actually return the ModifyStoragePoolAnswer when it's ModifyStoragePoolCommand? Pool=" + pool.getId() + "Host=" + hostId; + ModifyStoragePoolAnswer mspAnswer = (ModifyStoragePoolAnswer) answer; + + StoragePoolHostVO poolHost = storagePoolHostDao.findByPoolHost(pool.getId(), hostId); + if (poolHost == null) { + poolHost = new StoragePoolHostVO(pool.getId(), hostId, mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/")); + storagePoolHostDao.persist(poolHost); + } else { + poolHost.setLocalPath(mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/")); + } + + StoragePoolVO poolVO = this.primaryStoreDao.findById(poolId); + poolVO.setAvailableBytes(mspAnswer.getPoolInfo().getAvailableBytes()); + poolVO.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes()); + primaryStoreDao.update(pool.getId(), poolVO); + + s_logger.info("Connection established between " + pool + " host + " + hostId); + return true; + } + + @Override + public boolean hostDisconnected(long hostId, long poolId) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java index 540ea6381fa..a1402c13b3d 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java @@ -21,10 +21,11 @@ import java.util.Map; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; import org.apache.cloudstack.storage.datastore.driver.DefaultPrimaryDataStoreDriverImpl; import org.apache.cloudstack.storage.datastore.lifecycle.DefaultPrimaryDataStoreLifeCycleImpl; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; import org.springframework.stereotype.Component; import com.cloud.utils.component.ComponentContext; @@ -35,6 +36,7 @@ public class DefaultPrimaryDatastoreProviderImpl implements PrimaryDataStoreProv protected PrimaryDataStoreDriver driver; @Inject PrimaryDataStoreProviderManager storeMgr; + protected DataStoreLifeCycle lifecyle; protected String uuid; protected long id; @@ -52,9 +54,11 @@ public class DefaultPrimaryDatastoreProviderImpl implements PrimaryDataStoreProv public boolean configure(Map params) { lifecyle = ComponentContext.inject(DefaultPrimaryDataStoreLifeCycleImpl.class); driver = ComponentContext.inject(DefaultPrimaryDataStoreDriverImpl.class); + HypervisorHostListener listener = ComponentContext.inject(DefaultHostListener.class); uuid = (String)params.get("uuid"); id = (Long)params.get("id"); storeMgr.registerDriver(uuid, this.driver); + storeMgr.registerHostListener(uuid, listener); return true; } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategy.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategy.java index 7679bb3e729..99b34cbcf18 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategy.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategy.java @@ -18,9 +18,9 @@ */ package org.apache.cloudstack.storage.volume; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.volume.VolumeServiceImpl.CreateBaseImageResult; public interface TemplateInstallStrategy { diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java index 80e098d769a..5f1735c180a 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java @@ -20,24 +20,16 @@ package org.apache.cloudstack.storage.volume; import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; -import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.ImageDataFactory; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.motion.DataMotionService; import org.apache.cloudstack.storage.volume.VolumeServiceImpl.CreateBaseImageResult; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.fsm.NoTransitionException; - @Component public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { private static final Logger s_logger = Logger @@ -50,7 +42,7 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { ImageDataFactory imageFactory; protected long waitingTime = 1800; // half an hour protected long waitingRetries = 10; - +/* protected TemplateInfo waitingForTemplateDownload(TemplateInfo template, PrimaryDataStore dataStore) { long retries = this.waitingRetries; @@ -106,8 +98,8 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { boolean freshNewTemplate = false; if (obj == null) { try { - /*templateOnPrimaryStoreObj = objectInDataStoreMgr.create( - template, store);*/ + templateOnPrimaryStoreObj = objectInDataStoreMgr.create( + template, store); freshNewTemplate = true; } catch (Throwable e) { obj = objectInDataStoreMgr.findObject(template.getId(), @@ -264,13 +256,10 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { res.setResult(result.getResult()); context.getParentCallback().complete(res); } - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - templateOnPrimaryStoreObj.getId(), templateOnPrimaryStoreObj - .getType(), templateOnPrimaryStoreObj.getDataStore() - .getId(), templateOnPrimaryStoreObj.getDataStore() - .getRole()); + DataObjectInStore obj = objectInDataStoreMgr.findObject( + templateOnPrimaryStoreObj, templateOnPrimaryStoreObj.getDataStore()); + - obj.setInstallPath(result.getPath()); CreateBaseImageResult res = new CreateBaseImageResult( templateOnPrimaryStoreObj); try { @@ -289,6 +278,12 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { } context.getParentCallback().complete(res); return null; + }*/ + @Override + public Void installAsync(TemplateInfo template, PrimaryDataStore store, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + return null; } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeDataFactoryImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeDataFactoryImpl.java index 64af097bb32..e0ecd165d7f 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeDataFactoryImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeDataFactoryImpl.java @@ -20,21 +20,23 @@ package org.apache.cloudstack.storage.volume; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.storage.datastore.DataStoreManager; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.datastore.VolumeDataFactory; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.springframework.stereotype.Component; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; + @Component public class VolumeDataFactoryImpl implements VolumeDataFactory { @Inject - VolumeDao2 volumeDao; + VolumeDao volumeDao; @Inject ObjectInDataStoreManager objMap; @Inject @@ -42,12 +44,30 @@ public class VolumeDataFactoryImpl implements VolumeDataFactory { @Override public VolumeInfo getVolume(long volumeId, DataStore store) { VolumeVO volumeVO = volumeDao.findById(volumeId); - ObjectInDataStoreVO obj = objMap.findObject(volumeId, DataObjectType.VOLUME, store.getId(), store.getRole()); - if (obj == null) { - VolumeObject vol = VolumeObject.getVolumeObject(null, volumeVO); - return vol; - } + VolumeObject vol = VolumeObject.getVolumeObject(store, volumeVO); + + return vol; + } + + @Override + public VolumeInfo getVolume(long volumeId) { + VolumeVO volumeVO = volumeDao.findById(volumeId); + VolumeObject vol = null; + if (volumeVO.getPoolId() == null) { + DataStore store = objMap.findStore(volumeVO.getUuid(), DataObjectType.VOLUME, DataStoreRole.Image); + vol = VolumeObject.getVolumeObject(store, volumeVO); + } else { + DataStore store = this.storeMgr.getDataStore(volumeVO.getPoolId(), DataStoreRole.Primary); + vol = VolumeObject.getVolumeObject(store, volumeVO); + } + return vol; + } + + @Override + public VolumeInfo getVolume(DataObject volume, DataStore store) { + VolumeInfo vol = (VolumeObject)getVolume(volume.getId(), store); + vol.addPayload(((VolumeInfo)volume).getpayload()); return vol; } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java index 14d741707b5..f8d50437d14 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java @@ -22,20 +22,17 @@ import java.lang.reflect.Method; import java.util.Date; import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutionException; import org.apache.cloudstack.engine.cloud.entity.api.SnapshotEntity; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; import org.apache.cloudstack.engine.datacenter.entity.api.StorageEntity; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import org.apache.cloudstack.engine.subsystem.api.storage.type.VolumeType; -import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreEntityImpl; -import org.apache.cloudstack.storage.volume.VolumeService.VolumeApiResult; - -import com.cloud.utils.exception.CloudRuntimeException; public class VolumeEntityImpl implements VolumeEntity { private VolumeInfo volumeInfo; @@ -167,7 +164,7 @@ public class VolumeEntityImpl implements VolumeEntity { @Override public void destroy() { - AsyncCallFuture future = vs.deleteVolumeAsync(volumeInfo); + /*AsyncCallFuture future = vs.deleteVolumeAsync(volumeInfo); try { result = future.get(); if (!result.isSuccess()) { @@ -177,7 +174,7 @@ public class VolumeEntityImpl implements VolumeEntity { throw new CloudRuntimeException("wait to delete volume info failed", e); } catch (ExecutionException e) { throw new CloudRuntimeException("wait to delete volume failed", e); - } + }*/ } @Override diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java deleted file mode 100644 index bcff312626f..00000000000 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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.storage.volume; - -import javax.inject.Inject; - -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeProfile; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; -import org.springframework.stereotype.Component; - -import com.cloud.storage.Volume; -import com.cloud.storage.Volume.Event; -import com.cloud.storage.Volume.State; -import com.cloud.utils.fsm.NoTransitionException; -import com.cloud.utils.fsm.StateMachine2; - -@Component -public class VolumeManagerImpl implements VolumeManager { - @Inject - protected VolumeDao2 _volumeDao; - private final StateMachine2 s_fsm = new StateMachine2(); - public VolumeManagerImpl() { - initStateMachine(); - } - - @Override - public VolumeVO allocateDuplicateVolume(VolumeVO oldVol) { - /* - VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), oldVol.getDiskOfferingId(), oldVol.getSize()); - newVol.setTemplateId(oldVol.getTemplateId()); - newVol.setDeviceId(oldVol.getDeviceId()); - newVol.setInstanceId(oldVol.getInstanceId()); - newVol.setRecreatable(oldVol.isRecreatable()); - newVol.setReservationId(oldVol.getReservationId()); - */ - return null; - // return _volumeDao.persist(newVol); - } - - private void initStateMachine() { - s_fsm.addTransition(Volume.State.Allocated, Event.CreateRequested, Volume.State.Creating); - s_fsm.addTransition(Volume.State.Allocated, Event.DestroyRequested, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Creating, Event.OperationRetry, Volume.State.Creating); - s_fsm.addTransition(Volume.State.Creating, Event.OperationFailed, Volume.State.Allocated); - s_fsm.addTransition(Volume.State.Creating, Event.OperationSucceeded, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Creating, Event.DestroyRequested, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Creating, Event.CreateRequested, Volume.State.Creating); - s_fsm.addTransition(Volume.State.Allocated, Event.UploadRequested, Volume.State.UploadOp); - s_fsm.addTransition(Volume.State.UploadOp, Event.CopyRequested, Volume.State.Creating);// CopyRequested for volume from sec to primary storage - s_fsm.addTransition(Volume.State.Creating, Event.CopySucceeded, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Creating, Event.CopyFailed, Volume.State.UploadOp);// Copying volume from sec to primary failed. - s_fsm.addTransition(Volume.State.UploadOp, Event.DestroyRequested, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Ready, Event.DestroyRequested, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Destroy, Event.ExpungingRequested, Volume.State.Expunging); - s_fsm.addTransition(Volume.State.Ready, Event.SnapshotRequested, Volume.State.Snapshotting); - s_fsm.addTransition(Volume.State.Snapshotting, Event.OperationSucceeded, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Snapshotting, Event.OperationFailed, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Ready, Event.MigrationRequested, Volume.State.Migrating); - s_fsm.addTransition(Volume.State.Migrating, Event.OperationSucceeded, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Migrating, Event.OperationFailed, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Destroy, Event.OperationSucceeded, Volume.State.Destroy); - s_fsm.addTransition(Volume.State.Destroying, Event.OperationSucceeded, Volume.State.Destroy); - s_fsm.addTransition(Volume.State.Destroying, Event.OperationFailed, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Destroying, Event.DestroyRequested, Volume.State.Destroying); - } - - @Override - public StateMachine2 getStateMachine() { - return s_fsm; - } - - @Override - public VolumeVO processEvent(Volume vol, Volume.Event event) throws NoTransitionException { - // _volStateMachine.transitTo(vol, event, null, _volumeDao); - return _volumeDao.findById(vol.getId()); - } - - @Override - public VolumeProfile getProfile(long volumeId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public VolumeVO getVolume(long volumeId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public VolumeVO updateVolume(VolumeVO volume) { - // TODO Auto-generated method stub - return null; - } -} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java index 9e04909135e..6ad6cc9486f 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java @@ -16,19 +16,24 @@ // under the License. package org.apache.cloudstack.storage.volume; +import java.util.Date; + import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.apache.log4j.Logger; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Volume; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; @@ -38,17 +43,16 @@ import com.cloud.utils.storage.encoding.EncodingType; public class VolumeObject implements VolumeInfo { private static final Logger s_logger = Logger.getLogger(VolumeObject.class); protected VolumeVO volumeVO; - private StateMachine2 _volStateMachine; + private StateMachine2 _volStateMachine; protected DataStore dataStore; @Inject - VolumeDao2 volumeDao; - @Inject - VolumeManager volumeMgr; + VolumeDao volumeDao; @Inject ObjectInDataStoreManager ojbectInStoreMgr; + private Object payload; protected VolumeObject() { - + _volStateMachine = Volume.State.getStateMachine(); } protected void configure(DataStore dataStore, VolumeVO volumeVO) { @@ -70,6 +74,10 @@ public class VolumeObject implements VolumeInfo { public void setPath(String uuid) { volumeVO.setPath(uuid); } + + public void setSize(Long size) { + volumeVO.setSize(size); + } public Volume.State getState() { return volumeVO.getState(); @@ -88,12 +96,11 @@ public class VolumeObject implements VolumeInfo { public long getVolumeId() { return volumeVO.getId(); } - public boolean stateTransit(Volume.Event event) { boolean result = false; - _volStateMachine = volumeMgr.getStateMachine(); try { result = _volStateMachine.transitTo(volumeVO, event, null, volumeDao); + volumeVO = volumeDao.findById(volumeVO.getId()); } catch (NoTransitionException e) { String errorMessage = "Failed to transit volume: " + this.getVolumeId() + ", due to: " + e.toString(); s_logger.debug(errorMessage); @@ -122,7 +129,7 @@ public class VolumeObject implements VolumeInfo { if (this.dataStore == null) { throw new CloudRuntimeException("datastore must be set before using this object"); } - ObjectInDataStoreVO obj = ojbectInStoreMgr.findObject(this.volumeVO.getId(), DataObjectType.VOLUME, this.dataStore.getId(), this.dataStore.getRole()); + DataObjectInStore obj = ojbectInStoreMgr.findObject(this.volumeVO.getUuid(), DataObjectType.VOLUME, this.dataStore.getUuid(), this.dataStore.getRole()); if (obj.getState() != ObjectInDataStoreStateMachine.State.Ready) { return this.dataStore.getUri() + "&" + EncodingType.OBJTYPE + "=" + DataObjectType.VOLUME + @@ -145,4 +152,179 @@ public class VolumeObject implements VolumeInfo { // TODO Auto-generated method stub return null; } + + @Override + public void processEvent( + ObjectInDataStoreStateMachine.Event event) { + if (this.dataStore == null) { + return; + } + try { + Volume.Event volEvent = null; + if (this.dataStore.getRole() == DataStoreRole.Image) { + ojbectInStoreMgr.update(this, event); + if (event == ObjectInDataStoreStateMachine.Event.CreateRequested) { + volEvent = Volume.Event.UploadRequested; + } else if (event == ObjectInDataStoreStateMachine.Event.OperationSuccessed) { + volEvent = Volume.Event.CopySucceeded; + } else if (event == ObjectInDataStoreStateMachine.Event.OperationFailed) { + volEvent = Volume.Event.CopyFailed; + } + } else { + if (event == ObjectInDataStoreStateMachine.Event.CreateRequested || + event == ObjectInDataStoreStateMachine.Event.CreateOnlyRequested) { + volEvent = Volume.Event.CreateRequested; + } else if (event == ObjectInDataStoreStateMachine.Event.CopyingRequested) { + volEvent = Volume.Event.CopyRequested; + } + } + + if (event == ObjectInDataStoreStateMachine.Event.DestroyRequested) { + volEvent = Volume.Event.DestroyRequested; + } else if (event == ObjectInDataStoreStateMachine.Event.ExpungeRequested) { + volEvent = Volume.Event.ExpungingRequested; + } else if (event == ObjectInDataStoreStateMachine.Event.OperationSuccessed) { + volEvent = Volume.Event.OperationSucceeded; + } else if (event == ObjectInDataStoreStateMachine.Event.OperationFailed) { + volEvent = Volume.Event.OperationFailed; + } else if (event == ObjectInDataStoreStateMachine.Event.ResizeRequested) { + volEvent = Volume.Event.ResizeRequested; + } + this.stateTransit(volEvent); + } catch (Exception e) { + s_logger.debug("Failed to update state", e); + throw new CloudRuntimeException("Failed to update state:" + e.toString()); + } + + } + + @Override + public String getName() { + return this.volumeVO.getName(); + } + + @Override + public Long getInstanceId() { + return this.volumeVO.getInstanceId(); + } + + @Override + public String getFolder() { + return this.volumeVO.getFolder(); + } + + @Override + public String getPath() { + return this.volumeVO.getPath(); + } + + @Override + public Long getPodId() { + return this.volumeVO.getPodId(); + } + + @Override + public long getDataCenterId() { + return this.volumeVO.getDataCenterId(); + } + + @Override + public Type getVolumeType() { + return this.volumeVO.getVolumeType(); + } + + @Override + public Long getPoolId() { + return this.volumeVO.getPoolId(); + } + + @Override + public Date getAttached() { + return this.volumeVO.getAttached(); + } + + @Override + public Long getDeviceId() { + return this.volumeVO.getDeviceId(); + } + + @Override + public Date getCreated() { + return this.volumeVO.getCreated(); + } + + @Override + public long getDiskOfferingId() { + return this.volumeVO.getDiskOfferingId(); + } + + @Override + public String getChainInfo() { + return this.volumeVO.getChainInfo(); + } + + @Override + public boolean isRecreatable() { + return this.volumeVO.isRecreatable(); + } + + @Override + public long getUpdatedCount() { + return this.volumeVO.getUpdatedCount(); + } + + @Override + public void incrUpdatedCount() { + this.volumeVO.incrUpdatedCount(); + } + + @Override + public Date getUpdated() { + return this.volumeVO.getUpdated(); + } + + @Override + public String getReservationId() { + return this.volumeVO.getReservationId(); + } + + @Override + public void setReservationId(String reserv) { + this.volumeVO.setReservationId(reserv); + } + + @Override + public long getAccountId() { + return this.volumeVO.getAccountId(); + } + + @Override + public long getDomainId() { + return this.volumeVO.getDomainId(); + } + + @Override + public Long getTemplateId() { + return this.volumeVO.getTemplateId(); + } + + @Override + public void addPayload(Object data) { + this.payload = data; + } + + @Override + public Object getpayload() { + return this.payload; + } + + @Override + public HypervisorType getHypervisorType() { + return this.volumeDao.getHypervisorType(this.volumeVO.getId()); + } + + @Override + public Long getLastPoolId() { + return this.volumeVO.getLastPoolId(); + } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 8cfbae455e7..c019374d9b9 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -22,12 +22,16 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.type.VolumeType; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; @@ -36,22 +40,28 @@ import org.apache.cloudstack.storage.datastore.DataObjectManager; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.image.motion.ImageMotionService; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; +import org.apache.cloudstack.storage.motion.DataMotionService; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; +import com.cloud.storage.Volume.Type; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.utils.db.DB; - -//1. change volume state -//2. orchestrator of volume, control most of the information of volume, storage pool id, voluem state, scope etc. +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.dao.VMInstanceDao; @Component public class VolumeServiceImpl implements VolumeService { + private static final Logger s_logger = Logger + .getLogger(VolumeServiceImpl.class); @Inject - VolumeDao2 volDao; + VolumeDao volDao; @Inject PrimaryDataStoreProviderManager dataStoreMgr; @Inject @@ -59,27 +69,31 @@ public class VolumeServiceImpl implements VolumeService { @Inject DataObjectManager dataObjectMgr; @Inject - ImageMotionService imageMotion; + DataMotionService motionSrv; @Inject TemplateInstallStrategy templateInstallStrategy; + @Inject + VolumeDataFactory volFactory; + @Inject SnapshotManager snapshotMgr; + @Inject VMInstanceDao vmDao; public VolumeServiceImpl() { } private class CreateVolumeContext extends AsyncRpcConext { - private VolumeObject volume; + private DataObject volume; private AsyncCallFuture future; /** * @param callback */ - public CreateVolumeContext(AsyncCompletionCallback callback, VolumeObject volume, AsyncCallFuture future) { + public CreateVolumeContext(AsyncCompletionCallback callback, DataObject volume, AsyncCallFuture future) { super(callback); this.volume = volume; this.future = future; } - public VolumeObject getVolume() { + public DataObject getVolume() { return this.volume; } @@ -89,49 +103,35 @@ public class VolumeServiceImpl implements VolumeService { } - - @Override - public AsyncCallFuture createVolumeAsync(VolumeInfo volume, long dataStoreId) { - PrimaryDataStore dataStore = dataStoreMgr.getPrimaryDataStore(dataStoreId); + public AsyncCallFuture createVolumeAsync(VolumeInfo volume, DataStore dataStore) { AsyncCallFuture future = new AsyncCallFuture(); - VolumeApiResult result = new VolumeApiResult(volume); - - if (dataStore == null) { - result.setResult("Can't find dataStoreId: " + dataStoreId); - future.complete(result); - return future; - } + DataObject volumeOnStore = dataStore.create(volume); + volumeOnStore.processEvent(Event.CreateOnlyRequested); - if (dataStore.exists(volume)) { - result.setResult("Volume: " + volume.getId() + " already exists on primary data store: " + dataStoreId); - future.complete(result); - return future; - } - - VolumeObject vo = (VolumeObject) volume; - vo.stateTransit(Volume.Event.CreateRequested); - - CreateVolumeContext context = new CreateVolumeContext(null, vo, future); + CreateVolumeContext context = new CreateVolumeContext(null, volumeOnStore, future); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().createVolumeCallback(null, null)) .setContext(context); - dataObjectMgr.createAsync(volume, dataStore, caller, true); + dataStore.getDriver().createAsync(volumeOnStore, caller); return future; } protected Void createVolumeCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { CreateCmdResult result = callback.getResult(); - VolumeObject vo = context.getVolume(); - VolumeApiResult volResult = new VolumeApiResult(vo); + DataObject vo = context.getVolume(); + String errMsg = null; if (result.isSuccess()) { - vo.stateTransit(Volume.Event.OperationSucceeded); + vo.processEvent(Event.OperationSuccessed); } else { - vo.stateTransit(Volume.Event.OperationFailed); - volResult.setResult(result.getResult()); + vo.processEvent(Event.OperationFailed); + errMsg = result.getResult(); + } + VolumeApiResult volResult = new VolumeApiResult((VolumeObject)vo); + if (errMsg != null) { + volResult.setResult(errMsg); } - context.getFuture().complete(volResult); return null; } @@ -159,26 +159,47 @@ public class VolumeServiceImpl implements VolumeService { @DB @Override - public AsyncCallFuture deleteVolumeAsync(VolumeInfo volume) { - VolumeObject vo = (VolumeObject)volume; + public AsyncCallFuture expungeVolumeAsync(VolumeInfo volume) { AsyncCallFuture future = new AsyncCallFuture(); VolumeApiResult result = new VolumeApiResult(volume); - - DataStore dataStore = vo.getDataStore(); - vo.stateTransit(Volume.Event.DestroyRequested); - if (dataStore == null) { - vo.stateTransit(Volume.Event.OperationSucceeded); - volDao.remove(vo.getId()); + if (volume.getDataStore() == null) { + this.volDao.remove(volume.getId()); future.complete(result); return future; } + String vmName = null; + VolumeVO vol = this.volDao.findById(volume.getId()); + if (vol.getVolumeType() == Type.ROOT && vol.getInstanceId() != null) { + VirtualMachine vm = vmDao.findByIdIncludingRemoved(vol + .getInstanceId()); + if (vm != null) { + vmName = vm.getInstanceName(); + } + } + + String volumePath = vol.getPath(); + Long poolId = vol.getPoolId(); + if (poolId == null || volumePath == null || volumePath.trim().isEmpty()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Marking volume that was never created as destroyed: " + + vol); + } + this.volDao.remove(vol.getId()); + future.complete(result); + return future; + } + VolumeObject vo = (VolumeObject)volume; + + volume.processEvent(Event.ExpungeRequested); + + DeleteVolumeContext context = new DeleteVolumeContext(null, vo, future); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().deleteVolumeCallback(null, null)) .setContext(context); - dataObjectMgr.deleteAsync(volume, caller); + volume.getDataStore().getDriver().deleteAsync(volume, caller); return future; } @@ -187,10 +208,10 @@ public class VolumeServiceImpl implements VolumeService { VolumeObject vo = context.getVolume(); VolumeApiResult apiResult = new VolumeApiResult(vo); if (result.isSuccess()) { - vo.stateTransit(Volume.Event.OperationSucceeded); + vo.processEvent(Event.OperationSuccessed); volDao.remove(vo.getId()); } else { - vo.stateTransit(Volume.Event.OperationFailed); + vo.processEvent(Event.OperationFailed); apiResult.setResult(result.getResult()); } context.getFuture().complete(apiResult); @@ -203,24 +224,6 @@ public class VolumeServiceImpl implements VolumeService { return false; } - @Override - public boolean createVolumeFromSnapshot(long volumeId, long snapshotId) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean rokeAccess(long volumeId, long endpointId) { - // TODO Auto-generated method stub - return false; - } - - @Override - public VolumeEntity allocateVolumeInDb(long size, VolumeType type, String volName, Long templateId) { - VolumeVO vo = volDao.allocVolume(size, type, volName, templateId); - return new VolumeEntityImpl(VolumeObject.getVolumeObject(null, vo), this); - } - @Override public VolumeEntity getVolumeEntity(long volumeId) { VolumeVO vo = volDao.findById(volumeId); @@ -236,25 +239,21 @@ public class VolumeServiceImpl implements VolumeService { } } - @Override - public String grantAccess(VolumeInfo volume, EndPoint endpointId) { - // TODO Auto-generated method stub - return null; - } - class CreateBaseImageContext extends AsyncRpcConext { private final VolumeInfo volume; private final PrimaryDataStore dataStore; private final TemplateInfo srcTemplate; private final AsyncCallFuture future; + final DataObject destObj; public CreateBaseImageContext(AsyncCompletionCallback callback, VolumeInfo volume, PrimaryDataStore datastore, TemplateInfo srcTemplate, - AsyncCallFuture future) { + AsyncCallFuture future, DataObject destObj) { super(callback); this.volume = volume; this.dataStore = datastore; this.future = future; this.srcTemplate = srcTemplate; + this.destObj = destObj; } public VolumeInfo getVolume() { @@ -285,33 +284,45 @@ public class VolumeServiceImpl implements VolumeService { @DB protected void createBaseImageAsync(VolumeInfo volume, PrimaryDataStore dataStore, TemplateInfo template, AsyncCallFuture future) { + + DataObject templateOnPrimaryStoreObj = dataStore.create(template); CreateBaseImageContext context = new CreateBaseImageContext(null, volume, dataStore, template, - future); - - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + future, templateOnPrimaryStoreObj); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().copyBaseImageCallback(null, null)) .setContext(context); - DataObject templateOnPrimaryStoreObj = dataObjectMgr.createInternalStateOnly(template, dataStore); + + templateOnPrimaryStoreObj.processEvent(Event.CreateOnlyRequested); - dataObjectMgr.copyAsync(context.srcTemplate, templateOnPrimaryStoreObj, caller); + try { + motionSrv.copyAsync(template, templateOnPrimaryStoreObj, caller); + } catch (Exception e) { + s_logger.debug("failed to create template on storage", e); + templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); + VolumeApiResult result = new VolumeApiResult(volume); + result.setResult(e.toString()); + caller.complete(result); + } return; } @DB - protected Void copyBaseImageCallback(AsyncCallbackDispatcher callback, CreateBaseImageContext context) { - CreateCmdResult result = callback.getResult(); + protected Void copyBaseImageCallback(AsyncCallbackDispatcher callback, CreateBaseImageContext context) { + CopyCommandResult result = callback.getResult(); VolumeApiResult res = new VolumeApiResult(context.getVolume()); AsyncCallFuture future = context.getFuture(); + DataObject templateOnPrimaryStoreObj = context.destObj; if (!result.isSuccess()) { + templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); res.setResult(result.getResult()); future.complete(res); return null; } - DataObject templateOnPrimaryStoreObj = objectInDataStoreMgr.get(context.srcTemplate, context.dataStore); - + + templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed); createVolumeFromBaseImageAsync(context.volume, templateOnPrimaryStoreObj, context.dataStore, future); return null; } @@ -332,10 +343,7 @@ public class VolumeServiceImpl implements VolumeService { this.templateOnStore = templateOnStore; } - public VolumeObject getVolumeObject() { - return this.vo; - } - + public AsyncCallFuture getFuture() { return this.future; } @@ -343,39 +351,32 @@ public class VolumeServiceImpl implements VolumeService { @DB protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture future) { - VolumeObject vo = (VolumeObject) volume; - try { - vo.stateTransit(Volume.Event.CreateRequested); - } catch (Exception e) { - VolumeApiResult result = new VolumeApiResult(volume); - result.setResult(e.toString()); - future.complete(result); - return; - } - + VolumeObject vo = (VolumeObject)volume; CreateVolumeFromBaseImageContext context = new CreateVolumeFromBaseImageContext(null, vo, pd, templateOnPrimaryStore, future); - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().copyBaseImageCallBack(null, null)) .setContext(context); - DataObject volumeOnPrimaryStorage = dataObjectMgr.createInternalStateOnly(volume, pd); - dataObjectMgr.copyAsync(context.templateOnStore, volumeOnPrimaryStorage, caller); + DataObject volumeOnPrimaryStorage = pd.create(volume); + volume.processEvent(Event.CreateOnlyRequested); + + motionSrv.copyAsync(context.templateOnStore, volumeOnPrimaryStorage, caller); return; } @DB - public Void copyBaseImageCallBack(AsyncCallbackDispatcher callback, CreateVolumeFromBaseImageContext context) { - VolumeObject vo = context.getVolumeObject(); - CreateCmdResult result = callback.getResult(); + public Void copyBaseImageCallBack(AsyncCallbackDispatcher callback, CreateVolumeFromBaseImageContext context) { + VolumeObject vo = context.vo; + CopyCommandResult result = callback.getResult(); VolumeApiResult volResult = new VolumeApiResult(vo); if (result.isSuccess()) { if (result.getPath() != null) { vo.setPath(result.getPath()); } - vo.stateTransit(Volume.Event.OperationSucceeded); + vo.processEvent(Event.OperationSuccessed); } else { - vo.stateTransit(Volume.Event.OperationFailed); + vo.processEvent(Event.OperationFailed); volResult.setResult(result.getResult()); } @@ -397,13 +398,253 @@ public class VolumeServiceImpl implements VolumeService { return future; } - createVolumeFromBaseImageAsync(volume, template, pd, future); + createVolumeFromBaseImageAsync(volume, templateOnPrimaryStore, pd, future); return future; } @Override - public TemplateOnPrimaryDataStoreInfo grantAccess(TemplateOnPrimaryDataStoreInfo template, EndPoint endPoint) { - // TODO Auto-generated method stub + @DB + public boolean destroyVolume(long volumeId) + throws ConcurrentOperationException { + + VolumeInfo vol = this.volFactory.getVolume(volumeId); + vol.processEvent(Event.DestroyRequested); + this.snapshotMgr.deletePoliciesForVolume(volumeId); + + vol.processEvent(Event.OperationSuccessed); + + return true; + } + + @Override + public AsyncCallFuture createVolumeFromSnapshot( + VolumeInfo volume, DataStore store, SnapshotInfo snapshot) { + AsyncCallFuture future = new AsyncCallFuture(); + + try { + DataObject volumeOnStore = store.create(volume); + volume.processEvent(Event.CreateOnlyRequested); + CreateVolumeFromBaseImageContext context = new CreateVolumeFromBaseImageContext(null, + (VolumeObject)volume, store, volumeOnStore, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null)) + .setContext(context); + this.motionSrv.copyAsync(snapshot, volumeOnStore, caller); + } catch (Exception e) { + s_logger.debug("create volume from snapshot failed", e); + VolumeApiResult result = new VolumeApiResult(volume); + result.setResult(e.toString()); + future.complete(result); + } + + return future; + } + + protected Void createVolumeFromSnapshotCallback(AsyncCallbackDispatcher callback, + CreateVolumeFromBaseImageContext context) { + CopyCommandResult result = callback.getResult(); + VolumeInfo volume = context.vo; + VolumeApiResult apiResult = new VolumeApiResult(volume); + Event event = null; + if (result.isFailed()) { + apiResult.setResult(result.getResult()); + event = Event.OperationFailed; + } else { + event = Event.OperationSuccessed; + } + + try { + volume.processEvent(event); + } catch (Exception e) { + s_logger.debug("create volume from snapshot failed", e); + apiResult.setResult(e.toString()); + } + + AsyncCallFuture future = context.future; + future.complete(apiResult); + return null; + } + + protected VolumeVO duplicateVolumeOnAnotherStorage(Volume volume, StoragePool pool) { + Long lastPoolId = volume.getPoolId(); + VolumeVO newVol = new VolumeVO(volume); + newVol.setPoolId(pool.getId()); + newVol.setFolder(pool.getPath()); + newVol.setPodId(pool.getPodId()); + newVol.setPoolId(pool.getId()); + newVol.setLastPoolId(lastPoolId); + newVol.setPodId(pool.getPodId()); + return this.volDao.persist(newVol); + } + + + private class CopyVolumeContext extends AsyncRpcConext { + final VolumeInfo srcVolume; + final VolumeInfo destVolume; + final DataStore destStore; + final AsyncCallFuture future; + /** + * @param callback + */ + public CopyVolumeContext(AsyncCompletionCallback callback, AsyncCallFuture future, VolumeInfo srcVolume, VolumeInfo destVolume, + DataStore destStore) { + super(callback); + this.srcVolume = srcVolume; + this.destVolume = destVolume; + this.destStore = destStore; + this.future = future; + } + + } + @Override + public AsyncCallFuture copyVolume(VolumeInfo srcVolume, + DataStore destStore) { + AsyncCallFuture future = new AsyncCallFuture(); + VolumeApiResult res = new VolumeApiResult(srcVolume); + try { + if (!this.snapshotMgr.canOperateOnVolume(srcVolume)) { + s_logger.debug( + "There are snapshots creating on this volume, can not move this volume"); + + res.setResult("There are snapshots creating on this volume, can not move this volume"); + future.complete(res); + return future; + } + + VolumeVO destVol = duplicateVolumeOnAnotherStorage(srcVolume, (StoragePool)destStore); + VolumeInfo destVolume = this.volFactory.getVolume(destVol.getId(), destStore); + destVolume.processEvent(Event.CreateOnlyRequested); + srcVolume.processEvent(Event.CopyingRequested); + + CopyVolumeContext context = new CopyVolumeContext(null, future, srcVolume, + destVolume, + destStore); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().copyVolumeCallBack(null, null)) + .setContext(context); + this.motionSrv.copyAsync(srcVolume, destVolume, caller); + } catch (Exception e) { + s_logger.debug("Failed to copy volume", e); + res.setResult(e.toString()); + future.complete(res); + } + return future; + } + + protected Void copyVolumeCallBack(AsyncCallbackDispatcher callback, CopyVolumeContext context) { + VolumeInfo srcVolume = context.srcVolume; + VolumeInfo destVolume = context.destVolume; + CopyCommandResult result = callback.getResult(); + AsyncCallFuture future = context.future; + VolumeApiResult res = new VolumeApiResult(destVolume); + try { + if (result.isFailed()) { + res.setResult(result.getResult()); + destVolume.processEvent(Event.OperationFailed); + srcVolume.processEvent(Event.OperationFailed); + AsyncCallFuture destroyFuture = this.expungeVolumeAsync(destVolume); + destroyFuture.get(); + future.complete(res); + return null; + } + srcVolume.processEvent(Event.OperationSuccessed); + destVolume.processEvent(Event.OperationSuccessed); + AsyncCallFuture destroyFuture = this.expungeVolumeAsync(srcVolume); + destroyFuture.get(); + future.complete(res); + return null; + } catch (Exception e) { + s_logger.debug("Failed to process copy volume callback",e); + res.setResult(e.toString()); + future.complete(res); + } + return null; } + + @Override + public AsyncCallFuture registerVolume(VolumeInfo volume, DataStore store) { + + AsyncCallFuture future = new AsyncCallFuture(); + VolumeObject vo = (VolumeObject) volume; + vo.stateTransit(Volume.Event.UploadRequested); + + CreateVolumeContext context = new CreateVolumeContext(null, vo, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().registerVolumeCallback(null, null)) + .setContext(context); + + dataObjectMgr.createAsync(volume, store, caller, true); + return future; + } + + protected Void registerVolumeCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { + CreateCmdResult result = callback.getResult(); + VolumeObject vo = (VolumeObject)context.volume; + /*if (result.isFailed()) { + vo.stateTransit(Volume.Event.OperationFailed); + } else { + vo.stateTransit(Volume.Event.OperationSucceeded); + }*/ + VolumeApiResult res = new VolumeApiResult(vo); + context.future.complete(res); + return null; + } + + + @Override + public AsyncCallFuture resize(VolumeInfo volume) { + AsyncCallFuture future = new AsyncCallFuture(); + VolumeApiResult result = new VolumeApiResult(volume); + try { + volume.processEvent(Event.ResizeRequested); + } catch (Exception e) { + s_logger.debug("Failed to change state to resize", e); + result.setResult(e.toString()); + future.complete(result); + return future; + } + CreateVolumeContext context = new CreateVolumeContext(null, volume, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().registerVolumeCallback(null, null)) + .setContext(context); + volume.getDataStore().getDriver().resize(volume, caller); + return future; + } + + protected Void resizeVolumeCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { + CreateCmdResult result = callback.getResult(); + AsyncCallFuture future = context.future; + VolumeInfo volume = (VolumeInfo)context.volume; + + if (result.isFailed()) { + try { + volume.processEvent(Event.OperationFailed); + } catch (Exception e) { + s_logger.debug("Failed to change state", e); + } + VolumeApiResult res = new VolumeApiResult(volume); + res.setResult(result.getResult()); + future.complete(res); + return null; + } + + try { + volume.processEvent(Event.OperationSuccessed); + } catch(Exception e) { + s_logger.debug("Failed to change state", e); + VolumeApiResult res = new VolumeApiResult(volume); + res.setResult(result.getResult()); + future.complete(res); + return null; + } + + VolumeApiResult res = new VolumeApiResult(volume); + future.complete(res); + + return null; + } + + + } diff --git a/framework/api/pom.xml b/framework/api/pom.xml new file mode 100644 index 00000000000..5260ebc4bf6 --- /dev/null +++ b/framework/api/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + cloud-framework-api + + org.apache.cloudstack + cloudstack-framework + 4.2.0-SNAPSHOT + ../pom.xml + + + + + org.apache.cloudstack + cloud-utils + 4.2.0-SNAPSHOT + + + + + + install + src + ${project.basedir}/test + + + ${project.basedir}/test/resources + + + + diff --git a/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java b/framework/api/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java similarity index 100% rename from framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java rename to framework/api/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java diff --git a/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java b/framework/api/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java similarity index 100% rename from framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java rename to framework/api/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java diff --git a/framework/events/pom.xml b/framework/events/pom.xml index d21275a6744..7c788c35bbd 100644 --- a/framework/events/pom.xml +++ b/framework/events/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-framework - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml diff --git a/framework/ipc/pom.xml b/framework/ipc/pom.xml index 6e01b7ec5d2..b7f4fcc78ce 100644 --- a/framework/ipc/pom.xml +++ b/framework/ipc/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-framework - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml @@ -25,13 +25,13 @@ org.apache.cloudstack cloud-core - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT org.apache.cloudstack cloud-utils - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/framework/jobs/pom.xml b/framework/jobs/pom.xml index 8b12f5d4bb5..56490216f16 100644 --- a/framework/jobs/pom.xml +++ b/framework/jobs/pom.xml @@ -26,4 +26,4 @@ quartz 2.1.6 - \ No newline at end of file + diff --git a/framework/pom.xml b/framework/pom.xml index dafc0eb5a2d..4633dab2b30 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT install @@ -33,5 +33,6 @@ ipc rest events + api diff --git a/framework/rest/pom.xml b/framework/rest/pom.xml index e8322e03e59..2a22155603a 100644 --- a/framework/rest/pom.xml +++ b/framework/rest/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-framework - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../pom.xml cloud-framework-rest diff --git a/packaging/centos63/cloud-agent.rc b/packaging/centos63/cloud-agent.rc index acf81316479..65b0cd09250 100755 --- a/packaging/centos63/cloud-agent.rc +++ b/packaging/centos63/cloud-agent.rc @@ -31,7 +31,8 @@ whatami=cloudstack-agent SHORTNAME="$whatami" PIDFILE=/var/run/"$whatami".pid LOCKFILE=/var/lock/subsys/"$SHORTNAME" -LOGFILE=/var/log/cloudstack/agent/agent.log +LOGDIR=/var/log/cloudstack/agent +LOGFILE=${LOGDIR}/agent.log PROGNAME="Cloud Agent" CLASS="com.cloud.agent.AgentShell" JSVC=`which jsvc 2>/dev/null`; @@ -67,7 +68,8 @@ export CLASSPATH="$SCP:$DCP:$ACP:$JCP:/etc/cloudstack/agent:/usr/share/cloudstac start() { echo -n $"Starting $PROGNAME: " if hostname --fqdn >/dev/null 2>&1 ; then - $JSVC -cp "$CLASSPATH" -pidfile "$PIDFILE" $CLASS + $JSVC -cp "$CLASSPATH" -pidfile "$PIDFILE" \ + -errfile $LOGDIR/cloudstack-agent.out -outfile $LOGDIR/cloudstack-agent.out $CLASS RETVAL=$? echo else diff --git a/packaging/centos63/cloud-usage.rc b/packaging/centos63/cloud-usage.rc index 8bee5aeb6a0..6eff1233806 100755 --- a/packaging/centos63/cloud-usage.rc +++ b/packaging/centos63/cloud-usage.rc @@ -35,7 +35,8 @@ SHORTNAME="cloudstack-usage" PIDFILE=/var/run/"$SHORTNAME".pid LOCKFILE=/var/lock/subsys/"$SHORTNAME" -LOGFILE=/var/log/cloudstack/usage/usage.log +LOGDIR=/var/log/cloudstack/usage +LOGFILE=${LOGDIR}/usage.log PROGNAME="CloudStack Usage Monitor" CLASS="com.cloud.usage.UsageServer" PROG="jsvc" @@ -79,7 +80,8 @@ start() { echo -n "Starting $PROGNAME" "$SHORTNAME" - if daemon --pidfile $PIDFILE $DAEMON -cp "$CLASSPATH" -pidfile "$PIDFILE" -user "$USER" -errfile SYSLOG -Dpid=$$ $CLASS + if daemon --pidfile $PIDFILE $DAEMON -cp "$CLASSPATH" -pidfile "$PIDFILE" -user "$USER" \ + -errfile $LOGDIR/cloudstack-usage.out -outfile $LOGDIR/cloudstack-usage.out -Dpid=$$ $CLASS RETVAL=$? then rc=0 diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index d8143214b6b..72022d6f5ad 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -78,7 +78,7 @@ Requires: mkisofs Requires: MySQL-python Requires: python-paramiko Requires: ipmitool -Requires: %{name}-common = 4.1.0 +Requires: %{name}-common = %{_ver} Obsoletes: cloud-client < 4.1.0 Obsoletes: cloud-client-ui < 4.1.0 Obsoletes: cloud-daemonize < 4.1.0 @@ -181,8 +181,8 @@ mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms mkdir -p ${RPM_BUILD_ROOT}%{_libdir}/python2.6/site-packages/ cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts -install -D console-proxy/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso -install -D console-proxy/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip +install -D services/console-proxy/server/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso +install -D services/console-proxy/server/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{_libdir}/python2.6/site-packages/cloud_utils.py cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{_libdir}/python2.6/site-packages/ python -m py_compile ${RPM_BUILD_ROOT}%{_libdir}/python2.6/site-packages/cloud_utils.py @@ -215,14 +215,14 @@ install -D client/target/utilities/bin/cloud-sysvmadm ${RPM_BUILD_ROOT}%{_bindir install -D client/target/utilities/bin/cloud-update-xenserver-licenses ${RPM_BUILD_ROOT}%{_bindir}/%{name}-update-xenserver-licenses cp -r client/target/utilities/scripts/db/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/setup -cp -r client/target/cloud-client-ui-4.1.0-SNAPSHOT/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client +cp -r client/target/cloud-client-ui-*-SNAPSHOT/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client # Don't package the scripts in the management webapp rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/scripts rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/vms for name in db.properties log4j-cloud.xml tomcat6-nonssl.conf tomcat6-ssl.conf server-ssl.xml server-nonssl.xml \ - catalina.policy catalina.properties db-enc.properties classpath.conf tomcat-users.xml web.xml ; do + catalina.policy catalina.properties db-enc.properties classpath.conf tomcat-users.xml web.xml environment.properties ; do mv ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/$name \ ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/$name done @@ -284,7 +284,7 @@ fi %pre management id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -c "CloudStack unprivileged user" \ - -r -s /bin/sh -d %{_localstatedir}/cloud/management cloud|| true + -r -s /bin/sh -d %{_localstatedir}/cloudstack/management cloud|| true # set max file descriptors for cloud user to 4096 sed -i /"cloud hard nofile"/d /etc/security/limits.conf @@ -300,9 +300,9 @@ if [ "$1" == "1" ] ; then /sbin/chkconfig --level 345 cloud-management on > /dev/null 2>&1 || true fi -if [ ! -f %{_datadir}/cloud/management/webapps/client/WEB-INF/classes/scripts/scripts/vm/hypervisor/xenserver/vhd-util ] ; then +if [ ! -f %{_datadir}/cloudstack/management/webapps/client/WEB-INF/classes/scripts/scripts/vm/hypervisor/xenserver/vhd-util ] ; then echo Please download vhd-util from http://download.cloud.com.s3.amazonaws.com/tools/vhd-util and put it in - echo %{_datadir}/cloud/management/webapps/client/WEB-INF/classes/scripts/vm/hypervisor/xenserver/ + echo %{_datadir}/cloudstack/management/webapps/client/WEB-INF/classes/scripts/vm/hypervisor/xenserver/ fi #No default permission as the permission setup is complex @@ -336,6 +336,7 @@ fi %config(noreplace) %{_sysconfdir}/%{name}/management/server-ssl.xml %config(noreplace) %{_sysconfdir}/%{name}/management/tomcat-users.xml %config(noreplace) %{_sysconfdir}/%{name}/management/web.xml +%config(noreplace) %{_sysconfdir}/%{name}/management/environment.properties %attr(0755,root,root) %{_initrddir}/%{name}-management %attr(0755,root,root) %{_bindir}/%{name}-setup-management %attr(0755,root,root) %{_bindir}/%{name}-update-xenserver-licenses diff --git a/packaging/centos63/package.sh b/packaging/centos63/package.sh old mode 100644 new mode 100755 index 5b1bab49b61..2515ecba11f --- a/packaging/centos63/package.sh +++ b/packaging/centos63/package.sh @@ -18,10 +18,10 @@ CWD=`pwd` RPMDIR=$CWD/../../dist/rpmbuild +PACK_PROJECT=cloudstack - -VERSION=`(cd ../../; mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version) | grep -v '^\['` +VERSION=`(cd ../../; mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version) | grep '^[0-9]\.'` if echo $VERSION | grep SNAPSHOT ; then REALVER=`echo $VERSION | cut -d '-' -f 1` DEFVER="-D_ver $REALVER" @@ -34,12 +34,12 @@ else fi mkdir -p $RPMDIR/SPECS -mkdir -p $RPMDIR/SOURCES/cloudstack-$VERSION +mkdir -p $RPMDIR/SOURCES/$PACK_PROJECT-$VERSION -(cd ../../; tar -c --exclude .git --exclude dist . | tar -C $RPMDIR/SOURCES/cloudstack-$VERSION -x ) -(cd $RPMDIR/SOURCES/; tar -czf cloudstack-$VERSION.tgz cloudstack-$VERSION) +(cd ../../; tar -c --exclude .git --exclude dist . | tar -C $RPMDIR/SOURCES/$PACK_PROJECT-$VERSION -x ) +(cd $RPMDIR/SOURCES/; tar -czf $PACK_PROJECT-$VERSION.tgz $PACK_PROJECT-$VERSION) cp cloud.spec $RPMDIR/SPECS -(cd $RPMDIR; rpmbuild -ba SPECS/cloud.spec "-D_topdir $RPMDIR" "$DEFVER" "$DEFREL" "$DEFPRE" ) +(cd $RPMDIR; rpmbuild -ba SPECS/cloud.spec "-D_topdir $RPMDIR" "$DEFVER" "$DEFREL" "$DEFPRE") diff --git a/packaging/centos63/replace.properties b/packaging/centos63/replace.properties index bcc4d4a0087..211cc95449f 100644 --- a/packaging/centos63/replace.properties +++ b/packaging/centos63/replace.properties @@ -21,7 +21,6 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost -MSMNTDIR=/mnt COMPONENTS-SPEC=components-premium.xml AWSAPILOG=awsapi.log REMOTEHOST=localhost @@ -45,7 +44,7 @@ MSCONF=/etc/cloudstack/management MSENVIRON=/usr/share/cloudstack-management MSLOG=/var/log/cloudstack/management/management-server.log MSLOGDIR=/var/log/cloudstack/management/ -MSMNTDIR=/var/lib/cloud/mnt +MSMNTDIR=/var/cloudstack/mnt MSUSER=cloud PIDDIR=/var/run PLUGINJAVADIR=/usr/share/cloudstack-management/plugin diff --git a/patches/pom.xml b/patches/pom.xml index a662bcb9791..00eec02ddc9 100644 --- a/patches/pom.xml +++ b/patches/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT install diff --git a/patches/systemvm/debian/config/etc/logrotate.d/dnsmasq b/patches/systemvm/debian/config/etc/logrotate.d/dnsmasq index f448420e176..838415d3049 100644 --- a/patches/systemvm/debian/config/etc/logrotate.d/dnsmasq +++ b/patches/systemvm/debian/config/etc/logrotate.d/dnsmasq @@ -6,7 +6,7 @@ delaycompress sharedscripts postrotate - [ ! -f /var/run/dnsmasq.pid ] || kill -USR2 `cat /var/run/dnsmasq.pid` + [ ! -f /var/run/dnsmasq/dnsmasq.pid ] || kill -USR2 `cat /var/run/dnsmasq/dnsmasq.pid` endscript create 0640 nobody root } diff --git a/patches/systemvm/debian/config/root/func.sh b/patches/systemvm/debian/config/root/func.sh index 4047a4047a6..86317a06843 100644 --- a/patches/systemvm/debian/config/root/func.sh +++ b/patches/systemvm/debian/config/root/func.sh @@ -42,7 +42,11 @@ getLockFile() { psline=`ps u $$` echo $psline > $__LOCKFILE - + if [ ! -e $__LOCKFILE ] + then + return + fi + for i in `seq 1 $(($__TIMEOUT * 10))` do currlock=`ls -tr /tmp/$1-*.lock | head -n1` diff --git a/plugins/acl/static-role-based/pom.xml b/plugins/acl/static-role-based/pom.xml index a2e8d05d48e..e40cecb9d65 100644 --- a/plugins/acl/static-role-based/pom.xml +++ b/plugins/acl/static-role-based/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/api/discovery/pom.xml b/plugins/api/discovery/pom.xml index 1cfc5c2eaf2..5d9ad75ea3a 100644 --- a/plugins/api/discovery/pom.xml +++ b/plugins/api/discovery/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java b/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java old mode 100644 new mode 100755 index 30123c79df2..293a1a47c19 --- a/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java @@ -69,8 +69,10 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { long startTime = System.nanoTime(); s_apiNameDiscoveryResponseMap = new HashMap(); Set> cmdClasses = new HashSet>(); - for(PluggableService service: _services) - cmdClasses.addAll(service.getCommands()); + for(PluggableService service: _services) { + s_logger.debug(String.format("getting api commands of service: %s", service.getClass().getName())); + cmdClasses.addAll(service.getCommands()); + } cacheResponseMap(cmdClasses); long endTime = System.nanoTime(); s_logger.info("Api Discovery Service: Annotation, docstrings, api relation graph processed in " + (endTime - startTime) / 1000000.0 + " ms"); diff --git a/plugins/api/rate-limit/pom.xml b/plugins/api/rate-limit/pom.xml index 1f0330916a9..5645f0b3a32 100644 --- a/plugins/api/rate-limit/pom.xml +++ b/plugins/api/rate-limit/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitService.java b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitService.java index c5b715019b6..a135556a502 100644 --- a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitService.java +++ b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitService.java @@ -22,7 +22,6 @@ import com.cloud.utils.component.PluggableService; /** * Provide API rate limit service - * @author minc * */ public interface ApiRateLimitService extends PluggableService{ diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/EhcacheLimitStore.java b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/EhcacheLimitStore.java index 659cf81b0e6..ee7c528bd07 100644 --- a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/EhcacheLimitStore.java +++ b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/EhcacheLimitStore.java @@ -23,7 +23,6 @@ import net.sf.ehcache.constructs.blocking.LockTimeoutException; /** * A Limit store implementation using Ehcache. - * @author minc * */ public class EhcacheLimitStore implements LimitStore { diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/LimitStore.java b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/LimitStore.java index a5e086b3029..373d9652ee9 100644 --- a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/LimitStore.java +++ b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/LimitStore.java @@ -20,7 +20,6 @@ import com.cloud.user.Account; /** * Interface to define how an api limit store should work. - * @author minc * */ public interface LimitStore { diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/StoreEntry.java b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/StoreEntry.java index 76e8a2d9281..05a7029dcb0 100644 --- a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/StoreEntry.java +++ b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/StoreEntry.java @@ -18,7 +18,6 @@ package org.apache.cloudstack.ratelimit; /** * Interface for each entry in LimitStore. - * @author minc * */ public interface StoreEntry { diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/StoreEntryImpl.java b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/StoreEntryImpl.java index e8143e52370..9f10fe68a41 100644 --- a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/StoreEntryImpl.java +++ b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/StoreEntryImpl.java @@ -20,7 +20,6 @@ import java.util.concurrent.atomic.AtomicInteger; /** * Implementation of limit store entry. - * @author minc * */ public class StoreEntryImpl implements StoreEntry { diff --git a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/APITest.java b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/APITest.java index 7701b1515b0..e75e852f0b7 100644 --- a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/APITest.java +++ b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/APITest.java @@ -37,8 +37,6 @@ import com.google.gson.Gson; /** * Base class for API Test * - * @author Min Chen - * */ public abstract class APITest { diff --git a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/LoginResponse.java b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/LoginResponse.java index 719f39c0a5e..61a178033af 100644 --- a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/LoginResponse.java +++ b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/LoginResponse.java @@ -24,8 +24,6 @@ import com.google.gson.annotations.SerializedName; /** * Login Response object * - * @author Min Chen - * */ public class LoginResponse extends BaseResponse { diff --git a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java index 72d354c6c77..f9352333d12 100644 --- a/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java +++ b/plugins/api/rate-limit/test/org/apache/cloudstack/ratelimit/integration/RateLimitIntegrationTest.java @@ -34,9 +34,6 @@ import com.cloud.utils.exception.CloudRuntimeException; /** * Test fixture to do integration rate limit test. * Currently we commented out this test suite since it requires a real MS and Db running. - * - * @author Min Chen - * */ public class RateLimitIntegrationTest extends APITest { diff --git a/plugins/deployment-planners/user-concentrated-pod/pom.xml b/plugins/deployment-planners/user-concentrated-pod/pom.xml index 78829356170..df7c660630e 100644 --- a/plugins/deployment-planners/user-concentrated-pod/pom.xml +++ b/plugins/deployment-planners/user-concentrated-pod/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/deployment-planners/user-dispersing/pom.xml b/plugins/deployment-planners/user-dispersing/pom.xml index 33f6582e72f..0e5dbd58eb6 100644 --- a/plugins/deployment-planners/user-dispersing/pom.xml +++ b/plugins/deployment-planners/user-dispersing/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml index 6a47983a9b5..bd4d0977c04 100644 --- a/plugins/event-bus/rabbitmq/pom.xml +++ b/plugins/event-bus/rabbitmq/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/file-systems/netapp/pom.xml b/plugins/file-systems/netapp/pom.xml index e1c8866d15d..0e6f427da36 100644 --- a/plugins/file-systems/netapp/pom.xml +++ b/plugins/file-systems/netapp/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/host-allocators/random/pom.xml b/plugins/host-allocators/random/pom.xml index ba7e1ae1e65..6fc76fe8dad 100644 --- a/plugins/host-allocators/random/pom.xml +++ b/plugins/host-allocators/random/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/baremetal/pom.xml b/plugins/hypervisors/baremetal/pom.xml index 600eedb1440..328bd963c91 100755 --- a/plugins/hypervisors/baremetal/pom.xml +++ b/plugins/hypervisors/baremetal/pom.xml @@ -21,7 +21,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml cloud-plugin-hypervisor-baremetal diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbVO.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbVO.java deleted file mode 100755 index ee3848a5e9d..00000000000 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbVO.java +++ /dev/null @@ -1,104 +0,0 @@ -// 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. -// -// Automatically generated by addcopyright.py at 01/29/2013 -package com.cloud.baremetal.database; - -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name="baremetal_cmdb") -public class BaremetalCmdbVO { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - private long id; - - @Column(name="uuid") - private String uuid; - - @Column(name="zone_id") - private long zoneId; - - @Column(name="url") - private String url; - - @Column(name="password") - private String password; - - @Column(name="username") - private String username; - - public BaremetalCmdbVO() { - uuid = UUID.randomUUID().toString(); - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getUuid() { - return uuid; - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public long getZoneId() { - return zoneId; - } - - public void setZoneId(long zoneId) { - this.zoneId = zoneId; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } -} diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/AddBaremetalHostCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/AddBaremetalHostCmd.java index 5222d103699..f07b212173f 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/AddBaremetalHostCmd.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/AddBaremetalHostCmd.java @@ -18,17 +18,24 @@ // Automatically generated by addcopyright.py at 01/29/2013 package com.cloud.baremetal.manager; +import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.command.admin.host.AddHostCmd; - +import org.apache.cloudstack.api.response.HostResponse; +@APICommand(name="addBaremetalHost", description="add a baremetal host", responseObject = HostResponse.class) public class AddBaremetalHostCmd extends AddHostCmd { @Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, description="ip address intentionally allocated to this host after provisioning") private String vmIpAddress; public AddBaremetalHostCmd() { + } + + @Override + public void execute(){ this.getFullUrlParams().put(ApiConstants.BAREMETAL_DISCOVER_NAME, BareMetalDiscoverer.class.getName()); + super.execute(); } public String getVmIpAddress() { diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java index 9b0a5104889..28c83753c09 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java @@ -276,5 +276,13 @@ public class BareMetalDiscoverer extends DiscovererBase implements Discoverer, R return new DeleteHostAnswer(true); } + + @Override + protected HashMap buildConfigParams(HostVO host) { + HashMap params = super.buildConfigParams(host); + params.put("hostId", host.getId()); + params.put("ipaddress", host.getPrivateIpAddress()); + return params; + } } diff --git a/server/src/com/cloud/deploy/BareMetalPlanner.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalPlanner.java similarity index 85% rename from server/src/com/cloud/deploy/BareMetalPlanner.java rename to plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalPlanner.java index 829a4662e12..97b2840f419 100755 --- a/server/src/com/cloud/deploy/BareMetalPlanner.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalPlanner.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.deploy; +package com.cloud.baremetal.manager; import java.util.List; import java.util.Map; @@ -23,17 +23,20 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.*; +import com.cloud.dc.ClusterDetailsDao; import org.apache.log4j.Logger; import com.cloud.capacity.CapacityManager; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.DataCenter; -import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.deploy.DeploymentPlanner; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -57,16 +60,14 @@ public class BareMetalPlanner extends AdapterBase implements DeploymentPlanner { @Inject protected ConfigurationDao _configDao; @Inject protected CapacityManager _capacityMgr; @Inject protected ResourceManager _resourceMgr; + @Inject protected ClusterDetailsDao _clusterDetailsDao; @Override public DeployDestination plan(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid) throws InsufficientServerCapacityException { VirtualMachine vm = vmProfile.getVirtualMachine(); - ServiceOffering offering = vmProfile.getServiceOffering(); + ServiceOffering offering = vmProfile.getServiceOffering(); String hostTag = null; - - String opFactor = _configDao.getValue(Config.CPUOverprovisioningFactor.key()); - float cpuOverprovisioningFactor = NumbersUtil.parseFloat(opFactor, 1); - + String haVmTag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.HaTag); if (vm.getLastHostId() != null && haVmTag == null) { @@ -122,7 +123,13 @@ public class BareMetalPlanner extends AdapterBase implements DeploymentPlanner { return null; } for (HostVO h : hosts) { - if (_capacityMgr.checkIfHostHasCapacity(h.getId(), cpu_requested, ram_requested, false, cpuOverprovisioningFactor, true)) { + long cluster_id = h.getClusterId(); + ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id,"cpuOvercommitRatio") ; + ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id,"memoryOvercommitRatio"); + Float cpuOvercommitRatio = Float.parseFloat(cluster_detail_cpu.getValue()); + Float memoryOvercommitRatio = Float.parseFloat(cluster_detail_ram.getValue()); + + if (_capacityMgr.checkIfHostHasCapacity(h.getId(), cpu_requested, ram_requested, false, cpuOvercommitRatio, memoryOvercommitRatio, true)) { s_logger.debug("Find host " + h.getId() + " has enough capacity"); DataCenter dc = _dcDao.findById(h.getDataCenterId()); Pod pod = _podDao.findById(h.getPodId()); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java index ba5e811eeae..33725f63b1c 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java @@ -58,6 +58,11 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem private final static Logger s_logger = Logger.getLogger(BareMetalTemplateAdapter.class); @Inject HostDao _hostDao; @Inject ResourceManager _resourceMgr; + + @Override + public String getName() { + return TemplateAdapterType.BareMetal.getName(); + } @Override public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException { diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManager.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManager.java index 1599050453a..6467c945795 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManager.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManager.java @@ -20,8 +20,9 @@ package com.cloud.baremetal.manager; import com.cloud.network.Network.Provider; import com.cloud.utils.component.Manager; +import com.cloud.utils.component.PluggableService; -public interface BaremetalManager extends Manager { +public interface BaremetalManager extends Manager, PluggableService { public static final String EchoSecurityGroupAgent = "EchoSecurityGroupAgent"; public static final String ExternalBaremetalSystemUrl = "ExternalBaremetalSystemUrl"; public static final String DO_PXE = "doPxe"; diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java index b07a6bbf273..b41d6ca0426 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java @@ -18,6 +18,8 @@ // Automatically generated by addcopyright.py at 01/29/2013 package com.cloud.baremetal.manager; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import javax.ejb.Local; @@ -110,4 +112,11 @@ public class BaremetalManagerImpl extends ManagerBase implements BaremetalManage return true; } + + @Override + public List> getCommands() { + List> cmds = new ArrayList>(); + cmds.add(AddBaremetalHostCmd.class); + return cmds; + } } diff --git a/server/src/com/cloud/baremetal/PxeServerService.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalPlannerSelector.java old mode 100644 new mode 100755 similarity index 56% rename from server/src/com/cloud/baremetal/PxeServerService.java rename to plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalPlannerSelector.java index 0a9918450f5..9daee3f3fe7 --- a/server/src/com/cloud/baremetal/PxeServerService.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalPlannerSelector.java @@ -1,35 +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.baremetal; - -import com.cloud.baremetal.PxeServerManager.PxeServerType; -import com.cloud.deploy.DeployDestination; -import com.cloud.host.Host; -import com.cloud.uservm.UserVm; -import com.cloud.utils.component.Adapter; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachineProfile; - -public interface PxeServerService extends Adapter { - - public Host addPxeServer(PxeServerProfile profile); - - public boolean prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId); - - public boolean prepareCreateTemplate(Long pxeServerId, UserVm vm, String templateUrl); -} +// 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.baremetal.manager; + +import java.util.Map; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import com.cloud.deploy.AbstractDeployPlannerSelector; +import com.cloud.deploy.DeployPlannerSelector; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.vm.UserVmVO; +@Local(value = {DeployPlannerSelector.class}) +public class BaremetalPlannerSelector extends AbstractDeployPlannerSelector{ + + @Override + public String selectPlanner(UserVmVO vm) { + if (vm.getHypervisorType() == HypervisorType.BareMetal) { + return "BareMetalPlanner"; + } + return null; + } + +} diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalDhcpCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalDhcpCmd.java index 8a3d4d74191..c74983222f2 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalDhcpCmd.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalDhcpCmd.java @@ -20,11 +20,14 @@ package com.cloud.baremetal.networkservice; import javax.inject.Inject; +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.PhysicalNetworkResponse; +import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.log4j.Logger; @@ -37,7 +40,7 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.UserContext; - +@APICommand(name="addBaremetalDhcp", description="adds a baremetal dhcp server", responseObject = BaremetalDhcpResponse.class) public class AddBaremetalDhcpCmd extends BaseAsyncCmd { private static final String s_name = "addexternaldhcpresponse"; public static final Logger s_logger = Logger.getLogger(AddBaremetalDhcpCmd.class); @@ -47,10 +50,10 @@ public class AddBaremetalDhcpCmd extends BaseAsyncCmd { ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.LONG, required=true, description="the Physical Network ID") + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType=PhysicalNetworkResponse.class, required=true, description="the Physical Network ID") private Long physicalNetworkId; - @Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, required = true, description="Pod Id") + @Parameter(name=ApiConstants.POD_ID, type=CommandType.UUID, entityType=PodResponse.class, required = true, description="Pod Id") private Long podId; @Parameter(name=ApiConstants.DHCP_SERVER_TYPE, type=CommandType.STRING, required = true, description="Type of dhcp device") diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalKickStartPxeCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalKickStartPxeCmd.java index 4c3d0b22576..596a86dac8f 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalKickStartPxeCmd.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalKickStartPxeCmd.java @@ -18,10 +18,11 @@ // Automatically generated by addcopyright.py at 01/29/2013 package com.cloud.baremetal.networkservice; +import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.Parameter; - +@APICommand(name="addBaremetalPxeKickStartServer", description="add a baremetal pxe server", responseObject = BaremetalPxeKickStartResponse.class) public class AddBaremetalKickStartPxeCmd extends AddBaremetalPxeCmd { @Parameter(name=ApiConstants.TFTP_DIR, type=CommandType.STRING, required = true, description="Tftp root directory of PXE server") private String tftpDir; diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxeCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxeCmd.java index cd8da4a58b9..63e11478e4c 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxeCmd.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxeCmd.java @@ -20,11 +20,14 @@ package com.cloud.baremetal.networkservice; import javax.inject.Inject; +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.PhysicalNetworkResponse; +import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.log4j.Logger; @@ -37,7 +40,6 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.UserContext; - public class AddBaremetalPxeCmd extends BaseAsyncCmd { private static final String s_name = "addexternalpxeresponse"; public static final Logger s_logger = Logger.getLogger(AddBaremetalPxeCmd.class); @@ -46,10 +48,10 @@ public class AddBaremetalPxeCmd extends BaseAsyncCmd { ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.LONG, required=true, description="the Physical Network ID") + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType=PhysicalNetworkResponse.class, required=true, description="the Physical Network ID") private Long physicalNetworkId; - @Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, description="Pod Id") + @Parameter(name=ApiConstants.POD_ID, type=CommandType.UUID, entityType=PodResponse.class, description="Pod Id") private Long podId; @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the external pxe device") diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxePingServerCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxePingServerCmd.java index 70796f3499f..01cafd435da 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxePingServerCmd.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxePingServerCmd.java @@ -18,9 +18,11 @@ // Automatically generated by addcopyright.py at 01/29/2013 package com.cloud.baremetal.networkservice; +import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.Parameter; +@APICommand(name="addBaremetalPxePingServer", description="add a baremetal ping pxe server", responseObject = BaremetalPxePingResponse.class) public class AddBaremetalPxePingServerCmd extends AddBaremetalPxeCmd { @Parameter(name=ApiConstants.PING_STORAGE_SERVER_IP, type=CommandType.STRING, required = true, description="PING storage server ip") diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPingServiceImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPingServiceImpl.java index 3e21750132e..d6b96a81807 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPingServiceImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPingServiceImpl.java @@ -297,4 +297,10 @@ public class BareMetalPingServiceImpl extends BareMetalPxeServiceBase implements } return responses; } + + + @Override + public String getPxeServiceType() { + return BaremetalPxeManager.BaremetalPxeType.PING.toString(); + } } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java index af9e103f77b..f87bf71ca13 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java @@ -319,6 +319,9 @@ public class BaremetalDhcpManagerImpl extends ManagerBase implements BaremetalDh @Override public List> getCommands() { - return null; + List> cmds = new ArrayList>(); + cmds.add(AddBaremetalDhcpCmd.class); + cmds.add(ListBaremetalDhcpCmd.class); + return cmds; } } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResponse.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResponse.java index 952ac41a701..1875d3947a0 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResponse.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResponse.java @@ -18,12 +18,16 @@ // Automatically generated by addcopyright.py at 01/29/2013 package com.cloud.baremetal.networkservice; +import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import com.cloud.baremetal.database.BaremetalDhcpVO; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; +@EntityReference(value=BaremetalDhcpVO.class) public class BaremetalDhcpResponse extends BaseResponse { @SerializedName(ApiConstants.ID) @Param(description="device id of ") private String id; diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java index 938b3ac1d46..2b9b140607b 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java @@ -32,6 +32,7 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.routing.VmDataCommand; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; import com.cloud.utils.ssh.SSHCmdHelper; import com.cloud.vm.VirtualMachine.State; @@ -70,27 +71,27 @@ public class BaremetalKickStartPxeResource extends BaremetalPxeResourceBase { String prepareScript = "scripts/network/ping/prepare_kickstart_bootfile.py"; String prepareScriptPath = Script.findScript("", prepareScript); if (prepareScriptPath == null) { - throw new ConfigurationException("Can not find prepare_kickstart_bootfile.py at " + prepareScriptPath); + throw new ConfigurationException("Can not find prepare_kickstart_bootfile.py at " + prepareScript); } scp.put(prepareScriptPath, "/usr/bin/", "0755"); String cpScript = "scripts/network/ping/prepare_kickstart_kernel_initrd.py"; String cpScriptPath = Script.findScript("", cpScript); if (cpScriptPath == null) { - throw new ConfigurationException("Can not find prepare_kickstart_kernel_initrd.py at " + cpScriptPath); + throw new ConfigurationException("Can not find prepare_kickstart_kernel_initrd.py at " + cpScript); } scp.put(cpScriptPath, "/usr/bin/", "0755"); String userDataScript = "scripts/network/ping/baremetal_user_data.py"; String userDataScriptPath = Script.findScript("", userDataScript); if (userDataScriptPath == null) { - throw new ConfigurationException("Can not find baremetal_user_data.py at " + userDataScriptPath); + throw new ConfigurationException("Can not find baremetal_user_data.py at " + userDataScript); } scp.put(userDataScriptPath, "/usr/bin/", "0755"); return true; } catch (Exception e) { - throw new ConfigurationException(e.getMessage()); + throw new CloudRuntimeException(e); } finally { if (sshConnection != null) { sshConnection.close(); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java index 617893fc16c..ba5fb0d0b6c 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java @@ -233,6 +233,11 @@ public class BaremetalKickStartServiceImpl extends BareMetalPxeServiceBase imple responses.add(getApiResponse(vo)); } return responses; + } + + @Override + public String getPxeServiceType() { + return BaremetalPxeManager.BaremetalPxeType.KICK_START.toString(); } } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java index bc4bcd3d53a..7b8d528b4b4 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java @@ -166,13 +166,11 @@ public class BaremetalPxeElement extends AdapterBase implements NetworkElement { @Override public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { - // TODO Auto-generated method stub - return false; + return true; } @Override public boolean verifyServicesCombination(Set services) { - // TODO Auto-generated method stub - return false; + return true; } } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeKickStartResponse.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeKickStartResponse.java index 09c6cc6769d..64f22e0947e 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeKickStartResponse.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeKickStartResponse.java @@ -19,10 +19,13 @@ package com.cloud.baremetal.networkservice; import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.EntityReference; +import com.cloud.baremetal.database.BaremetalPxeVO; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; - + +@EntityReference(value=BaremetalPxeVO.class) public class BaremetalPxeKickStartResponse extends BaremetalPxeResponse { @SerializedName(ApiConstants.TFTP_DIR) @Param(description="Tftp root directory of PXE server") private String tftpDir; diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java index 6e3963def53..6288f918567 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java @@ -23,6 +23,7 @@ package com.cloud.baremetal.networkservice; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -53,7 +54,6 @@ import com.cloud.resource.UnableDeleteHostException; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.uservm.UserVm; import com.cloud.utils.StringUtils; -import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria2; @@ -106,12 +106,13 @@ public class BaremetalPxeManagerImpl extends ManagerBase implements BaremetalPxe } protected BaremetalPxeService getServiceByType(String type) { - BaremetalPxeService _service; - _service = AdapterBase.getAdapterByName(_services, type); - if (_service == null) { - throw new CloudRuntimeException("Cannot find PXE service for " + type); - } - return _service; + for (BaremetalPxeService service : _services) { + if (service.getPxeServiceType().equals(type)) { + return service; + } + } + + throw new CloudRuntimeException("Cannot find PXE service for " + type); } @Override @@ -236,7 +237,10 @@ public class BaremetalPxeManagerImpl extends ManagerBase implements BaremetalPxe @Override public List> getCommands() { - // TODO Auto-generated method stub - return null; + List> cmds = new ArrayList>(); + cmds.add(AddBaremetalKickStartPxeCmd.class); + cmds.add(AddBaremetalPxePingServerCmd.class); + cmds.add(ListBaremetalPxePingServersCmd.class); + return cmds; } } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxePingResponse.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxePingResponse.java index adbf0530e00..81bd2511355 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxePingResponse.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxePingResponse.java @@ -19,10 +19,12 @@ package com.cloud.baremetal.networkservice; import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.EntityReference; +import com.cloud.baremetal.database.BaremetalPxeVO; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; - +@EntityReference(value=BaremetalPxeVO.class) public class BaremetalPxePingResponse extends BaremetalPxeResponse { @SerializedName(ApiConstants.PING_STORAGE_SERVER_IP) @Param(description="PING storage server ip") private String pingStorageServerIp; diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java old mode 100644 new mode 100755 index 8504f82a86f..9fd560f2bc5 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java @@ -46,6 +46,8 @@ public interface BaremetalPxeService extends Adapter { List listPxeServers(ListBaremetalPxePingServersCmd cmd); + String getPxeServiceType(); + public static final String PXE_PARAM_TYPE = "type"; public static final String PXE_PARAM_ZONE = "zone"; public static final String PXE_PARAM_POD = "pod"; diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java index ae582544323..3d9f5819582 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java @@ -149,7 +149,7 @@ public class BaremetalUserdataElement extends AdapterBase implements NetworkElem @Override public boolean canEnableIndividualServices() { // TODO Auto-generated method stub - return false; + return true; } @@ -162,14 +162,12 @@ public class BaremetalUserdataElement extends AdapterBase implements NetworkElem @Override public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { - // TODO Auto-generated method stub - return false; + return true; } @Override public boolean verifyServicesCombination(Set services) { - // TODO Auto-generated method stub - return false; + return true; } } diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalDhcpCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalDhcpCmd.java index 14b74339fbf..1dc46a8f044 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalDhcpCmd.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalDhcpCmd.java @@ -22,6 +22,7 @@ import java.util.List; import javax.inject.Inject; +import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -37,7 +38,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; - +@APICommand(name="listBaremetalDhcp", description="list baremetal dhcp servers", responseObject = BaremetalDhcpResponse.class) public class ListBaremetalDhcpCmd extends BaseListCmd { private static final Logger s_logger = Logger.getLogger(ListBaremetalDhcpCmd.class); private static final String s_name = "listexternaldhcpresponse"; diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalPxePingServersCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalPxePingServersCmd.java index b4c569f0969..0b418f01d7a 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalPxePingServersCmd.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalPxePingServersCmd.java @@ -22,6 +22,7 @@ import java.util.List; import javax.inject.Inject; +import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -37,7 +38,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; - +@APICommand(name="listBaremetalPxePingServer", description="list baremetal ping pxe server", responseObject = BaremetalPxePingResponse.class) public class ListBaremetalPxePingServersCmd extends BaseListCmd { private static final Logger s_logger = Logger.getLogger(ListBaremetalPxePingServersCmd.class); private static final String s_name = "listpingpxeserverresponse"; diff --git a/plugins/hypervisors/kvm/pom.xml b/plugins/hypervisors/kvm/pom.xml index 8fc8f739460..579244014f9 100644 --- a/plugins/hypervisors/kvm/pom.xml +++ b/plugins/hypervisors/kvm/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 552afb1e665..99b8723c26e 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -698,10 +698,7 @@ ServerResource { _sysvmISOPath = (String) params.get("systemvm.iso.path"); if (_sysvmISOPath == null) { - String[] isoPaths = { "/usr/lib64/cloud/agent/vms/systemvm.iso", - "/usr/lib/cloud/agent/vms/systemvm.iso", - "/usr/lib64/cloud/common/vms/systemvm.iso", - "/usr/lib/cloud/common/vms/systemvm.iso" }; + String[] isoPaths = {"/usr/share/cloudstack-common/vms/systemvm.iso"}; for (String isoPath : isoPaths) { if (_storage.exists(isoPath)) { _sysvmISOPath = isoPath; @@ -858,7 +855,7 @@ ServerResource { private String getPif(String bridge) { String pif = matchPifFileInDirectory(bridge); - File vlanfile = new File("/proc/net/vlan" + pif); + File vlanfile = new File("/proc/net/vlan/" + pif); if (vlanfile.isFile()) { pif = Script.runSimpleBashScript("grep ^Device\\: /proc/net/vlan/" @@ -2924,12 +2921,20 @@ ServerResource { vm.addComp(guest); GuestResourceDef grd = new GuestResourceDef(); - grd.setMemorySize(vmTO.getMinRam() / 1024); + + if (vmTO.getMinRam() != vmTO.getMaxRam()){ + grd.setMemBalloning(true); + grd.setCurrentMem((int)vmTO.getMinRam()/1024); + grd.setMemorySize((int)vmTO.getMaxRam()/1024); + } + else{ + grd.setMemorySize(vmTO.getMaxRam() / 1024); + } grd.setVcpuNum(vmTO.getCpus()); vm.addComp(grd); CpuTuneDef ctd = new CpuTuneDef(); - ctd.setShares(vmTO.getCpus() * vmTO.getSpeed()); + ctd.setShares(vmTO.getCpus() * vmTO.getMinSpeed()); vm.addComp(ctd); FeaturesDef features = new FeaturesDef(); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index acfd9cf1fe8..5ab37702ed6 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -116,6 +116,7 @@ public class LibvirtVMDef { private int _currentMem = -1; private String _memBacking; private int _vcpu = -1; + private boolean _memBalloning= false; public void setMemorySize(long mem) { _mem = mem; @@ -133,6 +134,10 @@ public class LibvirtVMDef { _vcpu = vcpu; } + public void setMemBalloning(boolean turnon){ + _memBalloning = turnon; + } + @Override public String toString() { StringBuilder resBuidler = new StringBuilder(); @@ -145,6 +150,9 @@ public class LibvirtVMDef { resBuidler.append("" + "<" + _memBacking + "/>" + "\n"); } + if (_memBalloning){ + resBuidler.append("\n" + "\n" + "\n"); + } if (_vcpu != -1) { resBuidler.append("" + _vcpu + "\n"); } diff --git a/plugins/hypervisors/ovm/pom.xml b/plugins/hypervisors/ovm/pom.xml index 5700c14d4eb..84beff0d4eb 100644 --- a/plugins/hypervisors/ovm/pom.xml +++ b/plugins/hypervisors/ovm/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/simulator/pom.xml b/plugins/hypervisors/simulator/pom.xml index a1ab9c08639..ff1664ad85f 100644 --- a/plugins/hypervisors/simulator/pom.xml +++ b/plugins/hypervisors/simulator/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml org.apache.cloudstack diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java index 2178651403e..8542de3bd9f 100755 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockAgentManagerImpl.java @@ -62,7 +62,9 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; +import org.springframework.stereotype.Component; +@Component @Local(value = { MockAgentManager.class }) public class MockAgentManagerImpl extends ManagerBase implements MockAgentManager { private static final Logger s_logger = Logger.getLogger(MockAgentManagerImpl.class); diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java index f445bb32900..859acc85958 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java @@ -97,7 +97,9 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine.State; +import org.springframework.stereotype.Component; +@Component @Local(value = { MockStorageManager.class }) public class MockStorageManagerImpl extends ManagerBase implements MockStorageManager { private static final Logger s_logger = Logger.getLogger(MockStorageManagerImpl.class); diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java index 60e1a61a0bd..c0ccbe43978 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java @@ -17,58 +17,12 @@ package com.cloud.agent.manager; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.BumpUpPriorityCommand; -import com.cloud.agent.api.CheckRouterAnswer; -import com.cloud.agent.api.CheckRouterCommand; -import com.cloud.agent.api.CheckVirtualMachineAnswer; -import com.cloud.agent.api.CheckVirtualMachineCommand; -import com.cloud.agent.api.CleanupNetworkRulesCmd; -import com.cloud.agent.api.GetDomRVersionAnswer; -import com.cloud.agent.api.GetDomRVersionCmd; -import com.cloud.agent.api.GetVmStatsAnswer; -import com.cloud.agent.api.GetVmStatsCommand; -import com.cloud.agent.api.GetVncPortAnswer; -import com.cloud.agent.api.GetVncPortCommand; -import com.cloud.agent.api.MigrateAnswer; -import com.cloud.agent.api.MigrateCommand; -import com.cloud.agent.api.NetworkUsageAnswer; -import com.cloud.agent.api.NetworkUsageCommand; -import com.cloud.agent.api.PrepareForMigrationAnswer; -import com.cloud.agent.api.PrepareForMigrationCommand; -import com.cloud.agent.api.RebootAnswer; -import com.cloud.agent.api.RebootCommand; -import com.cloud.agent.api.SecurityGroupRuleAnswer; -import com.cloud.agent.api.SecurityGroupRulesCmd; -import com.cloud.agent.api.StartAnswer; -import com.cloud.agent.api.StartCommand; -import com.cloud.agent.api.StopAnswer; -import com.cloud.agent.api.StopCommand; -import com.cloud.agent.api.VmStatsEntry; +import com.cloud.agent.api.*; import com.cloud.agent.api.check.CheckSshAnswer; import com.cloud.agent.api.check.CheckSshCommand; import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand; -import com.cloud.agent.api.routing.DhcpEntryCommand; -import com.cloud.agent.api.routing.IpAssocCommand; -import com.cloud.agent.api.routing.LoadBalancerConfigCommand; -import com.cloud.agent.api.routing.NetworkElementCommand; -import com.cloud.agent.api.routing.SavePasswordCommand; -import com.cloud.agent.api.routing.SetFirewallRulesCommand; -import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; -import com.cloud.agent.api.routing.SetStaticNatRulesCommand; -import com.cloud.agent.api.routing.VmDataCommand; +import com.cloud.agent.api.routing.*; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.network.Networks.TrafficType; @@ -86,7 +40,18 @@ import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine.State; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Component @Local(value = { MockVmManager.class }) public class MockVmManagerImpl extends ManagerBase implements MockVmManager { private static final Logger s_logger = Logger.getLogger(MockVmManagerImpl.class); @@ -383,7 +348,7 @@ public class MockVmManagerImpl extends ManagerBase implements MockVmManager { @Override public Answer startVM(StartCommand cmd, SimulatorInfo info) { VirtualMachineTO vm = cmd.getVirtualMachine(); - String result = startVM(vm.getName(), vm.getNics(), vm.getCpus()* vm.getSpeed(), vm.getMaxRam(), vm.getBootArgs(), info.getHostUuid()); + String result = startVM(vm.getName(), vm.getNics(), vm.getCpus()* vm.getMaxSpeed(), vm.getMaxRam(), vm.getBootArgs(), info.getHostUuid()); if (result != null) { return new StartAnswer(cmd, result); } else { diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java index 41443572efd..c234cc5cb2e 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java @@ -16,73 +16,12 @@ // under the License. package com.cloud.agent.manager; -import java.util.HashMap; -import java.util.Map; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.AttachIsoCommand; -import com.cloud.agent.api.AttachVolumeCommand; -import com.cloud.agent.api.BackupSnapshotCommand; -import com.cloud.agent.api.BumpUpPriorityCommand; -import com.cloud.agent.api.CheckHealthCommand; -import com.cloud.agent.api.CheckNetworkCommand; -import com.cloud.agent.api.CheckRouterCommand; -import com.cloud.agent.api.CheckVirtualMachineCommand; -import com.cloud.agent.api.CleanupNetworkRulesCmd; -import com.cloud.agent.api.ClusterSyncCommand; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.ComputeChecksumCommand; -import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; -import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; -import com.cloud.agent.api.CreateStoragePoolCommand; -import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; -import com.cloud.agent.api.DeleteSnapshotBackupCommand; -import com.cloud.agent.api.DeleteStoragePoolCommand; -import com.cloud.agent.api.GetDomRVersionCmd; -import com.cloud.agent.api.GetHostStatsCommand; -import com.cloud.agent.api.GetStorageStatsCommand; -import com.cloud.agent.api.GetVmStatsCommand; -import com.cloud.agent.api.GetVncPortCommand; -import com.cloud.agent.api.MaintainCommand; -import com.cloud.agent.api.ManageSnapshotCommand; -import com.cloud.agent.api.MigrateCommand; -import com.cloud.agent.api.ModifyStoragePoolCommand; -import com.cloud.agent.api.NetworkUsageCommand; -import com.cloud.agent.api.PingTestCommand; -import com.cloud.agent.api.PrepareForMigrationCommand; -import com.cloud.agent.api.RebootCommand; -import com.cloud.agent.api.SecStorageSetupCommand; -import com.cloud.agent.api.SecStorageVMSetupCommand; -import com.cloud.agent.api.SecurityGroupRulesCmd; -import com.cloud.agent.api.StartCommand; -import com.cloud.agent.api.StopCommand; -import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.agent.api.*; import com.cloud.agent.api.check.CheckSshCommand; import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand; -import com.cloud.agent.api.routing.DhcpEntryCommand; -import com.cloud.agent.api.routing.IpAssocCommand; -import com.cloud.agent.api.routing.LoadBalancerConfigCommand; -import com.cloud.agent.api.routing.SavePasswordCommand; -import com.cloud.agent.api.routing.SetFirewallRulesCommand; -import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; -import com.cloud.agent.api.routing.SetStaticNatRulesCommand; -import com.cloud.agent.api.routing.VmDataCommand; -import com.cloud.agent.api.storage.CopyVolumeCommand; -import com.cloud.agent.api.storage.CreateCommand; -import com.cloud.agent.api.storage.DeleteTemplateCommand; -import com.cloud.agent.api.storage.DestroyCommand; -import com.cloud.agent.api.storage.DownloadCommand; -import com.cloud.agent.api.storage.DownloadProgressCommand; -import com.cloud.agent.api.storage.ListTemplateCommand; -import com.cloud.agent.api.storage.ListVolumeCommand; -import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; +import com.cloud.agent.api.routing.*; +import com.cloud.agent.api.storage.*; import com.cloud.simulator.MockConfigurationVO; import com.cloud.simulator.MockHost; import com.cloud.simulator.MockVMVO; @@ -95,7 +34,16 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine.State; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.Map; + +@Component @Local(value = { SimulatorManager.class }) public class SimulatorManagerImpl extends ManagerBase implements SimulatorManager { private static final Logger s_logger = Logger.getLogger(SimulatorManagerImpl.class); diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java index 721e5f70222..46df50c2133 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentRoutingResource.java @@ -184,7 +184,7 @@ public class AgentRoutingResource extends AgentStorageResource { throws IllegalArgumentException { VirtualMachineTO vmSpec = cmd.getVirtualMachine(); String vmName = vmSpec.getName(); - if (this.totalCpu < (vmSpec.getCpus() * vmSpec.getSpeed() + this.usedCpu) || + if (this.totalCpu < (vmSpec.getCpus() * vmSpec.getMaxSpeed() + this.usedCpu) || this.totalMem < (vmSpec.getMaxRam() + this.usedMem)) { return new StartAnswer(cmd, "Not enough resource to start the vm"); } @@ -199,9 +199,9 @@ public class AgentRoutingResource extends AgentStorageResource { return new StartAnswer(cmd, result.getDetails()); } - this.usedCpu += vmSpec.getCpus() * vmSpec.getSpeed(); + this.usedCpu += vmSpec.getCpus() * vmSpec.getMaxSpeed(); this.usedMem += vmSpec.getMaxRam(); - _runningVms.put(vmName, new Pair(Long.valueOf(vmSpec.getCpus() * vmSpec.getSpeed()), vmSpec.getMaxRam())); + _runningVms.put(vmName, new Pair(Long.valueOf(vmSpec.getCpus() * vmSpec.getMaxSpeed()), vmSpec.getMaxRam())); state = State.Running; } finally { diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java index 5cb094184ba..00fe356103b 100755 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java @@ -53,7 +53,7 @@ import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VMTemplateZoneDao; - +import org.springframework.stereotype.Component; @Local(value = Discoverer.class) public class SimulatorDiscoverer extends DiscovererBase implements Discoverer, Listener, ResourceStateAdapter { diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java index cd0cd2725c9..1dd71c5c27f 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java @@ -42,7 +42,9 @@ import com.cloud.storage.SnapshotVO; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.secondary.SecondaryStorageDiscoverer; import com.cloud.utils.exception.CloudRuntimeException; +import org.springframework.stereotype.Component; +@Component @Local(value=Discoverer.class) public class SimulatorSecondaryDiscoverer extends SecondaryStorageDiscoverer implements ResourceStateAdapter, Listener { private static final Logger s_logger = Logger.getLogger(SimulatorSecondaryDiscoverer.class); diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/SimulatorGuru.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/SimulatorGuru.java index c9d308023ed..57a38f1d3d8 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/SimulatorGuru.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/SimulatorGuru.java @@ -16,9 +16,6 @@ // under the License. package com.cloud.simulator; -import javax.ejb.Local; -import javax.inject.Inject; - import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuru; @@ -28,6 +25,10 @@ import com.cloud.storage.dao.GuestOSDao; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; +import javax.ejb.Local; +import javax.inject.Inject; + + @Local(value=HypervisorGuru.class) public class SimulatorGuru extends HypervisorGuruBase implements HypervisorGuru { @Inject GuestOSDao _guestOsDao; diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockConfigurationDaoImpl.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockConfigurationDaoImpl.java index bd1b48dfde8..fd825b751ed 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockConfigurationDaoImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockConfigurationDaoImpl.java @@ -16,18 +16,19 @@ // under the License. package com.cloud.simulator.dao; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.util.Formatter; - -import javax.ejb.Local; - import com.cloud.simulator.MockConfigurationVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import org.springframework.stereotype.Component; +import javax.ejb.Local; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.Formatter; + +@Component @Local(value={MockConfigurationDao.class}) public class MockConfigurationDaoImpl extends GenericDaoBase implements MockConfigurationDao { private SearchBuilder _searchByDcIdName; diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockHostDaoImpl.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockHostDaoImpl.java index 8a566d79ed2..4b60bc02d47 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockHostDaoImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockHostDaoImpl.java @@ -16,14 +16,16 @@ // under the License. package com.cloud.simulator.dao; -import javax.ejb.Local; - import com.cloud.simulator.MockHost; import com.cloud.simulator.MockHostVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; +import javax.ejb.Local; + +@Component @Local(value={MockHostDao.class}) public class MockHostDaoImpl extends GenericDaoBase implements MockHostDao { protected final SearchBuilder GuidSearch; diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockSecStorageDaoImpl.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockSecStorageDaoImpl.java index 65a375f5843..d4903244179 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockSecStorageDaoImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockSecStorageDaoImpl.java @@ -16,13 +16,15 @@ // under the License. package com.cloud.simulator.dao; -import javax.ejb.Local; - import com.cloud.simulator.MockSecStorageVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; +import javax.ejb.Local; + +@Component @Local(value={MockSecStorageDao.class}) public class MockSecStorageDaoImpl extends GenericDaoBase implements MockSecStorageDao { protected final SearchBuilder urlSearch; diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockSecurityRulesDaoImpl.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockSecurityRulesDaoImpl.java index 8831efef2ec..d35607e0ebc 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockSecurityRulesDaoImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockSecurityRulesDaoImpl.java @@ -16,16 +16,18 @@ // under the License. package com.cloud.simulator.dao; -import java.util.List; -import java.util.Map; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; - import com.cloud.simulator.MockSecurityRulesVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import java.util.List; +import java.util.Map; + +@Component @Local(value={MockSecurityRulesDao.class}) public class MockSecurityRulesDaoImpl extends GenericDaoBase implements MockSecurityRulesDao { protected SearchBuilder vmIdSearch; diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockStoragePoolDaoImpl.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockStoragePoolDaoImpl.java index 3a64d27e30d..0fc41abdc4c 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockStoragePoolDaoImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockStoragePoolDaoImpl.java @@ -16,14 +16,16 @@ // under the License. package com.cloud.simulator.dao; -import javax.ejb.Local; - import com.cloud.simulator.MockStoragePoolVO; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; +import javax.ejb.Local; + +@Component @Local(value={MockStoragePoolDao.class}) public class MockStoragePoolDaoImpl extends GenericDaoBase implements MockStoragePoolDao { protected final SearchBuilder uuidSearch; diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockVMDaoImpl.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockVMDaoImpl.java index be7a98859e2..5a8c66d69ef 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockVMDaoImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockVMDaoImpl.java @@ -16,14 +16,6 @@ // under the License. package com.cloud.simulator.dao; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - import com.cloud.simulator.MockHostVO; import com.cloud.simulator.MockVMVO; import com.cloud.utils.db.GenericDaoBase; @@ -31,7 +23,16 @@ import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.vm.VirtualMachine; +import org.springframework.stereotype.Component; +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component @Local(value={MockVMDao.class}) public class MockVMDaoImpl extends GenericDaoBase implements MockVMDao { protected SearchBuilder GuidSearch; diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockVolumeDaoImpl.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockVolumeDaoImpl.java index a3a35179337..5d64a9fa246 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockVolumeDaoImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/dao/MockVolumeDaoImpl.java @@ -16,10 +16,6 @@ // under the License. package com.cloud.simulator.dao; -import java.util.List; - -import javax.ejb.Local; - import com.cloud.simulator.MockVolumeVO; import com.cloud.simulator.MockVolumeVO.MockVolumeType; import com.cloud.utils.db.GenericDaoBase; @@ -27,7 +23,12 @@ import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; +import org.springframework.stereotype.Component; +import javax.ejb.Local; +import java.util.List; + +@Component @Local(value={MockVolumeDao.class}) public class MockVolumeDaoImpl extends GenericDaoBase implements MockVolumeDao { protected final SearchBuilder idTypeSearch; diff --git a/plugins/hypervisors/ucs/pom.xml b/plugins/hypervisors/ucs/pom.xml index 54cd68fd6b7..24bdc948e73 100755 --- a/plugins/hypervisors/ucs/pom.xml +++ b/plugins/hypervisors/ucs/pom.xml @@ -24,12 +24,12 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml org.apache.cloudstack cloud-plugin-hypervisor-ucs - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT Apache CloudStack Plugin - Hypervisor UCS http://maven.apache.org diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java index 8f65f6a21ae..570d1a39d1c 100644 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java @@ -17,11 +17,14 @@ package com.cloud.ucs.database; import javax.ejb.Local; + +import org.springframework.stereotype.Component; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; @Local(value = { UcsBladeDao.class }) -@DB(txn = false) +@DB(txn = false) +@Component public class UcsBladeDaoImpl extends GenericDaoBase implements UcsBladeDao { } diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java index bccc0faefa7..8a4c73e8e3e 100644 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java @@ -17,12 +17,15 @@ package com.cloud.ucs.database; import javax.ejb.Local; + +import org.springframework.stereotype.Component; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; @Local(value = { UcsManagerDao.class }) -@DB(txn = false) +@DB(txn = false) +@Component public class UcsManagerDaoImpl extends GenericDaoBase implements UcsManagerDao { } diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml index ad27ab7300a..468e0a50599 100644 --- a/plugins/hypervisors/vmware/pom.xml +++ b/plugins/hypervisors/vmware/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index 819d3999f92..bb7c29745d9 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -1,3 +1,4 @@ + // 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 @@ -129,6 +130,17 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { } } } + + String diskDeviceType = details.get(VmDetailConstants.ROOK_DISK_CONTROLLER); + if (!(vm.getVirtualMachine() instanceof DomainRouterVO || vm.getVirtualMachine() instanceof ConsoleProxyVO + || vm.getVirtualMachine() instanceof SecondaryStorageVmVO)){ + // user vm + if (diskDeviceType != null){ + details.remove(VmDetailConstants.ROOK_DISK_CONTROLLER); + } + details.put(VmDetailConstants.ROOK_DISK_CONTROLLER, _vmwareMgr.getRootDiskController()); + } + to.setDetails(details); if(vm.getVirtualMachine() instanceof DomainRouterVO) { diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java index e3a856077ce..00b6111e287 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java @@ -45,6 +45,7 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.hypervisor.vmware.manager.VmwareManager; import com.cloud.hypervisor.vmware.mo.ClusterMO; import com.cloud.hypervisor.vmware.mo.HostMO; @@ -59,9 +60,9 @@ import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.user.Account; import com.cloud.utils.UriUtils; @@ -96,77 +97,68 @@ public class VmwareServerDiscoverer extends DiscovererBase implements CiscoNexusVSMDeviceDao _nexusDao; @Inject NetworkModel _netmgr; + @Inject + HypervisorCapabilitiesDao _hvCapabilitiesDao; public VmwareServerDiscoverer() { s_logger.info("VmwareServerDiscoverer is constructed"); } @Override - public Map> find(long dcId, - Long podId, Long clusterId, URI url, String username, - String password, List hostTags) throws DiscoveryException { + public Map> find(long dcId, Long podId, Long clusterId, URI url, + String username, String password, List hostTags) throws DiscoveryException { - if (s_logger.isInfoEnabled()) - s_logger.info("Discover host. dc: " + dcId + ", pod: " + podId - + ", cluster: " + clusterId + ", uri host: " - + url.getHost()); + if(s_logger.isInfoEnabled()) + s_logger.info("Discover host. dc: " + dcId + ", pod: " + podId + ", cluster: " + clusterId + ", uri host: " + url.getHost()); - if (podId == null) { - if (s_logger.isInfoEnabled()) + if(podId == null) { + if(s_logger.isInfoEnabled()) s_logger.info("No pod is assigned, assuming that it is not for vmware and skip it to next discoverer"); return null; } ClusterVO cluster = _clusterDao.findById(clusterId); - if (cluster == null - || cluster.getHypervisorType() != HypervisorType.VMware) { - if (s_logger.isInfoEnabled()) + if(cluster == null || cluster.getHypervisorType() != HypervisorType.VMware) { + if(s_logger.isInfoEnabled()) s_logger.info("invalid cluster id or cluster is not for VMware hypervisors"); return null; } List hosts = _resourceMgr.listAllHostsInCluster(clusterId); - if (hosts.size() >= _vmwareMgr.getMaxHostsPerCluster()) { - String msg = "VMware cluster " - + cluster.getName() - + " is too big to add new host now. (current configured cluster size: " - + _vmwareMgr.getMaxHostsPerCluster() + ")"; + if (hosts != null && hosts.size() > 0) { + int maxHostsPerCluster = _hvCapabilitiesDao.getMaxHostsPerCluster(hosts.get(0).getHypervisorType(), hosts.get(0).getHypervisorVersion()); + if (hosts.size() > maxHostsPerCluster) { + String msg = "VMware cluster " + cluster.getName() + " is too big to add new host now. (current configured cluster size: " + maxHostsPerCluster + ")"; s_logger.error(msg); throw new DiscoveredWithErrorException(msg); } + } String privateTrafficLabel = null; String publicTrafficLabel = null; String guestTrafficLabel = null; Map vsmCredentials = null; - privateTrafficLabel = _netmgr.getDefaultManagementTrafficLabel(dcId, - HypervisorType.VMware); + privateTrafficLabel = _netmgr.getDefaultManagementTrafficLabel(dcId, HypervisorType.VMware); if (privateTrafficLabel != null) { - s_logger.info("Detected private network label : " - + privateTrafficLabel); + s_logger.info("Detected private network label : " + privateTrafficLabel); } if (_vmwareMgr.getNexusVSwitchGlobalParameter()) { DataCenterVO zone = _dcDao.findById(dcId); NetworkType zoneType = zone.getNetworkType(); if (zoneType != NetworkType.Basic) { - publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, - HypervisorType.VMware); + publicTrafficLabel = _netmgr.getDefaultPublicTrafficLabel(dcId, HypervisorType.VMware); if (publicTrafficLabel != null) { - s_logger.info("Detected public network label : " - + publicTrafficLabel); + s_logger.info("Detected public network label : " + publicTrafficLabel); } } // Get physical network label - guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, - HypervisorType.VMware); + guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware); if (guestTrafficLabel != null) { - s_logger.info("Detected guest network label : " - + guestTrafficLabel); + s_logger.info("Detected guest network label : " + guestTrafficLabel); } - vsmCredentials = _vmwareMgr - .getNexusVSMCredentialsByClusterId(clusterId); + vsmCredentials = _vmwareMgr.getNexusVSMCredentialsByClusterId(clusterId); } VmwareContext context = null; diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java index e1ca6ccac03..445b2f0debc 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java @@ -29,10 +29,6 @@ import com.vmware.vim25.ManagedObjectReference; public interface VmwareManager { public final String CONTEXT_STOCK_NAME = "vmwareMgr"; - // this limitation comes from the fact that we are using linked clone on shared VMFS storage, - // we need to limit the size of vCenter cluster, http://en.wikipedia.org/wiki/VMware_VMFS - public final int MAX_HOSTS_PER_CLUSTER = 8; - String composeWorkerName(); String getSystemVMIsoFileNameOnDatastore(); @@ -57,7 +53,6 @@ public interface VmwareManager { Pair getAddiionalVncPortRange(); - int getMaxHostsPerCluster(); int getRouterExtraPublicNics(); boolean beginExclusiveOperation(int timeOutSeconds); @@ -72,4 +67,6 @@ public interface VmwareManager { String getPublicVSwitchName(long dcId, HypervisorType hypervisorType); String getGuestVSwitchName(long dcId, HypervisorType hypervisorType); + + public String getRootDiskController(); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 64dbea18495..0ecfff8a962 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -58,6 +58,7 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.hypervisor.vmware.VmwareCleanupMaid; import com.cloud.hypervisor.vmware.mo.DiskControllerType; import com.cloud.hypervisor.vmware.mo.HostFirewallSystemMO; @@ -92,6 +93,7 @@ import com.cloud.utils.script.Script; import com.cloud.utils.ssh.SshHelper; import com.cloud.vm.DomainRouterVO; import com.google.gson.Gson; +import com.vmware.vim25.AboutInfo; import com.vmware.vim25.HostConnectSpec; import com.vmware.vim25.ManagedObjectReference; @@ -120,6 +122,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw @Inject ClusterVSMMapDao _vsmMapDao; @Inject ConfigurationDao _configDao; @Inject ConfigurationServer _configServer; + @Inject HypervisorCapabilitiesDao _hvCapabilitiesDao; String _mountParent; StorageLayer _storage; @@ -134,13 +137,10 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw String _recycleHungWorker = "false"; int _additionalPortRangeStart; int _additionalPortRangeSize; - int _maxHostsPerCluster; int _routerExtraPublicNics = 2; - String _cpuOverprovisioningFactor = "1"; String _reserveCpu = "false"; - String _memOverprovisioningFactor = "1"; String _reserveMem = "false"; String _rootDiskController = DiskControllerType.ide.toString(); @@ -262,15 +262,6 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw _routerExtraPublicNics = NumbersUtil.parseInt(_configDao.getValue(Config.RouterExtraPublicNics.key()), 2); - _maxHostsPerCluster = NumbersUtil.parseInt(_configDao.getValue(Config.VmwarePerClusterHostMax.key()), VmwareManager.MAX_HOSTS_PER_CLUSTER); - _cpuOverprovisioningFactor = _configDao.getValue(Config.CPUOverprovisioningFactor.key()); - if(_cpuOverprovisioningFactor == null || _cpuOverprovisioningFactor.isEmpty()) - _cpuOverprovisioningFactor = "1"; - - _memOverprovisioningFactor = _configDao.getValue(Config.MemOverprovisioningFactor.key()); - if(_memOverprovisioningFactor == null || _memOverprovisioningFactor.isEmpty()) - _memOverprovisioningFactor = "1"; - _reserveCpu = _configDao.getValue(Config.VmwareReserveCpu.key()); if(_reserveCpu == null || _reserveCpu.isEmpty()) _reserveCpu = "false"; @@ -403,11 +394,16 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw List hosts = (List)serviceContext.getVimClient().getDynamicProperty(mor, "host"); assert(hosts != null); - if(hosts.size() > _maxHostsPerCluster) { - String msg = "vCenter cluster size is too big (current configured cluster size: " + _maxHostsPerCluster + ")"; + if (hosts.size() > 0) { + AboutInfo about = (AboutInfo)(serviceContext.getVimClient().getDynamicProperty(hosts.get(0), "config.product")); + String version = about.getApiVersion(); + int maxHostsPerCluster = _hvCapabilitiesDao.getMaxHostsPerCluster(HypervisorType.VMware, version); + if (hosts.size() > maxHostsPerCluster) { + String msg = "vCenter cluster size is too big (current configured cluster size: " + maxHostsPerCluster + ")"; s_logger.error(msg); throw new DiscoveredWithErrorException(msg); } + } for(ManagedObjectReference morHost: hosts) { // For ESX host, we need to enable host firewall to allow VNC access @@ -505,9 +501,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw params.put("vmware.use.nexus.vswitch", _nexusVSwitchActive); params.put("service.console.name", _serviceConsoleName); params.put("management.portgroup.name", _managemetPortGroupName); - params.put("cpu.overprovisioning.factor", _cpuOverprovisioningFactor); params.put("vmware.reserve.cpu", _reserveCpu); - params.put("mem.overprovisioning.factor", _memOverprovisioningFactor); params.put("vmware.reserve.mem", _reserveMem); params.put("vmware.root.disk.controller", _rootDiskController); params.put("vmware.recycle.hung.wokervm", _recycleHungWorker); @@ -881,11 +875,6 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw return new Pair(_additionalPortRangeStart, _additionalPortRangeSize); } - @Override - public int getMaxHostsPerCluster() { - return this._maxHostsPerCluster; - } - @Override public int getRouterExtraPublicNics() { return this._routerExtraPublicNics; @@ -918,4 +907,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw } return nexusVSMCredentials; } + + @Override + public String getRootDiskController() { + return _rootDiskController; + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java index f27e0269a64..a2e517d1fdb 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java @@ -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); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index fd3afe8e5c9..8be76e8fff2 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -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) { @@ -392,8 +410,8 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { VmwareContext context = hostService.getServiceContext(cmd); try { VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd); - - ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStorageNameLabel); + ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, + primaryStorageNameLabel); if (morPrimaryDs == null) { String msg = "Unable to find datastore: " + primaryStorageNameLabel; s_logger.error(msg); @@ -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 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 mapNewDisk = new HashMap(); + 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.getVimClient().getDynamicProperty(taskmgr, "recentTask"); + for (ManagedObjectReference taskMor : tasks) { + TaskInfo info = (TaskInfo) (context.getVimClient().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.getVimClient().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> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i], false); + for(Pair 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 listVolumeTo = cmd.getVolumeTOs(); + VirtualMachineMO vmMo = null; + VmwareContext context = hostService.getServiceContext(cmd); + Map mapNewDisk = new HashMap(); + 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> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i], false); + for (Pair 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 listVolumeTo = cmd.getVolumeTOs(); + VirtualMachine.State vmState = VirtualMachine.State.Running; + VirtualMachineMO vmMo = null; + VmwareContext context = hostService.getServiceContext(cmd); + Map mapNewDisk = new HashMap(); + 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.getVimClient().getDynamicProperty(taskmgr, "recentTask"); + for (ManagedObjectReference taskMor : tasks) { + TaskInfo info = (TaskInfo) (context.getVimClient().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.getVimClient().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 + for (int i = 0; i < vdisks.length; i++) { + @SuppressWarnings("deprecation") + List> vmdkFiles = vmMo.getDiskDatastorePathChain( + vdisks[i], false); + for (Pair 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.OTHER_GUEST.toString()); + VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo(); + fileInfo.setVmPathName(String.format("[%s]", dsMo.getName())); + vmConfig.setFiles(fileInfo); + + VirtualLsiLogicController scsiController = new VirtualLsiLogicController(); + scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING); + scsiController.setBusNumber(0); + scsiController.setKey(1); + VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec(); + scsiControllerSpec.setDevice(scsiController); + scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); + + vmConfig.getDeviceChange().add(scsiControllerSpec); + hyperHost.createVm(vmConfig); + workingVM = hyperHost.findVmOnHyperHost(uniqueName); + return workingVM; + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 21f17328c53..c5b812bbbdf 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -66,9 +66,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; @@ -104,6 +108,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; @@ -287,10 +293,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected VirtualSwitchType _vSwitchType = VirtualSwitchType.StandardVirtualSwitch; protected boolean _nexusVSwitch = false; - protected float _cpuOverprovisioningFactor = 1; protected boolean _reserveCpu = false; - protected float _memOverprovisioningFactor = 1; protected boolean _reserveMem = false; protected boolean _recycleHungWorker = false; protected DiskControllerType _rootDiskController = DiskControllerType.ide; @@ -450,7 +454,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); @@ -2090,11 +2100,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } - assert (vmSpec.getSpeed() != null) && (rootDiskDataStoreDetails != null); - - if (!hyperHost.createBlankVm(vmName, vmSpec.getCpus(), vmSpec.getSpeed().intValue(), - getReserveCpuMHz(vmSpec.getSpeed().intValue()), vmSpec.getLimitCpuUse(), ramMb, getReserveMemMB(ramMb), - translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).value(), rootDiskDataStoreDetails.first(), false)) { + assert (vmSpec.getMinSpeed() != null) && (rootDiskDataStoreDetails != null); + if (!hyperHost.createBlankVm(vmName, vmSpec.getCpus(), vmSpec.getMaxSpeed().intValue(), + vmSpec.getMinSpeed(), vmSpec.getLimitCpuUse(),(int)(vmSpec.getMaxRam()/(1024*1024)), ramMb, + translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).toString(), rootDiskDataStoreDetails.first(), false)) { throw new Exception("Failed to create VM. vmName: " + vmName); } } @@ -2124,9 +2133,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); int ramMb = (int) (vmSpec.getMinRam() / (1024 * 1024)); - VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getSpeed().intValue(), - getReserveCpuMHz(vmSpec.getSpeed().intValue()), ramMb, getReserveMemMB(ramMb), - translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).value(), vmSpec.getLimitCpuUse()); + VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), + vmSpec.getMinSpeed(),(int) (vmSpec.getMaxRam()/(1024*1024)), ramMb, + translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).toString(), vmSpec.getLimitCpuUse()); VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[totalChangeDevices]; int i = 0; @@ -2379,21 +2388,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return validatedDetails; } - private int getReserveCpuMHz(int cpuMHz) { - if(this._reserveCpu) { - return (int)(cpuMHz / this._cpuOverprovisioningFactor); - } - return 0; - } - - private int getReserveMemMB(int memMB) { - if(this._reserveMem) { - return (int)(memMB / this._memOverprovisioningFactor); - } - - return 0; - } private NicTO[] sortNicsByDeviceId(NicTO[] nics) { @@ -2815,7 +2810,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); @@ -3367,7 +3361,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)); @@ -4855,11 +4884,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa _guestNetworkVSwitchName = (String) params.get("guest.network.vswitch.name"); } - String value = (String) params.get("cpu.overprovisioning.factor"); - if(value != null) - _cpuOverprovisioningFactor = Float.parseFloat(value); - - value = (String) params.get("vmware.reserve.cpu"); + String value = (String) params.get("vmware.reserve.cpu"); if(value != null && value.equalsIgnoreCase("true")) _reserveCpu = true; @@ -4867,10 +4892,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if(value != null && value.equalsIgnoreCase("true")) _recycleHungWorker = true; - value = (String) params.get("mem.overprovisioning.factor"); - if(value != null) - _memOverprovisioningFactor = Float.parseFloat(value); - value = (String) params.get("vmware.reserve.mem"); if(value != null && value.equalsIgnoreCase("true")) _reserveMem = true; diff --git a/plugins/hypervisors/xen/pom.xml b/plugins/hypervisors/xen/pom.xml index 0a57afca284..72d32f3029c 100644 --- a/plugins/hypervisors/xen/pom.xml +++ b/plugins/hypervisors/xen/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java index 65a97a8de31..c2f4923e7e6 100755 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java @@ -79,9 +79,9 @@ import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.user.Account; @@ -315,6 +315,7 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L params.put("wait", Integer.toString(_wait)); details.put("wait", Integer.toString(_wait)); params.put("migratewait", _configDao.getValue(Config.MigrateWait.toString())); + params.put(Config.XenMaxNics.toString().toLowerCase(), _configDao.getValue(Config.XenMaxNics.toString())); params.put(Config.InstanceName.toString().toLowerCase(), _instance); details.put(Config.InstanceName.toString().toLowerCase(), _instance); try { diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index c7ff5c7b4bf..4a89806a49f 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -90,9 +90,13 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; import com.cloud.agent.api.CreateStoragePoolCommand; +import com.cloud.agent.api.CreateVMSnapshotAnswer; +import com.cloud.agent.api.CreateVMSnapshotCommand; import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer; import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; import com.cloud.agent.api.DeleteStoragePoolCommand; +import com.cloud.agent.api.DeleteVMSnapshotAnswer; +import com.cloud.agent.api.DeleteVMSnapshotCommand; import com.cloud.agent.api.GetDomRVersionAnswer; import com.cloud.agent.api.GetDomRVersionCmd; import com.cloud.agent.api.GetHostStatsAnswer; @@ -129,6 +133,8 @@ import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.RebootAnswer; import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.RebootRouterCommand; +import com.cloud.agent.api.RevertToVMSnapshotAnswer; +import com.cloud.agent.api.RevertToVMSnapshotCommand; import com.cloud.agent.api.SecurityGroupRuleAnswer; import com.cloud.agent.api.SecurityGroupRulesCmd; import com.cloud.agent.api.SetupAnswer; @@ -237,6 +243,7 @@ import com.cloud.utils.net.NetUtils; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.snapshot.VMSnapshot; import com.trilead.ssh2.SCPClient; import com.xensource.xenapi.Bond; import com.xensource.xenapi.Connection; @@ -256,6 +263,10 @@ import com.xensource.xenapi.Types; import com.xensource.xenapi.Types.BadServerResponse; import com.xensource.xenapi.Types.ConsoleProtocol; import com.xensource.xenapi.Types.IpConfigurationMode; +import com.xensource.xenapi.Types.OperationNotAllowed; +import com.xensource.xenapi.Types.SrFull; +import com.xensource.xenapi.Types.VbdType; +import com.xensource.xenapi.Types.VmBadPowerState; import com.xensource.xenapi.Types.VmPowerState; import com.xensource.xenapi.Types.XenAPIException; import com.xensource.xenapi.VBD; @@ -320,6 +331,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe protected boolean _isOvs = false; protected List _tmpDom0Vif = new ArrayList(); protected XenServerStorageResource storageResource; + protected int _maxNics = 7; public enum SRType { NFS, LVM, ISCSI, ISO, LVMOISCSI, LVMOHBA, EXT, FILE; @@ -579,11 +591,109 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return execute((CheckS2SVpnConnectionsCommand) cmd); } else if (cmd instanceof StorageSubSystemCommand) { return this.storageResource.handleStorageCommands((StorageSubSystemCommand)cmd); + } else if (clazz == CreateVMSnapshotCommand.class) { + return execute((CreateVMSnapshotCommand)cmd); + } else if (clazz == DeleteVMSnapshotCommand.class) { + return execute((DeleteVMSnapshotCommand)cmd); + } else if (clazz == RevertToVMSnapshotCommand.class) { + return execute((RevertToVMSnapshotCommand)cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } } + + + private Answer execute(RevertToVMSnapshotCommand cmd) { + String vmName = cmd.getVmName(); + List 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 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 vbds = vm.getVBDs(conn); + Map vdiMap = new HashMap(); + // 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()) { @@ -1004,13 +1114,13 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe vm.setAffinity(conn, host); vm.removeFromOtherConfig(conn, "disks"); vm.setNameLabel(conn, vmSpec.getName()); - setMemory(conn, vm, vmSpec.getMinRam()); + setMemory(conn, vm, vmSpec.getMinRam(),vmSpec.getMaxRam()); vm.setVCPUsMax(conn, (long)vmSpec.getCpus()); vm.setVCPUsAtStartup(conn, (long)vmSpec.getCpus()); Map vcpuParams = new HashMap(); - Integer speed = vmSpec.getSpeed(); + Integer speed = vmSpec.getMinSpeed(); if (speed != null) { int cpuWeight = _maxWeight; //cpu_weight @@ -3143,8 +3253,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - protected void setMemory(Connection conn, VM vm, long memsize) throws XmlRpcException, XenAPIException { - vm.setMemoryLimits(conn, memsize, memsize, memsize, memsize); + protected void setMemory(Connection conn, VM vm, long minMemsize, long maxMemsize) throws XmlRpcException, XenAPIException { + vm.setMemoryLimits(conn, maxMemsize, maxMemsize, minMemsize, maxMemsize); } private void waitForTask(Connection c, Task task, long pollInterval, long timeout) throws XenAPIException, XmlRpcException { @@ -3733,22 +3843,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe throw new CloudRuntimeException("Could not find an available slot in VM with name to attach a new disk."); } - - protected String getUnusedVIFNum(Connection conn, VM vm) { - String vmName = ""; - try { - vmName = vm.getNameLabel(conn); - Set allowedVIFDevices = vm.getAllowedVIFDevices(conn); - if (allowedVIFDevices.size() > 0) { - return allowedVIFDevices.iterator().next(); - } - } catch (Exception e) { - String msg = "getUnusedVIFNum failed due to " + e.toString(); - s_logger.warn(msg, e); - } - throw new CloudRuntimeException("Could not find available VIF slot in VM with name: " + vmName + " to plug a VIF"); - } - protected String callHostPlugin(Connection conn, String plugin, String cmd, String... params) { Map args = new HashMap(); String msg; @@ -3880,22 +3974,29 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } protected String getLowestAvailableVIFDeviceNum(Connection conn, VM vm) { + String vmName = ""; try { - Set availableDeviceNums = vm.getAllowedVIFDevices(conn); - Iterator deviceNumsIterator = availableDeviceNums.iterator(); - List sortedDeviceNums = new ArrayList(); - - while (deviceNumsIterator.hasNext()) { - try { - sortedDeviceNums.add(Integer.valueOf(deviceNumsIterator.next())); + vmName = vm.getNameLabel(conn); + List usedDeviceNums = new ArrayList(); + Set vifs = vm.getVIFs(conn); + Iterator vifIter = vifs.iterator(); + while(vifIter.hasNext()){ + VIF vif = vifIter.next(); + try{ + usedDeviceNums.add(Integer.valueOf(vif.getDevice(conn))); } catch (NumberFormatException e) { - s_logger.debug("Obtained an invalid value for an available VIF device number for VM: " + vm.getNameLabel(conn)); - return null; + String msg = "Obtained an invalid value for an allocated VIF device number for VM: " + vmName; + s_logger.debug(msg, e); + throw new CloudRuntimeException(msg); } } - Collections.sort(sortedDeviceNums); - return String.valueOf(sortedDeviceNums.get(0)); + for(Integer i=0; i< _maxNics; i++){ + if(!usedDeviceNums.contains(i)){ + s_logger.debug("Lowest available Vif device number: "+i+" for VM: " + vmName); + return i.toString(); + } + } } catch (XmlRpcException e) { String msg = "Caught XmlRpcException: " + e.getMessage(); s_logger.warn(msg, e); @@ -3904,7 +4005,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.warn(msg, e); } - return null; + throw new CloudRuntimeException("Could not find available VIF slot in VM with name: " + vmName); } protected VDI mount(Connection conn, StoragePoolType pooltype, String volumeFolder, String volumePath) { @@ -4763,7 +4864,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.debug("Copying " + f + " to " + d + " on " + hr.address + " with permission " + p); } try { - session.execCommand("mkdir -p " + d); + session.execCommand("mkdir -m 700 -p " + d); } catch (IOException e) { s_logger.debug("Unable to create destination path: " + d + " on " + hr.address + " but trying anyway"); @@ -5546,6 +5647,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe value = (String) params.get("migratewait"); _migratewait = NumbersUtil.parseInt(value, 3600); + _maxNics = NumbersUtil.parseInt((String) params.get("xen.nics.max"), 7); + if (_pod == null) { throw new ConfigurationException("Unable to get the pod"); } @@ -6167,6 +6270,199 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } + protected Answer execute(final CreateVMSnapshotCommand cmd) { + String vmName = cmd.getVmName(); + String vmSnapshotName = cmd.getTarget().getSnapshotName(); + List 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 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 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 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("".length(), result.length() - "".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 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 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 vdiMap = new HashMap(); + 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 vdiList = new ArrayList(); + Set 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 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(); @@ -7463,7 +7759,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.warn(msg); return new PlugNicAnswer(cmd, false, msg); } - String deviceId = getUnusedVIFNum(conn, vm); + String deviceId = getLowestAvailableVIFDeviceNum(conn, vm); nic.setDeviceId(Integer.parseInt(deviceId)); vif = createVif(conn, vmName, vm, nic); vif.plug(conn); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpServerResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpServerResource.java index 0ce91bc58e2..7a958708e76 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpServerResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpServerResource.java @@ -72,17 +72,17 @@ public class XcpServerResource extends CitrixResourceBase { } @Override - protected void setMemory(Connection conn, VM vm, long memsize) throws XmlRpcException, XenAPIException { + protected void setMemory(Connection conn, VM vm, long minMemsize, long maxMemsize) throws XmlRpcException, XenAPIException { vm.setMemoryStaticMin(conn, 33554432L); - vm.setMemoryDynamicMin(conn, 33554432L); - vm.setMemoryDynamicMax(conn, 33554432L); + //vm.setMemoryDynamicMin(conn, 33554432L); + //vm.setMemoryDynamicMax(conn, 33554432L); vm.setMemoryStaticMax(conn, 33554432L); - vm.setMemoryStaticMax(conn, memsize); - vm.setMemoryDynamicMax(conn, memsize); - vm.setMemoryDynamicMin(conn, memsize); - vm.setMemoryStaticMin(conn, memsize); + //vm.setMemoryStaticMax(conn, maxMemsize ); + vm.setMemoryDynamicMax(conn, maxMemsize ); + vm.setMemoryDynamicMin(conn, minMemsize ); + //vm.setMemoryStaticMin(conn, maxMemsize ); } @@ -99,7 +99,7 @@ public class XcpServerResource extends CitrixResourceBase { return answer; } catch (Exception ex) { s_logger.warn("Failed to get network usage stats due to ", ex); - return new NetworkUsageAnswer(cmd, ex); + return new NetworkUsageAnswer(cmd, ex); } } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java index 58b8a035171..7040311d04e 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java @@ -136,9 +136,9 @@ public class XenServer56FP1Resource extends XenServer56Resource { record.nameLabel = vmSpec.getName(); record.actionsAfterCrash = Types.OnCrashBehaviour.DESTROY; record.actionsAfterShutdown = Types.OnNormalExit.DESTROY; - record.memoryDynamicMax = vmSpec.getMinRam(); + record.memoryDynamicMax = vmSpec.getMaxRam(); record.memoryDynamicMin = vmSpec.getMinRam(); - record.memoryStaticMax = vmSpec.getMinRam(); + record.memoryStaticMax = vmSpec.getMaxRam(); record.memoryStaticMin = vmSpec.getMinRam(); record.VCPUsMax = (long) vmSpec.getCpus(); record.VCPUsAtStartup = (long) vmSpec.getCpus(); @@ -152,7 +152,7 @@ public class XenServer56FP1Resource extends XenServer56Resource { Map vcpuParams = new HashMap(); - Integer speed = vmSpec.getSpeed(); + Integer speed = vmSpec.getMinSpeed(); if (speed != null) { int cpuWeight = _maxWeight; // cpu_weight diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java index 70660d2bb69..9c291491114 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java @@ -144,6 +144,7 @@ public class XenServerStorageResource { try { obj = Decoder.decode(uriString); + DecodedDataStore store = obj.getStore(); if (obj.getObjType().equalsIgnoreCase("template") && store.getRole().equalsIgnoreCase("image")) { return getTemplateSize(cmd, obj.getPath()); @@ -224,6 +225,7 @@ public class XenServerStorageResource { } protected SR getNfsSR(Connection conn, DecodedDataStore store) { + Map deviceConfig = new HashMap(); String uuid = store.getUuid(); @@ -410,6 +412,7 @@ public class XenServerStorageResource { try { DecodedDataObject obj = Decoder.decode(storeUrl); DecodedDataStore store = obj.getStore(); + if (store.getScheme().equalsIgnoreCase("nfs")) { SR sr = getNfsSR(conn, store); } else if (store.getScheme().equalsIgnoreCase("iscsi")) { @@ -570,7 +573,9 @@ public class XenServerStorageResource { Connection conn = hypervisorResource.getConnection(); try { DecodedDataObject obj = Decoder.decode(dataStoreUri); + DecodedDataStore store = obj.getStore(); + SR sr = hypervisorResource.getStorageRepository(conn, store.getUuid()); hypervisorResource.setupHeartbeatSr(conn, sr, false); long capacity = sr.getPhysicalSize(conn); diff --git a/plugins/network-elements/bigswitch-vns/pom.xml b/plugins/network-elements/bigswitch-vns/pom.xml index 32650f31497..95a7692ce75 100644 --- a/plugins/network-elements/bigswitch-vns/pom.xml +++ b/plugins/network-elements/bigswitch-vns/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/dns-notifier/pom.xml b/plugins/network-elements/dns-notifier/pom.xml index ea35d788653..1dea4b933d1 100644 --- a/plugins/network-elements/dns-notifier/pom.xml +++ b/plugins/network-elements/dns-notifier/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml org.apache.cloudstack diff --git a/plugins/network-elements/elastic-loadbalancer/pom.xml b/plugins/network-elements/elastic-loadbalancer/pom.xml index dac500d8fd2..4d02a61e93e 100644 --- a/plugins/network-elements/elastic-loadbalancer/pom.xml +++ b/plugins/network-elements/elastic-loadbalancer/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/f5/pom.xml b/plugins/network-elements/f5/pom.xml index bf40332cfbb..d0f8133f2b4 100644 --- a/plugins/network-elements/f5/pom.xml +++ b/plugins/network-elements/f5/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/juniper-srx/pom.xml b/plugins/network-elements/juniper-srx/pom.xml index 6040720da6e..28f2c29eda7 100644 --- a/plugins/network-elements/juniper-srx/pom.xml +++ b/plugins/network-elements/juniper-srx/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/netscaler/pom.xml b/plugins/network-elements/netscaler/pom.xml index b11009d8b1a..1eb73a236dc 100644 --- a/plugins/network-elements/netscaler/pom.xml +++ b/plugins/network-elements/netscaler/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/nicira-nvp/pom.xml b/plugins/network-elements/nicira-nvp/pom.xml index 70f85607e4a..4e05a4f9fae 100644 --- a/plugins/network-elements/nicira-nvp/pom.xml +++ b/plugins/network-elements/nicira-nvp/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java index 3ba6167a47d..b78d165ddd6 100644 --- a/plugins/network-elements/nicira-nvp/src/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java @@ -151,7 +151,12 @@ public class NiciraNvpGuestNetworkGuru extends GuestNetworkGuru { long dcId = dest.getDataCenter().getId(); //get physical network id - long physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType()); + Long physicalNetworkId = network.getPhysicalNetworkId(); + + // physical network id can be null in Guest Network in Basic zone, so locate the physical network + if (physicalNetworkId == null) { + physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType()); + } NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), network.getBroadcastDomainType(), network.getNetworkOfferingId(), State.Allocated, network.getDataCenterId(), physicalNetworkId); diff --git a/plugins/network-elements/nicira-nvp/test/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java b/plugins/network-elements/nicira-nvp/test/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java index f86e705336c..0e4f8fd4f84 100644 --- a/plugins/network-elements/nicira-nvp/test/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java +++ b/plugins/network-elements/nicira-nvp/test/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java @@ -252,6 +252,7 @@ public class NiciraNvpGuestNetworkGuruTest { NetworkVO network = mock(NetworkVO.class); when(network.getName()).thenReturn("testnetwork"); when(network.getState()).thenReturn(State.Implementing); + when(network.getPhysicalNetworkId()).thenReturn(42L); DeployDestination dest = mock(DeployDestination.class); @@ -308,7 +309,7 @@ public class NiciraNvpGuestNetworkGuruTest { when(network.getState()).thenReturn(State.Implementing); when(network.getGateway()).thenReturn("10.1.1.1"); when(network.getCidr()).thenReturn("10.1.1.0/24"); - + when(network.getPhysicalNetworkId()).thenReturn(42L); DeployDestination dest = mock(DeployDestination.class); @@ -365,6 +366,7 @@ public class NiciraNvpGuestNetworkGuruTest { NetworkVO network = mock(NetworkVO.class); when(network.getName()).thenReturn("testnetwork"); when(network.getState()).thenReturn(State.Implementing); + when(network.getPhysicalNetworkId()).thenReturn(42L); DeployDestination dest = mock(DeployDestination.class); diff --git a/plugins/network-elements/ovs/pom.xml b/plugins/network-elements/ovs/pom.xml index ab7ffab8465..7964b931e19 100644 --- a/plugins/network-elements/ovs/pom.xml +++ b/plugins/network-elements/ovs/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/pom.xml b/plugins/pom.xml index 02459b4c1b5..88f617b4560 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT install diff --git a/plugins/storage-allocators/random/pom.xml b/plugins/storage-allocators/random/pom.xml index b476d1de49f..06754ffc133 100644 --- a/plugins/storage-allocators/random/pom.xml +++ b/plugins/storage-allocators/random/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java b/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java index 812867ee69d..af21f50cc6f 100644 --- a/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java +++ b/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java @@ -21,6 +21,7 @@ import java.util.List; import javax.ejb.Local; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -28,7 +29,6 @@ import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.server.StatsCollector; import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateVO; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; @@ -77,7 +77,8 @@ public class RandomStoragePoolAllocator extends AbstractStoragePoolAllocator { break; } if (checkPool(avoid, pool, dskCh, template, null, sc, plan)) { - suitablePools.add(pool); + StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); + suitablePools.add(pol); } } diff --git a/plugins/storage/image/s3/pom.xml b/plugins/storage/image/s3/pom.xml index 4ea6517527b..7ab0d3e9301 100644 --- a/plugins/storage/image/s3/pom.xml +++ b/plugins/storage/image/s3/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml index cbbc54c368d..9db0685e91b 100644 --- a/plugins/storage/volume/solidfire/pom.xml +++ b/plugins/storage/volume/solidfire/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java index 3244c7aa4ed..f31126c2aeb 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java @@ -24,9 +24,9 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { @@ -72,17 +72,25 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { return false; } - @Override - public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback) { - // TODO Auto-generated method stub - - } - @Override public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback) { // TODO Auto-generated method stub } + @Override + public void resize(DataObject data, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + + @Override + public void takeSnapshot(SnapshotInfo snapshot, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + } diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml index 05e9466d825..5c45f1177b6 100644 --- a/plugins/user-authenticators/ldap/pom.xml +++ b/plugins/user-authenticators/ldap/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java index fb0273e6ea3..61eebe5fc93 100644 --- a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java +++ b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java @@ -66,7 +66,7 @@ public class LDAPUserAuthenticator extends DefaultUserAuthenticator { String port = _configDao.getValue(LDAPParams.port.toString()); String queryFilter = _configDao.getValue(LDAPParams.queryfilter.toString()); String searchBase = _configDao.getValue(LDAPParams.searchbase.toString()); - String useSSL = _configDao.getValue(LDAPParams.usessl.toString()); + Boolean useSSL = Boolean.valueOf(_configDao.getValue(LDAPParams.usessl.toString())); String bindDN = _configDao.getValue(LDAPParams.dn.toString()); String bindPasswd = _configDao.getValue(LDAPParams.passwd.toString()); String trustStore = _configDao.getValue(LDAPParams.truststore.toString()); @@ -77,7 +77,7 @@ public class LDAPUserAuthenticator extends DefaultUserAuthenticator { Hashtable env = new Hashtable(11); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); String protocol = "ldap://" ; - if (new Boolean(useSSL)){ + if (useSSL){ env.put(Context.SECURITY_PROTOCOL, "ssl"); protocol="ldaps://" ; System.setProperty("javax.net.ssl.trustStore", trustStore); @@ -123,7 +123,7 @@ public class LDAPUserAuthenticator extends DefaultUserAuthenticator { env = new Hashtable(11); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); protocol = "ldap://" ; - if (new Boolean(useSSL)){ + if (useSSL){ env.put(Context.SECURITY_PROTOCOL, "ssl"); protocol="ldaps://" ; } @@ -135,8 +135,7 @@ public class LDAPUserAuthenticator extends DefaultUserAuthenticator { ctx.close(); } catch (NamingException ne) { - ne.printStackTrace(); - s_logger.warn("Authentication failed due to " + ne.getMessage()); + s_logger.warn("Authentication Failed ! " + ne.getMessage() + (ne.getCause() != null ? ("; Caused by:" + ne.getCause().getMessage()) : "")); return false; } catch (Exception e){ diff --git a/plugins/user-authenticators/md5/pom.xml b/plugins/user-authenticators/md5/pom.xml index f358f8f1c21..605014ff953 100644 --- a/plugins/user-authenticators/md5/pom.xml +++ b/plugins/user-authenticators/md5/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/plain-text/pom.xml b/plugins/user-authenticators/plain-text/pom.xml index 6406fa92489..60336ebb22d 100644 --- a/plugins/user-authenticators/plain-text/pom.xml +++ b/plugins/user-authenticators/plain-text/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/sha256salted/pom.xml b/plugins/user-authenticators/sha256salted/pom.xml index 3f530f76e17..22e97632e3d 100644 --- a/plugins/user-authenticators/sha256salted/pom.xml +++ b/plugins/user-authenticators/sha256salted/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT ../../pom.xml diff --git a/pom.xml b/pom.xml index b1d0ea54e56..0cb711e50c6 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT pom Apache CloudStack Apache CloudStack is an IaaS (“Infrastracture as a Service”) cloud orchestration platform. @@ -89,7 +89,7 @@ 2.6 1.4 0.9.8 - 0.8 + 0.10 @@ -156,7 +156,6 @@ api agent - console-proxy core server usage @@ -164,10 +163,11 @@ deps/XenServerJava plugins patches - client - test engine framework + services + test + client @@ -361,7 +361,7 @@ **/target/** **/.vagrant build/build.number - console-proxy/js/jquery.js + services/console-proxy/server/js/jquery.js debian/compat debian/control debian/dirs @@ -372,6 +372,13 @@ dist/console-proxy/js/jquery.js scripts/vm/systemvm/id_rsa.cloud tools/devcloud/basebuild/puppet-devcloudinitial/files/network.conf + tools/appliance/definitions/systemvmtemplate/base.sh + tools/appliance/definitions/systemvmtemplate/cleanup.sh + tools/appliance/definitions/systemvmtemplate/definition.rb + tools/appliance/definitions/systemvmtemplate/preseed.cfg + tools/appliance/definitions/systemvmtemplate/zerodisk.sh + tools/devcloud/src/deps/boxes/basebox-build/definition.rb + tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg ui/lib/flot/jquery.colorhelpers.js ui/lib/flot/jquery.flot.crosshair.js ui/lib/flot/jquery.flot.fillbetween.js @@ -395,6 +402,7 @@ ui/lib/qunit/qunit.css ui/lib/qunit/qunit.js ui/lib/reset.css + ui/lib/require.js waf patches/systemvm/debian/systemvm.vmx patches/systemvm/debian/config/root/.ssh/authorized_keys @@ -406,16 +414,13 @@ patches/systemvm/debian/config/etc/dnsmasq.conf patches/systemvm/debian/config/etc/vpcdnsmasq.conf patches/systemvm/debian/config/etc/ssh/sshd_config - patches/systemvm/debian/config/etc/rsyslog.conf - patches/systemvm/debian/config/etc/logrotate.conf patches/systemvm/debian/config/etc/logrotate.d/* patches/systemvm/debian/config/etc/sysctl.conf patches/systemvm/debian/config/root/redundant_router/keepalived.conf.templ patches/systemvm/debian/config/root/redundant_router/arping_gateways.sh.templ patches/systemvm/debian/config/root/redundant_router/conntrackd.conf.templ - patches/systemvm/debian/vpn/etc/ipsec.conf patches/systemvm/debian/vpn/etc/ppp/options.xl2tpd patches/systemvm/debian/vpn/etc/xl2tpd/xl2tpd.conf @@ -501,13 +506,12 @@ developer + + tools/devcloud/devcloud.cfg + developer - tools/apidoc - tools/devcloud - tools/devcloud-kvm - tools/marvin - tools/cli + tools @@ -521,5 +525,113 @@ vmware-base + + simulator + + + deploydb-simulator + + + + + + org.codehaus.mojo + properties-maven-plugin + 1.0-alpha-2 + + + initialize + + read-project-properties + + + + ${project.basedir}/utils/conf/db.properties + ${project.basedir}/utils/conf/db.properties.override + + true + + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + + mysql + mysql-connector-java + ${cs.mysql.version} + + + commons-dbcp + commons-dbcp + ${cs.dbcp.version} + + + commons-pool + commons-pool + ${cs.pool.version} + + + org.jasypt + jasypt + ${cs.jasypt.version} + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-server + ${project.version} + + + + + process-resources + create-schema + + java + + + + + false + true + + org.apache.cloudstack + cloud-server + + com.cloud.upgrade.DatabaseCreator + + + ${project.basedir}/utils/conf/db.properties + ${project.basedir}/utils/conf/db.properties.override + + ${basedir}/target/db/create-schema-simulator.sql + ${basedir}/target/db/templates.simulator.sql + + com.cloud.upgrade.DatabaseUpgradeChecker + --database=simulator + --rootpassword=${db.root.password} + + + + + catalina.home + ${project.basedir}/utils + + + + + + + diff --git a/python/lib/cloudutils/serviceConfigServer.py b/python/lib/cloudutils/serviceConfigServer.py index 66ec2d00a92..a08ce02d766 100644 --- a/python/lib/cloudutils/serviceConfigServer.py +++ b/python/lib/cloudutils/serviceConfigServer.py @@ -73,7 +73,7 @@ class cloudManagementConfig(serviceCfgBase): bash("iptables -A PREROUTING -t nat -p tcp --dport 443 -j REDIRECT --to-port 8250 ") #generate keystore - keyPath = "/var/lib/cloud/management/web.keystore" + keyPath = "/var/cloudstack/management/web.keystore" if not os.path.exists(keyPath): cmd = bash("keytool -genkey -keystore %s -storepass \"cloud.com\" -keypass \"cloud.com\" -validity 3650 -dname cn=\"Cloudstack User\",ou=\"mycloud.cloud.com\",o=\"mycloud.cloud.com\",c=\"Unknown\""%keyPath) diff --git a/python/lib/cloudutils/utilities.py b/python/lib/cloudutils/utilities.py index c9d1e339f72..739a48385a0 100755 --- a/python/lib/cloudutils/utilities.py +++ b/python/lib/cloudutils/utilities.py @@ -122,7 +122,14 @@ class Distribution: if kernel.find("2.6.32") != -1: self.release = "10.04" self.arch = bash("uname -m").getStdout() - + elif os.path.exists("/usr/bin/lsb_release"): + o = bash("/usr/bin/lsb_release -i") + distributor = o.getStdout().split(":\t")[1] + if "Debian" in distributor: + # This obviously needs a rewrite at some point + self.distro = "Ubuntu" + else: + raise UnknownSystemException(distributor) else: raise UnknownSystemException diff --git a/scripts/network/ping/baremetal_user_data.py b/scripts/network/ping/baremetal_user_data.py new file mode 100755 index 00000000000..a8ce32cb3ba --- /dev/null +++ b/scripts/network/ping/baremetal_user_data.py @@ -0,0 +1,104 @@ +# 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. + +''' +Created on Jul 2, 2012 + +@author: frank +''' +import sys +import os +import os.path +import base64 + +HTML_ROOT = "/var/www/html/" + +def writeIfNotHere(fileName, texts): + if not os.path.exists(fileName): + entries = [] + else: + f = open(fileName, 'r') + entries = f.readlines() + f.close() + + texts = [ "%s\n" % t for t in texts ] + need = False + for t in texts: + if not t in entries: + entries.append(t) + need = True + + if need: + f = open(fileName, 'w') + f.write(''.join(entries)) + f.close() + +def createRedirectEntry(vmIp, folder, filename): + entry = "RewriteRule ^%s$ ../%s/%%{REMOTE_ADDR}/%s [L,NC,QSA]" % (filename, folder, filename) + htaccessFolder="/var/www/html/latest" + htaccessFile=os.path.join(htaccessFolder, ".htaccess") + if not os.path.exists(htaccessFolder): + os.makedirs(htaccessFolder) + writeIfNotHere(htaccessFile, ["Options +FollowSymLinks", "RewriteEngine On", entry]) + + htaccessFolder = os.path.join("/var/www/html/", folder, vmIp) + if not os.path.exists(htaccessFolder): + os.makedirs(htaccessFolder) + htaccessFile=os.path.join(htaccessFolder, ".htaccess") + entry="Options -Indexes\nOrder Deny,Allow\nDeny from all\nAllow from %s" % vmIp + f = open(htaccessFile, 'w') + f.write(entry) + f.close() + + if folder in ['metadata', 'meta-data']: + entry1="RewriteRule ^meta-data/(.+)$ ../%s/%%{REMOTE_ADDR}/$1 [L,NC,QSA]" % folder + htaccessFolder="/var/www/html/latest" + htaccessFile=os.path.join(htaccessFolder, ".htaccess") + entry2="RewriteRule ^meta-data/$ ../%s/%%{REMOTE_ADDR}/meta-data [L,NC,QSA]" % folder + writeIfNotHere(htaccessFile, [entry1, entry2]) + + +def addUserData(vmIp, folder, fileName, contents): + + baseFolder = os.path.join(HTML_ROOT, folder, vmIp) + if not os.path.exists(baseFolder): + os.makedirs(baseFolder) + + createRedirectEntry(vmIp, folder, fileName) + + datafileName = os.path.join(HTML_ROOT, folder, vmIp, fileName) + metaManifest = os.path.join(HTML_ROOT, folder, vmIp, "meta-data") + if folder == "userdata": + if contents != "none": + contents = base64.urlsafe_b64decode(contents) + else: + contents = "" + + f = open(datafileName, 'w') + f.write(contents) + f.close() + + if folder == "metadata" or folder == "meta-data": + writeIfNotHere(metaManifest, fileName) + +if __name__ == '__main__': + string = sys.argv[1] + allEntires = string.split(";") + for entry in allEntires: + (vmIp, folder, fileName, contents) = entry.split(',', 3) + addUserData(vmIp, folder, fileName, contents) + sys.exit(0) diff --git a/scripts/network/ping/prepare_kickstart_bootfile.py b/scripts/network/ping/prepare_kickstart_bootfile.py new file mode 100755 index 00000000000..4378293b43a --- /dev/null +++ b/scripts/network/ping/prepare_kickstart_bootfile.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +# Copyright 2012 Citrix Systems, Inc. Licensed under the +# Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. Citrix Systems, Inc. +# reserves all rights not expressly granted by 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. +# +# Automatically generated by addcopyright.py at 04/03/2012 + + + + + +# Usage: prepare_tftp_bootfile.py tftp_dir mac cifs_server share directory image_to_restore cifs_username cifs_password +import os, sys +from sys import exit +from os import makedirs +from os.path import exists, join + +fmt1 = '''DEFAULT default +PROMPT 1 +TIMEOUT 26 +DISPLAY boot.msg +LABEL default +KERNEL %s +APPEND ramdisk_size=66000 initrd=%s ksdevice=%s ks=%s +''' +fmt2 = '''DEFAULT default +PROMPT 1 +TIMEOUT 26 +DISPLAY boot.msg +LABEL default +KERNEL %s +APPEND ramdisk_size=66000 initrd=%s ks=%s +''' + +tftp_dir = '' +mac = '' +kernel = '' +initrd = '' +ks_file = '' +ks_device = '' + +def prepare(): + try: + pxelinux = join(tftp_dir, "pxelinux.cfg") + if exists(pxelinux) == False: + makedirs(pxelinux) + + cfg_name = "01-" + mac.replace(':','-').lower() + cfg_path = join(pxelinux, cfg_name) + f = open(cfg_path, "w") + if ks_device == '': + stuff = fmt2 % (kernel, initrd, ks_file) + else: + stuff = fmt1 % (kernel, initrd, ks_device, ks_file) + f.write(stuff) + f.close() + return 0 + except Exception, e: + print e + return 1 + + +if __name__ == "__main__": + if len(sys.argv) < 7: + print "Usage: prepare_kickstart_bootfile.py tftp_dir mac kernel initrd ks_file ks_device" + exit(1) + + (tftp_dir, mac, kernel, initrd, ks_file, ks_device) = sys.argv[1:] + + ret = prepare() + exit(ret) diff --git a/scripts/network/ping/prepare_kickstart_kernel_initrd.py b/scripts/network/ping/prepare_kickstart_kernel_initrd.py new file mode 100755 index 00000000000..b234a62de70 --- /dev/null +++ b/scripts/network/ping/prepare_kickstart_kernel_initrd.py @@ -0,0 +1,70 @@ +#!/usr/bin/python +# 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. + +import sys +import tempfile +import os.path +import os + +iso_folder = '' +copy_to = '' + +def cmd(cmdstr, err=True): + if os.system(cmdstr) != 0 and err: + raise Exception("Failed to run shell command: %s" % cmdstr) + +def prepare(): + try: + kernel = os.path.join(copy_to, "vmlinuz") + initrd = os.path.join(copy_to, "initrd.img") + if os.path.exists(kernel) and os.path.exists(initrd): + print "Having template(%s) prepared already, skip copying" % copy_to + return 0 + else: + if not os.path.exists(copy_to): + os.makedirs(copy_to) + + mnt_path = tempfile.mkdtemp() + try: + mnt = "mount %s %s" % (iso_folder, mnt_path) + cmd(mnt) + + kernel = os.path.join(mnt_path, "vmlinuz") + initrd = os.path.join(mnt_path, "initrd.img") + cp = "cp -f %s %s/" % (kernel, copy_to) + cmd(cp) + cp = "cp -f %s %s/" % (initrd, copy_to) + cmd(cp) + finally: + umnt = "umount %s" % mnt_path + cmd(umnt, False) + rm = "rm -r %s" % mnt_path + cmd(rm, False) + return 0 + except Exception, e: + print e + return 1 + +if __name__ == "__main__": + if len(sys.argv) < 3: + print "Usage: prepare_kickstart_kerneal_initrd.py path_to_kernel_initrd_iso path_kernel_initrd_copy_to" + sys.exit(1) + + (iso_folder, copy_to) = sys.argv[1:] + sys.exit(prepare()) + diff --git a/scripts/util/ipmi.py b/scripts/util/ipmi.py old mode 100644 new mode 100755 diff --git a/scripts/vm/hypervisor/kvm/setup_agent.sh b/scripts/vm/hypervisor/kvm/setup_agent.sh index c9753939550..243f4a2b96c 100755 --- a/scripts/vm/hypervisor/kvm/setup_agent.sh +++ b/scripts/vm/hypervisor/kvm/setup_agent.sh @@ -19,12 +19,12 @@ -# Did cloud-agent installed +# Did cloudstack-agent installed #set -x install_cloud_agent() { local dev=$1 local retry=10 - which cloud-setup-agent + which cloudstack-setup-agent if [ $? -gt 0 ] then # download the repo @@ -51,7 +51,7 @@ install_cloud_agent() { while [ "$retry" -gt "0" ] do yum clean all - yum install cloud-agent -y + yum install cloudstack-agent -y if [ $? -gt 0 ] then let retry=retry-1 @@ -64,7 +64,7 @@ install_cloud_agent() { while [ "$retry" -gt "0" ] do yum clean all - yum update cloud-agent -y + yum update cloudstack-agent -y if [ $? -gt 0 ] then let retry=retry-1 @@ -155,7 +155,7 @@ cloud_agent_setup() { sed -i 's/\(SELINUX\)\(.*\)/\1=permissive/' /etc/selinux/config setenforce 0 fi - cloud-setup-agent --host=$host --zone=$zone --pod=$pod --cluster=$cluster --guid=$guid -a > /dev/null + cloudstack-setup-agent --host=$host --zone=$zone --pod=$pod --cluster=$cluster --guid=$guid -a > /dev/null } cloud_consoleP_setup() { @@ -224,5 +224,5 @@ then setenforce 0 fi -cloud-setup-agent --host=$host --zone=$zone --pod=$pod --cluster=$cluster --guid=$guid $paramters -a > /dev/null +cloudstack-setup-agent --host=$host --zone=$zone --pod=$pod --cluster=$cluster --guid=$guid $paramters -a > /dev/null #cloud_consoleP_setup $host $zone $pod diff --git a/scripts/vm/hypervisor/xenserver/vmopsSnapshot b/scripts/vm/hypervisor/xenserver/vmopsSnapshot index 39fe31c443d..6fb1b18c1df 100755 --- a/scripts/vm/hypervisor/xenserver/vmopsSnapshot +++ b/scripts/vm/hypervisor/xenserver/vmopsSnapshot @@ -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}) + diff --git a/scripts/vm/hypervisor/xenserver/xenheartbeat.sh b/scripts/vm/hypervisor/xenserver/xenheartbeat.sh index 9cf2afe87f6..5edacf7e39a 100755 --- a/scripts/vm/hypervisor/xenserver/xenheartbeat.sh +++ b/scripts/vm/hypervisor/xenserver/xenheartbeat.sh @@ -6,9 +6,9 @@ # 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 @@ -17,9 +17,9 @@ # under the License. #set -x - + usage() { - printf "Usage: %s [uuid of this host] [interval in seconds]\n" $(basename $0) >&2 + printf "Usage: %s [uuid of this host] [timeout in seconds] [interval in seconds]\n" $(basename $0) >&2 } @@ -33,10 +33,24 @@ if [ -z $2 ]; then exit 3 fi +if [ ! -z $3 ]; then + interval=$3 +else + interval=10 +fi + +if [ $interval -gt $2 ]; then + usage + exit 3 +fi + file=/opt/xensource/bin/heartbeat -while true -do - sleep $2 +maxtries=$(($2 / $interval)) +tries=1 + +while [ $tries -le $maxtries ] +do + sleep $interval if [ ! -f $file ] then @@ -51,13 +65,17 @@ do hb=$dir/hb-$1 date +%s | dd of=$hb count=100 bs=1 2>/dev/null if [ $? -ne 0 ]; then - /usr/bin/logger -t heartbeat "Problem with $hb" - reboot -f + /usr/bin/logger -t heartbeat "Potential problem with $hb: not reachable since $(($tries * $interval)) seconds" + tries=$(($tries + 1)) + else + tries=1 fi else + /usr/bin/logger -t heartbeat "Heartbeat dir not found for $dir" sed -i /${dir##/*/}/d $file fi done + # for nfs dirs=$(cat $file | grep sr-mount) for dir in $dirs @@ -67,13 +85,17 @@ do hb=$dir/hb-$1 date +%s | dd of=$hb count=100 bs=1 2>/dev/null if [ $? -ne 0 ]; then - /usr/bin/logger -t heartbeat "Problem with $hb" - reboot -f + /usr/bin/logger -t heartbeat "Potential problem with $hb: not reachable since $(($tries * $interval)) seconds" + tries=$(($tries + 1)) + else + tries=1 fi else + /usr/bin/logger -t heartbeat "Heartbeat mount not found for $dir" sed -i /${dir##/*/}/d $file fi done - done +/usr/bin/logger -t heartbeat "Problem with $hb: not reachable for $2 seconds, rebooting system!" +reboot -f diff --git a/server/pom.xml b/server/pom.xml index 602ed5b977b..59d1b15b911 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 2286dabfda1..3b5d433f1be 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -230,7 +230,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl @Override public boolean configure(final String name, final Map params) throws ConfigurationException { - + final Map configs = _configDao.getConfiguration("AgentManager", params); _port = NumbersUtil.parseInt(configs.get("port"), 8250); final int workers = NumbersUtil.parseInt(configs.get("workers"), 5); @@ -778,7 +778,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl if (host != null) { agentStatusTransitTo(host, Event.AgentDisconnected, _nodeId); } - } + } } if (forRebalance) { @@ -895,7 +895,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl } catch (NoTransitionException ne) { /* Agent may be currently in status of Down, Alert, Removed, namely there is no next status for some events. * Why this can happen? Ask God not me. I hate there was no piece of comment for code handling race condition. - * God knew what race condition the code dealt with! + * God knew what race condition the code dealt with! */ } @@ -1046,6 +1046,11 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl return false; } + if (host.getStatus() == Status.Disconnected) { + s_logger.info("Host is already disconnected, no work to be done"); + return true; + } + if (host.getStatus() != Status.Up && host.getStatus() != Status.Alert && host.getStatus() != Status.Rebalancing) { s_logger.info("Unable to disconnect host because it is not in the correct state: host=" + hostId + "; Status=" + host.getStatus()); return false; @@ -1197,12 +1202,12 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl } } Response response = null; - response = new Response(request, answers[0], _nodeId, -1); + response = new Response(request, answers[0], _nodeId, -1); try { link.send(response.toBytes()); } catch (ClosedChannelException e) { s_logger.debug("Failed to send startupanswer: " + e.toString()); - } + } _connectExecutor.execute(new HandleAgentConnectTask(link, cmds, request)); } @@ -1405,7 +1410,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl } else { throw new CloudRuntimeException("Unkonwn TapAgentsAction " + action); } - } + } return true; } @@ -1508,7 +1513,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl attache.setMaintenanceMode(true); // Now cancel all of the commands except for the active one. attache.cancelAllCommands(Status.Disconnected, false); - } + } } @Override diff --git a/server/src/com/cloud/agent/manager/AgentMonitor.java b/server/src/com/cloud/agent/manager/AgentMonitor.java index 97c0411d4e6..c019a76eaa8 100755 --- a/server/src/com/cloud/agent/manager/AgentMonitor.java +++ b/server/src/com/cloud/agent/manager/AgentMonitor.java @@ -71,7 +71,7 @@ public class AgentMonitor extends Thread implements Listener { private ConnectionConcierge _concierge; @Inject ClusterDao _clusterDao; @Inject ResourceManager _resourceMgr; - + // private ConnectionConcierge _concierge; private Map _pingMap; @@ -104,7 +104,7 @@ public class AgentMonitor extends Thread implements Listener { /** * Check if the agent is behind on ping - * + * * @param agentId * agent or host id. * @return null if the agent is not kept here. true if behind; false if not. @@ -144,21 +144,29 @@ public class AgentMonitor extends Thread implements Listener { SearchCriteriaService sc = SearchCriteria2.create(HostVO.class); sc.addAnd(sc.getEntity().getId(), Op.EQ, agentId); HostVO h = sc.find(); - ResourceState resourceState = h.getResourceState(); - if (resourceState == ResourceState.Disabled || resourceState == ResourceState.Maintenance || resourceState == ResourceState.ErrorInMaintenance) { - /* Host is in non-operation state, so no investigation and direct put agent to Disconnected */ - status_Logger.debug("Ping timeout but host " + agentId + " is in resource state of " + resourceState + ", so no investigation"); - _agentMgr.disconnectWithoutInvestigation(agentId, Event.ShutdownRequested); - } else { - status_Logger.debug("Ping timeout for host " + agentId + ", do invstigation"); - _agentMgr.disconnectWithInvestigation(agentId, Event.PingTimeout); + if (h != null) { + ResourceState resourceState = h.getResourceState(); + if (resourceState == ResourceState.Disabled || resourceState == ResourceState.Maintenance + || resourceState == ResourceState.ErrorInMaintenance) { + /* + * Host is in non-operation state, so no + * investigation and direct put agent to + * Disconnected + */ + status_Logger.debug("Ping timeout but host " + agentId + " is in resource state of " + + resourceState + ", so no investigation"); + _agentMgr.disconnectWithoutInvestigation(agentId, Event.ShutdownRequested); + } else { + status_Logger.debug("Ping timeout for host " + agentId + ", do invstigation"); + _agentMgr.disconnectWithInvestigation(agentId, Event.PingTimeout); + } } } SearchCriteriaService sc = SearchCriteria2.create(HostVO.class); sc.addAnd(sc.getEntity().getResourceState(), Op.IN, ResourceState.PrepareForMaintenance, ResourceState.ErrorInMaintenance); List hosts = sc.list(); - + for (HostVO host : hosts) { long hostId = host.getId(); DataCenterVO dcVO = _dcDao.findById(host.getDataCenterId()); @@ -170,7 +178,7 @@ public class AgentMonitor extends Thread implements Listener { List vosMigrating = _vmDao.listVmsMigratingFromHost(hostId); if (vos.isEmpty() && vosMigrating.isEmpty()) { _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Migration Complete for host " + hostDesc, "Host [" + hostDesc + "] is ready for maintenance"); - _resourceMgr.resourceStateTransitTo(host, ResourceState.Event.InternalEnterMaintenance, _msId); + _resourceMgr.resourceStateTransitTo(host, ResourceState.Event.InternalEnterMaintenance, _msId); } } } diff --git a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java index a25e4014dea..0091e43cab8 100755 --- a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java @@ -26,6 +26,10 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.org.Cluster; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -78,6 +82,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { @Inject GuestOSCategoryDao _guestOSCategoryDao = null; @Inject VMInstanceDao _vmInstanceDao = null; @Inject ResourceManager _resourceMgr; + @Inject ClusterDao _clusterDao; + @Inject ClusterDetailsDao _clusterDetailsDao; float _factor = 1; boolean _checkHvm = true; protected String _allocationAlgorithm = "random"; @@ -214,8 +220,14 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { boolean numCpusGood = host.getCpus().intValue() >= offering.getCpu(); boolean cpuFreqGood = host.getSpeed().intValue() >= offering.getSpeed(); int cpu_requested = offering.getCpu() * offering.getSpeed(); - long ram_requested = offering.getRamSize() * 1024L * 1024L; - boolean hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false, _factor, considerReservedCapacity); + long ram_requested = offering.getRamSize() * 1024L * 1024L; + Cluster cluster = _clusterDao.findById(host.getClusterId()); + ClusterDetailsVO clusterDetailsCpuOvercommit = _clusterDetailsDao.findDetail(cluster.getId(),"cpuOvercommitRatio"); + ClusterDetailsVO clusterDetailsRamOvercommmt = _clusterDetailsDao.findDetail(cluster.getId(),"memoryOvercommitRatio"); + Float cpuOvercommitRatio = Float.parseFloat(clusterDetailsCpuOvercommit.getValue()); + Float memoryOvercommitRatio = Float.parseFloat(clusterDetailsRamOvercommmt.getValue()); + + boolean hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false,cpuOvercommitRatio,memoryOvercommitRatio, considerReservedCapacity); if (numCpusGood && cpuFreqGood && hostHasCapacity) { if (s_logger.isDebugEnabled()) { diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index 4545f0a5e99..f8a8fd8b1b9 100755 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -38,6 +38,8 @@ import javax.mail.URLName; import javax.mail.internet.InternetAddress; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -69,8 +71,6 @@ import com.cloud.network.dao.IPAddressDao; import com.cloud.org.Grouping.AllocationState; import com.cloud.resource.ResourceManager; import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ManagerBase; @@ -102,7 +102,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager { @Inject private VolumeDao _volumeDao; @Inject private IPAddressDao _publicIPAddressDao; @Inject private DataCenterIpAddressDao _privateIPAddressDao; - @Inject private StoragePoolDao _storagePoolDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private ConfigurationDao _configDao; @Inject private ResourceManager _resourceMgr; @Inject private ConfigurationManager _configMgr; diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 83132c6aa76..ffee22fa1ae 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -45,7 +45,7 @@ import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VolumeResponse; import org.apache.cloudstack.api.response.ZoneResponse; - +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; import com.cloud.api.query.dao.AccountJoinDao; @@ -182,10 +182,13 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.*; import com.cloud.storage.Storage.ImageFormat; + import com.cloud.storage.Volume.Type; import com.cloud.storage.dao.*; import com.cloud.storage.snapshot.SnapshotPolicy; +import com.cloud.template.TemplateManager; import com.cloud.user.*; + import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; @@ -209,6 +212,8 @@ import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component public class ApiDBUtils { @@ -216,9 +221,12 @@ public class ApiDBUtils { static AsyncJobManager _asyncMgr; static SecurityGroupManager _securityGroupMgr; static StorageManager _storageMgr; + static VolumeManager _volumeMgr; static UserVmManager _userVmMgr; static NetworkModel _networkModel; static NetworkManager _networkMgr; + static TemplateManager _templateMgr; + static StatsCollector _statsCollector; static AccountDao _accountDao; @@ -309,6 +317,8 @@ public class ApiDBUtils { static SnapshotPolicyDao _snapshotPolicyDao; static AsyncJobDao _asyncJobDao; static HostDetailsDao _hostDetailsDao; + static VMSnapshotDao _vmSnapshotDao; + static ClusterDetailsDao _clusterDetailsDao; @Inject private ManagementServer ms; @Inject public AsyncJobManager asyncMgr; @@ -318,6 +328,8 @@ public class ApiDBUtils { @Inject private NetworkModel networkModel; @Inject private NetworkManager networkMgr; @Inject private StatsCollector statsCollector; + @Inject private TemplateManager templateMgr; + @Inject private VolumeManager volumeMgr; @Inject private AccountDao accountDao; @Inject private AccountVlanMapDao accountVlanMapDao; @@ -407,7 +419,8 @@ public class ApiDBUtils { @Inject private SnapshotPolicyDao snapshotPolicyDao; @Inject private AsyncJobDao asyncJobDao; @Inject private HostDetailsDao hostDetailsDao; - + @Inject private ClusterDetailsDao clusterDetailsDao; + @Inject private VMSnapshotDao vmSnapshotDao; @PostConstruct void init() { _ms = ms; @@ -418,6 +431,7 @@ public class ApiDBUtils { _networkModel = networkModel; _networkMgr = networkMgr; _configMgr = configMgr; + _templateMgr = templateMgr; _accountDao = accountDao; _accountVlanMapDao = accountVlanMapDao; @@ -505,7 +519,8 @@ public class ApiDBUtils { _snapshotPolicyDao = snapshotPolicyDao; _asyncJobDao = asyncJobDao; _hostDetailsDao = hostDetailsDao; - + _clusterDetailsDao = clusterDetailsDao; + _vmSnapshotDao = vmSnapshotDao; // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned _statsCollector = StatsCollector.getInstance(); } @@ -606,7 +621,7 @@ public class ApiDBUtils { public static String getSnapshotIntervalTypes(long snapshotId) { SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - return snapshot.getType().name(); + return snapshot.getRecurringType().name(); } public static String getStoragePoolTags(long poolId) { @@ -669,6 +684,10 @@ public class ApiDBUtils { return _clusterDao.findById(clusterId); } + public static ClusterDetailsVO findClusterDetails(long clusterId, String name){ + return _clusterDetailsDao.findDetail(clusterId,name); + } + public static DiskOfferingVO findDiskOfferingById(Long diskOfferingId) { return _diskOfferingDao.findByIdIncludingRemoved(diskOfferingId); } @@ -781,7 +800,7 @@ public class ApiDBUtils { List res = _templateHostDao.listByTemplateId(templateId); return res.size() == 0 ? null : res.get(0); } else { - return _storageMgr.getTemplateHostRef(zoneId, templateId, readyOnly); + return _templateMgr.getTemplateHostRef(zoneId, templateId, readyOnly); } } @@ -883,7 +902,7 @@ public class ApiDBUtils { throw new InvalidParameterValueException("Please specify a valid volume ID."); } - return _storageMgr.volumeOnSharedStoragePool(volume); + return _volumeMgr.volumeOnSharedStoragePool(volume); } public static List getNics(VirtualMachine vm) { @@ -1054,6 +1073,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); } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 8c9761520bb..eafee8a2a4a 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -93,8 +93,8 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; - import org.apache.cloudstack.api.response.S3Response; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; import com.cloud.async.AsyncJob; @@ -166,6 +166,7 @@ import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; + import com.cloud.storage.snapshot.SnapshotPolicy; import com.cloud.storage.snapshot.SnapshotSchedule; import com.cloud.template.VirtualMachineTemplate; @@ -195,6 +196,13 @@ import org.apache.cloudstack.region.Region; import org.apache.cloudstack.usage.Usage; import org.apache.cloudstack.usage.UsageService; import org.apache.cloudstack.usage.UsageTypes; +import com.cloud.vm.VmStats; +import com.cloud.vm.dao.UserVmData; +import com.cloud.vm.dao.UserVmData.NicData; +import com.cloud.vm.dao.UserVmData.SecurityGroupData; +import com.cloud.vm.snapshot.VMSnapshot; +import org.apache.cloudstack.api.ResponseGenerator; +import org.apache.cloudstack.api.response.VMSnapshotResponse; import org.apache.log4j.Logger; import java.text.DecimalFormat; @@ -333,7 +341,7 @@ public class ApiResponseHelper implements ResponseGenerator { populateOwner(snapshotResponse, snapshot); VolumeVO volume = findVolumeById(snapshot.getVolumeId()); - String snapshotTypeStr = snapshot.getType().name(); + String snapshotTypeStr = snapshot.getRecurringType().name(); snapshotResponse.setSnapshotType(snapshotTypeStr); if (volume != null) { snapshotResponse.setVolumeId(volume.getUuid()); @@ -358,6 +366,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(); @@ -663,14 +690,12 @@ public class ApiResponseHelper implements ResponseGenerator { if (showCapacities != null && showCapacities) { List capacities = ApiDBUtils.getCapacityByClusterPodZone(null, pod.getId(), null); Set capacityResponses = new HashSet(); - float cpuOverprovisioningFactor = ApiDBUtils.getCpuOverprovisioningFactor(); - for (SummedCapacity capacity : capacities) { CapacityResponse capacityResponse = new CapacityResponse(); capacityResponse.setCapacityType(capacity.getCapacityType()); capacityResponse.setCapacityUsed(capacity.getUsedCapacity()); if (capacity.getCapacityType() == Capacity.CAPACITY_TYPE_CPU) { - capacityResponse.setCapacityTotal(new Long((long) (capacity.getTotalCapacity() * cpuOverprovisioningFactor))); + capacityResponse.setCapacityTotal(new Long((long) (capacity.getTotalCapacity()))); } else if (capacity.getCapacityType() == Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED) { List c = ApiDBUtils.findNonSharedStorageForClusterPodZone(null, pod.getId(), null); capacityResponse.setCapacityTotal(capacity.getTotalCapacity() - c.get(0).getTotalCapacity()); @@ -800,12 +825,15 @@ public class ApiResponseHelper implements ResponseGenerator { clusterResponse.setClusterType(cluster.getClusterType().toString()); clusterResponse.setAllocationState(cluster.getAllocationState().toString()); clusterResponse.setManagedState(cluster.getManagedState().toString()); + String cpuOvercommitRatio=ApiDBUtils.findClusterDetails(cluster.getId(),"cpuOvercommitRatio").getValue(); + String memoryOvercommitRatio=ApiDBUtils.findClusterDetails(cluster.getId(),"memoryOvercommitRatio").getValue(); + clusterResponse.setCpuovercommitratio(cpuOvercommitRatio); + clusterResponse.setRamovercommitratio(memoryOvercommitRatio); if (showCapacities != null && showCapacities) { List capacities = ApiDBUtils.getCapacityByClusterPodZone(null, null, cluster.getId()); Set capacityResponses = new HashSet(); - float cpuOverprovisioningFactor = ApiDBUtils.getCpuOverprovisioningFactor(); for (SummedCapacity capacity : capacities) { CapacityResponse capacityResponse = new CapacityResponse(); @@ -813,8 +841,11 @@ public class ApiResponseHelper implements ResponseGenerator { capacityResponse.setCapacityUsed(capacity.getUsedCapacity()); if (capacity.getCapacityType() == Capacity.CAPACITY_TYPE_CPU) { - capacityResponse.setCapacityTotal(new Long((long) (capacity.getTotalCapacity() * cpuOverprovisioningFactor))); - } else if (capacity.getCapacityType() == Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED) { + capacityResponse.setCapacityTotal(new Long((long) (capacity.getTotalCapacity() * Float.parseFloat(cpuOvercommitRatio)))); + }else if (capacity.getCapacityType() == Capacity.CAPACITY_TYPE_MEMORY){ + capacityResponse.setCapacityTotal(new Long((long) (capacity.getTotalCapacity() * Float.parseFloat(memoryOvercommitRatio)))); + } + else if (capacity.getCapacityType() == Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED) { List c = ApiDBUtils.findNonSharedStorageForClusterPodZone(null, null, cluster.getId()); capacityResponse.setCapacityTotal(capacity.getTotalCapacity() - c.get(0).getTotalCapacity()); capacityResponse.setCapacityUsed(capacity.getUsedCapacity() - c.get(0).getUsedCapacity()); @@ -2126,13 +2157,48 @@ public class ApiResponseHelper implements ResponseGenerator { // FIXME - either set netmask or cidr response.setCidr(network.getCidr()); - if (network.getCidr() != null) { + response.setNetworkCidr((network.getNetworkCidr())); + // If network has reservation its entire network cidr is defined by getNetworkCidr() + // if no reservation is present then getCidr() will define the entire network cidr + if (network.getNetworkCidr() != null) { + response.setNetmask(NetUtils.cidr2Netmask(network.getNetworkCidr())); + } + if (((network.getCidr()) != null) && (network.getNetworkCidr() == null)) { response.setNetmask(NetUtils.cidr2Netmask(network.getCidr())); } response.setIp6Gateway(network.getIp6Gateway()); response.setIp6Cidr(network.getIp6Cidr()); + // create response for reserved IP ranges that can be used for non-cloudstack purposes + String reservation = null; + if ((network.getCidr() != null) && (NetUtils.isNetworkAWithinNetworkB(network.getCidr(), network.getNetworkCidr()))) { + String[] guestVmCidrPair = network.getCidr().split("\\/"); + String[] guestCidrPair = network.getNetworkCidr().split("\\/"); + + Long guestVmCidrSize = Long.valueOf(guestVmCidrPair[1]); + Long guestCidrSize = Long.valueOf(guestCidrPair[1]); + + String[] guestVmIpRange = NetUtils.getIpRangeFromCidr(guestVmCidrPair[0], guestVmCidrSize); + String[] guestIpRange = NetUtils.getIpRangeFromCidr(guestCidrPair[0], guestCidrSize); + long startGuestIp = NetUtils.ip2Long(guestIpRange[0]); + long endGuestIp = NetUtils.ip2Long(guestIpRange[1]); + long startVmIp = NetUtils.ip2Long(guestVmIpRange[0]); + long endVmIp = NetUtils.ip2Long(guestVmIpRange[1]); + + if (startVmIp == startGuestIp && endVmIp < endGuestIp -1) { + reservation = (NetUtils.long2Ip(endVmIp + 1) + "-" + NetUtils.long2Ip(endGuestIp)); + } + if (endVmIp == endGuestIp && startVmIp > startGuestIp + 1) { + reservation = (NetUtils.long2Ip(startGuestIp) + "-" + NetUtils.long2Ip(startVmIp-1)); + } + if(startVmIp > startGuestIp + 1 && endVmIp < endGuestIp - 1) { + reservation = (NetUtils.long2Ip(startGuestIp) + "-" + NetUtils.long2Ip(startVmIp-1) + " , " + + NetUtils.long2Ip(endVmIp + 1) + "-"+ NetUtils.long2Ip(endGuestIp)); + } + } + response.setReservedIpRange(reservation); + //return vlan information only to Root admin if (network.getBroadcastUri() != null && UserContext.current().getCaller().getType() == Account.ACCOUNT_TYPE_ADMIN) { String broadcastUri = network.getBroadcastUri().toString(); @@ -3093,7 +3159,6 @@ public class ApiResponseHelper implements ResponseGenerator { response.setObjectName("vpnconnection"); return response; } - @Override public GuestOSResponse createGuestOSResponse(GuestOS guestOS) { GuestOSResponse response = new GuestOSResponse(); @@ -3133,7 +3198,6 @@ public class ApiResponseHelper implements ResponseGenerator { } - @Override public UsageRecordResponse createUsageResponse(Usage usageRecord) { UsageRecordResponse usageRecResponse = new UsageRecordResponse(); diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index d99d188b5d5..60d65da2f54 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -139,6 +139,7 @@ import com.cloud.utils.component.PluggableService; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; @Component public class ApiServer implements HttpRequestHandler { @@ -157,8 +158,6 @@ public class ApiServer implements HttpRequestHandler { @Inject List _pluggableServices; @Inject List _apiAccessCheckers; - private Account _systemAccount = null; - private User _systemUser = null; @Inject private RegionManager _regionMgr = null; private static int _workerCount = 0; @@ -182,9 +181,6 @@ public class ApiServer implements HttpRequestHandler { } public void init() { - _systemAccount = _accountMgr.getSystemAccount(); - _systemUser = _accountMgr.getSystemUser(); - Integer apiPort = null; // api port, null by default SearchCriteria sc = _configDao.createSearchCriteria(); sc.addAnd("name", SearchCriteria.Op.EQ, "integration.api.port"); @@ -212,8 +208,12 @@ public class ApiServer implements HttpRequestHandler { for(PluggableService pluggableService: _pluggableServices) cmdClasses.addAll(pluggableService.getCommands()); - for(Class cmdClass: cmdClasses) { - String apiName = cmdClass.getAnnotation(APICommand.class).name(); + for(Class cmdClass: cmdClasses) { + APICommand at = cmdClass.getAnnotation(APICommand.class); + if (at == null) { + throw new CloudRuntimeException(String.format("%s is claimed as a API command, but it doesn't have @APICommand annotation", cmdClass.getName())); + } + String apiName = at.name(); if (_apiNameCmdClassMap.containsKey(apiName)) { s_logger.error("API Cmd class " + cmdClass.getName() + " has non-unique apiname" + apiName); continue; @@ -278,7 +278,7 @@ public class ApiServer implements HttpRequestHandler { try { // always trust commands from API port, user context will always be UID_SYSTEM/ACCOUNT_ID_SYSTEM - UserContext.registerContext(_systemUser.getId(), _systemAccount, null, true); + UserContext.registerContext(_accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount(), null, true); sb.insert(0, "(userId=" + User.UID_SYSTEM + " accountId=" + Account.ACCOUNT_ID_SYSTEM + " sessionId=" + null + ") "); String responseText = handleRequest(parameterMap, responseType, sb); sb.append(" 200 " + ((responseText == null) ? 0 : responseText.length())); @@ -326,6 +326,12 @@ public class ApiServer implements HttpRequestHandler { continue; } String[] value = (String[]) params.get(key); + // fail if parameter value contains ASCII control (non-printable) characters + String newValue = StringUtils.stripControlCharacters(value[0]); + if ( !newValue.equals(value[0]) ) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Received value " + value[0] + " for parameter " + + key + " is invalid, contains illegal ASCII non-printable characters"); + } paramMap.put(key, value[0]); } diff --git a/server/src/com/cloud/api/query/ViewResponseHelper.java b/server/src/com/cloud/api/query/ViewResponseHelper.java index 55d84bb5af4..9e612b07d1b 100644 --- a/server/src/com/cloud/api/query/ViewResponseHelper.java +++ b/server/src/com/cloud/api/query/ViewResponseHelper.java @@ -67,7 +67,6 @@ import com.cloud.user.UserContext; /** * Helper class to generate response from DB view VO objects. - * @author minc * */ public class ViewResponseHelper { diff --git a/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java index 22b807c9d40..898bafc47cd 100644 --- a/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java @@ -157,6 +157,24 @@ public class AccountJoinDaoImpl extends GenericDaoBase impl accountResponse.setNetworkTotal(vpcTotal); accountResponse.setNetworkAvailable(vpcAvail); + //get resource limits for cpu cores + long cpuLimit = ApiDBUtils.findCorrectResourceLimit(account.getCpuLimit(), account.getType(), ResourceType.cpu); + String cpuLimitDisplay = (accountIsAdmin || cpuLimit == -1) ? "Unlimited" : String.valueOf(cpuLimit); + long cpuTotal = (account.getCpuTotal() == null) ? 0 : account.getCpuTotal(); + String cpuAvail = (accountIsAdmin || cpuLimit == -1) ? "Unlimited" : String.valueOf(cpuLimit - cpuTotal); + accountResponse.setCpuLimit(cpuLimitDisplay); + accountResponse.setCpuTotal(cpuTotal); + accountResponse.setCpuAvailable(cpuAvail); + + //get resource limits for memory + long memoryLimit = ApiDBUtils.findCorrectResourceLimit(account.getMemoryLimit(), account.getType(), ResourceType.memory); + String memoryLimitDisplay = (accountIsAdmin || memoryLimit == -1) ? "Unlimited" : String.valueOf(memoryLimit); + long memoryTotal = (account.getMemoryTotal() == null) ? 0 : account.getMemoryTotal(); + String memoryAvail = (accountIsAdmin || memoryLimit == -1) ? "Unlimited" : String.valueOf(memoryLimit - memoryTotal); + accountResponse.setMemoryLimit(memoryLimitDisplay); + accountResponse.setMemoryTotal(memoryTotal); + accountResponse.setMemoryAvailable(memoryAvail); + // adding all the users for an account as part of the response obj List usersForAccount = ApiDBUtils.findUserViewByAccountId(account.getId()); List userResponses = ViewResponseHelper.createUserResponse(usersForAccount.toArray(new UserAccountJoinVO[usersForAccount.size()])); diff --git a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java index 96b91df79f9..22e3badabac 100644 --- a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java @@ -68,7 +68,7 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase implem nicResponse.setNetmask(userVm.getNetmask()); nicResponse.setNetworkid(userVm.getNetworkUuid()); nicResponse.setMacAddress(userVm.getMacAddress()); + nicResponse.setIp6Address(userVm.getIp6Address()); + nicResponse.setIp6Gateway(userVm.getIp6Gateway()); + nicResponse.setIp6Cidr(userVm.getIp6Cidr()); if (userVm.getBroadcastUri() != null) { nicResponse.setBroadcastUri(userVm.getBroadcastUri().toString()); } @@ -244,6 +247,9 @@ public class UserVmJoinDaoImpl extends GenericDaoBase implem nicResponse.setNetmask(uvo.getNetmask()); nicResponse.setNetworkid(uvo.getNetworkUuid()); nicResponse.setMacAddress(uvo.getMacAddress()); + nicResponse.setIp6Address(uvo.getIp6Address()); + nicResponse.setIp6Gateway(uvo.getIp6Gateway()); + nicResponse.setIp6Cidr(uvo.getIp6Cidr()); if (uvo.getBroadcastUri() != null) { nicResponse.setBroadcastUri(uvo.getBroadcastUri().toString()); } @@ -327,7 +333,15 @@ public class UserVmJoinDaoImpl extends GenericDaoBase implem } Set vmIdSet = userVmDataHash.keySet(); - return searchByIds(vmIdSet.toArray(new Long[vmIdSet.size()])); + List uvms = searchByIds(vmIdSet.toArray(new Long[vmIdSet.size()])); + // populate transit password field from UserVm + if ( uvms != null ){ + for (UserVmJoinVO uvm : uvms){ + UserVm v = userVmDataHash.get(uvm.getId()); + uvm.setPassword(v.getPassword()); + } + } + return uvms; } } diff --git a/server/src/com/cloud/api/query/vo/AccountJoinVO.java b/server/src/com/cloud/api/query/vo/AccountJoinVO.java index 6d37f4de00e..cd7231cc8ea 100644 --- a/server/src/com/cloud/api/query/vo/AccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/AccountJoinVO.java @@ -148,6 +148,20 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident @Column(name="vpcTotal") private Long vpcTotal; + + @Column(name="cpuLimit") + private Long cpuLimit; + + @Column(name="cpuTotal") + private Long cpuTotal; + + + @Column(name="memoryLimit") + private Long memoryLimit; + + @Column(name="memoryTotal") + private Long memoryTotal; + @Column(name="job_id") private long jobId; @@ -445,7 +459,6 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident } - public Long getVpcTotal() { return vpcTotal; } @@ -456,6 +469,25 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident } + public Long getCpuTotal() { + return cpuTotal; + } + + + public void setCpuTotal(Long cpuTotal) { + this.cpuTotal = cpuTotal; + } + + public Long getMemoryTotal() { + return memoryTotal; + } + + + public void setMemoryTotal(Long memoryTotal) { + this.memoryTotal = memoryTotal; + } + + public Long getVmLimit() { return vmLimit; } @@ -536,6 +568,26 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident } + public Long getCpuLimit() { + return cpuLimit; + } + + + public void setCpuLimit(Long cpuLimit) { + this.cpuLimit = cpuLimit; + } + + + public Long getMemoryLimit() { + return memoryLimit; + } + + + public void setMemoryLimit(Long memoryLimit) { + this.memoryLimit = memoryLimit; + } + + public long getJobId() { return jobId; } diff --git a/server/src/com/cloud/api/query/vo/ControlledViewEntity.java b/server/src/com/cloud/api/query/vo/ControlledViewEntity.java index 12557504807..014abfaa3c0 100644 --- a/server/src/com/cloud/api/query/vo/ControlledViewEntity.java +++ b/server/src/com/cloud/api/query/vo/ControlledViewEntity.java @@ -24,7 +24,6 @@ import org.apache.cloudstack.api.InternalIdentity; /** * This is the interface for all VO classes representing DB views created for previous ControlledEntity. * - * @author minc * */ public interface ControlledViewEntity extends ControlledEntity, InternalIdentity, Identity { diff --git a/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java b/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java index a9c04586a92..606ec15fcbc 100644 --- a/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java +++ b/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java @@ -157,6 +157,15 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti @Column(name = "netmask") private String netmask; + @Column(name = "ip6_address") + private String ip6Address; + + @Column(name = "ip6_gateway") + private String ip6Gateway; + + @Column(name = "ip6_cidr") + private String ip6Cidr; + @Column(name = "mac_address") private String macAddress; @@ -920,4 +929,46 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti } + + + public String getIp6Address() { + return ip6Address; + } + + + + + public void setIp6Address(String ip6Address) { + this.ip6Address = ip6Address; + } + + + + + public String getIp6Gateway() { + return ip6Gateway; + } + + + + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + + + + public String getIp6Cidr() { + return ip6Cidr; + } + + + + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } + + } diff --git a/server/src/com/cloud/api/query/vo/HostJoinVO.java b/server/src/com/cloud/api/query/vo/HostJoinVO.java index a3796b97eba..0b8f6721325 100644 --- a/server/src/com/cloud/api/query/vo/HostJoinVO.java +++ b/server/src/com/cloud/api/query/vo/HostJoinVO.java @@ -39,7 +39,6 @@ import org.apache.cloudstack.api.InternalIdentity; /** * Host DB view. - * @author minc * */ @Entity diff --git a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java index fd837bd5d88..89e79e5eea5 100644 --- a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java +++ b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java @@ -34,7 +34,6 @@ import org.apache.cloudstack.api.InternalIdentity; /** * Storage Pool DB view. - * @author minc * */ @Entity diff --git a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java index 025db47d599..d7238224e4e 100644 --- a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java @@ -269,6 +269,15 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name = "netmask") private String netmask; + @Column(name = "ip6_address") + private String ip6Address; + + @Column(name = "ip6_gateway") + private String ip6Gateway; + + @Column(name = "ip6_cidr") + private String ip6Cidr; + @Column(name = "mac_address") private String macAddress; @@ -1611,4 +1620,42 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { return toString; } + public String getIp6Address() { + return ip6Address; + } + + + + + public void setIp6Address(String ip6Address) { + this.ip6Address = ip6Address; + } + + + + + public String getIp6Gateway() { + return ip6Gateway; + } + + + + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + + + + public String getIp6Cidr() { + return ip6Cidr; + } + + + + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } } diff --git a/server/src/com/cloud/baremetal/BareMetalDiscoverer.java b/server/src/com/cloud/baremetal/BareMetalDiscoverer.java deleted file mode 100755 index e7518853ef0..00000000000 --- a/server/src/com/cloud/baremetal/BareMetalDiscoverer.java +++ /dev/null @@ -1,245 +0,0 @@ -// 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.baremetal; - -import java.net.InetAddress; -import java.net.URI; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupRoutingCommand; -import org.apache.cloudstack.api.ApiConstants; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.dao.ClusterDao; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.exception.DiscoveryException; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.hypervisor.Hypervisor; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.Network; -import com.cloud.resource.Discoverer; -import com.cloud.resource.DiscovererBase; -import com.cloud.resource.ResourceManager; -import com.cloud.resource.ResourceStateAdapter; -import com.cloud.resource.ServerResource; -import com.cloud.resource.UnableDeleteHostException; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.script.Script; -import com.cloud.utils.script.Script2; -import com.cloud.utils.script.Script2.ParamType; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.dao.VMInstanceDao; - -@Local(value=Discoverer.class) -public class BareMetalDiscoverer extends DiscovererBase implements Discoverer, ResourceStateAdapter { - private static final Logger s_logger = Logger.getLogger(BareMetalDiscoverer.class); - @Inject ClusterDao _clusterDao; - @Inject protected HostDao _hostDao; - @Inject DataCenterDao _dcDao; - @Inject VMInstanceDao _vmDao = null; - @Inject ResourceManager _resourceMgr; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); - return super.configure(name, params); - } - - @Override - public boolean stop() { - _resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName()); - return super.stop(); - } - - @Override - public Map> find(long dcId, Long podId, Long clusterId, URI url, String username, String password, List hostTags) - throws DiscoveryException { - Map> resources = new HashMap>(); - Map details = new HashMap(); - - if (!url.getScheme().equals("http")) { - String msg = "urlString is not http so we're not taking care of the discovery for this: " + url; - s_logger.debug(msg); - return null; - } - if (clusterId == null) { - String msg = "must specify cluster Id when add host"; - s_logger.debug(msg); - throw new RuntimeException(msg); - } - - if (podId == null) { - String msg = "must specify pod Id when add host"; - s_logger.debug(msg); - throw new RuntimeException(msg); - } - - ClusterVO cluster = _clusterDao.findById(clusterId); - if (cluster == null || (cluster.getHypervisorType() != HypervisorType.BareMetal)) { - if (s_logger.isInfoEnabled()) - s_logger.info("invalid cluster id or cluster is not for Bare Metal hosts"); - return null; - } - - DataCenterVO zone = _dcDao.findById(dcId); - if (zone == null) { - throw new RuntimeException("Cannot find zone " + dcId); - } - - try { - String hostname = url.getHost(); - InetAddress ia = InetAddress.getByName(hostname); - String ipmiIp = ia.getHostAddress(); - String guid = UUID.nameUUIDFromBytes(ipmiIp.getBytes()).toString(); - - String injectScript = "scripts/util/ipmi.py"; - String scriptPath = Script.findScript("", injectScript); - if (scriptPath == null) { - throw new CloudRuntimeException("Unable to find key ipmi script " - + injectScript); - } - - final Script2 command = new Script2(scriptPath, s_logger); - command.add("ping"); - command.add("hostname="+ipmiIp); - command.add("usrname="+username); - command.add("password="+password, ParamType.PASSWORD); - final String result = command.execute(); - if (result != null) { - s_logger.warn(String.format("Can not set up ipmi connection(ip=%1$s, username=%2$s, password=%3$s, args) because %4$s", ipmiIp, username, "******", result)); - return null; - } - - ClusterVO clu = _clusterDao.findById(clusterId); - if (clu.getGuid() == null) { - clu.setGuid(UUID.randomUUID().toString()); - _clusterDao.update(clusterId, clu); - } - - Map params = new HashMap(); - params.putAll(_params); - params.put("zone", Long.toString(dcId)); - params.put("pod", Long.toString(podId)); - params.put("cluster", Long.toString(clusterId)); - params.put("guid", guid); - params.put(ApiConstants.PRIVATE_IP, ipmiIp); - params.put(ApiConstants.USERNAME, username); - params.put(ApiConstants.PASSWORD, password); - BareMetalResourceBase resource = new BareMetalResourceBase(); - resource.configure("Bare Metal Agent", params); - - String memCapacity = (String)params.get(ApiConstants.MEMORY); - String cpuCapacity = (String)params.get(ApiConstants.CPU_SPEED); - String cpuNum = (String)params.get(ApiConstants.CPU_NUMBER); - String mac = (String)params.get(ApiConstants.HOST_MAC); - if (hostTags != null && hostTags.size() != 0) { - details.put("hostTag", hostTags.get(0)); - } - details.put(ApiConstants.MEMORY, memCapacity); - details.put(ApiConstants.CPU_SPEED, cpuCapacity); - details.put(ApiConstants.CPU_NUMBER, cpuNum); - details.put(ApiConstants.HOST_MAC, mac); - details.put(ApiConstants.USERNAME, username); - details.put(ApiConstants.PASSWORD, password); - details.put(ApiConstants.PRIVATE_IP, ipmiIp); - - resources.put(resource, details); - resource.start(); - - zone.setGatewayProvider(Network.Provider.ExternalGateWay.getName()); - zone.setDnsProvider(Network.Provider.ExternalDhcpServer.getName()); - zone.setDhcpProvider(Network.Provider.ExternalDhcpServer.getName()); - _dcDao.update(zone.getId(), zone); - - s_logger.debug(String.format("Discover Bare Metal host successfully(ip=%1$s, username=%2$s, password=%3%s," + - "cpuNum=%4$s, cpuCapacity-%5$s, memCapacity=%6$s)", ipmiIp, username, "******", cpuNum, cpuCapacity, memCapacity)); - return resources; - } catch (Exception e) { - s_logger.warn("Can not set up bare metal agent", e); - } - - return null; - } - - @Override - public void postDiscovery(List hosts, long msId) - throws DiscoveryException { - } - - @Override - public boolean matchHypervisor(String hypervisor) { - return hypervisor.equalsIgnoreCase(Hypervisor.HypervisorType.BareMetal.toString()); - } - - @Override - public HypervisorType getHypervisorType() { - return Hypervisor.HypervisorType.BareMetal; - } - - @Override - public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { - // TODO Auto-generated method stub - return null; - } - - @Override - public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map details, - List hostTags) { - StartupCommand firstCmd = startup[0]; - if (!(firstCmd instanceof StartupRoutingCommand)) { - return null; - } - - StartupRoutingCommand ssCmd = ((StartupRoutingCommand) firstCmd); - if (ssCmd.getHypervisorType() != HypervisorType.BareMetal) { - return null; - } - - return _resourceMgr.fillRoutingHostVO(host, ssCmd, HypervisorType.BareMetal, details, hostTags); - } - - @Override - public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { - if (host.getType() != Host.Type.Routing || host.getHypervisorType() != HypervisorType.BareMetal) { - return null; - } - - List deadVms = _vmDao.listByLastHostId(host.getId()); - for (VMInstanceVO vm : deadVms) { - if (vm.getState() == State.Running || vm.getHostId() != null) { - throw new CloudRuntimeException("VM " + vm.getId() + "is still running on host " + host.getId()); - } - _vmDao.remove(vm.getId()); - } - - return new DeleteHostAnswer(true); - } - -} diff --git a/server/src/com/cloud/baremetal/BareMetalGuru.java b/server/src/com/cloud/baremetal/BareMetalGuru.java deleted file mode 100755 index 9268415b08d..00000000000 --- a/server/src/com/cloud/baremetal/BareMetalGuru.java +++ /dev/null @@ -1,59 +0,0 @@ -// 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.baremetal; - -import javax.ejb.Local; -import javax.inject.Inject; - -import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.hypervisor.HypervisorGuru; -import com.cloud.hypervisor.HypervisorGuruBase; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.storage.GuestOSVO; -import com.cloud.storage.dao.GuestOSDao; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineProfile; - -@Local(value=HypervisorGuru.class) -public class BareMetalGuru extends HypervisorGuruBase implements HypervisorGuru { - @Inject GuestOSDao _guestOsDao; - - protected BareMetalGuru() { - super(); - } - - @Override - public HypervisorType getHypervisorType() { - return HypervisorType.BareMetal; - } - - @Override - public VirtualMachineTO implement(VirtualMachineProfile vm) { - VirtualMachineTO to = toVirtualMachineTO(vm); - - // Determine the VM's OS description - GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine().getGuestOSId()); - to.setOs(guestOS.getDisplayName()); - - return to; - } - - @Override - public boolean trackVmHostChange() { - return true; - } -} diff --git a/server/src/com/cloud/baremetal/BareMetalPingServiceImpl.java b/server/src/com/cloud/baremetal/BareMetalPingServiceImpl.java deleted file mode 100755 index 3ccf29849b9..00000000000 --- a/server/src/com/cloud/baremetal/BareMetalPingServiceImpl.java +++ /dev/null @@ -1,199 +0,0 @@ -// 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.baremetal; - -import java.net.URI; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ejb.Local; -import javax.inject.Inject; - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.baremetal.PreparePxeServerAnswer; -import com.cloud.agent.api.baremetal.PreparePxeServerCommand; -import com.cloud.agent.api.baremetal.prepareCreateTemplateCommand; -import com.cloud.baremetal.PxeServerManager.PxeServerType; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.HostPodVO; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.resource.ResourceManager; -import com.cloud.resource.ServerResource; -import com.cloud.uservm.UserVm; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.NicProfile; -import com.cloud.vm.NicVO; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachineProfile; - -@Component -@Local(value=PxeServerService.class) -public class BareMetalPingServiceImpl extends BareMetalPxeServiceBase implements PxeServerService { - private static final Logger s_logger = Logger.getLogger(BareMetalPingServiceImpl.class); - @Inject ResourceManager _resourceMgr; - - @Override - public Host addPxeServer(PxeServerProfile profile) { - Long zoneId = profile.getZoneId(); - Long podId = profile.getPodId(); - - DataCenterVO zone = _dcDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId); - } - - List pxeServers = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.PxeServer, null, podId, zoneId); - if (pxeServers.size() != 0) { - InvalidParameterValueException ex = new InvalidParameterValueException("Already had a PXE server in Pod with specified podId and zone with specified zoneId"); - ex.addProxyObject("pod", podId, "podId"); - ex.addProxyObject(zone, zoneId, "zoneId"); - } - - - String ipAddress = profile.getUrl(); - String username = profile.getUsername(); - String password = profile.getPassword(); - - ServerResource resource = null; - Map params = new HashMap(); - params.put("type", PxeServerType.PING.getName()); - params.put("zone", Long.toString(zoneId)); - params.put("pod", podId.toString()); - params.put("ip", ipAddress); - params.put("username", username); - params.put("password", password); - if (profile.getType().equalsIgnoreCase(PxeServerType.PING.getName())) { - String storageServerIp = profile.getPingStorageServerIp(); - if (storageServerIp == null) { - throw new InvalidParameterValueException("No IP for storage server specified"); - } - String pingDir = profile.getPingDir(); - if (pingDir == null) { - throw new InvalidParameterValueException("No direcotry for storage server specified"); - } - String tftpDir = profile.getTftpDir(); - if (tftpDir == null) { - throw new InvalidParameterValueException("No TFTP directory specified"); - } - String cifsUsername = profile.getPingCifsUserName(); - if (cifsUsername == null || cifsUsername.equalsIgnoreCase("")) { - cifsUsername = "xxx"; - } - String cifsPassword = profile.getPingCifspassword(); - if (cifsPassword == null || cifsPassword.equalsIgnoreCase("")) { - cifsPassword = "xxx"; - } - String guid = getPxeServerGuid(Long.toString(zoneId) + "-" + Long.toString(podId), PxeServerType.PING.getName(), ipAddress); - - params.put("storageServer", storageServerIp); - params.put("pingDir", pingDir); - params.put("tftpDir", tftpDir); - params.put("cifsUserName", cifsUsername); - params.put("cifsPassword", cifsPassword); - params.put("guid", guid); - - resource = new PingPxeServerResource(); - try { - resource.configure("PING PXE resource", params); - } catch (Exception e) { - s_logger.debug(e); - throw new CloudRuntimeException(e.getMessage()); - } - - } else { - throw new CloudRuntimeException("Unsupport PXE server type:" + profile.getType()); - } - - Host pxeServer = _resourceMgr.addHost(zoneId, resource, Host.Type.PxeServer, params); - if (pxeServer == null) { - throw new CloudRuntimeException("Cannot add PXE server as a host"); - } - - return pxeServer; - } - - - @Override - public boolean prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId) { - List nics = profile.getNics(); - if (nics.size() == 0) { - throw new CloudRuntimeException("Cannot do PXE start without nic"); - } - - NicProfile pxeNic = nics.get(0); - String mac = pxeNic.getMacAddress(); - String ip = pxeNic.getIp4Address(); - String gateway = pxeNic.getGateway(); - String mask = pxeNic.getNetmask(); - String dns = pxeNic.getDns1(); - if (dns == null) { - dns = pxeNic.getDns2(); - } - - try { - String tpl = profile.getTemplate().getUrl(); - assert tpl != null : "How can a null template get here!!!"; - PreparePxeServerCommand cmd = new PreparePxeServerCommand(ip, mac, mask, gateway, dns, tpl, - profile.getVirtualMachine().getInstanceName(), dest.getHost().getName()); - PreparePxeServerAnswer ans = (PreparePxeServerAnswer) _agentMgr.send(pxeServerId, cmd); - return ans.getResult(); - } catch (Exception e) { - s_logger.warn("Cannot prepare PXE server", e); - return false; - } - } - - - @Override - public boolean prepareCreateTemplate(Long pxeServerId, UserVm vm, String templateUrl) { - List nics = _nicDao.listByVmId(vm.getId()); - if (nics.size() != 1) { - throw new CloudRuntimeException("Wrong nic number " + nics.size() + " of vm " + vm.getId()); - } - - /* use last host id when VM stopped */ - Long hostId = (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId()); - HostVO host = _hostDao.findById(hostId); - DataCenterVO dc = _dcDao.findById(host.getDataCenterId()); - NicVO nic = nics.get(0); - String mask = nic.getNetmask(); - String mac = nic.getMacAddress(); - String ip = nic.getIp4Address(); - String gateway = nic.getGateway(); - String dns = dc.getDns1(); - if (dns == null) { - dns = dc.getDns2(); - } - - try { - prepareCreateTemplateCommand cmd = new prepareCreateTemplateCommand(ip, mac, mask, gateway, dns, templateUrl); - Answer ans = _agentMgr.send(pxeServerId, cmd); - return ans.getResult(); - } catch (Exception e) { - s_logger.debug("Prepare for creating baremetal template failed", e); - return false; - } - } -} diff --git a/server/src/com/cloud/baremetal/BareMetalPxeServiceBase.java b/server/src/com/cloud/baremetal/BareMetalPxeServiceBase.java deleted file mode 100644 index 0df06509c25..00000000000 --- a/server/src/com/cloud/baremetal/BareMetalPxeServiceBase.java +++ /dev/null @@ -1,56 +0,0 @@ -// 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.baremetal; - -import java.util.Map; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import com.cloud.agent.AgentManager; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.dc.dao.HostPodDao; -import com.cloud.deploy.DeployDestination; -import com.cloud.host.Host; -import com.cloud.host.dao.HostDao; -import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.dao.NicDao; - -public abstract class BareMetalPxeServiceBase extends ManagerBase implements PxeServerService { - @Inject DataCenterDao _dcDao; - @Inject HostDao _hostDao; - @Inject AgentManager _agentMgr; - @Inject ExternalDhcpManager exDhcpMgr; - @Inject HostPodDao _podDao; - @Inject NicDao _nicDao; - - @Override - public boolean prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId) { - throw new CloudRuntimeException("Dervied class should implement this method"); - } - - protected String getPxeServerGuid(String zoneId, String name, String ip) { - return zoneId + "-" + name + "-" + ip; - } - - @Override - public abstract Host addPxeServer(PxeServerProfile profile); -} diff --git a/server/src/com/cloud/baremetal/BareMetalResourceBase.java b/server/src/com/cloud/baremetal/BareMetalResourceBase.java deleted file mode 100755 index 274cf077176..00000000000 --- a/server/src/com/cloud/baremetal/BareMetalResourceBase.java +++ /dev/null @@ -1,630 +0,0 @@ -// 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.baremetal; - -import java.util.HashMap; -import java.util.Map; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.IAgentControl; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.CheckNetworkAnswer; -import com.cloud.agent.api.CheckNetworkCommand; -import com.cloud.agent.api.CheckVirtualMachineAnswer; -import com.cloud.agent.api.CheckVirtualMachineCommand; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.MaintainAnswer; -import com.cloud.agent.api.MaintainCommand; -import com.cloud.agent.api.MigrateAnswer; -import com.cloud.agent.api.MigrateCommand; -import com.cloud.agent.api.PingCommand; -import com.cloud.agent.api.PingRoutingCommand; -import com.cloud.agent.api.PrepareForMigrationAnswer; -import com.cloud.agent.api.PrepareForMigrationCommand; -import com.cloud.agent.api.ReadyAnswer; -import com.cloud.agent.api.ReadyCommand; -import com.cloud.agent.api.RebootAnswer; -import com.cloud.agent.api.RebootCommand; -import com.cloud.agent.api.StartAnswer; -import com.cloud.agent.api.StartCommand; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupRoutingCommand; -import com.cloud.agent.api.StopAnswer; -import com.cloud.agent.api.StopCommand; -import com.cloud.agent.api.baremetal.IpmISetBootDevCommand; -import com.cloud.agent.api.baremetal.IpmISetBootDevCommand.BootDev; -import com.cloud.agent.api.baremetal.IpmiBootorResetCommand; -import com.cloud.agent.api.to.VirtualMachineTO; -import org.apache.cloudstack.api.ApiConstants; -import com.cloud.host.Host.Type; -import com.cloud.hypervisor.Hypervisor; -import com.cloud.resource.ServerResource; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.script.OutputInterpreter; -import com.cloud.utils.script.Script; -import com.cloud.utils.script.Script2; -import com.cloud.utils.script.Script2.ParamType; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachine.State; - -@Local(value = ServerResource.class) -public class BareMetalResourceBase implements ServerResource { - private static final Logger s_logger = Logger.getLogger(BareMetalResourceBase.class); - protected HashMap _vms = new HashMap(2); - protected String _name; - protected String _uuid; - protected String _zone; - protected String _pod; - protected String _cluster; - protected long _memCapacity; - protected long _cpuCapacity; - protected long _cpuNum; - protected String _mac; - protected String _username; - protected String _password; - protected String _ip; - protected IAgentControl _agentControl; - protected Script2 _pingCommand; - protected Script2 _setPxeBootCommand; - protected Script2 _setDiskBootCommand; - protected Script2 _rebootCommand; - protected Script2 _getStatusCommand; - protected Script2 _powerOnCommand; - protected Script2 _powerOffCommand; - protected Script2 _forcePowerOffCommand; - protected Script2 _bootOrRebootCommand; - protected String _vmName; - - private void changeVmState(String vmName, VirtualMachine.State state) { - synchronized (_vms) { - _vms.put(vmName, state); - } - } - - private State removeVmState(String vmName) { - synchronized (_vms) { - return _vms.remove(vmName); - } - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _name = name; - _uuid = (String) params.get("guid"); - try { - _memCapacity = Long.parseLong((String)params.get(ApiConstants.MEMORY)) * 1024L * 1024L; - _cpuCapacity = Long.parseLong((String)params.get(ApiConstants.CPU_SPEED)); - _cpuNum = Long.parseLong((String)params.get(ApiConstants.CPU_NUMBER)); - } catch (NumberFormatException e) { - throw new ConfigurationException(String.format("Unable to parse number of CPU or memory capacity " + - "or cpu capacity(cpu number = %1$s memCapacity=%2$s, cpuCapacity=%3$s", (String)params.get(ApiConstants.CPU_NUMBER), - (String)params.get(ApiConstants.MEMORY), (String)params.get(ApiConstants.CPU_SPEED))); - } - - _zone = (String) params.get("zone"); - _pod = (String) params.get("pod"); - _cluster = (String) params.get("cluster"); - _ip = (String)params.get(ApiConstants.PRIVATE_IP); - _mac = (String)params.get(ApiConstants.HOST_MAC); - _username = (String)params.get(ApiConstants.USERNAME); - _password = (String)params.get(ApiConstants.PASSWORD); - _vmName = (String)params.get("vmName"); - - if (_pod == null) { - throw new ConfigurationException("Unable to get the pod"); - } - - if (_cluster == null) { - throw new ConfigurationException("Unable to get the pod"); - } - - if (_ip == null) { - throw new ConfigurationException("Unable to get the host address"); - } - - if (_mac.equalsIgnoreCase("unknown")) { - throw new ConfigurationException("Unable to get the host mac address"); - } - - if (_mac.split(":").length != 6) { - throw new ConfigurationException("Wrong MAC format(" + _mac + "). It must be in format of for example 00:11:ba:33:aa:dd which is not case sensitive"); - } - - if (_uuid == null) { - throw new ConfigurationException("Unable to get the uuid"); - } - - String injectScript = "scripts/util/ipmi.py"; - String scriptPath = Script.findScript("", injectScript); - if (scriptPath == null) { - throw new ConfigurationException("Cannot find ping script " + scriptPath); - } - _pingCommand = new Script2(scriptPath, s_logger); - _pingCommand.add("ping"); - _pingCommand.add("hostname="+_ip); - _pingCommand.add("usrname="+_username); - _pingCommand.add("password="+_password, ParamType.PASSWORD); - - _setPxeBootCommand = new Script2(scriptPath, s_logger); - _setPxeBootCommand.add("boot_dev"); - _setPxeBootCommand.add("hostname="+_ip); - _setPxeBootCommand.add("usrname="+_username); - _setPxeBootCommand.add("password="+_password, ParamType.PASSWORD); - _setPxeBootCommand.add("dev=pxe"); - - _setDiskBootCommand = new Script2(scriptPath, s_logger); - _setDiskBootCommand.add("boot_dev"); - _setDiskBootCommand.add("hostname="+_ip); - _setDiskBootCommand.add("usrname="+_username); - _setDiskBootCommand.add("password="+_password, ParamType.PASSWORD); - _setDiskBootCommand.add("dev=disk"); - - _rebootCommand = new Script2(scriptPath, s_logger); - _rebootCommand.add("reboot"); - _rebootCommand.add("hostname="+_ip); - _rebootCommand.add("usrname="+_username); - _rebootCommand.add("password="+_password, ParamType.PASSWORD); - - _getStatusCommand = new Script2(scriptPath, s_logger); - _getStatusCommand.add("ping"); - _getStatusCommand.add("hostname="+_ip); - _getStatusCommand.add("usrname="+_username); - _getStatusCommand.add("password="+_password, ParamType.PASSWORD); - - _powerOnCommand = new Script2(scriptPath, s_logger); - _powerOnCommand.add("power"); - _powerOnCommand.add("hostname="+_ip); - _powerOnCommand.add("usrname="+_username); - _powerOnCommand.add("password="+_password, ParamType.PASSWORD); - _powerOnCommand.add("action=on"); - - _powerOffCommand = new Script2(scriptPath, s_logger); - _powerOffCommand.add("power"); - _powerOffCommand.add("hostname="+_ip); - _powerOffCommand.add("usrname="+_username); - _powerOffCommand.add("password="+_password, ParamType.PASSWORD); - _powerOffCommand.add("action=soft"); - - _forcePowerOffCommand = new Script2(scriptPath, s_logger); - _forcePowerOffCommand.add("power"); - _forcePowerOffCommand.add("hostname=" + _ip); - _forcePowerOffCommand.add("usrname=" + _username); - _forcePowerOffCommand.add("password=" + _password, ParamType.PASSWORD); - _forcePowerOffCommand.add("action=off"); - - _bootOrRebootCommand = new Script2(scriptPath, s_logger); - _bootOrRebootCommand.add("boot_or_reboot"); - _bootOrRebootCommand.add("hostname="+_ip); - _bootOrRebootCommand.add("usrname="+_username); - _bootOrRebootCommand.add("password="+_password, ParamType.PASSWORD); - - return true; - } - - protected boolean doScript(Script cmd) { - return doScript(cmd, null); - } - - protected boolean doScript(Script cmd, OutputInterpreter interpreter) { - int retry = 5; - String res = null; - while (retry-- > 0) { - if (interpreter == null) { - res = cmd.execute(); - } else { - res = cmd.execute(interpreter); - } - if (res != null && res.startsWith("Error: Unable to establish LAN")) { - s_logger.warn("IPMI script timeout(" + cmd.toString() + "), will retry " + retry + " times"); - continue; - } else if (res == null) { - return true; - } else { - break; - } - } - - s_logger.warn("IPMI Scirpt failed due to " + res + "(" + cmd.toString() +")"); - return false; - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - return true; - } - - @Override - public String getName() { - return _name; - } - - @Override - public Type getType() { - return com.cloud.host.Host.Type.Routing; - } - - protected State getVmState() { - OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser(); - if (!doScript(_getStatusCommand, interpreter)) { - s_logger.warn("Cannot get power status of " + _name + ", assume VM state was not changed"); - return null; - } - if (isPowerOn(interpreter.getLines())) { - return State.Running; - } else { - return State.Stopped; - } - } - - protected Map fullSync() { - Map changes = new HashMap(); - - if (_vmName != null) { - State state = getVmState(); - if (state != null) { - changes.put(_vmName, state); - } - } - - return changes; - } - - @Override - public StartupCommand[] initialize() { - StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.BareMetal, - new HashMap(), null); - cmd.setDataCenter(_zone); - cmd.setPod(_pod); - cmd.setCluster(_cluster); - cmd.setGuid(_uuid); - cmd.setName(_ip); - cmd.setPrivateIpAddress(_ip); - cmd.setStorageIpAddress(_ip); - cmd.setVersion(BareMetalResourceBase.class.getPackage().getImplementationVersion()); - cmd.setCpus((int)_cpuNum); - cmd.setSpeed(_cpuCapacity); - cmd.setMemory(_memCapacity); - cmd.setPrivateMacAddress(_mac); - cmd.setPublicMacAddress(_mac); - cmd.setStateChanges(fullSync()); - return new StartupCommand[] {cmd}; - } - - private boolean ipmiPing() { - return doScript(_pingCommand); - } - - @Override - public PingCommand getCurrentStatus(long id) { - try { - if (!ipmiPing()) { - Thread.sleep(1000); - if (!ipmiPing()) { - s_logger.warn("Cannot ping ipmi nic " + _ip); - return null; - } - } - } catch (Exception e) { - s_logger.debug("Cannot ping ipmi nic " + _ip, e); - return null; - } - - return new PingRoutingCommand(getType(), id, deltaSync()); - } - - protected Answer execute(IpmISetBootDevCommand cmd) { - Script bootCmd = null; - if (cmd.getBootDev() == BootDev.disk) { - bootCmd = _setDiskBootCommand; - } else if (cmd.getBootDev() == BootDev.pxe) { - bootCmd = _setPxeBootCommand; - } else { - throw new CloudRuntimeException("Unkonwn boot dev " + cmd.getBootDev()); - } - - String bootDev = cmd.getBootDev().name(); - if (!doScript(bootCmd)) { - s_logger.warn("Set " + _ip + " boot dev to " + bootDev + "failed"); - return new Answer(cmd, false, "Set " + _ip + " boot dev to " + bootDev + "failed"); - } - - s_logger.warn("Set " + _ip + " boot dev to " + bootDev + "Success"); - return new Answer(cmd, true, "Set " + _ip + " boot dev to " + bootDev + "Success"); - } - - protected MaintainAnswer execute(MaintainCommand cmd) { - return new MaintainAnswer(cmd, false); - } - - protected PrepareForMigrationAnswer execute(PrepareForMigrationCommand cmd) { - return new PrepareForMigrationAnswer(cmd); - } - - protected MigrateAnswer execute(MigrateCommand cmd) { - if (!doScript(_powerOffCommand)) { - return new MigrateAnswer(cmd, false, "IPMI power off failed", null); - } - return new MigrateAnswer(cmd, true, "success", null); - } - - protected CheckVirtualMachineAnswer execute(final CheckVirtualMachineCommand cmd) { - return new CheckVirtualMachineAnswer(cmd, State.Stopped, null); - } - - protected Answer execute(IpmiBootorResetCommand cmd) { - if (!doScript(_bootOrRebootCommand)) { - return new Answer(cmd ,false, "IPMI boot or reboot failed"); - } - return new Answer(cmd, true, "Success"); - - } - - protected CheckNetworkAnswer execute(CheckNetworkCommand cmd) { - return new CheckNetworkAnswer(cmd, true, "Success"); - } - - @Override - public Answer executeRequest(Command cmd) { - if (cmd instanceof ReadyCommand) { - return execute((ReadyCommand)cmd); - } else if (cmd instanceof StartCommand) { - return execute((StartCommand)cmd); - } else if (cmd instanceof StopCommand) { - return execute((StopCommand)cmd); - } else if (cmd instanceof RebootCommand) { - return execute((RebootCommand)cmd); - } else if (cmd instanceof IpmISetBootDevCommand) { - return execute((IpmISetBootDevCommand)cmd); - } else if (cmd instanceof MaintainCommand) { - return execute((MaintainCommand)cmd); - } else if (cmd instanceof PrepareForMigrationCommand) { - return execute((PrepareForMigrationCommand)cmd); - } else if (cmd instanceof MigrateCommand) { - return execute((MigrateCommand)cmd); - } else if (cmd instanceof CheckVirtualMachineCommand) { - return execute((CheckVirtualMachineCommand)cmd); - } else if (cmd instanceof IpmiBootorResetCommand) { - return execute((IpmiBootorResetCommand)cmd); - } else if (cmd instanceof CheckNetworkCommand) { - return execute((CheckNetworkCommand)cmd); - } else { - return Answer.createUnsupportedCommandAnswer(cmd); - } - } - - protected boolean isPowerOn(String str) { - if (str.startsWith("Chassis Power is on")) { - return true; - } else if (str.startsWith("Chassis Power is off")) { - return false; - } else { - throw new CloudRuntimeException("Cannot parse IPMI power status " + str); - } - } - - protected RebootAnswer execute(final RebootCommand cmd) { - if (!doScript(_rebootCommand)) { - return new RebootAnswer(cmd, "IPMI reboot failed", false); - } - - return new RebootAnswer(cmd, "reboot succeeded", true); - } - - protected StopAnswer execute(final StopCommand cmd) { - boolean success = false; - int count = 0; - Script powerOff = _powerOffCommand; - - while (count < 10) { - if (!doScript(powerOff)) { - break; - } - - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - break; - } - - OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser(); - if (!doScript(_getStatusCommand, interpreter)) { - s_logger.warn("Cannot get power status of " + _name + ", assume VM state was not changed"); - break; - } - - if (!isPowerOn(interpreter.getLines())) { - success = true; - break; - } else { - powerOff = _forcePowerOffCommand; - } - - count++; - } - - return success ? new StopAnswer(cmd, "Success", null, true) : new StopAnswer(cmd, "IPMI power off failed", false); - } - - protected StartAnswer execute(StartCommand cmd) { - VirtualMachineTO vm = cmd.getVirtualMachine(); - State state = State.Stopped; - - try { - changeVmState(vm.getName(), State.Starting); - - boolean pxeBoot = false; - String[] bootArgs = vm.getBootArgs().split(" "); - for (int i = 0; i < bootArgs.length; i++) { - if (bootArgs[i].equalsIgnoreCase("PxeBoot")) { - pxeBoot = true; - break; - } - } - - if (pxeBoot) { - if (!doScript(_setPxeBootCommand)) { - return new StartAnswer(cmd, "Set boot device to PXE failed"); - } - s_logger.debug("Set " + vm.getHostName() + " to PXE boot successfully"); - } else { - execute(new IpmISetBootDevCommand(BootDev.disk)); - } - - OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser(); - if (!doScript(_getStatusCommand, interpreter)) { - return new StartAnswer(cmd, "Cannot get current power status of " + _name); - } - - if (isPowerOn(interpreter.getLines())) { - if (pxeBoot) { - if (!doScript(_rebootCommand)) { - return new StartAnswer(cmd, "IPMI reboot failed"); - } - s_logger.debug("IPMI reboot " + vm.getHostName() + " successfully"); - } else { - s_logger.warn("Machine " + _name + " is alreay power on, why we still get a Start command? ignore it"); - - } - } else { - if (!doScript(_powerOnCommand)) { - return new StartAnswer(cmd, "IPMI power on failed"); - } - } - - s_logger.debug("Start bare metal vm " + vm.getName() + "successfully"); - state = State.Running; - _vmName = vm.getName(); - return new StartAnswer(cmd); - } finally { - if (state != State.Stopped) { - changeVmState(vm.getName(), state); - } else { - removeVmState(vm.getName()); - } - } - } - - protected HashMap deltaSync() { - final HashMap changes = new HashMap(); - /* - * Disable sync until we find a way that only tracks status but not does action - * - * The scenario is: Baremetal will reboot host when creating template. Given most - * servers take a long time to boot up, there would be a period that mgmt server finds - * the host is stopped through fullsync. Then mgmt server updates database with marking the host as - * stopped, after that, the host comes up and full sync then indicates it's running. Because - * in database the host is already stopped, mgmt server sends out a stop command. - * As a result, creating image gets never happened. - * - if (_vmName == null) { - return null; - } - - State newState = getVmState(); - if (newState == null) { - s_logger.warn("Cannot get power state of VM " + _vmName); - return null; - } - - final State oldState = removeVmState(_vmName); - if (oldState == null) { - changeVmState(_vmName, newState); - changes.put(_vmName, newState); - } else if (oldState == State.Starting) { - if (newState == State.Running) { - changeVmState(_vmName, newState); - } else if (newState == State.Stopped) { - s_logger.debug("Ignoring vm " + _vmName + " because of a lag in starting the vm."); - } - } else if (oldState == State.Migrating) { - s_logger.warn("How can baremetal VM get into migrating state???"); - } else if (oldState == State.Stopping) { - if (newState == State.Stopped) { - changeVmState(_vmName, newState); - } else if (newState == State.Running) { - s_logger.debug("Ignoring vm " + _vmName + " because of a lag in stopping the vm. "); - } - } else if (oldState != newState) { - changeVmState(_vmName, newState); - changes.put(_vmName, newState); - } - */ - return changes; - - } - - protected ReadyAnswer execute(ReadyCommand cmd) { - // derived resource should check if the PXE server is ready - s_logger.debug("Bare metal resource " + _name + " is ready"); - return new ReadyAnswer(cmd); - } - - @Override - public void disconnected() { - - } - - @Override - public IAgentControl getAgentControl() { - return _agentControl; - } - - @Override - public void setAgentControl(IAgentControl agentControl) { - _agentControl = agentControl; - } - - @Override - public void setName(String name) { - // TODO Auto-generated method stub - - } - - @Override - public void setConfigParams(Map params) { - // TODO Auto-generated method stub - - } - - @Override - public Map getConfigParams() { - // TODO Auto-generated method stub - return null; - } - - @Override - public int getRunLevel() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public void setRunLevel(int level) { - // TODO Auto-generated method stub - - } - -} diff --git a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java index 33ab4684a63..d902dc4dbfd 100755 --- a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java +++ b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java @@ -37,10 +37,10 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.resource.ResourceManager; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.TemplateProfile; +import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.template.TemplateAdapter; import com.cloud.template.TemplateAdapterBase; @@ -54,6 +54,11 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem @Inject HostDao _hostDao; @Inject ResourceManager _resourceMgr; + @Override + public String getName() { + return TemplateAdapterType.BareMetal.getName(); + } + @Override public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException { TemplateProfile profile = super.prepare(cmd); diff --git a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java b/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java deleted file mode 100755 index 8e447bc9aa6..00000000000 --- a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java +++ /dev/null @@ -1,551 +0,0 @@ -// 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.baremetal; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; - -import javax.annotation.PostConstruct; -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; -import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; -import org.apache.log4j.Logger; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.StopAnswer; -import com.cloud.agent.api.baremetal.IpmISetBootDevCommand; -import com.cloud.agent.api.baremetal.IpmiBootorResetCommand; -import com.cloud.agent.manager.Commands; -import org.apache.cloudstack.api.command.user.vm.StartVMCmd; - -import com.cloud.baremetal.PxeServerManager.PxeServerType; -import com.cloud.configuration.Resource.ResourceType; -import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.dc.DataCenterVO; -import com.cloud.deploy.DataCenterDeployment; -import com.cloud.deploy.DeployDestination; -import com.cloud.domain.DomainVO; -import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventUtils; -import com.cloud.exception.*; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.Network; -import com.cloud.network.Networks.TrafficType; -import com.cloud.network.dao.NetworkVO; -import com.cloud.org.Grouping; -import com.cloud.resource.ResourceManager; -import com.cloud.service.ServiceOfferingVO; -import com.cloud.storage.Storage; -import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.TemplateProfile; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.Volume; -import com.cloud.template.TemplateAdapter; -import com.cloud.template.TemplateAdapter.TemplateAdapterType; -import com.cloud.user.Account; -import com.cloud.user.AccountVO; -import com.cloud.user.SSHKeyPair; -import com.cloud.user.User; -import com.cloud.user.UserContext; -import com.cloud.user.*; -import com.cloud.uservm.UserVm; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.Pair; -import com.cloud.utils.component.AdapterBase; -import com.cloud.utils.component.Manager; -import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.DB; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.fsm.StateListener; -import com.cloud.utils.net.NetUtils; -import com.cloud.vm.*; -import com.cloud.vm.VirtualMachine.Event; -import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.VirtualMachine.Type; -import com.cloud.vm.VirtualMachineProfile.Param; - -@Local(value={BareMetalVmManager.class, BareMetalVmService.class}) -public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMetalVmManager, BareMetalVmService, - StateListener { - private static final Logger s_logger = Logger.getLogger(BareMetalVmManagerImpl.class); - @Inject ConfigurationDao _configDao; - @Inject PxeServerManager _pxeMgr; - @Inject ResourceManager _resourceMgr; - - @Inject protected List _adapters; - - @PostConstruct - public void init() { - } - - @Override - public boolean attachISOToVM(long vmId, long isoId, boolean attach) { - s_logger.warn("attachISOToVM is not supported by Bare Metal, just fake a true"); - return true; - } - - @Override - public Volume attachVolumeToVM(AttachVolumeCmd command) { - s_logger.warn("attachVolumeToVM is not supported by Bare Metal, return null"); - return null; - } - - @Override - public Volume detachVolumeFromVM(DetachVolumeCmd cmd) { - s_logger.warn("detachVolumeFromVM is not supported by Bare Metal, return null"); - return null; - } - - @Override - public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) { - s_logger.warn("upgradeVirtualMachine is not supported by Bare Metal, return null"); - return null; - } - - @Override - public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { - /*Baremetal creates record after host rebooting for imaging, in createPrivateTemplate*/ - return null; - } - - @Override @DB - public VMTemplateVO createPrivateTemplate(CreateTemplateCmd cmd) throws CloudRuntimeException { - Long vmId = cmd.getVmId(); - if (vmId == null) { - throw new InvalidParameterValueException("VM ID is null"); - } - - UserVmVO vm = _vmDao.findById(vmId); - if (vm == null) { - throw new InvalidParameterValueException("Cannot find VM for ID " + vmId); - } - - Long hostId = (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId()); - HostVO host = _hostDao.findById(hostId); - if (host == null) { - throw new InvalidParameterValueException("Cannot find host with id " + hostId); - } - - List pxes = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.PxeServer, null, host.getPodId(), host.getDataCenterId()); - if (pxes.size() == 0) { - throw new CloudRuntimeException("Please add PXE server in Pod before taking image"); - } - - if (pxes.size() > 1) { - CloudRuntimeException ex = new CloudRuntimeException("Multiple PXE servers found in Pod " + host.getPodId() + " in Zone with specified id"); - ex.addProxyObject("data_center", host.getDataCenterId(), "zoneId"); - throw ex; - } - - HostVO pxe = pxes.get(0); - /* - * prepare() will check if current account has right for creating - * template - */ - TemplateAdapter adapter = AdapterBase.getAdapterByName(_adapters, TemplateAdapterType.BareMetal.getName()); - Long userId = UserContext.current().getCallerUserId(); - userId = (userId == null ? User.UID_SYSTEM : userId); - AccountVO account = _accountDao.findById(vm.getAccountId()); - - try { - TemplateProfile tmplProfile; - tmplProfile = adapter.prepare(false, userId, cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), false, false, cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), false, - "BareMetal", cmd.getOsTypeId(), pxe.getDataCenterId(), HypervisorType.BareMetal, account.getAccountName(), account.getDomainId(), "0", true, cmd.getDetails()); - - if (!_pxeMgr.prepareCreateTemplate(_pxeMgr.getPxeServerType(pxe), pxe.getId(), vm, cmd.getUrl())) { - throw new Exception("Prepare PXE boot file for host " + hostId + " failed"); - } - - IpmISetBootDevCommand setBootDev = new IpmISetBootDevCommand(IpmISetBootDevCommand.BootDev.pxe); - Answer ans = _agentMgr.send(hostId, setBootDev); - if (!ans.getResult()) { - throw new Exception("Set host " + hostId + " to PXE boot failed"); - } - - IpmiBootorResetCommand boot = new IpmiBootorResetCommand(); - ans = _agentMgr.send(hostId, boot); - if (!ans.getResult()) { - throw new Exception("Boot/Reboot host " + hostId + " failed"); - } - - VMTemplateVO tmpl = adapter.create(tmplProfile); - s_logger.debug("Create baremetal template for host " + hostId + " successfully, template id:" + tmpl.getId()); - return tmpl; - } catch (Exception e) { - s_logger.debug("Create baremetal tempalte for host " + hostId + " failed", e); - throw new CloudRuntimeException(e.getMessage()); - } - } - - @Override - public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, - StorageUnavailableException, ResourceAllocationException { - Account caller = UserContext.current().getCaller(); - - String accountName = cmd.getAccountName(); - Long domainId = cmd.getDomainId(); - List networkList = cmd.getNetworkIds(); - String group = cmd.getGroup(); - - Account owner = _accountDao.findActiveAccount(accountName, domainId); - if (owner == null) { - throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId); - } - - _accountMgr.checkAccess(caller, null, true, owner); - long accountId = owner.getId(); - - DataCenterVO dc = _dcDao.findById(cmd.getZoneId()); - if (dc == null) { - throw new InvalidParameterValueException("Unable to find zone: " + cmd.getZoneId()); - } - - if(Grouping.AllocationState.Disabled == dc.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())){ - throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: "+ cmd.getZoneId() ); - } - - if (dc.getDomainId() != null) { - DomainVO domain = _domainDao.findById(dc.getDomainId()); - if (domain == null) { - throw new CloudRuntimeException("Unable to find the domain " + dc.getDomainId() + " for the zone: " + dc); - } - _configMgr.checkZoneAccess(caller, dc); - _configMgr.checkZoneAccess(owner, dc); - } - - // check if account/domain is with in resource limits to create a new vm - _resourceLimitMgr.checkResourceLimit(owner, ResourceType.user_vm); - - ServiceOfferingVO offering = _serviceOfferingDao.findById(cmd.getServiceOfferingId()); - if (offering == null || offering.getRemoved() != null) { - throw new InvalidParameterValueException("Unable to find service offering: " + cmd.getServiceOfferingId()); - } - - VMTemplateVO template = _templateDao.findById(cmd.getTemplateId()); - // Make sure a valid template ID was specified - if (template == null || template.getRemoved() != null) { - throw new InvalidParameterValueException("Unable to use template " + cmd.getTemplateId()); - } - - if (template.getTemplateType().equals(TemplateType.SYSTEM)) { - throw new InvalidParameterValueException("Unable to use system template " + cmd.getTemplateId()+" to deploy a user vm"); - } - - if (template.getFormat() != Storage.ImageFormat.BAREMETAL) { - throw new InvalidParameterValueException("Unable to use non Bare Metal template" + cmd.getTemplateId() +" to deploy a bare metal vm"); - } - - String userData = cmd.getUserData(); - byte [] decodedUserData = null; - if (userData != null) { - if (userData.length() >= 2 * MAX_USER_DATA_LENGTH_BYTES) { - throw new InvalidParameterValueException("User data is too long"); - } - decodedUserData = org.apache.commons.codec.binary.Base64.decodeBase64(userData.getBytes()); - if (decodedUserData.length > MAX_USER_DATA_LENGTH_BYTES){ - throw new InvalidParameterValueException("User data is too long"); - } - if (decodedUserData.length < 1) { - throw new InvalidParameterValueException("User data is too short"); - } - } - - // Find an SSH public key corresponding to the key pair name, if one is given - String sshPublicKey = null; - if (cmd.getSSHKeyPairName() != null && !cmd.getSSHKeyPairName().equals("")) { - Account account = UserContext.current().getCaller(); - SSHKeyPair pair = _sshKeyPairDao.findByName(account.getAccountId(), account.getDomainId(), cmd.getSSHKeyPairName()); - if (pair == null) { - throw new InvalidParameterValueException("A key pair with name '" + cmd.getSSHKeyPairName() + "' was not found."); - } - - sshPublicKey = pair.getPublicKey(); - } - - _accountMgr.checkAccess(caller, null, true, template); - - DataCenterDeployment plan = new DataCenterDeployment(dc.getId()); - - s_logger.debug("Allocating in the DB for bare metal vm"); - - if (dc.getNetworkType() != NetworkType.Basic || networkList != null) { - s_logger.warn("Bare Metal only supports basical network mode now, switch to baisc network automatically"); - } - - Network defaultNetwork = _networkModel.getExclusiveGuestNetwork(dc.getId()); - if (defaultNetwork == null) { - throw new InvalidParameterValueException("Unable to find a default network to start a vm"); - } - - - networkList = new ArrayList(); - networkList.add(defaultNetwork.getId()); - - List> networks = new ArrayList>(); - for (Long networkId : networkList) { - NetworkVO network = _networkDao.findById(networkId); - if (network == null) { - throw new InvalidParameterValueException("Unable to find network by id " + networkId); - } else { - if (network.getGuestType() != Network.GuestType.Shared) { - //Check account permissions - List networkMap = _networkDao.listBy(accountId, networkId); - if (networkMap == null || networkMap.isEmpty()) { - throw new PermissionDeniedException("Unable to create a vm using network with id " + networkId + ", permission denied"); - } - } - networks.add(new Pair(network, null)); - } - } - - long id = _vmDao.getNextInSequence(Long.class, "id"); - - String hostName = cmd.getName(); - String instanceName = VirtualMachineName.getVmName(id, owner.getId(), _instance); - if (hostName == null) { - hostName = instanceName; - } else { - //verify hostName (hostname doesn't have to be unique) - if (!NetUtils.verifyDomainNameLabel(hostName, true)) { - throw new InvalidParameterValueException("Invalid name. Vm name can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + - "and the hyphen ('-'), must be between 1 and 63 characters long, and can't start or end with \"-\" and can't start with digit"); - } - } - - UserVmVO vm = new UserVmVO(id, instanceName, cmd.getDisplayName(), template.getId(), HypervisorType.BareMetal, - template.getGuestOSId(), offering.getOfferHA(), false, domainId, owner.getId(), offering.getId(), userData, hostName, null); - - if (sshPublicKey != null) { - vm.setDetail("SSH.PublicKey", sshPublicKey); - } - - if (_itMgr.allocate(vm, template, offering, null, null, networks, null, plan, cmd.getHypervisor(), owner) == null) { - return null; - } - - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Successfully allocated DB entry for " + vm); - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Successfully allocated DB entry for " + vm); - } - UserContext.current().setEventDetails("Vm Id: " + vm.getId()); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, cmd.getZoneId(), vm.getId(), - vm.getHostName(), offering.getId(), template.getId(), HypervisorType.BareMetal.toString(), - VirtualMachine.class.getName(), vm.getUuid()); - - _resourceLimitMgr.incrementResourceCount(accountId, ResourceType.user_vm); - - // Assign instance to the group - try { - if (group != null) { - boolean addToGroup = addInstanceToGroup(Long.valueOf(id), group); - if (!addToGroup) { - throw new CloudRuntimeException("Unable to assign Vm to the group " + group); - } - } - } catch (Exception ex) { - throw new CloudRuntimeException("Unable to assign Vm to the group " + group); - } - - return vm; - } - - public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { - UserVmVO vm = _vmDao.findById(cmd.getInstanceId()); - - List servers = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByType(Host.Type.PxeServer, vm.getDataCenterId()); - if (servers.size() == 0) { - throw new CloudRuntimeException("Cannot find PXE server, please make sure there is one PXE server per zone"); - } - HostVO pxeServer = servers.get(0); - - VMTemplateVO template = _templateDao.findById(vm.getTemplateId()); - if (template == null || template.getFormat() != Storage.ImageFormat.BAREMETAL) { - throw new InvalidParameterValueException("Invalid template with id = " + vm.getTemplateId()); - } - - Map params = new HashMap(); - params.put(Param.PxeSeverType, _pxeMgr.getPxeServerType(pxeServer)); - - return startVirtualMachine(cmd, params); - } - - - public UserVm startVirtualMachine(StartVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { - UserVmVO vm = _vmDao.findById(cmd.getInstanceId()); - - VMTemplateVO template = _templateDao.findById(vm.getTemplateId()); - if (template == null || template.getFormat() != Storage.ImageFormat.BAREMETAL) { - throw new InvalidParameterValueException("Invalid template with id = " + vm.getTemplateId()); - } - - Map params = null; - if (vm.isUpdateParameters()) { - List servers = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByType(Host.Type.PxeServer, vm.getDataCenterId()); - if (servers.size() == 0) { - throw new CloudRuntimeException("Cannot find PXE server, please make sure there is one PXE server per zone"); - } - HostVO pxeServer = servers.get(0); - params = new HashMap(); - params.put(Param.PxeSeverType, _pxeMgr.getPxeServerType(pxeServer)); - } - - Pair> vmDetailsPair = super.startVirtualMachine(vm.getId(), cmd.getHostId(), params); - return vmDetailsPair.first(); - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _name = name; - - Map configs = _configDao.getConfiguration("AgentManager", params); - - _instance = configs.get("instance.name"); - if (_instance == null) { - _instance = "DEFAULT"; - } - - String workers = configs.get("expunge.workers"); - int wrks = NumbersUtil.parseInt(workers, 10); - - String time = configs.get("expunge.interval"); - _expungeInterval = NumbersUtil.parseInt(time, 86400); - - time = configs.get("expunge.delay"); - _expungeDelay = NumbersUtil.parseInt(time, _expungeInterval); - - _executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("UserVm-Scavenger")); - - _itMgr.registerGuru(Type.UserBareMetal, this); - VirtualMachine.State.getStateMachine().registerListener(this); - - s_logger.info("User VM Manager is configured."); - - return true; - } - - @Override - public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { - UserVmVO vm = profile.getVirtualMachine(); - Account owner = _accountDao.findById(vm.getAccountId()); - - if (owner == null || owner.getState() == Account.State.disabled) { - throw new PermissionDeniedException("The owner of " + vm + " either does not exist or is disabled: " + vm.getAccountId()); - } - - PxeServerType pxeType = (PxeServerType) profile.getParameter(Param.PxeSeverType); - if (pxeType == null) { - s_logger.debug("This is a normal IPMI start, skip prepartion of PXE server"); - return true; - } - s_logger.debug("This is a PXE start, prepare PXE server first"); - - List servers = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.PxeServer, null, dest.getPod().getId(), dest.getDataCenter().getId()); - if (servers.size() == 0) { - throw new CloudRuntimeException("Cannot find PXE server, please make sure there is one PXE server per zone"); - } - if (servers.size() > 1) { - throw new CloudRuntimeException("Find more than one PXE server, please make sure there is only one PXE server per zone in pod " + dest.getPod().getId() + " zone " + dest.getDataCenter().getId()); - } - HostVO pxeServer = servers.get(0); - - if (!_pxeMgr.prepare(pxeType, profile, dest, context, pxeServer.getId())) { - throw new CloudRuntimeException("Pepare PXE server failed"); - } - - profile.addBootArgs("PxeBoot"); - - return true; - } - - @Override - public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { - UserVmVO userVm = profile.getVirtualMachine(); - List nics = _nicDao.listByVmId(userVm.getId()); - for (NicVO nic : nics) { - NetworkVO network = _networkDao.findById(nic.getNetworkId()); - if (network.getTrafficType() == TrafficType.Guest) { - userVm.setPrivateIpAddress(nic.getIp4Address()); - userVm.setPrivateMacAddress(nic.getMacAddress()); - } - } - _vmDao.update(userVm.getId(), userVm); - return true; - } - - @Override - public void finalizeStop(VirtualMachineProfile profile, StopAnswer answer) { - super.finalizeStop(profile, answer); - } - - @Override - public UserVm destroyVm(long vmId) throws ResourceUnavailableException, ConcurrentOperationException { - return super.destroyVm(vmId); - } - - @Override - public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { - return true; - } - - @Override - public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { - if (newState != State.Starting && newState != State.Error && newState != State.Expunging) { - return true; - } - - if (vo.getHypervisorType() != HypervisorType.BareMetal) { - return true; - } - - HostVO host = _hostDao.findById(vo.getHostId()); - if (host == null) { - s_logger.debug("Skip oldState " + oldState + " to " + "newState " + newState + " transimtion"); - return true; - } - _hostDao.loadDetails(host); - - if (newState == State.Starting) { - host.setDetail("vmName", vo.getInstanceName()); - s_logger.debug("Add vmName " + host.getDetail("vmName") + " to host " + host.getId() + " details"); - } else { - if (host.getDetail("vmName") != null && host.getDetail("vmName").equalsIgnoreCase(vo.getInstanceName())) { - s_logger.debug("Remove vmName " + host.getDetail("vmName") + " from host " + host.getId() + " details"); - host.getDetails().remove("vmName"); - } - } - _hostDao.saveDetails(host); - - - return true; - } -} diff --git a/server/src/com/cloud/baremetal/DhcpdResource.java b/server/src/com/cloud/baremetal/DhcpdResource.java deleted file mode 100755 index 436d27598f8..00000000000 --- a/server/src/com/cloud/baremetal/DhcpdResource.java +++ /dev/null @@ -1,133 +0,0 @@ -// 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.baremetal; - -import java.util.HashMap; -import java.util.Map; - -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.PingCommand; -import com.cloud.agent.api.PingRoutingCommand; -import com.cloud.agent.api.routing.DhcpEntryCommand; -import com.cloud.utils.script.Script; -import com.cloud.utils.ssh.SSHCmdHelper; -import com.cloud.vm.VirtualMachine.State; -import com.trilead.ssh2.SCPClient; - -public class DhcpdResource extends ExternalDhcpResourceBase { - private static final Logger s_logger = Logger.getLogger(DhcpdResource.class); - - public boolean configure(String name, Map params) throws ConfigurationException { - com.trilead.ssh2.Connection sshConnection = null; - try { - super.configure(name, params); - s_logger.debug(String.format("Trying to connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s)", _ip, _username, "******")); - sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password); - if (sshConnection == null) { - throw new ConfigurationException( - String.format("Cannot connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, "******")); - } - - if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "[ -f '/usr/sbin/dhcpd' ]")) { - throw new ConfigurationException("Cannot find dhcpd.conf /etc/dhcpd.conf at on " + _ip); - } - - SCPClient scp = new SCPClient(sshConnection); - - String editHosts = "scripts/network/exdhcp/dhcpd_edithosts.py"; - String editHostsPath = Script.findScript("", editHosts); - if (editHostsPath == null) { - throw new ConfigurationException("Can not find script dnsmasq_edithosts.sh at " + editHosts); - } - scp.put(editHostsPath, "/usr/bin/", "0755"); - - String prepareDhcpdScript = "scripts/network/exdhcp/prepare_dhcpd.sh"; - String prepareDhcpdScriptPath = Script.findScript("", prepareDhcpdScript); - if (prepareDhcpdScriptPath == null) { - throw new ConfigurationException("Can not find prepare_dhcpd.sh at " + prepareDhcpdScriptPath); - } - scp.put(prepareDhcpdScriptPath, "/usr/bin/", "0755"); - - //TODO: tooooooooooooooo ugly here!!! - String[] ips = _ip.split("\\."); - ips[3] = "0"; - StringBuffer buf = new StringBuffer(); - int i; - for (i=0;i()); - } - } - - Answer execute(DhcpEntryCommand cmd) { - com.trilead.ssh2.Connection sshConnection = null; - try { - sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password); - if (sshConnection == null) { - return new Answer(cmd, false, "ssh authenticate failed"); - } - String addDhcp = String.format("python /usr/bin/dhcpd_edithosts.py %1$s %2$s %3$s %4$s %5$s %6$s", - cmd.getVmMac(), cmd.getVmIpAddress(), cmd.getVmName(), cmd.getDns(), cmd.getGateway(), cmd.getNextServer()); - if (!SSHCmdHelper.sshExecuteCmd(sshConnection, addDhcp)) { - return new Answer(cmd, false, "add Dhcp entry failed"); - } else { - return new Answer(cmd); - } - } finally { - SSHCmdHelper.releaseSshConnection(sshConnection); - } - } - - @Override - public Answer executeRequest(Command cmd) { - if (cmd instanceof DhcpEntryCommand) { - return execute((DhcpEntryCommand)cmd); - } else { - return super.executeRequest(cmd); - } - } -} diff --git a/server/src/com/cloud/baremetal/DnsmasqResource.java b/server/src/com/cloud/baremetal/DnsmasqResource.java deleted file mode 100644 index 1001dfc5c12..00000000000 --- a/server/src/com/cloud/baremetal/DnsmasqResource.java +++ /dev/null @@ -1,123 +0,0 @@ -// 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.baremetal; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.PingCommand; -import com.cloud.agent.api.PingRoutingCommand; -import com.cloud.agent.api.routing.DhcpEntryCommand; -import com.cloud.utils.script.Script; -import com.cloud.utils.ssh.SSHCmdHelper; -import com.cloud.vm.VirtualMachine.State; -import com.trilead.ssh2.SCPClient; - -public class DnsmasqResource extends ExternalDhcpResourceBase { - private static final Logger s_logger = Logger.getLogger(DnsmasqResource.class); - - public boolean configure(String name, Map params) throws ConfigurationException { - com.trilead.ssh2.Connection sshConnection = null; - try { - super.configure(name, params); - s_logger.debug(String.format("Trying to connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s)", _ip, _username, _password)); - sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password); - if (sshConnection == null) { - throw new ConfigurationException( - String.format("Cannot connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); - } - - if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "[ -f '/usr/sbin/dnsmasq' ]")) { - throw new ConfigurationException("Cannot find dnsmasq at /usr/sbin/dnsmasq on " + _ip); - } - - SCPClient scp = new SCPClient(sshConnection); - - String editHosts = "scripts/network/exdhcp/dnsmasq_edithosts.sh"; - String editHostsPath = Script.findScript("", editHosts); - if (editHostsPath == null) { - throw new ConfigurationException("Can not find script dnsmasq_edithosts.sh at " + editHosts); - } - scp.put(editHostsPath, "/usr/bin/", "0755"); - - String prepareDnsmasq = "scripts/network/exdhcp/prepare_dnsmasq.sh"; - String prepareDnsmasqPath = Script.findScript("", prepareDnsmasq); - if (prepareDnsmasqPath == null) { - throw new ConfigurationException("Can not find script prepare_dnsmasq.sh at " + prepareDnsmasq); - } - scp.put(prepareDnsmasqPath, "/usr/bin/", "0755"); - - String prepareCmd = String.format("sh /usr/bin/prepare_dnsmasq.sh %1$s %2$s %3$s", _gateway, _dns, _ip); - if (!SSHCmdHelper.sshExecuteCmd(sshConnection, prepareCmd)) { - throw new ConfigurationException("prepare dnsmasq at " + _ip + " failed"); - } - - s_logger.debug("Dnsmasq resource configure successfully"); - return true; - } catch (Exception e) { - s_logger.debug("Dnsmasq resorce configure failed", e); - throw new ConfigurationException(e.getMessage()); - } finally { - SSHCmdHelper.releaseSshConnection(sshConnection); - } - } - - @Override - public PingCommand getCurrentStatus(long id) { - com.trilead.ssh2.Connection sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password); - if (sshConnection == null) { - return null; - } else { - SSHCmdHelper.releaseSshConnection(sshConnection); - return new PingRoutingCommand(getType(), id, new HashMap()); - } - } - - Answer execute(DhcpEntryCommand cmd) { - com.trilead.ssh2.Connection sshConnection = null; - try { - sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password); - if (sshConnection == null) { - return new Answer(cmd, false, "ssh authenticate failed"); - } - String addDhcp = String.format("/usr/bin/dnsmasq_edithosts.sh %1$s %2$s %3$s", cmd.getVmMac(), cmd.getVmIpAddress(), cmd.getVmName()); - if (!SSHCmdHelper.sshExecuteCmd(sshConnection, addDhcp)) { - return new Answer(cmd, false, "add Dhcp entry failed"); - } else { - return new Answer(cmd); - } - } finally { - SSHCmdHelper.releaseSshConnection(sshConnection); - } - } - - @Override - public Answer executeRequest(Command cmd) { - if (cmd instanceof DhcpEntryCommand) { - return execute((DhcpEntryCommand)cmd); - } else { - return super.executeRequest(cmd); - } - } -} diff --git a/server/src/com/cloud/baremetal/ExternalDhcpEntryListener.java b/server/src/com/cloud/baremetal/ExternalDhcpEntryListener.java deleted file mode 100644 index d27d7972139..00000000000 --- a/server/src/com/cloud/baremetal/ExternalDhcpEntryListener.java +++ /dev/null @@ -1,44 +0,0 @@ -// 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.baremetal; - -public interface ExternalDhcpEntryListener { - public class DhcpEntryState { - String _name; - - public static final DhcpEntryState add = new DhcpEntryState("add"); - public static final DhcpEntryState old = new DhcpEntryState("old"); - public static final DhcpEntryState del = new DhcpEntryState("del"); - - public DhcpEntryState(String name) { - _name = name; - } - - public String getName() { - return _name; - } - } - - /** - * Notify that DHCP entry state change - * @param ip - * @param mac - * @param DHCP entry state - * @return: true means continuous listen on the entry, false cancels the listener - */ - public boolean notify(String ip, String mac, DhcpEntryState state, Object userData); -} diff --git a/server/src/com/cloud/baremetal/ExternalDhcpManager.java b/server/src/com/cloud/baremetal/ExternalDhcpManager.java deleted file mode 100644 index d256ef14267..00000000000 --- a/server/src/com/cloud/baremetal/ExternalDhcpManager.java +++ /dev/null @@ -1,54 +0,0 @@ -// 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.baremetal; - -import com.cloud.baremetal.ExternalDhcpEntryListener.DhcpEntryState; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.host.Host; -import com.cloud.network.Network; -import com.cloud.uservm.UserVm; -import com.cloud.utils.component.Manager; -import com.cloud.vm.NicProfile; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineProfile; - -public interface ExternalDhcpManager extends Manager { - public static class DhcpServerType { - private String _name; - - public static final DhcpServerType Dnsmasq = new DhcpServerType("Dnsmasq"); - public static final DhcpServerType Dhcpd = new DhcpServerType("Dhcpd"); - - public DhcpServerType(String name) { - _name = name; - } - - public String getName() { - return _name; - } - - } - - - DhcpServerResponse getApiResponse(Host dhcpServer); - - boolean addVirtualMachineIntoNetwork(Network network, NicProfile nic, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException; - - Host addDhcpServer(Long zoneId, Long podId, String type, String url, String username, String password); -} diff --git a/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java b/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java deleted file mode 100755 index c534df17381..00000000000 --- a/server/src/com/cloud/baremetal/ExternalDhcpManagerImpl.java +++ /dev/null @@ -1,250 +0,0 @@ -// 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.baremetal; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupExternalDhcpCommand; -import com.cloud.agent.api.routing.DhcpEntryCommand; -import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.HostPodVO; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.dc.dao.HostPodDao; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.host.Host; -import com.cloud.host.Host.Type; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.Network; -import com.cloud.resource.ResourceManager; -import com.cloud.resource.ResourceStateAdapter; -import com.cloud.resource.ServerResource; -import com.cloud.resource.UnableDeleteHostException; -import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.NicProfile; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.dao.NicDao; -import com.cloud.vm.dao.UserVmDao; - -@Component -@Local(value = {ExternalDhcpManager.class}) -public class ExternalDhcpManagerImpl extends ManagerBase implements ExternalDhcpManager, ResourceStateAdapter { - private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalDhcpManagerImpl.class); - @Inject DataCenterDao _dcDao; - @Inject HostDao _hostDao; - @Inject AgentManager _agentMgr; - @Inject HostPodDao _podDao; - @Inject UserVmDao _userVmDao; - @Inject ResourceManager _resourceMgr; - @Inject NicDao _nicDao; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); - return true; - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - _resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName()); - return true; - } - - protected String getDhcpServerGuid(String zoneId, String name, String ip) { - return zoneId + "-" + name + "-" + ip; - } - - - @Override @DB - public Host addDhcpServer(Long zoneId, Long podId, String type, String url, String username, String password) { - DataCenterVO zone = _dcDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId); - } - - HostPodVO pod = _podDao.findById(podId); - if (pod == null) { - throw new InvalidParameterValueException("Could not find pod with ID: " + podId); - } - - List dhcps = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.ExternalDhcp, null, podId, zoneId); - if (dhcps.size() != 0) { - throw new InvalidParameterValueException("Already had a DHCP server in Pod: " + podId + " zone: " + zoneId); - } - - - String ipAddress = url; - String guid = getDhcpServerGuid(Long.toString(zoneId) + "-" + Long.toString(podId), "ExternalDhcp", ipAddress); - Map params = new HashMap(); - params.put("type", type); - params.put("zone", Long.toString(zoneId)); - params.put("pod", podId.toString()); - params.put("ip", ipAddress); - params.put("username", username); - params.put("password", password); - params.put("guid", guid); - params.put("pod", Long.toString(podId)); - params.put("gateway", pod.getGateway()); - String dns = zone.getDns1(); - if (dns == null) { - dns = zone.getDns2(); - } - params.put("dns", dns); - - ServerResource resource = null; - try { - if (type.equalsIgnoreCase(DhcpServerType.Dnsmasq.getName())) { - resource = new DnsmasqResource(); - resource.configure("Dnsmasq resource", params); - } else if (type.equalsIgnoreCase(DhcpServerType.Dhcpd.getName())) { - resource = new DhcpdResource(); - resource.configure("Dhcpd resource", params); - } else { - throw new CloudRuntimeException("Unsupport DHCP server " + type); - } - } catch (Exception e) { - s_logger.debug(e); - throw new CloudRuntimeException(e.getMessage()); - } - - Host dhcpServer = _resourceMgr.addHost(zoneId, resource, Host.Type.ExternalDhcp, params); - if (dhcpServer == null) { - throw new CloudRuntimeException("Cannot add external Dhcp server as a host"); - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - pod.setExternalDhcp(true); - _podDao.update(pod.getId(), pod); - txn.commit(); - return dhcpServer; - } - - @Override - public DhcpServerResponse getApiResponse(Host dhcpServer) { - DhcpServerResponse response = new DhcpServerResponse(); - response.setId(dhcpServer.getUuid()); - return response; - } - - private void prepareBareMetalDhcpEntry(NicProfile nic, DhcpEntryCommand cmd) { - Long vmId = nic.getVmId(); - UserVmVO vm = _userVmDao.findById(vmId); - if (vm == null || vm.getHypervisorType() != HypervisorType.BareMetal) { - s_logger.debug("VM " + vmId + " is not baremetal machine, skip preparing baremetal DHCP entry"); - return; - } - - List servers = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.PxeServer, null, vm.getPodIdToDeployIn(), vm.getDataCenterId()); - if (servers.size() != 1) { - throw new CloudRuntimeException("Wrong number of PXE server found in zone " + vm.getDataCenterId() - + " Pod " + vm.getPodIdToDeployIn() + ", number is " + servers.size()); - } - HostVO pxeServer = servers.get(0); - cmd.setNextServer(pxeServer.getPrivateIpAddress()); - s_logger.debug("Set next-server to " + pxeServer.getPrivateIpAddress() + " for VM " + vm.getId()); - } - - @Override - public boolean addVirtualMachineIntoNetwork(Network network, NicProfile nic, VirtualMachineProfile profile, DeployDestination dest, - ReservationContext context) throws ResourceUnavailableException { - Long zoneId = profile.getVirtualMachine().getDataCenterId(); - Long podId = profile.getVirtualMachine().getPodIdToDeployIn(); - List hosts = _resourceMgr.listAllUpAndEnabledHosts(Type.ExternalDhcp, null, podId, zoneId); - if (hosts.size() == 0) { - throw new CloudRuntimeException("No external Dhcp found in zone " + zoneId + " pod " + podId); - } - - if (hosts.size() > 1) { - throw new CloudRuntimeException("Something wrong, more than 1 external Dhcp found in zone " + zoneId + " pod " + podId); - } - - HostVO h = hosts.get(0); - String dns = nic.getDns1(); - if (dns == null) { - dns = nic.getDns2(); - } - DhcpEntryCommand dhcpCommand = new DhcpEntryCommand(nic.getMacAddress(), nic.getIp4Address(), profile.getVirtualMachine().getHostName(), null, dns, nic.getGateway(), null); - String errMsg = String.format("Set dhcp entry on external DHCP %1$s failed(ip=%2$s, mac=%3$s, vmname=%4$s)", - h.getPrivateIpAddress(), nic.getIp4Address(), nic.getMacAddress(), profile.getVirtualMachine().getHostName()); - //prepareBareMetalDhcpEntry(nic, dhcpCommand); - try { - Answer ans = _agentMgr.send(h.getId(), dhcpCommand); - if (ans.getResult()) { - s_logger.debug(String.format("Set dhcp entry on external DHCP %1$s successfully(ip=%2$s, mac=%3$s, vmname=%4$s)", - h.getPrivateIpAddress(), nic.getIp4Address(), nic.getMacAddress(), profile.getVirtualMachine().getHostName())); - return true; - } else { - s_logger.debug(errMsg + " " + ans.getDetails()); - throw new ResourceUnavailableException(errMsg, DataCenter.class, zoneId); - } - } catch (Exception e) { - s_logger.debug(errMsg, e); - throw new ResourceUnavailableException(errMsg + e.getMessage(), DataCenter.class, zoneId); - } - } - - @Override - public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { - // TODO Auto-generated method stub - return null; - } - - @Override - public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map details, - List hostTags) { - if (!(startup[0] instanceof StartupExternalDhcpCommand)) { - return null; - } - - host.setType(Host.Type.ExternalDhcp); - return host; - } - - @Override - public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { - // TODO Auto-generated method stub - return null; - } -} diff --git a/server/src/com/cloud/baremetal/ExternalDhcpResourceBase.java b/server/src/com/cloud/baremetal/ExternalDhcpResourceBase.java deleted file mode 100644 index 937b4a7f30c..00000000000 --- a/server/src/com/cloud/baremetal/ExternalDhcpResourceBase.java +++ /dev/null @@ -1,198 +0,0 @@ -// 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.baremetal; - -import java.util.HashMap; -import java.util.Map; - -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.IAgentControl; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.PingCommand; -import com.cloud.agent.api.PingRoutingCommand; -import com.cloud.agent.api.ReadyAnswer; -import com.cloud.agent.api.ReadyCommand; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupExternalDhcpCommand; -import com.cloud.agent.api.StartupPxeServerCommand; -import com.cloud.host.Host.Type; -import com.cloud.resource.ServerResource; -import com.cloud.utils.script.Script; -import com.cloud.utils.ssh.SSHCmdHelper; -import com.cloud.vm.VirtualMachine.State; -import com.trilead.ssh2.SCPClient; - -public class ExternalDhcpResourceBase implements ServerResource { - private static final Logger s_logger = Logger.getLogger(ExternalDhcpResourceBase.class); - String _name; - String _guid; - String _username; - String _password; - String _ip; - String _zoneId; - String _podId; - String _gateway; - String _dns; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _name = name; - _guid = (String)params.get("guid"); - _ip = (String)params.get("ip"); - _username = (String)params.get("username"); - _password = (String)params.get("password"); - _zoneId = (String)params.get("zone"); - _podId = (String)params.get("pod"); - _gateway = (String)params.get("gateway"); - _dns = (String)params.get("dns"); - - if (_guid == null) { - throw new ConfigurationException("No Guid specified"); - } - - if (_zoneId == null) { - throw new ConfigurationException("No Zone specified"); - } - - if (_podId == null) { - throw new ConfigurationException("No Pod specified"); - } - - if (_ip == null) { - throw new ConfigurationException("No IP specified"); - } - - if (_username == null) { - throw new ConfigurationException("No username specified"); - } - - if (_password == null) { - throw new ConfigurationException("No password specified"); - } - - if (_gateway == null) { - throw new ConfigurationException("No gateway specified"); - } - - if (_dns == null) { - throw new ConfigurationException("No dns specified"); - } - - return true; - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - return true; - } - - @Override - public String getName() { - return _name; - } - - @Override - public Type getType() { - return Type.ExternalDhcp; - } - - @Override - public StartupCommand[] initialize() { - StartupExternalDhcpCommand cmd = new StartupExternalDhcpCommand(); - cmd.setName(_name); - cmd.setDataCenter(_zoneId); - cmd.setPod(_podId); - cmd.setPrivateIpAddress(_ip); - cmd.setStorageIpAddress(""); - cmd.setVersion(ExternalDhcpResourceBase.class.getPackage().getImplementationVersion()); - cmd.setGuid(_guid); - return new StartupCommand[]{cmd}; - } - - @Override - public PingCommand getCurrentStatus(long id) { - //TODO: check server - return new PingRoutingCommand(getType(), id, new HashMap()); - } - - protected ReadyAnswer execute(ReadyCommand cmd) { - s_logger.debug("External DHCP resource " + _name + " is ready"); - return new ReadyAnswer(cmd); - } - - @Override - public Answer executeRequest(Command cmd) { - if (cmd instanceof ReadyCommand) { - return execute((ReadyCommand) cmd); - } else { - return Answer.createUnsupportedCommandAnswer(cmd); - } - } - - @Override - public void disconnected() { - } - - @Override - public IAgentControl getAgentControl() { - return null; - } - - @Override - public void setAgentControl(IAgentControl agentControl) { - } - - @Override - public void setName(String name) { - // TODO Auto-generated method stub - - } - - @Override - public void setConfigParams(Map params) { - // TODO Auto-generated method stub - - } - - @Override - public Map getConfigParams() { - // TODO Auto-generated method stub - return null; - } - - @Override - public int getRunLevel() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public void setRunLevel(int level) { - // TODO Auto-generated method stub - - } - -} diff --git a/server/src/com/cloud/baremetal/PingPxeServerResource.java b/server/src/com/cloud/baremetal/PingPxeServerResource.java deleted file mode 100755 index 6655fd80efd..00000000000 --- a/server/src/com/cloud/baremetal/PingPxeServerResource.java +++ /dev/null @@ -1,196 +0,0 @@ -// 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.baremetal; - -import java.util.HashMap; -import java.util.Map; - -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.PingCommand; -import com.cloud.agent.api.PingRoutingCommand; -import com.cloud.agent.api.baremetal.PreparePxeServerAnswer; -import com.cloud.agent.api.baremetal.PreparePxeServerCommand; -import com.cloud.agent.api.baremetal.prepareCreateTemplateCommand; -import com.cloud.utils.script.Script; -import com.cloud.utils.ssh.SSHCmdHelper; -import com.cloud.vm.VirtualMachine.State; -import com.trilead.ssh2.SCPClient; - -public class PingPxeServerResource extends PxeServerResourceBase { - private static final Logger s_logger = Logger.getLogger(PingPxeServerResource.class); - String _storageServer; - String _pingDir; - String _share; - String _dir; - String _tftpDir; - String _cifsUserName; - String _cifsPassword; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - super.configure(name, params); - - _storageServer = (String)params.get("storageServer"); - _pingDir = (String)params.get("pingDir"); - _tftpDir = (String)params.get("tftpDir"); - _cifsUserName = (String)params.get("cifsUserName"); - _cifsPassword = (String)params.get("cifsPassword"); - - if (_storageServer == null) { - throw new ConfigurationException("No stroage server specified"); - } - - if (_tftpDir == null) { - throw new ConfigurationException("No tftp directory specified"); - } - - if (_pingDir == null) { - throw new ConfigurationException("No PING directory specified"); - } - - if (_cifsUserName == null || _cifsUserName.equalsIgnoreCase("")) { - _cifsUserName = "xxx"; - } - - if (_cifsPassword == null || _cifsPassword.equalsIgnoreCase("")) { - _cifsPassword = "xxx"; - } - - String pingDirs[]= _pingDir.split("/"); - if (pingDirs.length != 2) { - throw new ConfigurationException("PING dir should have format like myshare/direcotry, eg: windows/64bit"); - } - _share = pingDirs[0]; - _dir = pingDirs[1]; - - com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22); - - s_logger.debug(String.format("Trying to connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, "******")); - try { - sshConnection.connect(null, 60000, 60000); - if (!sshConnection.authenticateWithPassword(_username, _password)) { - s_logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, - "******")); - } - - String cmd = String.format("[ -f /%1$s/pxelinux.0 ] && [ -f /%2$s/kernel ] && [ -f /%3$s/initrd.gz ] ", _tftpDir, _tftpDir, _tftpDir); - if (!SSHCmdHelper.sshExecuteCmd(sshConnection, cmd)) { - throw new ConfigurationException("Miss files in TFTP directory at " + _tftpDir + " check if pxelinux.0, kernel initrd.gz are here"); - } - - SCPClient scp = new SCPClient(sshConnection); - String prepareScript = "scripts/network/ping/prepare_tftp_bootfile.py"; - String prepareScriptPath = Script.findScript("", prepareScript); - if (prepareScriptPath == null) { - throw new ConfigurationException("Can not find prepare_tftp_bootfile.py at " + prepareScriptPath); - } - scp.put(prepareScriptPath, "/usr/bin/", "0755"); - - return true; - } catch (Exception e) { - throw new ConfigurationException(e.getMessage()); - } finally { - if (sshConnection != null) { - sshConnection.close(); - } - } - } - - @Override - public PingCommand getCurrentStatus(long id) { - com.trilead.ssh2.Connection sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password); - if (sshConnection == null) { - return null; - } else { - SSHCmdHelper.releaseSshConnection(sshConnection); - return new PingRoutingCommand(getType(), id, new HashMap()); - } - } - - protected PreparePxeServerAnswer execute(PreparePxeServerCommand cmd) { - com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22); - try { - sshConnection.connect(null, 60000, 60000); - if (!sshConnection.authenticateWithPassword(_username, _password)) { - s_logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, - _password)); - } - - String script = String.format("python /usr/bin/prepare_tftp_bootfile.py restore %1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s %10$s %11$s", - _tftpDir, cmd.getMac(), _storageServer, _share, _dir, cmd.getTemplate(), _cifsUserName, _cifsPassword, cmd.getIp(), cmd.getNetMask(), cmd.getGateWay()); - s_logger.debug("Prepare Ping PXE server successfully"); - if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) { - return new PreparePxeServerAnswer(cmd, "prepare PING at " + _ip + " failed, command:" + script); - } - - return new PreparePxeServerAnswer(cmd); - } catch (Exception e){ - s_logger.debug("Prepare PING pxe server failed", e); - return new PreparePxeServerAnswer(cmd, e.getMessage()); - } finally { - if (sshConnection != null) { - sshConnection.close(); - } - } - } - - protected Answer execute(prepareCreateTemplateCommand cmd) { - com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22); - try { - sshConnection.connect(null, 60000, 60000); - if (!sshConnection.authenticateWithPassword(_username, _password)) { - s_logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, - _password)); - } - - String script = String.format("python /usr/bin/prepare_tftp_bootfile.py backup %1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s %10$s %11$s", - _tftpDir, cmd.getMac(), _storageServer, _share, _dir, cmd.getTemplate(), _cifsUserName, _cifsPassword, cmd.getIp(), cmd.getNetMask(), cmd.getGateWay()); - s_logger.debug("Prepare for creating template successfully"); - if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) { - return new Answer(cmd, false, "prepare for creating template failed, command:" + script); - } - - return new Answer(cmd, true, "Success"); - } catch (Exception e){ - s_logger.debug("Prepare for creating baremetal template failed", e); - return new Answer(cmd, false, e.getMessage()); - } finally { - if (sshConnection != null) { - sshConnection.close(); - } - } - } - - @Override - public Answer executeRequest(Command cmd) { - if (cmd instanceof PreparePxeServerCommand) { - return execute((PreparePxeServerCommand) cmd); - } else if (cmd instanceof prepareCreateTemplateCommand) { - return execute((prepareCreateTemplateCommand)cmd); - } else { - return super.executeRequest(cmd); - } - } -} diff --git a/server/src/com/cloud/baremetal/PxeServerManager.java b/server/src/com/cloud/baremetal/PxeServerManager.java deleted file mode 100644 index 1d2dde7f3f8..00000000000 --- a/server/src/com/cloud/baremetal/PxeServerManager.java +++ /dev/null @@ -1,54 +0,0 @@ -// 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.baremetal; - -import com.cloud.deploy.DeployDestination; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.uservm.UserVm; -import com.cloud.utils.component.Manager; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachineProfile; - -public interface PxeServerManager extends Manager { - public static class PxeServerType { - private String _name; - - public static final PxeServerType PING = new PxeServerType("PING"); - public static final PxeServerType DMCD = new PxeServerType("DMCD"); - - public PxeServerType(String name) { - _name = name; - } - - public String getName() { - return _name; - } - - } - - public PxeServerResponse getApiResponse(Host pxeServer); - - public boolean prepare(PxeServerType type, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId); - - Host addPxeServer(PxeServerProfile profile); - - public boolean prepareCreateTemplate(PxeServerType type, Long pxeServerId, UserVm vm, String templateUrl); - - public PxeServerType getPxeServerType(HostVO host); -} diff --git a/server/src/com/cloud/baremetal/PxeServerManagerImpl.java b/server/src/com/cloud/baremetal/PxeServerManagerImpl.java deleted file mode 100755 index f45b2757424..00000000000 --- a/server/src/com/cloud/baremetal/PxeServerManagerImpl.java +++ /dev/null @@ -1,145 +0,0 @@ -// 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.baremetal; - - -import java.util.List; -import java.util.Map; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupPxeServerCommand; -import com.cloud.baremetal.PxeServerManager.PxeServerType; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.deploy.DeployDestination; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.resource.ResourceManager; -import com.cloud.resource.ResourceStateAdapter; -import com.cloud.resource.ServerResource; -import com.cloud.resource.UnableDeleteHostException; -import com.cloud.uservm.UserVm; -import com.cloud.utils.component.AdapterBase; -import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.VirtualMachineProfile.Param; - -@Component -@Local(value = {PxeServerManager.class}) -public class PxeServerManagerImpl extends ManagerBase implements PxeServerManager, ResourceStateAdapter { - private static final org.apache.log4j.Logger s_logger = Logger.getLogger(PxeServerManagerImpl.class); - @Inject DataCenterDao _dcDao; - @Inject HostDao _hostDao; - @Inject AgentManager _agentMgr; - @Inject ExternalDhcpManager exDhcpMgr; - @Inject ResourceManager _resourceMgr; - - // @com.cloud.utils.component.Inject(adapter=PxeServerService.class) - @Inject protected List _services; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); - return true; - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - _resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName()); - return true; - } - - protected PxeServerService getServiceByType(String type) { - PxeServerService _service; - _service = AdapterBase.getAdapterByName(_services, type); - if (_service == null) { - throw new CloudRuntimeException("Cannot find PXE service for " + type); - } - return _service; - } - - - @Override - public Host addPxeServer(PxeServerProfile profile) { - return getServiceByType(profile.getType()).addPxeServer(profile); - } - - @Override - public PxeServerResponse getApiResponse(Host pxeServer) { - PxeServerResponse response = new PxeServerResponse(); - response.setId(pxeServer.getUuid()); - return response; - } - - @Override - public boolean prepare(PxeServerType type, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId) { - return getServiceByType(type.getName()).prepare(profile, dest, context, pxeServerId); - } - - @Override - public boolean prepareCreateTemplate(PxeServerType type, Long pxeServerId, UserVm vm, String templateUrl) { - return getServiceByType(type.getName()).prepareCreateTemplate(pxeServerId, vm, templateUrl); - } - - @Override - public PxeServerType getPxeServerType(HostVO host) { - if (host.getResource().equalsIgnoreCase(PingPxeServerResource.class.getName())) { - return PxeServerType.PING; - } else { - throw new CloudRuntimeException("Unkown PXE server resource " + host.getResource()); - } - } - - @Override - public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { - // TODO Auto-generated method stub - return null; - } - - @Override - public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map details, - List hostTags) { - if (!(startup[0] instanceof StartupPxeServerCommand)) { - return null; - } - - host.setType(Host.Type.PxeServer); - return host; - } - - @Override - public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { - // TODO Auto-generated method stub - return null; - } -} diff --git a/server/src/com/cloud/baremetal/PxeServerProfile.java b/server/src/com/cloud/baremetal/PxeServerProfile.java deleted file mode 100644 index e289adffee8..00000000000 --- a/server/src/com/cloud/baremetal/PxeServerProfile.java +++ /dev/null @@ -1,90 +0,0 @@ -// 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.baremetal; - -public class PxeServerProfile { - Long zoneId; - Long podId; - String url; - String username; - String password; - String type; - String pingStorageServerIp; - String pingDir; - String tftpDir; - String pingCifsUserName; - String pingCifspassword; - - public PxeServerProfile (Long zoneId, Long podId, String url, String username, String password, String type, - String pingStorageServerIp, String pingDir, String tftpDir, String pingCifsUserName, String pingCifsPassword) { - this.zoneId = zoneId; - this.podId = podId; - this.url = url; - this.username = username; - this.password = password; - this.type = type; - this.pingStorageServerIp = pingStorageServerIp; - this.pingDir = pingDir; - this.tftpDir = tftpDir; - this.pingCifsUserName = pingCifsUserName; - this.pingCifspassword = pingCifsPassword; - } - - public Long getZoneId() { - return zoneId; - } - - public Long getPodId() { - return podId; - } - - public String getUrl() { - return url; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public String getType() { - return type; - } - - public String getPingStorageServerIp() { - return pingStorageServerIp; - } - - public String getPingDir() { - return pingDir; - } - - public String getTftpDir() { - return tftpDir; - } - - public String getPingCifsUserName() { - return pingCifsUserName; - } - - public String getPingCifspassword() { - return pingCifspassword; - } -} diff --git a/server/src/com/cloud/baremetal/PxeServerResourceBase.java b/server/src/com/cloud/baremetal/PxeServerResourceBase.java deleted file mode 100644 index 4df5ea8fabf..00000000000 --- a/server/src/com/cloud/baremetal/PxeServerResourceBase.java +++ /dev/null @@ -1,185 +0,0 @@ -// 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.baremetal; - -import java.util.Map; - -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.IAgentControl; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.PingCommand; -import com.cloud.agent.api.ReadyAnswer; -import com.cloud.agent.api.ReadyCommand; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupPxeServerCommand; -import com.cloud.host.Host.Type; -import com.cloud.resource.ServerResource; - -public class PxeServerResourceBase implements ServerResource { - private static final Logger s_logger = Logger.getLogger(PxeServerResourceBase.class); - String _name; - String _guid; - String _username; - String _password; - String _ip; - String _zoneId; - String _podId; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _name = name; - _guid = (String)params.get("guid"); - _ip = (String)params.get("ip"); - _username = (String)params.get("username"); - _password = (String)params.get("password"); - _zoneId = (String)params.get("zone"); - _podId = (String)params.get("pod"); - - if (_guid == null) { - throw new ConfigurationException("No Guid specified"); - } - - if (_zoneId == null) { - throw new ConfigurationException("No Zone specified"); - } - - if (_podId == null) { - throw new ConfigurationException("No Pod specified"); - } - - if (_ip == null) { - throw new ConfigurationException("No IP specified"); - } - - if (_username == null) { - throw new ConfigurationException("No username specified"); - } - - if (_password == null) { - throw new ConfigurationException("No password specified"); - } - - return true; - } - - protected ReadyAnswer execute(ReadyCommand cmd) { - s_logger.debug("Pxe resource " + _name + " is ready"); - return new ReadyAnswer(cmd); - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - return true; - } - - @Override - public String getName() { - // TODO Auto-generated method stub - return _name; - } - - @Override - public Type getType() { - return Type.PxeServer; - } - - @Override - public StartupCommand[] initialize() { - StartupPxeServerCommand cmd = new StartupPxeServerCommand(); - cmd.setName(_name); - cmd.setDataCenter(_zoneId); - cmd.setPod(_podId); - cmd.setPrivateIpAddress(_ip); - cmd.setStorageIpAddress(""); - cmd.setVersion(PxeServerResourceBase.class.getPackage().getImplementationVersion()); - cmd.setGuid(_guid); - return new StartupCommand[]{cmd}; - } - - @Override - public PingCommand getCurrentStatus(long id) { - // TODO Auto-generated method stub - return null; - } - - @Override - public void disconnected() { - // TODO Auto-generated method stub - - } - - @Override - public IAgentControl getAgentControl() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void setAgentControl(IAgentControl agentControl) { - // TODO Auto-generated method stub - - } - - @Override - public Answer executeRequest(Command cmd) { - if (cmd instanceof ReadyCommand) { - return execute((ReadyCommand) cmd); - } else { - return Answer.createUnsupportedCommandAnswer(cmd); - } - } - - @Override - public void setName(String name) { - // TODO Auto-generated method stub - - } - - @Override - public void setConfigParams(Map params) { - // TODO Auto-generated method stub - - } - - @Override - public Map getConfigParams() { - // TODO Auto-generated method stub - return null; - } - - @Override - public int getRunLevel() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public void setRunLevel(int level) { - // TODO Auto-generated method stub - - } - -} diff --git a/server/src/com/cloud/capacity/CapacityManager.java b/server/src/com/cloud/capacity/CapacityManager.java index fffb41f87e6..bdd9ccd155b 100755 --- a/server/src/com/cloud/capacity/CapacityManager.java +++ b/server/src/com/cloud/capacity/CapacityManager.java @@ -16,8 +16,9 @@ // under the License. package com.cloud.capacity; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.host.HostVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateVO; import com.cloud.utils.component.Manager; import com.cloud.vm.VirtualMachine; @@ -38,8 +39,8 @@ public interface CapacityManager extends Manager { * @param ram required RAM * @param cpuOverprovisioningFactor factor to apply to the actual host cpu */ - boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean checkFromReservedCapacity, float cpuOverprovisioningFactor, boolean considerReservedCapacity); - + boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean checkFromReservedCapacity, float cpuOverprovisioningFactor, float memoryOvercommitRatio, boolean considerReservedCapacity); + void updateCapacityForHost(HostVO host); /** diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index d7b70535b06..292ef0abd5c 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -27,6 +27,13 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.DataCenter; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.resource.ResourceState; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -57,14 +64,13 @@ import com.cloud.resource.ServerResource; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStoragePoolVO; -import com.cloud.storage.VMTemplateSwiftVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.swift.SwiftManager; +import com.cloud.uservm.UserVm; import com.cloud.utils.DateUtil; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; @@ -78,7 +84,11 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.VMSnapshotVO; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component @Local(value = CapacityManager.class) @@ -110,27 +120,30 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, ConfigurationManager _configMgr; @Inject HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; - + @Inject + protected VMSnapshotDao _vmSnapshotDao; + @Inject + protected UserVmDao _userVMDao; + + @Inject + ClusterDetailsDao _clusterDetailsDao; + @Inject + ClusterDao _clusterDao; private int _vmCapacityReleaseInterval; private ScheduledExecutorService _executor; private boolean _stopped; long _extraBytesPerVolume = 0; private float _storageOverProvisioningFactor = 1.0f; - private float _cpuOverProvisioningFactor = 1.0f; @Override public boolean configure(String name, Map params) throws ConfigurationException { _vmCapacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), 3600); _storageOverProvisioningFactor = NumbersUtil.parseFloat(_configDao.getValue(Config.StorageOverprovisioningFactor.key()), 1.0f); - _cpuOverProvisioningFactor = NumbersUtil.parseFloat(_configDao.getValue(Config.CPUOverprovisioningFactor.key()), 1.0f); - if (_cpuOverProvisioningFactor < 1.0f) { - _cpuOverProvisioningFactor = 1.0f; - } _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("HostCapacity-Checker")); VirtualMachine.State.getStateMachine().registerListener(this); _agentManager.registerForHostEvents(new StorageCapacityListener(_capacityDao, _storageOverProvisioningFactor), true, false, false); - _agentManager.registerForHostEvents(new ComputeCapacityListener(_capacityDao, this, _cpuOverProvisioningFactor), true, false, false); + _agentManager.registerForHostEvents(new ComputeCapacityListener(_capacityDao, this), true, false, false); return true; } @@ -155,7 +168,11 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, ServiceOfferingVO svo = _offeringsDao.findById(vm.getServiceOfferingId()); CapacityVO capacityCpu = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_CPU); CapacityVO capacityMemory = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_MEMORY); - + Long clusterId=null; + if (hostId != null) { + HostVO host = _hostDao.findById(hostId); + clusterId= host.getClusterId(); + } if (capacityCpu == null || capacityMemory == null || svo == null) { return false; } @@ -164,9 +181,6 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, try { txn.start(); - int vmCPU = svo.getCpu() * svo.getSpeed(); - long vmMem = svo.getRamSize() * 1024L * 1024L; - capacityCpu = _capacityDao.lockRow(capacityCpu.getId(), true); capacityMemory = _capacityDao.lockRow(capacityMemory.getId(), true); @@ -175,13 +189,18 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, long reservedCpu = capacityCpu.getReservedCapacity(); long reservedMem = capacityMemory.getReservedCapacity(); long actualTotalCpu = capacityCpu.getTotalCapacity(); - String opFactor = _configDao.getValue(Config.CPUOverprovisioningFactor.key()); - float cpuOverprovisioningFactor = NumbersUtil.parseFloat(opFactor, 1); - long totalCpu = (long) (actualTotalCpu * cpuOverprovisioningFactor); + float cpuOvercommitRatio =Float.parseFloat(_clusterDetailsDao.findDetail(clusterId,"cpuOvercommitRatio").getValue()); + float memoryOvercommitRatio = Float.parseFloat(_clusterDetailsDao.findDetail(clusterId,"memoryOvercommitRatio").getValue()); + int vmCPU = (int) (svo.getCpu() * svo.getSpeed()); + long vmMem = (long) (svo.getRamSize() * 1024L * 1024L); + long actualTotalMem = capacityMemory.getTotalCapacity(); + long totalMem = (long) (actualTotalMem * memoryOvercommitRatio); + long totalCpu = (long) (actualTotalCpu * cpuOvercommitRatio); if (s_logger.isDebugEnabled()) { s_logger.debug("Hosts's actual total CPU: " + actualTotalCpu + " and CPU after applying overprovisioning: " + totalCpu); + s_logger.debug("Hosts's actual total RAM: " + actualTotalMem + " and RAM after applying overprovisioning: " + totalMem); } - long totalMem = capacityMemory.getTotalCapacity(); + if (!moveFromReserved) { /* move resource from used */ @@ -233,6 +252,10 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, public void allocateVmCapacity(VirtualMachine vm, boolean fromLastHost) { long hostId = vm.getHostId(); + HostVO host = _hostDao.findById(hostId); + long clusterId = host.getClusterId(); + float cpuOvercommitRatio =Float.parseFloat(_clusterDetailsDao.findDetail(clusterId,"cpuOvercommitRatio").getValue()); + float memoryOvercommitRatio = Float.parseFloat(_clusterDetailsDao.findDetail(clusterId,"memoryOvercommitRatio").getValue()); ServiceOfferingVO svo = _offeringsDao.findById(vm.getServiceOfferingId()); @@ -243,11 +266,9 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, return; } - int cpu = svo.getCpu() * svo.getSpeed(); - long ram = svo.getRamSize() * 1024L * 1024L; + int cpu = (int) (svo.getCpu() * svo.getSpeed()); + long ram = (long) (svo.getRamSize() * 1024L * 1024L); - String opFactor = _configDao.getValue(Config.CPUOverprovisioningFactor.key()); - float cpuOverprovisioningFactor = NumbersUtil.parseFloat(opFactor, 1); Transaction txn = Transaction.currentTxn(); @@ -261,11 +282,12 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, long reservedCpu = capacityCpu.getReservedCapacity(); long reservedMem = capacityMem.getReservedCapacity(); long actualTotalCpu = capacityCpu.getTotalCapacity(); - long totalCpu = (long) (actualTotalCpu * cpuOverprovisioningFactor); + long actualTotalMem = capacityMem.getTotalCapacity(); + long totalCpu = (long) (actualTotalCpu * cpuOvercommitRatio); + long totalMem = (long) (actualTotalMem * memoryOvercommitRatio); if (s_logger.isDebugEnabled()) { s_logger.debug("Hosts's actual total CPU: " + actualTotalCpu + " and CPU after applying overprovisioning: " + totalCpu); } - long totalMem = capacityMem.getTotalCapacity(); long freeCpu = totalCpu - (reservedCpu + usedCpu); long freeMem = totalMem - (reservedMem + usedMem); @@ -317,12 +339,12 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, } @Override - public boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean checkFromReservedCapacity, float cpuOverprovisioningFactor, boolean considerReservedCapacity) { + public boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean checkFromReservedCapacity, float cpuOvercommitRatio,float memoryOvercommitRatio, boolean considerReservedCapacity) { boolean hasCapacity = false; if (s_logger.isDebugEnabled()) { s_logger.debug("Checking if host: " + hostId + " has enough capacity for requested CPU: " + cpu + " and requested RAM: " + ram - + " , cpuOverprovisioningFactor: " + cpuOverprovisioningFactor); + + " , cpuOverprovisioningFactor: " + cpuOvercommitRatio); } CapacityVO capacityCpu = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_CPU); @@ -348,13 +370,13 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, long reservedCpu = capacityCpu.getReservedCapacity(); long reservedMem = capacityMem.getReservedCapacity(); long actualTotalCpu = capacityCpu.getTotalCapacity(); - long totalCpu = (long) (actualTotalCpu * cpuOverprovisioningFactor); + long actualTotalMem = capacityMem.getTotalCapacity(); + long totalCpu = (long) (actualTotalCpu * cpuOvercommitRatio ); + long totalMem = (long) (actualTotalMem *memoryOvercommitRatio ); if (s_logger.isDebugEnabled()) { s_logger.debug("Hosts's actual total CPU: " + actualTotalCpu + " and CPU after applying overprovisioning: " + totalCpu); } - long totalMem = capacityMem.getTotalCapacity(); - String failureReason = ""; if (checkFromReservedCapacity) { long freeCpu = reservedCpu; @@ -437,12 +459,43 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, } + private long getVMSnapshotAllocatedCapacity(StoragePoolVO pool){ + List 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 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 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; @@ -458,28 +511,9 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, } // Add the size for the templateForVmCreation if its not already present - if ((templateForVmCreation != null) && !tmpinstalled) { - // If the template that was passed into this allocator is not installed in the storage pool, - // add 3 * (template size on secondary storage) to the running total - VMTemplateHostVO templateHostVO = _storageMgr.findVmTemplateHost(templateForVmCreation.getId(), pool); - - if (templateHostVO == null) { - VMTemplateSwiftVO templateSwiftVO = _swiftMgr.findByTmpltId(templateForVmCreation.getId()); - if (templateSwiftVO != null) { - long templateSize = templateSwiftVO.getPhysicalSize(); - if (templateSize == 0) { - templateSize = templateSwiftVO.getSize(); - } - totalAllocatedSize += (templateSize + _extraBytesPerVolume); - } - } else { - long templateSize = templateHostVO.getPhysicalSize(); - if ( templateSize == 0 ){ - templateSize = templateHostVO.getSize(); - } - totalAllocatedSize += (templateSize + _extraBytesPerVolume); - } - } + /*if ((templateForVmCreation != null) && !tmpinstalled) { + + }*/ return totalAllocatedSize; } @@ -675,10 +709,12 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, capacityCPU.addAnd("podId", SearchCriteria.Op.EQ, server.getPodId()); capacityCPU.addAnd("capacityType", SearchCriteria.Op.EQ, CapacityVO.CAPACITY_TYPE_CPU); List capacityVOCpus = _capacityDao.search(capacitySC, null); + Float cpuovercommitratio = Float.parseFloat(_clusterDetailsDao.findDetail(server.getClusterId(),"cpuOvercommitRatio").getValue()); + Float memoryOvercommitRatio = Float.parseFloat(_clusterDetailsDao.findDetail(server.getClusterId(),"memoryOvercommitRatio").getValue()); if (capacityVOCpus != null && !capacityVOCpus.isEmpty()) { CapacityVO CapacityVOCpu = capacityVOCpus.get(0); - long newTotalCpu = (long) (server.getCpus().longValue() * server.getSpeed().longValue() * _cpuOverProvisioningFactor); + long newTotalCpu = (long) (server.getCpus().longValue() * server.getSpeed().longValue() * cpuovercommitratio); if ((CapacityVOCpu.getTotalCapacity() <= newTotalCpu) || ((CapacityVOCpu.getUsedCapacity() + CapacityVOCpu.getReservedCapacity()) <= newTotalCpu)) { CapacityVOCpu.setTotalCapacity(newTotalCpu); @@ -693,7 +729,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, _capacityDao.update(CapacityVOCpu.getId(), CapacityVOCpu); } else { CapacityVO capacity = new CapacityVO(server.getId(), server.getDataCenterId(), server.getPodId(), server.getClusterId(), 0L, - (long) (server.getCpus().longValue() * server.getSpeed().longValue() * _cpuOverProvisioningFactor), + (long) (server.getCpus().longValue() * server.getSpeed().longValue()), CapacityVO.CAPACITY_TYPE_CPU); _capacityDao.persist(capacity); } @@ -707,7 +743,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, if (capacityVOMems != null && !capacityVOMems.isEmpty()) { CapacityVO CapacityVOMem = capacityVOMems.get(0); - long newTotalMem = server.getTotalMemory(); + long newTotalMem = (long)((server.getTotalMemory())* memoryOvercommitRatio); if (CapacityVOMem.getTotalCapacity() <= newTotalMem || (CapacityVOMem.getUsedCapacity() + CapacityVOMem.getReservedCapacity() <= newTotalMem)) { CapacityVOMem.setTotalCapacity(newTotalMem); diff --git a/server/src/com/cloud/capacity/ComputeCapacityListener.java b/server/src/com/cloud/capacity/ComputeCapacityListener.java index 8ea695ad072..16e154a80a6 100755 --- a/server/src/com/cloud/capacity/ComputeCapacityListener.java +++ b/server/src/com/cloud/capacity/ComputeCapacityListener.java @@ -42,12 +42,11 @@ public class ComputeCapacityListener implements Listener { public ComputeCapacityListener(CapacityDao _capacityDao, - CapacityManager _capacityMgr, - float _overProvisioningFactor) { + CapacityManager _capacityMgr + ) { super(); this._capacityDao = _capacityDao; this._capacityMgr = _capacityMgr; - this._cpuOverProvisioningFactor = _overProvisioningFactor; } diff --git a/server/src/com/cloud/capacity/dao/CapacityDao.java b/server/src/com/cloud/capacity/dao/CapacityDao.java index 0c0723b837e..0132f69cd50 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDao.java +++ b/server/src/com/cloud/capacity/dao/CapacityDao.java @@ -26,20 +26,20 @@ import com.cloud.utils.db.GenericDao; public interface CapacityDao extends GenericDao { CapacityVO findByHostIdType(Long hostId, short capacityType); - List listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor); - List listHostsWithEnoughCapacity(int requiredCpu, long requiredRam, Long clusterId, String hostType, float cpuOverprovisioningFactor); + List listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone); + List listHostsWithEnoughCapacity(int requiredCpu, long requiredRam, Long clusterId, String hostType); boolean removeBy(Short capacityType, Long zoneId, Long podId, Long clusterId, Long hostId); List findByClusterPodZone(Long zoneId, Long podId, Long clusterId); List findNonSharedStorageForClusterPodZone(Long zoneId,Long podId, Long clusterId); - Pair, Map> orderClustersByAggregateCapacity(long id, short capacityType, boolean isZone, float cpuOverprovisioningFactor); + Pair, Map> orderClustersByAggregateCapacity(long id, short capacityType, boolean isZone); List findCapacityBy(Integer capacityType, Long zoneId, Long podId, Long clusterId); - List listPodsByHostCapacities(long zoneId, int requiredCpu, long requiredRam, short capacityType, float cpuOverprovisioningFactor); - Pair, Map> orderPodsByAggregateCapacity(long zoneId, short capacityType, float cpuOverprovisioningFactor); + List listPodsByHostCapacities(long zoneId, int requiredCpu, long requiredRam, short capacityType); + Pair, Map> orderPodsByAggregateCapacity(long zoneId, short capacityType); List findCapacityBy(Integer capacityType, Long zoneId, Long podId, Long clusterId, String resourceState); List listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit); void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState); - List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long computeRequested, Float overProvFactor); -} + List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long computeRequested); +} diff --git a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java index baaf39164cd..3aef29b954a 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -27,13 +27,13 @@ import java.util.Map; import javax.ejb.Local; import javax.inject.Inject; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; import com.cloud.storage.Storage; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; @@ -55,59 +55,64 @@ public class CapacityDaoImpl extends GenericDaoBase implements private static final String ADD_ALLOCATED_SQL = "UPDATE `cloud`.`op_host_capacity` SET used_capacity = used_capacity + ? WHERE host_id = ? AND capacity_type = ?"; private static final String SUBTRACT_ALLOCATED_SQL = "UPDATE `cloud`.`op_host_capacity` SET used_capacity = used_capacity - ? WHERE host_id = ? AND capacity_type = ?"; - private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART1 = "SELECT DISTINCT capacity.cluster_id FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster` cluster on (cluster.id = capacity.cluster_id AND cluster.removed is NULL) WHERE "; - private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART2 = " AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ? " + - "AND cluster_id IN (SELECT distinct cluster_id FROM `cloud`.`op_host_capacity` WHERE "; - private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART3 = " AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ?) "; + private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART1 = "SELECT DISTINCT capacity.cluster_id FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster` cluster on (cluster.id = capacity.cluster_id AND cluster.removed is NULL) INNER JOIN `cloud`.`cluster_details` cluster_details ON (cluster.id = cluster_details.cluster_id ) WHERE "; + private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART2 = " AND capacity_type = ? AND cluster_details.name= ? AND ((total_capacity * cluster_details.value ) - used_capacity + reserved_capacity) >= ? AND capacity.cluster_id IN (SELECT distinct capacity.cluster_id FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` cluster_details ON (capacity.cluster_id = cluster_details.cluster_id ) WHERE "; + private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART3 = " AND capacity_type = ? AND cluster_details.name= ? AND ((total_capacity * cluster_details.value) - used_capacity + reserved_capacity) >= ?) "; private final SearchBuilder _hostIdTypeSearch; private final SearchBuilder _hostOrPoolIdSearch; - protected GenericSearchBuilder SummedCapacitySearch; private final SearchBuilder _allFieldsSearch; @Inject protected StoragePoolDao _storagePoolDao; - private static final String LIST_HOSTS_IN_CLUSTER_WITH_ENOUGH_CAPACITY = "SELECT a.host_id FROM (host JOIN op_host_capacity a ON host.id = a.host_id AND host.cluster_id = ? AND host.type = ? " + - "AND (a.total_capacity * ? - a.used_capacity) >= ? and a.capacity_type = 1) " + - "JOIN op_host_capacity b ON a.host_id = b.host_id AND b.total_capacity - b.used_capacity >= ? AND b.capacity_type = 0"; + private static final String LIST_HOSTS_IN_CLUSTER_WITH_ENOUGH_CAPACITY = " SELECT host_capacity.host_id FROM (`cloud`.`host` JOIN `cloud`.`op_host_capacity` host_capacity ON (host.id = host_capacity.host_id AND host.cluster_id = ?) JOIN `cloud`.`cluster_details` cluster_details ON (host_capacity.cluster_id = cluster_details.cluster_id) AND host.type = ? AND cluster_details.name='cpuOvercommitRatio' AND ((host_capacity.total_capacity *cluster_details.value ) - host_capacity.used_capacity) >= ? and host_capacity.capacity_type = '1' " + + " AND host_capacity.host_id IN (SELECT capacity.host_id FROM `cloud`.`op_host_capacity` capacity JOIN `cloud`.`cluster_details` cluster_details ON (capacity.cluster_id= cluster_details.cluster_id) where capacity_type='0' AND cluster_details.name='memoryOvercommitRatio' AND ((total_capacity* cluster_details.value) - used_capacity ) >= ?)) "; - private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART1 = "SELECT cluster_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity * ?) FROM `cloud`.`op_host_capacity` WHERE " ; - private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2 = " AND capacity_type = ? GROUP BY cluster_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * ?) ASC"; + private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART1= "SELECT capacity.cluster_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity ) FROM `cloud`.`op_host_capacity` capacity WHERE "; - private static final String LIST_PODSINZONE_BY_HOST_CAPACITIES = "SELECT DISTINCT capacity.pod_id FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`host_pod_ref` pod " + - " ON (pod.id = capacity.pod_id AND pod.removed is NULL) WHERE " + - " capacity.data_center_id = ? AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ? " + - " AND pod_id IN (SELECT distinct pod_id FROM `cloud`.`op_host_capacity` WHERE " + - " capacity.data_center_id = ? AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ?) "; + private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2= " AND capacity_type = ? AND cluster_details.name =? GROUP BY capacity.cluster_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) ASC"; - private static final String ORDER_PODS_BY_AGGREGATE_CAPACITY = "SELECT pod_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity * ?) FROM `cloud`.`op_host_capacity` WHERE data_center_id = ? " + - " AND capacity_type = ? GROUP BY pod_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * ?) ASC"; + private static final String ORDER_CLUSTERS_BY_AGGREGATE_OVERCOMMIT_CAPACITY_PART1= "SELECT capacity.cluster_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` cluster_details ON (capacity.cluster_id = cluster_details.cluster_id) WHERE "; + + private static final String ORDER_CLUSTERS_BY_AGGREGATE_OVERCOMMIT_CAPACITY_PART2= " AND capacity_type = ? AND cluster_details.name =? GROUP BY capacity.cluster_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) ASC"; + + private static final String LIST_PODSINZONE_BY_HOST_CAPACITY_TYPE = "SELECT DISTINCT capacity.pod_id FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`host_pod_ref` pod " + + " ON (pod.id = capacity.pod_id AND pod.removed is NULL) INNER JOIN `cloud`.`cluster_details` cluster ON (capacity.cluster_id = cluster.cluster_id ) WHERE capacity.data_center_id = ? AND capacity_type = ? AND cluster_details.name= ? ((total_capacity * cluster.value ) - used_capacity + reserved_capacity) >= ? "; + + private static final String ORDER_PODS_BY_AGGREGATE_CAPACITY = " SELECT capacity.pod_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity) FROM `cloud`.`op_host_capacity` capacity WHERE data_center_id= ? AND capacity_type = ? GROUP BY capacity.pod_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity) ASC "; + + private static final String ORDER_PODS_BY_AGGREGATE_OVERCOMMIT_CAPACITY ="SELECT capacity.pod_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` cluster_details ON (capacity.cluster_id = cluster_details.cluster_id) WHERE data_center_id=? AND capacity_type = ? AND cluster_details.name = ? GROUP BY capacity.pod_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) ASC"; private static final String LIST_CAPACITY_BY_RESOURCE_STATE = "SELECT capacity.data_center_id, sum(capacity.used_capacity), sum(capacity.reserved_quantity), sum(capacity.total_capacity), capacity_capacity_type "+ - "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`data_center` dc ON (dc.id = capacity.data_center_id AND dc.removed is NULL)"+ - "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`host_pod_ref` pod ON (pod.id = capacity.pod_id AND pod.removed is NULL)"+ - "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster` cluster ON (cluster.id = capacity.cluster_id AND cluster.removed is NULL)"+ - "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`host` host ON (host.id = capacity.host_id AND host.removed is NULL)"+ - "WHERE dc.allocation_state = ? AND pod.allocation_state = ? AND cluster.allocation_state = ? AND host.resource_state = ? AND capacity_type not in (3,4) "; - + "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`data_center` dc ON (dc.id = capacity.data_center_id AND dc.removed is NULL)"+ + "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`host_pod_ref` pod ON (pod.id = capacity.pod_id AND pod.removed is NULL)"+ + "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster` cluster ON (cluster.id = capacity.cluster_id AND cluster.removed is NULL)"+ + "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`host` host ON (host.id = capacity.host_id AND host.removed is NULL)"+ + "WHERE dc.allocation_state = ? AND pod.allocation_state = ? AND cluster.allocation_state = ? AND host.resource_state = ? AND capacity_type not in (3,4) "; + private static final String LIST_CAPACITY_GROUP_BY_ZONE_TYPE_PART1 = "SELECT (sum(capacity.used_capacity) + sum(capacity.reserved_capacity)), (case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`configuration` where name like 'cpu.overprovisioning.factor')) else sum(total_capacity) end), " + - "((sum(capacity.used_capacity) + sum(capacity.reserved_capacity)) / (case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`configuration` where name like 'cpu.overprovisioning.factor')) else sum(total_capacity) end)) percent,"+ - " capacity.capacity_type, capacity.data_center_id "+ - "FROM `cloud`.`op_host_capacity` capacity "+ - "WHERE total_capacity > 0 AND data_center_id is not null AND capacity_state='Enabled'"; + "((sum(capacity.used_capacity) + sum(capacity.reserved_capacity)) / (case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`configuration` where name like 'cpu.overprovisioning.factor')) else sum(total_capacity) end)) percent,"+ + " capacity.capacity_type, capacity.data_center_id "+ + "FROM `cloud`.`op_host_capacity` capacity "+ + "WHERE total_capacity > 0 AND data_center_id is not null AND capacity_state='Enabled'"; private static final String LIST_CAPACITY_GROUP_BY_ZONE_TYPE_PART2 = " GROUP BY data_center_id, capacity_type order by percent desc limit "; - private static final String LIST_CAPACITY_GROUP_BY_POD_TYPE_PART1 = "SELECT (sum(capacity.used_capacity) + sum(capacity.reserved_capacity)), (case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`configuration` where name like 'cpu.overprovisioning.factor')) else sum(total_capacity) end), " + - "((sum(capacity.used_capacity) + sum(capacity.reserved_capacity)) / (case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`configuration` where name like 'cpu.overprovisioning.factor')) else sum(total_capacity) end)) percent,"+ - " capacity.capacity_type, capacity.data_center_id, pod_id "+ - "FROM `cloud`.`op_host_capacity` capacity "+ - "WHERE total_capacity > 0 AND pod_id is not null AND capacity_state='Enabled'"; + private static final String LIST_CAPACITY_GROUP_BY_POD_TYPE_PART1 = "SELECT (sum(capacity.used_capacity) + sum(capacity.reserved_capacity))," + + " (case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`cluster_details` where cluster_details.name= 'cpuOvercommitRatio' AND cluster_details.cluster_id=capacity.cluster_id)) " + + "when '0' then (sum(total_capacity) * (select value from `cloud`.`cluster_details` where cluster_details.name= 'memoryOvercommitRatio' AND cluster_details.cluster_id=capacity.cluster_id))else sum(total_capacity) end)," + + "((sum(capacity.used_capacity) + sum(capacity.reserved_capacity)) / ( case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`cluster_details` where cluster_details.name= 'cpuOvercommitRatio' AND cluster_details.cluster_id=capacity.cluster_id)) " + + "when '0' then (sum(total_capacity) * (select value from `cloud`.`cluster_details` where cluster_details.name= 'memoryOvercommitRatio' AND cluster_details.cluster_id=capacity.cluster_id))else sum(total_capacity) end)) percent," + + "capacity.capacity_type, capacity.data_center_id, pod_id FROM `cloud`.`op_host_capacity` capacity WHERE total_capacity > 0 AND data_center_id is not null AND capacity_state='Enabled' "; + private static final String LIST_CAPACITY_GROUP_BY_POD_TYPE_PART2 = " GROUP BY pod_id, capacity_type order by percent desc limit "; - private static final String LIST_CAPACITY_GROUP_BY_CLUSTER_TYPE_PART1 = "SELECT (sum(capacity.used_capacity) + sum(capacity.reserved_capacity)), (case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`configuration` where name like 'cpu.overprovisioning.factor')) else sum(total_capacity) end), " + - "((sum(capacity.used_capacity) + sum(capacity.reserved_capacity)) / (case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`configuration` where name like 'cpu.overprovisioning.factor')) else sum(total_capacity) end)) percent,"+ - "capacity.capacity_type, capacity.data_center_id, pod_id, cluster_id "+ - "FROM `cloud`.`op_host_capacity` capacity "+ - "WHERE total_capacity > 0 AND cluster_id is not null AND capacity_state='Enabled'"; + private static final String LIST_CAPACITY_GROUP_BY_CLUSTER_TYPE_PART1 = "SELECT (sum(capacity.used_capacity) + sum(capacity.reserved_capacity))," + + " (case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`cluster_details` where cluster_details.name= 'cpuOvercommitRatio' AND cluster_details.cluster_id=capacity.cluster_id)) " + + "when '0' then (sum(total_capacity) * (select value from `cloud`.`cluster_details` where cluster_details.name= 'memoryOvercommitRatio' AND cluster_details.cluster_id=capacity.cluster_id))else sum(total_capacity) end)," + + "((sum(capacity.used_capacity) + sum(capacity.reserved_capacity)) / ( case capacity_type when 1 then (sum(total_capacity) * (select value from `cloud`.`cluster_details` where cluster_details.name= 'cpuOvercommitRatio' AND cluster_details.cluster_id=capacity.cluster_id)) " + + "when '0' then (sum(total_capacity) * (select value from `cloud`.`cluster_details` where cluster_details.name= 'memoryOvercommitRatio' AND cluster_details.cluster_id=capacity.cluster_id))else sum(total_capacity) end)) percent," + + "capacity.capacity_type, capacity.data_center_id, pod_id, cluster_id FROM `cloud`.`op_host_capacity` capacity WHERE total_capacity > 0 AND data_center_id is not null AND capacity_state='Enabled' "; + + private static final String LIST_CAPACITY_GROUP_BY_CLUSTER_TYPE_PART2 = " GROUP BY cluster_id, capacity_type order by percent desc limit "; private static final String UPDATE_CAPACITY_STATE = "UPDATE `cloud`.`op_host_capacity` SET capacity_state = ? WHERE "; private static final String LIST_CLUSTERS_CROSSING_THRESHOLD = "SELECT cluster_id " + @@ -139,34 +144,34 @@ public class CapacityDaoImpl extends GenericDaoBase implements _allFieldsSearch.done(); } - + @Override - public List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long compute_requested, Float overProvFactor){ + public List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long compute_requested){ - Transaction txn = Transaction.currentTxn(); - PreparedStatement pstmt = null; - List result = new ArrayList(); - StringBuilder sql = new StringBuilder(LIST_CLUSTERS_CROSSING_THRESHOLD); + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + List result = new ArrayList(); + StringBuilder sql = new StringBuilder(LIST_CLUSTERS_CROSSING_THRESHOLD); + + + try { + pstmt = txn.prepareAutoCloseStatement(sql.toString()); + pstmt.setLong(1,compute_requested); + pstmt.setShort(2,capacityType); + pstmt.setFloat(3,disableThreshold); + pstmt.setLong(4,zoneId); - - try { - pstmt = txn.prepareAutoCloseStatement(sql.toString()); - pstmt.setLong(1, compute_requested); - pstmt.setLong(2, zoneId); - pstmt.setShort(3, capacityType); - pstmt.setFloat(4, disableThreshold*overProvFactor); - - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - result.add(rs.getLong(1)); - } - return result; - } catch (SQLException e) { - throw new CloudRuntimeException("DB Exception on: " + sql, e); - } catch (Throwable e) { - throw new CloudRuntimeException("Caught: " + sql, e); - } - } + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + result.add(rs.getLong(1)); + } + return result; + } catch (SQLException e) { + throw new CloudRuntimeException("DB Exception on: " + sql, e); + } catch (Throwable e) { + throw new CloudRuntimeException("Caught: " + sql, e); + } + } /*public static String preparePlaceHolders(int length) { StringBuilder builder = new StringBuilder(); @@ -243,6 +248,8 @@ public class CapacityDaoImpl extends GenericDaoBase implements PreparedStatement pstmt = null; List result = new ArrayList(); + List resourceIdList = new ArrayList(); + switch(level){ case 1: // List all the capacities grouped by zone, capacity Type finalQuery.append(LIST_CAPACITY_GROUP_BY_ZONE_TYPE_PART1); @@ -258,17 +265,21 @@ public class CapacityDaoImpl extends GenericDaoBase implements } if (zoneId != null){ - finalQuery.append(" AND data_center_id="+zoneId); + finalQuery.append(" AND data_center_id = ?" ); + resourceIdList.add(zoneId); } if (podId != null){ - finalQuery.append(" AND pod_id="+podId); + finalQuery.append(" AND pod_id = ?" ); + resourceIdList.add(podId); } if (clusterId != null){ - finalQuery.append(" AND cluster_id="+clusterId); + finalQuery.append(" AND cluster_id = ?" ); + resourceIdList.add(clusterId ); } if (capacityType != null){ - finalQuery.append(" AND capacity_type="+capacityType); - } + finalQuery.append(" AND capacity_type = ?"); + resourceIdList.add(capacityType.longValue() ); + } switch(level){ case 1: // List all the capacities grouped by zone, capacity Type @@ -284,12 +295,16 @@ public class CapacityDaoImpl extends GenericDaoBase implements break; } - finalQuery.append(limit.toString()); - + finalQuery.append("?"); + resourceIdList.add((long) limit); + try { - pstmt = txn.prepareAutoCloseStatement(finalQuery.toString()); + pstmt = txn.prepareAutoCloseStatement(finalQuery.toString()); + for (int i = 0; i < resourceIdList.size(); i++){ + pstmt.setLong(1+i, resourceIdList.get(i)); + } ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { + while (rs.next()) { SummedCapacity summedCapacity = new SummedCapacity( rs.getLong(1), rs.getLong(2), rs.getFloat(3), (short)rs.getLong(4), rs.getLong(5), level != 1 ? rs.getLong(6): null, @@ -309,7 +324,7 @@ public class CapacityDaoImpl extends GenericDaoBase implements @Override public List findCapacityBy(Integer capacityType, Long zoneId, Long podId, Long clusterId){ - SummedCapacitySearch = createSearchBuilder(SummedCapacity.class); + GenericSearchBuilder SummedCapacitySearch = createSearchBuilder(SummedCapacity.class); SummedCapacitySearch.select("dcId", Func.NATIVE, SummedCapacitySearch.entity().getDataCenterId()); SummedCapacitySearch.select("sumUsed", Func.SUM, SummedCapacitySearch.entity().getUsedCapacity()); SummedCapacitySearch.select("sumReserved", Func.SUM, SummedCapacitySearch.entity().getReservedCapacity()); @@ -391,8 +406,8 @@ public class CapacityDaoImpl extends GenericDaoBase implements } @Override - public List listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor){ - Transaction txn = Transaction.currentTxn(); + public List listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone){ + Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); @@ -415,11 +430,11 @@ public class CapacityDaoImpl extends GenericDaoBase implements pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(1, id); pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_CPU); - pstmt.setFloat(3, cpuOverprovisioningFactor); + pstmt.setString(3,"cpuOvercommitRatio"); pstmt.setLong(4, requiredCpu); pstmt.setLong(5, id); pstmt.setShort(6, CapacityVO.CAPACITY_TYPE_MEMORY); - pstmt.setFloat(7, 1); + pstmt.setString(7,"memoryOvercommitRatio"); pstmt.setLong(8, requiredRam); ResultSet rs = pstmt.executeQuery(); @@ -436,8 +451,8 @@ public class CapacityDaoImpl extends GenericDaoBase implements @Override - public List listHostsWithEnoughCapacity(int requiredCpu, long requiredRam, Long clusterId, String hostType, float cpuOverprovisioningFactor){ - Transaction txn = Transaction.currentTxn(); + public List listHostsWithEnoughCapacity(int requiredCpu, long requiredRam, Long clusterId, String hostType){ + Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); @@ -446,9 +461,8 @@ public class CapacityDaoImpl extends GenericDaoBase implements pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(1, clusterId); pstmt.setString(2, hostType); - pstmt.setFloat(3, cpuOverprovisioningFactor); - pstmt.setLong(4, requiredCpu); - pstmt.setLong(5, requiredRam); + pstmt.setLong(3, requiredCpu); + pstmt.setLong(4, requiredRam); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { @@ -528,7 +542,7 @@ public class CapacityDaoImpl extends GenericDaoBase implements @Override public List findByClusterPodZone(Long zoneId, Long podId, Long clusterId){ - SummedCapacitySearch = createSearchBuilder(SummedCapacity.class); + GenericSearchBuilder SummedCapacitySearch = createSearchBuilder(SummedCapacity.class); SummedCapacitySearch.select("sumUsed", Func.SUM, SummedCapacitySearch.entity().getUsedCapacity()); SummedCapacitySearch.select("sumTotal", Func.SUM, SummedCapacitySearch.entity().getTotalCapacity()); SummedCapacitySearch.select("capacityType", Func.NATIVE, SummedCapacitySearch.entity().getCapacityType()); @@ -563,7 +577,7 @@ public class CapacityDaoImpl extends GenericDaoBase implements @Override public List findNonSharedStorageForClusterPodZone(Long zoneId, Long podId, Long clusterId){ - SummedCapacitySearch = createSearchBuilder(SummedCapacity.class); + GenericSearchBuilder SummedCapacitySearch = createSearchBuilder(SummedCapacity.class); SummedCapacitySearch.select("sumUsed", Func.SUM, SummedCapacitySearch.entity().getUsedCapacity()); SummedCapacitySearch.select("sumTotal", Func.SUM, SummedCapacitySearch.entity().getTotalCapacity()); SummedCapacitySearch.select("capacityType", Func.NATIVE, SummedCapacitySearch.entity().getCapacityType()); @@ -630,31 +644,44 @@ public class CapacityDaoImpl extends GenericDaoBase implements } @Override - public Pair, Map> orderClustersByAggregateCapacity(long id, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor){ + public Pair, Map> orderClustersByAggregateCapacity(long id, short capacityTypeForOrdering, boolean isZone){ Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); Map clusterCapacityMap = new HashMap(); + StringBuilder sql = new StringBuilder(); + if (capacityTypeForOrdering != Capacity.CAPACITY_TYPE_CPU && capacityTypeForOrdering != Capacity.CAPACITY_TYPE_MEMORY) { + sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART1); + } + else { + sql.append(ORDER_CLUSTERS_BY_AGGREGATE_OVERCOMMIT_CAPACITY_PART1); + } - StringBuilder sql = new StringBuilder(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART1); if(isZone){ - sql.append("data_center_id = ?"); + sql.append(" data_center_id = ?"); }else{ - sql.append("pod_id = ?"); + sql.append(" pod_id = ?"); } - sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2); + if (capacityTypeForOrdering != Capacity.CAPACITY_TYPE_CPU && capacityTypeForOrdering != Capacity.CAPACITY_TYPE_MEMORY){ + sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2); + } + else { + sql.append(ORDER_CLUSTERS_BY_AGGREGATE_OVERCOMMIT_CAPACITY_PART2); + } + try { pstmt = txn.prepareAutoCloseStatement(sql.toString()); - if(capacityTypeForOrdering == CapacityVO.CAPACITY_TYPE_CPU){ - pstmt.setFloat(1, cpuOverprovisioningFactor); - pstmt.setFloat(4, cpuOverprovisioningFactor); - }else{ - pstmt.setFloat(1, 1); - pstmt.setFloat(4, 1); + pstmt.setLong(1, id); + pstmt.setShort(2,capacityTypeForOrdering); + + if (capacityTypeForOrdering == Capacity.CAPACITY_TYPE_CPU){ + pstmt.setString(3,"cpuOvercommitRatio"); } - pstmt.setLong(2, id); - pstmt.setShort(3, capacityTypeForOrdering); + else if (capacityTypeForOrdering == Capacity.CAPACITY_TYPE_MEMORY){ + pstmt.setString(3,"memoryOvercommitRatio"); + } + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Long clusterId = rs.getLong(1); @@ -670,22 +697,25 @@ public class CapacityDaoImpl extends GenericDaoBase implements } @Override - public List listPodsByHostCapacities(long zoneId, int requiredCpu, long requiredRam, short capacityType, float cpuOverprovisioningFactor) { + public List listPodsByHostCapacities(long zoneId, int requiredCpu, long requiredRam, short capacityType) { Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); - StringBuilder sql = new StringBuilder(LIST_PODSINZONE_BY_HOST_CAPACITIES); + StringBuilder sql = new StringBuilder(LIST_PODSINZONE_BY_HOST_CAPACITY_TYPE); + sql.append("AND capacity.pod_id IN ("); + sql.append(LIST_PODSINZONE_BY_HOST_CAPACITY_TYPE); + sql.append(")"); try { pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(1, zoneId); pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_CPU); - pstmt.setFloat(3, cpuOverprovisioningFactor); + pstmt.setString(3, "cpuOvercommitRatio"); pstmt.setLong(4, requiredCpu); pstmt.setLong(5, zoneId); pstmt.setShort(6, CapacityVO.CAPACITY_TYPE_MEMORY); - pstmt.setFloat(7, 1); + pstmt.setString(7,"memoryOvercommitRatio" ); pstmt.setLong(8, requiredRam); ResultSet rs = pstmt.executeQuery(); @@ -701,26 +731,22 @@ public class CapacityDaoImpl extends GenericDaoBase implements } @Override - public Pair, Map> orderPodsByAggregateCapacity(long zoneId, short capacityTypeForOrdering, float cpuOverprovisioningFactor) { + public Pair, Map> orderPodsByAggregateCapacity(long zoneId, short capacityTypeForOrdering) { Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); Map podCapacityMap = new HashMap(); - + StringBuilder sql = new StringBuilder(ORDER_PODS_BY_AGGREGATE_CAPACITY); try { pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(2, zoneId); pstmt.setShort(3, capacityTypeForOrdering); - + if(capacityTypeForOrdering == CapacityVO.CAPACITY_TYPE_CPU){ - pstmt.setFloat(1, cpuOverprovisioningFactor); - pstmt.setFloat(4, cpuOverprovisioningFactor); - }else{ - pstmt.setFloat(1, 1); - pstmt.setFloat(4, 1); + pstmt.setString(3, "cpuOvercommitRatio"); } - + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Long podId = rs.getLong(1); @@ -738,7 +764,7 @@ public class CapacityDaoImpl extends GenericDaoBase implements @Override public void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState) { Transaction txn = Transaction.currentTxn(); - StringBuilder sql = new StringBuilder(UPDATE_CAPACITY_STATE); + StringBuilder sql = new StringBuilder(UPDATE_CAPACITY_STATE); List resourceIdList = new ArrayList(); if (dcId != null){ diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 7bf68d26c1d..ebc2cac4813 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -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 { @@ -136,6 +137,7 @@ public enum Config { SnapshotMonthlyMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.max.monthly", "8", "Maximum monthly snapshots for a volume", null), SnapshotPollInterval("Snapshots", SnapshotManager.class, Integer.class, "snapshot.poll.interval", "300", "The time interval in seconds when the management server polls for snapshots to be scheduled.", null), SnapshotDeltaMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.delta.max", "16", "max delta snapshots between two full snapshots.", null), + BackupSnapshotAferTakingSnapshot("Snapshots", SnapshotManager.class, Boolean.class, "snapshot.backup.rightafter", "true", "backup snapshot right after snapshot is taken", null), // Advanced JobExpireMinutes("Advanced", ManagementServer.class, String.class, "job.expire.minutes", "1440", "Time (in minutes) for async-jobs to be kept in system", null), @@ -179,7 +181,7 @@ public enum Config { MigrateWait("Advanced", AgentManager.class, Integer.class, "migratewait", "3600", "Time (in seconds) to wait for VM migrate finish", null), Workers("Advanced", AgentManager.class, Integer.class, "workers", "5", "Number of worker threads.", null), HAWorkers("Advanced", AgentManager.class, Integer.class, "ha.workers", "5", "Number of ha worker threads.", null), - MountParent("Advanced", ManagementServer.class, String.class, "mount.parent", "/var/lib/cloud/management/mnt", "The mount point on the Management Server for Secondary Storage.", null), + MountParent("Advanced", ManagementServer.class, String.class, "mount.parent", "/var/cloudstack/mnt", "The mount point on the Management Server for Secondary Storage.", null), // UpgradeURL("Advanced", ManagementServer.class, String.class, "upgrade.url", "http://example.com:8080/client/agent/update.zip", "The upgrade URL is the URL of the management server that agents will connect to in order to automatically upgrade.", null), SystemVMUseLocalStorage("Advanced", ManagementServer.class, Boolean.class, "system.vm.use.local.storage", "false", "Indicates whether to use local storage pools or shared storage pools for system VMs.", null), SystemVMAutoReserveCapacity("Advanced", ManagementServer.class, Boolean.class, "system.vm.auto.reserve.capacity", "true", "Indicates whether or not to automatically reserver system VM standby capacity.", null), @@ -230,6 +232,7 @@ public enum Config { EnableEC2API("Advanced", ManagementServer.class, Boolean.class, "enable.ec2.api", "false", "enable EC2 API on CloudStack", null), EnableS3API("Advanced", ManagementServer.class, Boolean.class, "enable.s3.api", "false", "enable Amazon S3 API on CloudStack", null), RecreateSystemVmEnabled("Advanced", ManagementServer.class, Boolean.class, "recreate.systemvm.enabled", "false", "If true, will recreate system vm root disk whenever starting system vm", "true,false"), + SetVmInternalNameUsingDisplayName("Advanced", ManagementServer.class, Boolean.class, "vm.instancename.flag", "false", "If true, will append guest VM's display Name (if set) to its internal instance name", "true,false"), IncorrectLoginAttemptsAllowed("Advanced", ManagementServer.class, Integer.class, "incorrect.login.attempts.allowed", "5", "Incorrect login attempts allowed before the user is disabled", null), // Ovm OvmPublicNetwork("Hidden", ManagementServer.class, String.class, "ovm.public.network.device", null, "Specify the public bridge on host for public network", null), @@ -246,7 +249,7 @@ public enum Config { XenBondStorageNic("Advanced", ManagementServer.class, String.class, "xen.bond.storage.nics", null, "Attempt to bond the two networks if found", null), XenHeartBeatInterval("Advanced", ManagementServer.class, Integer.class, "xen.heartbeat.interval", "60", "heartbeat to use when implementing XenServer Self Fencing", null), XenGuestNetwork("Hidden", ManagementServer.class, String.class, "xen.guest.network.device", null, "Specify for guest network name label", null), - + XenMaxNics("Advanced", AgentManager.class, Integer.class, "xen.nics.max", "7", "Maximum allowed nics for Vms created on Xen", null), // VMware VmwarePrivateNetworkVSwitch("Hidden", ManagementServer.class, String.class, "vmware.private.vswitch", null, "Specify the vSwitch on host for private network", null), VmwarePublicNetworkVSwitch("Hidden", ManagementServer.class, String.class, "vmware.public.vswitch", null, "Specify the vSwitch on host for public network", null), @@ -257,9 +260,8 @@ public enum Config { VmwareAdditionalVncPortRangeStart("Advanced", ManagementServer.class, Integer.class, "vmware.additional.vnc.portrange.start", "50000", "Start port number of additional VNC port range", null), VmwareAdditionalVncPortRangeSize("Advanced", ManagementServer.class, Integer.class, "vmware.additional.vnc.portrange.size", "1000", "Start port number of additional VNC port range", null), //VmwareGuestNicDeviceType("Advanced", ManagementServer.class, String.class, "vmware.guest.nic.device.type", "E1000", "Ethernet card type used in guest VM, valid values are E1000, PCNet32, Vmxnet2, Vmxnet3", null), - VmwarePerClusterHostMax("Advanced", ManagementServer.class, Integer.class, "vmware.percluster.host.max", "8", "maxmium hosts per vCenter cluster(do not let it grow over 8)", "1-8"), - VmwareReserveCpu("Advanced", ManagementServer.class, Boolean.class, "vmware.reserve.cpu", "true", "Specify whether or not to reserve CPU based on CPU overprovisioning factor", null), - VmwareReserveMem("Advanced", ManagementServer.class, Boolean.class, "vmware.reserve.mem", "true", "Specify whether or not to reserve memory based on memory overprovisioning factor", null), + VmwareReserveCpu("Advanced", ManagementServer.class, Boolean.class, "vmware.reserve.cpu", "false", "Specify whether or not to reserve CPU based on CPU overprovisioning factor", null), + VmwareReserveMem("Advanced", ManagementServer.class, Boolean.class, "vmware.reserve.mem", "false", "Specify whether or not to reserve memory based on memory overprovisioning factor", null), VmwareRootDiskControllerType("Advanced", ManagementServer.class, String.class, "vmware.root.disk.controller", "ide", "Specify the default disk controller for root volumes, valid values are scsi, ide", null), VmwareSystemVmNicDeviceType("Advanced", ManagementServer.class, String.class, "vmware.systemvm.nic.device.type", "E1000", "Specify the default network device type for system VMs, valid values are E1000, PCNet32, Vmxnet2, Vmxnet3", null), VmwareRecycleHungWorker("Advanced", ManagementServer.class, Boolean.class, "vmware.recycle.hung.wokervm", "false", "Specify whether or not to recycle hung worker VMs", null), @@ -308,6 +310,8 @@ public enum Config { DefaultMaxAccountVolumes("Account Defaults", ManagementServer.class, Long.class, "max.account.volumes", "20", "The default maximum number of volumes that can be created for an account", null), DefaultMaxAccountNetworks("Account Defaults", ManagementServer.class, Long.class, "max.account.networks", "20", "The default maximum number of networks that can be created for an account", null), DefaultMaxAccountVpcs("Account Defaults", ManagementServer.class, Long.class, "max.account.vpcs", "20", "The default maximum number of vpcs that can be created for an account", null), + DefaultMaxAccountCpus("Account Defaults", ManagementServer.class, Long.class, "max.account.cpus", "40", "The default maximum number of cpu cores that can be used for an account", null), + DefaultMaxAccountMemory("Account Defaults", ManagementServer.class, Long.class, "max.account.memory", "40960", "The default maximum memory (in MB) that can be used for an account", null), ResourceCountCheckInterval("Advanced", ManagementServer.class, Long.class, "resourcecount.check.interval", "0", "Time (in seconds) to wait before retrying resource count check task. Default is 0 which is to never run the task", "Seconds"), @@ -316,7 +320,7 @@ public enum Config { //disabling lb as cluster sync does not work with distributed cluster AgentLbEnable("Advanced", ManagementServer.class, Boolean.class, "agent.lb.enabled", "false", "If agent load balancing enabled in cluster setup", null), SubDomainNetworkAccess("Advanced", NetworkManager.class, Boolean.class, "allow.subdomain.network.access", "true", "Allow subdomains to use networks dedicated to their parent domain(s)", null), - UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, "use.external.dns", "false", "Bypass internal dns, use exetrnal dns1 and dns2", null), + UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, "use.external.dns", "false", "Bypass internal dns, use external dns1 and dns2", null), EncodeApiResponse("Advanced", ManagementServer.class, Boolean.class, "encode.api.response", "false", "Do URL encoding for the api response, false by default", null), DnsBasicZoneUpdates("Advanced", NetworkManager.class, String.class, "network.dns.basiczone.updates", "all", "This parameter can take 2 values: all (default) and pod. It defines if DHCP/DNS requests have to be send to all dhcp servers in cloudstack, or only to the one in the same pod", "all,pod"), @@ -332,6 +336,8 @@ public enum Config { DefaultMaxProjectVolumes("Project Defaults", ManagementServer.class, Long.class, "max.project.volumes", "20", "The default maximum number of volumes that can be created for a project", null), DefaultMaxProjectNetworks("Project Defaults", ManagementServer.class, Long.class, "max.project.networks", "20", "The default maximum number of networks that can be created for a project", null), DefaultMaxProjectVpcs("Project Defaults", ManagementServer.class, Long.class, "max.project.vpcs", "20", "The default maximum number of vpcs that can be created for a project", null), + DefaultMaxProjectCpus("Project Defaults", ManagementServer.class, Long.class, "max.project.cpus", "40", "The default maximum number of cpu cores that can be used for a project", null), + DefaultMaxProjectMemory("Project Defaults", ManagementServer.class, Long.class, "max.project.memory", "40960", "The default maximum memory (in MB) that can be used for a project", null), ProjectInviteRequired("Project Defaults", ManagementServer.class, Boolean.class, "project.invite.required", "false", "If invitation confirmation is required when add account to project. Default value is false", null), ProjectInvitationExpirationTime("Project Defaults", ManagementServer.class, Long.class, "project.invite.timeout", "86400", "Invitation expiration time (in seconds). Default is 1 day - 86400 seconds", null), @@ -367,7 +373,15 @@ public enum Config { ApiLimitInterval("Advanced", ManagementServer.class, Integer.class, "api.throttling.interval", "1", "Time interval (in seconds) to reset API count", null), ApiLimitMax("Advanced", ManagementServer.class, Integer.class, "api.throttling.max", "25", "Max allowed number of APIs within fixed interval", null), - ApiLimitCacheSize("Advanced", ManagementServer.class, Integer.class, "api.throttling.cachesize", "50000", "Account based API count cache size", null); + ApiLimitCacheSize("Advanced", ManagementServer.class, Integer.class, "api.throttling.cachesize", "50000", "Account based API count cache size", null), + + + // VMSnapshots + VMSnapshotMax("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a vm", null), + VMSnapshotCreateWait("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.create.wait", "600", "In second, timeout for create vm snapshot", null), + VMSnapshotExpungeInterval("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.expunge.interval", "60", "The interval (in seconds) to wait before running the expunge thread.", null), + VMSnapshotExpungeWorkers("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.expunge.workers", "1", "Number of workers performing expunge ", null); + private final String _category; private final Class _componentClass; diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 5c1b0d58c6f..7193928ca33 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -72,6 +72,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @param localStorageRequired * @param offerHA * @param domainId + * @param volatileVm * @param hostTag * @param networkRate * TODO @@ -80,7 +81,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @return ID */ ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, - boolean offerHA, boolean limitResourceUse, String tags, Long domainId, String hostTag, Integer networkRate); + boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate); /** * Creates a new disk offering diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 074675cdd33..cf3a9080a1f 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1246,6 +1246,27 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return true; } + + @Override + @DB + public LDAPConfigCmd listLDAPConfig(LDAPConfigCmd cmd) { + String hostname = _configDao.getValue(LDAPParams.hostname.toString()); + cmd.setHostname(hostname == null ? "" : hostname); + String port = _configDao.getValue(LDAPParams.port.toString()); + cmd.setPort(port == null ? 0 : Integer.valueOf(port)); + String queryFilter = _configDao.getValue(LDAPParams.queryfilter.toString()); + cmd.setQueryFilter(queryFilter == null ? "" : queryFilter); + String searchBase = _configDao.getValue(LDAPParams.searchbase.toString()); + cmd.setSearchBase(searchBase == null ? "" : searchBase); + String useSSL = _configDao.getValue(LDAPParams.usessl.toString()); + cmd.setUseSSL(useSSL == null ? Boolean.FALSE : Boolean.valueOf(useSSL)); + String binddn = _configDao.getValue(LDAPParams.dn.toString()); + cmd.setBindDN(binddn == null ? "" : binddn); + String truststore = _configDao.getValue(LDAPParams.truststore.toString()); + cmd.setTrustStore(truststore == null ? "" : truststore); + return cmd; + } + @Override @DB public boolean updateLDAP(LDAPConfigCmd cmd) { @@ -1265,11 +1286,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("If you specify a bind name then you need to provide bind password too."); } + // check query filter if it contains valid substitution + if (!queryFilter.contains("%u") && !queryFilter.contains("%n") && !queryFilter.contains("%e")){ + throw new InvalidParameterValueException("QueryFilter should contain at least one of the substitutions: %u, %n or %e: " + queryFilter); + } + // check if the info is correct Hashtable env = new Hashtable(11); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); String protocol = "ldap://"; - if (new Boolean(useSSL)) { + if (useSSL) { env.put(Context.SECURITY_PROTOCOL, "ssl"); protocol = "ldaps://"; if (trustStore == null || trustStorePassword == null) { @@ -1288,7 +1314,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati DirContext ctx = new InitialDirContext(env); ctx.close(); - // store the result in DB COnfiguration + // store the result in DB Configuration ConfigurationVO cvo = _configDao.findByName(LDAPParams.hostname.toString()); if (cvo == null) { cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server", LDAPParams.hostname.toString(), null, "Hostname or ip address of the ldap server eg: my.ldap.com"); @@ -1356,8 +1382,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati s_logger.debug("The ldap server is configured: " + hostname); } catch (NamingException ne) { - ne.printStackTrace(); - throw new InvalidParameterValueException("Naming Exception, check you ldap data ! " + ne.getMessage() + (ne.getCause() != null ? ("Caused by:" + ne.getCause().getMessage()) : "")); + throw new InvalidParameterValueException("Naming Exception, check you ldap data ! " + ne.getMessage() + (ne.getCause() != null ? ("; Caused by:" + ne.getCause().getMessage()) : "")); } return true; } @@ -1752,14 +1777,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } Boolean offerHA = cmd.getOfferHa(); - if (offerHA == null) { - offerHA = false; - } - Boolean limitCpuUse = cmd.GetLimitCpuUse(); - if (limitCpuUse == null) { - limitCpuUse = false; - } + Boolean volatileVm = cmd.getVolatileVm(); String vmTypeString = cmd.getSystemVmType(); VirtualMachine.Type vmType = null; @@ -1786,15 +1805,15 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber.intValue(), memory.intValue(), cpuSpeed.intValue(), cmd.getDisplayText(), - localStorageRequired, offerHA, limitCpuUse, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate()); + localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate()); } @Override @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CREATE, eventDescription = "creating service offering") public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_type, String name, int cpu, int ramSize, int speed, String displayText, - boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, String tags, Long domainId, String hostTag, Integer networkRate) { + boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate) { tags = cleanupTags(tags); - ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, displayText, localStorageRequired, false, tags, isSystem, vm_type, + ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, localStorageRequired, false, tags, isSystem, vm_type, domainId, hostTag); if ((offering = _serviceOfferingDao.persist(offering)) != null) { diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 168ac0e43cb..69f70e521d8 100755 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -29,14 +29,10 @@ import java.util.UUID; import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import javax.persistence.Table; import org.apache.cloudstack.api.ServerApiException; -import com.cloud.offering.DiskOffering; -import com.cloud.storage.dao.DiskOfferingDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.AgentControlAnswer; @@ -102,6 +98,7 @@ import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.rules.RulesManager; +import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -114,13 +111,14 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.servlet.ConsoleProxyServlet; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.template.TemplateManager; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.User; @@ -233,6 +231,8 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy @Inject RulesManager _rulesMgr; @Inject + TemplateManager templateMgr; + @Inject IPAddressDao _ipAddressDao; private ConsoleProxyListener _listener; @@ -1175,7 +1175,7 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy ZoneHostInfo zoneHostInfo = zoneHostInfoMap.get(dataCenterId); if (zoneHostInfo != null && isZoneHostReady(zoneHostInfo)) { VMTemplateVO template = _templateDao.findSystemVMTemplate(dataCenterId); - HostVO secondaryStorageHost = _storageMgr.getSecondaryStorageHost(dataCenterId); + HostVO secondaryStorageHost = this.templateMgr.getSecondaryStorageHost(dataCenterId); boolean templateReady = false; if (template != null && secondaryStorageHost != null) { diff --git a/server/src/com/cloud/deploy/AbstractDeployPlannerSelector.java b/server/src/com/cloud/deploy/AbstractDeployPlannerSelector.java new file mode 100755 index 00000000000..62094eb5ea6 --- /dev/null +++ b/server/src/com/cloud/deploy/AbstractDeployPlannerSelector.java @@ -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.deploy; + +import java.util.Map; + +import javax.naming.ConfigurationException; + +import com.cloud.vm.UserVmVO; + +public abstract class AbstractDeployPlannerSelector implements DeployPlannerSelector { + protected Map params; + protected String name; + protected int runLevel; + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public void setConfigParams(Map params) { + this.params = params; + } + + @Override + public Map getConfigParams() { + return params; + } + + @Override + public int getRunLevel() { + return runLevel; + } + + @Override + public void setRunLevel(int level) { + this.runLevel = level; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } +} diff --git a/core/src/com/cloud/resource/NetworkPreparer.java b/server/src/com/cloud/deploy/DeployPlannerSelector.java old mode 100644 new mode 100755 similarity index 81% rename from core/src/com/cloud/resource/NetworkPreparer.java rename to server/src/com/cloud/deploy/DeployPlannerSelector.java index d7034535e9f..40eabb1646f --- a/core/src/com/cloud/resource/NetworkPreparer.java +++ b/server/src/com/cloud/deploy/DeployPlannerSelector.java @@ -1,29 +1,24 @@ -// 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.resource; - -import com.cloud.utils.component.Adapter; - -/** - * Prepares the network for VM. - */ -public interface NetworkPreparer extends Adapter { - - String setup(String vnet); - - void cleanup(String vnet); -} +// 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.deploy; + +import com.cloud.utils.component.Adapter; +import com.cloud.vm.UserVmVO; + +public interface DeployPlannerSelector extends Adapter { + String selectPlanner(UserVmVO vm); +} diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 66a24ac0e43..4933467bd8f 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -27,6 +27,8 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import com.cloud.dc.*; import org.apache.log4j.Logger; import com.cloud.agent.manager.allocator.HostAllocator; @@ -37,11 +39,6 @@ import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.HostPodVO; -import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; @@ -59,7 +56,6 @@ import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.allocator.StoragePoolAllocator; @@ -99,6 +95,8 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { @Inject protected CapacityDao _capacityDao; @Inject protected AccountManager _accountMgr; @Inject protected StorageManager _storageMgr; + @Inject DataStoreManager dataStoreMgr; + @Inject protected ClusterDetailsDao _clusterDetailsDao; //@com.cloud.utils.component.Inject(adapter=StoragePoolAllocator.class) @Inject protected List _storagePoolAllocators; @@ -127,9 +125,6 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { int cpu_requested = offering.getCpu() * offering.getSpeed(); long ram_requested = offering.getRamSize() * 1024L * 1024L; - String opFactor = _configDao.getValue(Config.CPUOverprovisioningFactor.key()); - float cpuOverprovisioningFactor = NumbersUtil.parseFloat(opFactor, 1); - if (s_logger.isDebugEnabled()) { s_logger.debug("DeploymentPlanner allocation algorithm: "+_allocationAlgorithm); @@ -198,7 +193,12 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { s_logger.debug("The last Host, hostId: "+ host.getId() +" already has max Running VMs(count includes system VMs), skipping this and trying other available hosts"); }else{ if (host.getStatus() == Status.Up && host.getResourceState() == ResourceState.Enabled) { - if(_capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, true, cpuOverprovisioningFactor, true)){ + long cluster_id = host.getClusterId(); + ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id,"cpuOvercommitRatio"); + ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id,"memoryOvercommitRatio"); + Float cpuOvercommitRatio = Float.parseFloat(cluster_detail_cpu.getValue()); + Float memoryOvercommitRatio = Float.parseFloat(cluster_detail_ram.getValue()); + if(_capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, true, cpuOvercommitRatio, memoryOvercommitRatio, true)){ s_logger.debug("The last host of this VM is UP and has enough capacity"); s_logger.debug("Now checking for suitable pools under zone: "+host.getDataCenterId() +", pod: "+ host.getPodId()+", cluster: "+ host.getClusterId()); //search for storage under the zone, pod, cluster of the last host. @@ -286,12 +286,9 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { ServiceOffering offering = vmProfile.getServiceOffering(); int requiredCpu = offering.getCpu() * offering.getSpeed(); long requiredRam = offering.getRamSize() * 1024L * 1024L; - String opFactor = _configDao.getValue(Config.CPUOverprovisioningFactor.key()); - float cpuOverprovisioningFactor = NumbersUtil.parseFloat(opFactor, 1); - //list pods under this zone by cpu and ram capacity List prioritizedPodIds = new ArrayList(); - Pair, Map> podCapacityInfo = listPodsByCapacity(plan.getDataCenterId(), requiredCpu, requiredRam, cpuOverprovisioningFactor); + Pair, Map> podCapacityInfo = listPodsByCapacity(plan.getDataCenterId(), requiredCpu, requiredRam); List podsWithCapacity = podCapacityInfo.first(); if(!podsWithCapacity.isEmpty()){ @@ -349,11 +346,9 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { DataCenter dc = _dcDao.findById(vm.getDataCenterId()); int requiredCpu = offering.getCpu() * offering.getSpeed(); long requiredRam = offering.getRamSize() * 1024L * 1024L; - String opFactor = _configDao.getValue(Config.CPUOverprovisioningFactor.key()); - float cpuOverprovisioningFactor = NumbersUtil.parseFloat(opFactor, 1); //list clusters under this zone by cpu and ram capacity - Pair, Map> clusterCapacityInfo = listClustersByCapacity(id, requiredCpu, requiredRam, avoid, isZone, cpuOverprovisioningFactor); + Pair, Map> clusterCapacityInfo = listClustersByCapacity(id, requiredCpu, requiredRam, avoid, isZone); List prioritizedClusterIds = clusterCapacityInfo.first(); if(!prioritizedClusterIds.isEmpty()){ if(avoid.getClustersToAvoid() != null){ @@ -467,30 +462,30 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { // For each capacity get the cluster list crossing the threshold and remove it from the clusterList that will be used for vm allocation. for(short capacity : capacityList){ - - if (clusterListForVmAllocation == null || clusterListForVmAllocation.size() == 0){ - return; + + if (clusterListForVmAllocation == null || clusterListForVmAllocation.size() == 0){ + return; + } + if (capacity == Capacity.CAPACITY_TYPE_CPU) { + clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, plan.getDataCenterId(), + capacityThresholdMap.get(capacity), cpu_requested); } - - if (capacity == Capacity.CAPACITY_TYPE_CPU){ - clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(Capacity.CAPACITY_TYPE_CPU, plan.getDataCenterId(), - capacityThresholdMap.get(capacity), cpu_requested, ApiDBUtils.getCpuOverprovisioningFactor()); - }else{ + else if (capacity == Capacity.CAPACITY_TYPE_MEMORY ) { clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, plan.getDataCenterId(), - capacityThresholdMap.get(capacity), ram_requested, 1.0f);//Mem overprov not supported yet - } - - - if (clustersCrossingThreshold != null && clustersCrossingThreshold.size() != 0){ - // addToAvoid Set - avoid.addClusterList(clustersCrossingThreshold); - // Remove clusters crossing disabled threshold - clusterListForVmAllocation.removeAll(clustersCrossingThreshold); - - s_logger.debug("Cannot allocate cluster list " + clustersCrossingThreshold.toString() + " for vm creation since their allocated percentage" + - " crosses the disable capacity threshold: " + capacityThresholdMap.get(capacity) + " for capacity Type : " + capacity + ", skipping these clusters"); + capacityThresholdMap.get(capacity), ram_requested ); } + + if (clustersCrossingThreshold != null && clustersCrossingThreshold.size() != 0){ + // addToAvoid Set + avoid.addClusterList(clustersCrossingThreshold); + // Remove clusters crossing disabled threshold + clusterListForVmAllocation.removeAll(clustersCrossingThreshold); + + s_logger.debug("Cannot allocate cluster list " + clustersCrossingThreshold.toString() + " for vm creation since their allocated percentage" + + " crosses the disable capacity threshold: " + capacityThresholdMap.get(capacity) + " for capacity Type : " + capacity + ", skipping these clusters"); + } + } } @@ -559,7 +554,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { } - protected Pair, Map> listClustersByCapacity(long id, int requiredCpu, long requiredRam, ExcludeList avoid, boolean isZone, float cpuOverprovisioningFactor){ + protected Pair, Map> listClustersByCapacity(long id, int requiredCpu, long requiredRam, ExcludeList avoid, boolean isZone){ //look at the aggregate available cpu and ram per cluster //although an aggregate value may be false indicator that a cluster can host a vm, it will at the least eliminate those clusters which definitely cannot @@ -573,14 +568,11 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { capacityType = CapacityVO.CAPACITY_TYPE_MEMORY; } - if (s_logger.isDebugEnabled()) { - s_logger.debug("CPUOverprovisioningFactor considered: " + cpuOverprovisioningFactor); - } - List clusterIdswithEnoughCapacity = _capacityDao.listClustersInZoneOrPodByHostCapacities(id, requiredCpu, requiredRam, capacityType, isZone, cpuOverprovisioningFactor); + List clusterIdswithEnoughCapacity = _capacityDao.listClustersInZoneOrPodByHostCapacities(id, requiredCpu, requiredRam, capacityType, isZone); if (s_logger.isTraceEnabled()) { s_logger.trace("ClusterId List having enough CPU and RAM capacity: " + clusterIdswithEnoughCapacity); } - Pair, Map> result = _capacityDao.orderClustersByAggregateCapacity(id, capacityType, isZone, cpuOverprovisioningFactor); + Pair, Map> result = _capacityDao.orderClustersByAggregateCapacity(id, capacityType, isZone); List clusterIdsOrderedByAggregateCapacity = result.first(); //only keep the clusters that have enough capacity to host this VM if (s_logger.isTraceEnabled()) { @@ -596,7 +588,8 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { } - protected Pair, Map> listPodsByCapacity(long zoneId, int requiredCpu, long requiredRam, float cpuOverprovisioningFactor){ + + protected Pair, Map> listPodsByCapacity(long zoneId, int requiredCpu, long requiredRam){ //look at the aggregate available cpu and ram per pod //although an aggregate value may be false indicator that a pod can host a vm, it will at the least eliminate those pods which definitely cannot @@ -610,14 +603,11 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { capacityType = CapacityVO.CAPACITY_TYPE_MEMORY; } - if (s_logger.isDebugEnabled()) { - s_logger.debug("CPUOverprovisioningFactor considered: " + cpuOverprovisioningFactor); - } - List podIdswithEnoughCapacity = _capacityDao.listPodsByHostCapacities(zoneId, requiredCpu, requiredRam, capacityType, cpuOverprovisioningFactor); + List podIdswithEnoughCapacity = _capacityDao.listPodsByHostCapacities(zoneId, requiredCpu, requiredRam, capacityType); if (s_logger.isTraceEnabled()) { s_logger.trace("PodId List having enough CPU and RAM capacity: " + podIdswithEnoughCapacity); } - Pair, Map> result = _capacityDao.orderPodsByAggregateCapacity(zoneId, capacityType, cpuOverprovisioningFactor); + Pair, Map> result = _capacityDao.orderPodsByAggregateCapacity(zoneId, capacityType); List podIdsOrderedByAggregateCapacity = result.first(); //only keep the clusters that have enough capacity to host this VM if (s_logger.isTraceEnabled()) { @@ -736,11 +726,11 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { if(plan.getPoolId() != null){ s_logger.debug("Volume has pool already allocated, checking if pool can be reused, poolId: "+toBeCreated.getPoolId()); List suitablePools = new ArrayList(); - StoragePoolVO pool; + StoragePool pool = null; if(toBeCreated.getPoolId() != null){ - pool = _storagePoolDao.findById(toBeCreated.getPoolId()); + pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(toBeCreated.getPoolId()); }else{ - pool = _storagePoolDao.findById(plan.getPoolId()); + pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(plan.getPoolId()); } if(!pool.isInMaintenance()){ diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDaoImpl.java b/server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java similarity index 63% rename from plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDaoImpl.java rename to server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java index 5a882f1ef14..034a9aafc92 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDaoImpl.java +++ b/server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java @@ -1,32 +1,33 @@ -// 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. -// -// Automatically generated by addcopyright.py at 01/29/2013 -package com.cloud.baremetal.database; +// 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.deploy; import javax.ejb.Local; - -import org.springframework.stereotype.Component; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.GenericDaoBase; -@Component -@Local(value = {BaremetalCmdbDao.class}) -@DB(txn = false) -public class BaremetalCmdbDaoImpl extends GenericDaoBase implements BaremetalCmdbDao { +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.vm.UserVmVO; +@Local(value = {DeployPlannerSelector.class}) +public class HypervisorVmPlannerSelector extends AbstractDeployPlannerSelector { + @Override + public String selectPlanner(UserVmVO vm) { + if (vm.getHypervisorType() != HypervisorType.BareMetal) { + return "FirstFitPlanner"; + } + return null; + } } diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java index eb27fda1fe8..bba8be5c649 100755 --- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -31,7 +31,6 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.apache.log4j.NDC; -import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.alert.AlertManager; @@ -60,6 +59,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.server.ManagementServer; import com.cloud.storage.StorageManager; +import com.cloud.storage.VolumeManager; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; import com.cloud.user.AccountManager; @@ -140,6 +140,8 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai ManagementServer _msServer; @Inject ConfigurationDao _configDao; + @Inject + VolumeManager volumeMgr; String _instance; ScheduledExecutorService _executor; @@ -499,7 +501,7 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai return null; // VM doesn't require HA } - if (!_storageMgr.canVmRestartOnAnotherServer(vm.getId())) { + if (!this.volumeMgr.canVmRestartOnAnotherServer(vm.getId())) { if (s_logger.isDebugEnabled()) { s_logger.debug("VM can not restart on another server."); } diff --git a/server/src/com/cloud/host/dao/HostDaoImpl.java b/server/src/com/cloud/host/dao/HostDaoImpl.java index c03611d41e9..697c3dc3826 100755 --- a/server/src/com/cloud/host/dao/HostDaoImpl.java +++ b/server/src/com/cloud/host/dao/HostDaoImpl.java @@ -491,7 +491,7 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao txn.start(); SearchCriteria sc = UnmanagedApplianceSearch.create(); sc.setParameters("lastPinged", lastPingSecondsAfter); - sc.setParameters("types", Type.ExternalDhcp, Type.ExternalFirewall, Type.ExternalLoadBalancer, Type.PxeServer, Type.TrafficMonitor, Type.L2Networking); + sc.setParameters("types", Type.ExternalDhcp, Type.ExternalFirewall, Type.ExternalLoadBalancer, Type.BaremetalDhcp, Type.BaremetalPxe, Type.TrafficMonitor, Type.L2Networking); List hosts = lockRows(sc, null, true); for (HostVO host : hosts) { diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index e158962aa11..efe93966fe9 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -76,9 +76,11 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis ServiceOffering offering = vmProfile.getServiceOffering(); VirtualMachine vm = vmProfile.getVirtualMachine(); - - VirtualMachineTO to = new VirtualMachineTO(vm.getId(), vm.getInstanceName(), vm.getType(), offering.getCpu(), offering.getSpeed(), - offering.getRamSize() * 1024l * 1024l, offering.getRamSize() * 1024l * 1024l, null, null, vm.isHaEnabled(), vm.limitCpuUse(), vm.getVncPassword()); + Long minMemory = (long) (offering.getRamSize()/vmProfile.getCpuOvercommitRatio()); + int minspeed= (int)(offering.getSpeed()/vmProfile.getMemoryOvercommitRatio()); + int maxspeed = (offering.getSpeed()); + VirtualMachineTO to = new VirtualMachineTO(vm.getId(), vm.getInstanceName(), vm.getType(), offering.getCpu(), minspeed, maxspeed, + minMemory * 1024l * 1024l, offering.getRamSize() * 1024l * 1024l, null, null, vm.isHaEnabled(), vm.limitCpuUse(), vm.getVncPassword()); to.setBootArgs(vmProfile.getBootArgs()); List nicProfiles = vmProfile.getNics(); diff --git a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java b/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java index 8f4a47584b3..0fe0b535f78 100644 --- a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java +++ b/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java @@ -31,4 +31,6 @@ public interface HypervisorCapabilitiesDao extends GenericDao HypervisorTypeSearch; protected final SearchBuilder HypervisorTypeAndVersionSearch; - protected final GenericSearchBuilder MaxGuestLimitByHypervisorSearch; - protected final GenericSearchBuilder MaxDataVolumesLimitByHypervisorSearch; private static final String DEFAULT_VERSION = "default"; @@ -52,18 +50,14 @@ public class HypervisorCapabilitiesDaoImpl extends GenericDaoBase sc = MaxGuestLimitByHypervisorSearch.create(); - sc.setParameters("hypervisorType", hypervisorType); - sc.setParameters("hypervisorVersion", hypervisorVersion); - List limitList = customSearch(sc, null); - if(!limitList.isEmpty()){ - result = limitList.get(0); - }else{ - useDefault = true; - } - }else{ - useDefault = true; - } - if(useDefault){ - SearchCriteria sc = MaxGuestLimitByHypervisorSearch.create(); - sc.setParameters("hypervisorType", hypervisorType); - sc.setParameters("hypervisorVersion", DEFAULT_VERSION); - List limitList = customSearch(sc, null); - if(!limitList.isEmpty()){ - result = limitList.get(0); - } - } - if(result == null){ + HypervisorCapabilitiesVO result = getCapabilities(hypervisorType, hypervisorVersion); + Long limit = result.getMaxGuestsLimit(); + if (limit == null) return defaultLimit; - } - return result; + return limit; } @Override public Integer getMaxDataVolumesLimit(HypervisorType hypervisorType, String hypervisorVersion) { - Integer result = null; - boolean useDefault = false; - if (hypervisorVersion != null) { - SearchCriteria sc = MaxDataVolumesLimitByHypervisorSearch.create(); - sc.setParameters("hypervisorType", hypervisorType); - sc.setParameters("hypervisorVersion", hypervisorVersion); - List limitList = customSearch(sc, null); - if (!limitList.isEmpty()) { - result = limitList.get(0); - } else { - useDefault = true; - } - } else { - useDefault = true; - } - // If data is not available for a specific hypervisor version then use 'default' as the version - if (useDefault) { - SearchCriteria sc = MaxDataVolumesLimitByHypervisorSearch.create(); - sc.setParameters("hypervisorType", hypervisorType); - sc.setParameters("hypervisorVersion", DEFAULT_VERSION); - List limitList = customSearch(sc, null); - if (!limitList.isEmpty()) { - result = limitList.get(0); - } - } - return result; + HypervisorCapabilitiesVO result = getCapabilities(hypervisorType, hypervisorVersion); + return result.getMaxDataVolumesLimit(); } -} \ No newline at end of file + + @Override + public Integer getMaxHostsPerCluster(HypervisorType hypervisorType, String hypervisorVersion) { + HypervisorCapabilitiesVO result = getCapabilities(hypervisorType, hypervisorVersion); + return result.getMaxHostsPerCluster(); + } +} diff --git a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java index 76626205f45..75e00adbfe4 100644 --- a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java +++ b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java @@ -212,7 +212,7 @@ Listener, ResourceStateAdapter { parameters += " --prvNic=" + kvmPrivateNic; parameters += " --guestNic=" + kvmGuestNic; - SSHCmdHelper.sshExecuteCmd(sshConnection, "cloud-setup-agent " + parameters, 3); + SSHCmdHelper.sshExecuteCmd(sshConnection, "cloudstack-setup-agent " + parameters, 3); KvmDummyResourceBase kvmResource = new KvmDummyResourceBase(); Map params = new HashMap(); diff --git a/server/src/com/cloud/migration/ServiceOffering21VO.java b/server/src/com/cloud/migration/ServiceOffering21VO.java index fdec30e3b8a..d07be6462f1 100644 --- a/server/src/com/cloud/migration/ServiceOffering21VO.java +++ b/server/src/com/cloud/migration/ServiceOffering21VO.java @@ -169,5 +169,10 @@ public class ServiceOffering21VO extends DiskOffering21VO implements ServiceOffe return null; } + @Override + public boolean getVolatileVm() { + return false; + } + } diff --git a/server/src/com/cloud/network/ExternalNetworkDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalNetworkDeviceManagerImpl.java index e2382f875c7..014db59447d 100755 --- a/server/src/com/cloud/network/ExternalNetworkDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalNetworkDeviceManagerImpl.java @@ -25,7 +25,6 @@ import java.util.concurrent.ScheduledExecutorService; import javax.ejb.Local; import javax.inject.Inject; -import javax.naming.ConfigurationException; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.network.AddNetworkDeviceCmd; @@ -37,14 +36,7 @@ import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; -import com.cloud.api.ApiDBUtils; -import com.cloud.baremetal.ExternalDhcpManager; -import com.cloud.baremetal.PxeServerManager; -import com.cloud.baremetal.PxeServerManager.PxeServerType; -import com.cloud.baremetal.PxeServerProfile; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.DataCenter; -import com.cloud.dc.Pod; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.VlanDao; import com.cloud.host.Host; @@ -63,8 +55,6 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.VpnUserDao; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offerings.dao.NetworkOfferingDao; -import com.cloud.server.api.response.NwDeviceDhcpResponse; -import com.cloud.server.api.response.PxePingResponse; import com.cloud.user.AccountManager; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserStatisticsDao; @@ -77,8 +67,6 @@ import com.cloud.vm.dao.NicDao; @Local(value = {ExternalNetworkDeviceManager.class}) public class ExternalNetworkDeviceManagerImpl extends ManagerBase implements ExternalNetworkDeviceManager { - @Inject ExternalDhcpManager _dhcpMgr; - @Inject PxeServerManager _pxeMgr; @Inject AgentManager _agentMgr; @Inject NetworkModel _networkMgr; @Inject HostDao _hostDao; @@ -121,80 +109,12 @@ public class ExternalNetworkDeviceManagerImpl extends ManagerBase implements Ext Collection paramsCollection = paramList.values(); HashMap params = (HashMap) (paramsCollection.toArray())[0]; - if (cmd.getDeviceType().equalsIgnoreCase(NetworkDevice.ExternalDhcp.getName())) { - //Long zoneId = _identityService.getIdentityId("data_center", (String) params.get(ApiConstants.ZONE_ID)); - //Long podId = _identityService.getIdentityId("host_pod_ref", (String)params.get(ApiConstants.POD_ID)); - Long zoneId = Long.valueOf((String) params.get(ApiConstants.ZONE_ID)); - Long podId = Long.valueOf((String)params.get(ApiConstants.POD_ID)); - String type = (String) params.get(ApiConstants.DHCP_SERVER_TYPE); - String url = (String) params.get(ApiConstants.URL); - String username = (String) params.get(ApiConstants.USERNAME); - String password = (String) params.get(ApiConstants.PASSWORD); - - return _dhcpMgr.addDhcpServer(zoneId, podId, type, url, username, password); - } else if (cmd.getDeviceType().equalsIgnoreCase(NetworkDevice.PxeServer.getName())) { - Long zoneId = Long.parseLong((String) params.get(ApiConstants.ZONE_ID)); - Long podId = Long.parseLong((String)params.get(ApiConstants.POD_ID)); - //Long zoneId = _identityService.getIdentityId("data_center", (String) params.get(ApiConstants.ZONE_ID)); - //Long podId = _identityService.getIdentityId("host_pod_ref", (String)params.get(ApiConstants.POD_ID)); - String type = (String) params.get(ApiConstants.PXE_SERVER_TYPE); - String url = (String) params.get(ApiConstants.URL); - String username = (String) params.get(ApiConstants.USERNAME); - String password = (String) params.get(ApiConstants.PASSWORD); - String pingStorageServerIp = (String) params.get(ApiConstants.PING_STORAGE_SERVER_IP); - String pingDir = (String) params.get(ApiConstants.PING_DIR); - String tftpDir = (String) params.get(ApiConstants.TFTP_DIR); - String pingCifsUsername = (String) params.get(ApiConstants.PING_CIFS_USERNAME); - String pingCifsPassword = (String) params.get(ApiConstants.PING_CIFS_PASSWORD); - PxeServerProfile profile = new PxeServerProfile(zoneId, podId, url, username, password, type, pingStorageServerIp, pingDir, tftpDir, - pingCifsUsername, pingCifsPassword); - return _pxeMgr.addPxeServer(profile); - } else { - throw new CloudRuntimeException("Unsupported network device type:" + cmd.getDeviceType()); - } + return null; } @Override public NetworkDeviceResponse getApiResponse(Host device) { - NetworkDeviceResponse response; - HostVO host = (HostVO)device; - _hostDao.loadDetails(host); - if (host.getType() == Host.Type.ExternalDhcp) { - NwDeviceDhcpResponse r = new NwDeviceDhcpResponse(); - r.setZoneId(host.getDataCenterId()); - r.setPodId(host.getPodId()); - r.setUrl(host.getPrivateIpAddress()); - r.setType(host.getDetail("type")); - response = r; - } else if (host.getType() == Host.Type.PxeServer) { - String pxeType = host.getDetail("type"); - if (pxeType.equalsIgnoreCase(PxeServerType.PING.getName())) { - PxePingResponse r = new PxePingResponse(); - DataCenter zone = ApiDBUtils.findZoneById(host.getDataCenterId()); - if (zone != null) { - r.setZoneId(zone.getUuid()); - } - if (host.getPodId() != null) { - Pod pod = ApiDBUtils.findPodById(host.getPodId()); - if (pod != null) { - r.setPodId(pod.getUuid()); - } - } - r.setUrl(host.getPrivateIpAddress()); - r.setType(pxeType); - r.setStorageServerIp(host.getDetail("storageServer")); - r.setPingDir(host.getDetail("pingDir")); - r.setTftpDir(host.getDetail("tftpDir")); - response = r; - } else { - throw new CloudRuntimeException("Unsupported PXE server type:" + pxeType); - } - } else { - throw new CloudRuntimeException("Unsupported network device type:" + host.getType()); - } - - response.setId(device.getUuid()); - return response; + return null; } private List listNetworkDevice(Long zoneId, Long physicalNetworkId, Long podId, Host.Type type) { diff --git a/server/src/com/cloud/network/Ipv6AddressManagerImpl.java b/server/src/com/cloud/network/Ipv6AddressManagerImpl.java index ecef5a225e9..a401f9ae396 100644 --- a/server/src/com/cloud/network/Ipv6AddressManagerImpl.java +++ b/server/src/com/cloud/network/Ipv6AddressManagerImpl.java @@ -80,7 +80,7 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa } List vlans = _vlanDao.listVlansByNetworkId(networkId); if (vlans == null) { - s_logger.debug("Cannot find related vlan or too many vlan attached to network " + networkId); + s_logger.debug("Cannot find related vlan attached to network " + networkId); return null; } String ip = null; @@ -109,7 +109,7 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa } } if (ip == null) { - throw new InsufficientAddressCapacityException("Cannot find a usable IP in the network " + network.getName() + " after network.ipv6.search.retry.max = " + _ipv6RetryMax + " times retry!", + throw new InsufficientAddressCapacityException("Cannot find a usable IP in the network " + network.getName() + " after " + _ipv6RetryMax + "(network.ipv6.search.retry.max) times retry!", DataCenter.class, network.getDataCenterId()); } } else { diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 7a6ac276c50..1f7e1fda1eb 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -98,6 +98,7 @@ import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.network.element.DhcpServiceProvider; import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.IpDeployingRequester; import com.cloud.network.element.LoadBalancingServiceProvider; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.StaticNatServiceProvider; @@ -536,9 +537,11 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } IpDeployer deployer = null; NetworkElement element = _networkModel.getElementImplementingProvider(provider.getName()); - if (element instanceof IpDeployer) { - deployer = (IpDeployer) element; - } else { + if (!(element instanceof IpDeployingRequester)) { + throw new CloudRuntimeException("Element " + element + " is not a IpDeployingRequester!"); + } + deployer = ((IpDeployingRequester)element).getIpDeployer(network); + if (deployer == null) { throw new CloudRuntimeException("Fail to get ip deployer for element: " + element); } Set services = new HashSet(); @@ -1514,7 +1517,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { element.prepare(network, profile, vmProfile, dest, context); - if (vmProfile.getType() == Type.User && vmProfile.getHypervisorType() != HypervisorType.BareMetal && element.getProvider() != null) { + if (vmProfile.getType() == Type.User && element.getProvider() != null) { if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp) && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, element.getProvider()) && (element instanceof DhcpServiceProvider)) { @@ -3067,7 +3070,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } try { - if (!_lbMgr.applyRules(network, Purpose.LoadBalancing, lbs)) { + if (!_lbMgr.applyRules(network, Purpose.LoadBalancing, lbRules)) { s_logger.warn("Failed to cleanup lb rules as a part of shutdownNetworkRules"); success = false; } diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index ce48e84eb78..7b3717a161f 100644 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -75,6 +75,8 @@ import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.dao.UserIpv6AddressDao; +import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.IpDeployingRequester; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.rules.FirewallRule.Purpose; @@ -390,9 +392,18 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { throw new InvalidParameterException("There is no new provider for IP " + publicIp.getAddress() + " of service " + service.getName() + "!"); } Provider newProvider = (Provider) newProviders.toArray()[0]; - if (!oldProvider.equals(newProvider)) { - throw new InvalidParameterException("There would be multiple providers for IP " + publicIp.getAddress() + "!"); - } + Network network = _networksDao.findById(networkId); + NetworkElement oldElement = getElementImplementingProvider(oldProvider.getName()); + NetworkElement newElement = getElementImplementingProvider(newProvider.getName()); + if (oldElement instanceof IpDeployingRequester && newElement instanceof IpDeployingRequester) { + IpDeployer oldIpDeployer = ((IpDeployingRequester)oldElement).getIpDeployer(network); + IpDeployer newIpDeployer = ((IpDeployingRequester)newElement).getIpDeployer(network); + if (!oldIpDeployer.getProvider().getName().equals(newIpDeployer.getProvider().getName())) { + throw new InvalidParameterException("There would be multiple providers for IP " + publicIp.getAddress() + "!"); + } + } else { + throw new InvalidParameterException("Ip cannot be applied for new provider!"); + } return true; } @@ -557,6 +568,9 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Override public boolean isIP6AddressAvailableInVlan(long vlanId) { VlanVO vlan = _vlanDao.findById(vlanId); + if (vlan.getIp6Range() == null) { + return false; + } long existedCount = _ipv6Dao.countExistedIpsInVlan(vlanId); BigInteger existedInt = BigInteger.valueOf(existedCount); BigInteger rangeInt = NetUtils.countIp6InRange(vlan.getIp6Range()); @@ -1751,17 +1765,26 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Override public boolean networkIsConfiguredForExternalNetworking(long zoneId, long networkId) { - boolean netscalerInNetwork = isProviderForNetwork(Network.Provider.Netscaler, networkId); - boolean juniperInNetwork = isProviderForNetwork(Network.Provider.JuniperSRX, networkId); - boolean f5InNetwork = isProviderForNetwork(Network.Provider.F5BigIp, networkId); - - if (netscalerInNetwork || juniperInNetwork || f5InNetwork) { - return true; - } else { - return false; + List networkProviders = getNetworkProviders(networkId); + for(Provider provider : networkProviders){ + if(provider.isExternal()){ + return true; + } } + return false; } + private List getNetworkProviders(long networkId) { + List providerNames = _ntwkSrvcDao.getDistinctProviders(networkId); + Map providers = new HashMap(); + for (String providerName : providerNames) { + if(!providers.containsKey(providerName)){ + providers.put(providerName, Network.Provider.getProvider(providerName)); + } + } + + return new ArrayList(providers.values()); + } @Override public boolean configure(String name, Map params) throws ConfigurationException { @@ -1912,4 +1935,36 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { throw new InvalidParameterValueException("The cidr size of IPv6 network must be no less than 64 bits!"); } } + + @Override + public void checkRequestedIpAddresses(long networkId, String ip4, String ip6) throws InvalidParameterValueException { + if (ip4 != null) { + if (!NetUtils.isValidIp(ip4)) { + throw new InvalidParameterValueException("Invalid specified IPv4 address " + ip4); + } + //Other checks for ipv4 are done in assignPublicIpAddress() + } + if (ip6 != null) { + if (!NetUtils.isValidIpv6(ip6)) { + throw new InvalidParameterValueException("Invalid specified IPv6 address " + ip6); + } + if (_ipv6Dao.findByNetworkIdAndIp(networkId, ip6) != null) { + throw new InvalidParameterValueException("The requested IP is already taken!"); + } + List vlans = _vlanDao.listVlansByNetworkId(networkId); + if (vlans == null) { + throw new CloudRuntimeException("Cannot find related vlan attached to network " + networkId); + } + Vlan ipVlan = null; + for (Vlan vlan : vlans) { + if (NetUtils.isIp6InRange(ip6, vlan.getIp6Range())) { + ipVlan = vlan; + break; + } + } + if (ipVlan == null) { + throw new InvalidParameterValueException("Requested IPv6 is not in the predefined range!"); + } + } + } } diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 050a1feb412..ce527b7dbe7 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -66,6 +66,7 @@ import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.*; import com.cloud.network.IpAddress.State; +import com.cloud.vm.Nic; import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; @@ -333,6 +334,18 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { private boolean canIpsUseOffering(List publicIps, long offeringId) { Map> ipToServices = getIpToServices(publicIps, false, true); Map> serviceToProviders = _networkModel.getNetworkOfferingServiceProvidersMap(offeringId); + NetworkOfferingVO offering = _networkOfferingDao.findById(offeringId); + //For inline mode checking, using firewall provider for LB instead, because public ip would apply on firewall provider + if (offering.isInline()) { + Provider firewallProvider = null; + if (serviceToProviders.containsKey(Service.Firewall)) { + firewallProvider = (Provider)serviceToProviders.get(Service.Firewall).toArray()[0]; + } + Set p = new HashSet(); + p.add(firewallProvider); + serviceToProviders.remove(Service.Lb); + serviceToProviders.put(Service.Lb, p); + } for (PublicIp ip : ipToServices.keySet()) { Set services = ipToServices.get(ip); Provider provider = null; @@ -1479,7 +1492,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { @DB @ActionEvent(eventType = EventTypes.EVENT_NETWORK_UPDATE, eventDescription = "updating network", async = true) public Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr) { + User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr) { boolean restartNetwork = false; // verify input parameters @@ -1540,8 +1553,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { ex.addProxyObject(networkOffering, networkOfferingId, "networkOfferingId"); throw ex; } - - //can't update from vpc to non-vpc network offering boolean forVpcNew = _configMgr.isOfferingForVpc(networkOffering); boolean vorVpcOriginal = _configMgr.isOfferingForVpc(_configMgr.getNetworkOffering(oldNetworkOfferingId)); @@ -1573,6 +1584,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { networkOfferingChanged = true; } } + Map newSvcProviders = new HashMap(); if (networkOfferingChanged) { newSvcProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(_configMgr.getNetworkOffering(networkOfferingId), network.getPhysicalNetworkId()); @@ -1604,6 +1616,81 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { restartNetwork = true; } + //IP reservation checks + // allow reservation only to Isolated Guest networks + DataCenter dc = _dcDao.findById(network.getDataCenterId()); + String networkCidr = network.getNetworkCidr(); + + if (guestVmCidr!= null ) { + if(dc.getNetworkType() == NetworkType.Basic) { + throw new InvalidParameterValueException("Guest VM CIDR can't be specified for zone with " + NetworkType.Basic + " networking"); + } + if (network.getGuestType() != GuestType.Isolated) { + throw new InvalidParameterValueException("Can only allow IP Reservation in networks with guest type " + GuestType.Isolated); + } + if (networkOfferingChanged == true) { + throw new InvalidParameterValueException("Cannot specify this nework offering change and guestVmCidr at same time. Specify only one."); + } + if (!(network.getState() == Network.State.Implemented)) { + throw new InvalidParameterValueException ("The network must be in " + Network.State.Implemented + " state. IP Reservation cannot be applied in " + network.getState() + " state"); + } + if (!NetUtils.isValidCIDR(guestVmCidr)) { + throw new InvalidParameterValueException ("Invalid format of Guest VM CIDR."); + } + if (!NetUtils.validateGuestCidr(guestVmCidr)) { + throw new InvalidParameterValueException ("Invalid format of Guest VM CIDR. Make sure it is RFC1918 compliant. "); + } + + // If networkCidr is null it implies that there was no prior IP reservation, so the network cidr is network.getCidr() + // But in case networkCidr is a non null value (IP reservation already exists), it implies network cidr is networkCidr + if (networkCidr != null && ! NetUtils.isNetworkAWithinNetworkB(guestVmCidr, networkCidr)) { + throw new InvalidParameterValueException ("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR should be a subset of network CIDR : " + networkCidr); + } else { + if (! NetUtils.isNetworkAWithinNetworkB(guestVmCidr, network.getCidr())) { + throw new InvalidParameterValueException ("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR should be a subset of network CIDR : " + network.getCidr()); + } + } + + // This check makes sure there are no active IPs existing outside the guestVmCidr in the network + String[] guestVmCidrPair = guestVmCidr.split("\\/"); + Long size = Long.valueOf(guestVmCidrPair[1]); + List nicsPresent = _nicDao.listByNetworkId(networkId); + + String cidrIpRange[] = NetUtils.getIpRangeFromCidr(guestVmCidrPair[0], size); + s_logger.info("The start IP of the specified guest vm cidr is: " + cidrIpRange[0] +" and end IP is: " + cidrIpRange[1]); + long startIp = NetUtils.ip2Long(cidrIpRange[0]); + long endIp = NetUtils.ip2Long(cidrIpRange[1]); + long range = endIp - startIp + 1; + s_logger.info("The specified guest vm cidr has " + range + " IPs"); + + for (NicVO nic : nicsPresent) { + long nicIp = NetUtils.ip2Long(nic.getIp4Address()); + //check if nic IP is outside the guest vm cidr + if (nicIp < startIp || nicIp > endIp) { + if(!(nic.getState() == Nic.State.Deallocating)) { + throw new InvalidParameterValueException("Active IPs like " + nic.getIp4Address() + " exist outside the Guest VM CIDR. Cannot apply reservation "); + } + } + } + + // When reservation is applied for the first time, network_cidr will be null + // Populate it with the actual network cidr + if (network.getNetworkCidr() == null) { + network.setNetworkCidr(network.getCidr()); + } + + // Condition for IP Reservation reset : guestVmCidr and network CIDR are same + if (network.getNetworkCidr().equals(guestVmCidr)) { + s_logger.warn("Guest VM CIDR and Network CIDR both are same, reservation will reset."); + network.setNetworkCidr(null); + } + // Finally update "cidr" with the guestVmCidr + // which becomes the effective address space for CloudStack guest VMs + network.setCidr(guestVmCidr); + _networksDao.update(networkId, network); + s_logger.info("IP Reservation has been applied. The new CIDR for Guests Vms is " + guestVmCidr); + } + ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount); // 1) Shutdown all the elements and cleanup all the rules. Don't allow to shutdown network in intermediate // states - Shutdown and Implementing @@ -1623,6 +1710,15 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { // We need to shutdown the network, since we want to re-implement the network. s_logger.debug("Shutting down network id=" + networkId + " as a part of network update"); + //check if network has reservation + if(NetUtils.isNetworkAWithinNetworkB(network.getCidr(), network.getNetworkCidr())) { + s_logger.warn ("Existing IP reservation will become ineffective for the network with id = " + networkId + " You need to reapply reservation after network reimplementation."); + //set cidr to the newtork cidr + network.setCidr(network.getNetworkCidr()); + //set networkCidr to null to bring network back to no IP reservation state + network.setNetworkCidr(null); + } + if (!_networkMgr.shutdownNetwork(network.getId(), context, true)) { s_logger.warn("Failed to shutdown the network as a part of update to network with specified id"); CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network as a part of update of specified network id"); @@ -1643,7 +1739,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { boolean validStateToImplement = (networkState == Network.State.Implemented || networkState == Network.State.Setup || networkState == Network.State.Allocated); if (restartNetwork && !validStateToImplement) { CloudRuntimeException ex = new CloudRuntimeException("Failed to implement the network elements and resources as a part of update to network with specified id; network is in wrong state: " + networkState); - ex.addProxyObject(network, networkId, "networkId"); + ex.addProxyObject(network, networkId, "networkId"); throw ex; } @@ -1669,11 +1765,11 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { UsageEventUtils.saveUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getHostName(), networkOfferingId, null, isDefault); } txn.commit(); - } else { + } else { network.setNetworkOfferingId(networkOfferingId); _networksDao.update(networkId, network, _networkMgr.finalizeServicesAndProvidersForNetwork(_configMgr.getNetworkOffering(networkOfferingId), network.getPhysicalNetworkId())); } - } else { + } else { _networksDao.update(networkId, network); } @@ -1699,7 +1795,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { // 4) if network has been upgraded from a non persistent ntwk offering to a persistent ntwk offering, // implement the network if its not already - if ( !oldNtwkOff.getIsPersistent() && networkOffering.getIsPersistent()) { + if ( networkOfferingChanged && !oldNtwkOff.getIsPersistent() && networkOffering.getIsPersistent()) { if( network.getState() == Network.State.Allocated) { try { DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null); @@ -1719,7 +1815,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } - + protected Set getAvailableIps(Network network, String requestedIp) { String[] cidr = network.getCidr().split("/"); @@ -1925,7 +2021,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { addDefaultSecurityGroupProviderToPhysicalNetwork(pNetwork.getId()); // add VPCVirtualRouter as the defualt network service provider - addDefaultVpcVirtualRouterToPhysicalNetwork(pNetwork.getId()); + addDefaultVpcVirtualRouterToPhysicalNetwork(pNetwork.getId()); + + // add baremetal pxe/dhcp provider to the physical network + addDefaultBaremetalProvidersToPhysicalNetwork(pNetwork.getId()); txn.commit(); return pNetwork; @@ -2733,6 +2832,18 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { element.addElement(nsp.getId(), VirtualRouterProviderType.VirtualRouter); return nsp; + } + + + private PhysicalNetworkServiceProvider addDefaultBaremetalProvidersToPhysicalNetwork(long physicalNetworkId) { + PhysicalNetworkVO pvo = _physicalNetworkDao.findById(physicalNetworkId); + DataCenterVO dvo = _dcDao.findById(pvo.getDataCenterId()); + if (dvo.getNetworkType() == NetworkType.Basic) { + addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalDhcpProvider", null, null); + addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalPxeProvider", null, null); + addProviderToPhysicalNetwork(physicalNetworkId, "BaremetaUserdataProvider", null, null); + } + return null; } protected PhysicalNetworkServiceProvider addDefaultVpcVirtualRouterToPhysicalNetwork(long physicalNetworkId) { diff --git a/server/src/com/cloud/network/dao/NetworkVO.java b/server/src/com/cloud/network/dao/NetworkVO.java index d51a065ff83..77b40c8a5c9 100644 --- a/server/src/com/cloud/network/dao/NetworkVO.java +++ b/server/src/com/cloud/network/dao/NetworkVO.java @@ -81,6 +81,9 @@ public class NetworkVO implements Network { @Column(name="cidr") String cidr; + @Column(name="network_cidr") + String networkCidr; + @Column(name="network_offering_id") long networkOfferingId; @@ -198,6 +201,7 @@ public class NetworkVO implements Network { related, name, displayText, networkDomain, guestType, dcId, physicalNetworkId, aclType, specifyIpRanges, vpcId); this.gateway = that.getGateway(); this.cidr = that.getCidr(); + this.networkCidr = that.getNetworkCidr(); this.broadcastUri = that.getBroadcastUri(); this.broadcastDomainType = that.getBroadcastDomainType(); this.guruName = guruName; @@ -353,7 +357,10 @@ public class NetworkVO implements Network { public void setGateway(String gateway) { this.gateway = gateway; } - + // "cidr" is the Cloudstack managed address space, all CloudStack managed vms get IP address from "cidr" + // In general "cidr" also serves as the network cidr + // But in case IP reservation feature is configured for a Guest network, "network_cidr" is the Effective network cidr for the network, + // "cidr" will still continue to be the effective address space for CloudStack managed vms in that Guest network @Override public String getCidr() { return cidr; @@ -363,6 +370,18 @@ public class NetworkVO implements Network { this.cidr = cidr; } + // "networkcidr" is the network CIDR of the guest network which is configured with IP reservation feature + // It is the summation of "cidr" and the reservedIPrange(the address space used for non cloudstack purposes.) + // For networks not using IP reservation "networkcidr" is always null + @Override + public String getNetworkCidr() { + return networkCidr; + } + + public void setNetworkCidr(String networkCidr) { + this.networkCidr = networkCidr; + } + @Override public URI getBroadcastUri() { return broadcastUri; diff --git a/server/src/com/cloud/network/element/BareMetalElement.java b/server/src/com/cloud/network/element/BareMetalElement.java deleted file mode 100644 index 553fe1d63b2..00000000000 --- a/server/src/com/cloud/network/element/BareMetalElement.java +++ /dev/null @@ -1,128 +0,0 @@ -// 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.network.element; - -import java.util.Map; -import java.util.Set; - -import javax.ejb.Local; -import javax.inject.Inject; - -import org.apache.log4j.Logger; - -import com.cloud.baremetal.ExternalDhcpManager; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.host.Host; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.Network; -import com.cloud.network.Network.Capability; -import com.cloud.network.Network.Provider; -import com.cloud.network.Network.Service; -import com.cloud.network.PhysicalNetworkServiceProvider; -import com.cloud.offering.NetworkOffering; -import com.cloud.utils.component.AdapterBase; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Transaction; -import com.cloud.vm.NicProfile; -import com.cloud.vm.NicVO; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.dao.NicDao; - -@Local(value=NetworkElement.class) -public class BareMetalElement extends AdapterBase implements NetworkElement { - private static final Logger s_logger = Logger.getLogger(BareMetalElement.class); - @Inject NicDao _nicDao; - @Inject ExternalDhcpManager _dhcpMgr; - - @Override - public Map> getCapabilities() { - return null; - } - - @Override - public Provider getProvider() { - return null; - } - - @Override - public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) - throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { - return true; - } - - @Override @DB - public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, - ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { - Host host = dest.getHost(); - if (host == null || host.getHypervisorType() != HypervisorType.BareMetal) { - return true; - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - nic.setMacAddress(host.getPrivateMacAddress()); - NicVO vo = _nicDao.findById(nic.getId()); - assert vo != null : "Where ths nic " + nic.getId() + " going???"; - vo.setMacAddress(nic.getMacAddress()); - _nicDao.update(vo.getId(), vo); - txn.commit(); - s_logger.debug("Bare Metal changes mac address of nic " + nic.getId() + " to " + nic.getMacAddress()); - - return _dhcpMgr.addVirtualMachineIntoNetwork(network, nic, vm, dest, context); - } - - @Override - public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) - throws ConcurrentOperationException, ResourceUnavailableException { - return true; - } - - @Override - public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { - return true; - } - - @Override - public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { - return true; - } - - @Override - public boolean isReady(PhysicalNetworkServiceProvider provider) { - return true; - } - - @Override - public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { - return true; - } - - @Override - public boolean canEnableIndividualServices() { - return false; - } - - @Override - public boolean verifyServicesCombination(Set services) { - return true; - } -} diff --git a/server/src/com/cloud/network/element/ExternalDhcpElement.java b/server/src/com/cloud/network/element/ExternalDhcpElement.java deleted file mode 100755 index f7c465ddd35..00000000000 --- a/server/src/com/cloud/network/element/ExternalDhcpElement.java +++ /dev/null @@ -1,152 +0,0 @@ -// 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.network.element; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import javax.ejb.Local; -import javax.inject.Inject; - -import org.apache.log4j.Logger; - -import com.cloud.baremetal.ExternalDhcpManager; -import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.dc.Pod; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.host.Host; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.Network; -import com.cloud.network.Network.Capability; -import com.cloud.network.Network.GuestType; -import com.cloud.network.Network.Provider; -import com.cloud.network.Network.Service; -import com.cloud.network.Networks.TrafficType; -import com.cloud.network.PhysicalNetworkServiceProvider; -import com.cloud.offering.NetworkOffering; -import com.cloud.utils.component.AdapterBase; -import com.cloud.vm.NicProfile; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineProfile; - -@Local(value = NetworkElement.class) -public class ExternalDhcpElement extends AdapterBase implements NetworkElement, DhcpServiceProvider { - private static final Logger s_logger = Logger.getLogger(ExternalDhcpElement.class); - @Inject - ExternalDhcpManager _dhcpMgr; - private static final Map> capabilities = setCapabilities(); - - private boolean canHandle(DeployDestination dest, TrafficType trafficType, GuestType networkType) { - DataCenter dc = dest.getDataCenter(); - Pod pod = dest.getPod(); - - if ((pod != null && pod.getExternalDhcp()) && dc.getNetworkType() == NetworkType.Basic && trafficType == TrafficType.Guest - && networkType == Network.GuestType.Shared) { - s_logger.debug("External DHCP can handle"); - return true; - } - - return false; - } - - private static Map> setCapabilities() { - // No external dhcp support for Acton release - Map> capabilities = new HashMap>(); - //capabilities.put(Service.Dhcp, null); - return capabilities; - } - - @Override - public Map> getCapabilities() { - return capabilities; - } - - @Override - public Provider getProvider() { - return Provider.ExternalDhcpServer; - } - - @Override - public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) - throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { - if (!canHandle(dest, offering.getTrafficType(), network.getGuestType())) { - return false; - } - return true; - } - - @Override - public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, - ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { - return true; - } - - @Override - public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) - throws ConcurrentOperationException, ResourceUnavailableException { - return true; - } - - @Override - public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { - return true; - } - - @Override - public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { - return true; - } - - @Override - public boolean isReady(PhysicalNetworkServiceProvider provider) { - // TODO Auto-generated method stub - return true; - } - - @Override - public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { - // TODO Auto-generated method stub - return true; - } - - @Override - public boolean canEnableIndividualServices() { - return false; - } - - @Override - public boolean addDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) - throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { - Host host = dest.getHost(); - if (host.getHypervisorType() == HypervisorType.BareMetal || !canHandle(dest, network.getTrafficType(), network.getGuestType())) { - // BareMetalElement or DhcpElement handle this - return false; - } - return _dhcpMgr.addVirtualMachineIntoNetwork(network, nic, vm, dest, context); - } - - @Override - public boolean verifyServicesCombination(Set services) { - return true; - } -} diff --git a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java index 27b1a2a7a9a..aa8f10d9c2a 100644 --- a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java @@ -446,7 +446,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc Long vpcId = ip.getVpcId(); Vpc vpc = _vpcMgr.getVpc(vpcId); - if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId())) { + if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId(), Provider.VPCVirtualRouter.getName())) { throw new ResourceUnavailableException("VPC provider is not enabled in zone " + vpc.getZoneId(), DataCenter.class, vpc.getZoneId()); } @@ -474,7 +474,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc Long vpcId = ip.getVpcId(); Vpc vpc = _vpcMgr.getVpc(vpcId); - if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId())) { + if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId(), Provider.VPCVirtualRouter.getName())) { throw new ResourceUnavailableException("VPC provider is not enabled in zone " + vpc.getZoneId(), DataCenter.class, vpc.getZoneId()); } diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index d3b4c0beabf..080f7b0edf6 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -536,12 +536,23 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, switch (purpose){ case Firewall: for (FirewallServiceProvider fwElement: _firewallElements) { + Network.Provider provider = fwElement.getProvider(); + boolean isFwProvider = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Firewall, provider); + if (!isFwProvider) { + continue; + } handled = fwElement.applyFWRules(network, rules); if (handled) break; } + break; case PortForwarding: for (PortForwardingServiceProvider element: _pfElements) { + Network.Provider provider = element.getProvider(); + boolean isPfProvider = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.PortForwarding, provider); + if (!isPfProvider) { + continue; + } handled = element.applyPFRules(network, (List) rules); if (handled) break; @@ -549,6 +560,11 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, break; case StaticNat: for (StaticNatServiceProvider element: _staticNatElements) { + Network.Provider provider = element.getProvider(); + boolean isSnatProvider = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.StaticNat, provider); + if (!isSnatProvider) { + continue; + } handled = element.applyStaticNats(network, (List) rules); if (handled) break; @@ -556,6 +572,11 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, break; case NetworkACL: for (NetworkACLServiceProvider element: _networkAclElements) { + Network.Provider provider = element.getProvider(); + boolean isAclProvider = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.NetworkACL, provider); + if (!isAclProvider) { + continue; + } handled = element.applyNetworkACLs(network, rules); if (handled) break; diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/com/cloud/network/guru/GuestNetworkGuru.java index ab8a06958da..cc79d300788 100755 --- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java @@ -314,7 +314,12 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur long dcId = dest.getDataCenter().getId(); //get physical network id - long physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType()); + Long physicalNetworkId = network.getPhysicalNetworkId(); + + // physical network id can be null in Guest Network in Basic zone, so locate the physical network + if (physicalNetworkId == null) { + physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType()); + } NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), network.getBroadcastDomainType(), network.getNetworkOfferingId(), State.Allocated, diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 85e850c0b5a..531a42805b6 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -1158,6 +1158,11 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements assert(purpose == Purpose.LoadBalancing): "LB Manager asked to handle non-LB rules"; boolean handled = false; for (LoadBalancingServiceProvider lbElement: _lbProviders) { + Provider provider = lbElement.getProvider(); + boolean isLbProvider = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Lb, provider); + if (!isLbProvider) { + continue; + } handled = lbElement.applyLBRules(network, (List) rules); if (handled) break; diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index d7fe3e05d97..4d1968d9f94 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -341,11 +341,11 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian _agentMgr.send(dest.getHost().getId(), cmds); PlugNicAnswer plugNicAnswer = cmds.getAnswer(PlugNicAnswer.class); if (!(plugNicAnswer != null && plugNicAnswer.getResult())) { - s_logger.warn("Unable to plug nic for vm " + vm.getHostName()); + s_logger.warn("Unable to plug nic for vm " + vm.getName()); result = false; } } catch (OperationTimedoutException e) { - throw new AgentUnavailableException("Unable to plug nic for router " + vm.getHostName() + " in network " + network, + throw new AgentUnavailableException("Unable to plug nic for router " + vm.getName() + " in network " + network, dest.getHost().getId(), e); } } else { diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 0a00d22b42a..614d30820b4 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -412,7 +412,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules // Verify input parameters boolean performedIpAssoc = false; - boolean result = false; + boolean isOneToOneNat = ipAddress.isOneToOneNat(); + Long associatedWithVmId = ipAddress.getAssociatedWithVmId(); try { Network network = _networkModel.getNetwork(networkId); if (network == null) { @@ -476,28 +477,26 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules // enable static nat on the backend s_logger.trace("Enabling static nat for ip address " + ipAddress + " and vm id=" + vmId + " on the backend"); if (applyStaticNatForIp(ipId, false, caller, false)) { - result = true; + performedIpAssoc = false; // ignor unassignIPFromVpcNetwork in finally block + return true; } else { s_logger.warn("Failed to enable static nat rule for ip address " + ipId + " on the backend"); + ipAddress.setOneToOneNat(isOneToOneNat); + ipAddress.setAssociatedWithVmId(associatedWithVmId); + _ipAddressDao.update(ipAddress.getId(), ipAddress); } } else { s_logger.warn("Failed to update ip address " + ipAddress + " in the DB as a part of enableStaticNat"); } } finally { - if (!result) { - ipAddress.setOneToOneNat(false); - ipAddress.setAssociatedWithVmId(null); - _ipAddressDao.update(ipAddress.getId(), ipAddress); - - if (performedIpAssoc) { - //if the rule is the last one for the ip address assigned to VPC, unassign it from the network - IpAddress ip = _ipAddressDao.findById(ipAddress.getId()); - _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), networkId); - } + if (performedIpAssoc) { + //if the rule is the last one for the ip address assigned to VPC, unassign it from the network + IpAddress ip = _ipAddressDao.findById(ipAddress.getId()); + _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), networkId); } } - return result; + return false; } protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress, Account caller, long callerUserId) diff --git a/server/src/com/cloud/network/vpc/VpcManager.java b/server/src/com/cloud/network/vpc/VpcManager.java index 8d49aa1615c..714330dd5aa 100644 --- a/server/src/com/cloud/network/vpc/VpcManager.java +++ b/server/src/com/cloud/network/vpc/VpcManager.java @@ -71,9 +71,10 @@ public interface VpcManager extends VpcService{ /** * @param zoneId + * @param provider * @return */ - boolean vpcProviderEnabledInZone(long zoneId); + boolean vpcProviderEnabledInZone(long zoneId, String provider); /** * @param vpcId diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 7197c363264..c9c13c97199 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -31,6 +31,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.element.StaticNatServiceProvider; import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -84,6 +85,7 @@ import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.dao.VpcGatewayDao; import com.cloud.network.vpc.dao.VpcOfferingDao; import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.network.vpc.dao.VpcServiceMapDao; import com.cloud.network.vpn.Site2SiteVpnManager; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingServiceMapVO; @@ -173,10 +175,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ VlanDao _vlanDao = null; @Inject ResourceLimitService _resourceLimitMgr; - + @Inject + VpcServiceMapDao _vpcSrvcDao; private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker")); - private VpcProvider vpcElement = null; + private List vpcElements = null; private final List nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall); int _cleanupInterval; @@ -255,7 +258,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_CREATE, eventDescription = "creating vpc offering", create=true) - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices) { + public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders) { Map> svcProviderMap = new HashMap>(); Set defaultProviders = new HashSet(); defaultProviders.add(Provider.VPCVirtualRouter); @@ -291,7 +294,34 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } svcProviderMap.put(Service.Gateway, defaultProviders); - + + if (serviceProviders != null) { + for (String serviceStr : serviceProviders.keySet()) { + Network.Service service = Network.Service.getService(serviceStr); + if (svcProviderMap.containsKey(service)) { + Set providers = new HashSet(); + // don't allow to specify more than 1 provider per service + if (serviceProviders.get(serviceStr) != null && serviceProviders.get(serviceStr).size() > 1) { + throw new InvalidParameterValueException("In the current release only one provider can be " + + "specified for the service"); + } + for (String prvNameStr : serviceProviders.get(serviceStr)) { + // check if provider is supported + Network.Provider provider = Network.Provider.getProvider(prvNameStr); + if (provider == null) { + throw new InvalidParameterValueException("Invalid service provider: " + prvNameStr); + } + + providers.add(provider); + } + svcProviderMap.put(service, providers); + } else { + throw new InvalidParameterValueException("Service " + serviceStr + " is not enabled for the network " + + "offering, can't add a provider to it"); + } + } + } + VpcOffering offering = createVpcOffering(name, displayText, svcProviderMap, false, null); UserContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name); @@ -556,11 +586,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } @Override - public boolean vpcProviderEnabledInZone(long zoneId) + public boolean vpcProviderEnabledInZone(long zoneId, String provider) { //the provider has to be enabled at least in one network in the zone for (PhysicalNetwork pNtwk : _pNtwkDao.listByZone(zoneId)) { - if (_ntwkModel.isProviderEnabledInPhysicalNetwork(pNtwk.getId(), Provider.VPCVirtualRouter.getName())) { + if (_ntwkModel.isProviderEnabledInPhysicalNetwork(pNtwk.getId(), provider)) { return true; } } @@ -573,11 +603,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ protected Vpc createVpc(long zoneId, long vpcOffId, Account vpcOwner, String vpcName, String displayText, String cidr, String networkDomain) { - if (!vpcProviderEnabledInZone(zoneId)) { - throw new InvalidParameterValueException("Provider " + Provider.VPCVirtualRouter.getName() + - " should be enabled in at least one physical network of the zone specified"); - } - //Validate CIDR if (!NetUtils.isValidCIDR(cidr)) { throw new InvalidParameterValueException("Invalid CIDR specified " + cidr); @@ -601,7 +626,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ txn.start(); VpcVO vpc = new VpcVO (zoneId, vpcName, displayText, vpcOwner.getId(), vpcOwner.getDomainId(), vpcOffId, cidr, networkDomain); - vpc = _vpcDao.persist(vpc); + vpc = _vpcDao.persist(vpc, finalizeServicesAndProvidersForVpc(zoneId, vpcOffId)); _resourceLimitMgr.incrementResourceCount(vpcOwner.getId(), ResourceType.vpc); txn.commit(); @@ -609,7 +634,44 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ return vpc; } - + + private Map finalizeServicesAndProvidersForVpc(long zoneId, long offeringId) { + Map svcProviders = new HashMap(); + Map> providerSvcs = new HashMap>(); + List servicesMap = _vpcOffSvcMapDao.listByVpcOffId(offeringId); + + for (VpcOfferingServiceMapVO serviceMap : servicesMap) { + if (svcProviders.containsKey(serviceMap.getService())) { + // FIXME - right now we pick up the first provider from the list, need to add more logic based on + // provider load, etc + continue; + } + + String service = serviceMap.getService(); + String provider = serviceMap.getProvider(); + + if (provider == null) { + // Default to VPCVirtualRouter + provider = Provider.VPCVirtualRouter.getName(); + } + + + if (!vpcProviderEnabledInZone(zoneId, provider)) { + throw new InvalidParameterValueException("Provider " + provider + + " should be enabled in at least one physical network of the zone specified"); + } + + svcProviders.put(service, provider); + List l = providerSvcs.get(provider); + if (l == null) { + providerSvcs.put(provider, l = new ArrayList()); + } + l.add(service); + } + + return svcProviders; + } + @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_DELETE, eventDescription = "deleting VPC") public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException { @@ -903,13 +965,19 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ protected boolean startVpc(Vpc vpc, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { //deploy provider - if (getVpcElement().implementVpc(vpc, dest, context)) { - s_logger.debug("Vpc " + vpc + " has started succesfully"); - return true; - } else { - s_logger.warn("Vpc " + vpc + " failed to start"); - return false; + boolean success = true; + List providersToImplement = getVpcProviders(vpc.getId()); + for (VpcProvider element: getVpcElements()){ + if(providersToImplement.contains(element.getProvider())){ + if (element.implementVpc(vpc, dest, context)) { + s_logger.debug("Vpc " + vpc + " has started succesfully"); + } else { + s_logger.warn("Vpc " + vpc + " failed to start"); + success = false; + } + } } + return success; } @Override @@ -928,15 +996,22 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ //shutdown provider s_logger.debug("Shutting down vpc " + vpc); - ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(ctx.getCallerUserId()), caller); - boolean success = getVpcElement().shutdownVpc(vpc, context); - //TODO - shutdown all vpc resources here (ACLs, gateways, etc) - if (success) { - s_logger.debug("Vpc " + vpc + " has been shutdown succesfully"); - } else { - s_logger.warn("Vpc " + vpc + " failed to shutdown"); + + boolean success = true; + List providersToImplement = getVpcProviders(vpc.getId()); + ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(ctx.getCallerUserId()), caller); + for (VpcProvider element: getVpcElements()){ + if(providersToImplement.contains(element.getProvider())){ + if (element.shutdownVpc(vpc, context)) { + s_logger.debug("Vpc " + vpc + " has been shutdown succesfully"); + } else { + s_logger.warn("Vpc " + vpc + " failed to shutdown"); + success = false; + } + } } + return success; } @@ -1085,16 +1160,18 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } - protected VpcProvider getVpcElement() { - if (vpcElement == null) { - vpcElement = ((VpcProvider)_ntwkModel.getElementImplementingProvider(Provider.VPCVirtualRouter.getName())); + protected List getVpcElements() { + if (vpcElements == null) { + vpcElements = new ArrayList(); + vpcElements.add((VpcProvider)_ntwkModel.getElementImplementingProvider(Provider.VPCVirtualRouter.getName())); + vpcElements.add((VpcProvider)_ntwkModel.getElementImplementingProvider(Provider.VPCNetscaler.getName())); } - if (vpcElement == null) { - throw new CloudRuntimeException("Failed to initialize vpc element"); + if (vpcElements == null) { + throw new CloudRuntimeException("Failed to initialize vpc elements"); } - - return vpcElement; + + return vpcElements; } @Override @@ -1233,13 +1310,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ ex.addProxyObject("vpc", vpcId, "VPC"); throw ex; } - - //allow only one private gateway per vpc - VpcGatewayVO gatewayVO = _vpcGatewayDao.getPrivateGatewayForVpc(vpcId); - if (gatewayVO != null) { - throw new InvalidParameterValueException("Private ip address already exists for vpc " + vpc); - } - + //Validate physical network if (physicalNetworkId == null) { List pNtwks = _ntwkModel.getPhysicalNtwksSupportingTrafficType(vpc.getZoneId(), TrafficType.Guest); @@ -1258,7 +1329,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ vlan, ipAddress, null, gateway, netmask, gatewayOwnerId, vpcId); //2) create gateway entry - gatewayVO = new VpcGatewayVO(ipAddress, VpcGateway.Type.Private, vpcId, privateNtwk.getDataCenterId(), + VpcGatewayVO gatewayVO = new VpcGatewayVO(ipAddress, VpcGateway.Type.Private, vpcId, privateNtwk.getDataCenterId(), privateNtwk.getId(), vlan, gateway, netmask, vpc.getAccountId(), vpc.getDomainId()); _vpcGatewayDao.persist(gatewayVO); @@ -1274,10 +1345,14 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ public PrivateGateway applyVpcPrivateGateway(long gatewayId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException { VpcGatewayVO vo = _vpcGatewayDao.findById(gatewayId); - boolean success = false; + boolean success = true; try { PrivateGateway gateway = getVpcPrivateGateway(gatewayId); - success = getVpcElement().createPrivateGateway(gateway); + for (VpcProvider provider: getVpcElements()){ + if(!provider.createPrivateGateway(gateway)){ + success = false; + } + } if (success) { s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend"); if (vo.getState() != VpcGateway.State.Ready) { @@ -1333,11 +1408,13 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ //1) delete the gateway on the backend PrivateGateway gateway = getVpcPrivateGateway(gatewayId); - if (getVpcElement().deletePrivateGateway(gateway)) { - s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend"); - } else { - s_logger.warn("Private gateway " + gateway + " failed to apply on the backend"); - return false; + for (VpcProvider provider: getVpcElements()){ + if (provider.deletePrivateGateway(gateway)) { + s_logger.debug("Private gateway " + gateway + " was applied succesfully on the backend"); + } else { + s_logger.warn("Private gateway " + gateway + " failed to apply on the backend"); + return false; + } } //2) Delete private gateway from the DB @@ -1505,11 +1582,19 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ Vpc vpc = getVpc(routes.get(0).getVpcId()); s_logger.debug("Applying static routes for vpc " + vpc); - if (getVpcElement().applyStaticRoutes(vpc, routes)) { - s_logger.debug("Applied static routes for vpc " + vpc); - } else { - s_logger.warn("Failed to apply static routes for vpc " + vpc); - return false; + String staticNatProvider = _vpcSrvcDao.getProviderForServiceInVpc(vpc.getId(), Service.StaticNat); + + for (VpcProvider provider: getVpcElements()){ + if (!(provider instanceof StaticNatServiceProvider && provider.getName().equalsIgnoreCase(staticNatProvider))) { + continue; + } + + if (provider.applyStaticRoutes(vpc, routes)) { + s_logger.debug("Applied static routes for vpc " + vpc); + } else { + s_logger.warn("Failed to apply static routes for vpc " + vpc); + return false; + } } return true; @@ -1941,7 +2026,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ @Override public Network updateVpcGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long ntwkOffId, Boolean changeCidr) { + User callerUser, String domainSuffix, Long ntwkOffId, Boolean changeCidr, String guestVmCidr) { NetworkVO network = _ntwkDao.findById(networkId); if (network == null) { throw new InvalidParameterValueException("Couldn't find network by id"); @@ -1953,7 +2038,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } return _ntwkSvc.updateGuestNetwork(networkId, name, displayText, callerAccount, callerUser, domainSuffix, - ntwkOffId, changeCidr); + ntwkOffId, changeCidr, guestVmCidr); } @Override @@ -1964,4 +2049,16 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ hTypes.add(HypervisorType.KVM); return hTypes; } + + private List getVpcProviders(long vpcId) { + List providerNames = _vpcSrvcDao.getDistinctProviders(vpcId); + Map providers = new HashMap(); + for (String providerName : providerNames) { + if(!providers.containsKey(providerName)){ + providers.put(providerName, Network.Provider.getProvider(providerName)); + } + } + + return new ArrayList(providers.values()); + } } diff --git a/server/src/com/cloud/network/vpc/VpcServiceMapVO.java b/server/src/com/cloud/network/vpc/VpcServiceMapVO.java new file mode 100644 index 00000000000..6f229096404 --- /dev/null +++ b/server/src/com/cloud/network/vpc/VpcServiceMapVO.java @@ -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.network.vpc; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name="vpc_service_map") +public class VpcServiceMapVO { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + long id; + + @Column(name="vpc_id") + long vpcId; + + @Column(name="service") + String service; + + @Column(name="provider") + String provider; + + @Column(name=GenericDao.CREATED_COLUMN) + Date created; + + public long getId() { + return id; + } + + public long getVpcId() { + return vpcId; + } + + public String getService() { + return service; + } + + public String getProvider() { + return provider; + } + + public Date getCreated() { + return created; + } + + public VpcServiceMapVO() { + } + + public VpcServiceMapVO(long vpcId, Service service, Provider provider) { + this.vpcId = vpcId; + this.service = service.getName(); + this.provider = provider.getName(); + } + + public String toString() { + StringBuilder buf = new StringBuilder("[VPC Service["); + return buf.append(vpcId).append("-").append(service).append("-").append(provider).append("]").toString(); + } +} + + + + + diff --git a/server/src/com/cloud/network/vpc/dao/VpcDao.java b/server/src/com/cloud/network/vpc/dao/VpcDao.java index 80e5e15f9c0..5a33217c028 100644 --- a/server/src/com/cloud/network/vpc/dao/VpcDao.java +++ b/server/src/com/cloud/network/vpc/dao/VpcDao.java @@ -17,6 +17,7 @@ package com.cloud.network.vpc.dao; import java.util.List; +import java.util.Map; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcVO; @@ -39,4 +40,8 @@ public interface VpcDao extends GenericDao{ long countByAccountId(long accountId); + VpcVO persist(VpcVO vpc, Map serviceProviderMap); + + void persistVpcServiceProviders(long vpcId, + Map serviceProviderMap); } diff --git a/server/src/com/cloud/network/vpc/dao/VpcDaoImpl.java b/server/src/com/cloud/network/vpc/dao/VpcDaoImpl.java index a9b5e182b60..5fdf27972a2 100644 --- a/server/src/com/cloud/network/vpc/dao/VpcDaoImpl.java +++ b/server/src/com/cloud/network/vpc/dao/VpcDaoImpl.java @@ -17,10 +17,13 @@ package com.cloud.network.vpc.dao; import java.util.List; +import java.util.Map; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.network.Network; +import com.cloud.network.vpc.VpcServiceMapVO; import org.springframework.stereotype.Component; import com.cloud.network.vpc.Vpc; @@ -45,6 +48,7 @@ public class VpcDaoImpl extends GenericDaoBase implements VpcDao{ final SearchBuilder AllFieldsSearch; final GenericSearchBuilder CountByAccountId; @Inject ResourceTagsDaoImpl _tagsDao; + @Inject VpcServiceMapDaoImpl _vpcSvcMap; protected VpcDaoImpl() { super(); @@ -120,5 +124,28 @@ public class VpcDaoImpl extends GenericDaoBase implements VpcDao{ List results = customSearch(sc, null); return results.get(0); } + + @Override + @DB + public VpcVO persist(VpcVO vpc, Map serviceProviderMap) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + VpcVO newVpc = super.persist(vpc); + persistVpcServiceProviders(vpc.getId(), serviceProviderMap); + txn.commit(); + return newVpc; + } + + @Override + @DB + public void persistVpcServiceProviders(long vpcId, Map serviceProviderMap) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + for (String service : serviceProviderMap.keySet()) { + VpcServiceMapVO serviceMap = new VpcServiceMapVO(vpcId, Network.Service.getService(service), Network.Provider.getProvider(serviceProviderMap.get(service))); + _vpcSvcMap.persist(serviceMap); + } + txn.commit(); + } } diff --git a/server/src/com/cloud/network/vpc/dao/VpcServiceMapDao.java b/server/src/com/cloud/network/vpc/dao/VpcServiceMapDao.java new file mode 100644 index 00000000000..8c4537ede4e --- /dev/null +++ b/server/src/com/cloud/network/vpc/dao/VpcServiceMapDao.java @@ -0,0 +1,40 @@ +// 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.network.vpc.dao; + +import java.util.List; + +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.dao.NetworkServiceMapVO; +import com.cloud.network.vpc.VpcServiceMapVO; +import com.cloud.utils.db.GenericDao; + +/** + * VpcServiceMapDao deals with searches and operations done on the + * vpc_service_map table. + * + */ +public interface VpcServiceMapDao extends GenericDao{ + boolean areServicesSupportedInVpc(long vpcId, Service... services); + boolean canProviderSupportServiceInVpc(long vpcId, Service service, Provider provider); + List getServicesInVpc(long vpcId); + String getProviderForServiceInVpc(long vpcId, Service service); + void deleteByVpcId(long vpcId); + List getDistinctProviders(long vpcId); + String isProviderForVpc(long vpcId, Provider provider); +} \ No newline at end of file diff --git a/server/src/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java b/server/src/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java new file mode 100644 index 00000000000..a992181f864 --- /dev/null +++ b/server/src/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java @@ -0,0 +1,115 @@ +// 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.network.vpc.dao; + +import java.util.List; + +import javax.ejb.Local; + +import com.cloud.exception.UnsupportedServiceException; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.dao.NetworkServiceMapVO; +import com.cloud.network.vpc.VpcServiceMapVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; + +@Component +@Local(value=VpcServiceMapDao.class) @DB(txn=false) +public class VpcServiceMapDaoImpl extends GenericDaoBase implements VpcServiceMapDao { + final SearchBuilder AllFieldsSearch; + final SearchBuilder MultipleServicesSearch; + final GenericSearchBuilder DistinctProvidersSearch; + + protected VpcServiceMapDaoImpl(){ + super(); + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("service", AllFieldsSearch.entity().getService(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("provider", AllFieldsSearch.entity().getProvider(), SearchCriteria.Op.EQ); + AllFieldsSearch.done(); + + MultipleServicesSearch = createSearchBuilder(); + MultipleServicesSearch.and("vpcId", MultipleServicesSearch.entity().getVpcId(), SearchCriteria.Op.EQ); + MultipleServicesSearch.and("service", MultipleServicesSearch.entity().getService(), SearchCriteria.Op.IN); + MultipleServicesSearch.and("provider", MultipleServicesSearch.entity().getProvider(), SearchCriteria.Op.EQ); + MultipleServicesSearch.done(); + + DistinctProvidersSearch = createSearchBuilder(String.class); + DistinctProvidersSearch.and("vpcId", DistinctProvidersSearch.entity().getVpcId(), SearchCriteria.Op.EQ); + DistinctProvidersSearch.and("provider", DistinctProvidersSearch.entity().getProvider(), SearchCriteria.Op.EQ); + DistinctProvidersSearch.selectField(DistinctProvidersSearch.entity().getProvider()); + DistinctProvidersSearch.done(); + } + + @Override + public boolean areServicesSupportedInVpc(long vpcId, Service... services) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean canProviderSupportServiceInVpc(long vpcId, Service service, + Provider provider) { + // TODO Auto-generated method stub + return false; + } + + @Override + public List getServicesInVpc(long vpcId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getProviderForServiceInVpc(long vpcId, Service service) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vpcId", vpcId); + sc.setParameters("service", service.getName()); + VpcServiceMapVO ntwkSvc = findOneBy(sc); + if (ntwkSvc == null) { + throw new UnsupportedServiceException("Service " + service.getName() + " is not supported in the vpc id=" + vpcId); + } + + return ntwkSvc.getProvider(); + } + + @Override + public void deleteByVpcId(long vpcId) { + // TODO Auto-generated method stub + + } + + @Override + public List getDistinctProviders(long vpcId) { + SearchCriteria sc = DistinctProvidersSearch.create(); + sc.setParameters("vpcId", vpcId); + List results = customSearch(sc, null); + return results; + } + + @Override + public String isProviderForVpc(long vpcId, Provider provider) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/server/src/com/cloud/resource/DiscovererBase.java b/server/src/com/cloud/resource/DiscovererBase.java index 940608c4419..b7c5b6f58de 100644 --- a/server/src/com/cloud/resource/DiscovererBase.java +++ b/server/src/com/cloud/resource/DiscovererBase.java @@ -128,6 +128,7 @@ public abstract class DiscovererBase extends AdapterBase implements Discoverer { params.put("secondary.storage.vm", "false"); params.put("max.template.iso.size", _configDao.getValue(Config.MaxTemplateAndIsoSize.toString())); params.put("migratewait", _configDao.getValue(Config.MigrateWait.toString())); + params.put(Config.XenMaxNics.toString().toLowerCase(), _configDao.getValue(Config.XenMaxNics.toString())); return params; } diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 82013d4380d..14628c1fe8d 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -30,6 +30,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.*; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; @@ -44,6 +45,7 @@ import org.apache.cloudstack.api.command.admin.storage.AddS3Cmd; import org.apache.cloudstack.api.command.admin.storage.ListS3sCmd; import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -71,12 +73,6 @@ import com.cloud.cluster.ManagementServerNode; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.DataCenterIpAddressVO; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.HostPodVO; -import com.cloud.dc.PodCluster; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.ClusterVSMMapDao; import com.cloud.dc.dao.DataCenterDao; @@ -116,7 +112,6 @@ import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StorageService; import com.cloud.storage.Swift; import com.cloud.storage.SwiftVO; @@ -483,6 +478,11 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, clusterId = cluster.getId(); result.add(cluster); + ClusterDetailsVO cluster_detail_cpu = new ClusterDetailsVO(clusterId, "cpuOvercommitRatio", Float.toString(cmd.getCpuOvercommitRatio())); + ClusterDetailsVO cluster_detail_ram = new ClusterDetailsVO(clusterId, "memoryOvercommitRatio", Float.toString(cmd.getMemoryOvercommitRaito())); + _clusterDetailsDao.persist(cluster_detail_cpu); + _clusterDetailsDao.persist(cluster_detail_ram); + if (clusterType == Cluster.ClusterType.CloudManaged) { return result; } @@ -494,6 +494,21 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, details.put("password", password); _clusterDetailsDao.persist(cluster.getId(), details); + _clusterDetailsDao.persist(cluster_detail_cpu); + _clusterDetailsDao.persist(cluster_detail_ram); + //create a new entry only if the overcommit ratios are greater than 1. + if(cmd.getCpuOvercommitRatio().compareTo(1f) > 0) { + cluster_detail_cpu = new ClusterDetailsVO(clusterId, "cpuOvercommitRatio", Float.toString(cmd.getCpuOvercommitRatio())); + _clusterDetailsDao.persist(cluster_detail_cpu); + } + + + if(cmd.getMemoryOvercommitRaito().compareTo(1f) > 0) { + cluster_detail_ram = new ClusterDetailsVO(clusterId, "memoryOvercommitRatio", Float.toString(cmd.getMemoryOvercommitRaito())); + _clusterDetailsDao.persist(cluster_detail_ram); + } + + boolean success = false; try { try { @@ -1061,7 +1076,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @Override @DB public Cluster updateCluster(Cluster clusterToUpdate, String clusterType, - String hypervisor, String allocationState, String managedstate) { + String hypervisor, String allocationState, String managedstate,Float memoryovercommitratio, Float cpuovercommitratio) { ClusterVO cluster = (ClusterVO) clusterToUpdate; // Verify cluster information and update the cluster if needed @@ -1144,6 +1159,31 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } } + ClusterDetailsVO memory_detail = _clusterDetailsDao.findDetail(cluster.getId(),"memoryOvercommitRatio"); + if( memory_detail == null){ + if (memoryovercommitratio.compareTo(1f) > 0){ + memory_detail = new ClusterDetailsVO(cluster.getId(),"memoryOvercommitRatio",Float.toString(memoryovercommitratio)); + _clusterDetailsDao.persist(memory_detail); + } + } + else { + memory_detail.setValue(Float.toString(memoryovercommitratio)); + _clusterDetailsDao.update(memory_detail.getId(),memory_detail); + } + + ClusterDetailsVO cpu_detail = _clusterDetailsDao.findDetail(cluster.getId(),"cpuOvercommitRatio"); + if( cpu_detail == null){ + if (cpuovercommitratio.compareTo(1f) > 0){ + cpu_detail = new ClusterDetailsVO(cluster.getId(),"cpuOvercommitRatio",Float.toString(cpuovercommitratio)); + _clusterDetailsDao.persist(cpu_detail); + } + } + else { + cpu_detail.setValue(Float.toString(cpuovercommitratio)); + _clusterDetailsDao.update(cpu_detail.getId(),cpu_detail); + } + + if (doUpdate) { Transaction txn = Transaction.currentTxn(); try { @@ -2223,20 +2263,22 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, User caller = _accountMgr.getActiveUser(UserContext.current() .getCallerUserId()); - if (forceDestroyStorage) { - // put local storage into mainenance mode, will set all the VMs on - // this local storage into stopped state - StoragePool storagePool = _storageMgr.findLocalStorageOnHost(host + + if (forceDestroyStorage) { + // put local storage into mainenance mode, will set all the VMs on + // this local storage into stopped state + StoragePoolVO storagePool = _storageMgr.findLocalStorageOnHost(host .getId()); if (storagePool != null) { if (storagePool.getStatus() == StoragePoolStatus.Up || storagePool.getStatus() == StoragePoolStatus.ErrorInMaintenance) { - try { - storagePool = _storageSvr + try { + StoragePool pool = _storageSvr .preparePrimaryStorageForMaintenance(storagePool .getId()); - if (storagePool == null) { - s_logger.debug("Failed to set primary storage into maintenance mode"); + if (pool == null) { + s_logger.debug("Failed to set primary storage into maintenance mode"); + throw new UnableDeleteHostException( "Failed to set primary storage into maintenance mode"); } @@ -2361,7 +2403,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, ResourceState.Event.AdminCancelMaintenance, _nodeId); _agentMgr.pullAgentOutMaintenance(hostId); - // for kvm, need to log into kvm host, restart cloud-agent + // for kvm, need to log into kvm host, restart cloudstack-agent if (host.getHypervisorType() == HypervisorType.KVM) { _hostDao.loadDetails(host); String password = host.getDetail("password"); @@ -2382,7 +2424,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, try { SSHCmdHelper.sshExecuteCmdOneShot(connection, - "service cloud-agent restart"); + "service cloudstack-agent restart"); } catch (sshException e) { return false; } diff --git a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index 7419690244f..7ff06af9409 100755 --- a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -29,10 +29,10 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.acl.SecurityChecker.AccessType; import com.cloud.alert.AlertManager; import com.cloud.configuration.Config; import com.cloud.configuration.Resource; @@ -59,9 +59,12 @@ import com.cloud.projects.Project; import com.cloud.projects.ProjectAccount.Role; import com.cloud.projects.dao.ProjectAccountDao; import com.cloud.projects.dao.ProjectDao; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeDaoImpl.SumCount; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountVO; @@ -69,15 +72,21 @@ import com.cloud.user.ResourceLimitService; import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.utils.NumbersUtil; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @@ -124,6 +133,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim private NetworkDao _networkDao; @Inject private VpcDao _vpcDao; + @Inject + private ServiceOfferingDao _serviceOfferingDao; protected SearchBuilder ResourceCountSearch; ScheduledExecutorService _rcExecutor; @@ -165,6 +176,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim projectResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVolumes.key()))); projectResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectNetworks.key()))); projectResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVpcs.key()))); + projectResourceLimitMap.put(Resource.ResourceType.cpu, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectCpus.key()))); + projectResourceLimitMap.put(Resource.ResourceType.memory, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectMemory.key()))); accountResourceLimitMap.put(Resource.ResourceType.public_ip, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPublicIPs.key()))); accountResourceLimitMap.put(Resource.ResourceType.snapshot, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountSnapshots.key()))); @@ -173,6 +186,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim accountResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVolumes.key()))); accountResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountNetworks.key()))); accountResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVpcs.key()))); + accountResourceLimitMap.put(Resource.ResourceType.cpu, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountCpus.key()))); + accountResourceLimitMap.put(Resource.ResourceType.memory, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountMemory.key()))); return true; } @@ -769,7 +784,11 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim } else if (type == Resource.ResourceType.network) { newCount = _networkDao.countNetworksUserCanCreate(accountId); } else if (type == Resource.ResourceType.vpc) { - newCount = _vpcDao.countByAccountId(accountId); + newCount = _vpcDao.countByAccountId(accountId); + } else if (type == Resource.ResourceType.cpu) { + newCount = countCpusForAccount(accountId); + } else if (type == Resource.ResourceType.memory) { + newCount = calculateMemoryForAccount(accountId); } else { throw new InvalidParameterValueException("Unsupported resource type " + type); } @@ -784,6 +803,50 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim return (newCount == null) ? 0 : newCount.longValue(); } + public long countCpusForAccount(long accountId) { + GenericSearchBuilder cpuSearch = _serviceOfferingDao.createSearchBuilder(SumCount.class); + cpuSearch.select("sum", Func.SUM, cpuSearch.entity().getCpu()); + SearchBuilder join1 = _userVmDao.createSearchBuilder(); + join1.and("accountId", join1.entity().getAccountId(), Op.EQ); + join1.and("type", join1.entity().getType(), Op.EQ); + join1.and("state", join1.entity().getState(), SearchCriteria.Op.NIN); + cpuSearch.join("offerings", join1, cpuSearch.entity().getId(), join1.entity().getServiceOfferingId(), JoinBuilder.JoinType.INNER); + cpuSearch.done(); + + SearchCriteria sc = cpuSearch.create(); + sc.setJoinParameters("offerings", "accountId", accountId); + sc.setJoinParameters("offerings", "type", VirtualMachine.Type.User); + sc.setJoinParameters("offerings", "state", new Object[] {State.Destroyed, State.Error, State.Expunging}); + List cpus = _serviceOfferingDao.customSearch(sc, null); + if (cpus != null) { + return cpus.get(0).sum; + } else { + return 0; + } + } + + public long calculateMemoryForAccount(long accountId) { + GenericSearchBuilder memorySearch = _serviceOfferingDao.createSearchBuilder(SumCount.class); + memorySearch.select("sum", Func.SUM, memorySearch.entity().getRamSize()); + SearchBuilder join1 = _userVmDao.createSearchBuilder(); + join1.and("accountId", join1.entity().getAccountId(), Op.EQ); + join1.and("type", join1.entity().getType(), Op.EQ); + join1.and("state", join1.entity().getState(), SearchCriteria.Op.NIN); + memorySearch.join("offerings", join1, memorySearch.entity().getId(), join1.entity().getServiceOfferingId(), JoinBuilder.JoinType.INNER); + memorySearch.done(); + + SearchCriteria sc = memorySearch.create(); + sc.setJoinParameters("offerings", "accountId", accountId); + sc.setJoinParameters("offerings", "type", VirtualMachine.Type.User); + sc.setJoinParameters("offerings", "state", new Object[] {State.Destroyed, State.Error, State.Expunging}); + List memory = _serviceOfferingDao.customSearch(sc, null); + if (memory != null) { + return memory.get(0).sum; + } else { + return 0; + } + } + @Override public long getResourceCount(Account account, ResourceType type) { return _resourceCountDao.getResourceCount(account.getId(), ResourceOwnerType.Account, type); diff --git a/server/src/com/cloud/server/ManagementServer.java b/server/src/com/cloud/server/ManagementServer.java index 5c34deea53b..6773725f361 100755 --- a/server/src/com/cloud/server/ManagementServer.java +++ b/server/src/com/cloud/server/ManagementServer.java @@ -19,11 +19,12 @@ package com.cloud.server; import java.util.Date; import java.util.List; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.event.EventVO; import com.cloud.host.HostVO; import com.cloud.info.ConsoleProxyInfo; import com.cloud.storage.GuestOSVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.utils.Pair; import com.cloud.utils.component.PluggableService; import com.cloud.vm.VirtualMachine; diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 0943bfc201e..e80d48c6512 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -47,12 +47,12 @@ import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.naming.ConfigurationException; -import com.cloud.storage.dao.*; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ApiConstants; import com.cloud.event.ActionEventUtils; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; + import org.apache.cloudstack.api.command.admin.account.*; import org.apache.cloudstack.api.command.admin.autoscale.*; import org.apache.cloudstack.api.command.admin.cluster.*; @@ -99,11 +99,17 @@ import org.apache.cloudstack.api.command.user.tag.*; import org.apache.cloudstack.api.command.user.template.*; import org.apache.cloudstack.api.command.user.vm.*; import org.apache.cloudstack.api.command.user.vmgroup.*; +import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd; import org.apache.cloudstack.api.command.user.volume.*; import org.apache.cloudstack.api.command.user.vpc.*; import org.apache.cloudstack.api.command.user.vpn.*; import org.apache.cloudstack.api.command.user.zone.*; import org.apache.cloudstack.api.response.ExtractResponse; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; @@ -202,15 +208,22 @@ import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.GuestOSVO; import com.cloud.storage.GuestOsCategory; import com.cloud.storage.Storage; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePoolVO; +import com.cloud.storage.StoragePool; import com.cloud.storage.Upload; import com.cloud.storage.Upload.Mode; import com.cloud.storage.UploadVO; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.GuestOSCategoryDao; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.UploadDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.snapshot.SnapshotManager; @@ -218,6 +231,7 @@ import com.cloud.storage.swift.SwiftManager; import com.cloud.storage.upload.UploadMonitor; import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.template.TemplateManager; import com.cloud.template.VirtualMachineTemplate.TemplateFilter; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -386,6 +400,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject HighAvailabilityManager _haMgr; @Inject + TemplateManager templateMgr; + @Inject + DataStoreManager dataStoreMgr; + @Inject HostTagsDao _hostTagsDao; @Inject @@ -2143,6 +2161,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(ResetVpnConnectionCmd.class); cmdList.add(UpdateVpnCustomerGatewayCmd.class); cmdList.add(ListZonesByCmd.class); + cmdList.add(ListVMSnapshotCmd.class); + cmdList.add(CreateVMSnapshotCmd.class); + cmdList.add(RevertToSnapshotCmd.class); + cmdList.add(DeleteVMSnapshotCmd.class); return cmdList; } @@ -2627,8 +2649,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } long accountId = volume.getAccountId(); - StoragePoolVO srcPool = _poolDao.findById(volume.getPoolId()); - HostVO sserver = _storageMgr.getSecondaryStorageHost(zoneId); + StoragePool srcPool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(volume.getPoolId()); + HostVO sserver = this.templateMgr.getSecondaryStorageHost(zoneId); String secondaryStorageURL = sserver.getStorageUrl(); List extractURLList = _uploadDao.listByTypeUploadStatus(volumeId, Upload.Type.VOLUME, UploadVO.Status.DOWNLOAD_URL_CREATED); @@ -2705,7 +2727,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } } - private String getFormatForPool(StoragePoolVO pool) { + private String getFormatForPool(StoragePool pool) { ClusterVO cluster = ApiDBUtils.findClusterById(pool.getClusterId()); if (cluster.getHypervisorType() == HypervisorType.XenServer) { diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index be83c188f8b..76bae5b4aca 100755 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -29,8 +29,8 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; -import com.cloud.resource.ResourceManager; - +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -49,14 +49,13 @@ import com.cloud.host.HostStats; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; +import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceState; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolHostVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StorageStats; import com.cloud.storage.VolumeStats; import com.cloud.storage.VolumeVO; -import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.secondary.SecondaryStorageVmManager; @@ -84,7 +83,7 @@ public class StatsCollector { @Inject private HostDao _hostDao; @Inject private UserVmDao _userVmDao; @Inject private VolumeDao _volsDao; - @Inject private StoragePoolDao _storagePoolDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private StorageManager _storageManager; @Inject private StoragePoolHostDao _storagePoolHostDao; @Inject private SecondaryStorageVmManager _ssvmMgr; @@ -301,7 +300,7 @@ public class StatsCollector { GetStorageStatsCommand command = new GetStorageStatsCommand(pool.getUuid(), pool.getPoolType(), pool.getPath()); long poolId = pool.getId(); try { - Answer answer = _storageManager.sendToPool(pool, command); + Answer answer = _storageManager.sendToPool(pool.getId(), command); if (answer != null && answer.getResult()) { storagePoolStats.put(pool.getId(), (StorageStats)answer); diff --git a/server/src/com/cloud/service/ServiceOfferingVO.java b/server/src/com/cloud/service/ServiceOfferingVO.java index c199a86afd1..7be939c3a15 100755 --- a/server/src/com/cloud/service/ServiceOfferingVO.java +++ b/server/src/com/cloud/service/ServiceOfferingVO.java @@ -53,6 +53,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering @Column(name="limit_cpu_use") private boolean limitCpuUse; + @Column(name="is_volatile") + private boolean volatileVm; + @Column(name="host_tag") private String hostTag; @@ -78,11 +81,12 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.multicastRateMbps = multicastRateMbps; this.offerHA = offerHA; this.limitCpuUse = false; + this.volatileVm = false; this.default_use = defaultUse; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); } - public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId) { + public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId) { super(name, displayText, false, tags, recreatable, useLocalStorage, systemUse, true, domainId); this.cpu = cpu; this.ramSize = ramSize; @@ -91,11 +95,12 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.multicastRateMbps = multicastRateMbps; this.offerHA = offerHA; this.limitCpuUse = limitCpuUse; + this.volatileVm = volatileVm; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); } - public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, String hostTag) { - this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId); + public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, String hostTag) { + this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId); this.hostTag = hostTag; } @@ -189,13 +194,18 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public String getSystemVmType(){ return vm_type; } + + public void setSortKey(int key) { + sortKey = key; + } + + public int getSortKey() { + return sortKey; + } - public void setSortKey(int key) { - sortKey = key; + @Override + public boolean getVolatileVm() { + return volatileVm; } - - public int getSortKey() { - return sortKey; - } - + } diff --git a/server/src/com/cloud/storage/LocalStoragePoolListener.java b/server/src/com/cloud/storage/LocalStoragePoolListener.java index 8d5875e9d76..a04c79cf435 100755 --- a/server/src/com/cloud/storage/LocalStoragePoolListener.java +++ b/server/src/com/cloud/storage/LocalStoragePoolListener.java @@ -16,8 +16,6 @@ // under the License. package com.cloud.storage; -import java.util.List; - import javax.inject.Inject; import org.apache.log4j.Logger; @@ -30,20 +28,14 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.StoragePoolInfo; -import com.cloud.capacity.Capacity; -import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; -import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.exception.ConnectionException; import com.cloud.host.HostVO; import com.cloud.host.Status; -import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.utils.db.DB; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; public class LocalStoragePoolListener implements Listener { private final static Logger s_logger = Logger.getLogger(LocalStoragePoolListener.class); @@ -91,63 +83,7 @@ public class LocalStoragePoolListener implements Listener { return; } - DataCenterVO dc = _dcDao.findById(host.getDataCenterId()); - if (dc == null || !dc.isLocalStorageEnabled()) { - return; - } - - try { - StoragePoolVO pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), pInfo.getHostPath(), pInfo.getUuid()); - if(pool == null && host.getHypervisorType() == HypervisorType.VMware) { - // perform run-time upgrade. In versions prior to 2.2.12, there is a bug that we don't save local datastore info (host path is empty), this will cause us - // not able to distinguish multiple local datastores that may be available on the host, to support smooth migration, we - // need to perform runtime upgrade here - if(pInfo.getHostPath().length() > 0) { - pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), "", pInfo.getUuid()); - } - } - - if (pool == null) { - - long poolId = _storagePoolDao.getNextInSequence(Long.class, "id"); - String name = cmd.getName() == null ? (host.getName() + " Local Storage") : cmd.getName(); - Transaction txn = Transaction.currentTxn(); - txn.start(); - pool = new StoragePoolVO(poolId, name, pInfo.getUuid(), pInfo.getPoolType(), host.getDataCenterId(), - host.getPodId(), pInfo.getAvailableBytes(), pInfo.getCapacityBytes(), pInfo.getHost(), 0, - pInfo.getHostPath()); - pool.setClusterId(host.getClusterId()); - pool.setStatus(StoragePoolStatus.Up); - _storagePoolDao.persist(pool, pInfo.getDetails()); - StoragePoolHostVO poolHost = new StoragePoolHostVO(pool.getId(), host.getId(), pInfo.getLocalPath()); - _storagePoolHostDao.persist(poolHost); - _storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getCapacityBytes() - pool.getAvailableBytes()); - - txn.commit(); - } else { - Transaction txn = Transaction.currentTxn(); - txn.start(); - pool.setPath(pInfo.getHostPath()); - pool.setAvailableBytes(pInfo.getAvailableBytes()); - pool.setCapacityBytes(pInfo.getCapacityBytes()); - _storagePoolDao.update(pool.getId(), pool); - if (pInfo.getDetails() != null) { - _storagePoolDao.updateDetails(pool.getId(), pInfo.getDetails()); - } - StoragePoolHostVO poolHost = _storagePoolHostDao.findByPoolHost(pool.getId(), host.getId()); - if (poolHost == null) { - poolHost = new StoragePoolHostVO(pool.getId(), host.getId(), pInfo.getLocalPath()); - _storagePoolHostDao.persist(poolHost); - } - - _storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getCapacityBytes() - pool.getAvailableBytes()); - - txn.commit(); - } - } catch (Exception e) { - s_logger.warn("Unable to setup the local storage pool for " + host, e); - throw new ConnectionException(true, "Unable to setup the local storage pool for " + host, e); - } + this._storageMgr.createLocalStorage(host, pInfo); } diff --git a/server/src/com/cloud/storage/OCFS2ManagerImpl.java b/server/src/com/cloud/storage/OCFS2ManagerImpl.java index 6bbeec40551..5c526a69e4f 100755 --- a/server/src/com/cloud/storage/OCFS2ManagerImpl.java +++ b/server/src/com/cloud/storage/OCFS2ManagerImpl.java @@ -25,6 +25,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; diff --git a/server/src/com/cloud/storage/RegisterVolumePayload.java b/server/src/com/cloud/storage/RegisterVolumePayload.java new file mode 100644 index 00000000000..142de186e25 --- /dev/null +++ b/server/src/com/cloud/storage/RegisterVolumePayload.java @@ -0,0 +1,43 @@ +/* + * 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.storage; + +public class RegisterVolumePayload { + private final String url; + private final String checksum; + private final String format; + + public RegisterVolumePayload(String url, String checksum, String format) { + this.url = url; + this.checksum = checksum; + this.format = format; + } + + public String getUrl() { + return this.url; + } + + public String getChecksum() { + return this.checksum; + } + + public String getFormat() { + return this.format; + } +} diff --git a/server/src/com/cloud/storage/ResizeVolumePayload.java b/server/src/com/cloud/storage/ResizeVolumePayload.java new file mode 100644 index 00000000000..205fafa4bb0 --- /dev/null +++ b/server/src/com/cloud/storage/ResizeVolumePayload.java @@ -0,0 +1,31 @@ +// 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.storage; + +public class ResizeVolumePayload { + public final Long newSize; + public final boolean shrinkOk; + public final String instanceName; + public final long[] hosts; + public ResizeVolumePayload(Long newSize, boolean shrinkOk, String instanceName, long[] hosts) { + this.newSize = newSize; + this.shrinkOk = shrinkOk; + this.instanceName = instanceName; + this.hosts = hosts; + } +} diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java index 97853ac76de..9213b4bf486 100755 --- a/server/src/com/cloud/storage/StorageManager.java +++ b/server/src/com/cloud/storage/StorageManager.java @@ -17,50 +17,29 @@ package com.cloud.storage; import java.util.List; +import java.util.Set; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.StoragePoolInfo; import com.cloud.agent.manager.Commands; import com.cloud.capacity.CapacityVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientStorageCapacityException; +import com.cloud.exception.ConnectionException; import com.cloud.exception.StorageUnavailableException; import com.cloud.host.Host; -import com.cloud.host.HostVO; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.Volume.Event; -import com.cloud.storage.Volume.Type; -import com.cloud.user.Account; import com.cloud.utils.Pair; -import com.cloud.utils.component.Manager; -import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.DiskProfile; import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineProfile; - -public interface StorageManager extends StorageService, Manager { - boolean canVmRestartOnAnotherServer(long vmId); - - /** Returns the absolute path of the specified ISO - * @param templateId - the ID of the template that represents the ISO - * @param datacenterId - * @return absolute ISO path - */ - public Pair getAbsoluteIsoPath(long templateId, long dataCenterId); - - /** - * Returns the URL of the secondary storage host - * @param zoneId - * @return URL - */ - public String getSecondaryStorageURL(long zoneId); +public interface StorageManager extends StorageService { /** * Returns a comma separated list of tags for the specified storage pool * @param poolId @@ -68,67 +47,9 @@ public interface StorageManager extends StorageService, Manager { */ public String getStoragePoolTags(long poolId); - /** - * Returns the secondary storage host - * @param zoneId - * @return secondary storage host - */ - public HostVO getSecondaryStorageHost(long zoneId); + - /** - * Returns the secondary storage host - * @param zoneId - * @return secondary storage host - */ - public VMTemplateHostVO findVmTemplateHost(long templateId, StoragePool pool); - /** - * Moves a volume from its current storage pool to a storage pool with enough capacity in the specified zone, pod, or cluster - * @param volume - * @param destPoolDcId - * @param destPoolPodId - * @param destPoolClusterId - * @return VolumeVO - * @throws ConcurrentOperationException - */ - VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException; - - /** - * Create a volume based on the given criteria - * @param volume - * @param vm - * @param template - * @param dc - * @param pod - * @param clusterId - * @param offering - * @param diskOffering - * @param avoids - * @param size - * @param hyperType - * @return volume VO if success, null otherwise - */ - VolumeVO createVolume(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, - ServiceOfferingVO offering, DiskOfferingVO diskOffering, List avoids, long size, HypervisorType hyperType); - - /** - * Marks the specified volume as destroyed in the management server database. The expunge thread will delete the volume from its storage pool. - * @param volume - * @return - */ - boolean destroyVolume(VolumeVO volume) throws ConcurrentOperationException; - - /** Create capacity entries in the op capacity table - * @param storagePool - */ - public void createCapacityEntry(StoragePoolVO storagePool); - - /** - * Checks that the volume is stored on a shared storage pool - * @param volume - * @return true if the volume is on a shared storage pool, false otherwise - */ - boolean volumeOnSharedStoragePool(VolumeVO volume); Answer sendToPool(long poolId, Command cmd) throws StorageUnavailableException; Answer sendToPool(StoragePool pool, Command cmd) throws StorageUnavailableException; @@ -137,17 +58,6 @@ public interface StorageManager extends StorageService, Manager { Pair sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List hostIdsToAvoid, Commands cmds) throws StorageUnavailableException; Pair sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List hostIdsToAvoid, Command cmd) throws StorageUnavailableException; - /** - * Checks that one of the following is true: - * 1. The volume is not attached to any VM - * 2. The volume is attached to a VM that is running on a host with the KVM hypervisor, and the VM is stopped - * 3. The volume is attached to a VM that is running on a host with the XenServer hypervisor (the VM can be stopped or running) - * @return true if one of the above conditions is true - */ - boolean volumeInactive(VolumeVO volume); - - String getVmNameOnVolume(VolumeVO volume); - /** * Checks if a host has running VMs that are using its local storage pool. * @return true if local storage is active on the host @@ -162,31 +72,10 @@ public interface StorageManager extends StorageService, Manager { String getPrimaryStorageNameLabel(VolumeVO volume); - /** - * Allocates one volume. - * @param - * @param type - * @param offering - * @param name - * @param size - * @param template - * @param vm - * @param account - * @return VolumeVO a persisted volume. - */ - DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, T vm, Account owner); - DiskProfile allocateTemplatedVolume(Type type, String name, DiskOfferingVO offering, VMTemplateVO template, T vm, Account owner); void createCapacityEntry(StoragePoolVO storagePool, short capacityType, long allocated); - void prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException, ConcurrentOperationException; - - void release(VirtualMachineProfile profile); - - void cleanupVolumes(long vmId) throws ConcurrentOperationException; - - void prepareForMigration(VirtualMachineProfile vm, DeployDestination dest); Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException; @@ -194,14 +83,6 @@ public interface StorageManager extends StorageService, Manager { CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, Long podId, Long zoneId); - boolean createStoragePool(long hostId, StoragePoolVO pool); - - boolean delPoolFromHost(long hostId); - - HostVO getSecondaryStorageHost(long zoneId, long tmpltId); - - List getSecondaryStorageHosts(long zoneId); - List ListByDataCenterHypervisor(long datacenterId, HypervisorType type); @@ -209,34 +90,34 @@ public interface StorageManager extends StorageService, Manager { StoragePoolVO findLocalStorageOnHost(long hostId); - VMTemplateHostVO getTemplateHostRef(long zoneId, long tmpltId, boolean readyOnly); - - boolean StorageMigration( - VirtualMachineProfile vm, - StoragePool destPool) throws ConcurrentOperationException; - - boolean stateTransitTo(Volume vol, Event event) - throws NoTransitionException; - - VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId); - Host updateSecondaryStorage(long secStorageId, String newUrl); List getUpHostsInPool(long poolId); void cleanupSecondaryStorage(boolean recurring); - VolumeVO copyVolumeFromSecToPrimary(VolumeVO volume, VMInstanceVO vm, - VMTemplateVO template, DataCenterVO dc, HostPodVO pod, - Long clusterId, ServiceOfferingVO offering, - DiskOfferingVO diskOffering, List avoids, long size, - HypervisorType hyperType) throws NoTransitionException; - - String getSupportedImageFormatForCluster(Long clusterId); HypervisorType getHypervisorTypeFromFormat(ImageFormat format); boolean storagePoolHasEnoughSpace(List volume, StoragePool pool); - boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException; + + boolean registerHostListener(String providerUuid, HypervisorHostListener listener); + + StoragePool findStoragePool(DiskProfile dskCh, DataCenterVO dc, + HostPodVO pod, Long clusterId, Long hostId, VMInstanceVO vm, + Set avoid); + + + void connectHostToSharedPool(long hostId, long poolId) + throws StorageUnavailableException; + + void createCapacityEntry(long poolId); + + + + + + DataStore createLocalStorage(Host host, StoragePoolInfo poolInfo) throws ConnectionException; + } diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 05e0cfe9869..9daf77db38a 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -17,8 +17,6 @@ package com.cloud.storage; import java.math.BigDecimal; -import java.net.Inet6Address; -import java.net.InetAddress; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; @@ -27,15 +25,13 @@ import java.sql.ResultSet; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; -import java.util.UUID; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -48,17 +44,41 @@ import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaint import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd; -import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreStatus; +import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.framework.async.AsyncCallFuture; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; -import com.cloud.agent.api.*; -import com.cloud.agent.api.storage.*; -import com.cloud.agent.api.to.StorageFilerTO; -import com.cloud.agent.api.to.VolumeTO; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.BackupSnapshotCommand; +import com.cloud.agent.api.CleanupSnapshotBackupCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.ManageSnapshotCommand; +import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.agent.api.storage.DeleteTemplateCommand; +import com.cloud.agent.api.storage.DeleteVolumeCommand; + import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; import com.cloud.api.ApiDBUtils; @@ -72,46 +92,61 @@ import com.cloud.cluster.ClusterManagerListener; import com.cloud.cluster.ManagementServerHostVO; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; -import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.consoleproxy.ConsoleProxyManager; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; -import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; -import com.cloud.deploy.DeployDestination; -import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; -import com.cloud.event.ActionEvent; -import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventUtils; + import com.cloud.event.dao.EventDao; -import com.cloud.exception.*; +import com.cloud.event.dao.UsageEventDao; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConnectionException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceInUseException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; + import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuruManager; +import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.network.NetworkModel; -import com.cloud.offering.ServiceOffering; import com.cloud.org.Grouping; import com.cloud.org.Grouping.AllocationState; import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceState; import com.cloud.server.ManagementServer; import com.cloud.server.StatsCollector; -import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.storage.Volume.Event; import com.cloud.storage.Volume.Type; import com.cloud.storage.allocator.StoragePoolAllocator; -import com.cloud.storage.dao.*; + +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotPolicyDao; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.StoragePoolWorkDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateS3Dao; +import com.cloud.storage.dao.VMTemplateSwiftDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; + import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.listener.StoragePoolMonitor; import com.cloud.storage.listener.VolumeStateListener; @@ -124,23 +159,24 @@ import com.cloud.template.TemplateManager; import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; -import com.cloud.uservm.UserVm; -import com.cloud.utils.EnumUtils; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.UriUtils; import com.cloud.utils.component.ComponentContext; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.*; import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.exception.ExecutionException; -import com.cloud.utils.fsm.NoTransitionException; -import com.cloud.utils.fsm.StateMachine2; -import com.cloud.vm.*; + +import com.cloud.vm.DiskProfile; +import com.cloud.vm.UserVmManager; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachineProfileImpl; + import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.*; @@ -173,6 +209,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Inject protected NetworkModel _networkMgr; @Inject + protected ServiceOfferingDao _serviceOfferingDao; + @Inject protected VolumeDao _volsDao; @Inject protected HostDao _hostDao; @@ -209,7 +247,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Inject protected VMInstanceDao _vmInstanceDao; @Inject - protected StoragePoolDao _storagePoolDao = null; + protected PrimaryDataStoreDao _storagePoolDao = null; @Inject protected CapacityDao _capacityDao; @Inject @@ -262,14 +300,30 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C protected ResourceTagDao _resourceTagDao; @Inject protected List _storagePoolAllocators; - @Inject ConfigurationDao _configDao; - @Inject ManagementServer _msServer; + @Inject + ConfigurationDao _configDao; + @Inject + ManagementServer _msServer; + @Inject + DataStoreManager dataStoreMgr; + @Inject + DataStoreProviderManager dataStoreProviderMgr; + @Inject + VolumeService volService; + @Inject + VolumeDataFactory volFactory; + @Inject + ImageDataFactory tmplFactory; + @Inject + SnapshotDataFactory snapshotFactory; + @Inject + protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; - // TODO : we don't have any instantiated pool discover, disable injection temporarily + // TODO : we don't have any instantiated pool discover, disable injection + // temporarily // @Inject protected List _discoverers; - protected SearchBuilder HostTemplateStatesSearch; protected GenericSearchBuilder UpHostsInPoolSearch; protected SearchBuilder StoragePoolSearch; @@ -288,32 +342,39 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C protected BigDecimal _overProvisioningFactor = new BigDecimal(1); private long _maxVolumeSizeInGb; private long _serverId; - private final StateMachine2 _volStateMachine; + private int _customDiskOfferingMinSize = 1; private int _customDiskOfferingMaxSize = 1024; private double _storageUsedThreshold = 1.0d; private double _storageAllocatedThreshold = 1.0d; protected BigDecimal _storageOverprovisioningFactor = new BigDecimal(1); + private Map hostListeners = new HashMap(); private boolean _recreateSystemVmEnabled; - public boolean share(VMInstanceVO vm, List vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException { + public boolean share(VMInstanceVO vm, List vols, HostVO host, + boolean cancelPreviousShare) throws StorageUnavailableException { // if pool is in maintenance and it is the ONLY pool available; reject - List rootVolForGivenVm = _volsDao.findByInstanceAndType(vm.getId(), Type.ROOT); + List rootVolForGivenVm = _volsDao.findByInstanceAndType( + vm.getId(), Type.ROOT); if (rootVolForGivenVm != null && rootVolForGivenVm.size() > 0) { - boolean isPoolAvailable = isPoolAvailable(rootVolForGivenVm.get(0).getPoolId()); + boolean isPoolAvailable = isPoolAvailable(rootVolForGivenVm.get(0) + .getPoolId()); if (!isPoolAvailable) { - throw new StorageUnavailableException("Can not share " + vm, rootVolForGivenVm.get(0).getPoolId()); + throw new StorageUnavailableException("Can not share " + vm, + rootVolForGivenVm.get(0).getPoolId()); } } // this check is done for maintenance mode for primary storage // if any one of the volume is unusable, we return false - // if we return false, the allocator will try to switch to another PS if available + // if we return false, the allocator will try to switch to another PS if + // available for (VolumeVO vol : vols) { if (vol.getRemoved() != null) { - s_logger.warn("Volume id:" + vol.getId() + " is removed, cannot share on this instance"); + s_logger.warn("Volume id:" + vol.getId() + + " is removed, cannot share on this instance"); // not ok to share return false; } @@ -323,26 +384,15 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return true; } - @Override - public VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId) { - VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), oldVol.getDiskOfferingId(), oldVol.getSize()); - if (templateId != null) { - newVol.setTemplateId(templateId); - } else { - newVol.setTemplateId(oldVol.getTemplateId()); - } - newVol.setDeviceId(oldVol.getDeviceId()); - newVol.setInstanceId(oldVol.getInstanceId()); - newVol.setRecreatable(oldVol.isRecreatable()); - return _volsDao.persist(newVol); - } - private boolean isPoolAvailable(Long poolId) { // get list of all pools List pools = _storagePoolDao.listAll(); // if no pools or 1 pool which is in maintenance - if (pools == null || pools.size() == 0 || (pools.size() == 1 && pools.get(0).getStatus().equals(StoragePoolStatus.Maintenance))) { + if (pools == null + || pools.size() == 0 + || (pools.size() == 1 && pools.get(0).getStatus() + .equals(DataStoreStatus.Maintenance))) { return false; } else { return true; @@ -350,8 +400,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public List ListByDataCenterHypervisor(long datacenterId, HypervisorType type) { - List pools = _storagePoolDao.listByDataCenterId(datacenterId); + public List ListByDataCenterHypervisor( + long datacenterId, HypervisorType type) { + List pools = _storagePoolDao + .listByDataCenterId(datacenterId); List retPools = new ArrayList(); for (StoragePoolVO pool : pools) { if (pool.getStatus() != StoragePoolStatus.Up) { @@ -368,21 +420,33 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Override public boolean isLocalStorageActiveOnHost(Long hostId) { - List storagePoolHostRefs = _storagePoolHostDao.listByHostId(hostId); + List storagePoolHostRefs = _storagePoolHostDao + .listByHostId(hostId); for (StoragePoolHostVO storagePoolHostRef : storagePoolHostRefs) { - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolHostRef.getPoolId()); - if (storagePool.getPoolType() == StoragePoolType.LVM || storagePool.getPoolType() == StoragePoolType.EXT) { - SearchBuilder volumeSB = _volsDao.createSearchBuilder(); - volumeSB.and("poolId", volumeSB.entity().getPoolId(), SearchCriteria.Op.EQ); - volumeSB.and("removed", volumeSB.entity().getRemoved(), SearchCriteria.Op.NULL); + StoragePoolVO PrimaryDataStoreVO = _storagePoolDao + .findById(storagePoolHostRef.getPoolId()); + if (PrimaryDataStoreVO.getPoolType() == StoragePoolType.LVM + || PrimaryDataStoreVO.getPoolType() == StoragePoolType.EXT) { + SearchBuilder volumeSB = _volsDao + .createSearchBuilder(); + volumeSB.and("poolId", volumeSB.entity().getPoolId(), + SearchCriteria.Op.EQ); + volumeSB.and("removed", volumeSB.entity().getRemoved(), + SearchCriteria.Op.NULL); - SearchBuilder activeVmSB = _vmInstanceDao.createSearchBuilder(); - activeVmSB.and("state", activeVmSB.entity().getState(), SearchCriteria.Op.IN); - volumeSB.join("activeVmSB", activeVmSB, volumeSB.entity().getInstanceId(), activeVmSB.entity().getId(), JoinBuilder.JoinType.INNER); + SearchBuilder activeVmSB = _vmInstanceDao + .createSearchBuilder(); + activeVmSB.and("state", activeVmSB.entity().getState(), + SearchCriteria.Op.IN); + volumeSB.join("activeVmSB", activeVmSB, volumeSB.entity() + .getInstanceId(), activeVmSB.entity().getId(), + JoinBuilder.JoinType.INNER); SearchCriteria volumeSC = volumeSB.create(); - volumeSC.setParameters("poolId", storagePool.getId()); - volumeSC.setJoinParameters("activeVmSB", "state", State.Starting, State.Running, State.Stopping, State.Migrating); + volumeSC.setParameters("poolId", PrimaryDataStoreVO.getId()); + volumeSC.setJoinParameters("activeVmSB", "state", + State.Starting, State.Running, State.Stopping, + State.Migrating); List volumes = _volsDao.search(volumeSC, null); if (volumes.size() > 0) { @@ -394,26 +458,35 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return false; } - protected StoragePoolVO findStoragePool(DiskProfile dskCh, final DataCenterVO dc, HostPodVO pod, Long clusterId, Long hostId, VMInstanceVO vm, final Set avoid) { + @Override + public StoragePool findStoragePool(DiskProfile dskCh, + final DataCenterVO dc, HostPodVO pod, Long clusterId, Long hostId, + VMInstanceVO vm, final Set avoid) { - VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); + VirtualMachineProfile profile = new VirtualMachineProfileImpl( + vm); for (StoragePoolAllocator allocator : _storagePoolAllocators) { - final List poolList = allocator.allocateToPool(dskCh, profile, dc.getId(), pod.getId(), clusterId, hostId, avoid, 1); + final List poolList = allocator.allocateToPool( + dskCh, profile, dc.getId(), pod.getId(), clusterId, hostId, + avoid, 1); if (poolList != null && !poolList.isEmpty()) { - return (StoragePoolVO) poolList.get(0); + return (StoragePool)this.dataStoreMgr.getDataStore(poolList.get(0).getId(), DataStoreRole.Primary); } } return null; } @Override - public Answer[] sendToPool(StoragePool pool, Commands cmds) throws StorageUnavailableException { + public Answer[] sendToPool(StoragePool pool, Commands cmds) + throws StorageUnavailableException { return sendToPool(pool, null, null, cmds).second(); } @Override - public Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException { - Answer[] answers = sendToPool(pool, hostIdsToTryFirst, null, new Commands(cmd)).second(); + public Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, + Command cmd) throws StorageUnavailableException { + Answer[] answers = sendToPool(pool, hostIdsToTryFirst, null, + new Commands(cmd)).second(); if (answers == null) { return null; } @@ -421,7 +494,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public Answer sendToPool(StoragePool pool, Command cmd) throws StorageUnavailableException { + public Answer sendToPool(StoragePool pool, Command cmd) + throws StorageUnavailableException { Answer[] answers = sendToPool(pool, new Commands(cmd)); if (answers == null) { return null; @@ -429,439 +503,27 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return answers[0]; } - @Override - public Answer sendToPool(long poolId, Command cmd) throws StorageUnavailableException { - StoragePool pool = _storagePoolDao.findById(poolId); - return sendToPool(pool, cmd); - } - - @Override - public Answer[] sendToPool(long poolId, Commands cmds) throws StorageUnavailableException { - StoragePool pool = _storagePoolDao.findById(poolId); - return sendToPool(pool, cmds); - } - - protected DiskProfile createDiskCharacteristics(VolumeVO volume, VMTemplateVO template, DataCenterVO dc, DiskOfferingVO diskOffering) { - if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { - SearchCriteria sc = HostTemplateStatesSearch.create(); - sc.setParameters("id", template.getId()); - sc.setParameters("state", com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); - sc.setJoinParameters("host", "dcId", dc.getId()); - - List sss = _vmTemplateHostDao.search(sc, null); - if (sss.size() == 0) { - throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + dc.getId()); - } - VMTemplateHostVO ss = sss.get(0); - - return new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), diskOffering.getId(), ss.getSize(), diskOffering.getTagsArray(), diskOffering.getUseLocalStorage(), - diskOffering.isRecreatable(), Storage.ImageFormat.ISO != template.getFormat() ? template.getId() : null); - } else { - return new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), diskOffering.getId(), diskOffering.getDiskSize(), diskOffering.getTagsArray(), - diskOffering.getUseLocalStorage(), diskOffering.isRecreatable(), null); - } - } - - @Override - public boolean canVmRestartOnAnotherServer(long vmId) { - List vols = _volsDao.findCreatedByInstance(vmId); - for (VolumeVO vol : vols) { - if (!vol.isRecreatable() && !vol.getPoolType().isShared()) { - return false; - } - } - return true; - } - - @DB - protected Pair createVolumeFromSnapshot(VolumeVO volume, SnapshotVO snapshot) { - VolumeVO createdVolume = null; - Long volumeId = volume.getId(); - - String volumeFolder = null; - - try { - stateTransitTo(volume, Volume.Event.CreateRequested); - } catch (NoTransitionException e) { - s_logger.debug(e.toString()); - return null; - } - // Create the Volume object and save it so that we can return it to the user - Account account = _accountDao.findById(volume.getAccountId()); - - final HashSet poolsToAvoid = new HashSet(); - StoragePoolVO pool = null; - boolean success = false; - Set podsToAvoid = new HashSet(); - Pair pod = null; - String volumeUUID = null; - String details = null; - - DiskOfferingVO diskOffering = _diskOfferingDao.findByIdIncludingRemoved(volume.getDiskOfferingId()); - DataCenterVO dc = _dcDao.findById(volume.getDataCenterId()); - DiskProfile dskCh = new DiskProfile(volume, diskOffering, snapshot.getHypervisorType()); - - int retry = 0; - // Determine what pod to store the volume in - while ((pod = _resourceMgr.findPod(null, null, dc, account.getId(), podsToAvoid)) != null) { - podsToAvoid.add(pod.first().getId()); - // Determine what storage pool to store the volume in - while ((pool = findStoragePool(dskCh, dc, pod.first(), null, null, null, poolsToAvoid)) != null) { - poolsToAvoid.add(pool); - volumeFolder = pool.getPath(); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Attempting to create volume from snapshotId: " + snapshot.getId() + " on storage pool " + pool.getName()); - } - - // Get the newly created VDI from the snapshot. - // This will return a null volumePath if it could not be created - Pair volumeDetails = createVDIFromSnapshot(UserContext.current().getCallerUserId(), snapshot, pool); - - volumeUUID = volumeDetails.first(); - details = volumeDetails.second(); - - if (volumeUUID != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume with UUID " + volumeUUID + " was created on storage pool " + pool.getName()); - } - success = true; - break; // break out of the "find storage pool" loop - } else { - retry++; - if (retry >= 3) { - _volsDao.expunge(volumeId); - String msg = "Unable to create volume from snapshot " + snapshot.getId() + " after retrying 3 times, due to " + details; - s_logger.debug(msg); - throw new CloudRuntimeException(msg); - - } - } - s_logger.warn("Unable to create volume on pool " + pool.getName() + ", reason: " + details); - } - - if (success) { - break; // break out of the "find pod" loop - } - } - - if (!success) { - _volsDao.expunge(volumeId); - String msg = "Unable to create volume from snapshot " + snapshot.getId() + " due to " + details; - s_logger.debug(msg); - throw new CloudRuntimeException(msg); - - } - - createdVolume = _volsDao.findById(volumeId); - - try { - if (success) { - createdVolume.setPodId(pod.first().getId()); - createdVolume.setPoolId(pool.getId()); - createdVolume.setPoolType(pool.getPoolType()); - createdVolume.setFolder(volumeFolder); - createdVolume.setPath(volumeUUID); - createdVolume.setDomainId(account.getDomainId()); - stateTransitTo(createdVolume, Volume.Event.OperationSucceeded); - } - } catch (NoTransitionException e) { - s_logger.debug("Failed to update volume state: " + e.toString()); - return null; - } - - return new Pair(createdVolume, details); - } - - @Override - public boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException { - return _volStateMachine.transitTo(vol, event, null, _volsDao); - } - - protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId) { - - // By default, assume failure. - VolumeVO createdVolume = null; - SnapshotVO snapshot = _snapshotDao.findById(snapshotId); // Precondition: snapshot is not null and not removed. - - Pair volumeDetails = createVolumeFromSnapshot(volume, snapshot); - if (volumeDetails != null) { - createdVolume = volumeDetails.first(); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, createdVolume.getAccountId(), - createdVolume.getDataCenterId(), createdVolume.getId(), createdVolume.getName(), createdVolume.getDiskOfferingId(), - null, createdVolume.getSize(), Volume.class.getName(), createdVolume.getUuid()); - } - return createdVolume; - } - - protected Pair createVDIFromSnapshot(long userId, SnapshotVO snapshot, StoragePoolVO pool) { - String vdiUUID = null; - Long snapshotId = snapshot.getId(); - Long volumeId = snapshot.getVolumeId(); - Long dcId = snapshot.getDataCenterId(); - String secondaryStoragePoolUrl = _snapMgr.getSecondaryStorageURL(snapshot); - long accountId = snapshot.getAccountId(); - - String backedUpSnapshotUuid = snapshot.getBackupSnapshotId(); - snapshot = _snapshotDao.findById(snapshotId); - if (snapshot.getVersion().trim().equals("2.1")) { - VolumeVO volume = _volsDao.findByIdIncludingRemoved(volumeId); - if (volume == null) { - throw new CloudRuntimeException("failed to upgrade snapshot " + snapshotId + " due to unable to find orignal volume:" + volumeId + ", try it later "); - } - if (volume.getTemplateId() == null) { - _snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); - } else { - VMTemplateVO template = _templateDao.findByIdIncludingRemoved(volume.getTemplateId()); - if (template == null) { - throw new CloudRuntimeException("failed to upgrade snapshot " + snapshotId + " due to unalbe to find orignal template :" + volume.getTemplateId() + ", try it later "); - } - Long templateId = template.getId(); - Long tmpltAccountId = template.getAccountId(); - if (!_snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { - throw new CloudRuntimeException("failed to upgrade snapshot " + snapshotId + " due to this snapshot is being used, try it later "); - } - UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null, secondaryStoragePoolUrl, dcId, accountId, volumeId, templateId, tmpltAccountId, null, snapshot.getBackupSnapshotId(), - snapshot.getName(), "2.1"); - Answer answer = null; - try { - answer = sendToPool(pool, cmd); - } catch (StorageUnavailableException e) { - } finally { - _snapshotDao.unlockFromLockTable(snapshotId.toString()); - } - if ((answer != null) && answer.getResult()) { - _snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); - } else { - return new Pair(null, "Unable to upgrade snapshot from 2.1 to 2.2 for " + snapshot.getId()); - } - } - } - String basicErrMsg = "Failed to create volume from " + snapshot.getName() + " on pool " + pool; - try { - if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) { - _snapshotMgr.downloadSnapshotsFromSwift(snapshot); - } else if (snapshot.getS3Id() != null && snapshot.getS3Id() != 0) { - _snapshotMgr.downloadSnapshotsFromS3(snapshot); - } - CreateVolumeFromSnapshotCommand createVolumeFromSnapshotCommand = new CreateVolumeFromSnapshotCommand(pool, secondaryStoragePoolUrl, dcId, accountId, volumeId, - backedUpSnapshotUuid, snapshot.getName(), _createVolumeFromSnapshotWait); - CreateVolumeFromSnapshotAnswer answer; - if (!_snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { - throw new CloudRuntimeException("failed to create volume from " + snapshotId + " due to this snapshot is being used, try it later "); - } - answer = (CreateVolumeFromSnapshotAnswer) sendToPool(pool, createVolumeFromSnapshotCommand); - if (answer != null && answer.getResult()) { - vdiUUID = answer.getVdi(); - } else { - s_logger.error(basicErrMsg + " due to " + ((answer == null) ? "null" : answer.getDetails())); - throw new CloudRuntimeException(basicErrMsg); - } - } catch (StorageUnavailableException e) { - s_logger.error(basicErrMsg); - } finally { - if (snapshot.getSwiftId() != null) { - _snapshotMgr.deleteSnapshotsDirForVolume(secondaryStoragePoolUrl, dcId, accountId, volumeId); - } - _snapshotDao.unlockFromLockTable(snapshotId.toString()); - } - return new Pair(vdiUUID, basicErrMsg); - } - - - @Override - @DB - public VolumeVO copyVolumeFromSecToPrimary(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, ServiceOfferingVO offering, DiskOfferingVO diskOffering, - List avoids, long size, HypervisorType hyperType) throws NoTransitionException { - - final HashSet avoidPools = new HashSet(avoids); - DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); - dskCh.setHyperType(vm.getHypervisorType()); - // Find a suitable storage to create volume on - StoragePoolVO destPool = findStoragePool(dskCh, dc, pod, clusterId, null, vm, avoidPools); - - // Copy the volume from secondary storage to the destination storage pool - stateTransitTo(volume, Event.CopyRequested); - VolumeHostVO volumeHostVO = _volumeHostDao.findByVolumeId(volume.getId()); - HostVO secStorage = _hostDao.findById(volumeHostVO.getHostId()); - String secondaryStorageURL = secStorage.getStorageUrl(); - String[] volumePath = volumeHostVO.getInstallPath().split("/"); - String volumeUUID = volumePath[volumePath.length - 1].split("\\.")[0]; - - CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volumeUUID, destPool, secondaryStorageURL, false, _copyvolumewait); - CopyVolumeAnswer cvAnswer; - try { - cvAnswer = (CopyVolumeAnswer) sendToPool(destPool, cvCmd); - } catch (StorageUnavailableException e1) { - stateTransitTo(volume, Event.CopyFailed); - throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); - } - - if (cvAnswer == null || !cvAnswer.getResult()) { - stateTransitTo(volume, Event.CopyFailed); - throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); - } - Transaction txn = Transaction.currentTxn(); - txn.start(); - volume.setPath(cvAnswer.getVolumePath()); - volume.setFolder(destPool.getPath()); - volume.setPodId(destPool.getPodId()); - volume.setPoolId(destPool.getId()); - volume.setPodId(destPool.getPodId()); - stateTransitTo(volume, Event.CopySucceeded); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), - volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(), - null, volume.getSize(), Volume.class.getName(), volume.getUuid()); - _volumeHostDao.remove(volumeHostVO.getId()); - txn.commit(); - return volume; - - } - - @Override - @DB - public VolumeVO createVolume(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, ServiceOfferingVO offering, DiskOfferingVO diskOffering, - List avoids, long size, HypervisorType hyperType) { - StoragePoolVO pool = null; - final HashSet avoidPools = new HashSet(avoids); - - try { - stateTransitTo(volume, Volume.Event.CreateRequested); - } catch (NoTransitionException e) { - s_logger.debug("Unable to update volume state: " + e.toString()); - return null; - } - - if (diskOffering != null && diskOffering.isCustomized()) { - diskOffering.setDiskSize(size); - } - DiskProfile dskCh = null; - if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { - dskCh = createDiskCharacteristics(volume, template, dc, offering); - } else { - dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); - } - - dskCh.setHyperType(hyperType); - - VolumeTO created = null; - int retry = _retry; - while (--retry >= 0) { - created = null; - - long podId = pod.getId(); - pod = _podDao.findById(podId); - if (pod == null) { - s_logger.warn("Unable to find pod " + podId + " when create volume " + volume.getName()); - break; - } - - pool = findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(), vm, avoidPools); - if (pool == null) { - s_logger.warn("Unable to find storage poll when create volume " + volume.getName()); - break; - } - - avoidPools.add(pool); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Trying to create " + volume + " on " + pool); - } - - CreateCommand cmd = null; - VMTemplateStoragePoolVO tmpltStoredOn = null; - - for (int i = 0; i < 2; i++) { - if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { - if (pool.getPoolType() == StoragePoolType.CLVM) { - //prepareISOForCreate does what we need, which is to tell us where the template is - VMTemplateHostVO tmpltHostOn = _tmpltMgr.prepareISOForCreate(template, pool); - if (tmpltHostOn == null) { - continue; - } - HostVO secondaryStorageHost = _hostDao.findById(tmpltHostOn.getHostId()); - String tmpltHostUrl = secondaryStorageHost.getStorageUrl(); - String fullTmpltUrl = tmpltHostUrl + "/" + tmpltHostOn.getInstallPath(); - cmd = new CreateCommand(dskCh, fullTmpltUrl, new StorageFilerTO(pool)); - } else { - tmpltStoredOn = _tmpltMgr.prepareTemplateForCreate(template, pool); - if (tmpltStoredOn == null) { - continue; - } - cmd = new CreateCommand(dskCh, tmpltStoredOn.getLocalDownloadPath(), new StorageFilerTO(pool)); - } - } else { - if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO == template.getFormat()) { - VMTemplateHostVO tmpltHostOn = _tmpltMgr.prepareISOForCreate(template, pool); - if (tmpltHostOn == null) { - throw new CloudRuntimeException("Did not find ISO in secondry storage in zone " + pool.getDataCenterId()); - } - } - cmd = new CreateCommand(dskCh, new StorageFilerTO(pool)); - } - - try { - Answer answer = sendToPool(pool, cmd); - if (answer != null && answer.getResult()) { - created = ((CreateAnswer) answer).getVolume(); - break; - } - - if (tmpltStoredOn != null && answer != null && (answer instanceof CreateAnswer) && ((CreateAnswer) answer).templateReloadRequested()) { - if (!_tmpltMgr.resetTemplateDownloadStateOnPool(tmpltStoredOn.getId())) { - break; // break out of template-redeploy retry loop - } - } else { - break; - } - } catch (StorageUnavailableException e) { - s_logger.debug("Storage unavailable for " + pool.getId()); - break; // break out of template-redeploy retry loop - } - } - - if (created != null) { - break; - } - - s_logger.debug("Retrying the create because it failed on pool " + pool); - } - - if (created == null) { - return null; - } else { - volume.setFolder(pool.getPath()); - volume.setPath(created.getPath()); - volume.setSize(created.getSize()); - volume.setPoolType(pool.getPoolType()); - volume.setPoolId(pool.getId()); - volume.setPodId(pod.getId()); - try { - stateTransitTo(volume, Volume.Event.OperationSucceeded); - } catch (NoTransitionException e) { - s_logger.debug("Unable to update volume state: " + e.toString()); - return null; - } - return volume; - } - } - - public Long chooseHostForStoragePool(StoragePoolVO poolVO, List avoidHosts, boolean sendToVmResidesOn, Long vmId) { + public Long chooseHostForStoragePool(StoragePoolVO poolVO, + List avoidHosts, boolean sendToVmResidesOn, Long vmId) { if (sendToVmResidesOn) { if (vmId != null) { VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); if (vmInstance != null) { Long hostId = vmInstance.getHostId(); - if (hostId != null && !avoidHosts.contains(vmInstance.getHostId())) { + if (hostId != null + && !avoidHosts.contains(vmInstance.getHostId())) { return hostId; } } } /* - * Can't find the vm where host resides on(vm is destroyed? or volume is detached from vm), randomly choose - * a host - * to send the cmd + * Can't find the vm where host resides on(vm is destroyed? or + * volume is detached from vm), randomly choose a host to send the + * cmd */ } - List poolHosts = _poolHostDao.listByHostStatus(poolVO.getId(), Status.Up); + List poolHosts = _poolHostDao.listByHostStatus( + poolVO.getId(), Status.Up); Collections.shuffle(poolHosts); if (poolHosts != null && poolHosts.size() > 0) { for (StoragePoolHostVO sphvo : poolHosts) { @@ -876,9 +538,12 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Override public boolean configure(String name, Map params) throws ConfigurationException { - Map configs = _configDao.getConfiguration("management-server", params); - String overProvisioningFactorStr = configs.get("storage.overprovisioning.factor"); + Map configs = _configDao.getConfiguration( + "management-server", params); + + String overProvisioningFactorStr = configs + .get("storage.overprovisioning.factor"); if (overProvisioningFactorStr != null) { _overProvisioningFactor = new BigDecimal(overProvisioningFactorStr); } @@ -886,94 +551,128 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C _retry = NumbersUtil.parseInt(configs.get(Config.StartRetry.key()), 10); _pingInterval = NumbersUtil.parseInt(configs.get("ping.interval"), 60); _hostRetry = NumbersUtil.parseInt(configs.get("host.retry"), 2); - _storagePoolAcquisitionWaitSeconds = NumbersUtil.parseInt(configs.get("pool.acquisition.wait.seconds"), 1800); - s_logger.info("pool.acquisition.wait.seconds is configured as " + _storagePoolAcquisitionWaitSeconds + " seconds"); + _storagePoolAcquisitionWaitSeconds = NumbersUtil.parseInt( + configs.get("pool.acquisition.wait.seconds"), 1800); + s_logger.info("pool.acquisition.wait.seconds is configured as " + + _storagePoolAcquisitionWaitSeconds + " seconds"); - _agentMgr.registerForHostEvents(new StoragePoolMonitor(this, _storagePoolDao), true, false, true); + _agentMgr.registerForHostEvents(new StoragePoolMonitor(this, + _storagePoolDao), true, false, true); String storageCleanupEnabled = configs.get("storage.cleanup.enabled"); - _storageCleanupEnabled = (storageCleanupEnabled == null) ? true : Boolean.parseBoolean(storageCleanupEnabled); + _storageCleanupEnabled = (storageCleanupEnabled == null) ? true + : Boolean.parseBoolean(storageCleanupEnabled); - String value = _configDao.getValue(Config.CreateVolumeFromSnapshotWait.toString()); - _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.CreateVolumeFromSnapshotWait.getDefaultValue())); + String value = _configDao.getValue(Config.CreateVolumeFromSnapshotWait + .toString()); + _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CreateVolumeFromSnapshotWait + .getDefaultValue())); value = _configDao.getValue(Config.CopyVolumeWait.toString()); - _copyvolumewait = NumbersUtil.parseInt(value, Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); + _copyvolumewait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); value = _configDao.getValue(Config.RecreateSystemVmEnabled.key()); _recreateSystemVmEnabled = Boolean.parseBoolean(value); value = _configDao.getValue(Config.StorageTemplateCleanupEnabled.key()); - _templateCleanupEnabled = (value == null ? true : Boolean.parseBoolean(value)); + _templateCleanupEnabled = (value == null ? true : Boolean + .parseBoolean(value)); String time = configs.get("storage.cleanup.interval"); _storageCleanupInterval = NumbersUtil.parseInt(time, 86400); - String storageUsedThreshold = _configDao.getValue(Config.StorageCapacityDisableThreshold.key()); + String storageUsedThreshold = _configDao + .getValue(Config.StorageCapacityDisableThreshold.key()); if (storageUsedThreshold != null) { _storageUsedThreshold = Double.parseDouble(storageUsedThreshold); } - String storageAllocatedThreshold = _configDao.getValue(Config.StorageAllocatedCapacityDisableThreshold.key()); + String storageAllocatedThreshold = _configDao + .getValue(Config.StorageAllocatedCapacityDisableThreshold.key()); if (storageAllocatedThreshold != null) { - _storageAllocatedThreshold = Double.parseDouble(storageAllocatedThreshold); + _storageAllocatedThreshold = Double + .parseDouble(storageAllocatedThreshold); } - String globalStorageOverprovisioningFactor = configs.get("storage.overprovisioning.factor"); - _storageOverprovisioningFactor = new BigDecimal(NumbersUtil.parseFloat(globalStorageOverprovisioningFactor, 2.0f)); + String globalStorageOverprovisioningFactor = configs + .get("storage.overprovisioning.factor"); + _storageOverprovisioningFactor = new BigDecimal(NumbersUtil.parseFloat( + globalStorageOverprovisioningFactor, 2.0f)); - s_logger.info("Storage cleanup enabled: " + _storageCleanupEnabled + ", interval: " + _storageCleanupInterval + ", template cleanup enabled: " + _templateCleanupEnabled); + s_logger.info("Storage cleanup enabled: " + _storageCleanupEnabled + + ", interval: " + _storageCleanupInterval + + ", template cleanup enabled: " + _templateCleanupEnabled); String workers = configs.get("expunge.workers"); int wrks = NumbersUtil.parseInt(workers, 10); - _executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("StorageManager-Scavenger")); + _executor = Executors.newScheduledThreadPool(wrks, + new NamedThreadFactory("StorageManager-Scavenger")); - _agentMgr.registerForHostEvents(ComponentContext.inject(LocalStoragePoolListener.class), true, false, false); + _agentMgr.registerForHostEvents( + ComponentContext.inject(LocalStoragePoolListener.class), true, + false, false); - String maxVolumeSizeInGbString = _configDao.getValue("storage.max.volume.size"); - _maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, 2000); + String maxVolumeSizeInGbString = _configDao + .getValue("storage.max.volume.size"); + _maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, + 2000); - String _customDiskOfferingMinSizeStr = _configDao.getValue(Config.CustomDiskOfferingMinSize.toString()); - _customDiskOfferingMinSize = NumbersUtil.parseInt(_customDiskOfferingMinSizeStr, Integer.parseInt(Config.CustomDiskOfferingMinSize.getDefaultValue())); + String _customDiskOfferingMinSizeStr = _configDao + .getValue(Config.CustomDiskOfferingMinSize.toString()); + _customDiskOfferingMinSize = NumbersUtil.parseInt( + _customDiskOfferingMinSizeStr, Integer + .parseInt(Config.CustomDiskOfferingMinSize + .getDefaultValue())); - String _customDiskOfferingMaxSizeStr = _configDao.getValue(Config.CustomDiskOfferingMaxSize.toString()); - _customDiskOfferingMaxSize = NumbersUtil.parseInt(_customDiskOfferingMaxSizeStr, Integer.parseInt(Config.CustomDiskOfferingMaxSize.getDefaultValue())); + String _customDiskOfferingMaxSizeStr = _configDao + .getValue(Config.CustomDiskOfferingMaxSize.toString()); + _customDiskOfferingMaxSize = NumbersUtil.parseInt( + _customDiskOfferingMaxSizeStr, Integer + .parseInt(Config.CustomDiskOfferingMaxSize + .getDefaultValue())); - HostTemplateStatesSearch = _vmTemplateHostDao.createSearchBuilder(); - HostTemplateStatesSearch.and("id", HostTemplateStatesSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); - HostTemplateStatesSearch.and("state", HostTemplateStatesSearch.entity().getDownloadState(), SearchCriteria.Op.EQ); - - SearchBuilder HostSearch = _hostDao.createSearchBuilder(); - HostSearch.and("dcId", HostSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); - - HostTemplateStatesSearch.join("host", HostSearch, HostSearch.entity().getId(), HostTemplateStatesSearch.entity().getHostId(), JoinBuilder.JoinType.INNER); - HostSearch.done(); - HostTemplateStatesSearch.done(); _serverId = _msServer.getId(); - UpHostsInPoolSearch = _storagePoolHostDao.createSearchBuilder(Long.class); - UpHostsInPoolSearch.selectField(UpHostsInPoolSearch.entity().getHostId()); + UpHostsInPoolSearch = _storagePoolHostDao + .createSearchBuilder(Long.class); + UpHostsInPoolSearch.selectField(UpHostsInPoolSearch.entity() + .getHostId()); SearchBuilder hostSearch = _hostDao.createSearchBuilder(); hostSearch.and("status", hostSearch.entity().getStatus(), Op.EQ); - hostSearch.and("resourceState", hostSearch.entity().getResourceState(), Op.EQ); - UpHostsInPoolSearch.join("hosts", hostSearch, hostSearch.entity().getId(), UpHostsInPoolSearch.entity().getHostId(), JoinType.INNER); - UpHostsInPoolSearch.and("pool", UpHostsInPoolSearch.entity().getPoolId(), Op.EQ); + hostSearch.and("resourceState", hostSearch.entity().getResourceState(), + Op.EQ); + UpHostsInPoolSearch.join("hosts", hostSearch, hostSearch.entity() + .getId(), UpHostsInPoolSearch.entity().getHostId(), + JoinType.INNER); + UpHostsInPoolSearch.and("pool", UpHostsInPoolSearch.entity() + .getPoolId(), Op.EQ); UpHostsInPoolSearch.done(); StoragePoolSearch = _vmInstanceDao.createSearchBuilder(); SearchBuilder volumeSearch = _volumeDao.createSearchBuilder(); - volumeSearch.and("volumeType", volumeSearch.entity().getVolumeType(), SearchCriteria.Op.EQ); - volumeSearch.and("poolId", volumeSearch.entity().getPoolId(), SearchCriteria.Op.EQ); - StoragePoolSearch.join("vmVolume", volumeSearch, volumeSearch.entity().getInstanceId(), StoragePoolSearch.entity().getId(), JoinBuilder.JoinType.INNER); + volumeSearch.and("volumeType", volumeSearch.entity().getVolumeType(), + SearchCriteria.Op.EQ); + volumeSearch.and("poolId", volumeSearch.entity().getPoolId(), + SearchCriteria.Op.EQ); + StoragePoolSearch.join("vmVolume", volumeSearch, volumeSearch.entity() + .getInstanceId(), StoragePoolSearch.entity().getId(), + JoinBuilder.JoinType.INNER); StoragePoolSearch.done(); LocalStorageSearch = _storagePoolDao.createSearchBuilder(); - SearchBuilder storageHostSearch = _storagePoolHostDao.createSearchBuilder(); - storageHostSearch.and("hostId", storageHostSearch.entity().getHostId(), SearchCriteria.Op.EQ); - LocalStorageSearch.join("poolHost", storageHostSearch, storageHostSearch.entity().getPoolId(), LocalStorageSearch.entity().getId(), JoinBuilder.JoinType.INNER); - LocalStorageSearch.and("type", LocalStorageSearch.entity().getPoolType(), SearchCriteria.Op.IN); + SearchBuilder storageHostSearch = _storagePoolHostDao + .createSearchBuilder(); + storageHostSearch.and("hostId", storageHostSearch.entity().getHostId(), + SearchCriteria.Op.EQ); + LocalStorageSearch.join("poolHost", storageHostSearch, + storageHostSearch.entity().getPoolId(), LocalStorageSearch + .entity().getId(), JoinBuilder.JoinType.INNER); + LocalStorageSearch.and("type", LocalStorageSearch.entity() + .getPoolType(), SearchCriteria.Op.IN); LocalStorageSearch.done(); Volume.State.getStateMachine().registerListener( new VolumeStateListener()); @@ -981,159 +680,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return true; } - public String getRandomVolumeName() { - return UUID.randomUUID().toString(); - } - - @Override - public boolean volumeOnSharedStoragePool(VolumeVO volume) { - Long poolId = volume.getPoolId(); - if (poolId == null) { - return false; - } else { - StoragePoolVO pool = _storagePoolDao.findById(poolId); - - if (pool == null) { - return false; - } else { - return pool.isShared(); - } - } - } - - @Override - public boolean volumeInactive(VolumeVO volume) { - Long vmId = volume.getInstanceId(); - if (vmId != null) { - UserVm vm = _userVmDao.findById(vmId); - if (vm == null) { - return true; - } - State state = vm.getState(); - if (state.equals(State.Stopped) || state.equals(State.Destroyed)) { - return true; - } - } - return false; - } - - @Override - public String getVmNameOnVolume(VolumeVO volume) { - Long vmId = volume.getInstanceId(); - if (vmId != null) { - VMInstanceVO vm = _vmInstanceDao.findById(vmId); - - if (vm == null) { - return null; - } - return vm.getInstanceName(); - } - return null; - } - - @Override - public Pair getAbsoluteIsoPath(long templateId, long dataCenterId) { - String isoPath = null; - - List storageHosts = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.SecondaryStorage, dataCenterId); - if (storageHosts != null) { - for (HostVO storageHost : storageHosts) { - List templateHostVOs = _vmTemplateHostDao.listByTemplateHostStatus(templateId, storageHost.getId(), VMTemplateStorageResourceAssoc.Status.DOWNLOADED ); - if (templateHostVOs != null && !templateHostVOs.isEmpty()) { - VMTemplateHostVO tmpHostVO = templateHostVOs.get(0); - isoPath = storageHost.getStorageUrl() + "/" + tmpHostVO.getInstallPath(); - return new Pair(isoPath, storageHost.getStorageUrl()); - } - } - } - s_logger.warn("Unable to find secondary storage in zone id=" + dataCenterId); - return null; - } - - @Override - public String getSecondaryStorageURL(long zoneId) { - // Determine the secondary storage URL - HostVO secondaryStorageHost = getSecondaryStorageHost(zoneId); - - if (secondaryStorageHost == null) { - return null; - } - - return secondaryStorageHost.getStorageUrl(); - } - - @Override - public HostVO getSecondaryStorageHost(long zoneId, long tmpltId) { - List hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); - if (hosts == null || hosts.size() == 0) { - return null; - } - for (HostVO host : hosts) { - VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(host.getId(), tmpltId); - if (tmpltHost != null && !tmpltHost.getDestroyed() && tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { - return host; - } - } - return null; - } - - @Override - public VMTemplateHostVO getTemplateHostRef(long zoneId, long tmpltId, boolean readyOnly) { - List hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); - if (hosts == null || hosts.size() == 0) { - return null; - } - VMTemplateHostVO inProgress = null; - VMTemplateHostVO other = null; - for (HostVO host : hosts) { - VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(host.getId(), tmpltId); - if (tmpltHost != null && !tmpltHost.getDestroyed()) { - if (tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { - return tmpltHost; - } else if (tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) { - inProgress = tmpltHost; - } else { - other = tmpltHost; - } - } - } - if (inProgress != null) { - return inProgress; - } - return other; - } - - @Override - public HostVO getSecondaryStorageHost(long zoneId) { - List hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); - if (hosts == null || hosts.size() == 0) { - hosts = _ssvmMgr.listLocalSecondaryStorageHostsInOneZone(zoneId); - if (hosts.isEmpty()) { - return null; - } - } - - int size = hosts.size(); - Random rn = new Random(); - int index = rn.nextInt(size); - return hosts.get(index); - } - - @Override - public List getSecondaryStorageHosts(long zoneId) { - List hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); - if (hosts == null || hosts.size() == 0) { - hosts = _ssvmMgr.listLocalSecondaryStorageHostsInOneZone(zoneId); - if (hosts.isEmpty()) { - return new ArrayList(); - } - } - return hosts; - } - + @Override public String getStoragePoolTags(long poolId) { - return _configMgr.listToCsvTags(_storagePoolDao.searchForStoragePoolDetails(poolId, "true")); + return _configMgr.listToCsvTags(_storagePoolDao + .searchForStoragePoolDetails(poolId, "true")); } @Override @@ -1141,7 +692,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C if (_storageCleanupEnabled) { Random generator = new Random(); int initialDelay = generator.nextInt(_storageCleanupInterval); - _executor.scheduleWithFixedDelay(new StorageGarbageCollector(), initialDelay, _storageCleanupInterval, TimeUnit.SECONDS); + _executor.scheduleWithFixedDelay(new StorageGarbageCollector(), + initialDelay, _storageCleanupInterval, TimeUnit.SECONDS); } else { s_logger.debug("Storage cleanup is not enabled, so the storage cleanup thread is not being scheduled."); } @@ -1157,22 +709,99 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return true; } + + @DB + @Override + public DataStore createLocalStorage(Host host, StoragePoolInfo pInfo) throws ConnectionException { - protected StorageManagerImpl() { - _volStateMachine = Volume.State.getStateMachine(); + DataCenterVO dc = _dcDao.findById(host.getDataCenterId()); + if (dc == null || !dc.isLocalStorageEnabled()) { + return null; + } + DataStore store = null; + try { + StoragePoolVO pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), pInfo.getHostPath(), pInfo.getUuid()); + if(pool == null && host.getHypervisorType() == HypervisorType.VMware) { + // perform run-time upgrade. In versions prior to 2.2.12, there is a bug that we don't save local datastore info (host path is empty), this will cause us + // not able to distinguish multiple local datastores that may be available on the host, to support smooth migration, we + // need to perform runtime upgrade here + if(pInfo.getHostPath().length() > 0) { + pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), "", pInfo.getUuid()); + } + } + DataStoreProvider provider = this.dataStoreProviderMgr.getDefaultPrimaryDataStoreProvider(); + DataStoreLifeCycle lifeCycle = provider.getLifeCycle(); + if (pool == null) { + Map params = new HashMap(); + String name = (host.getName() + " Local Storage"); + params.put("zoneId", host.getDataCenterId()); + params.put("clusterId", host.getClusterId()); + params.put("podId", host.getPodId()); + params.put("url", pInfo.getPoolType().toString() + "://" + pInfo.getHost() + "/" + pInfo.getHostPath()); + params.put("name", name); + params.put("localStorage", true); + params.put("details", pInfo.getDetails()); + params.put("uuid", pInfo.getUuid()); + params.put("providerId", provider.getId()); + + store = lifeCycle.initialize(params); + } else { + store = (DataStore) dataStoreMgr.getDataStore(pool.getId(), + DataStoreRole.Primary); + } + + HostScope scope = new HostScope(host.getId()); + lifeCycle.attachHost(store, scope, pInfo); + } catch (Exception e) { + s_logger.warn("Unable to setup the local storage pool for " + host, e); + throw new ConnectionException(true, "Unable to setup the local storage pool for " + host, e); + } + + return (DataStore) dataStoreMgr.getDataStore(store.getId(), + DataStoreRole.Primary); } @Override @SuppressWarnings("rawtypes") - public StoragePoolVO createPool(CreateStoragePoolCmd cmd) throws ResourceInUseException, IllegalArgumentException, UnknownHostException, ResourceUnavailableException { - Long clusterId = cmd.getClusterId(); - Long podId = cmd.getPodId(); - Map ds = cmd.getDetails(); + public PrimaryDataStoreInfo createPool(CreateStoragePoolCmd cmd) + throws ResourceInUseException, IllegalArgumentException, + UnknownHostException, ResourceUnavailableException { + String providerUuid = cmd.getStorageProviderUuid(); + DataStoreProvider storeProvider = dataStoreProviderMgr + .getDataStoreProviderByUuid(providerUuid); - if (clusterId != null && podId == null) { - throw new InvalidParameterValueException("Cluster id requires pod id"); + if (storeProvider == null) { + storeProvider = dataStoreProviderMgr.getDefaultPrimaryDataStoreProvider(); + if (storeProvider == null) { + throw new InvalidParameterValueException( + "can't find storage provider: " + providerUuid); + } } + Long clusterId = cmd.getClusterId(); + Long podId = cmd.getPodId(); + Long zoneId = cmd.getZoneId(); + + ScopeType scopeType = ScopeType.CLUSTER; + String scope = cmd.getScope(); + if (scope != null) { + try { + scopeType = Enum.valueOf(ScopeType.class, scope); + } catch (Exception e) { + throw new InvalidParameterValueException("invalid scope" + + scope); + } + } + + if (scopeType == ScopeType.CLUSTER && clusterId == null) { + throw new InvalidParameterValueException( + "cluster id can't be null, if scope is cluster"); + } else if (scopeType == ScopeType.ZONE && zoneId == null) { + throw new InvalidParameterValueException( + "zone id can't be null, if scope is zone"); + } + + Map ds = cmd.getDetails(); Map details = new HashMap(); if (ds != null) { Collection detailsCollection = ds.values(); @@ -1182,233 +811,69 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C Iterator it2 = d.entrySet().iterator(); while (it2.hasNext()) { Map.Entry entry = (Map.Entry) it2.next(); - details.put((String) entry.getKey(), (String) entry.getValue()); + details.put((String) entry.getKey(), + (String) entry.getValue()); } } } - // verify input parameters - Long zoneId = cmd.getZoneId(); DataCenterVO zone = _dcDao.findById(cmd.getZoneId()); if (zone == null) { - throw new InvalidParameterValueException("unable to find zone by id " + zoneId); + throw new InvalidParameterValueException( + "unable to find zone by id " + zoneId); } // Check if zone is disabled Account account = UserContext.current().getCaller(); - if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(account.getType())) { - throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId); + if (Grouping.AllocationState.Disabled == zone.getAllocationState() + && !_accountMgr.isRootAdmin(account.getType())) { + throw new PermissionDeniedException( + "Cannot perform this operation, Zone is currently disabled: " + + zoneId); } - // Check if there is host up in this cluster - List allHosts = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.Routing, clusterId, podId, zoneId); - if (allHosts.isEmpty()) { - throw new ResourceUnavailableException("No host up to associate a storage pool with in cluster " + clusterId, Pod.class, podId); - } - URI uri = null; + Map params = new HashMap(); + params.put("zoneId", zone.getId()); + params.put("clusterId", clusterId); + params.put("podId", podId); + params.put("url", cmd.getUrl()); + params.put("tags", cmd.getTags()); + params.put("name", cmd.getStoragePoolName()); + params.put("details", details); + params.put("providerId", storeProvider.getId()); + + DataStoreLifeCycle lifeCycle = storeProvider.getLifeCycle(); + DataStore store = null; try { - uri = new URI(UriUtils.encodeURIComponent(cmd.getUrl())); - if (uri.getScheme() == null) { - throw new InvalidParameterValueException("scheme is null " + cmd.getUrl() + ", add nfs:// as a prefix"); - } else if (uri.getScheme().equalsIgnoreCase("nfs")) { - String uriHost = uri.getHost(); - String uriPath = uri.getPath(); - if (uriHost == null || uriPath == null || uriHost.trim().isEmpty() || uriPath.trim().isEmpty()) { - throw new InvalidParameterValueException("host or path is null, should be nfs://hostname/path"); - } - } else if (uri.getScheme().equalsIgnoreCase("sharedMountPoint")) { - String uriPath = uri.getPath(); - if (uriPath == null) { - throw new InvalidParameterValueException("host or path is null, should be sharedmountpoint://localhost/path"); - } - } else if (uri.getScheme().equalsIgnoreCase("rbd")) { - String uriPath = uri.getPath(); - if (uriPath == null) { - throw new InvalidParameterValueException("host or path is null, should be rbd://hostname/pool"); - } + store = lifeCycle.initialize(params); + + if (scopeType == ScopeType.CLUSTER) { + ClusterScope clusterScope = new ClusterScope(clusterId, podId, + zoneId); + lifeCycle.attachCluster(store, clusterScope); + } else if (scopeType == ScopeType.ZONE) { + ZoneScope zoneScope = new ZoneScope(zoneId); + lifeCycle.attachZone(store, zoneScope); } - } catch (URISyntaxException e) { - throw new InvalidParameterValueException(cmd.getUrl() + " is not a valid uri"); + } catch (Exception e) { + s_logger.debug("Failed to add data store", e); + throw new CloudRuntimeException("Failed to add data store", e); } - String tags = cmd.getTags(); - if (tags != null) { - String[] tokens = tags.split(","); - - for (String tag : tokens) { - tag = tag.trim(); - if (tag.length() == 0) { - continue; - } - details.put(tag, "true"); - } - } - - String scheme = uri.getScheme(); - String storageHost = uri.getHost(); - String hostPath = uri.getPath(); - String userInfo = uri.getUserInfo(); - int port = uri.getPort(); - StoragePoolVO pool = null; - if (s_logger.isDebugEnabled()) { - s_logger.debug("createPool Params @ scheme - " + scheme + " storageHost - " + storageHost + " hostPath - " + hostPath + " port - " + port); - } - if (scheme.equalsIgnoreCase("nfs")) { - if (port == -1) { - port = 2049; - } - pool = new StoragePoolVO(StoragePoolType.NetworkFilesystem, storageHost, port, hostPath); - if (clusterId == null) { - throw new IllegalArgumentException("NFS need to have clusters specified for XenServers"); - } - } else if (scheme.equalsIgnoreCase("file")) { - if (port == -1) { - port = 0; - } - pool = new StoragePoolVO(StoragePoolType.Filesystem, "localhost", 0, hostPath); - } else if (scheme.equalsIgnoreCase("sharedMountPoint")) { - pool = new StoragePoolVO(StoragePoolType.SharedMountPoint, storageHost, 0, hostPath); - } else if (scheme.equalsIgnoreCase("clvm")) { - pool = new StoragePoolVO(StoragePoolType.CLVM, storageHost, 0, hostPath.replaceFirst("/", "")); - } else if (scheme.equalsIgnoreCase("rbd")) { - if (port == -1) { - port = 6789; - } - pool = new StoragePoolVO(StoragePoolType.RBD, storageHost, port, hostPath.replaceFirst("/", ""), userInfo); - } else if (scheme.equalsIgnoreCase("PreSetup")) { - pool = new StoragePoolVO(StoragePoolType.PreSetup, storageHost, 0, hostPath); - } else if (scheme.equalsIgnoreCase("iscsi")) { - String[] tokens = hostPath.split("/"); - int lun = NumbersUtil.parseInt(tokens[tokens.length - 1], -1); - if (port == -1) { - port = 3260; - } - if (lun != -1) { - if (clusterId == null) { - throw new IllegalArgumentException("IscsiLUN need to have clusters specified"); - } - hostPath.replaceFirst("/", ""); - pool = new StoragePoolVO(StoragePoolType.IscsiLUN, storageHost, port, hostPath); - } else { - for (StoragePoolDiscoverer discoverer : _discoverers) { - Map> pools; - try { - pools = discoverer.find(cmd.getZoneId(), podId, uri, details); - } catch (DiscoveryException e) { - throw new IllegalArgumentException("Not enough information for discovery " + uri, e); - } - if (pools != null) { - Map.Entry> entry = pools.entrySet().iterator().next(); - pool = entry.getKey(); - details = entry.getValue(); - break; - } - } - } - } else if (scheme.equalsIgnoreCase("iso")) { - if (port == -1) { - port = 2049; - } - pool = new StoragePoolVO(StoragePoolType.ISO, storageHost, port, hostPath); - } else if (scheme.equalsIgnoreCase("vmfs")) { - pool = new StoragePoolVO(StoragePoolType.VMFS, "VMFS datastore: " + hostPath, 0, hostPath); - } else if (scheme.equalsIgnoreCase("ocfs2")) { - port = 7777; - pool = new StoragePoolVO(StoragePoolType.OCFS2, "clustered", port, hostPath); - } else { - s_logger.warn("Unable to figure out the scheme for URI: " + uri); - throw new IllegalArgumentException("Unable to figure out the scheme for URI: " + uri); - } - - if (pool == null) { - s_logger.warn("Unable to figure out the scheme for URI: " + uri); - throw new IllegalArgumentException("Unable to figure out the scheme for URI: " + uri); - } - - List pools = _storagePoolDao.listPoolByHostPath(storageHost, hostPath); - if (!pools.isEmpty() && !scheme.equalsIgnoreCase("sharedmountpoint")) { - Long oldPodId = pools.get(0).getPodId(); - throw new ResourceInUseException("Storage pool " + uri + " already in use by another pod (id=" + oldPodId + ")", "StoragePool", uri.toASCIIString()); - } - - long poolId = _storagePoolDao.getNextInSequence(Long.class, "id"); - String uuid = null; - if (scheme.equalsIgnoreCase("sharedmountpoint") || scheme.equalsIgnoreCase("clvm")) { - uuid = UUID.randomUUID().toString(); - } else if (scheme.equalsIgnoreCase("PreSetup")) { - uuid = hostPath.replace("/", ""); - } else { - uuid = UUID.nameUUIDFromBytes(new String(storageHost + hostPath).getBytes()).toString(); - } - - List spHandles = _storagePoolDao.findIfDuplicatePoolsExistByUUID(uuid); - if ((spHandles != null) && (spHandles.size() > 0)) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Another active pool with the same uuid already exists"); - } - throw new ResourceInUseException("Another active pool with the same uuid already exists"); - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("In createPool Setting poolId - " + poolId + " uuid - " + uuid + " zoneId - " + zoneId + " podId - " + podId + " poolName - " + cmd.getStoragePoolName()); - } - - pool.setId(poolId); - pool.setUuid(uuid); - pool.setDataCenterId(cmd.getZoneId()); - pool.setPodId(podId); - pool.setName(cmd.getStoragePoolName()); - pool.setClusterId(clusterId); - pool.setStatus(StoragePoolStatus.Up); - pool = _storagePoolDao.persist(pool, details); - - if (pool.getPoolType() == StoragePoolType.OCFS2 && !_ocfs2Mgr.prepareNodes(allHosts, pool)) { - s_logger.warn("Can not create storage pool " + pool + " on cluster " + clusterId); - _storagePoolDao.expunge(pool.getId()); - return null; - } - - boolean success = false; - for (HostVO h : allHosts) { - success = createStoragePool(h.getId(), pool); - if (success) { - break; - } - } - if (!success) { - s_logger.warn("Can not create storage pool " + pool + " on cluster " + clusterId); - _storagePoolDao.expunge(pool.getId()); - return null; - } - s_logger.debug("In createPool Adding the pool to each of the hosts"); - List poolHosts = new ArrayList(); - for (HostVO h : allHosts) { - try { - connectHostToSharedPool(h.getId(), pool); - poolHosts.add(h); - } catch (Exception e) { - s_logger.warn("Unable to establish a connection between " + h + " and " + pool, e); - } - } - - if (poolHosts.isEmpty()) { - s_logger.warn("No host can access storage pool " + pool + " on cluster " + clusterId); - _storagePoolDao.expunge(pool.getId()); - return null; - } else { - createCapacityEntry(pool); - } - return pool; + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore(store.getId(), + DataStoreRole.Primary); } @Override - public StoragePoolVO updateStoragePool(UpdateStoragePoolCmd cmd) throws IllegalArgumentException { + public PrimaryDataStoreInfo updateStoragePool(UpdateStoragePoolCmd cmd) + throws IllegalArgumentException { // Input validation Long id = cmd.getId(); List tags = cmd.getTags(); StoragePoolVO pool = _storagePoolDao.findById(id); if (pool == null) { - throw new IllegalArgumentException("Unable to find storage pool with ID: " + id); + throw new IllegalArgumentException( + "Unable to find storage pool with ID: " + id); } if (tags != null) { @@ -1423,834 +888,102 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C _storagePoolDao.updateDetails(id, details); } - return pool; + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore(pool.getId(), + DataStoreRole.Primary); } @Override @DB public boolean deletePool(DeletePoolCmd cmd) { Long id = cmd.getId(); - boolean deleteFlag = false; boolean forced = cmd.isForced(); - // verify parameters StoragePoolVO sPool = _storagePoolDao.findById(id); if (sPool == null) { s_logger.warn("Unable to find pool:" + id); - throw new InvalidParameterValueException("Unable to find pool by id " + id); + throw new InvalidParameterValueException( + "Unable to find pool by id " + id); } - if(sPool.getStatus() != StoragePoolStatus.Maintenance){ - s_logger.warn("Unable to delete storage id: " + id +" due to it is not in Maintenance state"); - throw new InvalidParameterValueException("Unable to delete storage due to it is not in Maintenance state, id: " + id); + if (sPool.getStatus() != StoragePoolStatus.Maintenance) { + s_logger.warn("Unable to delete storage id: " + id + + " due to it is not in Maintenance state"); + throw new InvalidParameterValueException( + "Unable to delete storage due to it is not in Maintenance state, id: " + + id); } - if (sPool.getPoolType().equals(StoragePoolType.LVM) || sPool.getPoolType().equals(StoragePoolType.EXT)) { + if (sPool.isLocal()) { s_logger.warn("Unable to delete local storage id:" + id); - throw new InvalidParameterValueException("Unable to delete local storage id: " + id); + throw new InvalidParameterValueException( + "Unable to delete local storage id: " + id); } Pair vlms = _volsDao.getCountAndTotalByPool(id); if (forced) { if (vlms.first() > 0) { - Pair nonDstrdVlms = _volsDao.getNonDestroyedCountAndTotalByPool(id); + Pair nonDstrdVlms = _volsDao + .getNonDestroyedCountAndTotalByPool(id); if (nonDstrdVlms.first() > 0) { - throw new CloudRuntimeException("Cannot delete pool " + sPool.getName() + " as there are associated " + - "non-destroyed vols for this pool"); + throw new CloudRuntimeException("Cannot delete pool " + + sPool.getName() + " as there are associated " + + "non-destroyed vols for this pool"); } - //force expunge non-destroyed volumes + // force expunge non-destroyed volumes List vols = _volsDao.listVolumesToBeDestroyed(); for (VolumeVO vol : vols) { - expungeVolume(vol, true); + AsyncCallFuture future = this.volService.expungeVolumeAsync(this.volFactory.getVolume(vol.getId())); + try { + future.get(); + } catch (InterruptedException e) { + s_logger.debug("expunge volume failed" + vol.getId(), e); + } catch (ExecutionException e) { + s_logger.debug("expunge volume failed" + vol.getId(), e); + } } } } else { // Check if the pool has associated volumes in the volumes table // If it does , then you cannot delete the pool if (vlms.first() > 0) { - throw new CloudRuntimeException("Cannot delete pool " + sPool.getName() + " as there are associated vols" + - " for this pool"); + throw new CloudRuntimeException("Cannot delete pool " + + sPool.getName() + " as there are associated vols" + + " for this pool"); } } - // First get the host_id from storage_pool_host_ref for given pool id - StoragePoolVO lock = _storagePoolDao.acquireInLockTable(sPool.getId()); + StoragePoolVO lock = _storagePoolDao.acquireInLockTable(sPool + .getId()); if (lock == null) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Failed to acquire lock when deleting StoragePool with ID: " + sPool.getId()); + s_logger.debug("Failed to acquire lock when deleting PrimaryDataStoreVO with ID: " + + sPool.getId()); } return false; } - // mark storage pool as removed (so it can't be used for new volumes creation), release the lock - boolean isLockReleased = false; - isLockReleased = _storagePoolDao.releaseFromLockTable(lock.getId()); + _storagePoolDao.releaseFromLockTable(lock.getId()); s_logger.trace("Released lock for storage pool " + id); - // for the given pool id, find all records in the storage_pool_host_ref - List hostPoolRecords = _storagePoolHostDao.listByPoolId(id); - Transaction txn = Transaction.currentTxn(); - try { - // if not records exist, delete the given pool (base case) - if (hostPoolRecords.size() == 0) { - - txn.start(); - sPool.setUuid(null); - _storagePoolDao.update(id, sPool); - _storagePoolDao.remove(id); - deletePoolStats(id); - txn.commit(); - - deleteFlag = true; - return true; - } else { - // Remove the SR associated with the Xenserver - for (StoragePoolHostVO host : hostPoolRecords) { - DeleteStoragePoolCommand deleteCmd = new DeleteStoragePoolCommand(sPool); - final Answer answer = _agentMgr.easySend(host.getHostId(), deleteCmd); - - if (answer != null && answer.getResult()) { - deleteFlag = true; - break; - } - } - } - } finally { - if (deleteFlag) { - // now delete the storage_pool_host_ref and storage_pool records - txn.start(); - for (StoragePoolHostVO host : hostPoolRecords) { - _storagePoolHostDao.deleteStoragePoolHostDetails(host.getHostId(), host.getPoolId()); - } - sPool.setUuid(null); - _storagePoolDao.update(id, sPool); - _storagePoolDao.remove(id); - deletePoolStats(id); - // Delete op_host_capacity entries - _capacityDao.removeBy(Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, null, null, null, id); - txn.commit(); - - s_logger.debug("Storage pool id=" + id + " is removed successfully"); - return true; - } else { - // alert that the storage cleanup is required - s_logger.warn("Failed to Delete storage pool id: " + id); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_STORAGE_DELETE, sPool.getDataCenterId(), sPool.getPodId(), "Unable to delete storage pool id= " + id, - "Delete storage pool command failed. Please check logs."); - } - - if (lock != null && !isLockReleased) { - _storagePoolDao.releaseFromLockTable(lock.getId()); - } - } + DataStoreProvider storeProvider = dataStoreProviderMgr + .getDataStoreProviderById(sPool.getStorageProviderId()); + DataStoreLifeCycle lifeCycle = storeProvider.getLifeCycle(); + lifeCycle.deleteDataStore(id); return false; - - } - - @DB - private boolean deletePoolStats(Long poolId) { - CapacityVO capacity1 = _capacityDao.findByHostIdType(poolId, CapacityVO.CAPACITY_TYPE_STORAGE); - CapacityVO capacity2 = _capacityDao.findByHostIdType(poolId, CapacityVO.CAPACITY_TYPE_STORAGE_ALLOCATED); - Transaction txn = Transaction.currentTxn(); - txn.start(); - if (capacity1 != null) { - _capacityDao.remove(capacity1.getId()); - } - - if (capacity2 != null) { - _capacityDao.remove(capacity2.getId()); - } - - txn.commit(); - return true; - } @Override - public boolean createStoragePool(long hostId, StoragePoolVO pool) { - s_logger.debug("creating pool " + pool.getName() + " on host " + hostId); - if (pool.getPoolType() != StoragePoolType.NetworkFilesystem && pool.getPoolType() != StoragePoolType.Filesystem && pool.getPoolType() != StoragePoolType.IscsiLUN - && pool.getPoolType() != StoragePoolType.Iscsi && pool.getPoolType() != StoragePoolType.VMFS && pool.getPoolType() != StoragePoolType.SharedMountPoint - && pool.getPoolType() != StoragePoolType.PreSetup && pool.getPoolType() != StoragePoolType.OCFS2 && pool.getPoolType() != StoragePoolType.RBD && pool.getPoolType() != StoragePoolType.CLVM) { - s_logger.warn(" Doesn't support storage pool type " + pool.getPoolType()); - return false; - } - CreateStoragePoolCommand cmd = new CreateStoragePoolCommand(true, pool); - final Answer answer = _agentMgr.easySend(hostId, cmd); - if (answer != null && answer.getResult()) { - return true; - } else { - _storagePoolDao.expunge(pool.getId()); - String msg = ""; - if (answer != null) { - msg = "Can not create storage pool through host " + hostId + " due to " + answer.getDetails(); - s_logger.warn(msg); - } else { - msg = "Can not create storage pool through host " + hostId + " due to CreateStoragePoolCommand returns null"; - s_logger.warn(msg); - } - throw new CloudRuntimeException(msg); - } - } - - @Override - public boolean delPoolFromHost(long hostId) { - List poolHosts = _poolHostDao.listByHostIdIncludingRemoved(hostId); - for (StoragePoolHostVO poolHost : poolHosts) { - s_logger.debug("Deleting pool " + poolHost.getPoolId() + " from host " + hostId); - _poolHostDao.remove(poolHost.getId()); - } - return true; - } - - public void connectHostToSharedPool(long hostId, StoragePoolVO pool) throws StorageUnavailableException { - assert (pool.getPoolType().isShared()) : "Now, did you actually read the name of this method?"; + public void connectHostToSharedPool(long hostId, long poolId) + throws StorageUnavailableException { + StoragePool pool = (StoragePool)this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary); + assert (pool.isShared()) : "Now, did you actually read the name of this method?"; s_logger.debug("Adding pool " + pool.getName() + " to host " + hostId); - ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool); - final Answer answer = _agentMgr.easySend(hostId, cmd); - - if (answer == null) { - throw new StorageUnavailableException("Unable to get an answer to the modify storage pool command", pool.getId()); - } - - if (!answer.getResult()) { - String msg = "Add host failed due to ModifyStoragePoolCommand failed" + answer.getDetails(); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg); - throw new StorageUnavailableException("Unable establish connection from storage head to storage pool " + pool.getId() + " due to " + answer.getDetails(), pool.getId()); - } - - assert (answer instanceof ModifyStoragePoolAnswer) : "Well, now why won't you actually return the ModifyStoragePoolAnswer when it's ModifyStoragePoolCommand? Pool=" + pool.getId() + "Host=" + hostId; - ModifyStoragePoolAnswer mspAnswer = (ModifyStoragePoolAnswer) answer; - - StoragePoolHostVO poolHost = _poolHostDao.findByPoolHost(pool.getId(), hostId); - if (poolHost == null) { - poolHost = new StoragePoolHostVO(pool.getId(), hostId, mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/")); - _poolHostDao.persist(poolHost); - } else { - poolHost.setLocalPath(mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/")); - } - pool.setAvailableBytes(mspAnswer.getPoolInfo().getAvailableBytes()); - pool.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes()); - _storagePoolDao.update(pool.getId(), pool); - - s_logger.info("Connection established between " + pool + " host + " + hostId); - } - - @Override - public VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException { - - // Find a destination storage pool with the specified criteria - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId()); - DiskProfile dskCh = new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), diskOffering.getId(), diskOffering.getDiskSize(), diskOffering.getTagsArray(), - diskOffering.getUseLocalStorage(), diskOffering.isRecreatable(), null); - dskCh.setHyperType(dataDiskHyperType); - DataCenterVO destPoolDataCenter = _dcDao.findById(destPoolDcId); - HostPodVO destPoolPod = _podDao.findById(destPoolPodId); - StoragePoolVO destPool = findStoragePool(dskCh, destPoolDataCenter, destPoolPod, destPoolClusterId, null, null, new HashSet()); - String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId()); - - if (destPool == null) { - throw new CloudRuntimeException("Failed to find a storage pool with enough capacity to move the volume to."); - } - if (secondaryStorageURL == null) { - throw new CloudRuntimeException("Failed to find secondary storage."); - } - - List vols = new ArrayList(); - vols.add(volume); - migrateVolumes(vols, destPool); - return _volsDao.findById(volume.getId()); - } - - - /* - * Upload the volume to secondary storage. - * - */ - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPLOAD, eventDescription = "uploading volume", async = true) - public VolumeVO uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException{ - Account caller = UserContext.current().getCaller(); - long ownerId = cmd.getEntityOwnerId(); - Long zoneId = cmd.getZoneId(); - String volumeName = cmd.getVolumeName(); - String url = cmd.getUrl(); - String format = cmd.getFormat(); - - validateVolume(caller, ownerId, zoneId, volumeName, url, format); - VolumeVO volume = persistVolume(caller, ownerId, zoneId, volumeName, url, cmd.getFormat()); - _downloadMonitor.downloadVolumeToStorage(volume, zoneId, url, cmd.getChecksum(), ImageFormat.valueOf(format.toUpperCase())); - return volume; - } - - private boolean validateVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format) throws ResourceAllocationException{ - - // permission check - _accountMgr.checkAccess(caller, null, true, _accountMgr.getActiveAccountById(ownerId)); - - // Check that the resource limit for volumes won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), ResourceType.volume); - - - // Verify that zone exists - DataCenterVO zone = _dcDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Unable to find zone by id " + zoneId); - } - - // Check if zone is disabled - if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { - throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId); - } - - if (url.toLowerCase().contains("file://")) { - throw new InvalidParameterValueException("File:// type urls are currently unsupported"); - } - - ImageFormat imgfmt = ImageFormat.valueOf(format.toUpperCase()); - if (imgfmt == null) { - throw new IllegalArgumentException("Image format is incorrect " + format + ". Supported formats are " + EnumUtils.listValues(ImageFormat.values())); - } - - String userSpecifiedName = volumeName; - if (userSpecifiedName == null) { - userSpecifiedName = getRandomVolumeName(); - } - if((!url.toLowerCase().endsWith("vhd"))&&(!url.toLowerCase().endsWith("vhd.zip")) - &&(!url.toLowerCase().endsWith("vhd.bz2"))&&(!url.toLowerCase().endsWith("vhd.gz")) - &&(!url.toLowerCase().endsWith("qcow2"))&&(!url.toLowerCase().endsWith("qcow2.zip")) - &&(!url.toLowerCase().endsWith("qcow2.bz2"))&&(!url.toLowerCase().endsWith("qcow2.gz")) - &&(!url.toLowerCase().endsWith("ova"))&&(!url.toLowerCase().endsWith("ova.zip")) - &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz")) - &&(!url.toLowerCase().endsWith("img"))&&(!url.toLowerCase().endsWith("raw"))){ - throw new InvalidParameterValueException("Please specify a valid " + format.toLowerCase()); - } - - if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith(".vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith("vhd.gz") )) - || (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith(".qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz") )) - || (format.equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith(".ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase().endsWith("ova.gz"))) - || (format.equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith(".img") && !url.toLowerCase().endsWith("raw")))) { - throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + format.toLowerCase()); - } - validateUrl(url); - - return false; - } - - private String validateUrl(String url){ - try { - URI uri = new URI(url); - if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") - && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file"))) { - throw new IllegalArgumentException("Unsupported scheme for url: " + url); - } - - int port = uri.getPort(); - if (!(port == 80 || port == 443 || port == -1)) { - throw new IllegalArgumentException("Only ports 80 and 443 are allowed"); - } - String host = uri.getHost(); - try { - InetAddress hostAddr = InetAddress.getByName(host); - if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) { - throw new IllegalArgumentException("Illegal host specified in url"); - } - if (hostAddr instanceof Inet6Address) { - throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")"); - } - } catch (UnknownHostException uhe) { - throw new IllegalArgumentException("Unable to resolve " + host); - } - - return uri.toString(); - } catch (URISyntaxException e) { - throw new IllegalArgumentException("Invalid URL " + url); - } - - } - - private VolumeVO persistVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format) { - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK); - volume.setPoolId(null); - volume.setDataCenterId(zoneId); - volume.setPodId(null); - volume.setAccountId(ownerId); - volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId())); - long diskOfferingId = _diskOfferingDao.findByUniqueName("Cloud.com-Custom").getId(); - volume.setDiskOfferingId(diskOfferingId); - //volume.setSize(size); - volume.setInstanceId(null); - volume.setUpdated(new Date()); - volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId()); - - volume = _volsDao.persist(volume); - try { - stateTransitTo(volume, Event.UploadRequested); - } catch (NoTransitionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - UserContext.current().setEventDetails("Volume Id: " + volume.getId()); - - // Increment resource count during allocation; if actual creation fails, decrement it - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume); - - txn.commit(); - return volume; - } - - - /* - * Just allocate a volume in the database, don't send the createvolume cmd to hypervisor. The volume will be finally - * created - * only when it's attached to a VM. - */ - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true) - public VolumeVO allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationException { - // FIXME: some of the scheduled event stuff might be missing here... - Account caller = UserContext.current().getCaller(); - - long ownerId = cmd.getEntityOwnerId(); - - // permission check - _accountMgr.checkAccess(caller, null, true, _accountMgr.getActiveAccountById(ownerId)); - - // Check that the resource limit for volumes won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), ResourceType.volume); - - Long zoneId = cmd.getZoneId(); - Long diskOfferingId = null; - DiskOfferingVO diskOffering = null; - Long size = null; - - // validate input parameters before creating the volume - if ((cmd.getSnapshotId() == null && cmd.getDiskOfferingId() == null) || (cmd.getSnapshotId() != null && cmd.getDiskOfferingId() != null)) { - throw new InvalidParameterValueException("Either disk Offering Id or snapshot Id must be passed whilst creating volume"); - } - - if (cmd.getSnapshotId() == null) {// create a new volume - - diskOfferingId = cmd.getDiskOfferingId(); - size = cmd.getSize(); - Long sizeInGB = size; - if (size != null) { - if (size > 0) { - size = size * 1024 * 1024 * 1024; // user specify size in GB - } else { - throw new InvalidParameterValueException("Disk size must be larger than 0"); - } - } - - // Check that the the disk offering is specified - diskOffering = _diskOfferingDao.findById(diskOfferingId); - if ((diskOffering == null) || diskOffering.getRemoved() != null || !DiskOfferingVO.Type.Disk.equals(diskOffering.getType())) { - throw new InvalidParameterValueException("Please specify a valid disk offering."); - } - - if (diskOffering.isCustomized()) { - if (size == null) { - throw new InvalidParameterValueException("This disk offering requires a custom size specified"); - } - if ((sizeInGB < _customDiskOfferingMinSize) || (sizeInGB > _customDiskOfferingMaxSize)) { - throw new InvalidParameterValueException("Volume size: " + sizeInGB + "GB is out of allowed range. Max: " + _customDiskOfferingMaxSize + " Min:" + _customDiskOfferingMinSize); - } - } - - if (!diskOffering.isCustomized() && size != null) { - throw new InvalidParameterValueException("This disk offering does not allow custom size"); - } - - if (diskOffering.getDomainId() == null) { - // do nothing as offering is public - } else { - _configMgr.checkDiskOfferingAccess(caller, diskOffering); - } - - if (diskOffering.getDiskSize() > 0) { - size = diskOffering.getDiskSize(); - } - - if (!validateVolumeSizeRange(size)) {// convert size from mb to gb for validation - throw new InvalidParameterValueException("Invalid size for custom volume creation: " + size + " ,max volume size is:" + _maxVolumeSizeInGb); - } - } else { // create volume from snapshot - Long snapshotId = cmd.getSnapshotId(); - SnapshotVO snapshotCheck = _snapshotDao.findById(snapshotId); - if (snapshotCheck == null) { - throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId); - } - - if (snapshotCheck.getState() != Snapshot.State.BackedUp) { - throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.State.BackedUp + " state yet and can't be used for volume creation"); - } - - diskOfferingId = snapshotCheck.getDiskOfferingId(); - diskOffering = _diskOfferingDao.findById(diskOfferingId); - zoneId = snapshotCheck.getDataCenterId(); - size = snapshotCheck.getSize(); // ; disk offering is used for tags purposes - - // check snapshot permissions - _accountMgr.checkAccess(caller, null, true, snapshotCheck); - - /* - * // bug #11428. Operation not supported if vmware and snapshots parent volume = ROOT - * if(snapshotCheck.getHypervisorType() == HypervisorType.VMware - * && _volumeDao.findByIdIncludingRemoved(snapshotCheck.getVolumeId()).getVolumeType() == Type.ROOT){ - * throw new UnsupportedServiceException("operation not supported, snapshot with id " + snapshotId + - * " is created from ROOT volume"); - * } - * - */ - } - - // Verify that zone exists - DataCenterVO zone = _dcDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Unable to find zone by id " + zoneId); - } - - // Check if zone is disabled - if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { - throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId); - } - - // If local storage is disabled then creation of volume with local disk offering not allowed - if (!zone.isLocalStorageEnabled() && diskOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException("Zone is not configured to use local storage but volume's disk offering " + diskOffering.getName() + " uses it"); - } - - // Check that there is appropriate primary storage pool in the specified zone - List storagePools = _storagePoolDao.listByDataCenterId(zoneId); - boolean appropriatePoolExists = false; - if (!diskOffering.getUseLocalStorage()) { - for (StoragePoolVO storagePool : storagePools) { - if (storagePool.isShared()) { - appropriatePoolExists = true; - break; - } - } - } else { - for (StoragePoolVO storagePool : storagePools) { - if (storagePool.isLocal()) { - appropriatePoolExists = true; - break; - } - } - } - - // Check that there is at least one host in the specified zone - List hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByType(Host.Type.Routing, zoneId); - if (hosts.isEmpty()) { - throw new InvalidParameterValueException("There is no workable host in data center id " + zoneId + ", please check hosts' agent status and see if they are disabled"); - } - - if (!appropriatePoolExists) { - String storageType = diskOffering.getUseLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString(); - throw new InvalidParameterValueException("Volume's disk offering uses " + storageType + " storage, please specify a zone that has at least one " + storageType + " primary storage pool."); - } - - String userSpecifiedName = cmd.getVolumeName(); - if (userSpecifiedName == null) { - userSpecifiedName = getRandomVolumeName(); - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK); - volume.setPoolId(null); - volume.setDataCenterId(zoneId); - volume.setPodId(null); - volume.setAccountId(ownerId); - volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId())); - volume.setDiskOfferingId(diskOfferingId); - volume.setSize(size); - volume.setInstanceId(null); - volume.setUpdated(new Date()); - volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId()); - - volume = _volsDao.persist(volume); - if(cmd.getSnapshotId() == null){ - //for volume created from snapshot, create usage event after volume creation - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), - volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, size, - Volume.class.getName(), volume.getUuid()); - } - - UserContext.current().setEventDetails("Volume Id: " + volume.getId()); - - // Increment resource count during allocation; if actual creation fails, decrement it - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume); - - txn.commit(); - - return volume; - } - - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", async = true) - public VolumeVO createVolume(CreateVolumeCmd cmd) { - VolumeVO volume = _volsDao.findById(cmd.getEntityId()); - boolean created = false; - - try { - if (cmd.getSnapshotId() != null) { - volume = createVolumeFromSnapshot(volume, cmd.getSnapshotId()); - if (volume.getState() == Volume.State.Ready) { - created = true; - } - return volume; - } else { - _volsDao.update(volume.getId(), volume); - created = true; - } - - return _volsDao.findById(volume.getId()); - } finally { - if (!created) { - s_logger.trace("Decrementing volume resource count for account id=" + volume.getAccountId() + " as volume failed to create on the backend"); - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume); - } - } - } - - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true) - public VolumeVO resizeVolume(ResizeVolumeCmd cmd) { - VolumeVO volume = _volsDao.findById(cmd.getEntityId()); - Long newSize = null; - boolean shrinkOk = cmd.getShrinkOk(); - boolean success = false; - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId()); - DiskOfferingVO newDiskOffering = null; - - newDiskOffering = _diskOfferingDao.findById(cmd.getNewDiskOfferingId()); - - /* Volumes with no hypervisor have never been assigned, and can be resized by recreating. - perhaps in the future we can just update the db entry for the volume */ - if(_volsDao.getHypervisorType(volume.getId()) == HypervisorType.None){ - throw new InvalidParameterValueException("Can't resize a volume that has never been attached, not sure which hypervisor type. Recreate volume to resize."); - } - - /* Only works for KVM/Xen/VMware for now */ - if(_volsDao.getHypervisorType(volume.getId()) != HypervisorType.KVM - && _volsDao.getHypervisorType(volume.getId()) != HypervisorType.XenServer - && _volsDao.getHypervisorType(volume.getId()) != HypervisorType.VMware){ - throw new InvalidParameterValueException("Cloudstack currently only supports volumes marked as KVM, XenServer or VMware hypervisor for resize"); - } - - if (volume == null) { - throw new InvalidParameterValueException("No such volume"); - } - - if (volume.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException("Volume should be in ready state before attempting a resize"); - } - - if (!volume.getVolumeType().equals(Volume.Type.DATADISK)) { - throw new InvalidParameterValueException("Can only resize DATA volumes"); - } - - /* figure out whether or not a new disk offering or size parameter is required, get the correct size value */ - if (newDiskOffering == null) { - if (diskOffering.isCustomized()) { - newSize = cmd.getSize(); - - if (newSize == null) { - throw new InvalidParameterValueException("new offering is of custom size, need to specify a size"); - } - - newSize = ( newSize << 30 ); - } else { - throw new InvalidParameterValueException("current offering" + volume.getDiskOfferingId() + " cannot be resized, need to specify a disk offering"); - } - } else { - - if (newDiskOffering.getRemoved() != null || !DiskOfferingVO.Type.Disk.equals(newDiskOffering.getType())) { - throw new InvalidParameterValueException("Disk offering ID is missing or invalid"); - } - - if(diskOffering.getTags() != null) { - if(!newDiskOffering.getTags().equals(diskOffering.getTags())){ - throw new InvalidParameterValueException("Tags on new and old disk offerings must match"); - } - } else if (newDiskOffering.getTags() != null ){ - throw new InvalidParameterValueException("There are no tags on current disk offering, new disk offering needs to have no tags"); - } - - if (newDiskOffering.getDomainId() == null) { - // do nothing as offering is public - } else { - _configMgr.checkDiskOfferingAccess(UserContext.current().getCaller(), newDiskOffering); - } - - if (newDiskOffering.isCustomized()) { - newSize = cmd.getSize(); - - if (newSize == null) { - throw new InvalidParameterValueException("new offering is of custom size, need to specify a size"); - } - - newSize = ( newSize << 30 ); - } else { - newSize = newDiskOffering.getDiskSize(); - } - } - - if (newSize == null) { - throw new InvalidParameterValueException("could not detect a size parameter or fetch one from the diskofferingid parameter"); - } - - if (!validateVolumeSizeRange(newSize)) { - throw new InvalidParameterValueException("Requested size out of range"); - } - - /* does the caller have the authority to act on this volume? */ - _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, volume); - - UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); - - StoragePool pool = _storagePoolDao.findById(volume.getPoolId()); - long currentSize = volume.getSize(); - - /* lets make certain they (think they) know what they're doing if they - want to shrink, by forcing them to provide the shrinkok parameter. This will - be checked again at the hypervisor level where we can see the actual disk size */ - if (currentSize > newSize && !shrinkOk) { - throw new InvalidParameterValueException("Going from existing size of " + currentSize + " to size of " - + newSize + " would shrink the volume, need to sign off by supplying the shrinkok parameter with value of true"); - } - - /* get a list of hosts to send the commands to, try the system the - associated vm is running on first, then the last known place it ran. - If not attached to a userVm, we pass 'none' and resizevolume.sh is - ok with that since it only needs the vm name to live resize */ - long[] hosts = null; - String instanceName = "none"; - if (userVm != null) { - instanceName = userVm.getInstanceName(); - if(userVm.getHostId() != null) { - hosts = new long[] { userVm.getHostId() }; - } else if(userVm.getLastHostId() != null) { - hosts = new long[] { userVm.getLastHostId() }; - } - - /*Xen only works offline, SR does not support VDI.resizeOnline*/ - if(_volsDao.getHypervisorType(volume.getId()) == HypervisorType.XenServer - && ! userVm.getState().equals(State.Stopped)) { - throw new InvalidParameterValueException("VM must be stopped or disk detached in order to resize with the Xen HV"); - } - } - - try { - try { - stateTransitTo(volume, Volume.Event.ResizeRequested); - } catch (NoTransitionException etrans) { - throw new CloudRuntimeException("Unable to change volume state for resize: " + etrans.toString()); - } - - ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(pool), - currentSize, newSize, shrinkOk, instanceName); - ResizeVolumeAnswer answer = (ResizeVolumeAnswer) sendToPool(pool, hosts, resizeCmd); - - /* need to fetch/store new volume size in database. This value comes from - hypervisor rather than trusting that a success means we have a volume of the - size we requested */ - if (answer != null && answer.getResult()) { - long finalSize = answer.getNewSize(); - s_logger.debug("Resize: volume started at size " + currentSize + " and ended at size " + finalSize); - volume.setSize(finalSize); - if (newDiskOffering != null) { - volume.setDiskOfferingId(cmd.getNewDiskOfferingId()); - } - _volsDao.update(volume.getId(), volume); - - success = true; - return volume; - } else if (answer != null) { - s_logger.debug("Resize: returned '" + answer.getDetails() + "'"); - } - } catch (StorageUnavailableException e) { - s_logger.debug("volume failed to resize: "+e); - return null; - } finally { - if(success) { - try { - stateTransitTo(volume, Volume.Event.OperationSucceeded); - } catch (NoTransitionException etrans) { - throw new CloudRuntimeException("Failed to change volume state: " + etrans.toString()); - } - } else { - try { - stateTransitTo(volume, Volume.Event.OperationFailed); - } catch (NoTransitionException etrans) { - throw new CloudRuntimeException("Failed to change volume state: " + etrans.toString()); - } - } - } - return null; - } - - @Override - @DB - public boolean destroyVolume(VolumeVO volume) throws ConcurrentOperationException { - try { - if (!stateTransitTo(volume, Volume.Event.DestroyRequested)) { - throw new ConcurrentOperationException("Failed to transit to destroyed state"); - } - } catch (NoTransitionException e) { - s_logger.debug("Unable to destoy the volume: " + e.toString()); - return false; - } - - long volumeId = volume.getId(); - - // Delete the recurring snapshot policies for this volume. - _snapshotMgr.deletePoliciesForVolume(volumeId); - - Long instanceId = volume.getInstanceId(); - VMInstanceVO vmInstance = null; - if (instanceId != null) { - vmInstance = _vmInstanceDao.findById(instanceId); - } - - if (instanceId == null || (vmInstance.getType().equals(VirtualMachine.Type.User))) { - // Decrement the resource count for volumes belonging user VM's only - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume); - // Log usage event for volumes belonging user VM's only - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), - volume.getDataCenterId(), volume.getId(), volume.getName(), - Volume.class.getName(), volume.getUuid()); - } - - try { - if (!stateTransitTo(volume, Volume.Event.OperationSucceeded)) { - throw new ConcurrentOperationException("Failed to transit state"); - - } - } catch (NoTransitionException e) { - s_logger.debug("Unable to change volume state: " + e.toString()); - return false; - } - - return true; - - } - - @Override - public void createCapacityEntry(StoragePoolVO storagePool) { - createCapacityEntry(storagePool, Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, 0); + DataStoreProvider provider = dataStoreProviderMgr + .getDataStoreProviderById(pool.getStorageProviderId()); + HypervisorHostListener listener = hostListeners.get(provider.getUuid()); + listener.hostConnect(hostId, pool.getId()); } @Override @@ -2384,17 +1117,21 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } + cleanupSecondaryStorage(recurring); List vols = _volsDao.listVolumesToBeDestroyed(); for (VolumeVO vol : vols) { try { - expungeVolume(vol, false); + + this.volService.expungeVolumeAsync(this.volFactory.getVolume(vol.getId())); + } catch (Exception e) { s_logger.warn("Unable to destroy " + vol.getId(), e); } } + // remove snapshots in Error state List snapshots = _snapshotDao.listAllByStatus(Snapshot.State.Error); for (SnapshotVO snapshotVO : snapshots) { @@ -2405,11 +1142,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } - } finally { + }finally { scanLock.unlock(); } - } - } finally { + } + }finally { scanLock.releaseRef(); } } @@ -2430,7 +1167,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } return list; } catch (Exception e) { - s_logger.debug("failed to get all volumes who has snapshots in secondary storage " + hostId + " due to " + e.getMessage()); + s_logger.debug("failed to get all volumes who has snapshots in secondary storage " + + hostId + " due to " + e.getMessage()); return null; } @@ -2451,7 +1189,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } return list; } catch (Exception e) { - s_logger.debug("failed to get all snapshots for a volume " + volumeId + " due to " + e.getMessage()); + s_logger.debug("failed to get all snapshots for a volume " + + volumeId + " due to " + e.getMessage()); return null; } } @@ -2461,42 +1200,66 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C public void cleanupSecondaryStorage(boolean recurring) { try { // Cleanup templates in secondary storage hosts - List secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInAllZones(); + List secondaryStorageHosts = _ssvmMgr + .listSecondaryStorageHostsInAllZones(); for (HostVO secondaryStorageHost : secondaryStorageHosts) { try { long hostId = secondaryStorageHost.getId(); - List destroyedTemplateHostVOs = _vmTemplateHostDao.listDestroyed(hostId); - s_logger.debug("Secondary storage garbage collector found " + destroyedTemplateHostVOs.size() + " templates to cleanup on secondary storage host: " + List destroyedTemplateHostVOs = _vmTemplateHostDao + .listDestroyed(hostId); + s_logger.debug("Secondary storage garbage collector found " + + destroyedTemplateHostVOs.size() + + " templates to cleanup on secondary storage host: " + secondaryStorageHost.getName()); for (VMTemplateHostVO destroyedTemplateHostVO : destroyedTemplateHostVOs) { - if (!_tmpltMgr.templateIsDeleteable(destroyedTemplateHostVO)) { + if (!_tmpltMgr + .templateIsDeleteable(destroyedTemplateHostVO)) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Not deleting template at: " + destroyedTemplateHostVO); + s_logger.debug("Not deleting template at: " + + destroyedTemplateHostVO); } continue; } if (s_logger.isDebugEnabled()) { - s_logger.debug("Deleting template host: " + destroyedTemplateHostVO); + s_logger.debug("Deleting template host: " + + destroyedTemplateHostVO); } - String installPath = destroyedTemplateHostVO.getInstallPath(); + String installPath = destroyedTemplateHostVO + .getInstallPath(); if (installPath != null) { - Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(), destroyedTemplateHostVO.getInstallPath())); + Answer answer = _agentMgr.sendToSecStorage( + secondaryStorageHost, + new DeleteTemplateCommand( + secondaryStorageHost + .getStorageUrl(), + destroyedTemplateHostVO + .getInstallPath())); if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + destroyedTemplateHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); + s_logger.debug("Failed to delete " + + destroyedTemplateHostVO + + " due to " + + ((answer == null) ? "answer is null" + : answer.getDetails())); } else { - _vmTemplateHostDao.remove(destroyedTemplateHostVO.getId()); - s_logger.debug("Deleted template at: " + destroyedTemplateHostVO.getInstallPath()); + _vmTemplateHostDao + .remove(destroyedTemplateHostVO.getId()); + s_logger.debug("Deleted template at: " + + destroyedTemplateHostVO + .getInstallPath()); } } else { - _vmTemplateHostDao.remove(destroyedTemplateHostVO.getId()); + _vmTemplateHostDao.remove(destroyedTemplateHostVO + .getId()); } } } catch (Exception e) { - s_logger.warn("problem cleaning up templates in secondary storage " + secondaryStorageHost, e); + s_logger.warn( + "problem cleaning up templates in secondary storage " + + secondaryStorageHost, e); } } @@ -2511,9 +1274,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C for (Long volumeId : vIDs) { boolean lock = false; try { - VolumeVO volume = _volsDao.findByIdIncludingRemoved(volumeId); + VolumeVO volume = _volsDao + .findByIdIncludingRemoved(volumeId); if (volume.getRemoved() == null) { - volume = _volsDao.acquireInLockTable(volumeId, 10); + volume = _volsDao.acquireInLockTable(volumeId, + 10); if (volume == null) { continue; } @@ -2523,16 +1288,25 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C if (snapshots == null) { continue; } - CleanupSnapshotBackupCommand cmd = new CleanupSnapshotBackupCommand(secondaryStorageHost.getStorageUrl(), secondaryStorageHost.getDataCenterId(), volume.getAccountId(), - volumeId, snapshots); + CleanupSnapshotBackupCommand cmd = new CleanupSnapshotBackupCommand( + secondaryStorageHost.getStorageUrl(), + secondaryStorageHost.getDataCenterId(), + volume.getAccountId(), volumeId, snapshots); - Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, cmd); + Answer answer = _agentMgr.sendToSecStorage( + secondaryStorageHost, cmd); if ((answer == null) || !answer.getResult()) { - String details = "Failed to cleanup snapshots for volume " + volumeId + " due to " + (answer == null ? "null" : answer.getDetails()); + String details = "Failed to cleanup snapshots for volume " + + volumeId + + " due to " + + (answer == null ? "null" : answer + .getDetails()); s_logger.warn(details); } } catch (Exception e1) { - s_logger.warn("problem cleaning up snapshots in secondary storage " + secondaryStorageHost, e1); + s_logger.warn( + "problem cleaning up snapshots in secondary storage " + + secondaryStorageHost, e1); } finally { if (lock) { _volsDao.releaseFromLockTable(volumeId); @@ -2540,40 +1314,63 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } } catch (Exception e2) { - s_logger.warn("problem cleaning up snapshots in secondary storage " + secondaryStorageHost, e2); + s_logger.warn( + "problem cleaning up snapshots in secondary storage " + + secondaryStorageHost, e2); } } - //CleanUp volumes on Secondary Storage. + // CleanUp volumes on Secondary Storage. for (HostVO secondaryStorageHost : secondaryStorageHosts) { try { long hostId = secondaryStorageHost.getId(); - List destroyedVolumeHostVOs = _volumeHostDao.listDestroyed(hostId); - s_logger.debug("Secondary storage garbage collector found " + destroyedVolumeHostVOs.size() + " templates to cleanup on secondary storage host: " + List destroyedVolumeHostVOs = _volumeHostDao + .listDestroyed(hostId); + s_logger.debug("Secondary storage garbage collector found " + + destroyedVolumeHostVOs.size() + + " templates to cleanup on secondary storage host: " + secondaryStorageHost.getName()); for (VolumeHostVO destroyedVolumeHostVO : destroyedVolumeHostVOs) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Deleting volume host: " + destroyedVolumeHostVO); + s_logger.debug("Deleting volume host: " + + destroyedVolumeHostVO); } - String installPath = destroyedVolumeHostVO.getInstallPath(); + String installPath = destroyedVolumeHostVO + .getInstallPath(); if (installPath != null) { - Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteVolumeCommand(secondaryStorageHost.getStorageUrl(), destroyedVolumeHostVO.getInstallPath())); + Answer answer = _agentMgr.sendToSecStorage( + secondaryStorageHost, + new DeleteVolumeCommand( + secondaryStorageHost + .getStorageUrl(), + destroyedVolumeHostVO + .getInstallPath())); if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + destroyedVolumeHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); + s_logger.debug("Failed to delete " + + destroyedVolumeHostVO + + " due to " + + ((answer == null) ? "answer is null" + : answer.getDetails())); } else { - _volumeHostDao.remove(destroyedVolumeHostVO.getId()); - s_logger.debug("Deleted volume at: " + destroyedVolumeHostVO.getInstallPath()); + _volumeHostDao.remove(destroyedVolumeHostVO + .getId()); + s_logger.debug("Deleted volume at: " + + destroyedVolumeHostVO + .getInstallPath()); } } else { - _volumeHostDao.remove(destroyedVolumeHostVO.getId()); + _volumeHostDao + .remove(destroyedVolumeHostVO.getId()); } } - }catch (Exception e2) { - s_logger.warn("problem cleaning up volumes in secondary storage " + secondaryStorageHost, e2); + } catch (Exception e2) { + s_logger.warn( + "problem cleaning up volumes in secondary storage " + + secondaryStorageHost, e2); } } } catch (Exception e3) { @@ -2585,235 +1382,63 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C public String getPrimaryStorageNameLabel(VolumeVO volume) { Long poolId = volume.getPoolId(); - // poolId is null only if volume is destroyed, which has been checked before. + // poolId is null only if volume is destroyed, which has been checked + // before. assert poolId != null; - StoragePoolVO storagePoolVO = _storagePoolDao.findById(poolId); - assert storagePoolVO != null; - return storagePoolVO.getUuid(); + StoragePoolVO PrimaryDataStoreVO = _storagePoolDao + .findById(poolId); + assert PrimaryDataStoreVO != null; + return PrimaryDataStoreVO.getUuid(); } @Override @DB - public StoragePoolVO preparePrimaryStorageForMaintenance(Long primaryStorageId) throws ResourceUnavailableException, InsufficientCapacityException { + public PrimaryDataStoreInfo preparePrimaryStorageForMaintenance( + Long primaryStorageId) throws ResourceUnavailableException, + InsufficientCapacityException { Long userId = UserContext.current().getCallerUserId(); User user = _userDao.findById(userId); Account account = UserContext.current().getCaller(); + boolean restart = true; StoragePoolVO primaryStorage = null; - try { - // 1. Get the primary storage record and perform validation check - primaryStorage = _storagePoolDao.lockRow(primaryStorageId, true); - if (primaryStorage == null) { - String msg = "Unable to obtain lock on the storage pool record in preparePrimaryStorageForMaintenance()"; - s_logger.error(msg); - throw new ExecutionException(msg); - } - - List spes = _storagePoolDao.listBy(primaryStorage.getDataCenterId(), primaryStorage.getPodId(), primaryStorage.getClusterId()); - for (StoragePoolVO sp : spes) { - if (sp.getStatus() == StoragePoolStatus.PrepareForMaintenance) { - throw new CloudRuntimeException("Only one storage pool in a cluster can be in PrepareForMaintenance mode, " + sp.getId() + " is already in PrepareForMaintenance mode "); - } - } - - if (!primaryStorage.getStatus().equals(StoragePoolStatus.Up) && !primaryStorage.getStatus().equals(StoragePoolStatus.ErrorInMaintenance)) { - throw new InvalidParameterValueException("Primary storage with id " + primaryStorageId + " is not ready for migration, as the status is:" + primaryStorage.getStatus().toString()); - } - - List hosts = _resourceMgr.listHostsInClusterByStatus(primaryStorage.getClusterId(), Status.Up); - if (hosts == null || hosts.size() == 0) { - primaryStorage.setStatus(StoragePoolStatus.Maintenance); - _storagePoolDao.update(primaryStorageId, primaryStorage); - return _storagePoolDao.findById(primaryStorageId); - } else { - // set the pool state to prepare for maintenance - primaryStorage.setStatus(StoragePoolStatus.PrepareForMaintenance); - _storagePoolDao.update(primaryStorageId, primaryStorage); - } - // remove heartbeat - for (HostVO host : hosts) { - ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(false, primaryStorage); - final Answer answer = _agentMgr.easySend(host.getId(), cmd); - if (answer == null || !answer.getResult()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("ModifyStoragePool false failed due to " + ((answer == null) ? "answer null" : answer.getDetails())); - } - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("ModifyStoragePool false secceeded"); - } - } - } - // check to see if other ps exist - // if they do, then we can migrate over the system vms to them - // if they dont, then just stop all vms on this one - List upPools = _storagePoolDao.listByStatusInZone(primaryStorage.getDataCenterId(), StoragePoolStatus.Up); - - if (upPools == null || upPools.size() == 0) { - restart = false; - } - - // 2. Get a list of all the ROOT volumes within this storage pool - List allVolumes = _volsDao.findByPoolId(primaryStorageId); - - // 3. Enqueue to the work queue - for (VolumeVO volume : allVolumes) { - VMInstanceVO vmInstance = _vmInstanceDao.findById(volume.getInstanceId()); - - if (vmInstance == null) { - continue; - } - - // enqueue sp work - if (vmInstance.getState().equals(State.Running) || vmInstance.getState().equals(State.Starting) || vmInstance.getState().equals(State.Stopping)) { - - try { - StoragePoolWorkVO work = new StoragePoolWorkVO(vmInstance.getId(), primaryStorageId, false, false, _serverId); - _storagePoolWorkDao.persist(work); - } catch (Exception e) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Work record already exists, re-using by re-setting values"); - } - StoragePoolWorkVO work = _storagePoolWorkDao.findByPoolIdAndVmId(primaryStorageId, vmInstance.getId()); - work.setStartedAfterMaintenance(false); - work.setStoppedForMaintenance(false); - work.setManagementServerId(_serverId); - _storagePoolWorkDao.update(work.getId(), work); - } - } - } - - // 4. Process the queue - List pendingWork = _storagePoolWorkDao.listPendingWorkForPrepareForMaintenanceByPoolId(primaryStorageId); - - for (StoragePoolWorkVO work : pendingWork) { - // shut down the running vms - VMInstanceVO vmInstance = _vmInstanceDao.findById(work.getVmId()); - - if (vmInstance == null) { - continue; - } - - // if the instance is of type consoleproxy, call the console proxy - if (vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) { - // call the consoleproxymanager - ConsoleProxyVO consoleProxy = _consoleProxyDao.findById(vmInstance.getId()); - if (!_vmMgr.advanceStop(consoleProxy, true, user, account)) { - String errorMsg = "There was an error stopping the console proxy id: " + vmInstance.getId() + " ,cannot enable storage maintenance"; - s_logger.warn(errorMsg); - throw new CloudRuntimeException(errorMsg); - } else { - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - - if (restart) { - - if (_vmMgr.advanceStart(consoleProxy, null, user, account) == null) { - String errorMsg = "There was an error starting the console proxy id: " + vmInstance.getId() + " on another storage pool, cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - } else { - // update work status - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - } - - // if the instance is of type uservm, call the user vm manager - if (vmInstance.getType().equals(VirtualMachine.Type.User)) { - UserVmVO userVm = _userVmDao.findById(vmInstance.getId()); - if (!_vmMgr.advanceStop(userVm, true, user, account)) { - String errorMsg = "There was an error stopping the user vm id: " + vmInstance.getId() + " ,cannot enable storage maintenance"; - s_logger.warn(errorMsg); - throw new CloudRuntimeException(errorMsg); - } else { - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - - // if the instance is of type secondary storage vm, call the secondary storage vm manager - if (vmInstance.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) { - SecondaryStorageVmVO secStrgVm = _secStrgDao.findById(vmInstance.getId()); - if (!_vmMgr.advanceStop(secStrgVm, true, user, account)) { - String errorMsg = "There was an error stopping the ssvm id: " + vmInstance.getId() + " ,cannot enable storage maintenance"; - s_logger.warn(errorMsg); - throw new CloudRuntimeException(errorMsg); - } else { - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - - if (restart) { - if (_vmMgr.advanceStart(secStrgVm, null, user, account) == null) { - String errorMsg = "There was an error starting the ssvm id: " + vmInstance.getId() + " on another storage pool, cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - } else { - // update work status - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - } - - // if the instance is of type domain router vm, call the network manager - if (vmInstance.getType().equals(VirtualMachine.Type.DomainRouter)) { - DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); - if (!_vmMgr.advanceStop(domR, true, user, account)) { - String errorMsg = "There was an error stopping the domain router id: " + vmInstance.getId() + " ,cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - throw new CloudRuntimeException(errorMsg); - } else { - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - - if (restart) { - if (_vmMgr.advanceStart(domR, null, user, account) == null) { - String errorMsg = "There was an error starting the domain router id: " + vmInstance.getId() + " on another storage pool, cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - } else { - // update work status - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - } - } - - // 5. Update the status - primaryStorage.setStatus(StoragePoolStatus.Maintenance); - _storagePoolDao.update(primaryStorageId, primaryStorage); - - return _storagePoolDao.findById(primaryStorageId); - } catch (Exception e) { - if (e instanceof ExecutionException || e instanceof ResourceUnavailableException) { - s_logger.error("Exception in enabling primary storage maintenance:", e); - setPoolStateToError(primaryStorage); - throw (ResourceUnavailableException) e; - } - if (e instanceof InvalidParameterValueException) { - s_logger.error("Exception in enabling primary storage maintenance:", e); - setPoolStateToError(primaryStorage); - throw (InvalidParameterValueException) e; - } - if (e instanceof InsufficientCapacityException) { - s_logger.error("Exception in enabling primary storage maintenance:", e); - setPoolStateToError(primaryStorage); - throw (InsufficientCapacityException) e; - } - // for everything else - s_logger.error("Exception in enabling primary storage maintenance:", e); - setPoolStateToError(primaryStorage); - throw new CloudRuntimeException(e.getMessage()); + primaryStorage = _storagePoolDao.findById(primaryStorageId); + if (primaryStorage == null) { + String msg = "Unable to obtain lock on the storage pool record in preparePrimaryStorageForMaintenance()"; + s_logger.error(msg); + throw new InvalidParameterValueException(msg); } + + List spes = _storagePoolDao.listBy( + primaryStorage.getDataCenterId(), primaryStorage.getPodId(), + primaryStorage.getClusterId()); + for (StoragePoolVO sp : spes) { + if (sp.getStatus() == StoragePoolStatus.PrepareForMaintenance) { + throw new CloudRuntimeException( + "Only one storage pool in a cluster can be in PrepareForMaintenance mode, " + + sp.getId() + + " is already in PrepareForMaintenance mode "); + } + } + + if (!primaryStorage.getStatus().equals(DataStoreStatus.Up) + && !primaryStorage.getStatus().equals( + DataStoreStatus.ErrorInMaintenance)) { + throw new InvalidParameterValueException("Primary storage with id " + + primaryStorageId + + " is not ready for migration, as the status is:" + + primaryStorage.getStatus().toString()); + } + + DataStoreProvider provider = dataStoreProviderMgr + .getDataStoreProviderById(primaryStorage.getStorageProviderId()); + DataStoreLifeCycle lifeCycle = provider.getLifeCycle(); + lifeCycle.maintain(primaryStorage.getId()); + + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore( + primaryStorage.getId(), DataStoreRole.Primary); } private void setPoolStateToError(StoragePoolVO primaryStorage) { @@ -2823,156 +1448,46 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Override @DB - public StoragePoolVO cancelPrimaryStorageForMaintenance(CancelPrimaryStorageMaintenanceCmd cmd) throws ResourceUnavailableException { + public PrimaryDataStoreInfo cancelPrimaryStorageForMaintenance( + CancelPrimaryStorageMaintenanceCmd cmd) + throws ResourceUnavailableException { Long primaryStorageId = cmd.getId(); Long userId = UserContext.current().getCallerUserId(); User user = _userDao.findById(userId); Account account = UserContext.current().getCaller(); StoragePoolVO primaryStorage = null; - try { - Transaction txn = Transaction.currentTxn(); - txn.start(); - // 1. Get the primary storage record and perform validation check - primaryStorage = _storagePoolDao.lockRow(primaryStorageId, true); - if (primaryStorage == null) { - String msg = "Unable to obtain lock on the storage pool in cancelPrimaryStorageForMaintenance()"; - s_logger.error(msg); - throw new ExecutionException(msg); - } + primaryStorage = _storagePoolDao.findById(primaryStorageId); - if (primaryStorage.getStatus().equals(StoragePoolStatus.Up) || primaryStorage.getStatus().equals(StoragePoolStatus.PrepareForMaintenance)) { - throw new StorageUnavailableException("Primary storage with id " + primaryStorageId + " is not ready to complete migration, as the status is:" + primaryStorage.getStatus().toString(), - primaryStorageId); - } - - // Change the storage state back to up - primaryStorage.setStatus(StoragePoolStatus.Up); - _storagePoolDao.update(primaryStorageId, primaryStorage); - txn.commit(); - List hosts = _resourceMgr.listHostsInClusterByStatus(primaryStorage.getClusterId(), Status.Up); - if (hosts == null || hosts.size() == 0) { - return _storagePoolDao.findById(primaryStorageId); - } - // add heartbeat - for (HostVO host : hosts) { - ModifyStoragePoolCommand msPoolCmd = new ModifyStoragePoolCommand(true, primaryStorage); - final Answer answer = _agentMgr.easySend(host.getId(), msPoolCmd); - if (answer == null || !answer.getResult()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("ModifyStoragePool add failed due to " + ((answer == null) ? "answer null" : answer.getDetails())); - } - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("ModifyStoragePool add secceeded"); - } - } - } - - // 2. Get a list of pending work for this queue - List pendingWork = _storagePoolWorkDao.listPendingWorkForCancelMaintenanceByPoolId(primaryStorageId); - - // 3. work through the queue - for (StoragePoolWorkVO work : pendingWork) { - - VMInstanceVO vmInstance = _vmInstanceDao.findById(work.getVmId()); - - if (vmInstance == null) { - continue; - } - - // if the instance is of type consoleproxy, call the console proxy - if (vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) { - - ConsoleProxyVO consoleProxy = _consoleProxyDao.findById(vmInstance.getId()); - if (_vmMgr.advanceStart(consoleProxy, null, user, account) == null) { - String msg = "There was an error starting the console proxy id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } else { - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - - // if the instance is of type ssvm, call the ssvm manager - if (vmInstance.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) { - SecondaryStorageVmVO ssVm = _secStrgDao.findById(vmInstance.getId()); - if (_vmMgr.advanceStart(ssVm, null, user, account) == null) { - String msg = "There was an error starting the ssvm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } else { - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - - // if the instance is of type ssvm, call the ssvm manager - if (vmInstance.getType().equals(VirtualMachine.Type.DomainRouter)) { - DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); - if (_vmMgr.advanceStart(domR, null, user, account) == null) { - String msg = "There was an error starting the domR id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } else { - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - - // if the instance is of type user vm, call the user vm manager - if (vmInstance.getType().equals(VirtualMachine.Type.User)) { - UserVmVO userVm = _userVmDao.findById(vmInstance.getId()); - try { - if (_vmMgr.advanceStart(userVm, null, user, account) == null) { - - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } else { - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } catch (StorageUnavailableException e) { - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg, e); - throw new ExecutionException(msg); - } catch (InsufficientCapacityException e) { - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg, e); - throw new ExecutionException(msg); - } catch (ConcurrentOperationException e) { - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg, e); - throw new ExecutionException(msg); - } catch (ExecutionException e) { - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg, e); - throw new ExecutionException(msg); - } - } - } - return primaryStorage; - } catch (Exception e) { - setPoolStateToError(primaryStorage); - if (e instanceof ExecutionException) { - throw (ResourceUnavailableException) e; - } else if (e instanceof InvalidParameterValueException) { - throw (InvalidParameterValueException) e; - } else {// all other exceptions - throw new CloudRuntimeException(e.getMessage()); - } + if (primaryStorage == null) { + String msg = "Unable to obtain lock on the storage pool in cancelPrimaryStorageForMaintenance()"; + s_logger.error(msg); + throw new InvalidParameterValueException(msg); } + + if (primaryStorage.getStatus().equals(DataStoreStatus.Up) + || primaryStorage.getStatus().equals( + DataStoreStatus.PrepareForMaintenance)) { + throw new StorageUnavailableException("Primary storage with id " + + primaryStorageId + + " is not ready to complete migration, as the status is:" + + primaryStorage.getStatus().toString(), primaryStorageId); + } + + DataStoreProvider provider = dataStoreProviderMgr + .getDataStoreProviderById(primaryStorage.getStorageProviderId()); + DataStoreLifeCycle lifeCycle = provider.getLifeCycle(); + lifeCycle.cancelMaintain(primaryStorage.getId()); + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore( + primaryStorage.getId(), DataStoreRole.Primary); } - private boolean sendToVmResidesOn(StoragePoolVO storagePool, Command cmd) { - ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId()); - if ((cluster.getHypervisorType() == HypervisorType.KVM || cluster.getHypervisorType() == HypervisorType.VMware) + private boolean sendToVmResidesOn(StoragePoolVO PrimaryDataStoreVO, + Command cmd) { + ClusterVO cluster = _clusterDao.findById(PrimaryDataStoreVO + .getClusterId()); + if ((cluster.getHypervisorType() == HypervisorType.KVM || cluster + .getHypervisorType() == HypervisorType.VMware) && ((cmd instanceof ManageSnapshotCommand) || (cmd instanceof BackupSnapshotCommand))) { return true; } else { @@ -2980,754 +1495,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume") - public boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException { - - // Check that the volume ID is valid - VolumeVO volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new InvalidParameterValueException("Unable to aquire volume with ID: " + volumeId); - } - - if (!_snapshotMgr.canOperateOnVolume(volume)) { - throw new InvalidParameterValueException("There are snapshot creating on it, Unable to delete the volume"); - } - - // permission check - _accountMgr.checkAccess(caller, null, true, volume); - - // Check that the volume is not currently attached to any VM - if (volume.getInstanceId() != null) { - throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM."); - } - - // Check that volume is completely Uploaded - if (volume.getState() == Volume.State.UploadOp){ - VolumeHostVO volumeHost = _volumeHostDao.findByVolumeId(volume.getId()); - if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS){ - throw new InvalidParameterValueException("Please specify a volume that is not uploading"); - } - } - - // Check that the volume is not already destroyed - if (volume.getState() != Volume.State.Destroy) { - if (!destroyVolume(volume)) { - return false; - } - } - - try { - expungeVolume(volume, false); - } catch (Exception e) { - s_logger.warn("Failed to expunge volume:", e); - return false; - } - - return true; - } - - private boolean validateVolumeSizeRange(long size) { - if (size < 0 || (size > 0 && size < (1024 * 1024 * 1024))) { - throw new InvalidParameterValueException("Please specify a size of at least 1 Gb."); - } else if (size > (_maxVolumeSizeInGb * 1024 * 1024 * 1024)) { - throw new InvalidParameterValueException("volume size " + size + ", but the maximum size allowed is " + _maxVolumeSizeInGb + " Gb."); - } - - return true; - } - - protected DiskProfile toDiskProfile(VolumeVO vol, DiskOfferingVO offering) { - return new DiskProfile(vol.getId(), vol.getVolumeType(), vol.getName(), offering.getId(), vol.getSize(), offering.getTagsArray(), offering.getUseLocalStorage(), offering.isRecreatable(), - vol.getTemplateId()); - } - - @Override - public DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, T vm, Account owner) { - if (size == null) { - size = offering.getDiskSize(); - } else { - size = (size * 1024 * 1024 * 1024); - } - VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size); - if (vm != null) { - vol.setInstanceId(vm.getId()); - } - - if (type.equals(Type.ROOT)) { - vol.setDeviceId(0l); - } else { - vol.setDeviceId(1l); - } - - vol = _volsDao.persist(vol); - - // Save usage event and update resource count for user vm volumes - if (vm instanceof UserVm) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), - vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size, - Volume.class.getName(), vol.getUuid()); - _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume); - } - return toDiskProfile(vol, offering); - } - - @Override - public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOfferingVO offering, VMTemplateVO template, T vm, Account owner) { - assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really...."; - - SearchCriteria sc = HostTemplateStatesSearch.create(); - sc.setParameters("id", template.getId()); - sc.setParameters("state", com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); - sc.setJoinParameters("host", "dcId", vm.getDataCenterId()); - List tsvs = _vmTemplateSwiftDao.listByTemplateId(template.getId()); - Long size = null; - if (tsvs != null && tsvs.size() > 0) { - size = tsvs.get(0).getSize(); - } - - if (size == null && _s3Mgr.isS3Enabled()) { - VMTemplateS3VO vmTemplateS3VO = _vmTemplateS3Dao.findOneByTemplateId(template.getId()); - if (vmTemplateS3VO != null) { - size = vmTemplateS3VO.getSize(); - } - } - - if (size == null) { - List sss = _vmTemplateHostDao.search(sc, null); - if (sss == null || sss.size() == 0) { - throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + vm.getDataCenterId()); - } - size = sss.get(0).getSize(); - } - - VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size); - if (vm != null) { - vol.setInstanceId(vm.getId()); - } - vol.setTemplateId(template.getId()); - - if (type.equals(Type.ROOT)) { - vol.setDeviceId(0l); - if (!vm.getType().equals(VirtualMachine.Type.User)) { - vol.setRecreatable(true); - } - } else { - vol.setDeviceId(1l); - } - - vol = _volsDao.persist(vol); - - // Create event and update resource count for volumes if vm is a user vm - if (vm instanceof UserVm) { - - Long offeringId = null; - - if (offering.getType() == DiskOfferingVO.Type.Disk) { - offeringId = offering.getId(); - } - - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), - vol.getDataCenterId(), vol.getId(), vol.getName(), offeringId, template.getId(), - vol.getSize(), Volume.class.getName(), vol.getUuid()); - - _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume); - } - return toDiskProfile(vol, offering); - } - - @Override - public void prepareForMigration(VirtualMachineProfile vm, DeployDestination dest) { - List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Preparing " + vols.size() + " volumes for " + vm); - } - - for (VolumeVO vol : vols) { - StoragePool pool = _storagePoolDao.findById(vol.getPoolId()); - vm.addDisk(new VolumeTO(vol, pool)); - } - - if (vm.getType() == VirtualMachine.Type.User) { - UserVmVO userVM = (UserVmVO) vm.getVirtualMachine(); - if (userVM.getIsoId() != null) { - Pair isoPathPair = getAbsoluteIsoPath(userVM.getIsoId(), userVM.getDataCenterId()); - if (isoPathPair != null) { - String isoPath = isoPathPair.first(); - VolumeTO iso = new VolumeTO(vm.getId(), Volume.Type.ISO, StoragePoolType.ISO, null, null, null, isoPath, 0, null, null); - vm.addDisk(iso); - } - } - } - } - - @DB - @Override - public Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException { - VolumeVO vol = _volsDao.findById(volumeId); - if (vol == null) { - throw new InvalidParameterValueException("Failed to find the volume id: " + volumeId); - } - - if (vol.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException("Volume must be in ready state"); - } - - if (vol.getInstanceId() != null) { - throw new InvalidParameterValueException("Volume needs to be dettached from VM"); - } - - StoragePool destPool = _storagePoolDao.findById(storagePoolId); - if (destPool == null) { - throw new InvalidParameterValueException("Failed to find the destination storage pool: " + storagePoolId); - } - - if (!volumeOnSharedStoragePool(vol)) { - throw new InvalidParameterValueException("Migration of volume from local storage pool is not supported"); - } - - List vols = new ArrayList(); - vols.add(vol); - - migrateVolumes(vols, destPool); - return vol; - } - - @DB - public boolean migrateVolumes(List volumes, StoragePool destPool) throws ConcurrentOperationException { - Transaction txn = Transaction.currentTxn(); - txn.start(); - - boolean transitResult = false; - long checkPointTaskId = -1; - try { - List volIds = new ArrayList(); - for (Volume volume : volumes) { - if (!_snapshotMgr.canOperateOnVolume((VolumeVO) volume)) { - throw new CloudRuntimeException("There are snapshots creating on this volume, can not move this volume"); - } - - try { - if (!stateTransitTo(volume, Volume.Event.MigrationRequested)) { - throw new ConcurrentOperationException("Failed to transit volume state"); - } - } catch (NoTransitionException e) { - s_logger.debug("Failed to set state into migrate: " + e.toString()); - throw new CloudRuntimeException("Failed to set state into migrate: " + e.toString()); - } - volIds.add(volume.getId()); - } - - transitResult = true; - } finally { - if (!transitResult) { - txn.rollback(); - } else { - txn.commit(); - } - } - - // At this stage, nobody can modify volumes. Send the copyvolume command - List> destroyCmds = new ArrayList>(); - List answers = new ArrayList(); - try { - for (Volume volume : volumes) { - String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId()); - StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId()); - CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volume.getPath(), srcPool, secondaryStorageURL, true, _copyvolumewait); - CopyVolumeAnswer cvAnswer; - try { - cvAnswer = (CopyVolumeAnswer) sendToPool(srcPool, cvCmd); - } catch (StorageUnavailableException e1) { - throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.", e1); - } - - if (cvAnswer == null || !cvAnswer.getResult()) { - throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage."); - } - - String secondaryStorageVolumePath = cvAnswer.getVolumePath(); - - // Copy the volume from secondary storage to the destination storage - // pool - cvCmd = new CopyVolumeCommand(volume.getId(), secondaryStorageVolumePath, destPool, secondaryStorageURL, false, _copyvolumewait); - try { - cvAnswer = (CopyVolumeAnswer) sendToPool(destPool, cvCmd); - } catch (StorageUnavailableException e1) { - throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); - } - - if (cvAnswer == null || !cvAnswer.getResult()) { - throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); - } - - answers.add(cvAnswer); - destroyCmds.add(new Pair(srcPool, new DestroyCommand(srcPool, volume, null))); - } - } finally { - if (answers.size() != volumes.size()) { - // this means one of copying volume failed - for (Volume volume : volumes) { - try { - stateTransitTo(volume, Volume.Event.OperationFailed); - } catch (NoTransitionException e) { - s_logger.debug("Failed to change volume state: " + e.toString()); - } - } - } else { - // Need a transaction, make sure all the volumes get migrated to new storage pool - txn = Transaction.currentTxn(); - txn.start(); - - transitResult = false; - try { - for (int i = 0; i < volumes.size(); i++) { - CopyVolumeAnswer answer = answers.get(i); - VolumeVO volume = (VolumeVO) volumes.get(i); - Long oldPoolId = volume.getPoolId(); - volume.setPath(answer.getVolumePath()); - volume.setFolder(destPool.getPath()); - volume.setPodId(destPool.getPodId()); - volume.setPoolId(destPool.getId()); - volume.setLastPoolId(oldPoolId); - volume.setPodId(destPool.getPodId()); - try { - stateTransitTo(volume, Volume.Event.OperationSucceeded); - } catch (NoTransitionException e) { - s_logger.debug("Failed to change volume state: " + e.toString()); - throw new CloudRuntimeException("Failed to change volume state: " + e.toString()); - } - } - transitResult = true; - } finally { - if (!transitResult) { - txn.rollback(); - } else { - txn.commit(); - } - } - - } - } - - // all the volumes get migrated to new storage pool, need to delete the copy on old storage pool - for (Pair cmd : destroyCmds) { - try { - Answer cvAnswer = sendToPool(cmd.first(), cmd.second()); - } catch (StorageUnavailableException e) { - s_logger.debug("Unable to delete the old copy on storage pool: " + e.toString()); - } - } - return true; - } - - @Override - public boolean StorageMigration(VirtualMachineProfile vm, StoragePool destPool) throws ConcurrentOperationException { - List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); - List volumesNeedToMigrate = new ArrayList(); - - for (VolumeVO volume : vols) { - if (volume.getState() != Volume.State.Ready) { - s_logger.debug("volume: " + volume.getId() + " is in " + volume.getState() + " state"); - throw new CloudRuntimeException("volume: " + volume.getId() + " is in " + volume.getState() + " state"); - } - - if (volume.getPoolId() == destPool.getId()) { - s_logger.debug("volume: " + volume.getId() + " is on the same storage pool: " + destPool.getId()); - continue; - } - - volumesNeedToMigrate.add(volume); - } - - if (volumesNeedToMigrate.isEmpty()) { - s_logger.debug("No volume need to be migrated"); - return true; - } - - return migrateVolumes(volumesNeedToMigrate, destPool); - } - - @Override - public void prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException { - - if (dest == null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("DeployDestination cannot be null, cannot prepare Volumes for the vm: " + vm); - } - throw new CloudRuntimeException("Unable to prepare Volume for vm because DeployDestination is null, vm:" + vm); - } - List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Checking if we need to prepare " + vols.size() + " volumes for " + vm); - } - - boolean recreate = _recreateSystemVmEnabled; - - List recreateVols = new ArrayList(vols.size()); - - for (VolumeVO vol : vols) { - StoragePool assignedPool = null; - if (dest.getStorageForDisks() != null) { - assignedPool = dest.getStorageForDisks().get(vol); - } - if (assignedPool == null && recreate) { - assignedPool = _storagePoolDao.findById(vol.getPoolId()); - - } - if (assignedPool != null || recreate) { - Volume.State state = vol.getState(); - if (state == Volume.State.Allocated || state == Volume.State.Creating) { - recreateVols.add(vol); - } else { - if (vol.isRecreatable()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume " + vol + " will be recreated on storage pool " + assignedPool + " assigned by deploymentPlanner"); - } - recreateVols.add(vol); - } else { - if (assignedPool.getId() != vol.getPoolId()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Mismatch in storage pool " + assignedPool + " assigned by deploymentPlanner and the one associated with volume " + vol); - } - DiskOfferingVO diskOffering = _diskOfferingDao.findById(vol.getDiskOfferingId()); - if (diskOffering.getUseLocalStorage()) - { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Local volume " + vol + " will be recreated on storage pool " + assignedPool + " assigned by deploymentPlanner"); - } - recreateVols.add(vol); - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Shared volume " + vol + " will be migrated on storage pool " + assignedPool + " assigned by deploymentPlanner"); - } - try { - List volumesToMigrate = new ArrayList(); - volumesToMigrate.add(vol); - migrateVolumes(volumesToMigrate, assignedPool); - vm.addDisk(new VolumeTO(vol, assignedPool)); - } catch (ConcurrentOperationException e) { - throw new CloudRuntimeException("Migration of volume " + vol + " to storage pool " + assignedPool + " failed", e); - } - } - } else { - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); - vm.addDisk(new VolumeTO(vol, pool)); - } - - } - } - } else { - if (vol.getPoolId() == null) { - throw new StorageUnavailableException("Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create " + vol, Volume.class, vol.getId()); - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("No need to recreate the volume: " + vol + ", since it already has a pool assigned: " + vol.getPoolId() + ", adding disk to VM"); - } - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); - vm.addDisk(new VolumeTO(vol, pool)); - } - } - - for (VolumeVO vol : recreateVols) { - VolumeVO newVol; - StoragePool existingPool = null; - if (recreate && (dest.getStorageForDisks() == null || dest.getStorageForDisks().get(vol) == null)) { - existingPool = _storagePoolDao.findById(vol.getPoolId()); - s_logger.debug("existing pool: " + existingPool.getId()); - } - - if (vol.getState() == Volume.State.Allocated || vol.getState() == Volume.State.Creating) { - newVol = vol; - } else { - newVol = switchVolume(vol, vm); - // update the volume->storagePool map since volumeId has changed - if (dest.getStorageForDisks() != null && dest.getStorageForDisks().containsKey(vol)) { - StoragePool poolWithOldVol = dest.getStorageForDisks().get(vol); - dest.getStorageForDisks().put(newVol, poolWithOldVol); - dest.getStorageForDisks().remove(vol); - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Created new volume " + newVol + " for old volume " + vol); - } - } - - try { - stateTransitTo(newVol, Volume.Event.CreateRequested); - } catch (NoTransitionException e) { - throw new CloudRuntimeException("Unable to create " + e.toString()); - } - - Pair created = createVolume(newVol, _diskOfferingDao.findById(newVol.getDiskOfferingId()), vm, vols, dest, existingPool); - - if (created == null) { - Long poolId = newVol.getPoolId(); - newVol.setPoolId(null); - try { - stateTransitTo(newVol, Volume.Event.OperationFailed); - } catch (NoTransitionException e) { - throw new CloudRuntimeException("Unable to update the failure on a volume: " + newVol, e); - } - throw new StorageUnavailableException("Unable to create " + newVol, poolId == null ? -1L : poolId); - } - created.first().setDeviceId(newVol.getDeviceId().intValue()); - newVol.setFolder(created.second().getPath()); - newVol.setPath(created.first().getPath()); - newVol.setSize(created.first().getSize()); - newVol.setPoolType(created.second().getPoolType()); - newVol.setPodId(created.second().getPodId()); - try { - stateTransitTo(newVol, Volume.Event.OperationSucceeded); - } catch (NoTransitionException e) { - throw new CloudRuntimeException("Unable to update an CREATE operation succeeded on volume " + newVol, e); - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume " + newVol + " is created on " + created.second()); - } - - vm.addDisk(created.first()); - } - } - - @DB - protected VolumeVO switchVolume(VolumeVO existingVolume, VirtualMachineProfile vm) throws StorageUnavailableException { - Transaction txn = Transaction.currentTxn(); - - Long templateIdToUse = null; - Long volTemplateId = existingVolume.getTemplateId(); - long vmTemplateId = vm.getTemplateId(); - if (volTemplateId != null && volTemplateId.longValue() != vmTemplateId) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("switchVolume: Old Volume's templateId: " + volTemplateId + " does not match the VM's templateId: " + vmTemplateId + ", updating templateId in the new Volume"); - } - templateIdToUse = vmTemplateId; - } - - txn.start(); - VolumeVO newVolume = allocateDuplicateVolume(existingVolume, templateIdToUse); - // In case of Vmware if vm reference is not removed then during root disk cleanup - // the vm also gets deleted, so remove the reference - if (vm.getHypervisorType() == HypervisorType.VMware) { - _volsDao.detachVolume(existingVolume.getId()); - } - try { - stateTransitTo(existingVolume, Volume.Event.DestroyRequested); - } catch (NoTransitionException e) { - s_logger.debug("Unable to destroy existing volume: " + e.toString()); - } - txn.commit(); - return newVolume; - - } - - public Pair createVolume(VolumeVO toBeCreated, DiskOfferingVO offering, VirtualMachineProfile vm, List alreadyCreated, - DeployDestination dest, StoragePool sPool) throws StorageUnavailableException { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Creating volume: " + toBeCreated); - } - DiskProfile diskProfile = new DiskProfile(toBeCreated, offering, vm.getHypervisorType()); - - VMTemplateVO template = null; - if (toBeCreated.getTemplateId() != null) { - template = _templateDao.findById(toBeCreated.getTemplateId()); - } - - StoragePool pool = null; - if (sPool != null) { - pool = sPool; - } else { - pool = dest.getStorageForDisks().get(toBeCreated); - } - - if (pool != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Trying to create in " + pool); - } - toBeCreated.setPoolId(pool.getId()); - try { - stateTransitTo(toBeCreated, Volume.Event.OperationRetry); - } catch (NoTransitionException e) { - throw new CloudRuntimeException("Unable to retry a create operation on volume " + toBeCreated); - } - - CreateCommand cmd = null; - VMTemplateStoragePoolVO tmpltStoredOn = null; - - for (int i = 0; i < 2; i++) { - if (template != null && template.getFormat() != Storage.ImageFormat.ISO) { - if (pool.getPoolType() == StoragePoolType.CLVM) { - //prepareISOForCreate does what we need, which is to tell us where the template is - VMTemplateHostVO tmpltHostOn = _tmpltMgr.prepareISOForCreate(template, pool); - if (tmpltHostOn == null) { - s_logger.debug("cannot find template " + template.getId() + " " + template.getName()); - return null; - } - HostVO secondaryStorageHost = _hostDao.findById(tmpltHostOn.getHostId()); - String tmpltHostUrl = secondaryStorageHost.getStorageUrl(); - String fullTmpltUrl = tmpltHostUrl + "/" + tmpltHostOn.getInstallPath(); - cmd = new CreateCommand(diskProfile, fullTmpltUrl, new StorageFilerTO(pool)); - } else { - tmpltStoredOn = _tmpltMgr.prepareTemplateForCreate(template, pool); - if (tmpltStoredOn == null) { - s_logger.debug("Cannot use this pool " + pool + " because we can't propagate template " + template); - return null; - } - cmd = new CreateCommand(diskProfile, tmpltStoredOn.getLocalDownloadPath(), new StorageFilerTO(pool)); - } - } else { - if (template != null && Storage.ImageFormat.ISO == template.getFormat()) { - VMTemplateHostVO tmpltHostOn = _tmpltMgr.prepareISOForCreate(template, pool); - if (tmpltHostOn == null) { - throw new CloudRuntimeException("Did not find ISO in secondry storage in zone " + pool.getDataCenterId()); - } - } - cmd = new CreateCommand(diskProfile, new StorageFilerTO(pool)); - } - long[] hostIdsToTryFirst = { dest.getHost().getId() }; - Answer answer = sendToPool(pool, hostIdsToTryFirst, cmd); - if (answer.getResult()) { - CreateAnswer createAnswer = (CreateAnswer) answer; - return new Pair(createAnswer.getVolume(), pool); - } else { - if (tmpltStoredOn != null && (answer instanceof CreateAnswer) && ((CreateAnswer) answer).templateReloadRequested()) { - if (!_tmpltMgr.resetTemplateDownloadStateOnPool(tmpltStoredOn.getId())) { - break; // break out of template-redeploy retry loop - } - } else { - break; - } - } - } - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Unable to create volume " + toBeCreated); - } - return null; - } - - @Override - public void release(VirtualMachineProfile profile) { - // add code here - } - - public void expungeVolume(VolumeVO vol, boolean force) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Expunging " + vol); - } - - //Find out if the volume is present on secondary storage - VolumeHostVO volumeHost = _volumeHostDao.findByVolumeId(vol.getId()); - if(volumeHost != null){ - if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED){ - HostVO ssHost = _hostDao.findById(volumeHost.getHostId()); - DeleteVolumeCommand dtCommand = new DeleteVolumeCommand(ssHost.getStorageUrl(), volumeHost.getInstallPath()); - Answer answer = _agentMgr.sendToSecStorage(ssHost, dtCommand); - if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + volumeHost + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); - return; - } - }else if(volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS){ - s_logger.debug("Volume: " + vol.getName() + " is currently being uploaded; cant' delete it."); - throw new CloudRuntimeException("Please specify a volume that is not currently being uploaded."); - } - _volumeHostDao.remove(volumeHost.getId()); - _volumeDao.remove(vol.getId()); - return; - } - - String vmName = null; - if (vol.getVolumeType() == Type.ROOT && vol.getInstanceId() != null) { - VirtualMachine vm = _vmInstanceDao.findByIdIncludingRemoved(vol.getInstanceId()); - if (vm != null) { - vmName = vm.getInstanceName(); - } - } - - String volumePath = vol.getPath(); - Long poolId = vol.getPoolId(); - if (poolId == null || volumePath == null || volumePath.trim().isEmpty()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Marking volume that was never created as destroyed: " + vol); - } - _volsDao.remove(vol.getId()); - return; - } - - StoragePoolVO pool = _storagePoolDao.findById(poolId); - if (pool == null) { - s_logger.debug("Removing volume as storage pool is gone: " + poolId); - _volsDao.remove(vol.getId()); - return; - } - - DestroyCommand cmd = new DestroyCommand(pool, vol, vmName); - boolean removeVolume = false; - try { - Answer answer = sendToPool(pool, cmd); - if (answer != null && answer.getResult()) { - removeVolume = true; - } else { - s_logger.info("Will retry delete of " + vol + " from " + poolId); - } - } catch (StorageUnavailableException e) { - if (force) { - s_logger.info("Storage is unavailable currently, but marking volume id=" + vol.getId() + " as expunged anyway due to force=true"); - removeVolume = true; - } else { - s_logger.info("Storage is unavailable currently. Will retry delete of " + vol + " from " + poolId); - } - } catch (RuntimeException ex) { - if (force) { - s_logger.info("Failed to expunge volume, but marking volume id=" + vol.getId() + " as expunged anyway " + - "due to force=true. Volume failed to expunge due to ", ex); - removeVolume = true; - } else { - throw ex; - } - } finally { - if (removeVolume) { - _volsDao.remove(vol.getId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume successfully expunged from " + poolId); - } - } - } - - } - - @Override - @DB - public void cleanupVolumes(long vmId) throws ConcurrentOperationException { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Cleaning storage for vm: " + vmId); - } - List volumesForVm = _volsDao.findByInstance(vmId); - List toBeExpunged = new ArrayList(); - Transaction txn = Transaction.currentTxn(); - txn.start(); - for (VolumeVO vol : volumesForVm) { - if (vol.getVolumeType().equals(Type.ROOT)) { - // This check is for VM in Error state (volume is already destroyed) - if (!vol.getState().equals(Volume.State.Destroy)) { - destroyVolume(vol); - } - toBeExpunged.add(vol); - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Detaching " + vol); - } - _volsDao.detachVolume(vol.getId()); - } - } - txn.commit(); - - for (VolumeVO expunge : toBeExpunged) { - expungeVolume(expunge, false); - } - } - + + + protected class StorageGarbageCollector implements Runnable { public StorageGarbageCollector() { @@ -3747,25 +1517,35 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public void onManagementNodeJoined(List nodeList, long selfNodeId) { + public void onManagementNodeJoined(List nodeList, + long selfNodeId) { // TODO Auto-generated method stub } @Override - public void onManagementNodeLeft(List nodeList, long selfNodeId) { + public void onManagementNodeLeft(List nodeList, + long selfNodeId) { for (ManagementServerHostVO vo : nodeList) { if (vo.getMsid() == _serverId) { - s_logger.info("Cleaning up storage maintenance jobs associated with Management server" + vo.getMsid()); - List poolIds = _storagePoolWorkDao.searchForPoolIdsForPendingWorkJobs(vo.getMsid()); + s_logger.info("Cleaning up storage maintenance jobs associated with Management server" + + vo.getMsid()); + List poolIds = _storagePoolWorkDao + .searchForPoolIdsForPendingWorkJobs(vo.getMsid()); if (poolIds.size() > 0) { for (Long poolId : poolIds) { - StoragePoolVO pool = _storagePoolDao.findById(poolId); + StoragePoolVO pool = _storagePoolDao + .findById(poolId); // check if pool is in an inconsistent state if (pool != null - && (pool.getStatus().equals(StoragePoolStatus.ErrorInMaintenance) || pool.getStatus().equals(StoragePoolStatus.PrepareForMaintenance) || pool.getStatus().equals( - StoragePoolStatus.CancelMaintenance))) { - _storagePoolWorkDao.removePendingJobsOnMsRestart(vo.getMsid(), poolId); + && (pool.getStatus().equals( + DataStoreStatus.ErrorInMaintenance) + || pool.getStatus() + .equals(DataStoreStatus.PrepareForMaintenance) || pool + .getStatus() + .equals(DataStoreStatus.CancelMaintenance))) { + _storagePoolWorkDao.removePendingJobsOnMsRestart( + vo.getMsid(), poolId); pool.setStatus(StoragePoolStatus.ErrorInMaintenance); _storagePoolDao.update(poolId, pool); } @@ -3794,22 +1574,28 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); } - CapacityVO capacity = new CapacityVO(hostId, zoneId, null, null, 0, 0, CapacityVO.CAPACITY_TYPE_SECONDARY_STORAGE); + CapacityVO capacity = new CapacityVO(hostId, zoneId, null, null, 0, 0, + CapacityVO.CAPACITY_TYPE_SECONDARY_STORAGE); for (HostVO host : hosts) { - StorageStats stats = ApiDBUtils.getSecondaryStorageStatistics(host.getId()); + StorageStats stats = ApiDBUtils.getSecondaryStorageStatistics(host + .getId()); if (stats == null) { continue; } - capacity.setUsedCapacity(stats.getByteUsed() + capacity.getUsedCapacity()); - capacity.setTotalCapacity(stats.getCapacityBytes() + capacity.getTotalCapacity()); + capacity.setUsedCapacity(stats.getByteUsed() + + capacity.getUsedCapacity()); + capacity.setTotalCapacity(stats.getCapacityBytes() + + capacity.getTotalCapacity()); } return capacity; } @Override - public CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, Long podId, Long zoneId) { - SearchCriteria sc = _storagePoolDao.createSearchCriteria(); + public CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, + Long podId, Long zoneId) { + SearchCriteria sc = _storagePoolDao + .createSearchCriteria(); List pools = new ArrayList(); if (zoneId != null) { @@ -3833,59 +1619,29 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C pools = _storagePoolDao.search(sc, null); } - CapacityVO capacity = new CapacityVO(poolId, zoneId, podId, clusterId, 0, 0, CapacityVO.CAPACITY_TYPE_STORAGE); - for (StoragePoolVO storagePool : pools) { - StorageStats stats = ApiDBUtils.getStoragePoolStatistics(storagePool.getId()); + CapacityVO capacity = new CapacityVO(poolId, zoneId, podId, clusterId, + 0, 0, CapacityVO.CAPACITY_TYPE_STORAGE); + for (StoragePoolVO PrimaryDataStoreVO : pools) { + StorageStats stats = ApiDBUtils + .getStoragePoolStatistics(PrimaryDataStoreVO.getId()); if (stats == null) { continue; } - capacity.setUsedCapacity(stats.getByteUsed() + capacity.getUsedCapacity()); - capacity.setTotalCapacity(stats.getCapacityBytes() + capacity.getTotalCapacity()); + capacity.setUsedCapacity(stats.getByteUsed() + + capacity.getUsedCapacity()); + capacity.setTotalCapacity(stats.getCapacityBytes() + + capacity.getTotalCapacity()); } return capacity; } @Override - public StoragePool getStoragePool(long id) { - return _storagePoolDao.findById(id); + public PrimaryDataStoreInfo getStoragePool(long id) { + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore(id, + DataStoreRole.Primary); } - @Override - public VMTemplateHostVO findVmTemplateHost(long templateId, StoragePool pool) { - long dcId = pool.getDataCenterId(); - Long podId = pool.getPodId(); - - List secHosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(dcId); - - // FIXME, for cloudzone, the local secondary storoge - if (pool.isLocal() && pool.getPoolType() == StoragePoolType.Filesystem && secHosts.isEmpty()) { - List sphs = _storagePoolHostDao.listByPoolId(pool.getId()); - if (!sphs.isEmpty()) { - StoragePoolHostVO localStoragePoolHost = sphs.get(0); - return _templateHostDao.findLocalSecondaryStorageByHostTemplate(localStoragePoolHost.getHostId(), templateId); - } else { - return null; - } - } - - if (secHosts.size() == 1) { - VMTemplateHostVO templateHostVO = _templateHostDao.findByHostTemplate(secHosts.get(0).getId(), templateId); - return templateHostVO; - } - if (podId != null) { - List templHosts = _templateHostDao.listByTemplateStatus(templateId, dcId, podId, VMTemplateStorageResourceAssoc.Status.DOWNLOADED); - if (templHosts != null && !templHosts.isEmpty()) { - Collections.shuffle(templHosts); - return templHosts.get(0); - } - } - List templHosts = _templateHostDao.listByTemplateStatus(templateId, dcId, VMTemplateStorageResourceAssoc.Status.DOWNLOADED); - if (templHosts != null && !templHosts.isEmpty()) { - Collections.shuffle(templHosts); - return templHosts.get(0); - } - return null; - } + @Override @DB @@ -3900,9 +1656,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @DB public StoragePoolVO findLocalStorageOnHost(long hostId) { SearchCriteria sc = LocalStorageSearch.create(); - sc.setParameters("type", new Object[] { StoragePoolType.Filesystem, StoragePoolType.LVM }); + sc.setParameters("type", new Object[] { StoragePoolType.Filesystem, + StoragePoolType.LVM }); sc.setJoinParameters("poolHost", "hostId", hostId); - List storagePools = _storagePoolDao.search(sc, null); + List storagePools = _storagePoolDao + .search(sc, null); if (!storagePools.isEmpty()) { return storagePools.get(0); } else { @@ -3914,25 +1672,33 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C public Host updateSecondaryStorage(long secStorageId, String newUrl) { HostVO secHost = _hostDao.findById(secStorageId); if (secHost == null) { - throw new InvalidParameterValueException("Can not find out the secondary storage id: " + secStorageId); + throw new InvalidParameterValueException( + "Can not find out the secondary storage id: " + + secStorageId); } if (secHost.getType() != Host.Type.SecondaryStorage) { - throw new InvalidParameterValueException("host: " + secStorageId + " is not a secondary storage"); + throw new InvalidParameterValueException("host: " + secStorageId + + " is not a secondary storage"); } URI uri = null; try { uri = new URI(UriUtils.encodeURIComponent(newUrl)); if (uri.getScheme() == null) { - throw new InvalidParameterValueException("uri.scheme is null " + newUrl + ", add nfs:// as a prefix"); + throw new InvalidParameterValueException("uri.scheme is null " + + newUrl + ", add nfs:// as a prefix"); } else if (uri.getScheme().equalsIgnoreCase("nfs")) { - if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") || uri.getPath() == null || uri.getPath().equalsIgnoreCase("")) { - throw new InvalidParameterValueException("Your host and/or path is wrong. Make sure it's of the format nfs://hostname/path"); + if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") + || uri.getPath() == null + || uri.getPath().equalsIgnoreCase("")) { + throw new InvalidParameterValueException( + "Your host and/or path is wrong. Make sure it's of the format nfs://hostname/path"); } } } catch (URISyntaxException e) { - throw new InvalidParameterValueException(newUrl + " is not a valid uri"); + throw new InvalidParameterValueException(newUrl + + " is not a valid uri"); } String oldUrl = secHost.getStorageUrl(); @@ -3941,7 +1707,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C try { oldUri = new URI(UriUtils.encodeURIComponent(oldUrl)); if (!oldUri.getScheme().equalsIgnoreCase(uri.getScheme())) { - throw new InvalidParameterValueException("can not change old scheme:" + oldUri.getScheme() + " to " + uri.getScheme()); + throw new InvalidParameterValueException( + "can not change old scheme:" + oldUri.getScheme() + + " to " + uri.getScheme()); } } catch (URISyntaxException e) { s_logger.debug("Failed to get uri from " + oldUrl); @@ -3954,29 +1722,12 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return secHost; } - - - @Override - public String getSupportedImageFormatForCluster(Long clusterId) { - ClusterVO cluster = ApiDBUtils.findClusterById(clusterId); - - if (cluster.getHypervisorType() == HypervisorType.XenServer) { - return "vhd"; - } else if (cluster.getHypervisorType() == HypervisorType.KVM) { - return "qcow2"; - } else if (cluster.getHypervisorType() == HypervisorType.VMware) { - return "ova"; - } else if (cluster.getHypervisorType() == HypervisorType.Ovm) { - return "raw"; - } else { - return null; - } - } + @Override public HypervisorType getHypervisorTypeFromFormat(ImageFormat format) { - if(format == null) { + if (format == null) { return HypervisorType.None; } @@ -3993,22 +1744,32 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } - private boolean checkUsagedSpace(StoragePool pool){ + private boolean checkUsagedSpace(StoragePool pool) { StatsCollector sc = StatsCollector.getInstance(); if (sc != null) { long totalSize = pool.getCapacityBytes(); StorageStats stats = sc.getStoragePoolStats(pool.getId()); - if(stats == null){ + if (stats == null) { stats = sc.getStorageStats(pool.getId()); } if (stats != null) { - double usedPercentage = ((double)stats.getByteUsed() / (double)totalSize); + double usedPercentage = ((double) stats.getByteUsed() / (double) totalSize); if (s_logger.isDebugEnabled()) { - s_logger.debug("Checking pool " + pool.getId() + " for storage, totalSize: " + pool.getCapacityBytes() + ", usedBytes: " + stats.getByteUsed() + ", usedPct: " + usedPercentage + ", disable threshold: " + _storageUsedThreshold); + s_logger.debug("Checking pool " + pool.getId() + + " for storage, totalSize: " + + pool.getCapacityBytes() + ", usedBytes: " + + stats.getByteUsed() + ", usedPct: " + + usedPercentage + ", disable threshold: " + + _storageUsedThreshold); } if (usedPercentage >= _storageUsedThreshold) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Insufficient space on pool: " + pool.getId() + " since its usage percentage: " +usedPercentage + " has crossed the pool.storage.capacity.disablethreshold: " + _storageUsedThreshold); + s_logger.debug("Insufficient space on pool: " + + pool.getId() + + " since its usage percentage: " + + usedPercentage + + " has crossed the pool.storage.capacity.disablethreshold: " + + _storageUsedThreshold); } return false; } @@ -4019,54 +1780,113 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) { - if(volumes == null || volumes.isEmpty()) + public boolean storagePoolHasEnoughSpace(List volumes, + StoragePool pool) { + if (volumes == null || volumes.isEmpty()) return false; - if(!checkUsagedSpace(pool)) + if (!checkUsagedSpace(pool)) return false; // allocated space includes template of specified volume StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); - long allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); + long allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity( + poolVO, null); long totalAskingSize = 0; for (Volume volume : volumes) { - if(volume.getTemplateId()!=null){ - VMTemplateVO tmpl = _templateDao.findById(volume.getTemplateId()); - if (tmpl.getFormat() != ImageFormat.ISO){ - allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl); + if (volume.getTemplateId() != null) { + VMTemplateVO tmpl = _templateDao.findById(volume + .getTemplateId()); + if (tmpl.getFormat() != ImageFormat.ISO) { + allocatedSizeWithtemplate = _capacityMgr + .getAllocatedPoolCapacity(poolVO, tmpl); } } - if(volume.getState() != Volume.State.Ready) + if (volume.getState() != Volume.State.Ready) totalAskingSize = totalAskingSize + volume.getSize(); } long totalOverProvCapacity; if (pool.getPoolType() == StoragePoolType.NetworkFilesystem) { - totalOverProvCapacity = _storageOverprovisioningFactor.multiply(new BigDecimal(pool.getCapacityBytes())).longValue();// All this for the inaccuracy of floats for big number multiplication. - }else { + totalOverProvCapacity = _storageOverprovisioningFactor.multiply( + new BigDecimal(pool.getCapacityBytes())).longValue(); + } else { totalOverProvCapacity = pool.getCapacityBytes(); } if (s_logger.isDebugEnabled()) { - s_logger.debug("Checking pool: " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + _storageAllocatedThreshold); + s_logger.debug("Checking pool: " + pool.getId() + + " for volume allocation " + volumes.toString() + + ", maxSize : " + totalOverProvCapacity + + ", totalAllocatedSize : " + allocatedSizeWithtemplate + + ", askingSize : " + totalAskingSize + + ", allocated disable threshold: " + + _storageAllocatedThreshold); } - double usedPercentage = (allocatedSizeWithtemplate + totalAskingSize) / (double)(totalOverProvCapacity); - if (usedPercentage > _storageAllocatedThreshold){ + double usedPercentage = (allocatedSizeWithtemplate + totalAskingSize) + / (double) (totalOverProvCapacity); + if (usedPercentage > _storageAllocatedThreshold) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + " since its allocated percentage: " +usedPercentage + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + _storageAllocatedThreshold + ", skipping this pool"); + s_logger.debug("Insufficient un-allocated capacity on: " + + pool.getId() + + " for volume allocation: " + + volumes.toString() + + " since its allocated percentage: " + + usedPercentage + + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + + _storageAllocatedThreshold + ", skipping this pool"); } return false; } if (totalOverProvCapacity < (allocatedSizeWithtemplate + totalAskingSize)) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize); + s_logger.debug("Insufficient un-allocated capacity on: " + + pool.getId() + " for volume allocation: " + + volumes.toString() + + ", not enough storage, maxSize : " + + totalOverProvCapacity + ", totalAllocatedSize : " + + allocatedSizeWithtemplate + ", askingSize : " + + totalAskingSize); } return false; } return true; } + @Override + public void createCapacityEntry(long poolId) { + StoragePoolVO storage = _storagePoolDao.findById(poolId); + createCapacityEntry(storage, Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, 0); + } + + + @Override + public synchronized boolean registerHostListener(String providerUuid, + HypervisorHostListener listener) { + hostListeners.put(providerUuid, listener); + return true; + } + + @Override + public Answer sendToPool(long poolId, Command cmd) + throws StorageUnavailableException { + // TODO Auto-generated method stub + return null; + } + + @Override + public Answer[] sendToPool(long poolId, Commands cmd) + throws StorageUnavailableException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getName() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/src/com/cloud/storage/TemplateProfile.java b/server/src/com/cloud/storage/TemplateProfile.java index 1d8b6bfc1a3..0b55f1fbea2 100755 --- a/server/src/com/cloud/storage/TemplateProfile.java +++ b/server/src/com/cloud/storage/TemplateProfile.java @@ -20,7 +20,6 @@ import java.util.Map; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.VMTemplateVO; public class TemplateProfile { Long userId; @@ -46,6 +45,7 @@ public class TemplateProfile { Long templateId; VMTemplateVO template; String templateTag; + Long imageStoreId; Map details; public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, @@ -83,10 +83,12 @@ public class TemplateProfile { public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, Long zoneId, - HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details, Boolean sshKeyEnabled) { + HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details, Boolean sshKeyEnabled, + Long imageStoreId) { this(templateId, userId, name, displayText, bits, passwordEnabled, requiresHvm, url, isPublic, featured, isExtractable, format, guestOsId, zoneId, hypervisorType, accountName, domainId, accountId, chksum, bootable, details, sshKeyEnabled); this.templateTag = templateTag; + this.imageStoreId = imageStoreId; } public Long getTemplateId() { @@ -252,4 +254,8 @@ public class TemplateProfile { public Boolean getSshKeyEnabled() { return this.sshKeyEnbaled; } + + public Long getImageStoreId() { + return this.imageStoreId; + } } diff --git a/server/src/com/cloud/storage/VolumeManager.java b/server/src/com/cloud/storage/VolumeManager.java new file mode 100644 index 00000000000..af3cbbfbae5 --- /dev/null +++ b/server/src/com/cloud/storage/VolumeManager.java @@ -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 com.cloud.storage; + +import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; + +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientStorageCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Volume.Type; +import com.cloud.user.Account; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; + +public interface VolumeManager extends VolumeApiService { + + VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, + Long destPoolClusterId, HypervisorType dataDiskHyperType) + throws ConcurrentOperationException; + + VolumeVO uploadVolume(UploadVolumeCmd cmd) + throws ResourceAllocationException; + + VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId); + + boolean volumeOnSharedStoragePool(VolumeVO volume); + + boolean volumeInactive(Volume volume); + + String getVmNameOnVolume(Volume volume); + + VolumeVO allocVolume(CreateVolumeCmd cmd) + throws ResourceAllocationException; + + VolumeVO createVolume(CreateVolumeCmd cmd); + + VolumeVO resizeVolume(ResizeVolumeCmd cmd); + + boolean deleteVolume(long volumeId, Account caller) + throws ConcurrentOperationException; + + void destroyVolume(VolumeVO volume); + + DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, VMInstanceVO vm, Account owner); + Volume attachVolumeToVM(AttachVolumeCmd command); + + Volume detachVolumeFromVM(DetachVolumeCmd cmmd); + + void release(VirtualMachineProfile profile); + + void cleanupVolumes(long vmId) throws ConcurrentOperationException; + + Volume migrateVolume(MigrateVolumeCmd cmd); + + boolean storageMigration( + VirtualMachineProfile vm, + StoragePool destPool); + + void prepareForMigration( + VirtualMachineProfile vm, + DeployDestination dest); + + void prepare(VirtualMachineProfile vm, + DeployDestination dest) throws StorageUnavailableException, + InsufficientStorageCapacityException, ConcurrentOperationException; + + boolean canVmRestartOnAnotherServer(long vmId); + + DiskProfile allocateTemplatedVolume(Type type, String name, + DiskOfferingVO offering, VMTemplateVO template, VMInstanceVO vm, + Account owner); +} diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java new file mode 100644 index 00000000000..a69607f1f3f --- /dev/null +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -0,0 +1,2452 @@ +/* + * 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.storage; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; +import org.apache.cloudstack.framework.async.AsyncCallFuture; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.AttachVolumeAnswer; +import com.cloud.agent.api.AttachVolumeCommand; +import com.cloud.agent.api.to.VolumeTO; +import com.cloud.alert.AlertManager; +import com.cloud.api.ApiDBUtils; +import com.cloud.async.AsyncJobExecutor; +import com.cloud.async.AsyncJobManager; +import com.cloud.async.AsyncJobVO; +import com.cloud.async.BaseAsyncJobExecutor; +import com.cloud.capacity.CapacityManager; +import com.cloud.capacity.dao.CapacityDao; +import com.cloud.configuration.Config; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.Resource.ResourceType; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.consoleproxy.ConsoleProxyManager; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.domain.Domain; +import com.cloud.domain.dao.DomainDao; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventVO; +import com.cloud.event.dao.EventDao; +import com.cloud.event.dao.UsageEventDao; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientStorageCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.StorageUnavailableException; +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.hypervisor.dao.HypervisorCapabilitiesDao; +import com.cloud.network.NetworkModel; +import com.cloud.org.Grouping; +import com.cloud.resource.ResourceManager; +import com.cloud.server.ManagementServer; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.Volume.Event; +import com.cloud.storage.Volume.Type; +import com.cloud.storage.allocator.StoragePoolAllocator; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotPolicyDao; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.StoragePoolWorkDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateS3Dao; +import com.cloud.storage.dao.VMTemplateSwiftDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; +import com.cloud.storage.download.DownloadMonitor; +import com.cloud.storage.s3.S3Manager; +import com.cloud.storage.secondary.SecondaryStorageVmManager; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.storage.snapshot.SnapshotScheduler; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.template.TemplateManager; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.UserContext; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.uservm.UserVm; +import com.cloud.utils.EnumUtils; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.JoinBuilder; +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.DiskProfile; +import com.cloud.vm.UserVmManager; +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.ConsoleProxyDao; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.SecondaryStorageVmDao; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + +@Component +public class VolumeManagerImpl extends ManagerBase implements VolumeManager { + private static final Logger s_logger = Logger + .getLogger(VolumeManagerImpl.class); + @Inject + protected UserVmManager _userVmMgr; + @Inject + protected AgentManager _agentMgr; + @Inject + protected TemplateManager _tmpltMgr; + @Inject + protected AsyncJobManager _asyncMgr; + @Inject + protected SnapshotManager _snapshotMgr; + @Inject + protected SnapshotScheduler _snapshotScheduler; + @Inject + protected AccountManager _accountMgr; + @Inject + protected ConfigurationManager _configMgr; + @Inject + protected ConsoleProxyManager _consoleProxyMgr; + @Inject + protected SecondaryStorageVmManager _secStorageMgr; + @Inject + protected NetworkModel _networkMgr; + @Inject + protected ServiceOfferingDao _serviceOfferingDao; + @Inject + protected VolumeDao _volsDao; + @Inject + protected HostDao _hostDao; + @Inject + protected ConsoleProxyDao _consoleProxyDao; + @Inject + protected SnapshotDao _snapshotDao; + @Inject + protected SnapshotManager _snapMgr; + @Inject + protected SnapshotPolicyDao _snapshotPolicyDao; + @Inject + protected StoragePoolHostDao _storagePoolHostDao; + @Inject + protected AlertManager _alertMgr; + @Inject + protected VMTemplateHostDao _vmTemplateHostDao = null; + @Inject + protected VMTemplatePoolDao _vmTemplatePoolDao = null; + @Inject + protected VMTemplateSwiftDao _vmTemplateSwiftDao = null; + @Inject + protected VMTemplateS3Dao _vmTemplateS3Dao; + @Inject + protected S3Manager _s3Mgr; + @Inject + protected VMTemplateDao _vmTemplateDao = null; + @Inject + protected StoragePoolHostDao _poolHostDao = null; + @Inject + protected UserVmDao _userVmDao; + @Inject + VolumeHostDao _volumeHostDao; + @Inject + protected VMInstanceDao _vmInstanceDao; + @Inject + protected PrimaryDataStoreDao _storagePoolDao = null; + @Inject + protected CapacityDao _capacityDao; + @Inject + protected CapacityManager _capacityMgr; + @Inject + protected DiskOfferingDao _diskOfferingDao; + @Inject + protected AccountDao _accountDao; + @Inject + protected EventDao _eventDao = null; + @Inject + protected DataCenterDao _dcDao = null; + @Inject + protected HostPodDao _podDao = null; + @Inject + protected VMTemplateDao _templateDao; + @Inject + protected VMTemplateHostDao _templateHostDao; + @Inject + protected ServiceOfferingDao _offeringDao; + @Inject + protected DomainDao _domainDao; + @Inject + protected UserDao _userDao; + @Inject + protected ClusterDao _clusterDao; + @Inject + protected UsageEventDao _usageEventDao; + @Inject + protected VirtualMachineManager _vmMgr; + @Inject + protected DomainRouterDao _domrDao; + @Inject + protected SecondaryStorageVmDao _secStrgDao; + @Inject + protected StoragePoolWorkDao _storagePoolWorkDao; + @Inject + protected HypervisorGuruManager _hvGuruMgr; + @Inject + protected VolumeDao _volumeDao; + @Inject + protected OCFS2Manager _ocfs2Mgr; + @Inject + protected ResourceLimitService _resourceLimitMgr; + @Inject + protected SecondaryStorageVmManager _ssvmMgr; + @Inject + protected ResourceManager _resourceMgr; + @Inject + protected DownloadMonitor _downloadMonitor; + @Inject + protected ResourceTagDao _resourceTagDao; + @Inject + protected List _storagePoolAllocators; + @Inject + ConfigurationDao _configDao; + @Inject + ManagementServer _msServer; + @Inject + DataStoreManager dataStoreMgr; + @Inject + DataStoreProviderManager dataStoreProviderMgr; + @Inject + VolumeService volService; + @Inject + VolumeDataFactory volFactory; + @Inject + ImageDataFactory tmplFactory; + @Inject + SnapshotDataFactory snapshotFactory; + private int _copyvolumewait; + @Inject + protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; + private final StateMachine2 _volStateMachine; + @Inject + StorageManager storageMgr; + private int _customDiskOfferingMinSize = 1; + private int _customDiskOfferingMaxSize = 1024; + private long _maxVolumeSizeInGb; + private boolean _recreateSystemVmEnabled; + protected SearchBuilder HostTemplateStatesSearch; + + public VolumeManagerImpl() { + _volStateMachine = Volume.State.getStateMachine(); + } + + @Override + public VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, + Long destPoolPodId, Long destPoolClusterId, + HypervisorType dataDiskHyperType) + throws ConcurrentOperationException { + + // Find a destination storage pool with the specified criteria + DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume + .getDiskOfferingId()); + DiskProfile dskCh = new DiskProfile(volume.getId(), + volume.getVolumeType(), volume.getName(), diskOffering.getId(), + diskOffering.getDiskSize(), diskOffering.getTagsArray(), + diskOffering.getUseLocalStorage(), + diskOffering.isRecreatable(), null); + dskCh.setHyperType(dataDiskHyperType); + DataCenterVO destPoolDataCenter = _dcDao.findById(destPoolDcId); + HostPodVO destPoolPod = _podDao.findById(destPoolPodId); + + StoragePool destPool = storageMgr.findStoragePool(dskCh, + destPoolDataCenter, destPoolPod, destPoolClusterId, null, null, + new HashSet()); + + if (destPool == null) { + throw new CloudRuntimeException( + "Failed to find a storage pool with enough capacity to move the volume to."); + } + + Volume newVol = migrateVolume(volume, destPool); + return this.volFactory.getVolume(newVol.getId()); + } + + /* + * Upload the volume to secondary storage. + */ + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPLOAD, eventDescription = "uploading volume", async = true) + public VolumeVO uploadVolume(UploadVolumeCmd cmd) + throws ResourceAllocationException { + Account caller = UserContext.current().getCaller(); + long ownerId = cmd.getEntityOwnerId(); + Long zoneId = cmd.getZoneId(); + String volumeName = cmd.getVolumeName(); + String url = cmd.getUrl(); + String format = cmd.getFormat(); + String imageStoreUuid = cmd.getImageStoreUuid(); + DataStore store = this._tmpltMgr.getImageStore(imageStoreUuid, zoneId); + + validateVolume(caller, ownerId, zoneId, volumeName, url, format); + + VolumeVO volume = persistVolume(caller, ownerId, zoneId, volumeName, + url, cmd.getFormat()); + + VolumeInfo vol = this.volFactory.getVolume(volume.getId()); + + RegisterVolumePayload payload = new RegisterVolumePayload(cmd.getUrl(), cmd.getChecksum(), + cmd.getFormat()); + vol.addPayload(payload); + + this.volService.registerVolume(vol, store); + return volume; + } + + private boolean validateVolume(Account caller, long ownerId, Long zoneId, + String volumeName, String url, String format) + throws ResourceAllocationException { + + // permission check + _accountMgr.checkAccess(caller, null, true, + _accountMgr.getActiveAccountById(ownerId)); + + // Check that the resource limit for volumes won't be exceeded + _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), + ResourceType.volume); + + // Verify that zone exists + DataCenterVO zone = _dcDao.findById(zoneId); + if (zone == null) { + throw new InvalidParameterValueException( + "Unable to find zone by id " + zoneId); + } + + // Check if zone is disabled + if (Grouping.AllocationState.Disabled == zone.getAllocationState() + && !_accountMgr.isRootAdmin(caller.getType())) { + throw new PermissionDeniedException( + "Cannot perform this operation, Zone is currently disabled: " + + zoneId); + } + + if (url.toLowerCase().contains("file://")) { + throw new InvalidParameterValueException( + "File:// type urls are currently unsupported"); + } + + ImageFormat imgfmt = ImageFormat.valueOf(format.toUpperCase()); + if (imgfmt == null) { + throw new IllegalArgumentException("Image format is incorrect " + + format + ". Supported formats are " + + EnumUtils.listValues(ImageFormat.values())); + } + + String userSpecifiedName = volumeName; + if (userSpecifiedName == null) { + userSpecifiedName = getRandomVolumeName(); + } + if ((!url.toLowerCase().endsWith("vhd")) + && (!url.toLowerCase().endsWith("vhd.zip")) + && (!url.toLowerCase().endsWith("vhd.bz2")) + && (!url.toLowerCase().endsWith("vhd.gz")) + && (!url.toLowerCase().endsWith("qcow2")) + && (!url.toLowerCase().endsWith("qcow2.zip")) + && (!url.toLowerCase().endsWith("qcow2.bz2")) + && (!url.toLowerCase().endsWith("qcow2.gz")) + && (!url.toLowerCase().endsWith("ova")) + && (!url.toLowerCase().endsWith("ova.zip")) + && (!url.toLowerCase().endsWith("ova.bz2")) + && (!url.toLowerCase().endsWith("ova.gz")) + && (!url.toLowerCase().endsWith("img")) + && (!url.toLowerCase().endsWith("raw"))) { + throw new InvalidParameterValueException("Please specify a valid " + + format.toLowerCase()); + } + + if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith( + ".vhd") + && !url.toLowerCase().endsWith("vhd.zip") + && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase() + .endsWith("vhd.gz"))) + || (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase() + .endsWith(".qcow2") + && !url.toLowerCase().endsWith("qcow2.zip") + && !url.toLowerCase().endsWith("qcow2.bz2") && !url + .toLowerCase().endsWith("qcow2.gz"))) + || (format.equalsIgnoreCase("ova") && (!url.toLowerCase() + .endsWith(".ova") + && !url.toLowerCase().endsWith("ova.zip") + && !url.toLowerCase().endsWith("ova.bz2") && !url + .toLowerCase().endsWith("ova.gz"))) + || (format.equalsIgnoreCase("raw") && (!url.toLowerCase() + .endsWith(".img") && !url.toLowerCase().endsWith("raw")))) { + throw new InvalidParameterValueException( + "Please specify a valid URL. URL:" + url + + " is an invalid for the format " + + format.toLowerCase()); + } + validateUrl(url); + + return false; + } + + @Override + public VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId) { + VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), + oldVol.getName(), oldVol.getDataCenterId(), + oldVol.getDomainId(), oldVol.getAccountId(), + oldVol.getDiskOfferingId(), oldVol.getSize()); + if (templateId != null) { + newVol.setTemplateId(templateId); + } else { + newVol.setTemplateId(oldVol.getTemplateId()); + } + newVol.setDeviceId(oldVol.getDeviceId()); + newVol.setInstanceId(oldVol.getInstanceId()); + newVol.setRecreatable(oldVol.isRecreatable()); + return _volsDao.persist(newVol); + } + + @DB + protected VolumeInfo createVolumeFromSnapshot(VolumeVO volume, + SnapshotVO snapshot) { + Account account = _accountDao.findById(volume.getAccountId()); + + final HashSet poolsToAvoid = new HashSet(); + StoragePool pool = null; + + Set podsToAvoid = new HashSet(); + Pair pod = null; + + + DiskOfferingVO diskOffering = _diskOfferingDao + .findByIdIncludingRemoved(volume.getDiskOfferingId()); + DataCenterVO dc = _dcDao.findById(volume.getDataCenterId()); + DiskProfile dskCh = new DiskProfile(volume, diskOffering, + snapshot.getHypervisorType()); + + // Determine what pod to store the volume in + while ((pod = _resourceMgr.findPod(null, null, dc, account.getId(), + podsToAvoid)) != null) { + podsToAvoid.add(pod.first().getId()); + // Determine what storage pool to store the volume in + while ((pool = storageMgr.findStoragePool(dskCh, dc, pod.first(), null, null, + null, poolsToAvoid)) != null) { + break; + + } + } + + VolumeInfo vol = this.volFactory.getVolume(volume.getId()); + DataStore store = this.dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); + SnapshotInfo snapInfo = this.snapshotFactory.getSnapshot(snapshot.getId()); + AsyncCallFuture future = this.volService.createVolumeFromSnapshot(vol, store, snapInfo); + try { + VolumeApiResult result = future.get(); + if (result.isFailed()) { + s_logger.debug("Failed to create volume from snapshot:" + result.getResult()); + throw new CloudRuntimeException("Failed to create volume from snapshot:" + result.getResult()); + } + return result.getVolume(); + } catch (InterruptedException e) { + s_logger.debug("Failed to create volume from snapshot", e); + throw new CloudRuntimeException("Failed to create volume from snapshot", e); + } catch (ExecutionException e) { + s_logger.debug("Failed to create volume from snapshot", e); + throw new CloudRuntimeException("Failed to create volume from snapshot", e); + } + + } + + protected DiskProfile createDiskCharacteristics(VolumeInfo volume, + VMTemplateVO template, DataCenterVO dc, DiskOfferingVO diskOffering) { + if (volume.getVolumeType() == Type.ROOT + && Storage.ImageFormat.ISO != template.getFormat()) { + SearchCriteria sc = HostTemplateStatesSearch + .create(); + sc.setParameters("id", template.getId()); + sc.setParameters( + "state", + com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + sc.setJoinParameters("host", "dcId", dc.getId()); + + List sss = _vmTemplateHostDao.search(sc, null); + if (sss.size() == 0) { + throw new CloudRuntimeException("Template " + + template.getName() + + " has not been completely downloaded to zone " + + dc.getId()); + } + VMTemplateHostVO ss = sss.get(0); + + return new DiskProfile(volume.getId(), volume.getVolumeType(), + volume.getName(), diskOffering.getId(), ss.getSize(), + diskOffering.getTagsArray(), + diskOffering.getUseLocalStorage(), + diskOffering.isRecreatable(), + Storage.ImageFormat.ISO != template.getFormat() ? template + .getId() : null); + } else { + return new DiskProfile(volume.getId(), volume.getVolumeType(), + volume.getName(), diskOffering.getId(), + diskOffering.getDiskSize(), diskOffering.getTagsArray(), + diskOffering.getUseLocalStorage(), + diskOffering.isRecreatable(), null); + } + } + + protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId) { + VolumeInfo createdVolume = null; + SnapshotVO snapshot = _snapshotDao.findById(snapshotId); + createdVolume = createVolumeFromSnapshot(volume, + snapshot); + + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, + createdVolume.getAccountId(), + createdVolume.getDataCenterId(), createdVolume.getId(), + createdVolume.getName(), createdVolume.getDiskOfferingId(), + null, createdVolume.getSize()); + _usageEventDao.persist(usageEvent); + + return this._volsDao.findById(createdVolume.getId()); + } + + @DB + public VolumeInfo copyVolumeFromSecToPrimary(VolumeInfo volume, + VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, + HostPodVO pod, Long clusterId, ServiceOfferingVO offering, + DiskOfferingVO diskOffering, List avoids, + long size, HypervisorType hyperType) throws NoTransitionException { + + final HashSet avoidPools = new HashSet( + avoids); + DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, + diskOffering); + dskCh.setHyperType(vm.getHypervisorType()); + // Find a suitable storage to create volume on + StoragePool destPool = storageMgr.findStoragePool(dskCh, dc, pod, + clusterId, null, vm, avoidPools); + DataStore destStore = this.dataStoreMgr.getDataStore(destPool.getId(), DataStoreRole.Primary); + AsyncCallFuture future = this.volService.copyVolume(volume, destStore); + + try { + VolumeApiResult result = future.get(); + if (result.isFailed()) { + s_logger.debug("copy volume failed: " + result.getResult()); + throw new CloudRuntimeException("copy volume failed: " + result.getResult()); + } + return result.getVolume(); + } catch (InterruptedException e) { + s_logger.debug("Failed to copy volume: " + volume.getId(), e); + throw new CloudRuntimeException("Failed to copy volume", e); + } catch (ExecutionException e) { + s_logger.debug("Failed to copy volume: " + volume.getId(), e); + throw new CloudRuntimeException("Failed to copy volume", e); + } + } + + @DB + public VolumeInfo createVolume(VolumeInfo volume, VMInstanceVO vm, + VMTemplateVO template, DataCenterVO dc, HostPodVO pod, + Long clusterId, ServiceOfferingVO offering, + DiskOfferingVO diskOffering, List avoids, + long size, HypervisorType hyperType) { + StoragePool pool = null; + + if (diskOffering != null && diskOffering.isCustomized()) { + diskOffering.setDiskSize(size); + } + + DiskProfile dskCh = null; + if (volume.getVolumeType() == Type.ROOT + && Storage.ImageFormat.ISO != template.getFormat()) { + dskCh = createDiskCharacteristics(volume, template, dc, offering); + } else { + dskCh = createDiskCharacteristics(volume, template, dc, + diskOffering); + } + + dskCh.setHyperType(hyperType); + + final HashSet avoidPools = new HashSet( + avoids); + + pool = storageMgr.findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(), + vm, avoidPools); + if (pool == null) { + s_logger.warn("Unable to find storage poll when create volume " + + volume.getName()); + throw new CloudRuntimeException("Unable to find storage poll when create volume" + volume.getName()); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Trying to create " + volume + " on " + pool); + } + DataStore store = this.dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); + AsyncCallFuture future = null; + boolean isNotCreatedFromTemplate = volume.getTemplateId() == null ? true : false; + if (isNotCreatedFromTemplate) { + future = this.volService.createVolumeAsync(volume, store); + } else { + TemplateInfo templ = this.tmplFactory.getTemplate(template.getId()); + future = this.volService.createVolumeFromTemplateAsync(volume, store.getId(), templ); + } + try { + VolumeApiResult result = future.get(); + if (result.isFailed()) { + s_logger.debug("create volume failed: " + result.getResult()); + throw new CloudRuntimeException("create volume failed:" + result.getResult()); + } + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), + volume.getDiskOfferingId(), null, volume.getSize()); + _usageEventDao.persist(usageEvent); + return result.getVolume(); + } catch (InterruptedException e) { + s_logger.error("create volume failed", e); + throw new CloudRuntimeException("create volume failed", e); + } catch (ExecutionException e) { + s_logger.error("create volume failed", e); + throw new CloudRuntimeException("create volume failed", e); + } + + } + + public String getRandomVolumeName() { + return UUID.randomUUID().toString(); + } + + private VolumeVO persistVolume(Account caller, long ownerId, Long zoneId, + String volumeName, String url, String format) { + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, + new Long(-1), null, null, 0, Volume.Type.DATADISK); + volume.setPoolId(null); + volume.setDataCenterId(zoneId); + volume.setPodId(null); + volume.setAccountId(ownerId); + volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller + .getDomainId())); + long diskOfferingId = _diskOfferingDao.findByUniqueName( + "Cloud.com-Custom").getId(); + volume.setDiskOfferingId(diskOfferingId); + // volume.setSize(size); + volume.setInstanceId(null); + volume.setUpdated(new Date()); + volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller + .getDomainId()); + + volume = _volsDao.persist(volume); + try { + stateTransitTo(volume, Event.UploadRequested); + } catch (NoTransitionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + UserContext.current().setEventDetails("Volume Id: " + volume.getId()); + + // Increment resource count during allocation; if actual creation fails, + // decrement it + _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), + ResourceType.volume); + + txn.commit(); + return volume; + } + + @Override + public boolean volumeOnSharedStoragePool(VolumeVO volume) { + Long poolId = volume.getPoolId(); + if (poolId == null) { + return false; + } else { + StoragePoolVO pool = _storagePoolDao.findById(poolId); + + if (pool == null) { + return false; + } else { + return (pool.getScope() == ScopeType.HOST) ? false : true; + } + } + } + + @Override + public boolean volumeInactive(Volume volume) { + Long vmId = volume.getInstanceId(); + if (vmId != null) { + UserVm vm = _userVmDao.findById(vmId); + if (vm == null) { + return true; + } + State state = vm.getState(); + if (state.equals(State.Stopped) || state.equals(State.Destroyed)) { + return true; + } + } + return false; + } + + @Override + public String getVmNameOnVolume(Volume volume) { + Long vmId = volume.getInstanceId(); + if (vmId != null) { + VMInstanceVO vm = _vmInstanceDao.findById(vmId); + + if (vm == null) { + return null; + } + return vm.getInstanceName(); + } + return null; + } + + /* + * Just allocate a volume in the database, don't send the createvolume cmd + * to hypervisor. The volume will be finally created only when it's attached + * to a VM. + */ + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true) + public VolumeVO allocVolume(CreateVolumeCmd cmd) + throws ResourceAllocationException { + // FIXME: some of the scheduled event stuff might be missing here... + Account caller = UserContext.current().getCaller(); + + long ownerId = cmd.getEntityOwnerId(); + + // permission check + _accountMgr.checkAccess(caller, null, true, + _accountMgr.getActiveAccountById(ownerId)); + + // Check that the resource limit for volumes won't be exceeded + _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), + ResourceType.volume); + + Long zoneId = cmd.getZoneId(); + Long diskOfferingId = null; + DiskOfferingVO diskOffering = null; + Long size = null; + + // validate input parameters before creating the volume + if ((cmd.getSnapshotId() == null && cmd.getDiskOfferingId() == null) + || (cmd.getSnapshotId() != null && cmd.getDiskOfferingId() != null)) { + throw new InvalidParameterValueException( + "Either disk Offering Id or snapshot Id must be passed whilst creating volume"); + } + + if (cmd.getSnapshotId() == null) {// create a new volume + + diskOfferingId = cmd.getDiskOfferingId(); + size = cmd.getSize(); + Long sizeInGB = size; + if (size != null) { + if (size > 0) { + size = size * 1024 * 1024 * 1024; // user specify size in GB + } else { + throw new InvalidParameterValueException( + "Disk size must be larger than 0"); + } + } + + // Check that the the disk offering is specified + diskOffering = _diskOfferingDao.findById(diskOfferingId); + if ((diskOffering == null) || diskOffering.getRemoved() != null + || !DiskOfferingVO.Type.Disk.equals(diskOffering.getType())) { + throw new InvalidParameterValueException( + "Please specify a valid disk offering."); + } + + if (diskOffering.isCustomized()) { + if (size == null) { + throw new InvalidParameterValueException( + "This disk offering requires a custom size specified"); + } + if ((sizeInGB < _customDiskOfferingMinSize) + || (sizeInGB > _customDiskOfferingMaxSize)) { + throw new InvalidParameterValueException("Volume size: " + + sizeInGB + "GB is out of allowed range. Max: " + + _customDiskOfferingMaxSize + " Min:" + + _customDiskOfferingMinSize); + } + } + + if (!diskOffering.isCustomized() && size != null) { + throw new InvalidParameterValueException( + "This disk offering does not allow custom size"); + } + + if (diskOffering.getDomainId() == null) { + // do nothing as offering is public + } else { + _configMgr.checkDiskOfferingAccess(caller, diskOffering); + } + + if (diskOffering.getDiskSize() > 0) { + size = diskOffering.getDiskSize(); + } + + if (!validateVolumeSizeRange(size)) {// convert size from mb to gb + // for validation + throw new InvalidParameterValueException( + "Invalid size for custom volume creation: " + size + + " ,max volume size is:" + _maxVolumeSizeInGb); + } + } else { // create volume from snapshot + Long snapshotId = cmd.getSnapshotId(); + SnapshotVO snapshotCheck = _snapshotDao.findById(snapshotId); + if (snapshotCheck == null) { + throw new InvalidParameterValueException( + "unable to find a snapshot with id " + snapshotId); + } + + if (snapshotCheck.getState() != Snapshot.State.BackedUp) { + throw new InvalidParameterValueException("Snapshot id=" + + snapshotId + " is not in " + Snapshot.State.BackedUp + + " state yet and can't be used for volume creation"); + } + + diskOfferingId = snapshotCheck.getDiskOfferingId(); + diskOffering = _diskOfferingDao.findById(diskOfferingId); + zoneId = snapshotCheck.getDataCenterId(); + size = snapshotCheck.getSize(); // ; disk offering is used for tags + // purposes + + // check snapshot permissions + _accountMgr.checkAccess(caller, null, true, snapshotCheck); + } + + // Verify that zone exists + DataCenterVO zone = _dcDao.findById(zoneId); + if (zone == null) { + throw new InvalidParameterValueException( + "Unable to find zone by id " + zoneId); + } + + // Check if zone is disabled + if (Grouping.AllocationState.Disabled == zone.getAllocationState() + && !_accountMgr.isRootAdmin(caller.getType())) { + throw new PermissionDeniedException( + "Cannot perform this operation, Zone is currently disabled: " + + zoneId); + } + + // If local storage is disabled then creation of volume with local disk + // offering not allowed + if (!zone.isLocalStorageEnabled() && diskOffering.getUseLocalStorage()) { + throw new InvalidParameterValueException( + "Zone is not configured to use local storage but volume's disk offering " + + diskOffering.getName() + " uses it"); + } + + String userSpecifiedName = cmd.getVolumeName(); + if (userSpecifiedName == null) { + userSpecifiedName = getRandomVolumeName(); + } + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, + new Long(-1), null, null, 0, Volume.Type.DATADISK); + volume.setPoolId(null); + volume.setDataCenterId(zoneId); + volume.setPodId(null); + volume.setAccountId(ownerId); + volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller + .getDomainId())); + volume.setDiskOfferingId(diskOfferingId); + volume.setSize(size); + volume.setInstanceId(null); + volume.setUpdated(new Date()); + volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller + .getDomainId()); + + volume = _volsDao.persist(volume); + if (cmd.getSnapshotId() == null) { + // for volume created from snapshot, create usage event after volume + // creation + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), + diskOfferingId, null, size); + _usageEventDao.persist(usageEvent); + } + + UserContext.current().setEventDetails("Volume Id: " + volume.getId()); + + // Increment resource count during allocation; if actual creation fails, + // decrement it + _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), + ResourceType.volume); + + txn.commit(); + + return volume; + } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", async = true) + public VolumeVO createVolume(CreateVolumeCmd cmd) { + VolumeVO volume = _volsDao.findById(cmd.getEntityId()); + boolean created = true; + + try { + if (cmd.getSnapshotId() != null) { + volume = createVolumeFromSnapshot(volume, cmd.getSnapshotId()); + if (volume.getState() != Volume.State.Ready) { + created = false; + } + } + return volume; + } catch(Exception e) { + created = false; + s_logger.debug("Failed to create volume: " + volume.getId(), e); + return null; + } finally { + if (!created) { + s_logger.trace("Decrementing volume resource count for account id=" + + volume.getAccountId() + + " as volume failed to create on the backend"); + _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), + ResourceType.volume); + } + } + } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true) + public VolumeVO resizeVolume(ResizeVolumeCmd cmd) { + Long newSize = null; + boolean shrinkOk = cmd.getShrinkOk(); + + VolumeVO volume = _volsDao.findById(cmd.getEntityId()); + if (volume == null) { + throw new InvalidParameterValueException("No such volume"); + } + + DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume + .getDiskOfferingId()); + DiskOfferingVO newDiskOffering = null; + + newDiskOffering = _diskOfferingDao.findById(cmd.getNewDiskOfferingId()); + + /* + * Volumes with no hypervisor have never been assigned, and can be + * resized by recreating. perhaps in the future we can just update the + * db entry for the volume + */ + if (_volsDao.getHypervisorType(volume.getId()) == HypervisorType.None) { + throw new InvalidParameterValueException( + "Can't resize a volume that has never been attached, not sure which hypervisor type. Recreate volume to resize."); + } + + /* Only works for KVM/Xen for now */ + if (_volsDao.getHypervisorType(volume.getId()) != HypervisorType.KVM + && _volsDao.getHypervisorType(volume.getId()) != HypervisorType.XenServer) { + throw new InvalidParameterValueException( + "Cloudstack currently only supports volumes marked as KVM or XenServer hypervisor for resize"); + } + + + if (volume.getState() != Volume.State.Ready) { + throw new InvalidParameterValueException( + "Volume should be in ready state before attempting a resize"); + } + + if (!volume.getVolumeType().equals(Volume.Type.DATADISK)) { + throw new InvalidParameterValueException( + "Can only resize DATA volumes"); + } + + /* + * figure out whether or not a new disk offering or size parameter is + * required, get the correct size value + */ + if (newDiskOffering == null) { + if (diskOffering.isCustomized()) { + newSize = cmd.getSize(); + + if (newSize == null) { + throw new InvalidParameterValueException( + "new offering is of custom size, need to specify a size"); + } + + newSize = (newSize << 30); + } else { + throw new InvalidParameterValueException("current offering" + + volume.getDiskOfferingId() + + " cannot be resized, need to specify a disk offering"); + } + } else { + + if (newDiskOffering.getRemoved() != null + || !DiskOfferingVO.Type.Disk.equals(newDiskOffering + .getType())) { + throw new InvalidParameterValueException( + "Disk offering ID is missing or invalid"); + } + + if (diskOffering.getTags() != null) { + if (!newDiskOffering.getTags().equals(diskOffering.getTags())) { + throw new InvalidParameterValueException( + "Tags on new and old disk offerings must match"); + } + } else if (newDiskOffering.getTags() != null) { + throw new InvalidParameterValueException( + "There are no tags on current disk offering, new disk offering needs to have no tags"); + } + + if (newDiskOffering.getDomainId() == null) { + // do nothing as offering is public + } else { + _configMgr.checkDiskOfferingAccess(UserContext.current() + .getCaller(), newDiskOffering); + } + + if (newDiskOffering.isCustomized()) { + newSize = cmd.getSize(); + + if (newSize == null) { + throw new InvalidParameterValueException( + "new offering is of custom size, need to specify a size"); + } + + newSize = (newSize << 30); + } else { + newSize = newDiskOffering.getDiskSize(); + } + } + + if (newSize == null) { + throw new InvalidParameterValueException( + "could not detect a size parameter or fetch one from the diskofferingid parameter"); + } + + if (!validateVolumeSizeRange(newSize)) { + throw new InvalidParameterValueException( + "Requested size out of range"); + } + + /* does the caller have the authority to act on this volume? */ + _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, + volume); + + UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); + + PrimaryDataStoreInfo pool = (PrimaryDataStoreInfo)this.dataStoreMgr.getDataStore(volume.getPoolId(), DataStoreRole.Primary); + long currentSize = volume.getSize(); + + /* + * lets make certain they (think they) know what they're doing if they + * want to shrink, by forcing them to provide the shrinkok parameter. + * This will be checked again at the hypervisor level where we can see + * the actual disk size + */ + if (currentSize > newSize && !shrinkOk) { + throw new InvalidParameterValueException( + "Going from existing size of " + + currentSize + + " to size of " + + newSize + + " would shrink the volume, need to sign off by supplying the shrinkok parameter with value of true"); + } + + /* + * get a list of hosts to send the commands to, try the system the + * associated vm is running on first, then the last known place it ran. + * If not attached to a userVm, we pass 'none' and resizevolume.sh is ok + * with that since it only needs the vm name to live resize + */ + long[] hosts = null; + String instanceName = "none"; + if (userVm != null) { + instanceName = userVm.getInstanceName(); + if (userVm.getHostId() != null) { + hosts = new long[] { userVm.getHostId() }; + } else if (userVm.getLastHostId() != null) { + hosts = new long[] { userVm.getLastHostId() }; + } + + /* Xen only works offline, SR does not support VDI.resizeOnline */ + if (_volsDao.getHypervisorType(volume.getId()) == HypervisorType.XenServer + && !userVm.getState().equals(State.Stopped)) { + throw new InvalidParameterValueException( + "VM must be stopped or disk detached in order to resize with the Xen HV"); + } + } + + ResizeVolumePayload payload = new ResizeVolumePayload(newSize, shrinkOk, instanceName, hosts); + + try { + VolumeInfo vol = this.volFactory.getVolume(volume.getId()); + vol.addPayload(payload); + + AsyncCallFuture future = this.volService.resize(vol); + future.get(); + volume = _volsDao.findById(volume.getId()); + + if (newDiskOffering != null) { + volume.setDiskOfferingId(cmd.getNewDiskOfferingId()); + } + _volsDao.update(volume.getId(), volume); + + return volume; + } catch (InterruptedException e) { + s_logger.debug("failed get resize volume result", e); + } catch (ExecutionException e) { + s_logger.debug("failed get resize volume result", e); + } catch (Exception e) { + s_logger.debug("failed get resize volume result", e); + } + + return null; + } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume") + public boolean deleteVolume(long volumeId, Account caller) + throws ConcurrentOperationException { + + VolumeVO volume = _volsDao.findById(volumeId); + if (volume == null) { + throw new InvalidParameterValueException( + "Unable to aquire volume with ID: " + volumeId); + } + + if (!_snapshotMgr.canOperateOnVolume(volume)) { + throw new InvalidParameterValueException( + "There are snapshot creating on it, Unable to delete the volume"); + } + + _accountMgr.checkAccess(caller, null, true, volume); + + if (volume.getInstanceId() != null) { + throw new InvalidParameterValueException( + "Please specify a volume that is not attached to any VM."); + } + + if (volume.getState() == Volume.State.UploadOp) { + VolumeHostVO volumeHost = _volumeHostDao.findByVolumeId(volume + .getId()); + if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) { + throw new InvalidParameterValueException( + "Please specify a volume that is not uploading"); + } + } + + try { + if (volume.getState() != Volume.State.Destroy && volume.getState() != Volume.State.Expunging && volume.getState() != Volume.State.Expunging) { + Long instanceId = volume.getInstanceId(); + if (!this.volService.destroyVolume(volume.getId())) { + return false; + } + + VMInstanceVO vmInstance = this._vmInstanceDao.findById(instanceId); + if (instanceId == null + || (vmInstance.getType().equals(VirtualMachine.Type.User))) { + // Decrement the resource count for volumes belonging user VM's only + _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), + ResourceType.volume); + // Log usage event for volumes belonging user VM's only + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName()); + _usageEventDao.persist(usageEvent); + } + } + AsyncCallFuture future = this.volService.expungeVolumeAsync(this.volFactory.getVolume(volume.getId())); + future.get(); + + } catch (Exception e) { + s_logger.warn("Failed to expunge volume:", e); + return false; + } + + return true; + } + + private boolean validateVolumeSizeRange(long size) { + if (size < 0 || (size > 0 && size < (1024 * 1024 * 1024))) { + throw new InvalidParameterValueException( + "Please specify a size of at least 1 Gb."); + } else if (size > (_maxVolumeSizeInGb * 1024 * 1024 * 1024)) { + throw new InvalidParameterValueException("volume size " + size + + ", but the maximum size allowed is " + _maxVolumeSizeInGb + + " Gb."); + } + + return true; + } + + protected DiskProfile toDiskProfile(VolumeVO vol, DiskOfferingVO offering) { + return new DiskProfile(vol.getId(), vol.getVolumeType(), vol.getName(), + offering.getId(), vol.getSize(), offering.getTagsArray(), + offering.getUseLocalStorage(), offering.isRecreatable(), + vol.getTemplateId()); + } + + @Override + public DiskProfile allocateRawVolume(Type type, + String name, DiskOfferingVO offering, Long size, VMInstanceVO vm, Account owner) { + if (size == null) { + size = offering.getDiskSize(); + } else { + size = (size * 1024 * 1024 * 1024); + } + VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), + owner.getDomainId(), owner.getId(), offering.getId(), size); + if (vm != null) { + vol.setInstanceId(vm.getId()); + } + + if (type.equals(Type.ROOT)) { + vol.setDeviceId(0l); + } else { + vol.setDeviceId(1l); + } + + vol = _volsDao.persist(vol); + + // Save usage event and update resource count for user vm volumes + if (vm instanceof UserVm) { + + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), + vol.getDataCenterId(), vol.getId(), vol.getName(), + offering.getId(), null, size); + _usageEventDao.persist(usageEvent); + + _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), + ResourceType.volume); + } + return toDiskProfile(vol, offering); + } + + @Override + public DiskProfile allocateTemplatedVolume( + Type type, String name, DiskOfferingVO offering, + VMTemplateVO template, VMInstanceVO vm, Account owner) { + assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really...."; + + Long size = this._tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId()); + + VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), + owner.getDomainId(), owner.getId(), offering.getId(), size); + if (vm != null) { + vol.setInstanceId(vm.getId()); + } + vol.setTemplateId(template.getId()); + + if (type.equals(Type.ROOT)) { + vol.setDeviceId(0l); + if (!vm.getType().equals(VirtualMachine.Type.User)) { + vol.setRecreatable(true); + } + } else { + vol.setDeviceId(1l); + } + + vol = _volsDao.persist(vol); + + // Create event and update resource count for volumes if vm is a user vm + if (vm instanceof UserVm) { + + Long offeringId = null; + + if (offering.getType() == DiskOfferingVO.Type.Disk) { + offeringId = offering.getId(); + } + + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), + vol.getDataCenterId(), vol.getId(), vol.getName(), + offeringId, template.getId(), vol.getSize()); + _usageEventDao.persist(usageEvent); + + _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), + ResourceType.volume); + } + return toDiskProfile(vol, offering); + } + + private String getSupportedImageFormatForCluster(Long clusterId) { + ClusterVO cluster = ApiDBUtils.findClusterById(clusterId); + + if (cluster.getHypervisorType() == HypervisorType.XenServer) { + return "vhd"; + } else if (cluster.getHypervisorType() == HypervisorType.KVM) { + return "qcow2"; + } else if (cluster.getHypervisorType() == HypervisorType.VMware) { + return "ova"; + } else if (cluster.getHypervisorType() == HypervisorType.Ovm) { + return "raw"; + } else { + return null; + } + } + + private VolumeInfo copyVolume(StoragePoolVO rootDiskPool + , VolumeInfo volume, VMInstanceVO vm, VMTemplateVO rootDiskTmplt, DataCenterVO dcVO, + HostPodVO pod, DiskOfferingVO diskVO, ServiceOfferingVO svo, HypervisorType rootDiskHyperType) throws NoTransitionException { + VolumeHostVO volHostVO = _volumeHostDao.findByHostVolume(volume.getDataStore().getId(), volume.getId()); + if (!volHostVO + .getFormat() + .getFileExtension() + .equals( + getSupportedImageFormatForCluster(rootDiskPool + .getClusterId()))) { + throw new InvalidParameterValueException( + "Failed to attach volume to VM since volumes format " + + volHostVO.getFormat() + .getFileExtension() + + " is not compatible with the vm hypervisor type"); + } + + VolumeInfo volumeOnPrimary = copyVolumeFromSecToPrimary(volume, + vm, rootDiskTmplt, dcVO, pod, + rootDiskPool.getClusterId(), svo, diskVO, + new ArrayList(), + volume.getSize(), rootDiskHyperType); + + return volumeOnPrimary; + } + + private VolumeInfo createVolumeOnPrimaryStorage(VMInstanceVO vm, VolumeVO rootVolumeOfVm, VolumeInfo volume, HypervisorType rootDiskHyperType) throws NoTransitionException { + VMTemplateVO rootDiskTmplt = _templateDao.findById(vm + .getTemplateId()); + DataCenterVO dcVO = _dcDao.findById(vm + .getDataCenterId()); + HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn()); + StoragePoolVO rootDiskPool = _storagePoolDao + .findById(rootVolumeOfVm.getPoolId()); + ServiceOfferingVO svo = _serviceOfferingDao.findById(vm + .getServiceOfferingId()); + DiskOfferingVO diskVO = _diskOfferingDao.findById(volume + .getDiskOfferingId()); + Long clusterId = (rootDiskPool == null ? null : rootDiskPool + .getClusterId()); + + VolumeInfo vol = null; + if (volume.getState() == Volume.State.Allocated) { + vol = createVolume(volume, vm, + rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO, + new ArrayList(), volume.getSize(), + rootDiskHyperType); + } else if (volume.getState() == Volume.State.Uploaded) { + vol = copyVolume(rootDiskPool + , volume, vm, rootDiskTmplt, dcVO, + pod, diskVO, svo, rootDiskHyperType); + } + return vol; + } + + private boolean needMoveVolume(VolumeVO rootVolumeOfVm, VolumeInfo volume) { + StoragePoolVO vmRootVolumePool = _storagePoolDao + .findById(rootVolumeOfVm.getPoolId()); + DiskOfferingVO volumeDiskOffering = _diskOfferingDao + .findById(volume.getDiskOfferingId()); + String[] volumeTags = volumeDiskOffering.getTagsArray(); + + boolean isVolumeOnSharedPool = !volumeDiskOffering + .getUseLocalStorage(); + StoragePoolVO sourcePool = _storagePoolDao.findById(volume + .getPoolId()); + List matchingVMPools = _storagePoolDao + .findPoolsByTags(vmRootVolumePool.getDataCenterId(), + vmRootVolumePool.getPodId(), + vmRootVolumePool.getClusterId(), volumeTags, + isVolumeOnSharedPool); + + boolean moveVolumeNeeded = true; + if (matchingVMPools.size() == 0) { + String poolType; + if (vmRootVolumePool.getClusterId() != null) { + poolType = "cluster"; + } else if (vmRootVolumePool.getPodId() != null) { + poolType = "pod"; + } else { + poolType = "zone"; + } + throw new CloudRuntimeException( + "There are no storage pools in the VM's " + poolType + + " with all of the volume's tags (" + + volumeDiskOffering.getTags() + ")."); + } else { + long sourcePoolId = sourcePool.getId(); + Long sourcePoolDcId = sourcePool.getDataCenterId(); + Long sourcePoolPodId = sourcePool.getPodId(); + Long sourcePoolClusterId = sourcePool.getClusterId(); + for (StoragePoolVO vmPool : matchingVMPools) { + long vmPoolId = vmPool.getId(); + Long vmPoolDcId = vmPool.getDataCenterId(); + Long vmPoolPodId = vmPool.getPodId(); + Long vmPoolClusterId = vmPool.getClusterId(); + + // Moving a volume is not required if storage pools belongs + // to same cluster in case of shared volume or + // identical storage pool in case of local + if (sourcePoolDcId == vmPoolDcId + && sourcePoolPodId == vmPoolPodId + && sourcePoolClusterId == vmPoolClusterId + && (isVolumeOnSharedPool || sourcePoolId == vmPoolId)) { + moveVolumeNeeded = false; + break; + } + } + } + + return moveVolumeNeeded; + } + + + private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volume, Long deviceId) { + String errorMsg = "Failed to attach volume: " + volume.getName() + + " to VM: " + vm.getHostName(); + boolean sendCommand = (vm.getState() == State.Running); + AttachVolumeAnswer answer = null; + Long hostId = vm.getHostId(); + if (hostId == null) { + hostId = vm.getLastHostId(); + HostVO host = _hostDao.findById(hostId); + if (host != null + && host.getHypervisorType() == HypervisorType.VMware) { + sendCommand = true; + } + } + + if (sendCommand) { + StoragePoolVO volumePool = _storagePoolDao.findById(volume + .getPoolId()); + AttachVolumeCommand cmd = new AttachVolumeCommand(true, + vm.getInstanceName(), volume.getPoolType(), + volume.getFolder(), volume.getPath(), volume.getName(), + deviceId, volume.getChainInfo()); + cmd.setPoolUuid(volumePool.getUuid()); + + try { + answer = (AttachVolumeAnswer) _agentMgr.send(hostId, cmd); + } catch (Exception e) { + throw new CloudRuntimeException(errorMsg + " due to: " + + e.getMessage()); + } + } + + if (!sendCommand || (answer != null && answer.getResult())) { + // Mark the volume as attached + if (sendCommand) { + _volsDao.attachVolume(volume.getId(), vm.getId(), + answer.getDeviceId()); + } else { + _volsDao.attachVolume(volume.getId(), vm.getId(), deviceId); + } + return _volsDao.findById(volume.getId()); + } else { + if (answer != null) { + String details = answer.getDetails(); + if (details != null && !details.isEmpty()) { + errorMsg += "; " + details; + } + } + throw new CloudRuntimeException(errorMsg); + } + } + + private int getMaxDataVolumesSupported(UserVmVO vm) { + Long hostId = vm.getHostId(); + if (hostId == null) { + hostId = vm.getLastHostId(); + } + HostVO host = _hostDao.findById(hostId); + Integer maxDataVolumesSupported = null; + if (host != null) { + _hostDao.loadDetails(host); + maxDataVolumesSupported = _hypervisorCapabilitiesDao + .getMaxDataVolumesLimit(host.getHypervisorType(), + host.getDetail("product_version")); + } + if (maxDataVolumesSupported == null) { + maxDataVolumesSupported = 6; // 6 data disks by default if nothing + // is specified in + // 'hypervisor_capabilities' table + } + + return maxDataVolumesSupported.intValue(); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription = "attaching volume", async = true) + public Volume attachVolumeToVM(AttachVolumeCmd command) { + Long vmId = command.getVirtualMachineId(); + Long volumeId = command.getId(); + Long deviceId = command.getDeviceId(); + Account caller = UserContext.current().getCaller(); + + // Check that the volume ID is valid + VolumeInfo volume = volFactory.getVolume(volumeId); + // Check that the volume is a data volume + if (volume == null || volume.getVolumeType() != Volume.Type.DATADISK) { + throw new InvalidParameterValueException( + "Please specify a valid data volume."); + } + + // Check that the volume is not currently attached to any VM + if (volume.getInstanceId() != null) { + throw new InvalidParameterValueException( + "Please specify a volume that is not attached to any VM."); + } + + // Check that the volume is not destroyed + if (volume.getState() == Volume.State.Destroy) { + throw new InvalidParameterValueException( + "Please specify a volume that is not destroyed."); + } + + // Check that the virtual machine ID is valid and it's a user vm + UserVmVO vm = _userVmDao.findById(vmId); + if (vm == null || vm.getType() != VirtualMachine.Type.User) { + throw new InvalidParameterValueException( + "Please specify a valid User VM."); + } + + // Check that the VM is in the correct state + if (vm.getState() != State.Running && vm.getState() != State.Stopped) { + throw new InvalidParameterValueException( + "Please specify a VM that is either running or stopped."); + } + + // Check that the device ID is valid + if (deviceId != null) { + if (deviceId.longValue() == 0) { + throw new InvalidParameterValueException( + "deviceId can't be 0, which is used by Root device"); + } + } + + // Check that the number of data volumes attached to VM is less than + // that supported by hypervisor + List existingDataVolumes = _volsDao.findByInstanceAndType( + vmId, Volume.Type.DATADISK); + int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); + if (existingDataVolumes.size() >= maxDataVolumesSupported) { + throw new InvalidParameterValueException( + "The specified VM already has the maximum number of data disks (" + + maxDataVolumesSupported + + "). Please specify another VM."); + } + + // Check that the VM and the volume are in the same zone + if (vm.getDataCenterId() != volume.getDataCenterId()) { + throw new InvalidParameterValueException( + "Please specify a VM that is in the same zone as the volume."); + } + + // If local storage is disabled then attaching a volume with local disk + // offering not allowed + DataCenterVO dataCenter = _dcDao.findById(volume.getDataCenterId()); + if (!dataCenter.isLocalStorageEnabled()) { + DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume + .getDiskOfferingId()); + if (diskOffering.getUseLocalStorage()) { + throw new InvalidParameterValueException( + "Zone is not configured to use local storage but volume's disk offering " + + diskOffering.getName() + " uses it"); + } + } + + // permission check + _accountMgr.checkAccess(caller, null, true, volume, vm); + + if (!(Volume.State.Allocated.equals(volume.getState()) + || Volume.State.Ready.equals(volume.getState()) || Volume.State.Uploaded + .equals(volume.getState()))) { + throw new InvalidParameterValueException( + "Volume state must be in Allocated, Ready or in Uploaded state"); + } + + VolumeVO rootVolumeOfVm = null; + List rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, + Volume.Type.ROOT); + if (rootVolumesOfVm.size() != 1) { + throw new CloudRuntimeException( + "The VM " + + vm.getHostName() + + " has more than one ROOT volume and is in an invalid state."); + } else { + rootVolumeOfVm = rootVolumesOfVm.get(0); + } + + HypervisorType rootDiskHyperType = vm.getHypervisorType(); + + HypervisorType dataDiskHyperType = _volsDao.getHypervisorType(volume + .getId()); + if (dataDiskHyperType != HypervisorType.None + && rootDiskHyperType != dataDiskHyperType) { + throw new InvalidParameterValueException( + "Can't attach a volume created by: " + dataDiskHyperType + + " to a " + rootDiskHyperType + " vm"); + } + + + deviceId = getDeviceId(vmId, deviceId); + VolumeInfo volumeOnPrimaryStorage = volume; + if (volume.getState().equals(Volume.State.Allocated) + || volume.getState() == Volume.State.Uploaded) { + try { + volumeOnPrimaryStorage = createVolumeOnPrimaryStorage(vm, rootVolumeOfVm, volume, rootDiskHyperType); + } catch (NoTransitionException e) { + s_logger.debug("Failed to create volume on primary storage", e); + throw new CloudRuntimeException("Failed to create volume on primary storage", e); + } + } + + boolean moveVolumeNeeded = needMoveVolume(rootVolumeOfVm, volumeOnPrimaryStorage); + + if (moveVolumeNeeded) { + PrimaryDataStoreInfo primaryStore = (PrimaryDataStoreInfo)volumeOnPrimaryStorage.getDataStore(); + if (primaryStore.isLocal()) { + throw new CloudRuntimeException( + "Failed to attach local data volume " + + volume.getName() + + " to VM " + + vm.getDisplayName() + + " as migration of local data volume is not allowed"); + } + StoragePoolVO vmRootVolumePool = _storagePoolDao + .findById(rootVolumeOfVm.getPoolId()); + + try { + volumeOnPrimaryStorage = moveVolume(volumeOnPrimaryStorage, + vmRootVolumePool.getDataCenterId(), + vmRootVolumePool.getPodId(), + vmRootVolumePool.getClusterId(), + dataDiskHyperType); + } catch (ConcurrentOperationException e) { + s_logger.debug("move volume failed", e); + throw new CloudRuntimeException("move volume failed", e); + } + } + + + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor + .getCurrentExecutor(); + if (asyncExecutor != null) { + AsyncJobVO job = asyncExecutor.getJob(); + + if (s_logger.isInfoEnabled()) { + s_logger.info("Trying to attaching volume " + volumeId + + " to vm instance:" + vm.getId() + + ", update async job-" + job.getId() + + " progress status"); + } + + _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); + _asyncMgr.updateAsyncJobStatus(job.getId(), + BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId); + } + + VolumeVO newVol = _volumeDao.findById(volumeOnPrimaryStorage.getId()); + newVol = sendAttachVolumeCommand(vm, newVol, deviceId); + return newVol; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", 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)) + || (cmmd.getId() == null && (cmmd.getDeviceId() == null || cmmd + .getVirtualMachineId() == null))) { + throw new InvalidParameterValueException( + "Please provide either a volume id, or a tuple(device id, instance id)"); + } + + Long volumeId = cmmd.getId(); + VolumeVO volume = null; + + if (volumeId != null) { + volume = _volsDao.findById(volumeId); + } else { + volume = _volsDao.findByInstanceAndDeviceId( + cmmd.getVirtualMachineId(), cmmd.getDeviceId()).get(0); + } + + Long vmId = null; + + if (cmmd.getVirtualMachineId() == null) { + vmId = volume.getInstanceId(); + } else { + vmId = cmmd.getVirtualMachineId(); + } + + // Check that the volume ID is valid + if (volume == null) { + throw new InvalidParameterValueException( + "Unable to find volume with ID: " + volumeId); + } + + // Permissions check + _accountMgr.checkAccess(caller, null, true, volume); + + // Check that the volume is a data volume + if (volume.getVolumeType() != Volume.Type.DATADISK) { + throw new InvalidParameterValueException( + "Please specify a data volume."); + } + + // Check that the volume is currently attached to a VM + if (vmId == null) { + throw new InvalidParameterValueException( + "The specified volume is not attached to a VM."); + } + + // Check that the VM is in the correct state + UserVmVO vm = this._userVmDao.findById(vmId); + if (vm.getState() != State.Running && vm.getState() != State.Stopped + && vm.getState() != State.Destroyed) { + throw new InvalidParameterValueException( + "Please specify a VM that is either running or stopped."); + } + + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor + .getCurrentExecutor(); + if (asyncExecutor != null) { + AsyncJobVO job = asyncExecutor.getJob(); + + if (s_logger.isInfoEnabled()) { + s_logger.info("Trying to attaching volume " + volumeId + + "to vm instance:" + vm.getId() + + ", update async job-" + job.getId() + + " progress status"); + } + + _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); + _asyncMgr.updateAsyncJobStatus(job.getId(), + BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId); + } + + String errorMsg = "Failed to detach volume: " + volume.getName() + + " from VM: " + vm.getHostName(); + boolean sendCommand = (vm.getState() == State.Running); + Answer answer = null; + + if (sendCommand) { + AttachVolumeCommand cmd = new AttachVolumeCommand(false, + vm.getInstanceName(), volume.getPoolType(), + volume.getFolder(), volume.getPath(), volume.getName(), + cmmd.getDeviceId() != null ? cmmd.getDeviceId() : volume + .getDeviceId(), volume.getChainInfo()); + + StoragePoolVO volumePool = _storagePoolDao.findById(volume + .getPoolId()); + cmd.setPoolUuid(volumePool.getUuid()); + + try { + answer = _agentMgr.send(vm.getHostId(), cmd); + } catch (Exception e) { + throw new CloudRuntimeException(errorMsg + " due to: " + + e.getMessage()); + } + } + + if (!sendCommand || (answer != null && answer.getResult())) { + // Mark the volume as detached + _volsDao.detachVolume(volume.getId()); + if (answer != null && answer instanceof AttachVolumeAnswer) { + volume.setChainInfo(((AttachVolumeAnswer) answer) + .getChainInfo()); + _volsDao.update(volume.getId(), volume); + } + + return _volsDao.findById(volumeId); + } else { + + if (answer != null) { + String details = answer.getDetails(); + if (details != null && !details.isEmpty()) { + errorMsg += "; " + details; + } + } + + throw new CloudRuntimeException(errorMsg); + } + } + + + + + + + @DB + protected VolumeVO switchVolume(VolumeVO existingVolume, + VirtualMachineProfile vm) + throws StorageUnavailableException { + Transaction txn = Transaction.currentTxn(); + + Long templateIdToUse = null; + Long volTemplateId = existingVolume.getTemplateId(); + long vmTemplateId = vm.getTemplateId(); + if (volTemplateId != null && volTemplateId.longValue() != vmTemplateId) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("switchVolume: Old Volume's templateId: " + + volTemplateId + + " does not match the VM's templateId: " + + vmTemplateId + + ", updating templateId in the new Volume"); + } + templateIdToUse = vmTemplateId; + } + + txn.start(); + VolumeVO newVolume = allocateDuplicateVolume(existingVolume, + templateIdToUse); + // In case of Vmware if vm reference is not removed then during root + // disk cleanup + // the vm also gets deleted, so remove the reference + if (vm.getHypervisorType() == HypervisorType.VMware) { + _volsDao.detachVolume(existingVolume.getId()); + } + try { + stateTransitTo(existingVolume, Volume.Event.DestroyRequested); + } catch (NoTransitionException e) { + s_logger.debug("Unable to destroy existing volume: " + e.toString()); + } + txn.commit(); + return newVolume; + + } + + + @Override + public void release(VirtualMachineProfile profile) { + // add code here + } + + + @Override + @DB + public void cleanupVolumes(long vmId) throws ConcurrentOperationException { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cleaning storage for vm: " + vmId); + } + List volumesForVm = _volsDao.findByInstance(vmId); + List toBeExpunged = new ArrayList(); + Transaction txn = Transaction.currentTxn(); + txn.start(); + for (VolumeVO vol : volumesForVm) { + if (vol.getVolumeType().equals(Type.ROOT)) { + // This check is for VM in Error state (volume is already + // destroyed) + if (!vol.getState().equals(Volume.State.Destroy)) { + this.volService.destroyVolume(vol.getId()); + } + toBeExpunged.add(vol); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Detaching " + vol); + } + _volsDao.detachVolume(vol.getId()); + } + } + txn.commit(); + AsyncCallFuture future = null; + for (VolumeVO expunge : toBeExpunged) { + future = this.volService.expungeVolumeAsync(this.volFactory.getVolume(expunge.getId())); + try { + future.get(); + } catch (InterruptedException e) { + s_logger.debug("failed expunge volume" + expunge.getId(), e); + } catch (ExecutionException e) { + s_logger.debug("failed expunge volume" + expunge.getId(), e); + } + } + } + + @DB + @Override + public Volume migrateVolume(MigrateVolumeCmd cmd) { + Long volumeId = cmd.getVolumeId(); + Long storagePoolId = cmd.getStoragePoolId(); + + VolumeVO vol = _volsDao.findById(volumeId); + if (vol == null) { + throw new InvalidParameterValueException( + "Failed to find the volume id: " + volumeId); + } + + if (vol.getState() != Volume.State.Ready) { + throw new InvalidParameterValueException( + "Volume must be in ready state"); + } + + if (vol.getInstanceId() != null) { + throw new InvalidParameterValueException( + "Volume needs to be dettached from VM"); + } + + StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + if (destPool == null) { + throw new InvalidParameterValueException( + "Failed to find the destination storage pool: " + + storagePoolId); + } + + if (!volumeOnSharedStoragePool(vol)) { + throw new InvalidParameterValueException( + "Migration of volume from local storage pool is not supported"); + } + + Volume newVol = migrateVolume(vol, destPool); + return newVol; + } + + + + @DB + protected Volume migrateVolume(Volume volume, StoragePool destPool) { + VolumeInfo vol = this.volFactory.getVolume(volume.getId()); + AsyncCallFuture future = this.volService.copyVolume(vol, (DataStore)destPool); + try { + VolumeApiResult result = future.get(); + if (result.isFailed()) { + s_logger.debug("migrate volume failed:" + result.getResult()); + return null; + } + return result.getVolume(); + } catch (InterruptedException e) { + s_logger.debug("migrate volume failed", e); + return null; + } catch (ExecutionException e) { + s_logger.debug("migrate volume failed", e); + return null; + } + } + + @Override + public boolean storageMigration( + VirtualMachineProfile vm, + StoragePool destPool) { + List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); + List volumesNeedToMigrate = new ArrayList(); + + for (VolumeVO volume : vols) { + if (volume.getState() != Volume.State.Ready) { + s_logger.debug("volume: " + volume.getId() + " is in " + + volume.getState() + " state"); + throw new CloudRuntimeException("volume: " + volume.getId() + + " is in " + volume.getState() + " state"); + } + + if (volume.getPoolId() == destPool.getId()) { + s_logger.debug("volume: " + volume.getId() + + " is on the same storage pool: " + destPool.getId()); + continue; + } + + volumesNeedToMigrate.add(volume); + } + + if (volumesNeedToMigrate.isEmpty()) { + s_logger.debug("No volume need to be migrated"); + return true; + } + + for (Volume vol : volumesNeedToMigrate) { + Volume result = migrateVolume(vol, destPool); + if (result == null) { + return false; + } + } + return true; + } + + @Override + public void prepareForMigration( + VirtualMachineProfile vm, + DeployDestination dest) { + List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Preparing " + vols.size() + " volumes for " + vm); + } + + for (VolumeVO vol : vols) { + PrimaryDataStoreInfo pool = (PrimaryDataStoreInfo)this.dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary); + vm.addDisk(new VolumeTO(vol, pool)); + } + + if (vm.getType() == VirtualMachine.Type.User) { + UserVmVO userVM = (UserVmVO) vm.getVirtualMachine(); + if (userVM.getIsoId() != null) { + Pair isoPathPair = this._tmpltMgr.getAbsoluteIsoPath( + userVM.getIsoId(), userVM.getDataCenterId()); + if (isoPathPair != null) { + String isoPath = isoPathPair.first(); + VolumeTO iso = new VolumeTO(vm.getId(), Volume.Type.ISO, + StoragePoolType.ISO, null, null, null, isoPath, 0, + null, null); + vm.addDisk(iso); + } + } + } + } + + + + private static enum VolumeTaskType { + RECREATE, + NOP, + MIGRATE + } + private static class VolumeTask { + final VolumeTaskType type; + final StoragePoolVO pool; + final VolumeVO volume; + VolumeTask(VolumeTaskType type, VolumeVO volume, StoragePoolVO pool) { + this.type = type; + this.pool = pool; + this.volume = volume; + } + } + + private List getTasks(List vols, Map destVols) throws StorageUnavailableException { + boolean recreate = _recreateSystemVmEnabled; + List tasks = new ArrayList(); + for (VolumeVO vol : vols) { + StoragePoolVO assignedPool = null; + if (destVols != null) { + StoragePool pool = destVols.get(vol); + if (pool != null) { + assignedPool = _storagePoolDao.findById(pool.getId()); + } + } + if (assignedPool == null && recreate) { + assignedPool = _storagePoolDao.findById(vol.getPoolId()); + } + if (assignedPool != null || recreate) { + Volume.State state = vol.getState(); + if (state == Volume.State.Allocated + || state == Volume.State.Creating) { + VolumeTask task = new VolumeTask(VolumeTaskType.RECREATE, vol, null); + tasks.add(task); + } else { + if (vol.isRecreatable()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Volume " + vol + + " will be recreated on storage pool " + + assignedPool + + " assigned by deploymentPlanner"); + } + VolumeTask task = new VolumeTask(VolumeTaskType.RECREATE, vol, null); + tasks.add(task); + } else { + if (assignedPool.getId() != vol.getPoolId()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Mismatch in storage pool " + + assignedPool + + " assigned by deploymentPlanner and the one associated with volume " + + vol); + } + DiskOfferingVO diskOffering = _diskOfferingDao + .findById(vol.getDiskOfferingId()); + if (diskOffering.getUseLocalStorage()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Local volume " + + vol + + " will be recreated on storage pool " + + assignedPool + + " assigned by deploymentPlanner"); + } + VolumeTask task = new VolumeTask(VolumeTaskType.RECREATE, vol, null); + tasks.add(task); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Shared volume " + + vol + + " will be migrated on storage pool " + + assignedPool + + " assigned by deploymentPlanner"); + } + VolumeTask task = new VolumeTask(VolumeTaskType.MIGRATE, vol, null); + tasks.add(task); + } + } else { + StoragePoolVO pool = _storagePoolDao + .findById(vol.getPoolId()); + VolumeTask task = new VolumeTask(VolumeTaskType.NOP, vol, pool); + tasks.add(task); + } + + } + } + } else { + if (vol.getPoolId() == null) { + throw new StorageUnavailableException( + "Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create " + + vol, Volume.class, vol.getId()); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("No need to recreate the volume: " + vol + + ", since it already has a pool assigned: " + + vol.getPoolId() + ", adding disk to VM"); + } + StoragePoolVO pool = _storagePoolDao.findById(vol + .getPoolId()); + VolumeTask task = new VolumeTask(VolumeTaskType.NOP, vol, pool); + tasks.add(task); + } + } + + return tasks; + } + + private Pair recreateVolume(VolumeVO vol, VirtualMachineProfile vm, + DeployDestination dest) throws StorageUnavailableException { + VolumeVO newVol; + boolean recreate = _recreateSystemVmEnabled; + DataStore destPool = null; + if (recreate + && (dest.getStorageForDisks() == null || dest + .getStorageForDisks().get(vol) == null)) { + destPool = dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary); + s_logger.debug("existing pool: " + destPool.getId()); + } else { + StoragePool pool = dest.getStorageForDisks().get(vol); + destPool = dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); + } + + if (vol.getState() == Volume.State.Allocated + || vol.getState() == Volume.State.Creating) { + newVol = vol; + } else { + newVol = switchVolume(vol, vm); + // update the volume->PrimaryDataStoreVO map since volumeId has + // changed + if (dest.getStorageForDisks() != null + && dest.getStorageForDisks().containsKey(vol)) { + StoragePool poolWithOldVol = dest + .getStorageForDisks().get(vol); + dest.getStorageForDisks().put(newVol, poolWithOldVol); + dest.getStorageForDisks().remove(vol); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Created new volume " + newVol + + " for old volume " + vol); + } + } + VolumeInfo volume = volFactory.getVolume(newVol.getId(), destPool); + Long templateId = newVol.getTemplateId(); + AsyncCallFuture future = null; + if (templateId == null) { + future = this.volService.createVolumeAsync(volume, destPool); + } else { + TemplateInfo templ = this.tmplFactory.getTemplate(templateId); + future = this.volService.createVolumeFromTemplateAsync(volume, destPool.getId(), templ); + } + VolumeApiResult result = null; + try { + result = future.get(); + if (result.isFailed()) { + s_logger.debug("Unable to create " + + newVol + ":" + result.getResult()); + throw new StorageUnavailableException("Unable to create " + + newVol + ":" + result.getResult(), destPool.getId()); + } + newVol = this._volsDao.findById(newVol.getId()); + } catch (InterruptedException e) { + s_logger.error("Unable to create " + newVol, e); + throw new StorageUnavailableException("Unable to create " + + newVol + ":" + e.toString(), destPool.getId()); + } catch (ExecutionException e) { + s_logger.error("Unable to create " + newVol, e); + throw new StorageUnavailableException("Unable to create " + + newVol + ":" + e.toString(), destPool.getId()); + } + + return new Pair(newVol, destPool); + } + + @Override + public void prepare(VirtualMachineProfile vm, + DeployDestination dest) throws StorageUnavailableException, + InsufficientStorageCapacityException, ConcurrentOperationException { + + if (dest == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("DeployDestination cannot be null, cannot prepare Volumes for the vm: " + + vm); + } + throw new CloudRuntimeException( + "Unable to prepare Volume for vm because DeployDestination is null, vm:" + + vm); + } + List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Checking if we need to prepare " + vols.size() + + " volumes for " + vm); + } + + List tasks = getTasks(vols, dest.getStorageForDisks()); + Volume vol = null; + StoragePool pool = null; + for (VolumeTask task : tasks) { + if (task.type == VolumeTaskType.NOP) { + pool = (StoragePool)dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary); + vol = task.volume; + } else if (task.type == VolumeTaskType.MIGRATE) { + pool = (StoragePool)dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary); + migrateVolume(task.volume, pool); + vol = task.volume; + } else if (task.type == VolumeTaskType.RECREATE) { + Pair result = recreateVolume(task.volume, vm, dest); + pool = (StoragePool)dataStoreMgr.getDataStore(result.second().getId(), DataStoreRole.Primary); + vol = result.first(); + } + vm.addDisk(new VolumeTO(vol, pool)); + } + } + + private Long getDeviceId(long vmId, Long deviceId) { + // allocate deviceId + List vols = _volsDao.findByInstance(vmId); + if (deviceId != null) { + if (deviceId.longValue() > 15 || deviceId.longValue() == 0 + || deviceId.longValue() == 3) { + throw new RuntimeException("deviceId should be 1,2,4-15"); + } + for (VolumeVO vol : vols) { + if (vol.getDeviceId().equals(deviceId)) { + throw new RuntimeException("deviceId " + deviceId + + " is used by vm" + vmId); + } + } + } else { + // allocate deviceId here + List devIds = new ArrayList(); + for (int i = 1; i < 15; i++) { + devIds.add(String.valueOf(i)); + } + devIds.remove("3"); + for (VolumeVO vol : vols) { + devIds.remove(vol.getDeviceId().toString().trim()); + } + deviceId = Long.parseLong(devIds.iterator().next()); + } + + return deviceId; + } + + private boolean stateTransitTo(Volume vol, Volume.Event event) + throws NoTransitionException { + return _volStateMachine.transitTo(vol, event, null, _volsDao); + } + + + private String validateUrl(String url) { + try { + URI uri = new URI(url); + if ((uri.getScheme() == null) + || (!uri.getScheme().equalsIgnoreCase("http") + && !uri.getScheme().equalsIgnoreCase("https") && !uri + .getScheme().equalsIgnoreCase("file"))) { + throw new IllegalArgumentException( + "Unsupported scheme for url: " + url); + } + + int port = uri.getPort(); + if (!(port == 80 || port == 443 || port == -1)) { + throw new IllegalArgumentException( + "Only ports 80 and 443 are allowed"); + } + String host = uri.getHost(); + try { + InetAddress hostAddr = InetAddress.getByName(host); + if (hostAddr.isAnyLocalAddress() + || hostAddr.isLinkLocalAddress() + || hostAddr.isLoopbackAddress() + || hostAddr.isMulticastAddress()) { + throw new IllegalArgumentException( + "Illegal host specified in url"); + } + if (hostAddr instanceof Inet6Address) { + throw new IllegalArgumentException( + "IPV6 addresses not supported (" + + hostAddr.getHostAddress() + ")"); + } + } catch (UnknownHostException uhe) { + throw new IllegalArgumentException("Unable to resolve " + host); + } + + return uri.toString(); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Invalid URL " + url); + } + + } + + @Override + public boolean canVmRestartOnAnotherServer(long vmId) { + List vols = _volsDao.findCreatedByInstance(vmId); + for (VolumeVO vol : vols) { + if (!vol.isRecreatable() && !vol.getPoolType().isShared()) { + return false; + } + } + return true; + } + + @Override + public boolean configure(String name, Map params) + throws ConfigurationException { + String _customDiskOfferingMinSizeStr = _configDao + .getValue(Config.CustomDiskOfferingMinSize.toString()); + _customDiskOfferingMinSize = NumbersUtil.parseInt( + _customDiskOfferingMinSizeStr, Integer + .parseInt(Config.CustomDiskOfferingMinSize + .getDefaultValue())); + + String maxVolumeSizeInGbString = _configDao + .getValue("storage.max.volume.size"); + _maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, + 2000); + + String value = _configDao.getValue(Config.RecreateSystemVmEnabled.key()); + _recreateSystemVmEnabled = Boolean.parseBoolean(value); + _copyvolumewait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); + + HostTemplateStatesSearch = _vmTemplateHostDao.createSearchBuilder(); + HostTemplateStatesSearch.and("id", HostTemplateStatesSearch.entity() + .getTemplateId(), SearchCriteria.Op.EQ); + HostTemplateStatesSearch.and("state", HostTemplateStatesSearch.entity() + .getDownloadState(), SearchCriteria.Op.EQ); + + SearchBuilder HostSearch = _hostDao.createSearchBuilder(); + HostSearch.and("dcId", HostSearch.entity().getDataCenterId(), + SearchCriteria.Op.EQ); + + HostTemplateStatesSearch.join("host", HostSearch, HostSearch.entity() + .getId(), HostTemplateStatesSearch.entity().getHostId(), + JoinBuilder.JoinType.INNER); + HostSearch.done(); + HostTemplateStatesSearch.done(); + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return "Volume Manager"; + } + + @Override + public void destroyVolume(VolumeVO volume) { + try { + this.volService.destroyVolume(volume.getId()); + } catch (ConcurrentOperationException e) { + s_logger.debug("Failed to destroy volume" + volume.getId(), e); + throw new CloudRuntimeException("Failed to destroy volume" + volume.getId(), e); + } + } + +} diff --git a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java index 61b5e1f7752..d747d25c7b5 100755 --- a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java @@ -26,6 +26,8 @@ import java.util.Set; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import com.cloud.capacity.CapacityManager; @@ -41,7 +43,6 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; @@ -76,6 +77,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement @Inject ClusterDao _clusterDao; @Inject SwiftManager _swiftMgr; @Inject CapacityManager _capacityMgr; + @Inject DataStoreManager dataStoreMgr; protected BigDecimal _storageOverprovisioningFactor = new BigDecimal(1); long _extraBytesPerVolume = 0; Random _rand; @@ -121,7 +123,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement boolean localStorageAllocationNeeded = localStorageAllocationNeeded(dskCh); if (s_logger.isDebugEnabled()) { s_logger.debug("Is localStorageAllocationNeeded? "+ localStorageAllocationNeeded); - s_logger.debug("Is storage pool shared? "+ pool.getPoolType().isShared()); + s_logger.debug("Is storage pool shared? "+ pool.isShared()); } return ((!localStorageAllocationNeeded && pool.getPoolType().isShared()) || (localStorageAllocationNeeded && !pool.getPoolType().isShared())); @@ -133,8 +135,8 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement if (s_logger.isDebugEnabled()) { s_logger.debug("Checking if storage pool is suitable, name: " + pool.getName()+ " ,poolId: "+ pool.getId()); } - - if (avoid.shouldAvoid(pool)) { + StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); + if (avoid.shouldAvoid(pol)) { if (s_logger.isDebugEnabled()) { s_logger.debug("StoragePool is in avoid set, skipping this pool"); } @@ -157,7 +159,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement } // Check that the pool type is correct - if (!poolIsCorrectType(dskCh, pool)) { + if (!poolIsCorrectType(dskCh, pol)) { if (s_logger.isDebugEnabled()) { s_logger.debug("StoragePool is not of correct type, skipping this pool"); } @@ -181,7 +183,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement Volume volume = _volumeDao.findById(dskCh.getVolumeId()); List requestVolumes = new ArrayList(); requestVolumes.add(volume); - return _storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool); + return _storageMgr.storagePoolHasEnoughSpace(requestVolumes, pol); } diff --git a/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java index 13a010729e0..f0df3a6f001 100644 --- a/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java @@ -27,6 +27,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import com.cloud.deploy.DeploymentPlan; @@ -34,11 +35,10 @@ import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.offering.ServiceOffering; import com.cloud.server.StatsCollector; import com.cloud.storage.DiskOfferingVO; -import com.cloud.storage.dao.DiskOfferingDao; -import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePool; +import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.user.Account; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; @@ -117,7 +117,8 @@ public class FirstFitStoragePoolAllocator extends AbstractStoragePoolAllocator { } if (checkPool(avoid, pool, dskCh, template, null, sc, plan)) { - suitablePools.add(pool); + StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); + suitablePools.add(pol); } } diff --git a/server/src/com/cloud/storage/allocator/LocalStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/LocalStoragePoolAllocator.java index b6b8e8e98ff..24b4dabe281 100644 --- a/server/src/com/cloud/storage/allocator/LocalStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/LocalStoragePoolAllocator.java @@ -25,6 +25,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import com.cloud.capacity.CapacityVO; @@ -36,7 +37,6 @@ import com.cloud.offering.ServiceOffering; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.StoragePoolHostDao; @@ -110,7 +110,8 @@ public class LocalStoragePoolAllocator extends FirstFitStoragePoolAllocator { StoragePoolVO pool = _storagePoolDao.findById(hostPool.getPoolId()); if (pool != null && pool.isLocal()) { s_logger.debug("Found suitable local storage pool " + pool.getId() + ", adding to list"); - suitablePools.add(pool); + StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); + suitablePools.add(pol); } if (suitablePools.size() == returnUpTo) { diff --git a/server/src/com/cloud/storage/dao/LaunchPermissionDao.java b/server/src/com/cloud/storage/dao/LaunchPermissionDao.java index 86e5a9bf827..0ad60b50ee8 100644 --- a/server/src/com/cloud/storage/dao/LaunchPermissionDao.java +++ b/server/src/com/cloud/storage/dao/LaunchPermissionDao.java @@ -18,6 +18,7 @@ package com.cloud.storage.dao; import java.util.List; + import com.cloud.storage.LaunchPermissionVO; import com.cloud.storage.VMTemplateVO; import com.cloud.utils.db.GenericDao; diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/server/src/com/cloud/storage/dao/SnapshotDao.java index 3b961f6fa89..0e378a724b4 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotDao.java @@ -25,7 +25,7 @@ import com.cloud.utils.fsm.StateDao; import java.util.List; -public interface SnapshotDao extends GenericDao, StateDao { +public interface SnapshotDao extends GenericDao, StateDao { List listByVolumeId(long volumeId); List listByVolumeId(Filter filter, long volumeId); SnapshotVO findNextSnapshot(long parentSnapId); diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java index a8a07dcc3a6..5b3f2732f99 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -324,7 +324,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements } @Override - public boolean updateState(State currentState, Event event, State nextState, Snapshot snapshot, Object data) { + public boolean updateState(State currentState, Event event, State nextState, SnapshotVO snapshot, Object data) { Transaction txn = Transaction.currentTxn(); txn.start(); SnapshotVO snapshotVO = (SnapshotVO)snapshot; diff --git a/server/src/com/cloud/storage/dao/StoragePoolDao.java b/server/src/com/cloud/storage/dao/StoragePoolDao.java index ff8292e9705..64bbd5fb5ed 100644 --- a/server/src/com/cloud/storage/dao/StoragePoolDao.java +++ b/server/src/com/cloud/storage/dao/StoragePoolDao.java @@ -20,8 +20,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.utils.db.GenericDao; /** * Data Access Object for storage_pool table diff --git a/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java b/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java index 4019dffd4ae..ebf2943ec9c 100644 --- a/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java +++ b/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java @@ -28,13 +28,13 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; import com.cloud.host.Status; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePoolDetailVO; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; diff --git a/server/src/com/cloud/storage/dao/VMTemplateDao.java b/server/src/com/cloud/storage/dao/VMTemplateDao.java index a043a2c6079..c39626f54dd 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDao.java @@ -20,6 +20,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; + import com.cloud.domain.DomainVO; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.projects.Project.ListProjectResourcesCriteria; @@ -28,11 +31,12 @@ import com.cloud.template.VirtualMachineTemplate.TemplateFilter; import com.cloud.user.Account; import com.cloud.utils.Pair; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; /* * Data Access Object for vm_templates table */ -public interface VMTemplateDao extends GenericDao { +public interface VMTemplateDao extends GenericDao, StateDao { public List listByPublic(); diff --git a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index 42f10d34c1b..c4928be8fee 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -16,8 +16,8 @@ // under the License. package com.cloud.storage.dao; -import static com.cloud.utils.StringUtils.*; -import static com.cloud.utils.db.DbUtil.*; +import static com.cloud.utils.StringUtils.join; +import static com.cloud.utils.db.DbUtil.closeResources; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -34,10 +34,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.api.BaseCmd; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.DomainVO; @@ -55,11 +57,10 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.tags.ResourceTagVO; -import com.cloud.tags.dao.ResourceTagsDaoImpl; +import com.cloud.tags.dao.ResourceTagDao; import com.cloud.template.VirtualMachineTemplate.TemplateFilter; import com.cloud.user.Account; import com.cloud.utils.Pair; - import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; @@ -68,7 +69,9 @@ import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.exception.CloudRuntimeException; @Component @@ -122,14 +125,15 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem private SearchBuilder PublicIsoSearch; private SearchBuilder UserIsoSearch; private GenericSearchBuilder CountTemplatesByAccount; + private SearchBuilder updateStateSearch; - @Inject ResourceTagsDaoImpl _tagsDao; + @Inject ResourceTagDao _tagsDao; private String routerTmpltName; private String consoleProxyTmpltName; - protected VMTemplateDaoImpl() { + public VMTemplateDaoImpl() { } @Override @@ -378,6 +382,12 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem CountTemplatesByAccount.and("account", CountTemplatesByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); CountTemplatesByAccount.and("removed", CountTemplatesByAccount.entity().getRemoved(), SearchCriteria.Op.NULL); CountTemplatesByAccount.done(); + + updateStateSearch = this.createSearchBuilder(); + updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); + updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); + updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); + updateStateSearch.done(); return result; } @@ -1073,4 +1083,39 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem return templateZonePairList; } + @Override + public boolean updateState(TemplateState currentState, TemplateEvent event, + TemplateState nextState, VMTemplateVO vo, Object data) { + Long oldUpdated = vo.getUpdatedCount(); + Date oldUpdatedTime = vo.getUpdated(); + + + SearchCriteria sc = updateStateSearch.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((VMTemplateVO) vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + VMTemplateVO 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 objectIndatastore: id=" + vo.getId() + ", as there is no such object exists in the database anymore"); + } + } + return rows > 0; + } } diff --git a/server/src/com/cloud/storage/dao/VMTemplateHostDao.java b/server/src/com/cloud/storage/dao/VMTemplateHostDao.java index 5625e568ef0..23241cd17da 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateHostDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplateHostDao.java @@ -18,11 +18,15 @@ package com.cloud.storage.dao; import java.util.List; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; -public interface VMTemplateHostDao extends GenericDao { +public interface VMTemplateHostDao extends GenericDao, StateDao { List listByHostId(long id); List listByTemplateId(long templateId); @@ -30,6 +34,8 @@ public interface VMTemplateHostDao extends GenericDao { List listByOnlyTemplateId(long templateId); VMTemplateHostVO findByHostTemplate(long hostId, long templateId); + + VMTemplateHostVO findByTemplateId(long templateId); VMTemplateHostVO findByHostTemplate(long hostId, long templateId, boolean lock); diff --git a/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java index 4d1ac0208ac..7f35eabfaa7 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java @@ -29,6 +29,9 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -42,7 +45,9 @@ import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.UpdateBuilder; @Component @Local(value={VMTemplateHostDao.class}) @@ -57,6 +62,7 @@ public class VMTemplateHostDaoImpl extends GenericDaoBase HostDestroyedSearch; protected final SearchBuilder TemplateStatusSearch; protected final SearchBuilder TemplateStatesSearch; + protected final SearchBuilder updateStateSearch; protected SearchBuilder ZONE_TEMPLATE_SEARCH; protected SearchBuilder LOCAL_SECONDARY_STORAGE_SEARCH; @@ -120,6 +126,12 @@ public class VMTemplateHostDaoImpl extends GenericDaoBase sc = HostTemplateSearch.create(); + sc.setParameters("template_id", templateId); + sc.setParameters("destroyed", false); + return findOneIncludingRemovedBy(sc); + } @Override public List listByTemplateStatus(long templateId, VMTemplateHostVO.Status downloadState) { @@ -238,7 +258,6 @@ public class VMTemplateHostDaoImpl extends GenericDaoBase sc = updateStateSearch.create(); + sc.setParameters("id", templateHost.getId()); + sc.setParameters("state", currentState); + sc.setParameters("updatedCount", templateHost.getUpdatedCount()); + + templateHost.incrUpdatedCount(); + + UpdateBuilder builder = getUpdateBuilder(vo); + builder.set(vo, "state", nextState); + builder.set(vo, "updated", new Date()); + + int rows = update((VMTemplateHostVO) vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + VMTemplateHostVO dbVol = findByIdIncludingRemoved(templateHost.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(templateHost.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(templateHost.getUpdatedCount()) + .append("; updatedTime=").append(templateHost.getUpdated()); + str.append(": stale Data={id=").append(templateHost.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated) + .append("; updatedTime=").append(oldUpdatedTime); + } else { + s_logger.debug("Unable to update objectIndatastore: id=" + templateHost.getId() + ", as there is no such object exists in the database anymore"); + } + } + return rows > 0; + } } diff --git a/server/src/com/cloud/storage/dao/VMTemplatePoolDao.java b/server/src/com/cloud/storage/dao/VMTemplatePoolDao.java index f485be7f05c..501c3ca5cc8 100644 --- a/server/src/com/cloud/storage/dao/VMTemplatePoolDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplatePoolDao.java @@ -18,10 +18,14 @@ package com.cloud.storage.dao; import java.util.List; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; -public interface VMTemplatePoolDao extends GenericDao { +public interface VMTemplatePoolDao extends GenericDao, StateDao { public List listByPoolId(long id); public List listByTemplateId(long templateId); @@ -42,5 +46,4 @@ public interface VMTemplatePoolDao extends GenericDao TemplateStatusSearch; protected final SearchBuilder TemplatePoolStatusSearch; protected final SearchBuilder TemplateStatesSearch; + protected final SearchBuilder updateStateSearch; protected static final String UPDATE_TEMPLATE_HOST_REF = "UPDATE template_spool_ref SET download_state = ?, download_pct= ?, last_updated = ? " @@ -94,6 +101,12 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase sc = updateStateSearch.create(); + sc.setParameters("id", templatePool.getId()); + sc.setParameters("state", currentState); + sc.setParameters("updatedCount", templatePool.getUpdatedCount()); + + templatePool.incrUpdatedCount(); + + UpdateBuilder builder = getUpdateBuilder(vo); + builder.set(vo, "state", nextState); + builder.set(vo, "updated", new Date()); + + int rows = update((VMTemplateStoragePoolVO) vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + VMTemplateStoragePoolVO dbVol = findByIdIncludingRemoved(templatePool.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(templatePool.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(templatePool.getUpdatedCount()) + .append("; updatedTime=").append(templatePool.getUpdated()); + str.append(": stale Data={id=").append(templatePool.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated) + .append("; updatedTime=").append(oldUpdatedTime); + } else { + s_logger.debug("Unable to update objectIndatastore: id=" + templatePool.getId() + ", as there is no such object exists in the database anymore"); + } + } + return rows > 0; + } + } diff --git a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java index a189d00fead..ca3b82a06c1 100755 --- a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java @@ -39,7 +39,6 @@ import com.cloud.storage.Volume.Type; import com.cloud.storage.VolumeVO; import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.utils.Pair; - import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; @@ -250,7 +249,7 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol } } - protected VolumeDaoImpl() { + public VolumeDaoImpl() { AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ); AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ); diff --git a/server/src/com/cloud/storage/dao/VolumeHostDao.java b/server/src/com/cloud/storage/dao/VolumeHostDao.java index 6ba82370608..39dda12345b 100755 --- a/server/src/com/cloud/storage/dao/VolumeHostDao.java +++ b/server/src/com/cloud/storage/dao/VolumeHostDao.java @@ -18,10 +18,14 @@ package com.cloud.storage.dao; import java.util.List; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.storage.VolumeHostVO; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; -public interface VolumeHostDao extends GenericDao { +public interface VolumeHostDao extends GenericDao, StateDao{ VolumeHostVO findByHostVolume(long hostId, long volumeId); diff --git a/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java index 57f2153f10b..2fd39e6eeca 100755 --- a/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java @@ -16,28 +16,35 @@ // under the License. package com.cloud.storage.dao; +import java.util.Date; import java.util.List; import javax.ejb.Local; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.storage.VolumeHostVO; 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; @Component @Local(value={VolumeHostDao.class}) public class VolumeHostDaoImpl extends GenericDaoBase implements VolumeHostDao { - + private static final Logger s_logger = Logger.getLogger(VolumeHostDaoImpl.class); protected final SearchBuilder HostVolumeSearch; protected final SearchBuilder ZoneVolumeSearch; protected final SearchBuilder VolumeSearch; protected final SearchBuilder HostSearch; protected final SearchBuilder HostDestroyedSearch; - - VolumeHostDaoImpl(){ + protected final SearchBuilder updateStateSearch; + public VolumeHostDaoImpl(){ HostVolumeSearch = createSearchBuilder(); HostVolumeSearch.and("host_id", HostVolumeSearch.entity().getHostId(), SearchCriteria.Op.EQ); HostVolumeSearch.and("volume_id", HostVolumeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); @@ -64,6 +71,12 @@ public class VolumeHostDaoImpl extends GenericDaoBase implem HostDestroyedSearch.and("host_id", HostDestroyedSearch.entity().getHostId(), SearchCriteria.Op.EQ); HostDestroyedSearch.and("destroyed", HostDestroyedSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); HostDestroyedSearch.done(); + + updateStateSearch = this.createSearchBuilder(); + updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); + updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); + updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); + updateStateSearch.done(); } @@ -112,4 +125,41 @@ public class VolumeHostDaoImpl extends GenericDaoBase implem return listIncludingRemovedBy(sc); } + @Override + public boolean updateState(State currentState, Event event, + State nextState, DataObjectInStore vo, Object data) { + VolumeHostVO volHost = (VolumeHostVO) vo; + Long oldUpdated = volHost.getUpdatedCount(); + Date oldUpdatedTime = volHost.getUpdated(); + + + SearchCriteria sc = updateStateSearch.create(); + sc.setParameters("id", volHost.getId()); + sc.setParameters("state", currentState); + sc.setParameters("updatedCount", volHost.getUpdatedCount()); + + volHost.incrUpdatedCount(); + + UpdateBuilder builder = getUpdateBuilder(vo); + builder.set(vo, "state", nextState); + builder.set(vo, "updated", new Date()); + + int rows = update((VolumeHostVO) vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + VolumeHostVO dbVol = findByIdIncludingRemoved(volHost.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(volHost.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(volHost.getUpdatedCount()) + .append("; updatedTime=").append(volHost.getUpdated()); + str.append(": stale Data={id=").append(volHost.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated) + .append("; updatedTime=").append(oldUpdatedTime); + } else { + s_logger.debug("Unable to update objectIndatastore: id=" + volHost.getId() + ", as there is no such object exists in the database anymore"); + } + } + return rows > 0; + } + } diff --git a/server/src/com/cloud/storage/download/DownloadListener.java b/server/src/com/cloud/storage/download/DownloadListener.java index 036d40ad015..d0b186831c8 100755 --- a/server/src/com/cloud/storage/download/DownloadListener.java +++ b/server/src/com/cloud/storage/download/DownloadListener.java @@ -46,11 +46,11 @@ import com.cloud.host.HostVO; import com.cloud.storage.Storage; import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VolumeHostVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.Volume.Event; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VolumeDao; diff --git a/server/src/com/cloud/storage/download/DownloadMonitor.java b/server/src/com/cloud/storage/download/DownloadMonitor.java index 30ec3b1623b..897befa250b 100644 --- a/server/src/com/cloud/storage/download/DownloadMonitor.java +++ b/server/src/com/cloud/storage/download/DownloadMonitor.java @@ -18,6 +18,7 @@ package com.cloud.storage.download; import java.util.Map; + import com.cloud.exception.StorageUnavailableException; import com.cloud.host.HostVO; import com.cloud.storage.VMTemplateVO; diff --git a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java index 6d3cf2a101b..1fd1996fbd2 100755 --- a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java +++ b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java @@ -37,10 +37,21 @@ import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; -import com.cloud.agent.api.storage.*; + +import com.cloud.agent.api.storage.DeleteTemplateCommand; +import com.cloud.agent.api.storage.DeleteVolumeCommand; +import com.cloud.agent.api.storage.DownloadCommand; + import com.cloud.agent.api.storage.DownloadCommand.Proxy; import com.cloud.agent.api.storage.DownloadCommand.ResourceType; import com.cloud.agent.api.storage.DownloadProgressCommand.RequestType; + +import com.cloud.agent.api.storage.DownloadProgressCommand; +import com.cloud.agent.api.storage.ListTemplateAnswer; +import com.cloud.agent.api.storage.ListTemplateCommand; +import com.cloud.agent.api.storage.ListVolumeAnswer; +import com.cloud.agent.api.storage.ListVolumeCommand; + import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; import com.cloud.configuration.Config; @@ -50,6 +61,7 @@ import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; +import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.StorageUnavailableException; @@ -59,13 +71,31 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.*; + +import com.cloud.storage.StorageManager; +import com.cloud.storage.SwiftVO; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.dao.*; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.SwiftDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateSwiftDao; +import com.cloud.storage.dao.VMTemplateZoneDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; + import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.storage.template.TemplateConstants; import com.cloud.storage.template.TemplateInfo; +import com.cloud.template.TemplateManager; import com.cloud.user.Account; import com.cloud.user.ResourceLimitService; import com.cloud.utils.component.ManagerBase; @@ -78,8 +108,11 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.SecondaryStorageVm; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.UserVmManager; +import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.SecondaryStorageVmDao; +import com.cloud.vm.dao.UserVmDao; + import edu.emory.mathcs.backport.java.util.Collections; @@ -124,6 +157,14 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor ConfigurationDao _configDao; @Inject UserVmManager _vmMgr; + + @Inject TemplateManager templateMgr; + + + @Inject + private UsageEventDao _usageEventDao; + + @Inject private ClusterDao _clusterDao; @Inject @@ -134,6 +175,8 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor private SwiftDao _swiftDao; @Inject protected ResourceLimitService _resourceLimitMgr; + @Inject + protected UserVmDao _userVmDao; private Boolean _sslCopy = new Boolean(false); private String _copyAuthPasswd; @@ -233,7 +276,7 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor if(destTmpltHost != null) { start(); - String sourceChecksum = _vmMgr.getChecksum(srcTmpltHost.getHostId(), srcTmpltHost.getInstallPath()); + String sourceChecksum = this.templateMgr.getChecksum(srcTmpltHost.getHostId(), srcTmpltHost.getInstallPath()); DownloadCommand dcmd = new DownloadCommand(destServer.getStorageUrl(), url, template, TemplateConstants.DEFAULT_HTTP_AUTH_USER, _copyAuthPasswd, maxTemplateSizeInBytes); dcmd.setProxy(getHttpProxy()); @@ -473,6 +516,8 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor long size = -1; if(vmTemplateHost!=null){ size = vmTemplateHost.getPhysicalSize(); + template.setSize(size); + this._templateDao.update(template.getId(), template); } else{ s_logger.warn("Failed to get size for template" + template.getName()); @@ -510,6 +555,8 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor long size = -1; if(volumeHost!=null){ size = volumeHost.getPhysicalSize(); + volume.setSize(size); + this._volumeDao.update(volume.getId(), volume); } else{ s_logger.warn("Failed to get size for volume" + volume.getName()); @@ -884,17 +931,21 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor for (String uniqueName : templateInfos.keySet()) { TemplateInfo tInfo = templateInfos.get(uniqueName); - DeleteTemplateCommand dtCommand = new DeleteTemplateCommand(ssHost.getStorageUrl(), tInfo.getInstallPath()); - try { - _agentMgr.sendToSecStorage(ssHost, dtCommand, null); - } catch (AgentUnavailableException e) { - String err = "Failed to delete " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " which isn't in the database"; - s_logger.error(err); - return; - } + List userVmUsingIso = _userVmDao.listByIsoId(tInfo.getId()); + //check if there is any Vm using this ISO. + if (userVmUsingIso == null || userVmUsingIso.isEmpty()) { + DeleteTemplateCommand dtCommand = new DeleteTemplateCommand(ssHost.getStorageUrl(), tInfo.getInstallPath()); + try { + _agentMgr.sendToSecStorage(ssHost, dtCommand, null); + } catch (AgentUnavailableException e) { + String err = "Failed to delete " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " which isn't in the database"; + s_logger.error(err); + return; + } - String description = "Deleted template " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " since it isn't in the database"; - s_logger.info(description); + String description = "Deleted template " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " since it isn't in the database"; + s_logger.info(description); + } } } @@ -925,7 +976,7 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor s_logger.debug("Found " +templateHostRefList.size()+ " templates with no checksum. Will ask for computation"); for(VMTemplateHostVO templateHostRef : templateHostRefList){ s_logger.debug("Getting checksum for template - " + templateHostRef.getTemplateId()); - String checksum = _vmMgr.getChecksum(hostId, templateHostRef.getInstallPath()); + String checksum = this.templateMgr.getChecksum(hostId, templateHostRef.getInstallPath()); VMTemplateVO template = _templateDao.findById(templateHostRef.getTemplateId()); s_logger.debug("Setting checksum " +checksum+ " for template - " + template.getName()); template.setChecksum(checksum); diff --git a/server/src/com/cloud/storage/listener/SnapshotStateListener.java b/server/src/com/cloud/storage/listener/SnapshotStateListener.java index 17ccce54c82..8f94f23a27c 100644 --- a/server/src/com/cloud/storage/listener/SnapshotStateListener.java +++ b/server/src/com/cloud/storage/listener/SnapshotStateListener.java @@ -17,24 +17,24 @@ package com.cloud.storage.listener; -import com.cloud.event.EventCategory; -import com.cloud.storage.Snapshot; -import com.cloud.storage.Snapshot.Event; -import com.cloud.storage.Snapshot.State; -import com.cloud.server.ManagementServer; -import com.cloud.utils.fsm.StateListener; - -import org.apache.cloudstack.framework.events.EventBus; -import org.apache.cloudstack.framework.events.EventBusException; -import org.apache.log4j.Logger; - -import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; -public class SnapshotStateListener implements StateListener { +import org.apache.cloudstack.framework.events.EventBus; +import org.apache.cloudstack.framework.events.EventBusException; +import org.apache.log4j.Logger; + +import com.cloud.event.EventCategory; +import com.cloud.server.ManagementServer; +import com.cloud.storage.Snapshot; +import com.cloud.storage.Snapshot.Event; +import com.cloud.storage.Snapshot.State; +import com.cloud.storage.SnapshotVO; +import com.cloud.utils.fsm.StateListener; + +public class SnapshotStateListener implements StateListener { // get the event bus provider if configured @Inject protected EventBus _eventBus; @@ -46,13 +46,13 @@ public class SnapshotStateListener implements StateListener listSnapsforPolicy(long policyId, Filter filter); - */ - /** - * List all policies which are assigned to the specified volume - */ - List listPoliciesforVolume(long volumeId); - - /** - * List all policies to which a specified snapshot belongs. For ex: A snapshot may belong to a hourly snapshot and a daily - * snapshot run at the same time - */ - /* - * List listPoliciesforSnapshot(long snapshotId); - */ - /** - * List all snapshots for a specified volume irrespective of the policy which created the snapshot - */ - List listSnapsforVolume(long volumeId); - void deletePoliciesForVolume(Long volumeId); /** @@ -108,35 +55,20 @@ public interface SnapshotManager { * The account which is to be deleted. */ boolean deleteSnapshotDirsForAccount(long accountId); - - SnapshotPolicyVO getPolicyForVolume(long volumeId); - - boolean destroySnapshotBackUp(long snapshotId); - - /** - * Create a snapshot of a volume - * - * @param cmd - * the API command wrapping the parameters for creating the snapshot (mainly volumeId) - * @return the Snapshot that was created - */ - SnapshotVO createSnapshotOnPrimary(VolumeVO volume, Long polocyId, Long snapshotId) throws ResourceAllocationException; - - List listPoliciesforSnapshot(long snapshotId); - - List listSnapsforPolicy(long policyId, Filter filter); - + void downloadSnapshotsFromSwift(SnapshotVO ss); void downloadSnapshotsFromS3(SnapshotVO snapshot); - HostVO getSecondaryStorageHost(SnapshotVO snapshot); - String getSecondaryStorageURL(SnapshotVO snapshot); - void deleteSnapshotsForVolume (String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId ); - void deleteSnapshotsDirForVolume(String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId); - boolean canOperateOnVolume(VolumeVO volume); + boolean canOperateOnVolume(Volume volume); + + Answer sendToPool(Volume vol, Command cmd); + + SnapshotVO getParentSnapshot(VolumeInfo volume, Snapshot snapshot); + + Snapshot backupSnapshot(Long snapshotId); } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index c7beff08684..ed48bd1b45b 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -28,12 +28,26 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd; +import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd; +import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd; import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; -import com.cloud.agent.api.*; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.DeleteSnapshotBackupCommand; +import com.cloud.agent.api.DeleteSnapshotsDirCommand; +import com.cloud.agent.api.DownloadSnapshotFromS3Command; +import com.cloud.agent.api.downloadSnapshotFromSwiftCommand; import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.SwiftTO; import com.cloud.alert.AlertManager; @@ -46,9 +60,12 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.dao.DomainDao; -import com.cloud.event.*; +import com.cloud.event.ActionEvent; +import com.cloud.event.ActionEventUtils; +import com.cloud.event.EventTypes; +import com.cloud.event.EventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; -import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; @@ -58,43 +75,55 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Grouping; import com.cloud.projects.Project.ListProjectResourcesCriteria; -import com.cloud.resource.ResourceManager; import com.cloud.server.ResourceTag.TaggedResourceType; -import com.cloud.storage.*; +import com.cloud.storage.Snapshot; import com.cloud.storage.Snapshot.Type; -import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.storage.dao.*; -import com.cloud.storage.listener.SnapshotStateListener; +import com.cloud.storage.SnapshotPolicyVO; +import com.cloud.storage.SnapshotScheduleVO; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotPolicyDao; +import com.cloud.storage.dao.SnapshotScheduleDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; -import com.cloud.user.*; +import com.cloud.template.TemplateManager; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.DomainManager; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.User; +import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.utils.DateUtil; import com.cloud.utils.DateUtil.IntervalType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; - -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.*; 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.dao.UserVmDao; + import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd; import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd; import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd; @@ -104,6 +133,9 @@ import org.apache.log4j.Logger; import javax.ejb.Local; import javax.naming.ConfigurationException; import java.util.*; +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; + @Component @Local(value = { SnapshotManager.class, SnapshotService.class }) @@ -148,8 +180,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, @Inject protected ClusterDao _clusterDao; @Inject - private UsageEventDao _usageEventDao; - @Inject private ResourceLimitService _resourceLimitMgr; @Inject private SwiftManager _swiftMgr; @@ -158,31 +188,34 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, @Inject private SecondaryStorageVmManager _ssvmMgr; @Inject - private ResourceManager _resourceMgr; - @Inject private DomainManager _domainMgr; @Inject - private VolumeDao _volumeDao; - @Inject private ResourceTagDao _resourceTagDao; @Inject private ConfigurationDao _configDao; + + @Inject + private VMSnapshotDao _vmSnapshotDao; + String _name; + + @Inject TemplateManager templateMgr; + @Inject VolumeManager volumeMgr; + @Inject DataStoreManager dataStoreMgr; + @Inject List snapshotStrategies; + @Inject VolumeDataFactory volFactory; + @Inject SnapshotDataFactory snapshotFactory; + private int _totalRetries; private int _pauseInterval; - private int _deltaSnapshotMax; private int _backupsnapshotwait; - private StateMachine2 _snapshotFsm; - protected SearchBuilder PolicySnapshotSearch; protected SearchBuilder PoliciesForSnapSearch; - - - protected Answer sendToPool(Volume vol, Command cmd) { - StoragePool pool = _storagePoolDao.findById(vol.getPoolId()); - + @Override + public Answer sendToPool(Volume vol, Command cmd) { + StoragePool pool = (StoragePool)dataStoreMgr.getPrimaryDataStore(vol.getPoolId()); long[] hostIdsToTryFirst = null; Long vmHostId = getHostIdForSnapshotOperation(vol); @@ -233,128 +266,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, return null; } - @Override - public SnapshotVO createSnapshotOnPrimary(VolumeVO volume, Long policyId, Long snapshotId) { - SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - if (snapshot == null) { - throw new CloudRuntimeException("Can not find snapshot " + snapshotId); - } - - try { - stateTransitTo(snapshot, Snapshot.Event.CreateRequested); - } catch (NoTransitionException nte) { - s_logger.debug("Failed to update snapshot state due to " + nte.getMessage()); - } - - // Send a ManageSnapshotCommand to the agent - String vmName = _storageMgr.getVmNameOnVolume(volume); - long volumeId = volume.getId(); - long preId = _snapshotDao.getLastSnapshot(volumeId, snapshotId); - - String preSnapshotPath = null; - SnapshotVO preSnapshotVO = null; - if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) { - preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId); - if (preSnapshotVO != null && preSnapshotVO.getBackupSnapshotId() != null) { - preSnapshotPath = preSnapshotVO.getPath(); - } - } - StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId()); - - // RBD volumes do not support snapshotting in the way CloudStack does it. - // For now we leave the snapshot feature disabled for RBD volumes - if (srcPool.getPoolType() == StoragePoolType.RBD) { - throw new CloudRuntimeException("RBD volumes do not support snapshotting"); - } - - ManageSnapshotCommand cmd = new ManageSnapshotCommand(snapshotId, volume.getPath(), srcPool, preSnapshotPath, snapshot.getName(), vmName); - - ManageSnapshotAnswer answer = (ManageSnapshotAnswer) sendToPool(volume, cmd); - // Update the snapshot in the database - if ((answer != null) && answer.getResult()) { - // The snapshot was successfully created - if (preSnapshotPath != null && preSnapshotPath.equals(answer.getSnapshotPath())) { - // empty snapshot - s_logger.debug("CreateSnapshot: this is empty snapshot "); - try { - snapshot.setPath(preSnapshotPath); - snapshot.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId()); - snapshot.setSwiftId(preSnapshotVO.getSwiftId()); - snapshot.setPrevSnapshotId(preId); - snapshot.setSecHostId(preSnapshotVO.getSecHostId()); - stateTransitTo(snapshot, Snapshot.Event.OperationNotPerformed); - } catch (NoTransitionException nte) { - s_logger.debug("CreateSnapshot: failed to update state of snapshot due to " + nte.getMessage()); - } - } else { - long preSnapshotId = 0; - - if (preSnapshotVO != null && preSnapshotVO.getBackupSnapshotId() != null) { - preSnapshotId = preId; - // default delta snap number is 16 - int deltaSnap = _deltaSnapshotMax; - - int i; - for (i = 1; i < deltaSnap; i++) { - String prevBackupUuid = preSnapshotVO.getBackupSnapshotId(); - // previous snapshot doesn't have backup, create a full snapshot - if (prevBackupUuid == null) { - preSnapshotId = 0; - break; - } - long preSSId = preSnapshotVO.getPrevSnapshotId(); - if (preSSId == 0) { - break; - } - preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preSSId); - } - if (i >= deltaSnap) { - preSnapshotId = 0; - } - } - - //If the volume is moved around, backup a full snapshot to secondary storage - if (volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId())) { - preSnapshotId = 0; - volume.setLastPoolId(volume.getPoolId()); - _volumeDao.update(volume.getId(), volume); - } - snapshot = updateDBOnCreate(snapshotId, answer.getSnapshotPath(), preSnapshotId); - } - // Get the snapshot_schedule table entry for this snapshot and - // policy id. - // Set the snapshotId to retrieve it back later. - if (policyId != Snapshot.MANUAL_POLICY_ID) { - SnapshotScheduleVO snapshotSchedule = _snapshotScheduleDao.getCurrentSchedule(volumeId, policyId, true); - assert snapshotSchedule != null; - snapshotSchedule.setSnapshotId(snapshotId); - _snapshotScheduleDao.update(snapshotSchedule.getId(), snapshotSchedule); - } - - } else { - if (answer != null) { - s_logger.error(answer.getDetails()); - } - try { - stateTransitTo(snapshot, Snapshot.Event.OperationFailed); - } catch (NoTransitionException nte) { - s_logger.debug("Failed to update snapshot state due to " + nte.getMessage()); - } - throw new CloudRuntimeException("Creating snapshot for volume " + volumeId + " on primary storage failed."); - } - - return snapshot; - } - - public SnapshotVO createSnapshotImpl(long volumeId, long policyId) throws ResourceAllocationException { - return null; - } - @Override @DB @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "creating snapshot", async = true) - public SnapshotVO createSnapshot(Long volumeId, Long policyId, Long snapshotId, Account snapshotOwner) { - VolumeVO volume = _volsDao.findById(volumeId); + public Snapshot createSnapshot(Long volumeId, Long policyId, Long snapshotId, Account snapshotOwner) { + VolumeInfo volume = this.volFactory.getVolume(volumeId); if (volume == null) { throw new InvalidParameterValueException("No such volume exist"); } @@ -363,113 +279,50 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, throw new InvalidParameterValueException("Volume is not in ready state"); } - SnapshotVO snapshot = null; + SnapshotInfo snapshot = null; boolean backedUp = false; - UserVmVO uservm = null; // does the caller have the authority to act on this volume _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, volume); + + SnapshotInfo snap = this.snapshotFactory.getSnapshot(snapshotId); + SnapshotStrategy strategy = null; + for (SnapshotStrategy st : snapshotStrategies) { + if (st.canHandle(snap)) { + strategy = st; + break; + } + } + try { - - Long poolId = volume.getPoolId(); - if (poolId == null) { - throw new CloudRuntimeException("You cannot take a snapshot of a volume until it has been attached to an instance"); - } - - if (_volsDao.getHypervisorType(volume.getId()).equals(HypervisorType.KVM)) { - uservm = _vmDao.findById(volume.getInstanceId()); - if (uservm != null && uservm.getType() != VirtualMachine.Type.User) { - throw new CloudRuntimeException("Can't take a snapshot on system vm "); - } - - StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); - ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId()); - List hosts = _resourceMgr.listAllHostsInCluster(cluster.getId()); - if (hosts != null && !hosts.isEmpty()) { - HostVO host = hosts.get(0); - if (!hostSupportSnapsthot(host)) { - throw new CloudRuntimeException("KVM Snapshot is not supported on cluster: " + host.getId()); - } - } - } - - // if volume is attached to a vm in destroyed or expunging state; disallow - if (volume.getInstanceId() != null) { - UserVmVO userVm = _vmDao.findById(volume.getInstanceId()); - if (userVm != null) { - if (userVm.getState().equals(State.Destroyed) || userVm.getState().equals(State.Expunging)) { - throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " is associated with vm:" + userVm.getInstanceName() + " is in " - + userVm.getState().toString() + " state"); - } - - if(userVm.getHypervisorType() == HypervisorType.VMware || userVm.getHypervisorType() == HypervisorType.KVM) { - List activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp); - 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"); - } - } - } - - snapshot = createSnapshotOnPrimary(volume, policyId, snapshotId); - if (snapshot != null) { - if (snapshot.getState() == Snapshot.State.CreatedOnPrimary) { - backedUp = backupSnapshotToSecondaryStorage(snapshot); - } else if (snapshot.getState() == Snapshot.State.BackedUp) { - // For empty snapshot we set status to BackedUp in createSnapshotOnPrimary - backedUp = true; - } else { - throw new CloudRuntimeException("Failed to create snapshot: " + snapshot + " on primary storage"); - } - if (!backedUp) { - throw new CloudRuntimeException("Created snapshot: " + snapshot + " on primary but failed to backup on secondary"); - } - } else { - throw new CloudRuntimeException("Failed to create snapshot: " + snapshot + " on primary storage"); - } - } finally { - // Cleanup jobs to do after the snapshot has been created; decrement resource count - if (snapshot != null) { - postCreateSnapshot(volumeId, snapshot.getId(), policyId, backedUp); - //Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event - SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId()); - if ((freshSnapshot != null) && backedUp) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), - snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, - volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid()); - } - if( !backedUp ) { - - } else { - _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot); - } - } - - /* - try { - _storageMgr.stateTransitTo(volume, Volume.Event.OperationSucceeded); - } catch (NoTransitionException e) { - s_logger.debug("Failed to transit volume state: " + e.toString()); - }*/ + snapshot = strategy.takeSnapshot(volume, snapshotId); + if (snapshot != null) { + postCreateSnapshot(volumeId, snapshot.getId(), policyId); + //Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event + SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId()); + if ((freshSnapshot != null) && backedUp) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), + snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, + volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid()); + } + _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot); + } + + Boolean backup = Boolean.parseBoolean(this._configDao.getValue(Config.BackupSnapshotAferTakingSnapshot.toString())); + if (backup) { + this.backupSnapshot(snapshotId); + } + } catch(Exception e) { + s_logger.debug("Failed to create snapshot", e); + throw new CloudRuntimeException("Failed to create snapshot", e); } return snapshot; } - private SnapshotVO updateDBOnCreate(Long id, String snapshotPath, long preSnapshotId) { - SnapshotVO createdSnapshot = _snapshotDao.findByIdIncludingRemoved(id); - createdSnapshot.setPath(snapshotPath); - createdSnapshot.setPrevSnapshotId(preSnapshotId); - try { - stateTransitTo(createdSnapshot, Snapshot.Event.OperationSucceeded); - } catch (NoTransitionException nte) { - s_logger.debug("Faile to update state of snapshot due to " + nte.getMessage()); - } - return createdSnapshot; - } - - private static void checkObjectStorageConfiguration(SwiftTO swift, S3TO s3) { + private void checkObjectStorageConfiguration(SwiftTO swift, S3TO s3) { if (swift != null && s3 != null) { throw new CloudRuntimeException( @@ -478,26 +331,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } - @Override - public void deleteSnapshotsForVolume (String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId ){ - SwiftTO swift = _swiftMgr.getSwiftTO(); - S3TO s3 = _s3Mgr.getS3TO(); - - checkObjectStorageConfiguration(swift, s3); - - DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand( - swift, s3, secondaryStoragePoolUrl, dcId, accountId, volumeId, - null, true); - try { - Answer ans = _agentMgr.sendToSSVM(dcId, cmd); - if ( ans == null || !ans.getResult() ) { - s_logger.warn("DeleteSnapshotBackupCommand failed due to " + ans.getDetails() + " volume id: " + volumeId); - } - } catch (Exception e) { - s_logger.warn("DeleteSnapshotBackupCommand failed due to" + e.toString() + " volume id: " + volumeId); - } - } - @Override public void deleteSnapshotsDirForVolume(String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId) { DeleteSnapshotsDirCommand cmd = new DeleteSnapshotsDirCommand(secondaryStoragePoolUrl, dcId, accountId, volumeId); @@ -511,6 +344,27 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } } + @Override + public Snapshot backupSnapshot(Long snapshotId) { + SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotId); + if (snapshot == null) { + throw new CloudRuntimeException("Can't find snapshot:" + snapshotId); + } + + if (snapshot.getState() == Snapshot.State.BackedUp) { + return snapshot; + } + + SnapshotStrategy strategy = null; + for (SnapshotStrategy st : snapshotStrategies) { + if (st.canHandle(snapshot)) { + strategy = st; + break; + } + } + + return strategy.backupSnapshot(snapshot); + } @Override public void downloadSnapshotsFromSwift(SnapshotVO ss) { @@ -518,7 +372,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, VolumeVO volume = _volsDao.findById(volumeId); Long dcId = volume.getDataCenterId(); Long accountId = volume.getAccountId(); - HostVO secHost = _storageMgr.getSecondaryStorageHost(dcId); + HostVO secHost = this.templateMgr.getSecondaryStorageHost(dcId); String secondaryStoragePoolUrl = secHost.getStorageUrl(); Long swiftId = ss.getSwiftId(); @@ -569,7 +423,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, final VolumeVO volume = _volsDao.findById(snapshot.getVolumeId()); final Long zoneId = volume.getDataCenterId(); - final HostVO secHost = _storageMgr.getSecondaryStorageHost(zoneId); + final HostVO secHost = this.templateMgr.getSecondaryStorageHost(zoneId); final S3TO s3 = _s3Mgr.getS3TO(snapshot.getS3Id()); final List backupUuids = determineBackupUuids(snapshot); @@ -597,133 +451,17 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } } - + @Override - @DB - public boolean backupSnapshotToSecondaryStorage(SnapshotVO ss) { - long snapshotId = ss.getId(); - SnapshotVO snapshot = _snapshotDao.acquireInLockTable(snapshotId); - if (snapshot == null) { - throw new CloudRuntimeException("Can not acquire lock for snapshot: " + ss); - } - try { - try { - stateTransitTo(snapshot, Snapshot.Event.BackupToSecondary); - } catch (NoTransitionException nte) { - s_logger.debug("Failed to update the state of snapshot while backing up snapshot"); - } + public SnapshotVO getParentSnapshot(VolumeInfo volume, Snapshot snapshot) { + long preId = _snapshotDao.getLastSnapshot(volume.getId(), snapshot.getId()); - long volumeId = snapshot.getVolumeId(); - VolumeVO volume = _volsDao.lockRow(volumeId, true); - - Long dcId = volume.getDataCenterId(); - Long accountId = volume.getAccountId(); - - HostVO secHost = getSecHost(volumeId, volume.getDataCenterId()); - - String secondaryStoragePoolUrl = secHost.getStorageUrl(); - String snapshotUuid = snapshot.getPath(); - // In order to verify that the snapshot is not empty, - // we check if the parent of the snapshot is not the same as the parent of the previous snapshot. - // We pass the uuid of the previous snapshot to the plugin to verify this. - SnapshotVO prevSnapshot = null; - String prevSnapshotUuid = null; - String prevBackupUuid = null; - - - SwiftTO swift = _swiftMgr.getSwiftTO(); - S3TO s3 = _s3Mgr.getS3TO(); - - checkObjectStorageConfiguration(swift, s3); - - long prevSnapshotId = snapshot.getPrevSnapshotId(); - if (prevSnapshotId > 0) { - prevSnapshot = _snapshotDao.findByIdIncludingRemoved(prevSnapshotId); - if ( prevSnapshot.getBackupSnapshotId() != null && swift == null) { - if (prevSnapshot.getVersion() != null && prevSnapshot.getVersion().equals("2.2")) { - prevBackupUuid = prevSnapshot.getBackupSnapshotId(); - prevSnapshotUuid = prevSnapshot.getPath(); - } - } else if ((prevSnapshot.getSwiftId() != null && swift != null) - || (prevSnapshot.getS3Id() != null && s3 != null)) { - prevBackupUuid = prevSnapshot.getBackupSnapshotId(); - prevSnapshotUuid = prevSnapshot.getPath(); - } - } - boolean isVolumeInactive = _storageMgr.volumeInactive(volume); - String vmName = _storageMgr.getVmNameOnVolume(volume); - StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId()); - BackupSnapshotCommand backupSnapshotCommand = new BackupSnapshotCommand(secondaryStoragePoolUrl, dcId, accountId, volumeId, snapshot.getId(), volume.getPath(), srcPool, snapshotUuid, - snapshot.getName(), prevSnapshotUuid, prevBackupUuid, isVolumeInactive, vmName, _backupsnapshotwait); - - if ( swift != null ) { - backupSnapshotCommand.setSwift(swift); - } else if (s3 != null) { - backupSnapshotCommand.setS3(s3); - } - - String backedUpSnapshotUuid = null; - // By default, assume failed. - boolean backedUp = false; - BackupSnapshotAnswer answer = (BackupSnapshotAnswer) sendToPool(volume, backupSnapshotCommand); - if (answer != null && answer.getResult()) { - backedUpSnapshotUuid = answer.getBackupSnapshotName(); - if (backedUpSnapshotUuid != null) { - backedUp = true; - } - } else if (answer != null) { - s_logger.error(answer.getDetails()); - } - // Update the status in all cases. - Transaction txn = Transaction.currentTxn(); - txn.start(); - - if (backedUp) { - if (backupSnapshotCommand.getSwift() != null ) { - snapshot.setSwiftId(swift.getId()); - snapshot.setBackupSnapshotId(backedUpSnapshotUuid); - } else if (backupSnapshotCommand.getS3() != null) { - snapshot.setS3Id(s3.getId()); - snapshot.setBackupSnapshotId(backedUpSnapshotUuid); - } else { - snapshot.setSecHostId(secHost.getId()); - snapshot.setBackupSnapshotId(backedUpSnapshotUuid); - } - if (answer.isFull()) { - snapshot.setPrevSnapshotId(0); - } - try { - stateTransitTo(snapshot, Snapshot.Event.OperationSucceeded); - } catch (NoTransitionException nte) { - s_logger.debug("Failed to update the state of snapshot while backing up snapshot"); - } - - } else { - try { - stateTransitTo(snapshot, Snapshot.Event.OperationFailed); - } catch (NoTransitionException nte) { - s_logger.debug("Failed to update the state of snapshot while backing up snapshot"); - } - s_logger.warn("Failed to back up snapshot on secondary storage, deleting the record from the DB"); - _snapshotDao.remove(snapshotId); - } - txn.commit(); - - return backedUp; - } finally { - if (snapshot != null) { - _snapshotDao.releaseFromLockTable(snapshotId); - } - } - - } - - private HostVO getSecHost(long volumeId, long dcId) { - Long id = _snapshotDao.getSecHostId(volumeId); - if ( id != null) { - return _hostDao.findById(id); - } - return _storageMgr.getSecondaryStorageHost(dcId); + SnapshotVO preSnapshotVO = null; + if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) { + preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId); + } + + return preSnapshotVO; } private Long getSnapshotUserId() { @@ -734,11 +472,15 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, return userId; } - @Override - @DB - public void postCreateSnapshot(Long volumeId, Long snapshotId, Long policyId, boolean backedUp) { + private void postCreateSnapshot(Long volumeId, Long snapshotId, Long policyId) { Long userId = getSnapshotUserId(); SnapshotVO snapshot = _snapshotDao.findById(snapshotId); + if (policyId != Snapshot.MANUAL_POLICY_ID) { + SnapshotScheduleVO snapshotSchedule = _snapshotScheduleDao.getCurrentSchedule(volumeId, policyId, true); + assert snapshotSchedule != null; + snapshotSchedule.setSnapshotId(snapshotId); + _snapshotScheduleDao.update(snapshotSchedule.getId(), snapshotSchedule); + } if (snapshot != null && snapshot.isRecursive()) { postCreateRecurringSnapshotForPolicy(userId, volumeId, snapshotId, policyId); @@ -748,7 +490,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, private void postCreateRecurringSnapshotForPolicy(long userId, long volumeId, long snapshotId, long policyId) { // Use count query SnapshotVO spstVO = _snapshotDao.findById(snapshotId); - Type type = spstVO.getType(); + Type type = spstVO.getRecurringType(); int maxSnaps = type.getMax(); List snaps = listSnapsforVolumeType(volumeId, type); @@ -760,7 +502,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, SnapshotVO oldestSnapshot = snaps.get(0); long oldSnapId = oldestSnapshot.getId(); s_logger.debug("Max snaps: " + policy.getMaxSnaps() + " exceeded for snapshot policy with Id: " + policyId + ". Deleting oldest snapshot: " + oldSnapId); - if(deleteSnapshotInternal(oldSnapId)){ + if(deleteSnapshot(oldSnapId)){ //log Snapshot delete event ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, oldestSnapshot.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_SNAPSHOT_DELETE, "Successfully deleted oldest snapshot: " + oldSnapId, 0); } @@ -775,104 +517,44 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, Account caller = UserContext.current().getCaller(); // Verify parameters - Snapshot snapshotCheck = _snapshotDao.findById(snapshotId); + SnapshotInfo snapshotCheck = this.snapshotFactory.getSnapshot(snapshotId); if (snapshotCheck == null) { throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId); } _accountMgr.checkAccess(caller, null, true, snapshotCheck); - if( !Snapshot.State.BackedUp.equals(snapshotCheck.getState() ) ) { - throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status"); + SnapshotStrategy strategy = null; + for (SnapshotStrategy st : snapshotStrategies) { + if (st.canHandle(snapshotCheck)) { + strategy = st; + break; + } + } + try { + boolean result = strategy.deleteSnapshot(snapshotCheck); + if (result) { + if (snapshotCheck.getState() == Snapshot.State.BackedUp) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(), + snapshotCheck.getDataCenterId(), snapshotId, snapshotCheck.getName(), null, null, 0L, + snapshotCheck.getClass().getName(), snapshotCheck.getUuid()); + } + _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot); + } + return result; + } catch (Exception e) { + s_logger.debug("Failed to delete snapshot: " + snapshotCheck.getId() + ":" + e.toString()); + throw new CloudRuntimeException("Failed to delete snapshot:" + e.toString()); } - - return deleteSnapshotInternal(snapshotId); } - @DB - private boolean deleteSnapshotInternal(Long snapshotId) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId); - } - SnapshotVO lastSnapshot = null; - SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - if (snapshot.getBackupSnapshotId() != null) { - List snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId()); - if (snaps != null && snaps.size() > 1) { - snapshot.setBackupSnapshotId(null); - _snapshotDao.update(snapshot.getId(), snapshot); - } - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - _snapshotDao.remove(snapshotId); - if (snapshot.getState() == Snapshot.State.BackedUp) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), - snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, 0L, - snapshot.getClass().getName(), snapshot.getUuid()); - } - _resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.snapshot); - txn.commit(); - - long lastId = snapshotId; - boolean destroy = false; - while (true) { - lastSnapshot = _snapshotDao.findNextSnapshot(lastId); - if (lastSnapshot == null) { - // if all snapshots after this snapshot in this chain are removed, remove those snapshots. - destroy = true; - break; - } - if (lastSnapshot.getRemoved() == null) { - // if there is one child not removed, then can not remove back up snapshot. - break; - } - lastId = lastSnapshot.getId(); - } - if (destroy) { - lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId); - while (lastSnapshot.getRemoved() != null) { - String BackupSnapshotId = lastSnapshot.getBackupSnapshotId(); - if (BackupSnapshotId != null) { - List snaps = _snapshotDao.listByBackupUuid(lastSnapshot.getVolumeId(), BackupSnapshotId); - if (snaps != null && snaps.size() > 1) { - lastSnapshot.setBackupSnapshotId(null); - _snapshotDao.update(lastSnapshot.getId(), lastSnapshot); - } else { - if (destroySnapshotBackUp(lastId)) { - - } else { - s_logger.debug("Destroying snapshot backup failed " + lastSnapshot); - break; - } - } - } - lastId = lastSnapshot.getPrevSnapshotId(); - if (lastId == 0) { - break; - } - lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId); - } - } - return true; - } - - @Override - @DB - public boolean destroySnapshot(long userId, long snapshotId, long policyId) { - return true; - } - - - @Override - public HostVO getSecondaryStorageHost(SnapshotVO snapshot) { + private HostVO getSecondaryStorageHost(SnapshotVO snapshot) { HostVO secHost = null; if( snapshot.getSwiftId() == null || snapshot.getSwiftId() == 0) { secHost = _hostDao.findById(snapshot.getSecHostId()); } else { Long dcId = snapshot.getDataCenterId(); - secHost = _storageMgr.getSecondaryStorageHost(dcId); + secHost = this.templateMgr.getSecondaryStorageHost(dcId); } return secHost; } @@ -886,51 +568,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, throw new CloudRuntimeException("Can not find secondary storage"); } - @Override - @DB - public boolean destroySnapshotBackUp(long snapshotId) { - boolean success = false; - String details; - SnapshotVO snapshot = _snapshotDao.findByIdIncludingRemoved(snapshotId); - if (snapshot == null) { - throw new CloudRuntimeException("Destroying snapshot " + snapshotId + " backup failed due to unable to find snapshot "); - } - String secondaryStoragePoolUrl = getSecondaryStorageURL(snapshot); - Long dcId = snapshot.getDataCenterId(); - Long accountId = snapshot.getAccountId(); - Long volumeId = snapshot.getVolumeId(); - - String backupOfSnapshot = snapshot.getBackupSnapshotId(); - if (backupOfSnapshot == null) { - return true; - } - SwiftTO swift = _swiftMgr.getSwiftTO(snapshot.getSwiftId()); - S3TO s3 = _s3Mgr.getS3TO(); - - checkObjectStorageConfiguration(swift, s3); - - DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand( - swift, s3, secondaryStoragePoolUrl, dcId, accountId, volumeId, - backupOfSnapshot, false); - Answer answer = _agentMgr.sendToSSVM(dcId, cmd); - - if ((answer != null) && answer.getResult()) { - snapshot.setBackupSnapshotId(null); - _snapshotDao.update(snapshotId, snapshot); - success = true; - details = "Successfully deleted snapshot " + snapshotId + " for volumeId: " + volumeId; - s_logger.debug(details); - } else if (answer != null) { - details = "Failed to destroy snapshot id:" + snapshotId + " for volume: " + volumeId + " due to "; - if (answer.getDetails() != null) { - details += answer.getDetails(); - } - s_logger.error(details); - } - return success; - - } - @Override public Pair, Integer> listSnapshots(ListSnapshotsCmd cmd) { Long volumeId = cmd.getVolumeId(); @@ -1106,7 +743,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, List snapshots = listSnapsforVolume(volumeId); for (SnapshotVO snapshot : snapshots) { if (_snapshotDao.expunge(snapshot.getId())) { - if (snapshot.getType() == Type.MANUAL) { + if (snapshot.getRecurringType() == Type.MANUAL) { _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.snapshot); } @@ -1216,8 +853,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, return policy; } - @Override - public boolean deletePolicy(long userId, Long policyId) { + protected boolean deletePolicy(long userId, Long policyId) { SnapshotPolicyVO snapshotPolicy = _snapshotPolicyDao.findById(policyId); _snapSchedMgr.removeSchedule(snapshotPolicy.getVolumeId(), snapshotPolicy.getId()); return _snapshotPolicyDao.remove(policyId); @@ -1235,31 +871,16 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, return new Pair, Integer>(result.first(), result.second()); } - @Override - public List listPoliciesforVolume(long volumeId) { + + private List listPoliciesforVolume(long volumeId) { return _snapshotPolicyDao.listByVolumeId(volumeId); } - - @Override - public List listPoliciesforSnapshot(long snapshotId) { - SearchCriteria sc = PoliciesForSnapSearch.create(); - sc.setJoinParameters("policyRef", "snapshotId", snapshotId); - return _snapshotPolicyDao.search(sc, null); - } - - @Override - public List listSnapsforPolicy(long policyId, Filter filter) { - SearchCriteria sc = PolicySnapshotSearch.create(); - sc.setJoinParameters("policy", "policyId", policyId); - return _snapshotDao.search(sc, filter); - } - - @Override - public List listSnapsforVolume(long volumeId) { + + private List listSnapsforVolume(long volumeId) { return _snapshotDao.listByVolumeId(volumeId); } - public List listSnapsforVolumeType(long volumeId, Type type) { + private List listSnapsforVolumeType(long volumeId, Type type) { return _snapshotDao.listByVolumeIdType(volumeId, type); } @@ -1278,9 +899,6 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } } - /** - * {@inheritDoc} - */ @Override public List findRecurringSnapshotSchedule(ListRecurringSnapshotScheduleCmd cmd) { Long volumeId = cmd.getVolumeId(); @@ -1319,12 +937,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, return snapshotSchedules; } - @Override - public SnapshotPolicyVO getPolicyForVolume(long volumeId) { - return _snapshotPolicyDao.findOneByVolume(volumeId); - } - - public Type getSnapshotType(Long policyId) { + private Type getSnapshotType(Long policyId) { if (policyId.equals(Snapshot.MANUAL_POLICY_ID)) { return Type.MANUAL; } else { @@ -1334,7 +947,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } } - public Type getSnapshotType(IntervalType intvType) { + private Type getSnapshotType(IntervalType intvType) { if (intvType.equals(IntervalType.HOURLY)) { return Type.HOURLY; } else if (intvType.equals(IntervalType.DAILY)) { @@ -1434,15 +1047,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, Type.DAILY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.daily"), DAILYMAX)); Type.WEEKLY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.weekly"), WEEKLYMAX)); Type.MONTHLY.setMax(NumbersUtil.parseInt(_configDao.getValue("snapshot.max.monthly"), MONTHLYMAX)); - _deltaSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("snapshot.delta.max"), DELTAMAX); _totalRetries = NumbersUtil.parseInt(_configDao.getValue("total.retries"), 4); _pauseInterval = 2 * NumbersUtil.parseInt(_configDao.getValue("ping.interval"), 60); s_logger.info("Snapshot Manager is configured."); - _snapshotFsm = Snapshot.State.getStateMachine(); - _snapshotFsm.registerListener(new SnapshotStateListener()); - return true; } @@ -1503,27 +1112,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, return success; } - - private boolean hostSupportSnapsthot(HostVO host) { - if (host.getHypervisorType() != HypervisorType.KVM) { - return true; - } - // Determine host capabilities - String caps = host.getCapabilities(); - - if (caps != null) { - String[] tokens = caps.split(","); - for (String token : tokens) { - if (token.contains("snapshot")) { - return true; - } - } - } - return false; - } @Override - public boolean canOperateOnVolume(VolumeVO volume) { + public boolean canOperateOnVolume(Volume volume) { List snapshots = _snapshotDao.listByStatus(volume.getId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp); if (snapshots.size() > 0) { @@ -1531,8 +1122,4 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } return true; } - - protected boolean stateTransitTo(Snapshot snapshot, Snapshot.Event e) throws NoTransitionException { - return _snapshotFsm.transitTo(snapshot, e, null, _snapshotDao); - } } diff --git a/server/src/com/cloud/storage/upload/UploadMonitor.java b/server/src/com/cloud/storage/upload/UploadMonitor.java index aada1f43c41..1c3590e91e2 100755 --- a/server/src/com/cloud/storage/upload/UploadMonitor.java +++ b/server/src/com/cloud/storage/upload/UploadMonitor.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.storage.upload; + import com.cloud.async.AsyncJobManager; import com.cloud.host.HostVO; import com.cloud.storage.Upload.Mode; diff --git a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java index e44343dda8e..06756b617eb 100644 --- a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java +++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java @@ -73,6 +73,7 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.uuididentity.dao.IdentityDao; import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component @@ -121,6 +122,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso VpcDao _vpcDao; @Inject StaticRouteDao _staticRouteDao; + @Inject + VMSnapshotDao _vmSnapshotDao; @Override public boolean configure(String name, Map params) throws ConfigurationException { @@ -139,6 +142,7 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso _daoMap.put(TaggedResourceType.Vpc, _vpcDao); _daoMap.put(TaggedResourceType.NetworkACL, _firewallDao); _daoMap.put(TaggedResourceType.StaticRoute, _staticRouteDao); + _daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao); return true; } diff --git a/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java b/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java index 97639564967..a8e1393d6da 100644 --- a/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java +++ b/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java @@ -17,6 +17,7 @@ package com.cloud.tags.dao; import java.util.List; + import javax.ejb.Local; import org.springframework.stereotype.Component; diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index b93d7e5ba42..142642193b6 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -22,12 +22,22 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.List; +import java.util.concurrent.ExecutionException; import javax.ejb.Local; import javax.inject.Inject; import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; +import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -43,9 +53,9 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.host.HostVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.TemplateProfile; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.TemplateProfile; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.download.DownloadMonitor; @@ -53,6 +63,8 @@ import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.user.Account; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.UserVmVO; + import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; @@ -70,6 +82,16 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase implements Te @Inject SecondaryStorageVmManager _ssvmMgr; @Inject AgentManager _agentMgr; + @Inject DataStoreManager storeMgr; + @Inject ImageService imageService; + @Inject ImageDataFactory imageFactory; + @Inject TemplateManager templateMgr; + + @Override + public String getName() { + return TemplateAdapterType.Hypervisor.getName(); + } + private String validateUrl(String url) { try { URI uri = new URI(url); @@ -149,7 +171,18 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase implements Te throw new CloudRuntimeException("Unable to persist the template " + profile.getTemplate()); } - _downloadMonitor.downloadTemplateToStorage(template, profile.getZoneId()); + DataStore imageStore = this.storeMgr.getDataStore(profile.getImageStoreId(), DataStoreRole.Image); + + AsyncCallFuture future = this.imageService.createTemplateAsync(this.imageFactory.getTemplate(template.getId()), imageStore); + try { + future.get(); + } catch (InterruptedException e) { + s_logger.debug("create template Failed", e); + throw new CloudRuntimeException("create template Failed", e); + } catch (ExecutionException e) { + s_logger.debug("create template Failed", e); + throw new CloudRuntimeException("create template Failed", e); + } _resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template); return template; @@ -215,6 +248,9 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase implements Te templateHostVO.setDestroyed(true); _tmpltHostDao.update(templateHostVO.getId(), templateHostVO); String installPath = templateHostVO.getInstallPath(); + List userVmUsingIso = _userVmDao.listByIsoId(templateId); + //check if there is any VM using this ISO. + if (userVmUsingIso == null || userVmUsingIso.isEmpty()) { if (installPath != null) { Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(), installPath)); @@ -226,6 +262,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase implements Te } } else { _tmpltHostDao.remove(templateHostVO.getId()); + } } VMTemplateZoneVO templateZone = _tmpltZoneDao.findByZoneTemplate(sZoneId, templateId); diff --git a/server/src/com/cloud/template/TemplateAdapter.java b/server/src/com/cloud/template/TemplateAdapter.java index 19cfef039de..1f8f491cb25 100755 --- a/server/src/com/cloud/template/TemplateAdapter.java +++ b/server/src/com/cloud/template/TemplateAdapter.java @@ -22,6 +22,7 @@ import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; + import com.cloud.exception.ResourceAllocationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.TemplateProfile; @@ -65,5 +66,5 @@ public interface TemplateAdapter extends Adapter { public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, - String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled) throws ResourceAllocationException; + String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid) throws ResourceAllocationException; } diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index fa677acdc5c..1b114250621 100755 --- a/server/src/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/com/cloud/template/TemplateAdapterBase.java @@ -20,16 +20,18 @@ import java.util.List; import java.util.Map; import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; -import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; -import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; -import org.apache.log4j.Logger; import org.apache.cloudstack.api.ApiConstants; -import com.cloud.api.ApiDBUtils; +import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; +import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.log4j.Logger; + +import com.cloud.api.ApiDBUtils; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenterVO; @@ -43,9 +45,9 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Grouping; import com.cloud.storage.GuestOS; -import com.cloud.storage.TemplateProfile; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.TemplateProfile; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; @@ -61,6 +63,7 @@ import com.cloud.utils.EnumUtils; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.UserVmVO; +import com.cloud.vm.dao.UserVmDao; public abstract class TemplateAdapterBase extends AdapterBase implements TemplateAdapter { private final static Logger s_logger = Logger.getLogger(TemplateAdapterBase.class); @@ -75,7 +78,10 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat protected @Inject VMTemplateZoneDao _tmpltZoneDao; protected @Inject UsageEventDao _usageEventDao; protected @Inject HostDao _hostDao; + protected @Inject UserVmDao _userVmDao; protected @Inject ResourceLimitService _resourceLimitMgr; + protected @Inject DataStoreManager storeMgr; + @Inject TemplateManager templateMgr; @Override public boolean stop() { @@ -94,16 +100,26 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, String accountName, Long domainId, String chksum, Boolean bootable, Map details) throws ResourceAllocationException { return prepare(isIso, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId, hypervisorType, - chksum, bootable, null, null, details, false); + chksum, bootable, null, null, details, false, null); } public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, - String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled) throws ResourceAllocationException { + String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled, + String imageStoreUuid) throws ResourceAllocationException { //Long accountId = null; // parameters verification + String storeUuid = imageStoreUuid; + if (storeUuid != null) { + DataStore store = this.storeMgr.getDataStore(storeUuid, DataStoreRole.Image); + if (store == null) { + throw new InvalidParameterValueException("invalide image store uuid" + storeUuid); + } + + } + if (isPublic == null) { isPublic = Boolean.FALSE; } @@ -197,10 +213,16 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat } } + DataStore imageStore = this.templateMgr.getImageStore(imageStoreUuid, zoneId); + if (imageStore == null) { + throw new IllegalArgumentException("Cann't find an image store"); + } + Long imageStoreId = imageStore.getId(); + Long id = _tmpltDao.getNextInSequence(Long.class, "id"); UserContext.current().setEventDetails("Id: " +id+ " name: " + name); return new TemplateProfile(id, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, - featured, isExtractable, imgfmt, guestOSId, zoneId, hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details, sshkeyEnabled); + featured, isExtractable, imgfmt, guestOSId, zoneId, hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details, sshkeyEnabled, imageStoreId); } @Override @@ -210,10 +232,12 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId()); _accountMgr.checkAccess(caller, null, true, owner); + + return prepare(false, UserContext.current().getCallerUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(), cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), cmd.getZoneId(), HypervisorType.getType(cmd.getHypervisor()), - cmd.getChecksum(), true, cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled()); + cmd.getChecksum(), true, cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), cmd.getImageStoreUuid()); } public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException { @@ -224,7 +248,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat return prepare(true, UserContext.current().getCallerUserId(), cmd.getIsoName(), cmd.getDisplayText(), 64, false, true, cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), ImageFormat.ISO.toString(), cmd.getOsTypeId(), - cmd.getZoneId(), HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null, owner, null, false); + cmd.getZoneId(), HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null, owner, null, false, cmd.getImageStoreUuid()); } protected VMTemplateVO persistTemplate(TemplateProfile profile) { @@ -234,7 +258,8 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat profile.getBits(), profile.getAccountId(), profile.getCheckSum(), profile.getDisplayText(), profile.getPasswordEnabled(), profile.getGuestOsId(), profile.getBootable(), profile.getHypervisorType(), profile.getTemplateTag(), profile.getDetails(), profile.getSshKeyEnabled()); - + + template.setImageDataStoreId(profile.getImageStoreId()); if (zoneId == null || zoneId.longValue() == -1) { List dcs = _dcDao.listAll(); diff --git a/server/src/com/cloud/template/TemplateManager.java b/server/src/com/cloud/template/TemplateManager.java index ad145a911bf..19ba3b52734 100755 --- a/server/src/com/cloud/template/TemplateManager.java +++ b/server/src/com/cloud/template/TemplateManager.java @@ -18,16 +18,19 @@ package com.cloud.template; import java.util.List; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.dc.DataCenterVO; import com.cloud.exception.InternalErrorException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; import com.cloud.host.HostVO; import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.utils.Pair; /** * TemplateManager manages the templates stored on secondary storage. It is responsible for creating private/public templates. @@ -91,4 +94,27 @@ public interface TemplateManager extends TemplateService{ VMTemplateHostVO prepareISOForCreate(VMTemplateVO template, StoragePool pool); + + VMTemplateHostVO findVmTemplateHost(long templateId, + StoragePool pool); + + Pair getAbsoluteIsoPath(long templateId, long dataCenterId); + + String getSecondaryStorageURL(long zoneId); + + HostVO getSecondaryStorageHost(long zoneId, long tmpltId); + + VMTemplateHostVO getTemplateHostRef(long zoneId, long tmpltId, + boolean readyOnly); + + HostVO getSecondaryStorageHost(long zoneId); + + List getSecondaryStorageHosts(long zoneId); + + Long getTemplateSize(long templateId, long zoneId); + + DataStore getImageStore(String storeUuid, Long zoneId); + + String getChecksum(Long hostId, String templatePath); + } diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index f9cf277842d..29659d3deee 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -26,6 +26,9 @@ import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -35,22 +38,50 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd; -import org.apache.cloudstack.api.command.user.iso.*; -import org.apache.cloudstack.api.command.user.template.*; +import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; +import org.apache.cloudstack.api.command.user.iso.ExtractIsoCmd; +import org.apache.cloudstack.api.command.user.iso.ListIsoPermissionsCmd; +import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.cloudstack.api.command.user.iso.UpdateIsoPermissionsCmd; +import org.apache.cloudstack.api.command.user.template.CopyTemplateCmd; +import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; +import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCmd; +import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.framework.async.AsyncCallFuture; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.acl.SecurityChecker.AccessType; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; +import com.cloud.agent.api.AttachIsoCommand; +import com.cloud.agent.api.ComputeChecksumCommand; import com.cloud.agent.api.downloadTemplateFromSwiftToSecondaryStorageCommand; +import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand; import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.to.SwiftTO; -import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand; + +import com.cloud.api.ApiDBUtils; import com.cloud.async.AsyncJobManager; import com.cloud.async.AsyncJobVO; import com.cloud.configuration.Config; @@ -64,12 +95,14 @@ import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; +import com.cloud.event.UsageEventVO; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; @@ -77,34 +110,72 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuruManager; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; -import com.cloud.storage.*; + +import com.cloud.resource.ResourceManager; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.LaunchPermissionVO; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; + import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.TemplateProfile; import com.cloud.storage.Upload; import com.cloud.storage.Upload.Type; + +import com.cloud.storage.UploadVO; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateS3VO; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.dao.*; +import com.cloud.storage.VMTemplateSwiftVO; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.LaunchPermissionDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.UploadDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateDetailsDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateS3Dao; +import com.cloud.storage.dao.VMTemplateSwiftDao; +import com.cloud.storage.dao.VMTemplateZoneDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.storage.upload.UploadMonitor; import com.cloud.template.TemplateAdapter.TemplateAdapterType; -import com.cloud.user.*; + +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountService; +import com.cloud.user.AccountVO; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.User; +import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserAccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.ManagerBase; - import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.*; import com.cloud.utils.exception.CloudRuntimeException; @@ -123,6 +194,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Inject VMTemplateHostDao _tmpltHostDao; @Inject VMTemplatePoolDao _tmpltPoolDao; @Inject VMTemplateZoneDao _tmpltZoneDao; + @Inject + protected VMTemplateDetailsDao _templateDetailsDao; @Inject VMInstanceDao _vmInstanceDao; @Inject StoragePoolDao _poolDao; @Inject StoragePoolHostDao _poolHostDao; @@ -153,6 +226,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, ClusterDao _clusterDao; @Inject DomainDao _domainDao; @Inject UploadDao _uploadDao; + @Inject + protected GuestOSDao _guestOSDao; long _routerTemplateId = -1; @Inject StorageManager _storageMgr; @Inject AsyncJobManager _asyncMgr; @@ -164,6 +239,20 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Inject SecondaryStorageVmManager _ssvmMgr; @Inject LaunchPermissionDao _launchPermissionDao; @Inject ProjectManager _projectMgr; + @Inject + VolumeDataFactory volFactory; + @Inject + ImageDataFactory tmplFactory; + @Inject + SnapshotDataFactory snapshotFactory; + @Inject + ImageService imageSvr; + @Inject + DataStoreManager dataStoreMgr; + @Inject + protected ResourceManager _resourceMgr; + @Inject VolumeManager volumeMgr; + @Inject VMTemplateHostDao templateHostDao; int _primaryStorageDownloadWait; @@ -217,7 +306,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if(!_accountService.isRootAdmin(account.getType())){ throw new PermissionDeniedException("Parameter templatetag can only be specified by a Root Admin, permission denied"); } - } + } + TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor())); TemplateProfile profile = adapter.prepare(cmd); VMTemplateVO template = adapter.create(profile); @@ -228,6 +318,22 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new CloudRuntimeException("Failed to create a template"); } } + + @Override + public DataStore getImageStore(String storeUuid, Long zoneId) { + DataStore imageStore = null; + if (storeUuid != null) { + imageStore = this.dataStoreMgr.getDataStore(storeUuid, DataStoreRole.Image); + } else { + List stores = this.dataStoreMgr.getImageStores(new ZoneScope(zoneId)); + if (stores.size() > 1) { + throw new CloudRuntimeException("multiple image stores, don't know which one to use"); + } + imageStore = stores.get(0); + } + + return imageStore; + } @Override @ActionEvent(eventType = EventTypes.EVENT_ISO_EXTRACT, eventDescription = "extracting ISO", async = true) @@ -330,7 +436,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, _accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template); - List sservers = _storageMgr.getSecondaryStorageHosts(zoneId); + List sservers = getSecondaryStorageHosts(zoneId); VMTemplateHostVO tmpltHostRef = null; if (sservers != null) { @@ -425,7 +531,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, private void reallyRun() { s_logger.info("Start to preload template " + template.getId() + " into primary storage " + pool.getId()); - prepareTemplateForCreate(template, pool); + StoragePool pol = (StoragePool)dataStoreMgr.getPrimaryDataStore(pool.getId()); + prepareTemplateForCreate(template, pol); s_logger.info("End of preloading template " + template.getId() + " into primary storage " + pool.getId()); } }); @@ -539,8 +646,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override @DB - public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO template, StoragePool pool) { - template = _tmpltDao.findById(template.getId(), true); + public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO templ, StoragePool pool) { + VMTemplateVO template = _tmpltDao.findById(templ.getId(), true); long poolId = pool.getId(); long templateId = template.getId(); @@ -564,7 +671,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } } - templateHostRef = _storageMgr.findVmTemplateHost(templateId, pool); + templateHostRef = findVmTemplateHost(templateId, pool); if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) { String result = downloadTemplateFromSwiftToSecondaryStorage(dcId, templateId); @@ -578,7 +685,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, s_logger.error("Unable to find a secondary storage host who has completely downloaded the template."); return null; } - templateHostRef = _storageMgr.findVmTemplateHost(templateId, pool); + templateHostRef = findVmTemplateHost(templateId, pool); if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) { s_logger.error("Unable to find a secondary storage host who has completely downloaded the template."); return null; @@ -671,6 +778,61 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, return null; } + + + + @Override + public VMTemplateHostVO findVmTemplateHost(long templateId, + StoragePool pool) { + long dcId = pool.getDataCenterId(); + Long podId = pool.getPodId(); + + List secHosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(dcId); + + + if (secHosts.size() == 1) { + VMTemplateHostVO templateHostVO = this._tmpltHostDao + .findByHostTemplate(secHosts.get(0).getId(), templateId); + return templateHostVO; + } + if (podId != null) { + List templHosts = this._tmpltHostDao + .listByTemplateStatus(templateId, dcId, podId, + VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + if (templHosts != null && !templHosts.isEmpty()) { + Collections.shuffle(templHosts); + return templHosts.get(0); + } + } + List templHosts = this._tmpltHostDao + .listByTemplateStatus(templateId, dcId, + VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + if (templHosts != null && !templHosts.isEmpty()) { + Collections.shuffle(templHosts); + return templHosts.get(0); + } + return null; + } + + @Override + public String getChecksum(Long hostId, String templatePath) { + HostVO ssHost = _hostDao.findById(hostId); + Host.Type type = ssHost.getType(); + if (type != Host.Type.SecondaryStorage + && type != Host.Type.LocalSecondaryStorage) { + return null; + } + String secUrl = ssHost.getStorageUrl(); + Answer answer; + answer = _agentMgr.sendToSecStorage(ssHost, new ComputeChecksumCommand( + secUrl, templatePath)); + if (answer != null && answer.getResult()) { + return answer.getDetails(); + } + return null; + } + @Override @DB public VMTemplateHostVO prepareISOForCreate(VMTemplateVO template, StoragePool pool) { @@ -684,7 +846,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, long templateStoragePoolRefId; String origUrl = null; - templateHostRef = _storageMgr.findVmTemplateHost(templateId, pool); + templateHostRef = findVmTemplateHost(templateId, pool); if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) { String result = downloadTemplateFromSwiftToSecondaryStorage(dcId, templateId); @@ -698,7 +860,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, s_logger.error("Unable to find a secondary storage host who has completely downloaded the template."); return null; } - templateHostRef = _storageMgr.findVmTemplateHost(templateId, pool); + templateHostRef = findVmTemplateHost(templateId, pool); if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) { s_logger.error("Unable to find a secondary storage host who has completely downloaded the template."); return null; @@ -839,13 +1001,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new InvalidParameterValueException("Unable to find template with id"); } - HostVO dstSecHost = _storageMgr.getSecondaryStorageHost(destZoneId, templateId); + HostVO dstSecHost = getSecondaryStorageHost(destZoneId, templateId); if ( dstSecHost != null ) { s_logger.debug("There is template " + templateId + " in secondary storage " + dstSecHost.getId() + " in zone " + destZoneId + " , don't need to copy"); return template; } - HostVO srcSecHost = _storageMgr.getSecondaryStorageHost(sourceZoneId, templateId); + HostVO srcSecHost = getSecondaryStorageHost(sourceZoneId, templateId); if ( srcSecHost == null ) { throw new InvalidParameterValueException("There is no template " + templateId + " in zone " + sourceZoneId ); } @@ -900,7 +1062,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Override public void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO) { - StoragePoolVO pool = _poolDao.findById(templatePoolVO.getPoolId()); + StoragePool pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId()); VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId()); @@ -1065,32 +1227,37 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override - public boolean templateIsDeleteable(VMTemplateHostVO templateHostRef) { - VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templateHostRef.getTemplateId()); - long templateId = template.getId(); - HostVO secondaryStorageHost = _hostDao.findById(templateHostRef.getHostId()); - long zoneId = secondaryStorageHost.getDataCenterId(); - DataCenterVO zone = _dcDao.findById(zoneId); - - // Check if there are VMs running in the template host ref's zone that use the template - List nonExpungedVms = _vmInstanceDao.listNonExpungedByZoneAndTemplate(zoneId, templateId); - - if (!nonExpungedVms.isEmpty()) { - s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are non-expunged VMs deployed from this template."); - return false; - } - - // Check if there are any snapshots for the template in the template host ref's zone - List volumes = _volumeDao.findByTemplateAndZone(templateId, zoneId); - for (VolumeVO volume : volumes) { - List snapshots = _snapshotDao.listByVolumeIdVersion(volume.getId(), "2.1"); - if (!snapshots.isEmpty()) { - s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are 2.1 snapshots using this template."); - return false; - } - } - - return true; + public boolean templateIsDeleteable(VMTemplateHostVO templateHostRef) { + VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templateHostRef.getTemplateId()); + long templateId = template.getId(); + HostVO secondaryStorageHost = _hostDao.findById(templateHostRef.getHostId()); + long zoneId = secondaryStorageHost.getDataCenterId(); + DataCenterVO zone = _dcDao.findById(zoneId); + + // Check if there are VMs running in the template host ref's zone that use the template + List nonExpungedVms = _vmInstanceDao.listNonExpungedByZoneAndTemplate(zoneId, templateId); + + if (!nonExpungedVms.isEmpty()) { + s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are non-expunged VMs deployed from this template."); + return false; + } + List userVmUsingIso = _userVmDao.listByIsoId(templateId); + //check if there is any VM using this ISO. + if (!userVmUsingIso.isEmpty()) { + s_logger.debug("ISO " + template.getName() + " in zone " + zone.getName() + " is not deleteable because it is attached to " + userVmUsingIso.size() + " VMs"); + return false; + } + // Check if there are any snapshots for the template in the template host ref's zone + List volumes = _volumeDao.findByTemplateAndZone(templateId, zoneId); + for (VolumeVO volume : volumes) { + List snapshots = _snapshotDao.listByVolumeIdVersion(volume.getId(), "2.1"); + if (!snapshots.isEmpty()) { + s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + " is not deleteable because there are 2.1 snapshots using this template."); + return false; + } + } + + return true; } @Override @@ -1176,12 +1343,57 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new CloudRuntimeException("Failed to attach iso"); } } + + private boolean attachISOToVM(long vmId, long isoId, boolean attach) { + UserVmVO vm = this._userVmDao.findById(vmId); + + if (vm == null) { + return false; + } else if (vm.getState() != State.Running) { + return true; + } + String isoPath; + VMTemplateVO tmplt = this._tmpltDao.findById(isoId); + if (tmplt == null) { + s_logger.warn("ISO: " + isoId + " does not exist"); + return false; + } + // Get the path of the ISO + Pair isoPathPair = null; + if (tmplt.getTemplateType() == TemplateType.PERHOST) { + isoPath = tmplt.getName(); + } else { + isoPathPair = getAbsoluteIsoPath(isoId, + vm.getDataCenterId()); + if (isoPathPair == null) { + s_logger.warn("Couldn't get absolute iso path"); + return false; + } else { + isoPath = isoPathPair.first(); + } + } + + String vmName = vm.getInstanceName(); + + HostVO host = _hostDao.findById(vm.getHostId()); + if (host == null) { + s_logger.warn("Host: " + vm.getHostId() + " does not exist"); + return false; + } + AttachIsoCommand cmd = new AttachIsoCommand(vmName, isoPath, attach); + if (isoPathPair != null) { + cmd.setStoreUrl(isoPathPair.second()); + } + Answer a = _agentMgr.easySend(vm.getHostId(), cmd); + + return (a != null && a.getResult()); + } private boolean attachISOToVM(long vmId, long userId, long isoId, boolean attach) { UserVmVO vm = _userVmDao.findById(vmId); VMTemplateVO iso = _tmpltDao.findById(isoId); - boolean success = _vmMgr.attachISOToVM(vmId, isoId, attach); + boolean success = attachISOToVM(vmId, isoId, attach); if ( success && attach) { vm.setIsoId(iso.getId()); _userVmDao.update(vmId, vm); @@ -1475,4 +1687,456 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, return true; } + + private String getRandomPrivateTemplateName() { + return UUID.randomUUID().toString(); + } + + + + + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", async = true) + public VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) + throws CloudRuntimeException { + Long userId = UserContext.current().getCallerUserId(); + if (userId == null) { + userId = User.UID_SYSTEM; + } + long templateId = command.getEntityId(); + Long volumeId = command.getVolumeId(); + Long snapshotId = command.getSnapshotId(); + VMTemplateVO privateTemplate = null; + Long accountId = null; + SnapshotVO snapshot = null; + + try { + TemplateInfo tmplInfo = this.tmplFactory.getTemplate(templateId); + snapshot = _snapshotDao.findById(snapshotId); + ZoneScope scope = new ZoneScope(snapshot.getDataCenterId()); + List store = this.dataStoreMgr.getImageStores(scope); + if (store.size() > 1) { + throw new CloudRuntimeException("muliple image data store, don't know which one to use"); + } + AsyncCallFuture future = null; + if (snapshotId != null) { + SnapshotInfo snapInfo = this.snapshotFactory.getSnapshot(snapshotId); + future = this.imageSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store.get(0)); + } else if (volumeId != null) { + VolumeInfo volInfo = this.volFactory.getVolume(volumeId); + future = this.imageSvr.createTemplateFromVolumeAsync(volInfo, tmplInfo, store.get(0)); + } else { + throw new CloudRuntimeException( + "Creating private Template need to specify snapshotId or volumeId"); + } + + CommandResult result = null; + try { + result = future.get(); + if (result.isFailed()) { + privateTemplate = null; + s_logger.debug("Failed to create template" + result.getResult()); + throw new CloudRuntimeException("Failed to create template" + result.getResult()); + } + + privateTemplate = this._tmpltDao.findById(templateId); + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_TEMPLATE_CREATE, + privateTemplate.getAccountId(), + snapshot.getDataCenterId(), + privateTemplate.getId(), privateTemplate.getName(), + null, privateTemplate.getSourceTemplateId(), + privateTemplate.getSize()); + _usageEventDao.persist(usageEvent); + } catch (InterruptedException e) { + s_logger.debug("Failed to create template", e); + throw new CloudRuntimeException("Failed to create template", e); + } catch (ExecutionException e) { + s_logger.debug("Failed to create template", e); + throw new CloudRuntimeException("Failed to create template", e); + } + + } finally { + /*if (snapshot != null && snapshot.getSwiftId() != null + && secondaryStorageURL != null && zoneId != null + && accountId != null && volumeId != null) { + _snapshotMgr.deleteSnapshotsForVolume(secondaryStorageURL, + zoneId, accountId, volumeId); + }*/ + if (privateTemplate == null) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + // Remove the template record + this._tmpltDao.expunge(templateId); + + // decrement resource count + if (accountId != null) { + _resourceLimitMgr.decrementResourceCount(accountId, + ResourceType.template); + } + txn.commit(); + } + } + + if (privateTemplate != null) { + return privateTemplate; + } else { + throw new CloudRuntimeException("Failed to create a template"); + } + } + + private static boolean isAdmin(short accountType) { + return ((accountType == Account.ACCOUNT_TYPE_ADMIN) + || (accountType == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) + || (accountType == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) || (accountType == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)); + } + @Override + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) + public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, + Account templateOwner) throws ResourceAllocationException { + Long userId = UserContext.current().getCallerUserId(); + + Account caller = UserContext.current().getCaller(); + boolean isAdmin = (isAdmin(caller.getType())); + + _accountMgr.checkAccess(caller, null, true, templateOwner); + + String name = cmd.getTemplateName(); + if ((name == null) || (name.length() > 32)) { + throw new InvalidParameterValueException( + "Template name cannot be null and should be less than 32 characters"); + } + + if (cmd.getTemplateTag() != null) { + if (!_accountService.isRootAdmin(caller.getType())) { + throw new PermissionDeniedException( + "Parameter templatetag can only be specified by a Root Admin, permission denied"); + } + } + + // do some parameter defaulting + Integer bits = cmd.getBits(); + Boolean requiresHvm = cmd.getRequiresHvm(); + Boolean passwordEnabled = cmd.isPasswordEnabled(); + Boolean isPublic = cmd.isPublic(); + Boolean featured = cmd.isFeatured(); + int bitsValue = ((bits == null) ? 64 : bits.intValue()); + boolean requiresHvmValue = ((requiresHvm == null) ? true : requiresHvm + .booleanValue()); + boolean passwordEnabledValue = ((passwordEnabled == null) ? false + : passwordEnabled.booleanValue()); + if (isPublic == null) { + isPublic = Boolean.FALSE; + } + boolean allowPublicUserTemplates = Boolean.parseBoolean(_configDao + .getValue("allow.public.user.templates")); + if (!isAdmin && !allowPublicUserTemplates && isPublic) { + throw new PermissionDeniedException("Failed to create template " + + name + ", only private templates can be created."); + } + + Long volumeId = cmd.getVolumeId(); + Long snapshotId = cmd.getSnapshotId(); + if ((volumeId == null) && (snapshotId == null)) { + throw new InvalidParameterValueException( + "Failed to create private template record, neither volume ID nor snapshot ID were specified."); + } + if ((volumeId != null) && (snapshotId != null)) { + throw new InvalidParameterValueException( + "Failed to create private template record, please specify only one of volume ID (" + + volumeId + + ") and snapshot ID (" + + snapshotId + + ")"); + } + + HypervisorType hyperType; + VolumeVO volume = null; + VMTemplateVO privateTemplate = null; + if (volumeId != null) { // create template from volume + volume = this._volumeDao.findById(volumeId); + if (volume == null) { + throw new InvalidParameterValueException( + "Failed to create private template record, unable to find volume " + + volumeId); + } + // check permissions + _accountMgr.checkAccess(caller, null, true, volume); + + // If private template is created from Volume, check that the volume + // will not be active when the private template is + // created + if (!this.volumeMgr.volumeInactive(volume)) { + String msg = "Unable to create private template for volume: " + + volume.getName() + + "; volume is attached to a non-stopped VM, please stop the VM first"; + if (s_logger.isInfoEnabled()) { + s_logger.info(msg); + } + throw new CloudRuntimeException(msg); + } + hyperType = this._volumeDao.getHypervisorType(volumeId); + } else { // create template from snapshot + SnapshotVO snapshot = _snapshotDao.findById(snapshotId); + if (snapshot == null) { + throw new InvalidParameterValueException( + "Failed to create private template record, unable to find snapshot " + + snapshotId); + } + + volume = this._volumeDao.findById(snapshot.getVolumeId()); + VolumeVO snapshotVolume = this._volumeDao + .findByIdIncludingRemoved(snapshot.getVolumeId()); + + // check permissions + _accountMgr.checkAccess(caller, null, true, snapshot); + + if (snapshot.getState() != Snapshot.State.BackedUp) { + throw new InvalidParameterValueException("Snapshot id=" + + snapshotId + " is not in " + Snapshot.State.BackedUp + + " state yet and can't be used for template creation"); + } + + /* + * // bug #11428. Operation not supported if vmware and snapshots + * parent volume = ROOT if(snapshot.getHypervisorType() == + * HypervisorType.VMware && snapshotVolume.getVolumeType() == + * Type.DATADISK){ throw new UnsupportedServiceException( + * "operation not supported, snapshot with id " + snapshotId + + * " is created from Data Disk"); } + */ + + hyperType = snapshot.getHypervisorType(); + } + + _resourceLimitMgr.checkResourceLimit(templateOwner, + ResourceType.template); + + if (!isAdmin || featured == null) { + featured = Boolean.FALSE; + } + Long guestOSId = cmd.getOsTypeId(); + GuestOSVO guestOS = this._guestOSDao.findById(guestOSId); + if (guestOS == null) { + throw new InvalidParameterValueException("GuestOS with ID: " + + guestOSId + " does not exist."); + } + + String uniqueName = Long.valueOf((userId == null) ? 1 : userId) + .toString() + + UUID.nameUUIDFromBytes(name.getBytes()).toString(); + Long nextTemplateId = this._tmpltDao.getNextInSequence(Long.class, "id"); + String description = cmd.getDisplayText(); + boolean isExtractable = false; + Long sourceTemplateId = null; + if (volume != null) { + VMTemplateVO template = ApiDBUtils.findTemplateById(volume + .getTemplateId()); + isExtractable = template != null + && template.isExtractable() + && template.getTemplateType() != Storage.TemplateType.SYSTEM; + if (template != null) { + sourceTemplateId = template.getId(); + } else if (volume.getVolumeType() == Volume.Type.ROOT) { // vm created out + // of blank + // template + UserVm userVm = ApiDBUtils.findUserVmById(volume + .getInstanceId()); + sourceTemplateId = userVm.getIsoId(); + } + } + String templateTag = cmd.getTemplateTag(); + if (templateTag != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Adding template tag: " + templateTag); + } + } + privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, name, + ImageFormat.RAW, isPublic, featured, isExtractable, + TemplateType.USER, null, null, requiresHvmValue, bitsValue, + templateOwner.getId(), null, description, passwordEnabledValue, + guestOS.getId(), true, hyperType, templateTag, cmd.getDetails()); + if (sourceTemplateId != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("This template is getting created from other template, setting source template Id to: " + + sourceTemplateId); + } + } + privateTemplate.setSourceTemplateId(sourceTemplateId); + + VMTemplateVO template = this._tmpltDao.persist(privateTemplate); + // Increment the number of templates + if (template != null) { + if (cmd.getDetails() != null) { + this._templateDetailsDao.persist(template.getId(), cmd.getDetails()); + } + + _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), + ResourceType.template); + } + + if (template != null) { + return template; + } else { + throw new CloudRuntimeException("Failed to create a template"); + } + + } + + @Override + public Pair getAbsoluteIsoPath(long templateId, + long dataCenterId) { + String isoPath = null; + + List storageHosts = _resourceMgr.listAllHostsInOneZoneByType( + Host.Type.SecondaryStorage, dataCenterId); + if (storageHosts != null) { + for (HostVO storageHost : storageHosts) { + List templateHostVOs = this._tmpltHostDao + .listByTemplateHostStatus( + templateId, + storageHost.getId(), + VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + if (templateHostVOs != null && !templateHostVOs.isEmpty()) { + VMTemplateHostVO tmpHostVO = templateHostVOs.get(0); + isoPath = storageHost.getStorageUrl() + "/" + + tmpHostVO.getInstallPath(); + return new Pair(isoPath, + storageHost.getStorageUrl()); + } + } + } + s_logger.warn("Unable to find secondary storage in zone id=" + + dataCenterId); + return null; + } + + @Override + public String getSecondaryStorageURL(long zoneId) { + // Determine the secondary storage URL + HostVO secondaryStorageHost = getSecondaryStorageHost(zoneId); + + if (secondaryStorageHost == null) { + return null; + } + + return secondaryStorageHost.getStorageUrl(); + } + + @Override + public HostVO getSecondaryStorageHost(long zoneId, long tmpltId) { + List hosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(zoneId); + if (hosts == null || hosts.size() == 0) { + return null; + } + for (HostVO host : hosts) { + VMTemplateHostVO tmpltHost = this._tmpltHostDao.findByHostTemplate( + host.getId(), tmpltId); + if (tmpltHost != null + && !tmpltHost.getDestroyed() + && tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { + return host; + } + } + return null; + } + + @Override + public VMTemplateHostVO getTemplateHostRef(long zoneId, long tmpltId, + boolean readyOnly) { + List hosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(zoneId); + if (hosts == null || hosts.size() == 0) { + return null; + } + VMTemplateHostVO inProgress = null; + VMTemplateHostVO other = null; + for (HostVO host : hosts) { + VMTemplateHostVO tmpltHost = this._tmpltHostDao.findByHostTemplate( + host.getId(), tmpltId); + if (tmpltHost != null && !tmpltHost.getDestroyed()) { + if (tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { + return tmpltHost; + } else if (tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) { + inProgress = tmpltHost; + } else { + other = tmpltHost; + } + } + } + if (inProgress != null) { + return inProgress; + } + return other; + } + + @Override + public HostVO getSecondaryStorageHost(long zoneId) { + List hosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(zoneId); + if (hosts == null || hosts.size() == 0) { + hosts = _ssvmMgr.listLocalSecondaryStorageHostsInOneZone(zoneId); + if (hosts.isEmpty()) { + return null; + } + } + + int size = hosts.size(); + Random rn = new Random(); + int index = rn.nextInt(size); + return hosts.get(index); + } + + @Override + public List getSecondaryStorageHosts(long zoneId) { + List hosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(zoneId); + if (hosts == null || hosts.size() == 0) { + hosts = _ssvmMgr.listLocalSecondaryStorageHostsInOneZone(zoneId); + if (hosts.isEmpty()) { + return new ArrayList(); + } + } + return hosts; + } + + @Override + public Long getTemplateSize(long templateId, long zoneId) { + SearchCriteria sc = HostTemplateStatesSearch.create(); + sc.setParameters("id", templateId); + sc.setParameters( + "state", + com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + sc.setJoinParameters("host", "dcId", zoneId); + List tsvs = _tmpltSwiftDao + .listByTemplateId(templateId); + Long size = null; + if (tsvs != null && tsvs.size() > 0) { + size = tsvs.get(0).getSize(); + } + + if (size == null && _s3Mgr.isS3Enabled()) { + VMTemplateS3VO vmTemplateS3VO = _vmS3TemplateDao + .findOneByTemplateId(templateId); + if (vmTemplateS3VO != null) { + size = vmTemplateS3VO.getSize(); + } + } + + if (size == null) { + List sss = this.templateHostDao.search(sc, null); + if (sss == null || sss.size() == 0) { + throw new CloudRuntimeException("Template " + + templateId + + " has not been completely downloaded to zone " + + zoneId); + } + size = sss.get(0).getSize(); + } + return size; + } + } diff --git a/server/src/com/cloud/upgrade/DatabaseCreator.java b/server/src/com/cloud/upgrade/DatabaseCreator.java index 4d706344707..9841faeb94b 100755 --- a/server/src/com/cloud/upgrade/DatabaseCreator.java +++ b/server/src/com/cloud/upgrade/DatabaseCreator.java @@ -29,6 +29,7 @@ import java.util.Properties; import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.SystemIntegrityChecker; import com.cloud.utils.db.ScriptRunner; import com.cloud.utils.db.Transaction; @@ -192,6 +193,8 @@ public class DatabaseCreator { } } + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { // Process db upgrade classes for (String upgradeClass: upgradeClasses) { System.out.println("========> Processing upgrade: " + upgradeClass); @@ -202,13 +205,22 @@ public class DatabaseCreator { System.err.println("The class must be of SystemIntegrityChecker: " + clazz.getName()); System.exit(1); } + SystemIntegrityChecker checker = (SystemIntegrityChecker)clazz.newInstance(); + checker.check(); } catch (ClassNotFoundException e) { System.err.println("Unable to find " + upgradeClass + ": " + e.getMessage()); System.exit(1); + } catch (InstantiationException e) { + System.err.println("Unable to instantiate " + upgradeClass + ": " + e.getMessage()); + System.exit(1); + } catch (IllegalAccessException e) { + System.err.println("Unable to access " + upgradeClass + ": " + e.getMessage()); + System.exit(1); } - //SystemIntegrityChecker checker = (SystemIntegrityChecker)ComponentLocator.inject(clazz); - //checker.check(); + } + } finally { + txn.close(); } } } diff --git a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java index f831a032385..5bd749fe842 100755 --- a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java +++ b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java @@ -31,7 +31,6 @@ import java.util.List; import java.util.TreeMap; import javax.ejb.Local; -import javax.inject.Inject; import org.apache.log4j.Logger; @@ -57,6 +56,7 @@ import com.cloud.upgrade.dao.Upgrade301to302; import com.cloud.upgrade.dao.Upgrade302to40; import com.cloud.upgrade.dao.Upgrade30to301; import com.cloud.upgrade.dao.Upgrade40to41; +import com.cloud.upgrade.dao.Upgrade410to420; import com.cloud.upgrade.dao.UpgradeSnapshot217to224; import com.cloud.upgrade.dao.UpgradeSnapshot223to224; import com.cloud.upgrade.dao.VersionDao; @@ -76,90 +76,93 @@ public class DatabaseUpgradeChecker implements SystemIntegrityChecker { protected HashMap _upgradeMap = new HashMap(); - @Inject VersionDao _dao; + VersionDao _dao; public DatabaseUpgradeChecker() { + _dao = new VersionDaoImpl(); _upgradeMap.put("2.1.7", new DbUpgrade[] { new Upgrade217to218(), new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), - new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.1.8", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), - new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.1.9", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), - new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.1", new DbUpgrade[] { new Upgrade221to222(), new UpgradeSnapshot223to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), - new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.2", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), - new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.3", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), - new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.4", new DbUpgrade[] { new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), - new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), - new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), + new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.5", new DbUpgrade[] { new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), - new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), - new Upgrade302to40() }); + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), + new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.6", new DbUpgrade[] { new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), - new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.7", new DbUpgrade[] { new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), - new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.8", new DbUpgrade[] { new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30() - , new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + , new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.9", new DbUpgrade[] { new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), - new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.10", new DbUpgrade[] { new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), - new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.11", new DbUpgrade[] { new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), - new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.12", new DbUpgrade[] { new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), - new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.13", new DbUpgrade[] { new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), - new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); _upgradeMap.put("2.2.14", new DbUpgrade[] { new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), - new Upgrade302to40() }); + new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); - _upgradeMap.put("3.0.0", new DbUpgrade[] { new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + _upgradeMap.put("3.0.0", new DbUpgrade[] { new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); - _upgradeMap.put("3.0.1", new DbUpgrade[] { new Upgrade301to302(), new Upgrade302to40() }); + _upgradeMap.put("3.0.1", new DbUpgrade[] { new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); - _upgradeMap.put("3.0.2", new DbUpgrade[] { new Upgrade302to40() }); - - _upgradeMap.put("4.0.0", new DbUpgrade[] { new Upgrade40to41() }); + _upgradeMap.put("3.0.2", new DbUpgrade[] { new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420() }); + + _upgradeMap.put("4.0.0", new DbUpgrade[] { new Upgrade40to41(), new Upgrade410to420() }); + + _upgradeMap.put("4.1.0", new DbUpgrade[] { new Upgrade410to420() }); } protected void runScript(Connection conn, File file) { diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java b/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java index 88370c10c8c..c0f827e655e 100755 --- a/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java @@ -266,8 +266,19 @@ public class Upgrade2214to30 extends Upgrade30xBase implements DbUpgrade { addPhysicalNtwk_To_Ntwk_IP_Vlan(conn, physicalNetworkId,networkId); } pstmt3.close(); + + // add the reference to this physical network for the default public network entries in vlan / user_ip_address tables // add first physicalNetworkId to op_dc_vnet_alloc for this zone - just a placeholder since direct networking dont need this if(isFirstPhysicalNtwk){ + s_logger.debug("Adding PhysicalNetwork to default Public network entries in vlan and user_ip_address"); + pstmt3 = conn.prepareStatement("SELECT id FROM `cloud`.`networks` where traffic_type = 'Public' and data_center_id = "+zoneId); + ResultSet rsPubNet = pstmt3.executeQuery(); + if(rsPubNet.next()){ + Long publicNetworkId = rsPubNet.getLong(1); + addPhysicalNtwk_To_Ntwk_IP_Vlan(conn, physicalNetworkId,publicNetworkId); + } + pstmt3.close(); + s_logger.debug("Adding PhysicalNetwork to op_dc_vnet_alloc"); String updateVnet = "UPDATE `cloud`.`op_dc_vnet_alloc` SET physical_network_id = " + physicalNetworkId + " WHERE data_center_id = " + zoneId; pstmtUpdate = conn.prepareStatement(updateVnet); diff --git a/server/src/com/cloud/upgrade/dao/Upgrade40to41.java b/server/src/com/cloud/upgrade/dao/Upgrade40to41.java index d3a8cd5a9d3..e7fea237700 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade40to41.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade40to41.java @@ -32,47 +32,24 @@ import java.util.UUID; import org.apache.log4j.Logger; -/** - * @author htrippaers - * - */ public class Upgrade40to41 implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade40to41.class); - /** - * - */ - public Upgrade40to41() { - // TODO Auto-generated constructor stub - } - - /* (non-Javadoc) - * @see com.cloud.upgrade.dao.DbUpgrade#getUpgradableVersionRange() - */ @Override public String[] getUpgradableVersionRange() { return new String[] { "4.0.0", "4.1.0" }; } - /* (non-Javadoc) - * @see com.cloud.upgrade.dao.DbUpgrade#getUpgradedVersion() - */ @Override public String getUpgradedVersion() { return "4.1.0"; } - /* (non-Javadoc) - * @see com.cloud.upgrade.dao.DbUpgrade#supportsRollingUpgrade() - */ @Override public boolean supportsRollingUpgrade() { return false; } - /* (non-Javadoc) - * @see com.cloud.upgrade.dao.DbUpgrade#getPrepareScripts() - */ @Override public File[] getPrepareScripts() { String script = Script.findScript("", "db/schema-40to410.sql"); @@ -83,21 +60,20 @@ public class Upgrade40to41 implements DbUpgrade { return new File[] { new File(script) }; } - /* (non-Javadoc) - * @see com.cloud.upgrade.dao.DbUpgrade#performDataMigration(java.sql.Connection) - */ @Override public void performDataMigration(Connection conn) { upgradeEIPNetworkOfferings(conn); upgradeEgressFirewallRules(conn); } - /* (non-Javadoc) - * @see com.cloud.upgrade.dao.DbUpgrade#getCleanupScripts() - */ @Override public File[] getCleanupScripts() { - return new File[0]; + String script = Script.findScript("", "db/schema-40to410-cleanup.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-40to410-cleanup.sql"); + } + + return new File[] { new File(script) }; } private void upgradeEIPNetworkOfferings(Connection conn) { @@ -133,7 +109,6 @@ public class Upgrade40to41 implements DbUpgrade { } } - private void upgradeEgressFirewallRules(Connection conn) { PreparedStatement pstmt = null; ResultSet rs = null; diff --git a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java new file mode 100644 index 00000000000..a0592579a43 --- /dev/null +++ b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -0,0 +1,73 @@ +// 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.upgrade.dao; + +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; + +import java.io.File; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +import org.apache.log4j.Logger; + +public class Upgrade410to420 implements DbUpgrade { + final static Logger s_logger = Logger.getLogger(Upgrade410to420.class); + + @Override + public String[] getUpgradableVersionRange() { + return new String[] { "4.1.0", "4.2.0" }; + } + + @Override + public String getUpgradedVersion() { + return "4.2.0"; + } + + @Override + public boolean supportsRollingUpgrade() { + return false; + } + + @Override + public File[] getPrepareScripts() { + String script = Script.findScript("", "db/schema-410to420.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-410to420.sql"); + } + + return new File[] { new File(script) }; + } + + @Override + public void performDataMigration(Connection conn) { + } + + @Override + public File[] getCleanupScripts() { + String script = Script.findScript("", "db/schema-410to420-cleanup.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-410to420-cleanup.sql"); + } + + return new File[] { new File(script) }; + } + } \ No newline at end of file diff --git a/server/src/com/cloud/upgrade/dao/VersionDaoImpl.java b/server/src/com/cloud/upgrade/dao/VersionDaoImpl.java index 5e6e7bc75b8..7c5c9ccccf0 100644 --- a/server/src/com/cloud/upgrade/dao/VersionDaoImpl.java +++ b/server/src/com/cloud/upgrade/dao/VersionDaoImpl.java @@ -47,7 +47,7 @@ public class VersionDaoImpl extends GenericDaoBase implements V final GenericSearchBuilder CurrentVersionSearch; final SearchBuilder AllFieldsSearch; - protected VersionDaoImpl() { + public VersionDaoImpl() { super(); CurrentVersionSearch = createSearchBuilder(String.class); diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 54447a2f176..f9a61e89df7 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -104,6 +104,7 @@ import com.cloud.server.auth.UserAuthenticator; import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; +import com.cloud.storage.VolumeManager; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.VMTemplateDao; @@ -118,7 +119,6 @@ import com.cloud.user.dao.UserDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; - import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -218,7 +218,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M private IPAddressDao _ipAddressDao; @Inject private RegionManager _regionMgr; - + @Inject private VpcManager _vpcMgr; @Inject private DomainRouterDao _routerDao; @@ -226,6 +226,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M Site2SiteVpnManager _vpnMgr; @Inject private AutoScaleManager _autoscaleMgr; + @Inject VolumeManager volumeMgr; @Inject private List _userAuthenticators; @@ -576,7 +577,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M for (VolumeVO volume : volumes) { if (!volume.getState().equals(Volume.State.Destroy)) { try { - _storageMgr.deleteVolume(volume.getId(), caller); + this.volumeMgr.deleteVolume(volume.getId(), caller); } catch (Exception ex) { s_logger.warn("Failed to cleanup volumes as a part of account id=" + accountId + " cleanup due to Exception: ", ex); accountCleanupNeeded = true; diff --git a/server/src/com/cloud/vm/UserVmManager.java b/server/src/com/cloud/vm/UserVmManager.java index 3e4a2dbf27f..cc1fffd780b 100755 --- a/server/src/com/cloud/vm/UserVmManager.java +++ b/server/src/com/cloud/vm/UserVmManager.java @@ -49,16 +49,7 @@ public interface UserVmManager extends VirtualMachineGuru, UserVmServi * @return VirtualMachine */ UserVmVO getVirtualMachine(long vmId); - - /** - * Attaches an ISO to the virtual CDROM device of the specified VM. Will eject any existing virtual CDROM if isoPath is null. - * @param vmId - * @param isoId - * @param attach whether to attach or detach the given iso - * @return - */ - boolean attachISOToVM(long vmId, long isoId, boolean attach); - + /** * Stops the virtual machine * @param userId the id of the user performing the action @@ -101,8 +92,6 @@ public interface UserVmManager extends VirtualMachineGuru, UserVmServi */ Pair, Integer> searchForUserVMs(Criteria c, Account caller, Long domainId, boolean isRecursive, List permittedAccounts, boolean listAll, ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags); - String getChecksum(Long hostId, String templatePath); - Pair> startVirtualMachine(long vmId, Long hostId, Map additionalParams) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java old mode 100644 new mode 100755 index 33a53d9e5f4..6cb3f1a70af --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -34,10 +34,8 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; @@ -52,48 +50,31 @@ import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; - import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity; import org.apache.cloudstack.engine.service.api.OrchestrationService; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; +import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.api.Answer; -import com.cloud.agent.api.AttachIsoCommand; -import com.cloud.agent.api.AttachVolumeAnswer; -import com.cloud.agent.api.AttachVolumeCommand; -import com.cloud.agent.api.ComputeChecksumCommand; -import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; -import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; import com.cloud.agent.api.GetVmStatsAnswer; import com.cloud.agent.api.GetVmStatsCommand; -import com.cloud.agent.api.SnapshotCommand; +import com.cloud.agent.api.PlugNicAnswer; +import com.cloud.agent.api.PlugNicCommand; import com.cloud.agent.api.StartAnswer; import com.cloud.agent.api.StopAnswer; -import com.cloud.agent.api.UpgradeSnapshotCommand; +import com.cloud.agent.api.UnPlugNicAnswer; +import com.cloud.agent.api.UnPlugNicCommand; import com.cloud.agent.api.VmStatsEntry; -import com.cloud.agent.AgentManager.OnError; -import com.cloud.agent.api.*; -import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; -import com.cloud.agent.api.PlugNicAnswer; -import com.cloud.agent.api.PlugNicCommand; -import com.cloud.agent.api.UnPlugNicAnswer; -import com.cloud.agent.api.UnPlugNicCommand; import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; -import com.cloud.api.ApiDBUtils; import com.cloud.api.query.dao.UserVmJoinDao; import com.cloud.api.query.vo.UserVmJoinVO; -import com.cloud.async.AsyncJobExecutor; import com.cloud.async.AsyncJobManager; -import com.cloud.async.AsyncJobVO; -import com.cloud.async.BaseAsyncJobExecutor; import com.cloud.capacity.CapacityManager; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; @@ -108,6 +89,7 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeployPlannerSelector; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; @@ -134,7 +116,6 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.network.Network; -import com.cloud.network.*; import com.cloud.network.Network.IpAddresses; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; @@ -182,7 +163,6 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.GuestOSVO; -import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; @@ -191,14 +171,10 @@ import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.Volume; -import com.cloud.storage.Volume.Type; -import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeManager; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; @@ -213,6 +189,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeHostDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.template.TemplateManager; import com.cloud.template.VirtualMachineTemplate; import com.cloud.template.VirtualMachineTemplate.BootloaderType; import com.cloud.user.Account; @@ -249,12 +226,37 @@ import com.cloud.utils.exception.ExecutionException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.dao.*; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; +import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; +import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; +import org.apache.cloudstack.api.command.user.vm.*; +import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; +import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; +import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.InstanceGroupVMMapDao; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.VMSnapshotManager; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Local(value = { UserVmManager.class, UserVmService.class }) public class UserVmManagerImpl extends ManagerBase implements UserVmManager, UserVmService { @@ -389,9 +391,18 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Inject VpcManager _vpcMgr; @Inject + TemplateManager templateMgr; + @Inject protected GuestOSCategoryDao _guestOSCategoryDao; @Inject UsageEventDao _usageEventDao; + @Inject + protected VMSnapshotDao _vmSnapshotDao; + @Inject + protected VMSnapshotManager _vmSnapshotMgr; + + @Inject + List plannerSelectors; protected ScheduledExecutorService _executor = null; protected int _expungeInterval; @@ -400,13 +411,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use protected String _name; protected String _instance; protected String _zone; + protected boolean _instanceNameFlag; @Inject ConfigurationDao _configDao; private int _createprivatetemplatefromvolumewait; private int _createprivatetemplatefromsnapshotwait; + private final int MAX_VM_NAME_LEN = 80; @Inject protected OrchestrationService _orchSrvc; + + @Inject VolumeManager volumeMgr; @Override public UserVmVO getVirtualMachine(long vmId) { @@ -418,6 +433,24 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return _vmDao.listByHostId(hostId); } + protected void resourceLimitCheck (Account owner, Long cpu, Long memory) throws ResourceAllocationException { + _resourceLimitMgr.checkResourceLimit(owner, ResourceType.user_vm); + _resourceLimitMgr.checkResourceLimit(owner, ResourceType.cpu, cpu); + _resourceLimitMgr.checkResourceLimit(owner, ResourceType.memory, memory); + } + + protected void resourceCountIncrement (long accountId, Long cpu, Long memory) { + _resourceLimitMgr.incrementResourceCount(accountId, ResourceType.user_vm); + _resourceLimitMgr.incrementResourceCount(accountId, ResourceType.cpu, cpu); + _resourceLimitMgr.incrementResourceCount(accountId, ResourceType.memory, memory); + } + + protected void resourceCountDecrement (long accountId, Long cpu, Long memory) { + _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.user_vm); + _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.cpu, cpu); + _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.memory, memory); + } + @Override @ActionEvent(eventType = EventTypes.EVENT_VM_RESETPASSWORD, eventDescription = "resetting Vm password", async = true) public UserVm resetVMPassword(ResetVMPasswordCmd cmd, String password) @@ -690,574 +723,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - private int getMaxDataVolumesSupported(UserVmVO vm) { - Long hostId = vm.getHostId(); - if (hostId == null) { - hostId = vm.getLastHostId(); - } - HostVO host = _hostDao.findById(hostId); - Integer maxDataVolumesSupported = null; - if (host != null) { - _hostDao.loadDetails(host); - maxDataVolumesSupported = _hypervisorCapabilitiesDao - .getMaxDataVolumesLimit(host.getHypervisorType(), - host.getDetail("product_version")); - } - if (maxDataVolumesSupported == null) { - maxDataVolumesSupported = 6; // 6 data disks by default if nothing - // is specified in - // 'hypervisor_capabilities' table - } - return maxDataVolumesSupported.intValue(); + + + private void checkVMSnapshots(UserVmVO vm, Long volumeId, boolean attach) { + // Check that if vm has any VM snapshot + /*Long vmId = vm.getId(); + List 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_ATTACH, eventDescription = "attaching volume", async = true) - public Volume attachVolumeToVM(AttachVolumeCmd command) { - Long vmId = command.getVirtualMachineId(); - Long volumeId = command.getId(); - Long deviceId = command.getDeviceId(); - Account caller = UserContext.current().getCaller(); - - // Check that the volume ID is valid - VolumeVO volume = _volsDao.findById(volumeId); - // Check that the volume is a data volume - if (volume == null || volume.getVolumeType() != Volume.Type.DATADISK) { - throw new InvalidParameterValueException( - "Please specify a valid data volume."); - } - - // Check that the volume is not currently attached to any VM - if (volume.getInstanceId() != null) { - throw new InvalidParameterValueException( - "Please specify a volume that is not attached to any VM."); - } - - // Check that the volume is not destroyed - if (volume.getState() == Volume.State.Destroy) { - throw new InvalidParameterValueException( - "Please specify a volume that is not destroyed."); - } - - // Check that the virtual machine ID is valid and it's a user vm - UserVmVO vm = _vmDao.findById(vmId); - if (vm == null || vm.getType() != VirtualMachine.Type.User) { - throw new InvalidParameterValueException( - "Please specify a valid User VM."); - } - - // Check that the VM is in the correct state - if (vm.getState() != State.Running && vm.getState() != State.Stopped) { - throw new InvalidParameterValueException( - "Please specify a VM that is either running or stopped."); - } - - // Check that the device ID is valid - if (deviceId != null) { - if (deviceId.longValue() == 0) { - throw new InvalidParameterValueException( - "deviceId can't be 0, which is used by Root device"); - } - } - - // Check that the number of data volumes attached to VM is less than - // that supported by hypervisor - List existingDataVolumes = _volsDao.findByInstanceAndType( - vmId, Volume.Type.DATADISK); - int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); - if (existingDataVolumes.size() >= maxDataVolumesSupported) { - throw new InvalidParameterValueException( - "The specified VM already has the maximum number of data disks (" - + maxDataVolumesSupported - + "). Please specify another VM."); - } - - // Check that the VM and the volume are in the same zone - if (vm.getDataCenterId() != volume.getDataCenterId()) { - throw new InvalidParameterValueException( - "Please specify a VM that is in the same zone as the volume."); - } - - // If local storage is disabled then attaching a volume with local disk - // offering not allowed - DataCenterVO dataCenter = _dcDao.findById(volume.getDataCenterId()); - if (!dataCenter.isLocalStorageEnabled()) { - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume - .getDiskOfferingId()); - if (diskOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException( - "Zone is not configured to use local storage but volume's disk offering " - + diskOffering.getName() + " uses it"); - } - } - - // permission check - _accountMgr.checkAccess(caller, null, true, volume, vm); - - // Check if volume is stored on secondary Storage. - boolean isVolumeOnSec = false; - VolumeHostVO volHostVO = _volumeHostDao.findByVolumeId(volume.getId()); - if (volHostVO != null) { - isVolumeOnSec = true; - if (!(volHostVO.getDownloadState() == Status.DOWNLOADED)) { - throw new InvalidParameterValueException( - "Volume is not uploaded yet. Please try this operation once the volume is uploaded"); - } - } - - if (!(Volume.State.Allocated.equals(volume.getState()) - || Volume.State.Ready.equals(volume.getState()) || Volume.State.UploadOp - .equals(volume.getState()))) { - throw new InvalidParameterValueException( - "Volume state must be in Allocated, Ready or in Uploaded state"); - } - - VolumeVO rootVolumeOfVm = null; - List rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, - Volume.Type.ROOT); - if (rootVolumesOfVm.size() != 1) { - throw new CloudRuntimeException( - "The VM " - + vm.getHostName() - + " has more than one ROOT volume and is in an invalid state."); - } else { - rootVolumeOfVm = rootVolumesOfVm.get(0); - } - - HypervisorType rootDiskHyperType = vm.getHypervisorType(); - - HypervisorType dataDiskHyperType = _volsDao.getHypervisorType(volume - .getId()); - if (dataDiskHyperType != HypervisorType.None - && rootDiskHyperType != dataDiskHyperType) { - throw new InvalidParameterValueException( - "Can't attach a volume created by: " + dataDiskHyperType - + " to a " + rootDiskHyperType + " vm"); - } - - // allocate deviceId - List vols = _volsDao.findByInstance(vmId); - if (deviceId != null) { - if (deviceId.longValue() > 15 || deviceId.longValue() == 0 - || deviceId.longValue() == 3) { - throw new RuntimeException("deviceId should be 1,2,4-15"); - } - for (VolumeVO vol : vols) { - if (vol.getDeviceId().equals(deviceId)) { - throw new RuntimeException("deviceId " + deviceId - + " is used by VM " + vm.getHostName()); - } - } - } else { - // allocate deviceId here - List devIds = new ArrayList(); - for (int i = 1; i < 15; i++) { - devIds.add(String.valueOf(i)); - } - devIds.remove("3"); - for (VolumeVO vol : vols) { - devIds.remove(vol.getDeviceId().toString().trim()); - } - deviceId = Long.parseLong(devIds.iterator().next()); - } - - boolean createVolumeOnBackend = true; - if (rootVolumeOfVm.getState() == Volume.State.Allocated) { - createVolumeOnBackend = false; - if (isVolumeOnSec) { - throw new CloudRuntimeException( - "Cant attach uploaded volume to the vm which is not created. Please start it and then retry"); - } - } - - // create volume on the backend only when vm's root volume is allocated - if (createVolumeOnBackend) { - if (volume.getState().equals(Volume.State.Allocated) - || isVolumeOnSec) { - /* Need to create the volume */ - VMTemplateVO rootDiskTmplt = _templateDao.findById(vm - .getTemplateId()); - DataCenterVO dcVO = _dcDao.findById(vm - .getDataCenterId()); - HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn()); - StoragePoolVO rootDiskPool = _storagePoolDao - .findById(rootVolumeOfVm.getPoolId()); - ServiceOfferingVO svo = _serviceOfferingDao.findById(vm - .getServiceOfferingId()); - DiskOfferingVO diskVO = _diskOfferingDao.findById(volume - .getDiskOfferingId()); - Long clusterId = (rootDiskPool == null ? null : rootDiskPool - .getClusterId()); - - if (!isVolumeOnSec) { - volume = _storageMgr.createVolume(volume, vm, - rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO, - new ArrayList(), volume.getSize(), - rootDiskHyperType); - } else { - try { - // Format of data disk should be the same as root disk - if (!volHostVO - .getFormat() - .getFileExtension() - .equals(_storageMgr - .getSupportedImageFormatForCluster(rootDiskPool - .getClusterId()))) { - throw new InvalidParameterValueException( - "Failed to attach volume to VM since volumes format " - + volHostVO.getFormat() - .getFileExtension() - + " is not compatible with the vm hypervisor type"); - } - - // Check that there is some shared storage. - StoragePoolVO vmRootVolumePool = _storagePoolDao - .findById(rootVolumeOfVm.getPoolId()); - List sharedVMPools = _storagePoolDao - .findPoolsByTags( - vmRootVolumePool.getDataCenterId(), - vmRootVolumePool.getPodId(), - vmRootVolumePool.getClusterId(), null, - true); - if (sharedVMPools.size() == 0) { - throw new CloudRuntimeException( - "Cannot attach volume since there are no shared storage pools in the VM's cluster to copy the uploaded volume to."); - } - - volume = _storageMgr.copyVolumeFromSecToPrimary(volume, - vm, rootDiskTmplt, dcVO, pod, - rootDiskPool.getClusterId(), svo, diskVO, - new ArrayList(), - volume.getSize(), rootDiskHyperType); - } catch (NoTransitionException e) { - throw new CloudRuntimeException( - "Unable to transition the volume ", e); - } - } - - if (volume == null) { - throw new CloudRuntimeException( - "Failed to create volume when attaching it to VM: " - + vm.getHostName()); - } - } - - StoragePoolVO vmRootVolumePool = _storagePoolDao - .findById(rootVolumeOfVm.getPoolId()); - DiskOfferingVO volumeDiskOffering = _diskOfferingDao - .findById(volume.getDiskOfferingId()); - String[] volumeTags = volumeDiskOffering.getTagsArray(); - - boolean isVolumeOnSharedPool = !volumeDiskOffering - .getUseLocalStorage(); - StoragePoolVO sourcePool = _storagePoolDao.findById(volume - .getPoolId()); - List matchingVMPools = _storagePoolDao - .findPoolsByTags(vmRootVolumePool.getDataCenterId(), - vmRootVolumePool.getPodId(), - vmRootVolumePool.getClusterId(), volumeTags, - isVolumeOnSharedPool); - boolean moveVolumeNeeded = true; - if (matchingVMPools.size() == 0) { - String poolType; - if (vmRootVolumePool.getClusterId() != null) { - poolType = "cluster"; - } else if (vmRootVolumePool.getPodId() != null) { - poolType = "pod"; - } else { - poolType = "zone"; - } - throw new CloudRuntimeException( - "There are no storage pools in the VM's " + poolType - + " with all of the volume's tags (" - + volumeDiskOffering.getTags() + ")."); - } else { - long sourcePoolId = sourcePool.getId(); - Long sourcePoolDcId = sourcePool.getDataCenterId(); - Long sourcePoolPodId = sourcePool.getPodId(); - Long sourcePoolClusterId = sourcePool.getClusterId(); - for (StoragePoolVO vmPool : matchingVMPools) { - long vmPoolId = vmPool.getId(); - Long vmPoolDcId = vmPool.getDataCenterId(); - Long vmPoolPodId = vmPool.getPodId(); - Long vmPoolClusterId = vmPool.getClusterId(); - - // Moving a volume is not required if storage pools belongs - // to same cluster in case of shared volume or - // identical storage pool in case of local - if (sourcePoolDcId == vmPoolDcId - && sourcePoolPodId == vmPoolPodId - && sourcePoolClusterId == vmPoolClusterId - && (isVolumeOnSharedPool || sourcePoolId == vmPoolId)) { - moveVolumeNeeded = false; - break; - } - } - } - - if (moveVolumeNeeded) { - if (isVolumeOnSharedPool) { - // Move the volume to a storage pool in the VM's zone, pod, - // or cluster - try { - volume = _storageMgr.moveVolume(volume, - vmRootVolumePool.getDataCenterId(), - vmRootVolumePool.getPodId(), - vmRootVolumePool.getClusterId(), - dataDiskHyperType); - } catch (ConcurrentOperationException e) { - throw new CloudRuntimeException(e.toString()); - } - } else { - throw new CloudRuntimeException( - "Failed to attach local data volume " - + volume.getName() - + " to VM " - + vm.getDisplayName() - + " as migration of local data volume is not allowed"); - } - } - } - - AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor - .getCurrentExecutor(); - if (asyncExecutor != null) { - AsyncJobVO job = asyncExecutor.getJob(); - - if (s_logger.isInfoEnabled()) { - s_logger.info("Trying to attaching volume " + volumeId - + " to vm instance:" + vm.getId() - + ", update async job-" + job.getId() - + " progress status"); - } - - _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); - _asyncMgr.updateAsyncJobStatus(job.getId(), - BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId); - } - - String errorMsg = "Failed to attach volume: " + volume.getName() - + " to VM: " + vm.getHostName(); - boolean sendCommand = (vm.getState() == State.Running); - AttachVolumeAnswer answer = null; - Long hostId = vm.getHostId(); - if (hostId == null) { - hostId = vm.getLastHostId(); - HostVO host = _hostDao.findById(hostId); - if (host != null - && host.getHypervisorType() == HypervisorType.VMware) { - sendCommand = true; - } - } - - if (sendCommand) { - StoragePoolVO volumePool = _storagePoolDao.findById(volume - .getPoolId()); - AttachVolumeCommand cmd = new AttachVolumeCommand(true, - vm.getInstanceName(), volume.getPoolType(), - volume.getFolder(), volume.getPath(), volume.getName(), - deviceId, volume.getChainInfo()); - cmd.setPoolUuid(volumePool.getUuid()); - - try { - answer = (AttachVolumeAnswer) _agentMgr.send(hostId, cmd); - } catch (Exception e) { - throw new CloudRuntimeException(errorMsg + " due to: " - + e.getMessage()); - } - } - - if (!sendCommand || (answer != null && answer.getResult())) { - // Mark the volume as attached - if (sendCommand) { - _volsDao.attachVolume(volume.getId(), vmId, - answer.getDeviceId()); - } else { - _volsDao.attachVolume(volume.getId(), vmId, deviceId); - } - return _volsDao.findById(volumeId); - } else { - if (answer != null) { - String details = answer.getDetails(); - if (details != null && !details.isEmpty()) { - errorMsg += "; " + details; - } - } - throw new CloudRuntimeException(errorMsg); - } - } - - @Override - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", 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)) - || (cmmd.getId() == null && (cmmd.getDeviceId() == null || cmmd - .getVirtualMachineId() == null))) { - throw new InvalidParameterValueException( - "Please provide either a volume id, or a tuple(device id, instance id)"); - } - - Long volumeId = cmmd.getId(); - VolumeVO volume = null; - - if (volumeId != null) { - volume = _volsDao.findById(volumeId); - } else { - volume = _volsDao.findByInstanceAndDeviceId( - cmmd.getVirtualMachineId(), cmmd.getDeviceId()).get(0); - } - - Long vmId = null; - - if (cmmd.getVirtualMachineId() == null) { - vmId = volume.getInstanceId(); - } else { - vmId = cmmd.getVirtualMachineId(); - } - - // Check that the volume ID is valid - if (volume == null) { - throw new InvalidParameterValueException( - "Unable to find volume with ID: " + volumeId); - } - - // Permissions check - _accountMgr.checkAccess(caller, null, true, volume); - - // Check that the volume is a data volume - if (volume.getVolumeType() != Volume.Type.DATADISK) { - throw new InvalidParameterValueException( - "Please specify a data volume."); - } - - // Check that the volume is currently attached to a VM - if (vmId == null) { - throw new InvalidParameterValueException( - "The specified volume is not attached to a VM."); - } - - // Check that the VM is in the correct state - UserVmVO vm = _vmDao.findById(vmId); - if (vm.getState() != State.Running && vm.getState() != State.Stopped - && vm.getState() != State.Destroyed) { - throw new InvalidParameterValueException( - "Please specify a VM that is either running or stopped."); - } - - AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor - .getCurrentExecutor(); - if (asyncExecutor != null) { - AsyncJobVO job = asyncExecutor.getJob(); - - if (s_logger.isInfoEnabled()) { - s_logger.info("Trying to attaching volume " + volumeId - + "to vm instance:" + vm.getId() - + ", update async job-" + job.getId() - + " progress status"); - } - - _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); - _asyncMgr.updateAsyncJobStatus(job.getId(), - BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId); - } - - String errorMsg = "Failed to detach volume: " + volume.getName() - + " from VM: " + vm.getHostName(); - boolean sendCommand = (vm.getState() == State.Running); - Answer answer = null; - - if (sendCommand) { - AttachVolumeCommand cmd = new AttachVolumeCommand(false, - vm.getInstanceName(), volume.getPoolType(), - volume.getFolder(), volume.getPath(), volume.getName(), - cmmd.getDeviceId() != null ? cmmd.getDeviceId() : volume - .getDeviceId(), volume.getChainInfo()); - - StoragePoolVO volumePool = _storagePoolDao.findById(volume - .getPoolId()); - cmd.setPoolUuid(volumePool.getUuid()); - - try { - answer = _agentMgr.send(vm.getHostId(), cmd); - } catch (Exception e) { - throw new CloudRuntimeException(errorMsg + " due to: " - + e.getMessage()); - } - } - - if (!sendCommand || (answer != null && answer.getResult())) { - // Mark the volume as detached - _volsDao.detachVolume(volume.getId()); - if (answer != null && answer instanceof AttachVolumeAnswer) { - volume.setChainInfo(((AttachVolumeAnswer) answer) - .getChainInfo()); - _volsDao.update(volume.getId(), volume); - } - - return _volsDao.findById(volumeId); - } else { - - if (answer != null) { - String details = answer.getDetails(); - if (details != null && !details.isEmpty()) { - errorMsg += "; " + details; - } - } - - throw new CloudRuntimeException(errorMsg); - } - } - - @Override - public boolean attachISOToVM(long vmId, long isoId, boolean attach) { - UserVmVO vm = _vmDao.findById(vmId); - - if (vm == null) { - return false; - } else if (vm.getState() != State.Running) { - return true; - } - String isoPath; - VMTemplateVO tmplt = _templateDao.findById(isoId); - if (tmplt == null) { - s_logger.warn("ISO: " + isoId + " does not exist"); - return false; - } - // Get the path of the ISO - Pair isoPathPair = null; - if (tmplt.getTemplateType() == TemplateType.PERHOST) { - isoPath = tmplt.getName(); - } else { - isoPathPair = _storageMgr.getAbsoluteIsoPath(isoId, - vm.getDataCenterId()); - if (isoPathPair == null) { - s_logger.warn("Couldn't get absolute iso path"); - return false; - } else { - isoPath = isoPathPair.first(); - } - } - - String vmName = vm.getInstanceName(); - - HostVO host = _hostDao.findById(vm.getHostId()); - if (host == null) { - s_logger.warn("Host: " + vm.getHostId() + " does not exist"); - return false; - } - AttachIsoCommand cmd = new AttachIsoCommand(vmName, isoPath, attach); - if (isoPathPair != null) { - cmd.setStoreUrl(isoPathPair.second()); - } - Answer a = _agentMgr.easySend(vm.getHostId(), cmd); - - return (a != null && a.getResult()); - } + private UserVm rebootVirtualMachine(long userId, long vmId) throws InsufficientCapacityException, ResourceUnavailableException { @@ -1296,12 +776,25 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new InvalidParameterValueException( "unable to find a virtual machine with id " + vmId); } - + _accountMgr.checkAccess(caller, null, true, vmInstance); // Check that the specified service offering ID is valid _itMgr.checkIfCanUpgrade(vmInstance, svcOffId); + // remove diskAndMemory VM snapshots + /* List 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()); @@ -1629,9 +1122,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use "Unable to recover VM as the account is deleted"); } - // First check that the maximum number of UserVMs for the given + // Get serviceOffering for Virtual Machine + ServiceOfferingVO serviceOffering = _serviceOfferingDao.findById(vm.getServiceOfferingId()); + + // First check that the maximum number of UserVMs, CPU and Memory limit for the given // accountId will not be exceeded - _resourceLimitMgr.checkResourceLimit(account, ResourceType.user_vm); + resourceLimitCheck(account, new Long(serviceOffering.getCpu()), new Long(serviceOffering.getRamSize())); _haMgr.cancelDestroy(vm, vm.getHostId()); @@ -1672,12 +1168,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } + //Update Resource Count for the given account _resourceLimitMgr.incrementResourceCount(account.getId(), ResourceType.volume, new Long(volumes.size())); - - _resourceLimitMgr.incrementResourceCount(account.getId(), - ResourceType.user_vm); - + resourceCountIncrement(account.getId(), new Long(serviceOffering.getCpu()), + new Long(serviceOffering.getRamSize())); txn.commit(); return _vmDao.findById(vmId); @@ -1729,6 +1224,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use VirtualMachine.State.getStateMachine().registerListener( new UserVmStateListener(_usageEventDao, _networkDao, _nicDao)); + value = _configDao.getValue(Config.SetVmInternalNameUsingDisplayName.key()); + if(value == null) { + _instanceNameFlag = false; + } + else + { + _instanceNameFlag = Boolean.parseBoolean(value); + } + s_logger.info("User VM Manager is configured."); return true; @@ -1882,476 +1386,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - @Override - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) - public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, - Account templateOwner) throws ResourceAllocationException { - Long userId = UserContext.current().getCallerUserId(); - - Account caller = UserContext.current().getCaller(); - boolean isAdmin = (isAdmin(caller.getType())); - - _accountMgr.checkAccess(caller, null, true, templateOwner); - - String name = cmd.getTemplateName(); - if ((name == null) || (name.length() > 32)) { - throw new InvalidParameterValueException( - "Template name cannot be null and should be less than 32 characters"); - } - - if (cmd.getTemplateTag() != null) { - if (!_accountService.isRootAdmin(caller.getType())) { - throw new PermissionDeniedException( - "Parameter templatetag can only be specified by a Root Admin, permission denied"); - } - } - - // do some parameter defaulting - Integer bits = cmd.getBits(); - Boolean requiresHvm = cmd.getRequiresHvm(); - Boolean passwordEnabled = cmd.isPasswordEnabled(); - Boolean isPublic = cmd.isPublic(); - Boolean featured = cmd.isFeatured(); - int bitsValue = ((bits == null) ? 64 : bits.intValue()); - boolean requiresHvmValue = ((requiresHvm == null) ? true : requiresHvm - .booleanValue()); - boolean passwordEnabledValue = ((passwordEnabled == null) ? false - : passwordEnabled.booleanValue()); - if (isPublic == null) { - isPublic = Boolean.FALSE; - } - boolean allowPublicUserTemplates = Boolean.parseBoolean(_configDao - .getValue("allow.public.user.templates")); - if (!isAdmin && !allowPublicUserTemplates && isPublic) { - throw new PermissionDeniedException("Failed to create template " - + name + ", only private templates can be created."); - } - - Long volumeId = cmd.getVolumeId(); - Long snapshotId = cmd.getSnapshotId(); - if ((volumeId == null) && (snapshotId == null)) { - throw new InvalidParameterValueException( - "Failed to create private template record, neither volume ID nor snapshot ID were specified."); - } - if ((volumeId != null) && (snapshotId != null)) { - throw new InvalidParameterValueException( - "Failed to create private template record, please specify only one of volume ID (" - + volumeId - + ") and snapshot ID (" - + snapshotId - + ")"); - } - - HypervisorType hyperType; - VolumeVO volume = null; - VMTemplateVO privateTemplate = null; - if (volumeId != null) { // create template from volume - volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new InvalidParameterValueException( - "Failed to create private template record, unable to find volume " - + volumeId); - } - // check permissions - _accountMgr.checkAccess(caller, null, true, volume); - - // If private template is created from Volume, check that the volume - // will not be active when the private template is - // created - if (!_storageMgr.volumeInactive(volume)) { - String msg = "Unable to create private template for volume: " - + volume.getName() - + "; volume is attached to a non-stopped VM, please stop the VM first"; - if (s_logger.isInfoEnabled()) { - s_logger.info(msg); - } - throw new CloudRuntimeException(msg); - } - hyperType = _volsDao.getHypervisorType(volumeId); - } else { // create template from snapshot - SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - if (snapshot == null) { - throw new InvalidParameterValueException( - "Failed to create private template record, unable to find snapshot " - + snapshotId); - } - - volume = _volsDao.findById(snapshot.getVolumeId()); - VolumeVO snapshotVolume = _volsDao - .findByIdIncludingRemoved(snapshot.getVolumeId()); - - // check permissions - _accountMgr.checkAccess(caller, null, true, snapshot); - - if (snapshot.getState() != Snapshot.State.BackedUp) { - throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.State.BackedUp + " state yet and can't be used for template creation"); - } - - /* - * // bug #11428. Operation not supported if vmware and snapshots - * parent volume = ROOT if(snapshot.getHypervisorType() == - * HypervisorType.VMware && snapshotVolume.getVolumeType() == - * Type.DATADISK){ throw new UnsupportedServiceException( - * "operation not supported, snapshot with id " + snapshotId + - * " is created from Data Disk"); } - */ - - hyperType = snapshot.getHypervisorType(); - } - - _resourceLimitMgr.checkResourceLimit(templateOwner, - ResourceType.template); - - if (!isAdmin || featured == null) { - featured = Boolean.FALSE; - } - Long guestOSId = cmd.getOsTypeId(); - GuestOSVO guestOS = _guestOSDao.findById(guestOSId); - if (guestOS == null) { - throw new InvalidParameterValueException("GuestOS with ID: " - + guestOSId + " does not exist."); - } - - String uniqueName = Long.valueOf((userId == null) ? 1 : userId) - .toString() - + UUID.nameUUIDFromBytes(name.getBytes()).toString(); - Long nextTemplateId = _templateDao.getNextInSequence(Long.class, "id"); - String description = cmd.getDisplayText(); - boolean isExtractable = false; - Long sourceTemplateId = null; - if (volume != null) { - VMTemplateVO template = ApiDBUtils.findTemplateById(volume - .getTemplateId()); - isExtractable = template != null - && template.isExtractable() - && template.getTemplateType() != Storage.TemplateType.SYSTEM; - if (template != null) { - sourceTemplateId = template.getId(); - } else if (volume.getVolumeType() == Type.ROOT) { // vm created out - // of blank - // template - UserVm userVm = ApiDBUtils.findUserVmById(volume - .getInstanceId()); - sourceTemplateId = userVm.getIsoId(); - } - } - String templateTag = cmd.getTemplateTag(); - if (templateTag != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Adding template tag: " + templateTag); - } - } - privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, name, - ImageFormat.RAW, isPublic, featured, isExtractable, - TemplateType.USER, null, null, requiresHvmValue, bitsValue, - templateOwner.getId(), null, description, passwordEnabledValue, - guestOS.getId(), true, hyperType, templateTag, cmd.getDetails()); - if (sourceTemplateId != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("This template is getting created from other template, setting source template Id to: " - + sourceTemplateId); - } - } - privateTemplate.setSourceTemplateId(sourceTemplateId); - - VMTemplateVO template = _templateDao.persist(privateTemplate); - // Increment the number of templates - if (template != null) { - if (cmd.getDetails() != null) { - _templateDetailsDao.persist(template.getId(), cmd.getDetails()); - } - - _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), - ResourceType.template); - } - - if (template != null) { - return template; - } else { - throw new CloudRuntimeException("Failed to create a template"); - } - - } - - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", async = true) - public VMTemplateVO createPrivateTemplate(CreateTemplateCmd command) - throws CloudRuntimeException { - Long userId = UserContext.current().getCallerUserId(); - if (userId == null) { - userId = User.UID_SYSTEM; - } - long templateId = command.getEntityId(); - Long volumeId = command.getVolumeId(); - Long snapshotId = command.getSnapshotId(); - SnapshotCommand cmd = null; - VMTemplateVO privateTemplate = null; - - String uniqueName = getRandomPrivateTemplateName(); - - StoragePoolVO pool = null; - HostVO secondaryStorageHost = null; - Long zoneId = null; - Long accountId = null; - SnapshotVO snapshot = null; - String secondaryStorageURL = null; - try { - if (snapshotId != null) { // create template from snapshot - snapshot = _snapshotDao.findById(snapshotId); - if (snapshot == null) { - throw new CloudRuntimeException( - "Unable to find Snapshot for Id " + snapshotId); - } - zoneId = snapshot.getDataCenterId(); - secondaryStorageHost = _snapshotMgr - .getSecondaryStorageHost(snapshot); - secondaryStorageURL = _snapshotMgr - .getSecondaryStorageURL(snapshot); - String name = command.getTemplateName(); - String backupSnapshotUUID = snapshot.getBackupSnapshotId(); - if (backupSnapshotUUID == null) { - throw new CloudRuntimeException( - "Unable to create private template from snapshot " - + snapshotId - + " due to there is no backupSnapshotUUID for this snapshot"); - } - - Long dcId = snapshot.getDataCenterId(); - accountId = snapshot.getAccountId(); - volumeId = snapshot.getVolumeId(); - - String origTemplateInstallPath = null; - List pools = _storageMgr - .ListByDataCenterHypervisor(zoneId, - snapshot.getHypervisorType()); - if (pools == null || pools.size() == 0) { - throw new CloudRuntimeException( - "Unable to find storage pools in zone " + zoneId); - } - pool = pools.get(0); - if (snapshot.getVersion() != null - && snapshot.getVersion().equalsIgnoreCase("2.1")) { - VolumeVO volume = _volsDao - .findByIdIncludingRemoved(volumeId); - if (volume == null) { - throw new CloudRuntimeException( - "failed to upgrade snapshot " - + snapshotId - + " due to unable to find orignal volume:" - + volumeId + ", try it later "); - } - if (volume.getTemplateId() == null) { - _snapshotDao.updateSnapshotVersion(volumeId, "2.1", - "2.2"); - } else { - VMTemplateVO template = _templateDao - .findByIdIncludingRemoved(volume - .getTemplateId()); - if (template == null) { - throw new CloudRuntimeException( - "failed to upgrade snapshot " - + snapshotId - + " due to unalbe to find orignal template :" - + volume.getTemplateId() - + ", try it later "); - } - Long origTemplateId = template.getId(); - Long origTmpltAccountId = template.getAccountId(); - if (!_volsDao.lockInLockTable(volumeId.toString(), 10)) { - throw new CloudRuntimeException( - "failed to upgrade snapshot " + snapshotId - + " due to volume:" + volumeId - + " is being used, try it later "); - } - cmd = new UpgradeSnapshotCommand(null, - secondaryStorageURL, dcId, accountId, volumeId, - origTemplateId, origTmpltAccountId, null, - snapshot.getBackupSnapshotId(), - snapshot.getName(), "2.1"); - if (!_volsDao.lockInLockTable(volumeId.toString(), 10)) { - throw new CloudRuntimeException( - "Creating template failed due to volume:" - + volumeId - + " is being used, try it later "); - } - Answer answer = null; - try { - answer = _storageMgr.sendToPool(pool, cmd); - cmd = null; - } catch (StorageUnavailableException e) { - } finally { - _volsDao.unlockFromLockTable(volumeId.toString()); - } - if ((answer != null) && answer.getResult()) { - _snapshotDao.updateSnapshotVersion(volumeId, "2.1", - "2.2"); - } else { - throw new CloudRuntimeException( - "Unable to upgrade snapshot"); - } - } - } - if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) { - _snapshotMgr.downloadSnapshotsFromSwift(snapshot); - } - cmd = new CreatePrivateTemplateFromSnapshotCommand(pool, secondaryStorageURL, dcId, accountId, snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(), - origTemplateInstallPath, templateId, name, _createprivatetemplatefromsnapshotwait); - } else if (volumeId != null) { - VolumeVO volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new CloudRuntimeException( - "Unable to find volume for Id " + volumeId); - } - accountId = volume.getAccountId(); - - if (volume.getPoolId() == null) { - _templateDao.remove(templateId); - throw new CloudRuntimeException("Volume " + volumeId - + " is empty, can't create template on it"); - } - String vmName = _storageMgr.getVmNameOnVolume(volume); - zoneId = volume.getDataCenterId(); - secondaryStorageHost = _storageMgr - .getSecondaryStorageHost(zoneId); - if (secondaryStorageHost == null) { - throw new CloudRuntimeException( - "Can not find the secondary storage for zoneId " - + zoneId); - } - secondaryStorageURL = secondaryStorageHost.getStorageUrl(); - - pool = _storagePoolDao.findById(volume.getPoolId()); - cmd = new CreatePrivateTemplateFromVolumeCommand(pool, secondaryStorageURL, templateId, accountId, command.getTemplateName(), uniqueName, volume.getPath(), vmName, _createprivatetemplatefromvolumewait); - - } else { - throw new CloudRuntimeException( - "Creating private Template need to specify snapshotId or volumeId"); - } - // FIXME: before sending the command, check if there's enough - // capacity - // on the storage server to create the template - - // This can be sent to a KVM host too. - CreatePrivateTemplateAnswer answer = null; - if (snapshotId != null) { - if (!_snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { - throw new CloudRuntimeException( - "Creating template from snapshot failed due to snapshot:" - + snapshotId - + " is being used, try it later "); - } - } else { - if (!_volsDao.lockInLockTable(volumeId.toString(), 10)) { - throw new CloudRuntimeException( - "Creating template from volume failed due to volume:" - + volumeId - + " is being used, try it later "); - } - } - try { - answer = (CreatePrivateTemplateAnswer) _storageMgr.sendToPool( - pool, cmd); - } catch (StorageUnavailableException e) { - } finally { - if (snapshotId != null) { - _snapshotDao.unlockFromLockTable(snapshotId.toString()); - } else { - _volsDao.unlockFromLockTable(volumeId.toString()); - } - } - if ((answer != null) && answer.getResult()) { - privateTemplate = _templateDao.findById(templateId); - String answerUniqueName = answer.getUniqueName(); - if (answerUniqueName != null) { - privateTemplate.setUniqueName(answerUniqueName); - } else { - privateTemplate.setUniqueName(uniqueName); - } - ImageFormat format = answer.getImageFormat(); - if (format != null) { - privateTemplate.setFormat(format); - } else { - // This never occurs. - // Specify RAW format makes it unusable for snapshots. - privateTemplate.setFormat(ImageFormat.RAW); - } - - String checkSum = getChecksum(secondaryStorageHost.getId(), - answer.getPath()); - - Transaction txn = Transaction.currentTxn(); - - txn.start(); - - privateTemplate.setChecksum(checkSum); - _templateDao.update(templateId, privateTemplate); - - // add template zone ref for this template - _templateDao.addTemplateToZone(privateTemplate, zoneId); - VMTemplateHostVO templateHostVO = new VMTemplateHostVO( - secondaryStorageHost.getId(), templateId); - templateHostVO.setDownloadPercent(100); - templateHostVO.setDownloadState(Status.DOWNLOADED); - templateHostVO.setInstallPath(answer.getPath()); - templateHostVO.setLastUpdated(new Date()); - templateHostVO.setSize(answer.getVirtualSize()); - templateHostVO.setPhysicalSize(answer.getphysicalSize()); - _templateHostDao.persist(templateHostVO); - - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_TEMPLATE_CREATE, privateTemplate.getAccountId(), - secondaryStorageHost.getDataCenterId(), privateTemplate.getId(), - privateTemplate.getName(), null, privateTemplate.getSourceTemplateId(), - templateHostVO.getSize(), VirtualMachineTemplate.class.getName(), privateTemplate.getUuid()); - txn.commit(); - } - } finally { - if (snapshot != null && snapshot.getSwiftId() != null - && secondaryStorageURL != null && zoneId != null - && accountId != null && volumeId != null) { - _snapshotMgr.deleteSnapshotsForVolume(secondaryStorageURL, - zoneId, accountId, volumeId); - } - if (privateTemplate == null) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - // Remove the template record - _templateDao.expunge(templateId); - - // decrement resource count - if (accountId != null) { - _resourceLimitMgr.decrementResourceCount(accountId, - ResourceType.template); - } - txn.commit(); - } - } - - if (privateTemplate != null) { - return privateTemplate; - } else { - throw new CloudRuntimeException("Failed to create a template"); - } - } - - @Override - public String getChecksum(Long hostId, String templatePath) { - HostVO ssHost = _hostDao.findById(hostId); - Host.Type type = ssHost.getType(); - if (type != Host.Type.SecondaryStorage - && type != Host.Type.LocalSecondaryStorage) { - return null; - } - String secUrl = ssHost.getStorageUrl(); - Answer answer; - answer = _agentMgr.sendToSecStorage(ssHost, new ComputeChecksumCommand( - secUrl, templatePath)); - if (answer != null && answer.getResult()) { - return answer.getDetails(); - } - return null; - } - // used for vm transitioning to error state private void updateVmStateForFailedVmCreation(Long vmId, Long hostId) { @@ -2371,21 +1405,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use List volumesForThisVm = _volsDao .findUsableVolumesForInstance(vm.getId()); for (VolumeVO volume : volumesForThisVm) { - try { - if (volume.getState() != Volume.State.Destroy) { - _storageMgr.destroyVolume(volume); - } - } catch (ConcurrentOperationException e) { - s_logger.warn("Unable to delete volume:" - + volume.getId() + " for vm:" + vmId - + " whilst transitioning to error state"); + if (volume.getState() != Volume.State.Destroy) { + this.volumeMgr.destroyVolume(volume); } } String msg = "Failed to deploy Vm with Id: " + vmId + ", on Host with Id: " + hostId; _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); - _resourceLimitMgr.decrementResourceCount(vm.getAccountId(), - ResourceType.user_vm); + // Get serviceOffering for Virtual Machine + ServiceOfferingVO offering = _serviceOfferingDao.findById(vm.getServiceOfferingId()); + + // Update Resource Count for the given account + resourceCountDecrement(vm.getAccountId(), new Long(offering.getCpu()), + new Long(offering.getRamSize())); } } } @@ -2590,6 +1622,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _accountMgr.checkAccess(caller, null, true, vmInstance); + // If the VM is Volatile in nature, on reboot discard the VM's root disk and create a new root disk for it: by calling restoreVM + long serviceOfferingId = vmInstance.getServiceOfferingId(); + ServiceOfferingVO offering = _serviceOfferingDao.findById(serviceOfferingId); + if(offering != null && offering.getRemoved() == null) { + if(offering.getVolatileVm()){ + return restoreVMInternal(caller, vmInstance, null); + } + } else { + throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId + " corresponding to the vm"); + } + return rebootVirtualMachine(UserContext.current().getCallerUserId(), vmId); } @@ -3085,6 +2128,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); } + + public void checkNameForRFCCompliance(String name) { + if (!NetUtils.verifyDomainNameLabel(name, true)) { + throw new InvalidParameterValueException("Invalid name. Vm name can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'), must be between 1 and 63 characters long, and can't start or end with \"-\" and can't start with digit"); + } + } + @DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, Long diskSize, List networkList, List securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, IpAddresses defaultIps, String keyboard) @@ -3120,9 +2171,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _configMgr.checkZoneAccess(owner, zone); } + ServiceOfferingVO offering = _serviceOfferingDao.findById(serviceOffering.getId()); + // check if account/domain is with in resource limits to create a new vm boolean isIso = Storage.ImageFormat.ISO == template.getFormat(); - _resourceLimitMgr.checkResourceLimit(owner, ResourceType.user_vm); + resourceLimitCheck(owner, new Long(offering.getCpu()), new Long(offering.getRamSize())); _resourceLimitMgr.checkResourceLimit(owner, ResourceType.volume, (isIso || diskOfferingId == null ? 1 : 2)); @@ -3140,19 +2193,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } } - - // check if we have available pools for vm deployment - long availablePools = _storagePoolDao - .countPoolsByStatus(StoragePoolStatus.Up); - if (availablePools < 1) { - throw new StorageUnavailableException( - "There are no available pools in the UP state for vm deployment", - -1); + + if (template.getHypervisorType() != null && template.getHypervisorType() != HypervisorType.BareMetal) { + // check if we have available pools for vm deployment + long availablePools = _storagePoolDao.countPoolsByStatus(StoragePoolStatus.Up); + if (availablePools < 1) { + throw new StorageUnavailableException("There are no available pools in the UP state for vm deployment", -1); + } } - ServiceOfferingVO offering = _serviceOfferingDao - .findById(serviceOffering.getId()); - if (template.getTemplateType().equals(TemplateType.SYSTEM)) { throw new InvalidParameterValueException( "Unable to use system template " + template.getId() @@ -3218,7 +2267,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (requestedIpPair == null) { requestedIpPair = new IpAddresses(null, null); } else { - checkRequestedIpAddresses(requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address()); + _networkModel.checkRequestedIpAddresses(network.getId(), requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address()); } NicProfile profile = new NicProfile(requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address()); @@ -3227,7 +2276,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use defaultNetworkNumber++; // if user requested specific ip for default network, add it if (defaultIps.getIp4Address() != null || defaultIps.getIp6Address() != null) { - checkRequestedIpAddresses(defaultIps.getIp4Address(), defaultIps.getIp6Address()); + _networkModel.checkRequestedIpAddresses(network.getId(), defaultIps.getIp4Address(), defaultIps.getIp6Address()); profile = new NicProfile(defaultIps.getIp4Address(), defaultIps.getIp6Address()); } @@ -3273,8 +2322,23 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use long id = _vmDao.getNextInSequence(Long.class, "id"); - String instanceName = VirtualMachineName.getVmName(id, owner.getId(), - _instance); + String instanceName; + if (_instanceNameFlag && displayName != null) { + // Check if the displayName conforms to RFC standards. + checkNameForRFCCompliance(displayName); + instanceName = VirtualMachineName.getVmName(id, owner.getId(), displayName); + if (instanceName.length() > MAX_VM_NAME_LEN) { + throw new InvalidParameterValueException("Specified display name " + displayName + " causes VM name to exceed 80 characters in length"); + } + // Search whether there is already an instance with the same instance name + // that is not in the destroyed or expunging state. + VMInstanceVO vm = _vmInstanceDao.findVMByInstanceName(instanceName); + if (vm != null && vm.getState() != VirtualMachine.State.Expunging) { + throw new InvalidParameterValueException("There already exists a VM by the display name supplied"); + } + } else { + instanceName = VirtualMachineName.getVmName(id, owner.getId(), _instance); + } String uuidName = UUID.randomUUID().toString(); @@ -3282,12 +2346,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (hostName == null) { hostName = uuidName; } else { - // 1) check is hostName is RFC complient - if (!NetUtils.verifyDomainNameLabel(hostName, true)) { - throw new InvalidParameterValueException( - "Invalid name. Vm name can contain ASCII letters 'a' through 'z', the digits '0' through '9', " - + "and the hyphen ('-'), must be between 1 and 63 characters long, and can't start or end with \"-\" and can't start with digit"); - } + //1) check is hostName is RFC compliant + checkNameForRFCCompliance(hostName); // 2) hostName has to be unique in the network domain Map> ntwkDomains = new HashMap>(); for (NetworkVO network : networkList) { @@ -3380,8 +2440,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use vm.getHostName(), offering.getId(), template.getId(), hypervisorType.toString(), VirtualMachine.class.getName(), vm.getUuid()); - _resourceLimitMgr.incrementResourceCount(accountId, - ResourceType.user_vm); + //Update Resource Count for the given account + resourceCountIncrement(accountId, new Long(offering.getCpu()), + new Long(offering.getRamSize())); txn.commit(); @@ -3404,19 +2465,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return vm; } - private void checkRequestedIpAddresses(String ip4, String ip6) throws InvalidParameterValueException { - if (ip4 != null) { - if (!NetUtils.isValidIp(ip4)) { - throw new InvalidParameterValueException("Invalid specified IPv4 address " + ip4); - } - } - if (ip6 != null) { - if (!NetUtils.isValidIpv6(ip6)) { - throw new InvalidParameterValueException("Invalid specified IPv6 address " + ip6); - } - } - } - private void validateUserData(String userData) { byte[] decodedUserData = null; if (userData != null) { @@ -3497,7 +2545,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + vm.getIsoId()); } - Pair isoPathPair = _storageMgr.getAbsoluteIsoPath( + Pair isoPathPair = this.templateMgr.getAbsoluteIsoPath( template.getId(), vm.getDataCenterId()); if (template.getTemplateType() == TemplateType.PERHOST) { @@ -3848,8 +2896,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); + + String plannerName = null; + for (DeployPlannerSelector dps : plannerSelectors) { + plannerName = dps.selectPlanner(vm); + if (plannerName != null) { + break; + } + } + if (plannerName == null) { + throw new CloudRuntimeException(String.format("cannot find DeployPlannerSelector for vm[uuid:%s, hypervisorType:%s]", vm.getUuid(), vm.getHypervisorType())); + } - String reservationId = vmEntity.reserve("FirstFitPlanner", plan, new ExcludeList(), new Long(callerUser.getId()).toString()); + String reservationId = vmEntity.reserve(plannerName, plan, new ExcludeList(), new Long(callerUser.getId()).toString()); vmEntity.deploy(reservationId, new Long(callerUser.getId()).toString()); Pair> vmParamPair = new Pair(vm, params); @@ -3915,10 +2974,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } if (vmState != State.Error) { - _resourceLimitMgr.decrementResourceCount(vm.getAccountId(), - ResourceType.user_vm); - } + // Get serviceOffering for Virtual Machine + ServiceOfferingVO offering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getServiceOfferingId()); + //Update Resource Count for the given account + resourceCountDecrement(vm.getAccountId(), new Long(offering.getCpu()), + new Long(offering.getRamSize())); + } return _vmDao.findById(vmId); } else { CloudRuntimeException ex = new CloudRuntimeException( @@ -4414,12 +3476,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use DataCenterVO zone = _dcDao.findById(vm.getDataCenterId()); - // Remove vm from instance group + // Get serviceOffering for Virtual Machine + ServiceOfferingVO offering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getServiceOfferingId()); + + //Remove vm from instance group removeInstanceFromInstanceGroup(cmd.getVmId()); - // VV 2: check if account/domain is with in resource limits to create a - // new vm - _resourceLimitMgr.checkResourceLimit(newAccount, ResourceType.user_vm); + // VV 2: check if account/domain is with in resource limits to create a new vm + resourceLimitCheck(newAccount, new Long(offering.getCpu()), new Long(offering.getRamSize())); // VV 3: check if volumes are with in resource limits _resourceLimitMgr.checkResourceLimit(newAccount, ResourceType.volume, @@ -4444,9 +3508,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), vm.getHypervisorType().toString(), VirtualMachine.class.getName(), vm.getUuid()); - // update resource counts - _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), - ResourceType.user_vm); + + // update resource counts for old account + resourceCountDecrement(oldAccount.getAccountId(), new Long(offering.getCpu()), + new Long(offering.getRamSize())); // OWNERSHIP STEP 1: update the vm owner vm.setAccountId(newAccount.getAccountId()); @@ -4473,7 +3538,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.user_vm); + //update resource count of new account + resourceCountIncrement(newAccount.getAccountId(), new Long(offering.getCpu()), new Long(offering.getRamSize())); + //generate usage events to account for this change UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), vm.getHypervisorType().toString(), @@ -4711,20 +3778,30 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use public UserVm restoreVM(RestoreVMCmd cmd) { // Input validation Account caller = UserContext.current().getCaller(); - Long userId = UserContext.current().getCallerUserId(); - UserVO user = _userDao.findById(userId); - boolean needRestart = false; long vmId = cmd.getVmId(); + Long newTemplateId = cmd.getTemplateId(); UserVmVO vm = _vmDao.findById(vmId); if (vm == null) { - InvalidParameterValueException ex = new InvalidParameterValueException( - "Cann not find VM with ID " + vmId); + InvalidParameterValueException ex = new InvalidParameterValueException("Cannot find VM with ID " + vmId); ex.addProxyObject(vm, vmId, "vmId"); throw ex; } + _accountMgr.checkAccess(caller, null, true, vm); + + return restoreVMInternal(caller, vm, newTemplateId); + } + + public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long newTemplateId){ + + Long userId = caller.getId(); Account owner = _accountDao.findById(vm.getAccountId()); + UserVO user = _userDao.findById(userId); + long vmId = vm.getId(); + boolean needRestart = false; + + // Input validation if (owner == null) { throw new InvalidParameterValueException("The owner of " + vm + " does not exist: " + vm.getAccountId()); @@ -4739,7 +3816,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use && vm.getState() != VirtualMachine.State.Stopped) { throw new CloudRuntimeException( "Vm " - + vmId + + vm.getUuid() + " currently in " + vm.getState() + " state, restore vm can only execute when VM in Running or Stopped"); @@ -4752,27 +3829,39 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use List rootVols = _volsDao.findByInstance(vmId); if (rootVols.isEmpty()) { InvalidParameterValueException ex = new InvalidParameterValueException( - "Can not find root volume for VM " + vmId); + "Can not find root volume for VM " + vm.getUuid()); ex.addProxyObject(vm, vmId, "vmId"); throw ex; } VolumeVO root = rootVols.get(0); - long templateId = root.getTemplateId(); - VMTemplateVO template = _templateDao.findById(templateId); - if (template == null) { - InvalidParameterValueException ex = new InvalidParameterValueException( - "Cannot find template for specified volumeid and vmId"); + Long templateId = root.getTemplateId(); + if(templateId == null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Currently there is no support to reset a vm that is deployed using ISO " + vm.getUuid()); ex.addProxyObject(vm, vmId, "vmId"); - ex.addProxyObject(root, root.getId(), "volumeId"); throw ex; } + VMTemplateVO template = null; + if(newTemplateId != null) { + template = _templateDao.findById(newTemplateId); + _accountMgr.checkAccess(caller, null, true, template); + } else { + template = _templateDao.findById(templateId); + if (template == null) { + InvalidParameterValueException ex = new InvalidParameterValueException( + "Cannot find template for specified volumeid and vmId"); + ex.addProxyObject(vm, vmId, "vmId"); + ex.addProxyObject(root, root.getId(), "volumeId"); + throw ex; + } + } + if (needRestart) { try { _itMgr.stop(vm, user, caller); } catch (ResourceUnavailableException e) { - s_logger.debug("Stop vm " + vmId + " failed", e); + s_logger.debug("Stop vm " + vm.getUuid() + " failed", e); CloudRuntimeException ex = new CloudRuntimeException( "Stop vm failed for specified vmId"); ex.addProxyObject(vm, vmId, "vmId"); @@ -4780,24 +3869,29 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - /* allocate a new volume from original template */ - VolumeVO newVol = _storageMgr.allocateDuplicateVolume(root, null); + /* If new template is provided allocate a new volume from new template otherwise allocate new volume from original template */ + VolumeVO newVol = null; + if (newTemplateId != null){ + newVol = volumeMgr.allocateDuplicateVolume(root, newTemplateId); + vm.setGuestOSId(template.getGuestOSId()); + vm.setTemplateId(newTemplateId); + _vmDao.update(vmId, vm); + } else { + newVol = volumeMgr.allocateDuplicateVolume(root, null); + } + _volsDao.attachVolume(newVol.getId(), vmId, newVol.getDeviceId()); /* Detach and destory the old root volume */ - try { - _volsDao.detachVolume(root.getId()); - _storageMgr.destroyVolume(root); - } catch (ConcurrentOperationException e) { - s_logger.debug("Unable to delete old root volume " + root.getId() - + ", user may manually delete it", e); - } + + _volsDao.detachVolume(root.getId()); + this.volumeMgr.destroyVolume(root); if (needRestart) { try { _itMgr.start(vm, null, user, caller); } catch (Exception e) { - s_logger.debug("Unable to start VM " + vmId, e); + s_logger.debug("Unable to start VM " + vm.getUuid(), e); CloudRuntimeException ex = new CloudRuntimeException( "Unable to start VM with specified id" + e.getMessage()); ex.addProxyObject(vm, vmId, "vmId"); @@ -4806,8 +3900,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } s_logger.debug("Restore VM " + vmId + " with template " - + root.getTemplateId() + " successfully"); + + template.getUuid() + " done successfully"); return vm; + } @Override diff --git a/server/src/com/cloud/vm/VirtualMachineManager.java b/server/src/com/cloud/vm/VirtualMachineManager.java index 6a959fcefb6..7b34f7f0616 100644 --- a/server/src/com/cloud/vm/VirtualMachineManager.java +++ b/server/src/com/cloud/vm/VirtualMachineManager.java @@ -20,6 +20,7 @@ import java.net.URI; import java.util.List; import java.util.Map; + import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.deploy.DeployDestination; diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 1838ed2fbfa..f8448c0ac8f 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -36,8 +36,9 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import com.cloud.dc.*; import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager.OnError; @@ -69,15 +70,14 @@ import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.manager.Commands; import com.cloud.agent.manager.allocator.HostAllocator; import com.cloud.alert.AlertManager; -import com.cloud.capacity.CapacityManager; import com.cloud.cluster.ClusterManager; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.consoleproxy.ConsoleProxyManager; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; +import com.cloud.consoleproxy.ConsoleProxyManager; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DataCenterDeployment; @@ -121,10 +121,10 @@ import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.Volume.Type; +import com.cloud.storage.VolumeManager; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; @@ -152,12 +152,14 @@ 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.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; +import com.cloud.vm.dao.UserVmDetailsDao; @Local(value = VirtualMachineManager.class) public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, Listener { @@ -166,6 +168,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected StorageManager _storageMgr; @Inject + DataStoreManager dataStoreMgr; + @Inject protected NetworkManager _networkMgr; @Inject protected NetworkModel _networkModel; @@ -190,12 +194,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected UserVmDao _userVmDao; @Inject - protected DomainRouterDao _routerDao; - @Inject - protected ConsoleProxyDao _consoleDao; - @Inject - protected SecondaryStorageVmDao _secondaryDao; - @Inject protected NicDao _nicsDao; @Inject protected AccountManager _accountMgr; @@ -210,12 +208,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected VolumeDao _volsDao; @Inject - protected ConsoleProxyManager _consoleProxyMgr; - @Inject protected ConfigurationManager _configMgr; @Inject - protected CapacityManager _capacityMgr; - @Inject protected HighAvailabilityManager _haMgr; @Inject protected HostPodDao _podDao; @@ -227,6 +221,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac protected HypervisorGuruManager _hvGuruMgr; @Inject protected NetworkDao _networkDao; + @Inject + protected VMSnapshotDao _vmSnapshotDao; @Inject protected List _planners; @@ -236,9 +232,18 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected ResourceManager _resourceMgr; + + @Inject + protected VMSnapshotManager _vmSnapshotMgr = null; + @Inject + protected ClusterDetailsDao _clusterDetailsDao; + @Inject + protected UserVmDetailsDao _uservmDetailsDao; @Inject protected ConfigurationDao _configDao; + @Inject + VolumeManager volumeMgr; Map> _vmGurus = new HashMap>(); protected StateMachine2 _stateMachine; @@ -305,15 +310,15 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } if (template.getFormat() == ImageFormat.ISO) { - _storageMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner); + this.volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner); } else if (template.getFormat() == ImageFormat.BAREMETAL) { // Do nothing } else { - _storageMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner); + this.volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner); } for (Pair offering : dataDiskOfferings) { - _storageMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner); + this.volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner); } txn.commit(); @@ -345,11 +350,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return (VirtualMachineGuru) _vmGurus.get(vm.getType()); } - @SuppressWarnings("unchecked") - private VirtualMachineGuru getBareMetalVmGuru(T vm) { - return (VirtualMachineGuru) _vmGurus.get(VirtualMachine.Type.UserBareMetal); - } - @Override public boolean expunge(T vm, User caller, Account account) throws ResourceUnavailableException { try { @@ -401,10 +401,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Cleaning up NICS"); _networkMgr.cleanupNics(profile); // Clean up volumes based on the vm's instance id - _storageMgr.cleanupVolumes(vm.getId()); + this.volumeMgr.cleanupVolumes(vm.getId()); VirtualMachineGuru guru = getVmGuru(vm); guru.finalizeExpunge(vm); + //remove the overcommit detials from the uservm details + _uservmDetailsDao.deleteDetails(vm.getId()); if (s_logger.isDebugEnabled()) { s_logger.debug("Expunged " + vm); @@ -590,17 +592,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac ConcurrentOperationException, ResourceUnavailableException { return advanceStart(vm, params, caller, account, null); } - + @Override public T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlan planToDeploy) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { long vmId = vm.getId(); - VirtualMachineGuru vmGuru; - if (vm.getHypervisorType() == HypervisorType.BareMetal) { - vmGuru = getBareMetalVmGuru(vm); - } else { - vmGuru = getVmGuru(vm); - } + VirtualMachineGuru vmGuru = getVmGuru(vm); vm = vmGuru.findById(vm.getId()); Ternary start = changeToStartState(vmGuru, vm, caller, account); @@ -668,7 +665,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac continue; } - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); + StoragePool pool = (StoragePool)dataStoreMgr.getPrimaryDataStore(vol.getPoolId()); if (!pool.isInMaintenance()) { if (s_logger.isDebugEnabled()) { s_logger.debug("Root volume is ready, need to place VM in volume's cluster"); @@ -730,6 +727,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac long destHostId = dest.getHost().getId(); vm.setPodId(dest.getPod().getId()); + Long cluster_id = dest.getCluster().getId(); + ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id,"cpuOvercommitRatio"); + ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id,"memoryOvercommitRatio"); + vmProfile.setcpuOvercommitRatio(Float.parseFloat(cluster_detail_cpu.getValue())); + vmProfile.setramOvercommitRatio(Float.parseFloat(cluster_detail_ram.getValue())); try { if (!changeState(vm, Event.OperationRetry, destHostId, work, Step.Prepare)) { @@ -745,7 +747,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } _networkMgr.prepare(vmProfile, dest, ctx); if (vm.getHypervisorType() != HypervisorType.BareMetal) { - _storageMgr.prepare(vmProfile, dest); + this.volumeMgr.prepare(vmProfile, dest); } //since StorageMgr succeeded in volume creation, reuse Volume for further tries until current cluster has capacity if(!reuseVolume){ @@ -960,7 +962,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.warn("Unable to release some network resources.", e); } - _storageMgr.release(profile); + this.volumeMgr.release(profile); s_logger.debug("Successfully cleanued up resources for the vm " + vm + " in " + state + " state"); return true; } @@ -1109,7 +1111,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac try { if (vm.getHypervisorType() != HypervisorType.BareMetal) { - _storageMgr.release(profile); + this.volumeMgr.release(profile); s_logger.debug("Successfully released storage resources for the vm " + vm); } } catch (Exception e) { @@ -1143,6 +1145,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Override public boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId) throws NoTransitionException { + // if there are active vm snapshots task, state change is not allowed + if(_vmSnapshotMgr.hasActiveVMSnapshotTasks(vm.getId())){ + s_logger.error("State transit with event: " + e + " failed due to: " + vm.getInstanceName() + " has active VM snapshots tasks"); + return false; + } + State oldState = vm.getState(); if (oldState == State.Starting) { if (e == Event.OperationSucceeded) { @@ -1177,7 +1185,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Unable to stop " + vm); return false; } - + + if (!_vmSnapshotMgr.deleteAllVMSnapshots(vm.getId(),null)){ + s_logger.debug("Unable to delete all snapshots for " + vm); + return false; + } + try { if (!stateTransitTo(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId())) { s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm); @@ -1217,7 +1230,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); boolean migrationResult = false; try { - migrationResult = _storageMgr.StorageMigration(profile, destPool); + migrationResult = this.volumeMgr.storageMigration(profile, destPool); if (migrationResult) { //if the vm is migrated to different pod in basic mode, need to reallocate ip @@ -1302,7 +1315,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); _networkMgr.prepareNicForMigration(profile, dest); - _storageMgr.prepareForMigration(profile, dest); + this.volumeMgr.prepareForMigration(profile, dest); VirtualMachineTO to = toVmTO(profile); PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to); @@ -1626,6 +1639,19 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Found " + vms.size() + " VMs for host " + hostId); for (VMInstanceVO vm : vms) { AgentVmInfo info = infos.remove(vm.getId()); + + // sync VM Snapshots related transient states + List vmSnapshotsInTrasientStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging,VMSnapshot.State.Reverting, VMSnapshot.State.Creating); + if(vmSnapshotsInTrasientStates.size() > 1){ + s_logger.info("Found vm " + vm.getInstanceName() + " with VM snapshots in transient states, needs to sync VM snapshot state"); + if(!_vmSnapshotMgr.syncVMSnapshot(vm, hostId)){ + s_logger.warn("Failed to sync VM in a transient snapshot related state: " + vm.getInstanceName()); + continue; + }else{ + s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName()); + } + } + VMInstanceVO castedVm = null; if (info == null) { info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped); @@ -1743,8 +1769,27 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac for (VMInstanceVO vm : set_vms) { AgentVmInfo info = infos.remove(vm.getId()); VMInstanceVO castedVm = null; - if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting)) - || (info != null && (info.state == State.Running && vm.getState() == State.Starting))) + + // sync VM Snapshots related transient states + List vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Creating,VMSnapshot.State.Reverting); + if(vmSnapshotsInExpungingStates.size() > 0){ + s_logger.info("Found vm " + vm.getInstanceName() + " in state. " + vm.getState() + ", needs to sync VM snapshot state"); + Long hostId = null; + Host host = null; + if(info != null && info.getHostUuid() != null){ + host = _hostDao.findByGuid(info.getHostUuid()); + } + hostId = host == null ? (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId()) : host.getId(); + if(!_vmSnapshotMgr.syncVMSnapshot(vm, hostId)){ + s_logger.warn("Failed to sync VM with transient snapshot: " + vm.getInstanceName()); + continue; + }else{ + s_logger.info("Successfully sync VM with transient snapshot: " + vm.getInstanceName()); + } + } + + if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting )) + || (info != null && (info.state == State.Running && vm.getState() == State.Starting))) { s_logger.info("Found vm " + vm.getInstanceName() + " in inconsistent state. " + vm.getState() + " on CS while " + (info == null ? "Stopped" : "Running") + " on agent"); info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped); @@ -1785,7 +1830,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } else if (info != null && (vm.getState() == State.Stopped || vm.getState() == State.Stopping - || vm.isRemoved() || vm.getState() == State.Destroyed || vm.getState() == State.Expunging)) { + || vm.isRemoved() || vm.getState() == State.Destroyed || vm.getState() == State.Expunging )) { Host host = _hostDao.findByGuid(info.getHostUuid()); if (host != null){ s_logger.warn("Stopping a VM which is stopped/stopping/destroyed/expunging " + info.name); @@ -2260,6 +2305,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac Long clusterId = agent.getClusterId(); long agentId = agent.getId(); + if (agent.getHypervisorType() == HypervisorType.XenServer) { // only for Xen StartupRoutingCommand startup = (StartupRoutingCommand) cmd; HashMap> allStates = startup.getClusterVMStateChanges(); @@ -2375,7 +2421,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac if (newServiceOffering == null) { throw new InvalidParameterValueException("Unable to find a service offering with id " + newServiceOfferingId); } - + // Check that the VM is stopped if (!vmInstance.getState().equals(State.Stopped)) { s_logger.warn("Unable to upgrade virtual machine " + vmInstance.toString() + " in state " + vmInstance.getState()); @@ -2538,7 +2584,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac _networkModel.getNetworkRate(network.getId(), vm.getId()), _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vmProfile.getVirtualMachine().getHypervisorType(), network)); - + //1) Unplug the nic if (vm.getState() == State.Running) { NicTO nicTO = toNicTO(nicProfile, vmProfile.getVirtualMachine().getHypervisorType()); @@ -2555,11 +2601,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac throw new ResourceUnavailableException("Unable to remove vm " + vm + " from network, is not in the right state", DataCenter.class, vm.getDataCenterId()); } - + //2) Release the nic _networkMgr.releaseNic(vmProfile, nic); s_logger.debug("Successfully released nic " + nic + "for vm " + vm); - + //3) Remove the nic _networkMgr.removeNic(vmProfile, nic); _nicsDao.expunge(nic.getId()); @@ -2594,7 +2640,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.warn("Could not get a nic with " + network); return false; } - + // don't delete default NIC on a user VM if (nic.isDefaultNic() && vm.getType() == VirtualMachine.Type.User ) { s_logger.warn("Failed to remove nic from " + vm + " in " + network + ", nic is default."); @@ -2608,15 +2654,15 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac //1) Unplug the nic if (vm.getState() == State.Running) { - NicTO nicTO = toNicTO(nicProfile, vmProfile.getVirtualMachine().getHypervisorType()); - s_logger.debug("Un-plugging nic for vm " + vm + " from network " + network); - boolean result = vmGuru.unplugNic(network, nicTO, vmTO, context, dest); - if (result) { - s_logger.debug("Nic is unplugged successfully for vm " + vm + " in network " + network ); - } else { - s_logger.warn("Failed to unplug nic for the vm " + vm + " from network " + network); - return false; - } + NicTO nicTO = toNicTO(nicProfile, vmProfile.getVirtualMachine().getHypervisorType()); + s_logger.debug("Un-plugging nic for vm " + vm + " from network " + network); + boolean result = vmGuru.unplugNic(network, nicTO, vmTO, context, dest); + if (result) { + s_logger.debug("Nic is unplugged successfully for vm " + vm + " in network " + network ); + } else { + s_logger.warn("Failed to unplug nic for the vm " + vm + " from network " + network); + return false; + } } else if (vm.getState() != State.Stopped) { s_logger.warn("Unable to remove vm " + vm + " from network " + network); throw new ResourceUnavailableException("Unable to remove vm " + vm + " from network, is not in the right state", diff --git a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java index e83d6a0d926..24f44cb07ac 100644 --- a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + import com.cloud.agent.api.to.VolumeTO; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.ServiceOffering; @@ -42,13 +43,16 @@ public class VirtualMachineProfileImpl implements Virtua T _vm; ServiceOfferingVO _offering; VMTemplateVO _template; + UserVmDetailVO _userVmDetails; Map _params; List _nics = new ArrayList(); List _disks = new ArrayList(); StringBuilder _bootArgs = new StringBuilder(); Account _owner; BootloaderType _bootloader; - + Float cpuOvercommitRatio = 1.0f; + Float memoryOvercommitRatio = 1.0f; + VirtualMachine.Type _type; public VirtualMachineProfileImpl(T vm, VMTemplateVO template, ServiceOfferingVO offering, Account owner, Map params) { @@ -238,6 +242,25 @@ public class VirtualMachineProfileImpl implements Virtua public void setServiceOffering(ServiceOfferingVO offering) { _offering = offering; } - - + + public void setcpuOvercommitRatio(Float cpuOvercommitRatio){ + this.cpuOvercommitRatio= cpuOvercommitRatio; + + } + + public void setramOvercommitRatio(Float memoryOvercommitRatio){ + this.memoryOvercommitRatio= memoryOvercommitRatio; + + } + @Override + public Float getCpuOvercommitRatio(){ + return this.cpuOvercommitRatio; + } + + @Override + public Float getMemoryOvercommitRatio(){ + return this.memoryOvercommitRatio; + } + + } diff --git a/server/src/com/cloud/vm/dao/UserVmDao.java b/server/src/com/cloud/vm/dao/UserVmDao.java index 9fbcde377dd..81d13cda2ed 100755 --- a/server/src/com/cloud/vm/dao/UserVmDao.java +++ b/server/src/com/cloud/vm/dao/UserVmDao.java @@ -70,5 +70,7 @@ public interface UserVmDao extends GenericDao { public Long countAllocatedVMsForAccount(long accountId); Hashtable listVmDetails(Hashtable userVmData); + + List listByIsoId(Long isoId); } diff --git a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java index f2fc10bbaa4..02604fe767b 100755 --- a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java +++ b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java @@ -72,10 +72,11 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use protected SearchBuilder DestroySearch; protected SearchBuilder AccountDataCenterVirtualSearch; protected GenericSearchBuilder CountByAccountPod; - protected GenericSearchBuilder CountByAccount; - protected GenericSearchBuilder PodsHavingVmsForAccount; - - protected SearchBuilder UserVmSearch; + protected GenericSearchBuilder CountByAccount; + protected GenericSearchBuilder PodsHavingVmsForAccount; + + protected SearchBuilder UserVmSearch; + protected SearchBuilder UserVmByIsoSearch; protected Attribute _updateTimeAttr; // ResourceTagsDaoImpl _tagsDao = ComponentLocator.inject(ResourceTagsDaoImpl.class); @Inject ResourceTagsDaoImpl _tagsDao; @@ -194,7 +195,10 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use AccountDataCenterVirtualSearch.and("dc", AccountDataCenterVirtualSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); AccountDataCenterVirtualSearch.join("nicSearch", nicSearch, AccountDataCenterVirtualSearch.entity().getId(), nicSearch.entity().getInstanceId(), JoinBuilder.JoinType.INNER); AccountDataCenterVirtualSearch.done(); - + + UserVmByIsoSearch = createSearchBuilder(); + UserVmByIsoSearch.and("isoId", UserVmByIsoSearch.entity().getIsoId(), SearchCriteria.Op.EQ); + UserVmByIsoSearch.done(); _updateTimeAttr = _allAttributes.get("updateTime"); assert _updateTimeAttr != null : "Couldn't get this updateTime attribute"; @@ -248,13 +252,20 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use public List listByHostId(Long id) { SearchCriteria sc = HostSearch.create(); sc.setParameters("host", id); - - return listBy(sc); - } - - @Override - public List listUpByHostId(Long hostId) { - SearchCriteria sc = HostUpSearch.create(); + + return listBy(sc); + } + + @Override + public List listByIsoId(Long isoId) { + SearchCriteria sc = UserVmByIsoSearch.create(); + sc.setParameters("isoId", isoId); + return listBy(sc); + } + + @Override + public List listUpByHostId(Long hostId) { + SearchCriteria sc = HostUpSearch.create(); sc.setParameters("host", hostId); sc.setParameters("states", new Object[] {State.Destroyed, State.Stopped, State.Expunging}); return listBy(sc); diff --git a/server/src/com/cloud/vm/dao/VMInstanceDao.java b/server/src/com/cloud/vm/dao/VMInstanceDao.java index d34b25726dc..c604027abde 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDao.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDao.java @@ -26,7 +26,6 @@ import com.cloud.utils.fsm.StateDao; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.VirtualMachine.Type; /* @@ -75,6 +74,8 @@ public interface VMInstanceDao extends GenericDao, StateDao< VMInstanceVO findByIdTypes(long id, VirtualMachine.Type... types); + VMInstanceVO findVMByInstanceName(String name); + void updateProxyId(long id, Long proxyId, Date time); List listByHostIdTypes(long hostid, VirtualMachine.Type... types); diff --git a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java index 531c79447b7..7198b7c24e0 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -35,12 +35,9 @@ import org.springframework.stereotype.Component; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; -import com.cloud.host.dao.HostDaoImpl; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.tags.dao.ResourceTagDao; -import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.utils.Pair; - import com.cloud.utils.db.Attribute; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; @@ -80,6 +77,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected SearchBuilder HostIdTypesSearch; protected SearchBuilder HostIdUpTypesSearch; protected SearchBuilder HostUpSearch; + protected SearchBuilder InstanceNameSearch; protected GenericSearchBuilder CountVirtualRoutersByAccount; protected GenericSearchBuilder CountRunningByHost; protected GenericSearchBuilder CountRunningByAccount; @@ -188,6 +186,10 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem HostUpSearch.and("states", HostUpSearch.entity().getState(), Op.IN); HostUpSearch.done(); + InstanceNameSearch = createSearchBuilder(); + InstanceNameSearch.and("instanceName", InstanceNameSearch.entity().getInstanceName(), Op.EQ); + InstanceNameSearch.done(); + CountVirtualRoutersByAccount = createSearchBuilder(Long.class); CountVirtualRoutersByAccount.select(null, Func.COUNT, null); CountVirtualRoutersByAccount.and("account", CountVirtualRoutersByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); @@ -340,6 +342,12 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return findOneIncludingRemovedBy(sc); } + @Override + public VMInstanceVO findVMByInstanceName(String name) { + SearchCriteria sc = InstanceNameSearch.create(); + sc.setParameters("instanceName", name); + return findOneBy(sc); + } @Override public void updateProxyId(long id, Long proxyId, Date time) { diff --git a/core/src/com/cloud/resource/DiskPreparer.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManager.java similarity index 51% rename from core/src/com/cloud/resource/DiskPreparer.java rename to server/src/com/cloud/vm/snapshot/VMSnapshotManager.java index 77b8f7c1b7f..c60900551ee 100644 --- a/core/src/com/cloud/resource/DiskPreparer.java +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManager.java @@ -14,29 +14,34 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.resource; -import com.cloud.storage.VolumeVO; -import com.cloud.template.VirtualMachineTemplate.BootloaderType; -import com.cloud.utils.component.Adapter; +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; -/** - * DiskMounter mounts and unmounts disk for VMs - * to consume. - * - */ -public interface DiskPreparer extends Adapter { - /** - * Mounts a volumeVO and returns a path. - * - * @param vol - * @return - */ - public String mount(String vmName, VolumeVO vol, BootloaderType type); /** - * Unmounts + * Delete all VM snapshots belonging to one VM + * @param id, VM id + * @param type, + * @return true for success, false for failure */ - public boolean unmount(String path); + boolean deleteAllVMSnapshots(long id, VMSnapshot.Type type); + + /** + * Sync VM snapshot state when VM snapshot in reverting or snapshoting or expunging state + * Used for fullsync after agent connects + * + * @param vm, the VM in question + * @param hostId + * @return true if succeeds, false if fails + */ + boolean syncVMSnapshot(VMInstanceVO vm, Long hostId); + + boolean hasActiveVMSnapshotTasks(Long vmId); } diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java new file mode 100644 index 00000000000..01f3dd3afe2 --- /dev/null +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -0,0 +1,836 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.vm.snapshot; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.CreateVMSnapshotAnswer; +import com.cloud.agent.api.CreateVMSnapshotCommand; +import com.cloud.agent.api.DeleteVMSnapshotAnswer; +import com.cloud.agent.api.DeleteVMSnapshotCommand; +import com.cloud.agent.api.RevertToVMSnapshotAnswer; +import com.cloud.agent.api.RevertToVMSnapshotCommand; +import com.cloud.agent.api.VMSnapshotTO; +import com.cloud.agent.api.to.VolumeTO; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.hypervisor.HypervisorGuruManager; +import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.StoragePool; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.UserContext; +import com.cloud.user.UserVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.uservm.UserVm; +import com.cloud.utils.DateUtil; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; + +@Component +@Local(value = { VMSnapshotManager.class, VMSnapshotService.class }) +public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotManager, VMSnapshotService { + private static final Logger s_logger = Logger.getLogger(VMSnapshotManagerImpl.class); + String _name; + @Inject VMSnapshotDao _vmSnapshotDao; + @Inject VolumeDao _volumeDao; + @Inject AccountDao _accountDao; + @Inject VMInstanceDao _vmInstanceDao; + @Inject UserVmDao _userVMDao; + @Inject HostDao _hostDao; + @Inject UserDao _userDao; + @Inject AgentManager _agentMgr; + @Inject HypervisorGuruManager _hvGuruMgr; + @Inject AccountManager _accountMgr; + @Inject GuestOSDao _guestOSDao; + @Inject StoragePoolDao _storagePoolDao; + @Inject SnapshotDao _snapshotDao; + @Inject VirtualMachineManager _itMgr; + @Inject DataStoreManager dataStoreMgr; + @Inject ConfigurationDao _configDao; + int _vmSnapshotMax; + StateMachine2 _vmSnapshottateMachine ; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _name = name; + if (_configDao == null) { + throw new ConfigurationException( + "Unable to get the configuration dao."); + } + + _vmSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("vmsnapshot.max"), VMSNAPSHOTMAX); + + _vmSnapshottateMachine = VMSnapshot.State.getStateMachine(); + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public List listVMSnapshots(ListVMSnapshotCmd cmd) { + Account caller = getCaller(); + List permittedAccounts = new ArrayList(); + + 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 domainIdRecursiveListProject = new Ternary( + 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 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 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 ssc = _vmSnapshotDao.createSearchCriteria(); + ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + ssc.addOr("display_name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + ssc.addOr("description", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + sc.addAnd("name", SearchCriteria.Op.SC, ssc); + } + + if (id != null) { + sc.setParameters("id", id); + } + + return _vmSnapshotDao.search(sc, searchFilter); + + } + + protected Account getCaller(){ + return UserContext.current().getCaller(); + } + + @Override + public VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDescription, Boolean snapshotMemory) + throws ResourceAllocationException { + + Account caller = getCaller(); + + // check if VM exists + UserVmVO userVmVo = _userVMDao.findById(vmId); + if (userVmVo == null) { + throw new InvalidParameterValueException("Creating VM snapshot failed due to VM:" + vmId + " is a system VM or does not exist"); + } + + // parameter length check + if(vsDisplayName != null && vsDisplayName.length()>255) + throw new InvalidParameterValueException("Creating VM snapshot failed due to length of VM snapshot vsDisplayName should not exceed 255"); + if(vsDescription != null && vsDescription.length()>255) + throw new InvalidParameterValueException("Creating VM snapshot failed due to length of VM snapshot vsDescription should not exceed 255"); + + // VM snapshot display name must be unique for a VM + String timeString = DateUtil.getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(), DateUtil.YYYYMMDD_FORMAT); + String vmSnapshotName = userVmVo.getInstanceName() + "_VS_" + timeString; + if (vsDisplayName == null) { + vsDisplayName = vmSnapshotName; + } + if(_vmSnapshotDao.findByName(vmId,vsDisplayName) != null){ + throw new InvalidParameterValueException("Creating VM snapshot failed due to VM snapshot with name" + vsDisplayName + " already exists"); + } + + // check VM state + if (userVmVo.getState() != VirtualMachine.State.Running && userVmVo.getState() != VirtualMachine.State.Stopped) { + throw new InvalidParameterValueException("Creating vm snapshot failed due to VM:" + vmId + " is not in the running or Stopped state"); + } + + if(snapshotMemory && userVmVo.getState() == VirtualMachine.State.Stopped){ + throw new InvalidParameterValueException("Can not snapshot memory when VM is in stopped state"); + } + + // for KVM, only allow snapshot with memory when VM is in running state + if(userVmVo.getHypervisorType() == HypervisorType.KVM && userVmVo.getState() == State.Running && !snapshotMemory){ + throw new InvalidParameterValueException("KVM VM does not allow to take a disk-only snapshot when VM is in running state"); + } + + // check access + _accountMgr.checkAccess(caller, null, true, userVmVo); + + // check max snapshot limit for per VM + if (_vmSnapshotDao.findByVm(vmId).size() >= _vmSnapshotMax) { + throw new CloudRuntimeException("Creating vm snapshot failed due to a VM can just have : " + _vmSnapshotMax + + " VM snapshots. Please delete old ones"); + } + + // check if there are active volume snapshots tasks + List listVolumes = _volumeDao.findByInstance(vmId); + for (VolumeVO volume : listVolumes) { + List activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating, + Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp); + if (activeSnapshots.size() > 0) { + throw new CloudRuntimeException( + "There is other active volume snapshot tasks on the instance to which the volume is attached, please try again later."); + } + } + + // check if there are other active VM snapshot tasks + if (hasActiveVMSnapshotTasks(vmId)) { + throw new CloudRuntimeException("There is other active vm snapshot tasks on the instance, please try again later"); + } + + VMSnapshot.Type vmSnapshotType = VMSnapshot.Type.Disk; + if(snapshotMemory && userVmVo.getState() == VirtualMachine.State.Running) + vmSnapshotType = VMSnapshot.Type.DiskAndMemory; + + try { + VMSnapshotVO vmSnapshotVo = new VMSnapshotVO(userVmVo.getAccountId(), userVmVo.getDomainId(), vmId, vsDescription, vmSnapshotName, + vsDisplayName, userVmVo.getServiceOfferingId(), vmSnapshotType, null); + VMSnapshot vmSnapshot = _vmSnapshotDao.persist(vmSnapshotVo); + if (vmSnapshot == null) { + throw new CloudRuntimeException("Failed to create snapshot for vm: " + vmId); + } + return vmSnapshot; + } catch (Exception e) { + String msg = e.getMessage(); + s_logger.error("Create vm snapshot record failed for vm: " + vmId + " due to: " + msg); + } + return null; + } + + @Override + public String getName() { + return _name; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_CREATE, eventDescription = "creating VM snapshot", async = true) + public VMSnapshot creatVMSnapshot(Long vmId, Long vmSnapshotId) { + UserVmVO userVm = _userVMDao.findById(vmId); + if (userVm == null) { + throw new InvalidParameterValueException("Create vm to snapshot failed due to vm: " + vmId + " is not found"); + } + VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId); + if(vmSnapshot == null){ + throw new CloudRuntimeException("VM snapshot id: " + vmSnapshotId + " can not be found"); + } + Long hostId = pickRunningHost(vmId); + try { + vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.CreateRequested); + } catch (NoTransitionException e) { + throw new CloudRuntimeException(e.getMessage()); + } + return createVmSnapshotInternal(userVm, vmSnapshot, hostId); + } + + protected VMSnapshot createVmSnapshotInternal(UserVmVO userVm, VMSnapshotVO vmSnapshot, Long hostId) { + try { + CreateVMSnapshotAnswer answer = null; + GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId()); + + // prepare snapshotVolumeTos + List volumeTOs = getVolumeTOList(userVm.getId()); + + // prepare target snapshotTO and its parent snapshot (current snapshot) + VMSnapshotTO current = null; + VMSnapshotVO currentSnapshot = _vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId()); + if (currentSnapshot != null) + current = getSnapshotWithParents(currentSnapshot); + VMSnapshotTO target = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(), null, vmSnapshot.getDescription(), false, + current); + if (current == null) + vmSnapshot.setParent(null); + else + vmSnapshot.setParent(current.getId()); + + CreateVMSnapshotCommand ccmd = new CreateVMSnapshotCommand(userVm.getInstanceName(),target ,volumeTOs, guestOS.getDisplayName(),userVm.getState()); + + answer = (CreateVMSnapshotAnswer) sendToPool(hostId, ccmd); + if (answer != null && answer.getResult()) { + processAnswer(vmSnapshot, userVm, answer, hostId); + s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName()); + }else{ + String errMsg = answer.getDetails(); + s_logger.error("Agent reports creating vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + errMsg); + vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed); + } + return vmSnapshot; + } catch (Exception e) { + if(e instanceof AgentUnavailableException){ + try { + vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed); + } catch (NoTransitionException e1) { + s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage()); + } + } + String msg = e.getMessage(); + s_logger.error("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + msg); + throw new CloudRuntimeException(msg); + } finally{ + if(vmSnapshot.getState() == VMSnapshot.State.Allocated){ + s_logger.warn("Create vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName()); + _vmSnapshotDao.remove(vmSnapshot.getId()); + } + } + } + + protected List getVolumeTOList(Long vmId) { + List volumeTOs = new ArrayList(); + List volumeVos = _volumeDao.findByInstance(vmId); + + for (VolumeVO volume : volumeVos) { + StoragePool pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(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 snapshotMap = new HashMap(); + List allSnapshots = _vmSnapshotDao.findByVm(snapshot.getVmId()); + for (VMSnapshotVO vmSnapshotVO : allSnapshots) { + snapshotMap.put(vmSnapshotVO.getId(), vmSnapshotVO); + } + + VMSnapshotTO currentTO = convert2VMSnapshotTO(snapshot); + VMSnapshotTO result = currentTO; + VMSnapshotVO current = snapshot; + while (current.getParent() != null) { + VMSnapshotVO parent = snapshotMap.get(current.getParent()); + currentTO.setParent(convert2VMSnapshotTO(parent)); + current = snapshotMap.get(current.getParent()); + currentTO = currentTO.getParent(); + } + return result; + } + + private VMSnapshotTO convert2VMSnapshotTO(VMSnapshotVO vo) { + return new VMSnapshotTO(vo.getId(), vo.getName(), vo.getType(), vo.getCreated().getTime(), vo.getDescription(), + vo.getCurrent(), null); + } + + protected boolean vmSnapshotStateTransitTo(VMSnapshotVO vsnp, VMSnapshot.Event event) throws NoTransitionException { + return _vmSnapshottateMachine.transitTo(vsnp, event, null, _vmSnapshotDao); + } + + @DB + protected void processAnswer(VMSnapshotVO vmSnapshot, UserVmVO userVm, Answer as, Long hostId) { + final Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + if (as instanceof CreateVMSnapshotAnswer) { + CreateVMSnapshotAnswer answer = (CreateVMSnapshotAnswer) as; + finalizeCreate(vmSnapshot, answer.getVolumeTOs()); + vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded); + } else if (as instanceof RevertToVMSnapshotAnswer) { + RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) as; + finalizeRevert(vmSnapshot, answer.getVolumeTOs()); + vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationSucceeded); + } else if (as instanceof DeleteVMSnapshotAnswer) { + DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) as; + finalizeDelete(vmSnapshot, answer.getVolumeTOs()); + _vmSnapshotDao.remove(vmSnapshot.getId()); + } + txn.commit(); + } catch (Exception e) { + String errMsg = "Error while process answer: " + as.getClass() + " due to " + e.getMessage(); + s_logger.error(errMsg, e); + txn.rollback(); + throw new CloudRuntimeException(errMsg); + } finally { + txn.close(); + } + } + + protected void finalizeDelete(VMSnapshotVO vmSnapshot, List VolumeTOs) { + // update volumes path + updateVolumePath(VolumeTOs); + + // update children's parent snapshots + List 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 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 volumeToList) { + // update volumes path + updateVolumePath(volumeToList); + + // update current snapshot, current snapshot is the one reverted to + VMSnapshotVO previousCurrent = _vmSnapshotDao.findCurrentSnapshotByVmId(vmSnapshot.getVmId()); + if(previousCurrent != null){ + previousCurrent.setCurrent(false); + _vmSnapshotDao.persist(previousCurrent); + } + vmSnapshot.setCurrent(true); + _vmSnapshotDao.persist(vmSnapshot); + } + + private void updateVolumePath(List volumeTOs) { + for (VolumeTO volume : volumeTOs) { + if (volume.getPath() != null) { + VolumeVO volumeVO = _volumeDao.findById(volume.getId()); + volumeVO.setPath(volume.getPath()); + _volumeDao.persist(volumeVO); + } + } + } + + public VMSnapshotManagerImpl() { + + } + + protected Answer sendToPool(Long hostId, Command cmd) throws AgentUnavailableException, OperationTimedoutException { + long targetHostId = _hvGuruMgr.getGuruProcessedCommandTargetHost(hostId, cmd); + Answer answer = _agentMgr.send(targetHostId, cmd); + return answer; + } + + @Override + public boolean hasActiveVMSnapshotTasks(Long vmId){ + List activeVMSnapshots = _vmSnapshotDao.listByInstanceId(vmId, + VMSnapshot.State.Creating, VMSnapshot.State.Expunging,VMSnapshot.State.Reverting,VMSnapshot.State.Allocated); + return activeVMSnapshots.size() > 0; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_DELETE, eventDescription = "delete vm snapshots", async=true) + public boolean deleteVMSnapshot(Long vmSnapshotId) { + Account caller = getCaller(); + + VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId); + if (vmSnapshot == null) { + throw new InvalidParameterValueException("unable to find the vm snapshot with id " + vmSnapshotId); + } + + _accountMgr.checkAccess(caller, null, true, vmSnapshot); + + // check VM snapshot states, only allow to delete vm snapshots in created and error state + if (VMSnapshot.State.Ready != vmSnapshot.getState() && VMSnapshot.State.Expunging != vmSnapshot.getState() && VMSnapshot.State.Error != vmSnapshot.getState()) { + throw new InvalidParameterValueException("Can't delete the vm snapshotshot " + vmSnapshotId + " due to it is not in Created or Error, or Expunging State"); + } + + // check if there are other active VM snapshot tasks + if (hasActiveVMSnapshotTasks(vmSnapshot.getVmId())) { + List expungingSnapshots = _vmSnapshotDao.listByInstanceId(vmSnapshot.getVmId(), VMSnapshot.State.Expunging); + if(expungingSnapshots.size() > 0 && expungingSnapshots.get(0).getId() == vmSnapshot.getId()) + s_logger.debug("Target VM snapshot already in expunging state, go on deleting it: " + vmSnapshot.getDisplayName()); + else + throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later"); + } + + if(vmSnapshot.getState() == VMSnapshot.State.Allocated){ + return _vmSnapshotDao.remove(vmSnapshot.getId()); + }else{ + return deleteSnapshotInternal(vmSnapshot); + } + } + + @DB + protected boolean deleteSnapshotInternal(VMSnapshotVO vmSnapshot) { + UserVmVO userVm = _userVMDao.findById(vmSnapshot.getVmId()); + + try { + vmSnapshotStateTransitTo(vmSnapshot,VMSnapshot.Event.ExpungeRequested); + Long hostId = pickRunningHost(vmSnapshot.getVmId()); + + // prepare snapshotVolumeTos + List volumeTOs = getVolumeTOList(vmSnapshot.getVmId()); + + // prepare DeleteVMSnapshotCommand + String vmInstanceName = userVm.getInstanceName(); + VMSnapshotTO parent = getSnapshotWithParents(vmSnapshot).getParent(); + VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(vmSnapshot.getId(), vmSnapshot.getName(), vmSnapshot.getType(), + vmSnapshot.getCreated().getTime(), vmSnapshot.getDescription(), vmSnapshot.getCurrent(), parent); + GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId()); + DeleteVMSnapshotCommand deleteSnapshotCommand = new DeleteVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs,guestOS.getDisplayName()); + + DeleteVMSnapshotAnswer answer = (DeleteVMSnapshotAnswer) sendToPool(hostId, deleteSnapshotCommand); + + if (answer != null && answer.getResult()) { + processAnswer(vmSnapshot, userVm, answer, hostId); + s_logger.debug("Delete VM snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName()); + return true; + } else { + s_logger.error("Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + answer.getDetails()); + return false; + } + } catch (Exception e) { + String msg = "Delete vm snapshot " + vmSnapshot.getName() + " of vm " + userVm.getInstanceName() + " failed due to " + e.getMessage(); + s_logger.error(msg , e); + throw new CloudRuntimeException(e.getMessage()); + } + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_REVERT, eventDescription = "revert to VM snapshot", async = true) + public UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException { + + // check if VM snapshot exists in DB + VMSnapshotVO vmSnapshotVo = _vmSnapshotDao.findById(vmSnapshotId); + if (vmSnapshotVo == null) { + throw new InvalidParameterValueException( + "unable to find the vm snapshot with id " + vmSnapshotId); + } + Long vmId = vmSnapshotVo.getVmId(); + UserVmVO userVm = _userVMDao.findById(vmId); + // check if VM exists + if (userVm == null) { + throw new InvalidParameterValueException("Revert vm to snapshot: " + + vmSnapshotId + " failed due to vm: " + vmId + + " is not found"); + } + + // check if there are other active VM snapshot tasks + if (hasActiveVMSnapshotTasks(vmId)) { + throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later"); + } + + Account caller = getCaller(); + _accountMgr.checkAccess(caller, null, true, vmSnapshotVo); + + // VM should be in running or stopped states + if (userVm.getState() != VirtualMachine.State.Running + && userVm.getState() != VirtualMachine.State.Stopped) { + throw new InvalidParameterValueException( + "VM Snapshot reverting failed due to vm is not in the state of Running or Stopped."); + } + + // if snapshot is not created, error out + if (vmSnapshotVo.getState() != VMSnapshot.State.Ready) { + throw new InvalidParameterValueException( + "VM Snapshot reverting failed due to vm snapshot is not in the state of Created."); + } + + UserVO callerUser = _userDao.findById(UserContext.current().getCallerUserId()); + + UserVmVO vm = null; + Long hostId = null; + Account owner = _accountDao.findById(vmSnapshotVo.getAccountId()); + + // start or stop VM first, if revert from stopped state to running state, or from running to stopped + if(userVm.getState() == VirtualMachine.State.Stopped && vmSnapshotVo.getType() == VMSnapshot.Type.DiskAndMemory){ + try { + vm = _itMgr.advanceStart(userVm, new HashMap(), callerUser, owner); + hostId = vm.getHostId(); + } catch (Exception e) { + s_logger.error("Start VM " + userVm.getInstanceName() + " before reverting failed due to " + e.getMessage()); + throw new CloudRuntimeException(e.getMessage()); + } + }else { + if(userVm.getState() == VirtualMachine.State.Running && vmSnapshotVo.getType() == VMSnapshot.Type.Disk){ + try { + _itMgr.advanceStop(userVm, true, callerUser, owner); + } catch (Exception e) { + s_logger.error("Stop VM " + userVm.getInstanceName() + " before reverting failed due to " + e.getMessage()); + throw new CloudRuntimeException(e.getMessage()); + } + } + hostId = pickRunningHost(userVm.getId()); + } + + if(hostId == null) + throw new CloudRuntimeException("Can not find any host to revert snapshot " + vmSnapshotVo.getName()); + + // check if there are other active VM snapshot tasks + if (hasActiveVMSnapshotTasks(userVm.getId())) { + throw new InvalidParameterValueException("There is other active vm snapshot tasks on the instance, please try again later"); + } + + userVm = _userVMDao.findById(userVm.getId()); + try { + vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.RevertRequested); + } catch (NoTransitionException e) { + throw new CloudRuntimeException(e.getMessage()); + } + return revertInternal(userVm, vmSnapshotVo, hostId); + } + + private UserVm revertInternal(UserVmVO userVm, VMSnapshotVO vmSnapshotVo, Long hostId) { + try { + VMSnapshotVO snapshot = _vmSnapshotDao.findById(vmSnapshotVo.getId()); + // prepare RevertToSnapshotCommand + List volumeTOs = getVolumeTOList(userVm.getId()); + String vmInstanceName = userVm.getInstanceName(); + VMSnapshotTO parent = getSnapshotWithParents(snapshot).getParent(); + VMSnapshotTO vmSnapshotTO = new VMSnapshotTO(snapshot.getId(), snapshot.getName(), snapshot.getType(), + snapshot.getCreated().getTime(), snapshot.getDescription(), snapshot.getCurrent(), parent); + + GuestOSVO guestOS = _guestOSDao.findById(userVm.getGuestOSId()); + RevertToVMSnapshotCommand revertToSnapshotCommand = new RevertToVMSnapshotCommand(vmInstanceName, vmSnapshotTO, volumeTOs, guestOS.getDisplayName()); + + RevertToVMSnapshotAnswer answer = (RevertToVMSnapshotAnswer) sendToPool(hostId, revertToSnapshotCommand); + if (answer != null && answer.getResult()) { + processAnswer(vmSnapshotVo, userVm, answer, hostId); + s_logger.debug("RevertTo " + vmSnapshotVo.getName() + " succeeded for vm: " + userVm.getInstanceName()); + } else { + String errMsg = "Revert VM: " + userVm.getInstanceName() + " to snapshot: "+ vmSnapshotVo.getName() + " failed"; + if(answer != null && answer.getDetails() != null) + errMsg = errMsg + " due to " + answer.getDetails(); + s_logger.error(errMsg); + // agent report revert operation fails + vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed); + throw new CloudRuntimeException(errMsg); + } + } catch (Exception e) { + if(e instanceof AgentUnavailableException){ + try { + vmSnapshotStateTransitTo(vmSnapshotVo, VMSnapshot.Event.OperationFailed); + } catch (NoTransitionException e1) { + s_logger.error("Cannot set vm snapshot state due to: " + e1.getMessage()); + } + } + // for other exceptions, do not change VM snapshot state, leave it for snapshotSync + String errMsg = "revert vm: " + userVm.getInstanceName() + " to snapshot " + vmSnapshotVo.getName() + " failed due to " + e.getMessage(); + s_logger.error(errMsg); + throw new CloudRuntimeException(e.getMessage()); + } + return userVm; + } + + + @Override + public VMSnapshot getVMSnapshotById(Long id) { + VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id); + return vmSnapshot; + } + + protected Long pickRunningHost(Long vmId) { + UserVmVO vm = _userVMDao.findById(vmId); + // use VM's host if VM is running + if(vm.getState() == State.Running) + return vm.getHostId(); + + // check if lastHostId is available + if(vm.getLastHostId() != null){ + HostVO lastHost = _hostDao.findById(vm.getLastHostId()); + if(lastHost.getStatus() == com.cloud.host.Status.Up && !lastHost.isInMaintenanceStates()) + return lastHost.getId(); + } + + List 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 listHost = _hostDao.listAllUpAndEnabledNonHAHosts(Host.Type.Routing, storagePool.getClusterId(), storagePool.getPodId(), + storagePool.getDataCenterId(), null); + if (listHost == null || listHost.size() == 0) { + throw new InvalidParameterValueException("no host in up state is found"); + } + return listHost.get(0).getId(); + } + + @Override + public VirtualMachine getVMBySnapshotId(Long id) { + VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(id); + if(vmSnapshot == null){ + throw new InvalidParameterValueException("unable to find the vm snapshot with id " + id); + } + Long vmId = vmSnapshot.getVmId(); + UserVmVO vm = _userVMDao.findById(vmId); + return vm; + } + + @Override + public boolean deleteAllVMSnapshots(long vmId, VMSnapshot.Type type) { + boolean result = true; + List listVmSnapshots = _vmSnapshotDao.findByVm(vmId); + if (listVmSnapshots == null || listVmSnapshots.isEmpty()) { + return true; + } + for (VMSnapshotVO snapshot : listVmSnapshots) { + VMSnapshotVO target = _vmSnapshotDao.findById(snapshot.getId()); + if(type != null && target.getType() != type) + continue; + if (!deleteSnapshotInternal(target)) { + result = false; + break; + } + } + return result; + } + + @Override + public boolean syncVMSnapshot(VMInstanceVO vm, Long hostId) { + try{ + + UserVmVO userVm = _userVMDao.findById(vm.getId()); + if(userVm == null) + return false; + + List vmSnapshotsInExpungingStates = _vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging, VMSnapshot.State.Reverting, VMSnapshot.State.Creating); + for (VMSnapshotVO vmSnapshotVO : vmSnapshotsInExpungingStates) { + if(vmSnapshotVO.getState() == VMSnapshot.State.Expunging){ + return deleteSnapshotInternal(vmSnapshotVO); + }else if(vmSnapshotVO.getState() == VMSnapshot.State.Creating){ + return createVmSnapshotInternal(userVm, vmSnapshotVO, hostId) != null; + }else if(vmSnapshotVO.getState() == VMSnapshot.State.Reverting){ + return revertInternal(userVm, vmSnapshotVO, hostId) != null; + } + } + }catch (Exception e) { + s_logger.error(e.getMessage(),e); + if(_vmSnapshotDao.listByInstanceId(vm.getId(), VMSnapshot.State.Expunging).size() == 0) + return true; + else + return false; + } + return false; + } + +} diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotVO.java b/server/src/com/cloud/vm/snapshot/VMSnapshotVO.java new file mode 100644 index 00000000000..03d4945fda0 --- /dev/null +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotVO.java @@ -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; + } +} diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/HypervisorBasedSnapshot.java b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java similarity index 54% rename from engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/HypervisorBasedSnapshot.java rename to server/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java index 7f18200cd3d..7532edf03f7 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/HypervisorBasedSnapshot.java +++ b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java @@ -14,31 +14,26 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.storage.snapshot.strategy; +package com.cloud.vm.snapshot.dao; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.snapshot.SnapshotStrategy; -import org.springframework.stereotype.Component; +import java.util.List; -@Component -public class HypervisorBasedSnapshot implements SnapshotStrategy { +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.VMSnapshotVO; - @Override - public boolean takeSnapshot(SnapshotInfo snapshot) { - // TODO Auto-generated method stub - return false; - } +public interface VMSnapshotDao extends GenericDao, StateDao { - @Override - public boolean revertSnapshot(SnapshotInfo snapshot) { - // TODO Auto-generated method stub - return false; - } + List findByVm(Long vmId); - @Override - public boolean deleteSnapshot(SnapshotInfo snapshot) { - // TODO Auto-generated method stub - return false; - } + List listExpungingSnapshot(); + List listByInstanceId(Long vmId, VMSnapshot.State... status); + + VMSnapshotVO findCurrentSnapshotByVmId(Long vmId); + + List listByParent(Long vmSnapshotId); + + VMSnapshotVO findByName(Long vm_id, String name); } diff --git a/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java new file mode 100644 index 00000000000..7d8ace7f82d --- /dev/null +++ b/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java @@ -0,0 +1,161 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.vm.snapshot.dao; + +import java.util.Date; +import java.util.List; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.UpdateBuilder; +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.VMSnapshot.Event; +import com.cloud.vm.snapshot.VMSnapshot.State; +import com.cloud.vm.snapshot.VMSnapshotVO; +@Component +@Local(value = { VMSnapshotDao.class }) +public class VMSnapshotDaoImpl extends GenericDaoBase + implements VMSnapshotDao { + private static final Logger s_logger = Logger.getLogger(VMSnapshotDaoImpl.class); + private final SearchBuilder SnapshotSearch; + private final SearchBuilder ExpungingSnapshotSearch; + private final SearchBuilder SnapshotStatusSearch; + private final SearchBuilder 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 findByVm(Long vmId) { + SearchCriteria sc = SnapshotSearch.create(); + sc.setParameters("vm_id", vmId); + return listBy(sc, null); + } + + @Override + public List listExpungingSnapshot() { + SearchCriteria sc = ExpungingSnapshotSearch.create(); + sc.setParameters("state", State.Expunging); + return listBy(sc, null); + } + + @Override + public List listByInstanceId(Long vmId, State... status) { + SearchCriteria sc = SnapshotStatusSearch.create(); + sc.setParameters("vm_id", vmId); + sc.setParameters("state", (Object[]) status); + return listBy(sc, null); + } + + @Override + public VMSnapshotVO findCurrentSnapshotByVmId(Long vmId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vm_id", vmId); + sc.setParameters("current", 1); + return findOneBy(sc); + } + + @Override + public List listByParent(Long vmSnapshotId) { + SearchCriteria 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 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 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; + } + +} diff --git a/server/test/com/cloud/api/APITest.java b/server/test/com/cloud/api/APITest.java index 0b040abc3f5..63e08719f4b 100644 --- a/server/test/com/cloud/api/APITest.java +++ b/server/test/com/cloud/api/APITest.java @@ -36,8 +36,6 @@ import com.google.gson.Gson; /** * Base class for API Test * - * @author Min Chen - * */ public abstract class APITest { diff --git a/server/test/com/cloud/api/ListPerfTest.java b/server/test/com/cloud/api/ListPerfTest.java index b8cb97eb8f0..8437ca42770 100644 --- a/server/test/com/cloud/api/ListPerfTest.java +++ b/server/test/com/cloud/api/ListPerfTest.java @@ -33,8 +33,6 @@ import com.cloud.utils.exception.CloudRuntimeException; * Test fixture to do performance test for list command * Currently we commented out this test suite since it requires a real MS and Db running. * - * @author Min Chen - * */ public class ListPerfTest extends APITest { diff --git a/server/test/com/cloud/api/LoginResponse.java b/server/test/com/cloud/api/LoginResponse.java index 097ae42c999..0f58374f187 100644 --- a/server/test/com/cloud/api/LoginResponse.java +++ b/server/test/com/cloud/api/LoginResponse.java @@ -24,8 +24,6 @@ import com.google.gson.annotations.SerializedName; /** * Login Response object * - * @author Min Chen - * */ public class LoginResponse extends BaseResponse { diff --git a/server/test/com/cloud/capacity/CapacityManagerTest.java b/server/test/com/cloud/capacity/CapacityManagerTest.java new file mode 100644 index 00000000000..3faa32f0f6d --- /dev/null +++ b/server/test/com/cloud/capacity/CapacityManagerTest.java @@ -0,0 +1,78 @@ +// 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.capacity; +import com.cloud.capacity.dao.CapacityDao; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.vm.UserVmDetailVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.dao.UserVmDetailsDao; +import org.apache.log4j.Logger; +import org.junit.*; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.mockito.Mockito.*; + + +public class CapacityManagerTest { + CapacityDao CDao = mock(CapacityDao.class); + ServiceOfferingDao SOfferingDao = mock(ServiceOfferingDao.class); + ClusterDetailsDao ClusterDetailsDao= mock(com.cloud.dc.ClusterDetailsDao.class); + CapacityManagerImpl capMgr; + private ServiceOfferingVO svo = mock(ServiceOfferingVO.class); + private CapacityVO cvo_cpu = mock(CapacityVO.class); + private CapacityVO cvo_ram = mock(CapacityVO.class); + private VirtualMachine vm = mock(VirtualMachine.class); + private ClusterDetailsVO cluster_detail_cpu = mock(ClusterDetailsVO.class); + private ClusterDetailsVO cluster_detail_ram = mock(ClusterDetailsVO.class); + + public CapacityManagerImpl setUp() { + CapacityManagerImpl capMgr = new CapacityManagerImpl(); + ((CapacityManagerImpl)capMgr)._clusterDetailsDao= ClusterDetailsDao; + capMgr._capacityDao = CDao; + capMgr._offeringsDao = SOfferingDao; + return capMgr; + } + + @Test + public void allocateCapacityTest(){ + capMgr=setUp(); + when(vm.getHostId()).thenReturn(1l); + when(vm.getServiceOfferingId()).thenReturn(2l); + when(SOfferingDao.findById(anyLong())).thenReturn(svo); + when(CDao.findByHostIdType(anyLong(), eq(Capacity.CAPACITY_TYPE_CPU))).thenReturn(cvo_cpu); + when(CDao.findByHostIdType(anyLong(), eq(Capacity.CAPACITY_TYPE_MEMORY))).thenReturn(cvo_ram); + when(cvo_cpu.getUsedCapacity()).thenReturn(500l); + when(cvo_cpu.getTotalCapacity()).thenReturn(2000l); + when(cvo_ram.getUsedCapacity()).thenReturn(3000l); + when(cvo_ram.getTotalCapacity()).thenReturn((long) 1024*1024*1024); + when(svo.getCpu()).thenReturn(500); + when(svo.getRamSize()).thenReturn(512); + when(cvo_cpu.getReservedCapacity()).thenReturn(0l); + when(cvo_ram.getReservedCapacity()).thenReturn(0l); + when(cluster_detail_ram.getValue()).thenReturn("1.5"); + when(cluster_detail_cpu.getValue()).thenReturn("2"); + when(CDao.update(anyLong(), isA(CapacityVO.class))).thenReturn(true) ; + boolean hasCapacity=capMgr.checkIfHostHasCapacity(1l,500,1024*1024*1024,false,2,2,false); + Assert.assertTrue(hasCapacity); + + } +} diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 4a24f9a8fcf..3568da57b71 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -569,7 +569,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage */ @Override public Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr) { + User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr) { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/network/MockNetworkModelImpl.java b/server/test/com/cloud/network/MockNetworkModelImpl.java index a2bef63d539..d7ffa7da280 100644 --- a/server/test/com/cloud/network/MockNetworkModelImpl.java +++ b/server/test/com/cloud/network/MockNetworkModelImpl.java @@ -829,4 +829,10 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { // TODO Auto-generated method stub } + + @Override + public void checkRequestedIpAddresses(long networkId, String ip4, String ip6) + throws InvalidParameterValueException { + // TODO Auto-generated method stub + } } diff --git a/server/test/com/cloud/resource/MockResourceManagerImpl.java b/server/test/com/cloud/resource/MockResourceManagerImpl.java index 889318bcd46..1d851a037d4 100644 --- a/server/test/com/cloud/resource/MockResourceManagerImpl.java +++ b/server/test/com/cloud/resource/MockResourceManagerImpl.java @@ -53,8 +53,10 @@ import com.cloud.storage.S3; import com.cloud.storage.Swift; import com.cloud.template.VirtualMachineTemplate; import com.cloud.utils.Pair; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.component.Manager; + + import com.cloud.utils.fsm.NoTransitionException; @Local(value = {ResourceManager.class}) @@ -111,7 +113,7 @@ public class MockResourceManagerImpl extends ManagerBase implements ResourceMana */ @Override public Cluster updateCluster(Cluster cluster, String clusterType, String hypervisor, String allocationState, - String managedstate) { + String managedstate, Float memoryOvercommitRaito, Float cpuOvercommitRatio) { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java b/server/test/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java new file mode 100644 index 00000000000..d311ad38170 --- /dev/null +++ b/server/test/com/cloud/resourcelimit/ResourceLimitManagerImplTest.java @@ -0,0 +1,92 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// 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.resourcelimit; + +import javax.inject.Inject; + +import junit.framework.TestCase; + +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.cloud.configuration.ResourceLimit; +import com.cloud.vpc.MockResourceLimitManagerImpl; + +public class ResourceLimitManagerImplTest extends TestCase{ + private static final Logger s_logger = Logger.getLogger(ResourceLimitManagerImplTest.class); + + MockResourceLimitManagerImpl _resourceLimitService = new MockResourceLimitManagerImpl(); + + @Override + @Before + public void setUp() { + + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testInjected() throws Exception { + s_logger.info("Starting test for Resource Limit manager"); + updateResourceCount(); + updateResourceLimit(); + //listResourceLimits(); + s_logger.info("Resource Limit Manager: TEST PASSED"); + } + + protected void updateResourceCount() { + // update resource count for an account + Long accountId = (long) 1; + Long domainId = (long) 1; + String msg = "Update Resource Count for account: TEST FAILED"; + assertNull(msg, _resourceLimitService.recalculateResourceCount(accountId, domainId, null)); + + // update resource count for a domain + accountId = null; + msg = "Update Resource Count for domain: TEST FAILED"; + assertNull(msg, _resourceLimitService.recalculateResourceCount(accountId, domainId, null)); + } + + protected void updateResourceLimit() { + // update resource Limit for an account for resource_type = 8 (CPU) + resourceLimitServiceCall((long) 1, (long) 1, 8, (long) 20); + + // update resource Limit for a domain for resource_type = 8 (CPU) + resourceLimitServiceCall(null, (long) 1, 8, (long) 40); + + // update resource Limit for an account for resource_type = 9 (Memory) + resourceLimitServiceCall((long) 1, (long) 1, 9, (long) 4096); + + // update resource Limit for a domain for resource_type = 9 (Memory) + resourceLimitServiceCall(null, (long) 1, 9, (long) 10240); + } + + private void resourceLimitServiceCall(Long accountId, Long domainId, Integer resourceType, Long max) { + String msg = "Update Resource Limit: TEST FAILED"; + ResourceLimit result = null; + try { + result = _resourceLimitService.updateResourceLimit(accountId, domainId, resourceType, max); + assertFalse(msg, (result != null || (result == null && max != null && max.longValue() == -1L))); + } catch (Exception ex) { + fail(msg); + } + } +} \ No newline at end of file diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index 1ee627fb738..09825a8eeb6 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -25,7 +25,6 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; @@ -40,8 +39,6 @@ import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; import org.springframework.stereotype.Component; import com.cloud.agent.api.StopAnswer; @@ -69,7 +66,6 @@ import com.cloud.offering.ServiceOffering; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.server.Criteria; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -155,11 +151,6 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override - public boolean attachISOToVM(long vmId, long isoId, boolean attach) { - // TODO Auto-generated method stub - return false; - } @Override public boolean stopVirtualMachine(long userId, long vmId) { @@ -209,12 +200,6 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override - public String getChecksum(Long hostId, String templatePath) { - // TODO Auto-generated method stub - return null; - } - @Override public boolean configure(String name, Map params) throws ConfigurationException { return true; @@ -255,24 +240,6 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override - public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException { - // TODO Auto-generated method stub - return null; - } - - @Override - public Volume attachVolumeToVM(AttachVolumeCmd cmd) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) { - // TODO Auto-generated method stub - return null; - } - @Override public UserVm startVirtualMachine(StartVMCmd cmd) throws StorageUnavailableException, ExecutionException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException { @@ -316,18 +283,6 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override - public VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { - // TODO Auto-generated method stub - return null; - } - - @Override - public VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd cmd) { - // TODO Auto-generated method stub - return null; - } - @Override public UserVm startVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { // TODO Auto-generated method stub @@ -469,4 +424,9 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return false; } + @Override + public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java new file mode 100755 index 00000000000..0795a359fdd --- /dev/null +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -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; + +import java.util.List; + +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.log4j.Logger; +import org.junit.Test; +import org.junit.Before; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +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.storage.StorageManager; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.UserVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.dao.UserVmDao; + +import static org.mockito.Mockito.*; + +public class UserVmManagerTest { + + @Spy UserVmManagerImpl _userVmMgr = new UserVmManagerImpl(); + @Mock VirtualMachineManager _itMgr; + @Mock VolumeManager _storageMgr; + @Mock Account _account; + @Mock AccountManager _accountMgr; + @Mock AccountDao _accountDao; + @Mock UserDao _userDao; + @Mock UserVmDao _vmDao; + @Mock VMTemplateDao _templateDao; + @Mock VolumeDao _volsDao; + @Mock RestoreVMCmd _restoreVMCmd; + @Mock AccountVO _accountMock; + @Mock UserVO _userMock; + @Mock UserVmVO _vmMock; + @Mock VMTemplateVO _templateMock; + @Mock VolumeVO _volumeMock; + @Mock List _rootVols; + @Before + public void setup(){ + MockitoAnnotations.initMocks(this); + + _userVmMgr._vmDao = _vmDao; + _userVmMgr._templateDao = _templateDao; + _userVmMgr._volsDao = _volsDao; + _userVmMgr._itMgr = _itMgr; + _userVmMgr.volumeMgr = _storageMgr; + _userVmMgr._accountDao = _accountDao; + _userVmMgr._userDao = _userDao; + _userVmMgr._accountMgr = _accountMgr; + + doReturn(3L).when(_account).getId(); + doReturn(8L).when(_vmMock).getAccountId(); + when(_accountDao.findById(anyLong())).thenReturn(_accountMock); + when(_userDao.findById(anyLong())).thenReturn(_userMock); + doReturn(Account.State.enabled).when(_account).getState(); + when(_vmMock.getId()).thenReturn(314L); + + } + + // Test restoreVm when VM state not in running/stopped case + @Test(expected=CloudRuntimeException.class) + public void testRestoreVMF1() throws ResourceAllocationException { + + when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + when(_templateDao.findById(anyLong())).thenReturn(_templateMock); + doReturn(VirtualMachine.State.Error).when(_vmMock).getState(); + _userVmMgr.restoreVMInternal(_account, _vmMock, null); + } + + // Test restoreVm when VM is in stopped state + @Test + public void testRestoreVMF2() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, + ConcurrentOperationException, ResourceAllocationException { + + doReturn(VirtualMachine.State.Stopped).when(_vmMock).getState(); + when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + when(_volsDao.findByInstance(anyLong())).thenReturn(_rootVols); + doReturn(false).when(_rootVols).isEmpty(); + when(_rootVols.get(eq(0))).thenReturn(_volumeMock); + doReturn(3L).when(_volumeMock).getTemplateId(); + when(_templateDao.findById(anyLong())).thenReturn(_templateMock); + when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock); + doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong()); + when(_volumeMock.getId()).thenReturn(3L); + doNothing().when(_volsDao).detachVolume(anyLong()); + + when(_templateMock.getUuid()).thenReturn("e0552266-7060-11e2-bbaa-d55f5db67735"); + + _userVmMgr.restoreVMInternal(_account, _vmMock, null); + + } + + // Test restoreVM when VM is in running state + @Test + public void testRestoreVMF3() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, + ConcurrentOperationException, ResourceAllocationException { + + doReturn(VirtualMachine.State.Running).when(_vmMock).getState(); + when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + when(_volsDao.findByInstance(anyLong())).thenReturn(_rootVols); + doReturn(false).when(_rootVols).isEmpty(); + when(_rootVols.get(eq(0))).thenReturn(_volumeMock); + doReturn(3L).when(_volumeMock).getTemplateId(); + when(_templateDao.findById(anyLong())).thenReturn(_templateMock); + when(_itMgr.stop(_vmMock, _userMock, _account)).thenReturn(true); + when(_itMgr.start(_vmMock, null, _userMock, _account)).thenReturn(_vmMock); + when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock); + doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong()); + when(_volumeMock.getId()).thenReturn(3L); + doNothing().when(_volsDao).detachVolume(anyLong()); + + when(_templateMock.getUuid()).thenReturn("e0552266-7060-11e2-bbaa-d55f5db67735"); + + _userVmMgr.restoreVMInternal(_account, _vmMock, null); + + } + + // Test restoreVM on providing new template Id, when VM is in running state + @Test + public void testRestoreVMF4() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, + ConcurrentOperationException, ResourceAllocationException { + doReturn(VirtualMachine.State.Running).when(_vmMock).getState(); + when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + when(_volsDao.findByInstance(anyLong())).thenReturn(_rootVols); + doReturn(false).when(_rootVols).isEmpty(); + when(_rootVols.get(eq(0))).thenReturn(_volumeMock); + doReturn(3L).when(_volumeMock).getTemplateId(); + when(_templateDao.findById(anyLong())).thenReturn(_templateMock); + doNothing().when(_accountMgr).checkAccess(_account, null, true, _templateMock); + when(_itMgr.stop(_vmMock, _userMock, _account)).thenReturn(true); + when(_storageMgr.allocateDuplicateVolume(_volumeMock, 14L)).thenReturn(_volumeMock); + when(_templateMock.getGuestOSId()).thenReturn(5L); + doNothing().when(_vmMock).setGuestOSId(anyLong()); + doNothing().when(_vmMock).setTemplateId(3L); + when(_vmDao.update(314L, _vmMock)).thenReturn(true); + when(_itMgr.start(_vmMock, null, _userMock, _account)).thenReturn(_vmMock); + when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock); + doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong()); + when(_volumeMock.getId()).thenReturn(3L); + doNothing().when(_volsDao).detachVolume(anyLong()); + + when(_templateMock.getUuid()).thenReturn("b1a3626e-72e0-4697-8c7c-a110940cc55d"); + + _userVmMgr.restoreVMInternal(_account, _vmMock, 14L); + + } + +} \ No newline at end of file diff --git a/server/test/com/cloud/vm/snapshot/VMSnapshotManagerTest.java b/server/test/com/cloud/vm/snapshot/VMSnapshotManagerTest.java new file mode 100644 index 00000000000..6fc6404e15f --- /dev/null +++ b/server/test/com/cloud/vm/snapshot/VMSnapshotManagerTest.java @@ -0,0 +1,186 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.vm.snapshot; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CreateVMSnapshotAnswer; +import com.cloud.agent.api.CreateVMSnapshotCommand; +import com.cloud.agent.api.to.VolumeTO; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.HypervisorGuruManager; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; + + + +public class VMSnapshotManagerTest { + @Spy VMSnapshotManagerImpl _vmSnapshotMgr = new VMSnapshotManagerImpl(); + @Mock Account admin; + @Mock VMSnapshotDao _vmSnapshotDao; + @Mock VolumeDao _volumeDao; + @Mock AccountDao _accountDao; + @Mock VMInstanceDao _vmInstanceDao; + @Mock UserVmDao _userVMDao; + @Mock HostDao _hostDao; + @Mock UserDao _userDao; + @Mock AgentManager _agentMgr; + @Mock HypervisorGuruManager _hvGuruMgr; + @Mock AccountManager _accountMgr; + @Mock GuestOSDao _guestOSDao; + @Mock StoragePoolDao _storagePoolDao; + @Mock SnapshotDao _snapshotDao; + @Mock VirtualMachineManager _itMgr; + @Mock ConfigurationDao _configDao; + int _vmSnapshotMax = 10; + + private static long TEST_VM_ID = 3L; + @Mock UserVmVO vmMock; + @Mock VolumeVO volumeMock; + + @Before + public void setup(){ + MockitoAnnotations.initMocks(this); + doReturn(admin).when(_vmSnapshotMgr).getCaller(); + _vmSnapshotMgr._accountDao = _accountDao; + _vmSnapshotMgr._userVMDao = _userVMDao; + _vmSnapshotMgr._vmSnapshotDao = _vmSnapshotDao; + _vmSnapshotMgr._volumeDao = _volumeDao; + _vmSnapshotMgr._accountMgr = _accountMgr; + _vmSnapshotMgr._snapshotDao = _snapshotDao; + _vmSnapshotMgr._guestOSDao = _guestOSDao; + + doNothing().when(_accountMgr).checkAccess(any(Account.class), any(AccessType.class), + any(Boolean.class), any(ControlledEntity.class)); + + _vmSnapshotMgr._vmSnapshotMax = _vmSnapshotMax; + + when(_userVMDao.findById(anyLong())).thenReturn(vmMock); + when(_vmSnapshotDao.findByName(anyLong(), anyString())).thenReturn(null); + when(_vmSnapshotDao.findByVm(anyLong())).thenReturn(new ArrayList()); + + List mockVolumeList = new ArrayList(); + mockVolumeList.add(volumeMock); + when(volumeMock.getInstanceId()).thenReturn(TEST_VM_ID); + when(_volumeDao.findByInstance(anyLong())).thenReturn(mockVolumeList); + + when(vmMock.getInstanceName()).thenReturn("i-3-VM-TEST"); + when(vmMock.getState()).thenReturn(State.Running); + + when(_guestOSDao.findById(anyLong())).thenReturn(mock(GuestOSVO.class)); + } + + // vmId null case + @Test(expected=InvalidParameterValueException.class) + public void testAllocVMSnapshotF1() throws ResourceAllocationException{ + when(_userVMDao.findById(TEST_VM_ID)).thenReturn(null); + _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true); + } + + // vm state not in [running, stopped] case + @Test(expected=InvalidParameterValueException.class) + public void testAllocVMSnapshotF2() throws ResourceAllocationException{ + when(vmMock.getState()).thenReturn(State.Starting); + _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true); + } + + // VM in stopped state & snapshotmemory case + @Test(expected=InvalidParameterValueException.class) + public void testCreateVMSnapshotF3() throws AgentUnavailableException, OperationTimedoutException, ResourceAllocationException{ + when(vmMock.getState()).thenReturn(State.Stopped); + _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true); + } + + // max snapshot limit case + @SuppressWarnings("unchecked") + @Test(expected=CloudRuntimeException.class) + public void testAllocVMSnapshotF4() throws ResourceAllocationException{ + List mockList = mock(List.class); + when(mockList.size()).thenReturn(10); + when(_vmSnapshotDao.findByVm(TEST_VM_ID)).thenReturn(mockList); + _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true); + } + + // active volume snapshots case + @SuppressWarnings("unchecked") + @Test(expected=CloudRuntimeException.class) + public void testAllocVMSnapshotF5() throws ResourceAllocationException{ + List mockList = mock(List.class); + when(mockList.size()).thenReturn(1); + when(_snapshotDao.listByInstanceId(TEST_VM_ID,Snapshot.State.Creating, + Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp)).thenReturn(mockList); + _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true); + } + + // successful creation case + @Test + public void testCreateVMSnapshot() throws AgentUnavailableException, OperationTimedoutException, ResourceAllocationException, NoTransitionException{ + when(vmMock.getState()).thenReturn(State.Running); + _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID,"","",true); + + when(_vmSnapshotDao.findCurrentSnapshotByVmId(anyLong())).thenReturn(null); + doReturn(new ArrayList()).when(_vmSnapshotMgr).getVolumeTOList(anyLong()); + doReturn(new CreateVMSnapshotAnswer(null,true,"")).when(_vmSnapshotMgr).sendToPool(anyLong(), any(CreateVMSnapshotCommand.class)); + doNothing().when(_vmSnapshotMgr).processAnswer(any(VMSnapshotVO.class), + any(UserVmVO.class), any(Answer.class), anyLong()); + doReturn(true).when(_vmSnapshotMgr).vmSnapshotStateTransitTo(any(VMSnapshotVO.class),any(VMSnapshot.Event.class)); + _vmSnapshotMgr.createVmSnapshotInternal(vmMock, mock(VMSnapshotVO.class), 5L); + } + +} diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index 574ce0a0352..e93b2a14c52 100644 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -365,6 +365,15 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu return false; } + /* (non-Javadoc) + * @see com.cloud.configuration.ConfigurationService#listLDAPConfig(org.apache.cloudstack.api.commands.LDAPConfigCmd) + */ + @Override + public LDAPConfigCmd listLDAPConfig(LDAPConfigCmd cmd) { + // TODO Auto-generated method stub + return null; + } + /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationService#isOfferingForVpc(com.cloud.offering.NetworkOffering) */ @@ -424,7 +433,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu */ @Override public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA, - boolean limitResourceUse, String tags, Long domainId, String hostTag, Integer networkRate) { + boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate) { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index bcaaa26b418..828a555a539 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -303,15 +303,11 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage */ @Override public Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr) { + User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr) { // TODO Auto-generated method stub return null; } - - - - /* (non-Javadoc) * @see com.cloud.network.NetworkService#createPhysicalNetwork(java.lang.Long, java.lang.String, java.lang.String, java.util.List, java.lang.String, java.lang.Long, java.util.List, java.lang.String) */ diff --git a/server/test/com/cloud/vpc/MockNetworkModelImpl.java b/server/test/com/cloud/vpc/MockNetworkModelImpl.java index 3fad33870bf..5ac87772529 100644 --- a/server/test/com/cloud/vpc/MockNetworkModelImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkModelImpl.java @@ -842,4 +842,10 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { // TODO Auto-generated method stub } + @Override + public void checkRequestedIpAddresses(long networkId, String ip4, String ip6) + throws InvalidParameterValueException { + // TODO Auto-generated method stub + } + } diff --git a/server/test/com/cloud/vpc/MockResourceLimitManagerImpl.java b/server/test/com/cloud/vpc/MockResourceLimitManagerImpl.java index 690aed65677..b9fc8617059 100644 --- a/server/test/com/cloud/vpc/MockResourceLimitManagerImpl.java +++ b/server/test/com/cloud/vpc/MockResourceLimitManagerImpl.java @@ -31,7 +31,6 @@ import com.cloud.domain.Domain; import com.cloud.exception.ResourceAllocationException; import com.cloud.user.Account; import com.cloud.user.ResourceLimitService; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; @Component @@ -117,6 +116,22 @@ public class MockResourceLimitManagerImpl extends ManagerBase implements Resourc } + /* (non-Javadoc) + * @see com.cloud.user.ResourceLimitService#countCpusForAccount(long) + */ + public long countCpusForAccount(long accountId) { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see com.cloud.user.ResourceLimitService#calculateRAMForAccount(long) + */ + public long calculateMemoryForAccount(long accountId) { + // TODO Auto-generated method stub + return 0; + } + /* (non-Javadoc) * @see com.cloud.user.ResourceLimitService#getResourceCount(com.cloud.user.Account, com.cloud.configuration.Resource.ResourceType) */ diff --git a/server/test/com/cloud/vpc/MockVpcManagerImpl.java b/server/test/com/cloud/vpc/MockVpcManagerImpl.java index 0a44a49c5e9..e6c65200ded 100644 --- a/server/test/com/cloud/vpc/MockVpcManagerImpl.java +++ b/server/test/com/cloud/vpc/MockVpcManagerImpl.java @@ -72,12 +72,8 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { return null; } - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcService#createVpcOffering(java.lang.String, java.lang.String, java.util.List) - */ @Override - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices) { - // TODO Auto-generated method stub + public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders) { return null; } @@ -320,11 +316,6 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { /* (non-Javadoc) * @see com.cloud.network.vpc.VpcService#updateVpcGuestNetwork(long, java.lang.String, java.lang.String, com.cloud.user.Account, com.cloud.user.User, java.lang.String, java.lang.Long, java.lang.Boolean) */ - @Override - public Network updateVpcGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, String domainSuffix, Long ntwkOffId, Boolean changeCidr) { - // TODO Auto-generated method stub - return null; - } /* (non-Javadoc) * @see com.cloud.network.vpc.VpcManager#validateNtkwOffForVpc(long, java.lang.String, java.lang.String, com.cloud.user.Account, com.cloud.network.vpc.Vpc, java.lang.Long, java.lang.String) @@ -362,12 +353,8 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { return null; } - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcManager#vpcProviderEnabledInZone(long) - */ @Override - public boolean vpcProviderEnabledInZone(long zoneId) { - // TODO Auto-generated method stub + public boolean vpcProviderEnabledInZone(long zoneId, String provider) { return false; } @@ -471,4 +458,11 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { return null; } + @Override + public Network updateVpcGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, + String domainSuffix, Long ntwkOffId, Boolean changeCidr, String guestVmCidr) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/vpc/dao/MockVpcDaoImpl.java b/server/test/com/cloud/vpc/dao/MockVpcDaoImpl.java index 99bdb58e4f7..562d67dc207 100644 --- a/server/test/com/cloud/vpc/dao/MockVpcDaoImpl.java +++ b/server/test/com/cloud/vpc/dao/MockVpcDaoImpl.java @@ -18,6 +18,7 @@ package com.cloud.vpc.dao; import java.lang.reflect.Field; import java.util.List; +import java.util.Map; import javax.ejb.Local; @@ -83,7 +84,17 @@ public class MockVpcDaoImpl extends GenericDaoBase implements VpcDa // TODO Auto-generated method stub return 0; } - + + @Override + public VpcVO persist(VpcVO vpc, Map serviceProviderMap) { + return null; + } + + @Override + public void persistVpcServiceProviders(long vpcId, Map serviceProviderMap) { + return; + } + @Override public VpcVO findById(Long id) { VpcVO vo = null; diff --git a/plugins/parent/pom.xml b/services/console-proxy/plugin/pom.xml similarity index 53% rename from plugins/parent/pom.xml rename to services/console-proxy/plugin/pom.xml index 3a0bf3ce3cf..4cbe6d1c8f4 100644 --- a/plugins/parent/pom.xml +++ b/services/console-proxy/plugin/pom.xml @@ -16,27 +16,20 @@ specific language governing permissions and limitations under the License. --> - - 4.0.0 - cloud-plugin-parent - Apache CloudStack Plugin POM - pom - - com.cloud - cloud-parent - 4.0.0-SNAPSHOT - ../../parent/pom.xml - - - - com.cloud - cloud-server - ${project.version} - - - - install - src - + + 4.0.0 + cloud-plugin-console-proxy + Apache CloudStack Console Proxy Plugin + pom + + org.apache.cloudstack + cloud-service-console-proxy + 4.2.0-SNAPSHOT + ../pom.xml + + + install + src + test + diff --git a/services/console-proxy/pom.xml b/services/console-proxy/pom.xml new file mode 100644 index 00000000000..1453e8cc264 --- /dev/null +++ b/services/console-proxy/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + cloud-service-console-proxy + Apache CloudStack Console Proxy Service + pom + + org.apache.cloudstack + cloud-services + 4.2.0-SNAPSHOT + ../pom.xml + + + install + + + plugin + server + + diff --git a/console-proxy/bindir/cloud-setup-console-proxy.in b/services/console-proxy/server/bindir/cloud-setup-console-proxy.in similarity index 100% rename from console-proxy/bindir/cloud-setup-console-proxy.in rename to services/console-proxy/server/bindir/cloud-setup-console-proxy.in diff --git a/console-proxy/certs/localhost.crt b/services/console-proxy/server/certs/localhost.crt similarity index 100% rename from console-proxy/certs/localhost.crt rename to services/console-proxy/server/certs/localhost.crt diff --git a/console-proxy/certs/localhost.key b/services/console-proxy/server/certs/localhost.key similarity index 100% rename from console-proxy/certs/localhost.key rename to services/console-proxy/server/certs/localhost.key diff --git a/console-proxy/certs/realhostip.crt b/services/console-proxy/server/certs/realhostip.crt similarity index 100% rename from console-proxy/certs/realhostip.crt rename to services/console-proxy/server/certs/realhostip.crt diff --git a/console-proxy/certs/realhostip.csr b/services/console-proxy/server/certs/realhostip.csr similarity index 100% rename from console-proxy/certs/realhostip.csr rename to services/console-proxy/server/certs/realhostip.csr diff --git a/console-proxy/certs/realhostip.key b/services/console-proxy/server/certs/realhostip.key similarity index 100% rename from console-proxy/certs/realhostip.key rename to services/console-proxy/server/certs/realhostip.key diff --git a/console-proxy/certs/realhostip.keystore b/services/console-proxy/server/certs/realhostip.keystore similarity index 100% rename from console-proxy/certs/realhostip.keystore rename to services/console-proxy/server/certs/realhostip.keystore diff --git a/console-proxy/conf.dom0/agent.properties.in b/services/console-proxy/server/conf.dom0/agent.properties.in similarity index 100% rename from console-proxy/conf.dom0/agent.properties.in rename to services/console-proxy/server/conf.dom0/agent.properties.in diff --git a/console-proxy/conf.dom0/consoleproxy.properties.in b/services/console-proxy/server/conf.dom0/consoleproxy.properties.in similarity index 100% rename from console-proxy/conf.dom0/consoleproxy.properties.in rename to services/console-proxy/server/conf.dom0/consoleproxy.properties.in diff --git a/console-proxy/conf.dom0/log4j-cloud.xml.in b/services/console-proxy/server/conf.dom0/log4j-cloud.xml.in similarity index 100% rename from console-proxy/conf.dom0/log4j-cloud.xml.in rename to services/console-proxy/server/conf.dom0/log4j-cloud.xml.in diff --git a/console-proxy/conf/agent.properties b/services/console-proxy/server/conf/agent.properties similarity index 100% rename from console-proxy/conf/agent.properties rename to services/console-proxy/server/conf/agent.properties diff --git a/console-proxy/conf/consoleproxy.properties b/services/console-proxy/server/conf/consoleproxy.properties similarity index 100% rename from console-proxy/conf/consoleproxy.properties rename to services/console-proxy/server/conf/consoleproxy.properties diff --git a/console-proxy/conf/log4j-cloud.xml b/services/console-proxy/server/conf/log4j-cloud.xml similarity index 100% rename from console-proxy/conf/log4j-cloud.xml rename to services/console-proxy/server/conf/log4j-cloud.xml diff --git a/console-proxy/css/ajaxviewer.css b/services/console-proxy/server/css/ajaxviewer.css similarity index 100% rename from console-proxy/css/ajaxviewer.css rename to services/console-proxy/server/css/ajaxviewer.css diff --git a/console-proxy/css/logger.css b/services/console-proxy/server/css/logger.css similarity index 100% rename from console-proxy/css/logger.css rename to services/console-proxy/server/css/logger.css diff --git a/console-proxy/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/services/console-proxy/server/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in similarity index 100% rename from console-proxy/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in rename to services/console-proxy/server/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in diff --git a/console-proxy/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/services/console-proxy/server/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in similarity index 100% rename from console-proxy/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in rename to services/console-proxy/server/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in diff --git a/console-proxy/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/services/console-proxy/server/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in similarity index 100% rename from console-proxy/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in rename to services/console-proxy/server/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in diff --git a/console-proxy/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in b/services/console-proxy/server/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in similarity index 100% rename from console-proxy/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in rename to services/console-proxy/server/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in diff --git a/console-proxy/images/back.gif b/services/console-proxy/server/images/back.gif similarity index 100% rename from console-proxy/images/back.gif rename to services/console-proxy/server/images/back.gif diff --git a/console-proxy/images/bright-green.png b/services/console-proxy/server/images/bright-green.png similarity index 100% rename from console-proxy/images/bright-green.png rename to services/console-proxy/server/images/bright-green.png diff --git a/console-proxy/images/cad.gif b/services/console-proxy/server/images/cad.gif similarity index 100% rename from console-proxy/images/cad.gif rename to services/console-proxy/server/images/cad.gif diff --git a/console-proxy/images/cannotconnect.jpg b/services/console-proxy/server/images/cannotconnect.jpg similarity index 100% rename from console-proxy/images/cannotconnect.jpg rename to services/console-proxy/server/images/cannotconnect.jpg diff --git a/console-proxy/images/clr_button.gif b/services/console-proxy/server/images/clr_button.gif similarity index 100% rename from console-proxy/images/clr_button.gif rename to services/console-proxy/server/images/clr_button.gif diff --git a/console-proxy/images/clr_button_hover.gif b/services/console-proxy/server/images/clr_button_hover.gif similarity index 100% rename from console-proxy/images/clr_button_hover.gif rename to services/console-proxy/server/images/clr_button_hover.gif diff --git a/console-proxy/images/dot.cur b/services/console-proxy/server/images/dot.cur similarity index 100% rename from console-proxy/images/dot.cur rename to services/console-proxy/server/images/dot.cur diff --git a/console-proxy/images/gray-green.png b/services/console-proxy/server/images/gray-green.png similarity index 100% rename from console-proxy/images/gray-green.png rename to services/console-proxy/server/images/gray-green.png diff --git a/console-proxy/images/grid_headerbg.gif b/services/console-proxy/server/images/grid_headerbg.gif similarity index 100% rename from console-proxy/images/grid_headerbg.gif rename to services/console-proxy/server/images/grid_headerbg.gif diff --git a/console-proxy/images/left.png b/services/console-proxy/server/images/left.png similarity index 100% rename from console-proxy/images/left.png rename to services/console-proxy/server/images/left.png diff --git a/console-proxy/images/minimize_button.gif b/services/console-proxy/server/images/minimize_button.gif similarity index 100% rename from console-proxy/images/minimize_button.gif rename to services/console-proxy/server/images/minimize_button.gif diff --git a/console-proxy/images/minimize_button_hover.gif b/services/console-proxy/server/images/minimize_button_hover.gif similarity index 100% rename from console-proxy/images/minimize_button_hover.gif rename to services/console-proxy/server/images/minimize_button_hover.gif diff --git a/console-proxy/images/notready.jpg b/services/console-proxy/server/images/notready.jpg similarity index 100% rename from console-proxy/images/notready.jpg rename to services/console-proxy/server/images/notready.jpg diff --git a/console-proxy/images/play_button.gif b/services/console-proxy/server/images/play_button.gif similarity index 100% rename from console-proxy/images/play_button.gif rename to services/console-proxy/server/images/play_button.gif diff --git a/console-proxy/images/play_button_hover.gif b/services/console-proxy/server/images/play_button_hover.gif similarity index 100% rename from console-proxy/images/play_button_hover.gif rename to services/console-proxy/server/images/play_button_hover.gif diff --git a/console-proxy/images/right.png b/services/console-proxy/server/images/right.png similarity index 100% rename from console-proxy/images/right.png rename to services/console-proxy/server/images/right.png diff --git a/console-proxy/images/right2.png b/services/console-proxy/server/images/right2.png similarity index 100% rename from console-proxy/images/right2.png rename to services/console-proxy/server/images/right2.png diff --git a/console-proxy/images/shrink_button.gif b/services/console-proxy/server/images/shrink_button.gif similarity index 100% rename from console-proxy/images/shrink_button.gif rename to services/console-proxy/server/images/shrink_button.gif diff --git a/console-proxy/images/shrink_button_hover.gif b/services/console-proxy/server/images/shrink_button_hover.gif similarity index 100% rename from console-proxy/images/shrink_button_hover.gif rename to services/console-proxy/server/images/shrink_button_hover.gif diff --git a/console-proxy/images/stop_button.gif b/services/console-proxy/server/images/stop_button.gif similarity index 100% rename from console-proxy/images/stop_button.gif rename to services/console-proxy/server/images/stop_button.gif diff --git a/console-proxy/images/stop_button_hover.gif b/services/console-proxy/server/images/stop_button_hover.gif similarity index 100% rename from console-proxy/images/stop_button_hover.gif rename to services/console-proxy/server/images/stop_button_hover.gif diff --git a/console-proxy/images/winlog.png b/services/console-proxy/server/images/winlog.png similarity index 100% rename from console-proxy/images/winlog.png rename to services/console-proxy/server/images/winlog.png diff --git a/console-proxy/js/ajaxkeys.js b/services/console-proxy/server/js/ajaxkeys.js similarity index 100% rename from console-proxy/js/ajaxkeys.js rename to services/console-proxy/server/js/ajaxkeys.js diff --git a/console-proxy/js/ajaxviewer.js b/services/console-proxy/server/js/ajaxviewer.js similarity index 100% rename from console-proxy/js/ajaxviewer.js rename to services/console-proxy/server/js/ajaxviewer.js diff --git a/console-proxy/js/cloud.logger.js b/services/console-proxy/server/js/cloud.logger.js similarity index 100% rename from console-proxy/js/cloud.logger.js rename to services/console-proxy/server/js/cloud.logger.js diff --git a/console-proxy/js/handler.js b/services/console-proxy/server/js/handler.js similarity index 100% rename from console-proxy/js/handler.js rename to services/console-proxy/server/js/handler.js diff --git a/console-proxy/js/jquery.js b/services/console-proxy/server/js/jquery.js similarity index 100% rename from console-proxy/js/jquery.js rename to services/console-proxy/server/js/jquery.js diff --git a/console-proxy/libexec/console-proxy-runner.in b/services/console-proxy/server/libexec/console-proxy-runner.in similarity index 100% rename from console-proxy/libexec/console-proxy-runner.in rename to services/console-proxy/server/libexec/console-proxy-runner.in diff --git a/console-proxy/pom.xml b/services/console-proxy/server/pom.xml similarity index 95% rename from console-proxy/pom.xml rename to services/console-proxy/server/pom.xml index ab9af163180..0df7559781e 100644 --- a/console-proxy/pom.xml +++ b/services/console-proxy/server/pom.xml @@ -22,8 +22,9 @@ Apache CloudStack Console Proxy org.apache.cloudstack - cloudstack - 4.1.0-SNAPSHOT + cloud-service-console-proxy + 4.2.0-SNAPSHOT + ../pom.xml mkisofs @@ -110,7 +111,7 @@ - ../patches/systemvm/debian/config/root/.ssh + ../../../patches/systemvm/debian/config/root/.ssh authorized_keys @@ -132,7 +133,7 @@ - + diff --git a/console-proxy/scripts/_run.sh b/services/console-proxy/server/scripts/_run.sh similarity index 100% rename from console-proxy/scripts/_run.sh rename to services/console-proxy/server/scripts/_run.sh diff --git a/console-proxy/scripts/config_auth.sh b/services/console-proxy/server/scripts/config_auth.sh similarity index 100% rename from console-proxy/scripts/config_auth.sh rename to services/console-proxy/server/scripts/config_auth.sh diff --git a/console-proxy/scripts/config_ssl.sh b/services/console-proxy/server/scripts/config_ssl.sh similarity index 100% rename from console-proxy/scripts/config_ssl.sh rename to services/console-proxy/server/scripts/config_ssl.sh diff --git a/console-proxy/scripts/ipfirewall.sh b/services/console-proxy/server/scripts/ipfirewall.sh similarity index 100% rename from console-proxy/scripts/ipfirewall.sh rename to services/console-proxy/server/scripts/ipfirewall.sh diff --git a/console-proxy/scripts/run-proxy.sh b/services/console-proxy/server/scripts/run-proxy.sh similarity index 100% rename from console-proxy/scripts/run-proxy.sh rename to services/console-proxy/server/scripts/run-proxy.sh diff --git a/console-proxy/scripts/run.bat b/services/console-proxy/server/scripts/run.bat similarity index 100% rename from console-proxy/scripts/run.bat rename to services/console-proxy/server/scripts/run.bat diff --git a/console-proxy/scripts/run.sh b/services/console-proxy/server/scripts/run.sh similarity index 100% rename from console-proxy/scripts/run.sh rename to services/console-proxy/server/scripts/run.sh diff --git a/console-proxy/scripts/ssvm-check.sh b/services/console-proxy/server/scripts/ssvm-check.sh similarity index 100% rename from console-proxy/scripts/ssvm-check.sh rename to services/console-proxy/server/scripts/ssvm-check.sh diff --git a/console-proxy/src/com/cloud/consoleproxy/AjaxFIFOImageCache.java b/services/console-proxy/server/src/com/cloud/consoleproxy/AjaxFIFOImageCache.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/AjaxFIFOImageCache.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/AjaxFIFOImageCache.java diff --git a/console-proxy/src/com/cloud/consoleproxy/AuthenticationException.java b/services/console-proxy/server/src/com/cloud/consoleproxy/AuthenticationException.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/AuthenticationException.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/AuthenticationException.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxy.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxy.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAuthenticationResult.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAuthenticationResult.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAuthenticationResult.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyAuthenticationResult.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyBaseServerFactoryImpl.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyBaseServerFactoryImpl.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyBaseServerFactoryImpl.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyBaseServerFactoryImpl.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClient.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClient.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClient.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClient.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientListener.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientListener.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientListener.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientListener.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientParam.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientParam.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientParam.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientParam.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientStatsCollector.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientStatsCollector.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientStatsCollector.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientStatsCollector.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyCmdHandler.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyCmdHandler.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyCmdHandler.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyCmdHandler.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyGCThread.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyGCThread.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyGCThread.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyGCThread.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyLoggerFactory.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyLoggerFactory.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyLoggerFactory.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyLoggerFactory.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyMonitor.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyMonitor.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyMonitor.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyMonitor.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyResourceHandler.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyResourceHandler.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyResourceHandler.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyResourceHandler.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyServerFactory.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyServerFactory.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyServerFactory.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyServerFactory.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyVncClient.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyVncClient.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/ConsoleProxyVncClient.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyVncClient.java diff --git a/console-proxy/src/com/cloud/consoleproxy/InputEventType.java b/services/console-proxy/server/src/com/cloud/consoleproxy/InputEventType.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/InputEventType.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/InputEventType.java diff --git a/console-proxy/src/com/cloud/consoleproxy/util/ITileScanListener.java b/services/console-proxy/server/src/com/cloud/consoleproxy/util/ITileScanListener.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/util/ITileScanListener.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/util/ITileScanListener.java diff --git a/console-proxy/src/com/cloud/consoleproxy/util/ImageHelper.java b/services/console-proxy/server/src/com/cloud/consoleproxy/util/ImageHelper.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/util/ImageHelper.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/util/ImageHelper.java diff --git a/console-proxy/src/com/cloud/consoleproxy/util/Logger.java b/services/console-proxy/server/src/com/cloud/consoleproxy/util/Logger.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/util/Logger.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/util/Logger.java diff --git a/console-proxy/src/com/cloud/consoleproxy/util/LoggerFactory.java b/services/console-proxy/server/src/com/cloud/consoleproxy/util/LoggerFactory.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/util/LoggerFactory.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/util/LoggerFactory.java diff --git a/console-proxy/src/com/cloud/consoleproxy/util/RawHTTP.java b/services/console-proxy/server/src/com/cloud/consoleproxy/util/RawHTTP.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/util/RawHTTP.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/util/RawHTTP.java diff --git a/console-proxy/src/com/cloud/consoleproxy/util/Region.java b/services/console-proxy/server/src/com/cloud/consoleproxy/util/Region.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/util/Region.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/util/Region.java diff --git a/console-proxy/src/com/cloud/consoleproxy/util/RegionClassifier.java b/services/console-proxy/server/src/com/cloud/consoleproxy/util/RegionClassifier.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/util/RegionClassifier.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/util/RegionClassifier.java diff --git a/console-proxy/src/com/cloud/consoleproxy/util/TileInfo.java b/services/console-proxy/server/src/com/cloud/consoleproxy/util/TileInfo.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/util/TileInfo.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/util/TileInfo.java diff --git a/console-proxy/src/com/cloud/consoleproxy/util/TileTracker.java b/services/console-proxy/server/src/com/cloud/consoleproxy/util/TileTracker.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/util/TileTracker.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/util/TileTracker.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/BufferedImageCanvas.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/BufferedImageCanvas.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/BufferedImageCanvas.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/BufferedImageCanvas.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/FrameBufferCanvas.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/FrameBufferCanvas.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/FrameBufferCanvas.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/FrameBufferCanvas.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/FrameBufferUpdateListener.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/FrameBufferUpdateListener.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/FrameBufferUpdateListener.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/FrameBufferUpdateListener.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/PaintNotificationListener.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/PaintNotificationListener.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/PaintNotificationListener.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/PaintNotificationListener.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/RfbConstants.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/RfbConstants.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/RfbConstants.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/RfbConstants.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/VncClient.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/VncClient.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/VncClient.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/VncClient.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/VncClientPacketSender.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/VncClientPacketSender.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/VncClientPacketSender.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/VncClientPacketSender.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/VncScreenDescription.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/VncScreenDescription.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/VncScreenDescription.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/VncScreenDescription.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/VncServerPacketReceiver.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/VncServerPacketReceiver.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/VncServerPacketReceiver.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/VncServerPacketReceiver.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/ClientPacket.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/ClientPacket.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/ClientPacket.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/ClientPacket.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/FramebufferUpdateRequestPacket.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/FramebufferUpdateRequestPacket.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/FramebufferUpdateRequestPacket.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/FramebufferUpdateRequestPacket.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/KeyboardEventPacket.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/KeyboardEventPacket.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/KeyboardEventPacket.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/KeyboardEventPacket.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/MouseEventPacket.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/MouseEventPacket.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/MouseEventPacket.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/MouseEventPacket.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/SetEncodingsPacket.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/SetEncodingsPacket.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/SetEncodingsPacket.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/SetEncodingsPacket.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/SetPixelFormatPacket.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/SetPixelFormatPacket.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/client/SetPixelFormatPacket.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/client/SetPixelFormatPacket.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/AbstractRect.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/AbstractRect.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/AbstractRect.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/AbstractRect.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/CopyRect.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/CopyRect.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/CopyRect.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/CopyRect.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/FrameBufferSizeChangeRequest.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/FrameBufferSizeChangeRequest.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/FrameBufferSizeChangeRequest.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/FrameBufferSizeChangeRequest.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/FramebufferUpdatePacket.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/FramebufferUpdatePacket.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/FramebufferUpdatePacket.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/FramebufferUpdatePacket.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/RawRect.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/RawRect.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/RawRect.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/RawRect.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/Rect.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/Rect.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/Rect.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/Rect.java diff --git a/console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/ServerCutText.java b/services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/ServerCutText.java similarity index 100% rename from console-proxy/src/com/cloud/consoleproxy/vnc/packet/server/ServerCutText.java rename to services/console-proxy/server/src/com/cloud/consoleproxy/vnc/packet/server/ServerCutText.java diff --git a/console-proxy/systemvm-descriptor.xml b/services/console-proxy/server/systemvm-descriptor.xml similarity index 90% rename from console-proxy/systemvm-descriptor.xml rename to services/console-proxy/server/systemvm-descriptor.xml index 7efe7fdfcb0..e34026bc3a6 100644 --- a/console-proxy/systemvm-descriptor.xml +++ b/services/console-proxy/server/systemvm-descriptor.xml @@ -31,13 +31,13 @@ - ../scripts/storage/secondary/ + ../../../scripts/storage/secondary/ scripts/storage/secondary 555 555 - ../scripts/storage/secondary/ + ../../../scripts/storage/secondary/ scripts/storage/secondary 555 555 @@ -60,7 +60,7 @@ - ../console-proxy/images + images images 555 555 @@ -72,7 +72,7 @@ - ../console-proxy/js + js js 555 555 @@ -81,7 +81,7 @@ - ../console-proxy/ui + ui ui 555 555 @@ -90,7 +90,7 @@ - ../console-proxy/css + css css 555 555 @@ -99,7 +99,7 @@ - ../console-proxy/certs + certs certs 555 555 diff --git a/console-proxy/ui/viewer-bad-sid.ftl b/services/console-proxy/server/ui/viewer-bad-sid.ftl similarity index 100% rename from console-proxy/ui/viewer-bad-sid.ftl rename to services/console-proxy/server/ui/viewer-bad-sid.ftl diff --git a/console-proxy/ui/viewer-connect-failed.ftl b/services/console-proxy/server/ui/viewer-connect-failed.ftl similarity index 100% rename from console-proxy/ui/viewer-connect-failed.ftl rename to services/console-proxy/server/ui/viewer-connect-failed.ftl diff --git a/console-proxy/ui/viewer-update.ftl b/services/console-proxy/server/ui/viewer-update.ftl similarity index 100% rename from console-proxy/ui/viewer-update.ftl rename to services/console-proxy/server/ui/viewer-update.ftl diff --git a/console-proxy/ui/viewer.ftl b/services/console-proxy/server/ui/viewer.ftl similarity index 100% rename from console-proxy/ui/viewer.ftl rename to services/console-proxy/server/ui/viewer.ftl diff --git a/console-proxy/vm-script/vmops b/services/console-proxy/server/vm-script/vmops similarity index 100% rename from console-proxy/vm-script/vmops rename to services/console-proxy/server/vm-script/vmops diff --git a/services/pom.xml b/services/pom.xml new file mode 100644 index 00000000000..35ec2e186ba --- /dev/null +++ b/services/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + cloud-services + Apache CloudStack Cloud Services + pom + + org.apache.cloudstack + cloudstack + 4.2.0-SNAPSHOT + ../pom.xml + + + install + + + console-proxy + + diff --git a/setup/bindir/cloud-setup-databases.in b/setup/bindir/cloud-setup-databases.in index 8330f35e659..52a23d6f0fc 100755 --- a/setup/bindir/cloud-setup-databases.in +++ b/setup/bindir/cloud-setup-databases.in @@ -211,7 +211,7 @@ for full help ""), ) - for f in ["create-database","create-schema", "create-database-premium","create-schema-premium", "create-schema-view", "4.1-new-db-schema"]: + for f in ["create-database","create-schema", "create-database-premium","create-schema-premium"]: p = os.path.join(self.dbFilesPath,"%s.sql"%f) if not os.path.exists(p): continue text = file(p).read() @@ -358,7 +358,7 @@ for example: if not os.path.exists(dbf): self.errorAndExit("Cannot find %s"%dbf) - coreSchemas = ['create-database.sql', 'create-schema.sql', 'create-schema-view.sql', 'templates.sql'] + coreSchemas = ['create-database.sql', 'create-schema.sql', 'templates.sql'] if not self.serversetup: coreSchemas.append('server-setup.sql') diff --git a/setup/db/4.1-new-db-schema.sql b/setup/db/4.1-new-db-schema.sql deleted file mode 100644 index d60eca2f890..00000000000 --- a/setup/db/4.1-new-db-schema.sql +++ /dev/null @@ -1,142 +0,0 @@ --- 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. - -use cloud; - -alter table vm_template add image_data_store_id bigint unsigned; -alter table vm_template add size bigint unsigned; -alter table vm_template add state varchar(255); -alter table vm_template add update_count bigint unsigned; -alter table vm_template add updated datetime; -alter table storage_pool add storage_provider_id bigint unsigned; -alter table storage_pool add scope varchar(255); -alter table storage_pool modify id bigint unsigned AUTO_INCREMENT UNIQUE NOT NULL; -alter table template_spool_ref add state varchar(255); -alter table template_spool_ref add update_count bigint unsigned; -alter table volumes add disk_type varchar(255); -alter table volumes drop foreign key `fk_volumes__account_id`; -alter table vm_instance add column disk_offering_id bigint unsigned; -alter table vm_instance add column cpu int(10) unsigned; -alter table vm_instance add column ram bigint unsigned; -alter table vm_instance add column owner varchar(255); -alter table vm_instance add column speed int(10) unsigned; -alter table vm_instance add column host_name varchar(255); -alter table vm_instance add column display_name varchar(255); - -alter table data_center add column owner varchar(255); -alter table data_center add column created datetime COMMENT 'date created'; -alter table data_center add column lastUpdated datetime COMMENT 'last updated'; -alter table data_center add column engine_state varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'the engine state of the zone'; -alter table host_pod_ref add column owner varchar(255); -alter table host_pod_ref add column created datetime COMMENT 'date created'; -alter table host_pod_ref add column lastUpdated datetime COMMENT 'last updated'; -alter table host_pod_ref add column engine_state varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'the engine state of the zone'; -alter table host add column owner varchar(255); -alter table host add column lastUpdated datetime COMMENT 'last updated'; -alter table host add column engine_state varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'the engine state of the zone'; - - -alter table cluster add column owner varchar(255); -alter table cluster add column created datetime COMMENT 'date created'; -alter table cluster add column lastUpdated datetime COMMENT 'last updated'; -alter table cluster add column engine_state varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'the engine state of the zone'; -CREATE TABLE `cloud`.`object_datastore_ref` ( - `id` bigint unsigned NOT NULL auto_increment, - `datastore_id` bigint unsigned NOT NULL, - `datastore_role` varchar(255) NOT NULL, - `object_id` bigint unsigned NOT NULL, - `object_type` varchar(255) NOT NULL, - `created` DATETIME NOT NULL, - `last_updated` DATETIME, - `job_id` varchar(255), - `download_pct` int(10) unsigned, - `download_state` varchar(255), - `error_str` varchar(255), - `local_path` varchar(255), - `install_path` varchar(255), - `size` bigint unsigned COMMENT 'the size of the template on the pool', - `state` varchar(255) NOT NULL, - `update_count` bigint unsigned NOT NULL, - `updated` DATETIME, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`data_store_provider` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `name` varchar(255) NOT NULL COMMENT 'name of primary data store provider', - `uuid` varchar(255) NOT NULL COMMENT 'uuid of primary data store provider', - PRIMARY KEY(`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`image_data_store` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `name` varchar(255) NOT NULL COMMENT 'name of data store', - `image_provider_id` bigint unsigned NOT NULL COMMENT 'id of image_data_store_provider', - `protocol` varchar(255) NOT NULL COMMENT 'protocol of data store', - `data_center_id` bigint unsigned COMMENT 'datacenter id of data store', - `scope` varchar(255) COMMENT 'scope of data store', - `uuid` varchar(255) COMMENT 'uuid of data store', - PRIMARY KEY(`id`), - CONSTRAINT `fk_tags__image_data_store_provider_id` FOREIGN KEY(`image_provider_id`) REFERENCES `data_store_provider`(`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`vm_compute_tags` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', - `compute_tag` varchar(255) NOT NULL COMMENT 'name of tag', - PRIMARY KEY(`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`vm_root_disk_tags` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', - `root_disk_tag` varchar(255) NOT NULL COMMENT 'name of tag', - PRIMARY KEY(`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -CREATE TABLE `cloud`.`vm_network_map` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', - `network_id` bigint unsigned NOT NULL COMMENT 'network id', - PRIMARY KEY(`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -CREATE TABLE `cloud`.`vm_reservation` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `uuid` varchar(40) NOT NULL COMMENT 'reservation id', - `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', - `data_center_id` bigint unsigned NOT NULL COMMENT 'zone id', - `pod_id` bigint unsigned NOT NULL COMMENT 'pod id', - `cluster_id` bigint unsigned NOT NULL COMMENT 'cluster id', - `host_id` bigint unsigned NOT NULL COMMENT 'host id', - `created` datetime COMMENT 'date created', - `removed` datetime COMMENT 'date removed if not null', - CONSTRAINT `uc_vm_reservation__uuid` UNIQUE (`uuid`), - PRIMARY KEY(`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`volume_reservation` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `vm_reservation_id` bigint unsigned NOT NULL COMMENT 'id of the vm reservation', - `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', - `volume_id` bigint unsigned NOT NULL COMMENT 'volume id', - `pool_id` bigint unsigned NOT NULL COMMENT 'pool assigned to the volume', - CONSTRAINT `fk_vm_pool_reservation__vm_reservation_id` FOREIGN KEY (`vm_reservation_id`) REFERENCES `vm_reservation`(`id`) ON DELETE CASCADE, - PRIMARY KEY(`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/setup/db/create-schema-view.sql b/setup/db/create-schema-view.sql deleted file mode 100644 index f68a6cadb71..00000000000 --- a/setup/db/create-schema-view.sql +++ /dev/null @@ -1,1136 +0,0 @@ --- 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. - --- DB views for list api - -DROP VIEW IF EXISTS `cloud`.`user_vm_view`; -CREATE VIEW `cloud`.`user_vm_view` AS - select - vm_instance.id id, - vm_instance.name name, - user_vm.display_name display_name, - user_vm.user_data user_data, - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name, - instance_group.id instance_group_id, - instance_group.uuid instance_group_uuid, - instance_group.name instance_group_name, - vm_instance.uuid uuid, - vm_instance.last_host_id last_host_id, - vm_instance.vm_type type, - vm_instance.vnc_password vnc_password, - vm_instance.limit_cpu_use limit_cpu_use, - vm_instance.created created, - vm_instance.state state, - vm_instance.removed removed, - vm_instance.ha_enabled ha_enabled, - vm_instance.hypervisor_type hypervisor_type, - vm_instance.instance_name instance_name, - vm_instance.guest_os_id guest_os_id, - guest_os.uuid guest_os_uuid, - vm_instance.pod_id pod_id, - host_pod_ref.uuid pod_uuid, - vm_instance.private_ip_address private_ip_address, - vm_instance.private_mac_address private_mac_address, - vm_instance.vm_type vm_type, - data_center.id data_center_id, - data_center.uuid data_center_uuid, - data_center.name data_center_name, - data_center.is_security_group_enabled security_group_enabled, - host.id host_id, - host.uuid host_uuid, - host.name host_name, - vm_template.id template_id, - vm_template.uuid template_uuid, - vm_template.name template_name, - vm_template.display_text template_display_text, - vm_template.enable_password password_enabled, - iso.id iso_id, - iso.uuid iso_uuid, - iso.name iso_name, - iso.display_text iso_display_text, - service_offering.id service_offering_id, - disk_offering.uuid service_offering_uuid, - service_offering.cpu cpu, - service_offering.speed speed, - service_offering.ram_size ram_size, - disk_offering.name service_offering_name, - storage_pool.id pool_id, - storage_pool.uuid pool_uuid, - storage_pool.pool_type pool_type, - volumes.id volume_id, - volumes.uuid volume_uuid, - volumes.device_id volume_device_id, - volumes.volume_type volume_type, - security_group.id security_group_id, - security_group.uuid security_group_uuid, - security_group.name security_group_name, - security_group.description security_group_description, - nics.id nic_id, - nics.uuid nic_uuid, - nics.network_id network_id, - nics.ip4_address ip_address, - nics.default_nic is_default_nic, - nics.gateway gateway, - nics.netmask netmask, - nics.mac_address mac_address, - nics.broadcast_uri broadcast_uri, - nics.isolation_uri isolation_uri, - vpc.id vpc_id, - vpc.uuid vpc_uuid, - networks.uuid network_uuid, - networks.traffic_type traffic_type, - networks.guest_type guest_type, - user_ip_address.id public_ip_id, - user_ip_address.uuid public_ip_uuid, - user_ip_address.public_ip_address public_ip_address, - ssh_keypairs.keypair_name keypair_name, - resource_tags.id tag_id, - resource_tags.uuid tag_uuid, - resource_tags.key tag_key, - resource_tags.value tag_value, - resource_tags.domain_id tag_domain_id, - resource_tags.account_id tag_account_id, - resource_tags.resource_id tag_resource_id, - resource_tags.resource_uuid tag_resource_uuid, - resource_tags.resource_type tag_resource_type, - resource_tags.customer tag_customer, - async_job.id job_id, - async_job.uuid job_uuid, - async_job.job_status job_status, - async_job.account_id job_account_id - from - `cloud`.`user_vm` - inner join - `cloud`.`vm_instance` ON vm_instance.id = user_vm.id - and vm_instance.removed is NULL - inner join - `cloud`.`account` ON vm_instance.account_id = account.id - inner join - `cloud`.`domain` ON vm_instance.domain_id = domain.id - left join - `cloud`.`guest_os` ON vm_instance.guest_os_id = guest_os.id - left join - `cloud`.`host_pod_ref` ON vm_instance.pod_id = host_pod_ref.id - left join - `cloud`.`projects` ON projects.project_account_id = account.id - left join - `cloud`.`instance_group_vm_map` ON vm_instance.id = instance_group_vm_map.instance_id - left join - `cloud`.`instance_group` ON instance_group_vm_map.group_id = instance_group.id - left join - `cloud`.`data_center` ON vm_instance.data_center_id = data_center.id - left join - `cloud`.`host` ON vm_instance.host_id = host.id - left join - `cloud`.`vm_template` ON vm_instance.vm_template_id = vm_template.id - left join - `cloud`.`vm_template` iso ON iso.id = user_vm.iso_id - left join - `cloud`.`service_offering` ON vm_instance.service_offering_id = service_offering.id - left join - `cloud`.`disk_offering` ON vm_instance.service_offering_id = disk_offering.id - left join - `cloud`.`volumes` ON vm_instance.id = volumes.instance_id - left join - `cloud`.`storage_pool` ON volumes.pool_id = storage_pool.id - left join - `cloud`.`security_group_vm_map` ON vm_instance.id = security_group_vm_map.instance_id - left join - `cloud`.`security_group` ON security_group_vm_map.security_group_id = security_group.id - left join - `cloud`.`nics` ON vm_instance.id = nics.instance_id - left join - `cloud`.`networks` ON nics.network_id = networks.id - left join - `cloud`.`vpc` ON networks.vpc_id = vpc.id - left join - `cloud`.`user_ip_address` ON user_ip_address.vm_id = vm_instance.id - left join - `cloud`.`user_vm_details` ON user_vm_details.vm_id = vm_instance.id - and user_vm_details.name = 'SSH.PublicKey' - left join - `cloud`.`ssh_keypairs` ON ssh_keypairs.public_key = user_vm_details.value - left join - `cloud`.`resource_tags` ON resource_tags.resource_id = vm_instance.id - and resource_tags.resource_type = 'UserVm' - left join - `cloud`.`async_job` ON async_job.instance_id = vm_instance.id - and async_job.instance_type = 'VirtualMachine' - and async_job.job_status = 0; - -DROP VIEW IF EXISTS `cloud`.`domain_router_view`; -CREATE VIEW `cloud`.`domain_router_view` AS - select - vm_instance.id id, - vm_instance.name name, - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name, - vm_instance.uuid uuid, - vm_instance.created created, - vm_instance.state state, - vm_instance.removed removed, - vm_instance.pod_id pod_id, - vm_instance.instance_name instance_name, - host_pod_ref.uuid pod_uuid, - data_center.id data_center_id, - data_center.uuid data_center_uuid, - data_center.name data_center_name, - data_center.dns1 dns1, - data_center.dns2 dns2, - host.id host_id, - host.uuid host_uuid, - host.name host_name, - vm_template.id template_id, - vm_template.uuid template_uuid, - service_offering.id service_offering_id, - disk_offering.uuid service_offering_uuid, - disk_offering.name service_offering_name, - nics.id nic_id, - nics.uuid nic_uuid, - nics.network_id network_id, - nics.ip4_address ip_address, - nics.default_nic is_default_nic, - nics.gateway gateway, - nics.netmask netmask, - nics.mac_address mac_address, - nics.broadcast_uri broadcast_uri, - nics.isolation_uri isolation_uri, - vpc.id vpc_id, - vpc.uuid vpc_uuid, - networks.uuid network_uuid, - networks.name network_name, - networks.network_domain network_domain, - networks.traffic_type traffic_type, - networks.guest_type guest_type, - async_job.id job_id, - async_job.uuid job_uuid, - async_job.job_status job_status, - async_job.account_id job_account_id, - domain_router.template_version template_version, - domain_router.scripts_version scripts_version, - domain_router.is_redundant_router is_redundant_router, - domain_router.redundant_state redundant_state, - domain_router.stop_pending stop_pending - from - `cloud`.`domain_router` - inner join - `cloud`.`vm_instance` ON vm_instance.id = domain_router.id - inner join - `cloud`.`account` ON vm_instance.account_id = account.id - inner join - `cloud`.`domain` ON vm_instance.domain_id = domain.id - left join - `cloud`.`host_pod_ref` ON vm_instance.pod_id = host_pod_ref.id - left join - `cloud`.`projects` ON projects.project_account_id = account.id - left join - `cloud`.`data_center` ON vm_instance.data_center_id = data_center.id - left join - `cloud`.`host` ON vm_instance.host_id = host.id - left join - `cloud`.`vm_template` ON vm_instance.vm_template_id = vm_template.id - left join - `cloud`.`service_offering` ON vm_instance.service_offering_id = service_offering.id - left join - `cloud`.`disk_offering` ON vm_instance.service_offering_id = disk_offering.id - left join - `cloud`.`volumes` ON vm_instance.id = volumes.instance_id - left join - `cloud`.`storage_pool` ON volumes.pool_id = storage_pool.id - left join - `cloud`.`nics` ON vm_instance.id = nics.instance_id - left join - `cloud`.`networks` ON nics.network_id = networks.id - left join - `cloud`.`vpc` ON networks.vpc_id = vpc.id - left join - `cloud`.`async_job` ON async_job.instance_id = vm_instance.id - and async_job.instance_type = 'DomainRouter' - and async_job.job_status = 0; - -DROP VIEW IF EXISTS `cloud`.`security_group_view`; -CREATE VIEW `cloud`.`security_group_view` AS - select - security_group.id id, - security_group.name name, - security_group.description description, - security_group.uuid uuid, - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name, - security_group_rule.id rule_id, - security_group_rule.uuid rule_uuid, - security_group_rule.type rule_type, - security_group_rule.start_port rule_start_port, - security_group_rule.end_port rule_end_port, - security_group_rule.protocol rule_protocol, - security_group_rule.allowed_network_id rule_allowed_network_id, - security_group_rule.allowed_ip_cidr rule_allowed_ip_cidr, - security_group_rule.create_status rule_create_status, - resource_tags.id tag_id, - resource_tags.uuid tag_uuid, - resource_tags.key tag_key, - resource_tags.value tag_value, - resource_tags.domain_id tag_domain_id, - resource_tags.account_id tag_account_id, - resource_tags.resource_id tag_resource_id, - resource_tags.resource_uuid tag_resource_uuid, - resource_tags.resource_type tag_resource_type, - resource_tags.customer tag_customer, - async_job.id job_id, - async_job.uuid job_uuid, - async_job.job_status job_status, - async_job.account_id job_account_id - from - `cloud`.`security_group` - left join - `cloud`.`security_group_rule` ON security_group.id = security_group_rule.security_group_id - inner join - `cloud`.`account` ON security_group.account_id = account.id - inner join - `cloud`.`domain` ON security_group.domain_id = domain.id - left join - `cloud`.`projects` ON projects.project_account_id = security_group.account_id - left join - `cloud`.`resource_tags` ON resource_tags.resource_id = security_group.id - and resource_tags.resource_type = 'SecurityGroup' - left join - `cloud`.`async_job` ON async_job.instance_id = security_group.id - and async_job.instance_type = 'SecurityGroup' - and async_job.job_status = 0; - -DROP VIEW IF EXISTS `cloud`.`resource_tag_view`; -CREATE VIEW `cloud`.`resource_tag_view` AS - select - resource_tags.id, - resource_tags.uuid, - resource_tags.key, - resource_tags.value, - resource_tags.resource_id, - resource_tags.resource_uuid, - resource_tags.resource_type, - resource_tags.customer, - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name - from - `cloud`.`resource_tags` - inner join - `cloud`.`account` ON resource_tags.account_id = account.id - inner join - `cloud`.`domain` ON resource_tags.domain_id = domain.id - left join - `cloud`.`projects` ON projects.project_account_id = resource_tags.account_id; - - -DROP VIEW IF EXISTS `cloud`.`event_view`; -CREATE VIEW `cloud`.`event_view` AS - select - event.id, - event.uuid, - event.type, - event.state, - event.description, - event.created, - event.level, - event.parameters, - event.start_id, - eve.uuid start_uuid, - event.user_id, - user.username user_name, - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name - from - `cloud`.`event` - inner join - `cloud`.`account` ON event.account_id = account.id - inner join - `cloud`.`domain` ON event.domain_id = domain.id - inner join - `cloud`.`user` ON event.user_id = user.id - left join - `cloud`.`projects` ON projects.project_account_id = event.account_id - left join - `cloud`.`event` eve ON event.start_id = eve.id; - -DROP VIEW IF EXISTS `cloud`.`instance_group_view`; -CREATE VIEW `cloud`.`instance_group_view` AS - select - instance_group.id, - instance_group.uuid, - instance_group.name, - instance_group.removed, - instance_group.created, - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name - from - `cloud`.`instance_group` - inner join - `cloud`.`account` ON instance_group.account_id = account.id - inner join - `cloud`.`domain` ON account.domain_id = domain.id - left join - `cloud`.`projects` ON projects.project_account_id = instance_group.account_id; - -DROP VIEW IF EXISTS `cloud`.`user_view`; -CREATE VIEW `cloud`.`user_view` AS - select - user.id, - user.uuid, - user.username, - user.password, - user.firstname, - user.lastname, - user.email, - user.state, - user.api_key, - user.secret_key, - user.created, - user.removed, - user.timezone, - user.registration_token, - user.is_registered, - user.incorrect_login_attempts, - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - async_job.id job_id, - async_job.uuid job_uuid, - async_job.job_status job_status, - async_job.account_id job_account_id - from - `cloud`.`user` - inner join - `cloud`.`account` ON user.account_id = account.id - inner join - `cloud`.`domain` ON account.domain_id = domain.id - left join - `cloud`.`async_job` ON async_job.instance_id = user.id - and async_job.instance_type = 'User' - and async_job.job_status = 0; - - -DROP VIEW IF EXISTS `cloud`.`project_view`; -CREATE VIEW `cloud`.`project_view` AS - select - projects.id, - projects.uuid, - projects.name, - projects.display_text, - projects.state, - projects.removed, - projects.created, - account.account_name owner, - pacct.account_id, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - resource_tags.id tag_id, - resource_tags.uuid tag_uuid, - resource_tags.key tag_key, - resource_tags.value tag_value, - resource_tags.domain_id tag_domain_id, - resource_tags.account_id tag_account_id, - resource_tags.resource_id tag_resource_id, - resource_tags.resource_uuid tag_resource_uuid, - resource_tags.resource_type tag_resource_type, - resource_tags.customer tag_customer - from - `cloud`.`projects` - inner join - `cloud`.`domain` ON projects.domain_id = domain.id - inner join - `cloud`.`project_account` ON projects.id = project_account.project_id - and project_account.account_role = 'Admin' - inner join - `cloud`.`account` ON account.id = project_account.account_id - left join - `cloud`.`resource_tags` ON resource_tags.resource_id = projects.id - and resource_tags.resource_type = 'Project' - left join - `cloud`.`project_account` pacct ON projects.id = pacct.project_id; - -DROP VIEW IF EXISTS `cloud`.`project_account_view`; -CREATE VIEW `cloud`.`project_account_view` AS - select - project_account.id, - account.id account_id, - account.uuid account_uuid, - account.account_name, - account.type account_type, - project_account.account_role, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path - from - `cloud`.`project_account` - inner join - `cloud`.`account` ON project_account.account_id = account.id - inner join - `cloud`.`domain` ON account.domain_id = domain.id - inner join - `cloud`.`projects` ON projects.id = project_account.project_id; - -DROP VIEW IF EXISTS `cloud`.`project_invitation_view`; -CREATE VIEW `cloud`.`project_invitation_view` AS - select - project_invitations.id, - project_invitations.uuid, - project_invitations.email, - project_invitations.created, - project_invitations.state, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name, - account.id account_id, - account.uuid account_uuid, - account.account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path - from - `cloud`.`project_invitations` - left join - `cloud`.`account` ON project_invitations.account_id = account.id - left join - `cloud`.`domain` ON project_invitations.domain_id = domain.id - left join - `cloud`.`projects` ON projects.id = project_invitations.project_id; - -DROP VIEW IF EXISTS `cloud`.`host_view`; -CREATE VIEW `cloud`.`host_view` AS - select - host.id, - host.uuid, - host.name, - host.status, - host.disconnected, - host.type, - host.private_ip_address, - host.version, - host.hypervisor_type, - host.hypervisor_version, - host.capabilities, - host.last_ping, - host.created, - host.removed, - host.resource_state, - host.mgmt_server_id, - host.cpus, - host.speed, - host.ram, - cluster.id cluster_id, - cluster.uuid cluster_uuid, - cluster.name cluster_name, - cluster.cluster_type, - data_center.id data_center_id, - data_center.uuid data_center_uuid, - data_center.name data_center_name, - host_pod_ref.id pod_id, - host_pod_ref.uuid pod_uuid, - host_pod_ref.name pod_name, - host_tags.tag, - guest_os_category.id guest_os_category_id, - guest_os_category.uuid guest_os_category_uuid, - guest_os_category.name guest_os_category_name, - mem_caps.used_capacity memory_used_capacity, - mem_caps.reserved_capacity memory_reserved_capacity, - cpu_caps.used_capacity cpu_used_capacity, - cpu_caps.reserved_capacity cpu_reserved_capacity, - async_job.id job_id, - async_job.uuid job_uuid, - async_job.job_status job_status, - async_job.account_id job_account_id - from - `cloud`.`host` - left join - `cloud`.`cluster` ON host.cluster_id = cluster.id - left join - `cloud`.`data_center` ON host.data_center_id = data_center.id - left join - `cloud`.`host_pod_ref` ON host.pod_id = host_pod_ref.id - left join - `cloud`.`host_details` ON host.id = host_details.id - and host_details.name = 'guest.os.category.id' - left join - `cloud`.`guest_os_category` ON guest_os_category.id = CONVERT( host_details.value , UNSIGNED) - left join - `cloud`.`host_tags` ON host_tags.host_id = host.id - left join - `cloud`.`op_host_capacity` mem_caps ON host.id = mem_caps.host_id - and mem_caps.capacity_type = 0 - left join - `cloud`.`op_host_capacity` cpu_caps ON host.id = cpu_caps.host_id - and cpu_caps.capacity_type = 1 - left join - `cloud`.`async_job` ON async_job.instance_id = host.id - and async_job.instance_type = 'Host' - and async_job.job_status = 0; - -DROP VIEW IF EXISTS `cloud`.`volume_view`; -CREATE VIEW `cloud`.`volume_view` AS - select - volumes.id, - volumes.uuid, - volumes.name, - volumes.device_id, - volumes.volume_type, - volumes.size, - volumes.created, - volumes.state, - volumes.attached, - volumes.removed, - volumes.pod_id, - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name, - data_center.id data_center_id, - data_center.uuid data_center_uuid, - data_center.name data_center_name, - vm_instance.id vm_id, - vm_instance.uuid vm_uuid, - vm_instance.name vm_name, - vm_instance.state vm_state, - vm_instance.vm_type, - user_vm.display_name vm_display_name, - volume_host_ref.size volume_host_size, - volume_host_ref.created volume_host_created, - volume_host_ref.format, - volume_host_ref.download_pct, - volume_host_ref.download_state, - volume_host_ref.error_str, - disk_offering.id disk_offering_id, - disk_offering.uuid disk_offering_uuid, - disk_offering.name disk_offering_name, - disk_offering.display_text disk_offering_display_text, - disk_offering.use_local_storage, - disk_offering.system_use, - storage_pool.id pool_id, - storage_pool.uuid pool_uuid, - storage_pool.name pool_name, - cluster.hypervisor_type, - vm_template.id template_id, - vm_template.uuid template_uuid, - vm_template.extractable, - vm_template.type template_type, - resource_tags.id tag_id, - resource_tags.uuid tag_uuid, - resource_tags.key tag_key, - resource_tags.value tag_value, - resource_tags.domain_id tag_domain_id, - resource_tags.account_id tag_account_id, - resource_tags.resource_id tag_resource_id, - resource_tags.resource_uuid tag_resource_uuid, - resource_tags.resource_type tag_resource_type, - resource_tags.customer tag_customer, - async_job.id job_id, - async_job.uuid job_uuid, - async_job.job_status job_status, - async_job.account_id job_account_id - from - `cloud`.`volumes` - inner join - `cloud`.`account` ON volumes.account_id = account.id - inner join - `cloud`.`domain` ON volumes.domain_id = domain.id - left join - `cloud`.`projects` ON projects.project_account_id = account.id - left join - `cloud`.`data_center` ON volumes.data_center_id = data_center.id - left join - `cloud`.`vm_instance` ON volumes.instance_id = vm_instance.id - left join - `cloud`.`user_vm` ON user_vm.id = vm_instance.id - left join - `cloud`.`volume_host_ref` ON volumes.id = volume_host_ref.volume_id - and volumes.data_center_id = volume_host_ref.zone_id - left join - `cloud`.`disk_offering` ON volumes.disk_offering_id = disk_offering.id - left join - `cloud`.`storage_pool` ON volumes.pool_id = storage_pool.id - left join - `cloud`.`cluster` ON storage_pool.cluster_id = cluster.id - left join - `cloud`.`vm_template` ON volumes.template_id = vm_template.id - left join - `cloud`.`resource_tags` ON resource_tags.resource_id = volumes.id - and resource_tags.resource_type = 'Volume' - left join - `cloud`.`async_job` ON async_job.instance_id = volumes.id - and async_job.instance_type = 'Volume' - and async_job.job_status = 0; - -DROP VIEW IF EXISTS `cloud`.`account_netstats_view`; -CREATE VIEW `cloud`.`account_netstats_view` AS - SELECT - account_id, - sum(net_bytes_received) + sum(current_bytes_received) as bytesReceived, - sum(net_bytes_sent) + sum(current_bytes_sent) as bytesSent - FROM - `cloud`.`user_statistics` - group by account_id; - - -DROP VIEW IF EXISTS `cloud`.`account_vmstats_view`; -CREATE VIEW `cloud`.`account_vmstats_view` AS - SELECT - account_id, state, count(*) as vmcount - from - `cloud`.`vm_instance` - group by account_id , state; - -DROP VIEW IF EXISTS `cloud`.`free_ip_view`; -CREATE VIEW `cloud`.`free_ip_view` AS - select - count(user_ip_address.id) free_ip - from - `cloud`.`user_ip_address` - inner join - `cloud`.`vlan` ON vlan.id = user_ip_address.vlan_db_id - and vlan.vlan_type = 'VirtualNetwork' - where - state = 'Free'; - -DROP VIEW IF EXISTS `cloud`.`account_view`; -CREATE VIEW `cloud`.`account_view` AS - select - account.id, - account.uuid, - account.account_name, - account.type, - account.state, - account.removed, - account.cleanup_needed, - account.network_domain, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - data_center.id data_center_id, - data_center.uuid data_center_uuid, - data_center.name data_center_name, - account_netstats_view.bytesReceived, - account_netstats_view.bytesSent, - vmlimit.max vmLimit, - vmcount.count vmTotal, - runningvm.vmcount runningVms, - stoppedvm.vmcount stoppedVms, - iplimit.max ipLimit, - ipcount.count ipTotal, - free_ip_view.free_ip ipFree, - volumelimit.max volumeLimit, - volumecount.count volumeTotal, - snapshotlimit.max snapshotLimit, - snapshotcount.count snapshotTotal, - templatelimit.max templateLimit, - templatecount.count templateTotal, - vpclimit.max vpcLimit, - vpccount.count vpcTotal, - projectlimit.max projectLimit, - projectcount.count projectTotal, - networklimit.max networkLimit, - networkcount.count networkTotal, - async_job.id job_id, - async_job.uuid job_uuid, - async_job.job_status job_status, - async_job.account_id job_account_id - from - `cloud`.`free_ip_view`, - `cloud`.`account` - inner join - `cloud`.`domain` ON account.domain_id = domain.id - left join - `cloud`.`data_center` ON account.default_zone_id = data_center.id - left join - `cloud`.`account_netstats_view` ON account.id = account_netstats_view.account_id - left join - `cloud`.`resource_limit` vmlimit ON account.id = vmlimit.account_id - and vmlimit.type = 'user_vm' - left join - `cloud`.`resource_count` vmcount ON account.id = vmcount.account_id - and vmcount.type = 'user_vm' - left join - `cloud`.`account_vmstats_view` runningvm ON account.id = runningvm.account_id - and runningvm.state = 'Running' - left join - `cloud`.`account_vmstats_view` stoppedvm ON account.id = stoppedvm.account_id - and stoppedvm.state = 'Stopped' - left join - `cloud`.`resource_limit` iplimit ON account.id = iplimit.account_id - and iplimit.type = 'public_ip' - left join - `cloud`.`resource_count` ipcount ON account.id = ipcount.account_id - and ipcount.type = 'public_ip' - left join - `cloud`.`resource_limit` volumelimit ON account.id = volumelimit.account_id - and volumelimit.type = 'volume' - left join - `cloud`.`resource_count` volumecount ON account.id = volumecount.account_id - and volumecount.type = 'volume' - left join - `cloud`.`resource_limit` snapshotlimit ON account.id = snapshotlimit.account_id - and snapshotlimit.type = 'snapshot' - left join - `cloud`.`resource_count` snapshotcount ON account.id = snapshotcount.account_id - and snapshotcount.type = 'snapshot' - left join - `cloud`.`resource_limit` templatelimit ON account.id = templatelimit.account_id - and templatelimit.type = 'template' - left join - `cloud`.`resource_count` templatecount ON account.id = templatecount.account_id - and templatecount.type = 'template' - left join - `cloud`.`resource_limit` vpclimit ON account.id = vpclimit.account_id - and vpclimit.type = 'vpc' - left join - `cloud`.`resource_count` vpccount ON account.id = vpccount.account_id - and vpccount.type = 'vpc' - left join - `cloud`.`resource_limit` projectlimit ON account.id = projectlimit.account_id - and projectlimit.type = 'project' - left join - `cloud`.`resource_count` projectcount ON account.id = projectcount.account_id - and projectcount.type = 'project' - left join - `cloud`.`resource_limit` networklimit ON account.id = networklimit.account_id - and networklimit.type = 'network' - left join - `cloud`.`resource_count` networkcount ON account.id = networkcount.account_id - and networkcount.type = 'network' - left join - `cloud`.`async_job` ON async_job.instance_id = account.id - and async_job.instance_type = 'Account' - and async_job.job_status = 0; - -DROP VIEW IF EXISTS `cloud`.`async_job_view`; -CREATE VIEW `cloud`.`async_job_view` AS - select - account.id account_id, - account.uuid account_uuid, - account.account_name account_name, - account.type account_type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path, - user.id user_id, - user.uuid user_uuid, - async_job.id, - async_job.uuid, - async_job.job_cmd, - async_job.job_status, - async_job.job_process_status, - async_job.job_result_code, - async_job.job_result, - async_job.created, - async_job.removed, - async_job.instance_type, - async_job.instance_id, - CASE - WHEN async_job.instance_type = 'Volume' THEN volumes.uuid - WHEN - async_job.instance_type = 'Template' - or async_job.instance_type = 'Iso' - THEN - vm_template.uuid - WHEN - async_job.instance_type = 'VirtualMachine' - or async_job.instance_type = 'ConsoleProxy' - or async_job.instance_type = 'SystemVm' - or async_job.instance_type = 'DomainRouter' - THEN - vm_instance.uuid - WHEN async_job.instance_type = 'Snapshot' THEN snapshots.uuid - WHEN async_job.instance_type = 'Host' THEN host.uuid - WHEN async_job.instance_type = 'StoragePool' THEN storage_pool.uuid - WHEN async_job.instance_type = 'IpAddress' THEN user_ip_address.uuid - WHEN async_job.instance_type = 'SecurityGroup' THEN security_group.uuid - WHEN async_job.instance_type = 'PhysicalNetwork' THEN physical_network.uuid - WHEN async_job.instance_type = 'TrafficType' THEN physical_network_traffic_types.uuid - WHEN async_job.instance_type = 'PhysicalNetworkServiceProvider' THEN physical_network_service_providers.uuid - WHEN async_job.instance_type = 'FirewallRule' THEN firewall_rules.uuid - WHEN async_job.instance_type = 'Account' THEN acct.uuid - WHEN async_job.instance_type = 'User' THEN us.uuid - WHEN async_job.instance_type = 'StaticRoute' THEN static_routes.uuid - WHEN async_job.instance_type = 'PrivateGateway' THEN vpc_gateways.uuid - WHEN async_job.instance_type = 'Counter' THEN counter.uuid - WHEN async_job.instance_type = 'Condition' THEN conditions.uuid - WHEN async_job.instance_type = 'AutoScalePolicy' THEN autoscale_policies.uuid - WHEN async_job.instance_type = 'AutoScaleVmProfile' THEN autoscale_vmprofiles.uuid - WHEN async_job.instance_type = 'AutoScaleVmGroup' THEN autoscale_vmgroups.uuid - ELSE null - END instance_uuid - from - `cloud`.`async_job` - left join - `cloud`.`account` ON async_job.account_id = account.id - left join - `cloud`.`domain` ON domain.id = account.domain_id - left join - `cloud`.`user` ON async_job.user_id = user.id - left join - `cloud`.`volumes` ON async_job.instance_id = volumes.id - left join - `cloud`.`vm_template` ON async_job.instance_id = vm_template.id - left join - `cloud`.`vm_instance` ON async_job.instance_id = vm_instance.id - left join - `cloud`.`snapshots` ON async_job.instance_id = snapshots.id - left join - `cloud`.`host` ON async_job.instance_id = host.id - left join - `cloud`.`storage_pool` ON async_job.instance_id = storage_pool.id - left join - `cloud`.`user_ip_address` ON async_job.instance_id = user_ip_address.id - left join - `cloud`.`security_group` ON async_job.instance_id = security_group.id - left join - `cloud`.`physical_network` ON async_job.instance_id = physical_network.id - left join - `cloud`.`physical_network_traffic_types` ON async_job.instance_id = physical_network_traffic_types.id - left join - `cloud`.`physical_network_service_providers` ON async_job.instance_id = physical_network_service_providers.id - left join - `cloud`.`firewall_rules` ON async_job.instance_id = firewall_rules.id - left join - `cloud`.`account` acct ON async_job.instance_id = acct.id - left join - `cloud`.`user` us ON async_job.instance_id = us.id - left join - `cloud`.`static_routes` ON async_job.instance_id = static_routes.id - left join - `cloud`.`vpc_gateways` ON async_job.instance_id = vpc_gateways.id - left join - `cloud`.`counter` ON async_job.instance_id = counter.id - left join - `cloud`.`conditions` ON async_job.instance_id = conditions.id - left join - `cloud`.`autoscale_policies` ON async_job.instance_id = autoscale_policies.id - left join - `cloud`.`autoscale_vmprofiles` ON async_job.instance_id = autoscale_vmprofiles.id - left join - `cloud`.`autoscale_vmgroups` ON async_job.instance_id = autoscale_vmgroups.id; - -DROP VIEW IF EXISTS `cloud`.`storage_pool_view`; -CREATE VIEW `cloud`.`storage_pool_view` AS - select - storage_pool.id, - storage_pool.uuid, - storage_pool.name, - storage_pool.status, - storage_pool.path, - storage_pool.pool_type, - storage_pool.host_address, - storage_pool.created, - storage_pool.removed, - storage_pool.capacity_bytes, - cluster.id cluster_id, - cluster.uuid cluster_uuid, - cluster.name cluster_name, - cluster.cluster_type, - data_center.id data_center_id, - data_center.uuid data_center_uuid, - data_center.name data_center_name, - host_pod_ref.id pod_id, - host_pod_ref.uuid pod_uuid, - host_pod_ref.name pod_name, - storage_pool_details.name tag, - op_host_capacity.used_capacity disk_used_capacity, - op_host_capacity.reserved_capacity disk_reserved_capacity, - async_job.id job_id, - async_job.uuid job_uuid, - async_job.job_status job_status, - async_job.account_id job_account_id - from - `cloud`.`storage_pool` - left join - `cloud`.`cluster` ON storage_pool.cluster_id = cluster.id - left join - `cloud`.`data_center` ON storage_pool.data_center_id = data_center.id - left join - `cloud`.`host_pod_ref` ON storage_pool.pod_id = host_pod_ref.id - left join - `cloud`.`storage_pool_details` ON storage_pool_details.pool_id = storage_pool.id - and storage_pool_details.value = 'true' - left join - `cloud`.`op_host_capacity` ON storage_pool.id = op_host_capacity.host_id - and op_host_capacity.capacity_type = 3 - left join - `cloud`.`async_job` ON async_job.instance_id = storage_pool.id - and async_job.instance_type = 'StoragePool' - and async_job.job_status = 0; - -DROP VIEW IF EXISTS `cloud`.`disk_offering_view`; -CREATE VIEW `cloud`.`disk_offering_view` AS - select - disk_offering.id, - disk_offering.uuid, - disk_offering.name, - disk_offering.display_text, - disk_offering.disk_size, - disk_offering.created, - disk_offering.tags, - disk_offering.customized, - disk_offering.removed, - disk_offering.use_local_storage, - disk_offering.system_use, - disk_offering.sort_key, - disk_offering.type, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path - from - `cloud`.`disk_offering` - left join - `cloud`.`domain` ON disk_offering.domain_id = domain.id; - -DROP VIEW IF EXISTS `cloud`.`service_offering_view`; -CREATE VIEW `cloud`.`service_offering_view` AS - select - service_offering.id, - disk_offering.uuid, - disk_offering.name, - disk_offering.display_text, - disk_offering.created, - disk_offering.tags, - disk_offering.removed, - disk_offering.use_local_storage, - disk_offering.system_use, - service_offering.cpu, - service_offering.speed, - service_offering.ram_size, - service_offering.nw_rate, - service_offering.mc_rate, - service_offering.ha_enabled, - service_offering.limit_cpu_use, - service_offering.host_tag, - service_offering.default_use, - service_offering.vm_type, - service_offering.sort_key, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path - from - `cloud`.`service_offering` - inner join - `cloud`.`disk_offering` ON service_offering.id = disk_offering.id - left join - `cloud`.`domain` ON disk_offering.domain_id = domain.id; - -DROP VIEW IF EXISTS `cloud`.`data_center_view`; -CREATE VIEW `cloud`.`data_center_view` AS - select - data_center.id, - data_center.uuid, - data_center.name, - data_center.is_security_group_enabled, - data_center.is_local_storage_enabled, - data_center.description, - data_center.dns1, - data_center.dns2, - data_center.internal_dns1, - data_center.internal_dns2, - data_center.guest_network_cidr, - data_center.domain, - data_center.networktype, - data_center.allocation_state, - data_center.zone_token, - data_center.dhcp_provider, - data_center.removed, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path - from - `cloud`.`data_center` - left join - `cloud`.`domain` ON data_center.domain_id = domain.id; \ No newline at end of file diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index f89c8851e8e..7361681da47 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -145,12 +145,12 @@ DROP TABLE IF EXISTS `cloud`.`region`; DROP TABLE IF EXISTS `cloud`.`s2s_customer_gateway`; DROP TABLE IF EXISTS `cloud`.`s2s_vpn_gateway`; DROP TABLE IF EXISTS `cloud`.`s2s_vpn_connection`; -DROP TABLE IF EXISTS `cloud`,`external_nicira_nvp_devices`; -DROP TABLE IF EXISTS `cloud`,`nicira_nvp_nic_map`; -DROP TABLE IF EXISTS `cloud`,`s3`; -DROP TABLE IF EXISTS `cloud`,`template_s3_ref`; -DROP TABLE IF EXISTS `cloud`,`nicira_nvp_router_map`; -DROP TABLE IF EXISTS `cloud`,`external_bigswitch_vns_devices`; +DROP TABLE IF EXISTS `cloud`.`external_nicira_nvp_devices`; +DROP TABLE IF EXISTS `cloud`.`nicira_nvp_nic_map`; +DROP TABLE IF EXISTS `cloud`.`s3`; +DROP TABLE IF EXISTS `cloud`.`template_s3_ref`; +DROP TABLE IF EXISTS `cloud`.`nicira_nvp_router_map`; +DROP TABLE IF EXISTS `cloud`.`external_bigswitch_vns_devices`; DROP TABLE IF EXISTS `cloud`.`autoscale_vmgroup_policy_map`; DROP TABLE IF EXISTS `cloud`.`autoscale_policy_condition_map`; DROP TABLE IF EXISTS `cloud`.`autoscale_vmgroups`; @@ -207,7 +207,7 @@ CREATE TABLE `cloud`.`version` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `version` (`version`, `updated`, `step`) VALUES('4.1.0', now(), 'Complete'); +INSERT INTO `version` (`version`, `updated`, `step`) VALUES('4.0.0', now(), 'Complete'); CREATE TABLE `cloud`.`op_it_work` ( `id` char(40) COMMENT 'reservation id', @@ -247,8 +247,6 @@ CREATE TABLE `cloud`.`networks` ( `broadcast_uri` varchar(255) COMMENT 'broadcast domain specifier', `gateway` varchar(15) COMMENT 'gateway for this network configuration', `cidr` varchar(18) COMMENT 'network cidr', - `ip6_gateway` varchar(50) COMMENT 'IPv6 gateway for this network', - `ip6_cidr` varchar(50) COMMENT 'IPv6 cidr for this network', `mode` varchar(32) COMMENT 'How to retrieve ip address in this network', `network_offering_id` bigint unsigned NOT NULL COMMENT 'network offering id that this configuration is created from', `physical_network_id` bigint unsigned COMMENT 'physical network id that this configuration is based on', @@ -312,8 +310,6 @@ CREATE TABLE `cloud`.`nics` ( `update_time` timestamp NOT NULL COMMENT 'time the state was changed', `isolation_uri` varchar(255) COMMENT 'id for isolation', `ip6_address` char(40) COMMENT 'ip6 address', - `ip6_gateway` varchar(50) COMMENT 'gateway for ip6 address', - `ip6_cidr` varchar(50) COMMENT 'cidr for ip6 address', `default_nic` tinyint NOT NULL COMMENT "None", `vm_type` varchar(32) COMMENT 'type of vm: System or User vm', `created` datetime NOT NULL COMMENT 'date created', @@ -352,8 +348,6 @@ CREATE TABLE `cloud`.`network_offerings` ( `elastic_ip_service` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if the network offering provides elastic ip service', `elastic_lb_service` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if the network offering provides elastic lb service', `specify_ip_ranges` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if the network offering provides an ability to define ip ranges', - `inline` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'Is this network offering LB provider is in inline mode', - `is_persistent` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if the network offering provides an ability to create persistent networks', PRIMARY KEY (`id`), INDEX `i_network_offerings__system_only`(`system_only`), INDEX `i_network_offerings__removed`(`removed`), @@ -528,14 +522,12 @@ CREATE TABLE `cloud`.`snapshots` ( `removed` datetime COMMENT 'Date removed. not null if removed', `backup_snap_id` varchar(255) COMMENT 'Back up uuid of the snapshot', `swift_id` bigint unsigned COMMENT 'which swift', - `s3_id` bigint unsigned COMMENT 'S3 to which this snapshot will be stored', `sechost_id` bigint unsigned COMMENT 'secondary storage host id', `prev_snap_id` bigint unsigned COMMENT 'Id of the most recent snapshot', `hypervisor_type` varchar(32) NOT NULL COMMENT 'hypervisor that the snapshot was taken under', `version` varchar(32) COMMENT 'snapshot version', PRIMARY KEY (`id`), CONSTRAINT `uc_snapshots__uuid` UNIQUE (`uuid`), - CONSTRAINT `fk_snapshots__s3_id` FOREIGN KEY `fk_snapshots__s3_id` (`s3_id`) REFERENCES `s3` (`id`), INDEX `i_snapshots__removed`(`removed`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -545,10 +537,7 @@ CREATE TABLE `cloud`.`vlan` ( `vlan_id` varchar(255), `vlan_gateway` varchar(255), `vlan_netmask` varchar(255), - `ip6_gateway` varchar(255), - `ip6_cidr` varchar(255), `description` varchar(255), - `ip6_range` varchar(255), `vlan_type` varchar(255), `data_center_id` bigint unsigned NOT NULL, `network_id` bigint unsigned NOT NULL COMMENT 'id of corresponding network offering', @@ -711,7 +700,7 @@ CREATE TABLE `cloud`.`op_dc_vnet_alloc` ( PRIMARY KEY (`id`), UNIQUE `i_op_dc_vnet_alloc__vnet__data_center_id__account_id`(`vnet`, `data_center_id`, `account_id`), INDEX `i_op_dc_vnet_alloc__dc_taken`(`data_center_id`, `taken`), - UNIQUE `i_op_dc_vnet_alloc__vnet__data_center_id`(`vnet`, `physical_network_id`, `data_center_id`), + UNIQUE `i_op_dc_vnet_alloc__vnet__data_center_id`(`vnet`, `data_center_id`), CONSTRAINT `fk_op_dc_vnet_alloc__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, CONSTRAINT `fk_op_dc_vnet_alloc__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -794,10 +783,12 @@ CREATE TABLE `cloud`.`load_balancer_stickiness_policies` ( CREATE TABLE `cloud`.`inline_load_balancer_nic_map` ( `id` bigint unsigned NOT NULL auto_increment, + `load_balancer_id` bigint unsigned NOT NULL, `public_ip_address` char(40) NOT NULL, `nic_id` bigint unsigned NULL COMMENT 'nic id', PRIMARY KEY (`id`), UNIQUE KEY (`nic_id`), + CONSTRAINT `fk_inline_load_balancer_nic_map__load_balancer_id` FOREIGN KEY(`load_balancer_id`) REFERENCES `load_balancing_rules`(`id`) ON DELETE CASCADE, CONSTRAINT `fk_inline_load_balancer_nic_map__nic_id` FOREIGN KEY(`nic_id`) REFERENCES `nics`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -950,7 +941,6 @@ CREATE TABLE `cloud`.`user` ( `timezone` varchar(30) default NULL, `registration_token` varchar(255) default NULL, `is_registered` tinyint NOT NULL DEFAULT 0 COMMENT '1: yes, 0: no', - `region_id` int unsigned NOT NULL, `incorrect_login_attempts` integer unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`id`), INDEX `i_user__removed`(`removed`), @@ -1079,7 +1069,6 @@ CREATE TABLE `cloud`.`vm_instance` ( `uuid` varchar(40), `instance_name` varchar(255) NOT NULL COMMENT 'name of the vm instance running on the hosts', `state` varchar(32) NOT NULL, - `desired_state` varchar(32) NULL, `vm_template_id` bigint unsigned, `guest_os_id` bigint unsigned NOT NULL, `private_mac_address` varchar(17), @@ -1169,7 +1158,6 @@ CREATE TABLE `cloud`.`upload` ( `id` bigint unsigned NOT NULL auto_increment, `host_id` bigint unsigned NOT NULL, `type_id` bigint unsigned NOT NULL, - `uuid` varchar(40), `type` varchar(255), `mode` varchar(255), `created` DATETIME NOT NULL, @@ -1302,7 +1290,6 @@ CREATE TABLE `cloud`.`domain` ( `state` char(32) NOT NULL default 'Active' COMMENT 'state of the domain', `network_domain` varchar(255), `type` varchar(255) NOT NULL DEFAULT 'Normal' COMMENT 'type of the domain - can be Normal or Project', - `region_id` int unsigned NOT NULL, PRIMARY KEY (`id`), UNIQUE (parent, name, removed), INDEX `i_domain__path`(`path`), @@ -1321,7 +1308,6 @@ CREATE TABLE `cloud`.`account` ( `cleanup_needed` tinyint(1) NOT NULL default '0', `network_domain` varchar(255), `default_zone_id` bigint unsigned, - `region_id` int unsigned NOT NULL, PRIMARY KEY (`id`), INDEX i_account__removed(`removed`), CONSTRAINT `fk_account__default_zone_id` FOREIGN KEY `fk_account__default_zone_id`(`default_zone_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, @@ -1384,7 +1370,6 @@ CREATE TABLE `cloud`.`alert` ( `last_sent` DATETIME NULL COMMENT 'Last time the alert was sent', `resolved` DATETIME NULL COMMENT 'when the alert status was resolved (available memory no longer at critical level, etc.)', PRIMARY KEY (`id`), - INDEX `last_sent` (`last_sent` DESC), CONSTRAINT `uc_alert__uuid` UNIQUE (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -1395,7 +1380,7 @@ CREATE TABLE `cloud`.`async_job` ( `session_key` varchar(64) COMMENT 'all async-job manage to apply session based security enforcement', `instance_type` varchar(64) COMMENT 'instance_type and instance_id work together to allow attaching an instance object to a job', `instance_id` bigint unsigned, - `job_cmd` varchar(255) NOT NULL COMMENT 'command name', + `job_cmd` varchar(64) NOT NULL COMMENT 'command name', `job_cmd_originator` varchar(64) COMMENT 'command originator', `job_cmd_info` text COMMENT 'command parameter info', `job_cmd_ver` int(1) COMMENT 'command version', @@ -1428,15 +1413,16 @@ CREATE TABLE `cloud`.`sync_queue` ( `id` bigint unsigned NOT NULL auto_increment, `sync_objtype` varchar(64) NOT NULL, `sync_objid` bigint unsigned NOT NULL, + `queue_proc_msid` bigint, `queue_proc_number` bigint COMMENT 'process number, increase 1 for each iteration', + `queue_proc_time` datetime COMMENT 'last time to process the queue', `created` datetime COMMENT 'date created', `last_updated` datetime COMMENT 'date created', - `queue_size` smallint DEFAULT 0 COMMENT 'number of items being processed by the queue', - `queue_size_limit` smallint DEFAULT 1 COMMENT 'max number of items the queue can process concurrently', PRIMARY KEY (`id`), UNIQUE `i_sync_queue__objtype__objid`(`sync_objtype`, `sync_objid`), INDEX `i_sync_queue__created`(`created`), - INDEX `i_sync_queue__last_updated`(`last_updated`) + INDEX `i_sync_queue__last_updated`(`last_updated`), + INDEX `i_sync_queue__queue_proc_time`(`queue_proc_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `cloud`.`stack_maid` ( @@ -1457,15 +1443,13 @@ CREATE TABLE `cloud`.`sync_queue_item` ( `content_id` bigint, `queue_proc_msid` bigint COMMENT 'owner msid when the queue item is being processed', `queue_proc_number` bigint COMMENT 'used to distinguish raw items and items being in process', - `queue_proc_time` datetime COMMENT 'when processing started for the item', `created` datetime COMMENT 'time created', PRIMARY KEY (`id`), CONSTRAINT `fk_sync_queue_item__queue_id` FOREIGN KEY `fk_sync_queue_item__queue_id` (`queue_id`) REFERENCES `sync_queue` (`id`) ON DELETE CASCADE, INDEX `i_sync_queue_item__queue_id`(`queue_id`), INDEX `i_sync_queue_item__created`(`created`), INDEX `i_sync_queue_item__queue_proc_number`(`queue_proc_number`), - INDEX `i_sync_queue_item__queue_proc_msid`(`queue_proc_msid`), - INDEX `i_sync_queue__queue_proc_time`(`queue_proc_time`) + INDEX `i_sync_queue_item__queue_proc_msid`(`queue_proc_msid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `cloud`.`disk_offering` ( @@ -1907,37 +1891,6 @@ CREATE TABLE `cloud`.`swift` ( CONSTRAINT `uc_swift__uuid` UNIQUE (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `cloud`.`s3` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `uuid` varchar(40), - `access_key` varchar(20) NOT NULL COMMENT ' The S3 access key', - `secret_key` varchar(40) NOT NULL COMMENT ' The S3 secret key', - `end_point` varchar(1024) COMMENT ' The S3 host', - `bucket` varchar(63) NOT NULL COMMENT ' The S3 host', - `https` tinyint unsigned DEFAULT NULL COMMENT ' Flag indicating whether or not to connect over HTTPS', - `connection_timeout` integer COMMENT ' The amount of time to wait (in milliseconds) when initially establishing a connection before giving up and timing out.', - `max_error_retry` integer COMMENT ' The maximum number of retry attempts for failed retryable requests (ex: 5xx error responses from services).', - `socket_timeout` integer COMMENT ' The amount of time to wait (in milliseconds) for data to be transfered over an established, open connection before the connection times out and is closed.', - `created` datetime COMMENT 'date the s3 first signed on', - PRIMARY KEY (`id`), - CONSTRAINT `uc_s3__uuid` UNIQUE (`uuid`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`template_s3_ref` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `s3_id` bigint unsigned NOT NULL COMMENT ' Associated S3 instance id', - `template_id` bigint unsigned NOT NULL COMMENT ' Associated template id', - `created` DATETIME NOT NULL COMMENT ' The creation timestamp', - `size` bigint unsigned COMMENT ' The size of the object', - `physical_size` bigint unsigned DEFAULT 0 COMMENT ' The physical size of the object', - PRIMARY KEY (`id`), - CONSTRAINT `uc_template_s3_ref__template_id` UNIQUE (`template_id`), - CONSTRAINT `fk_template_s3_ref__s3_id` FOREIGN KEY `fk_template_s3_ref__s3_id` (`s3_id`) REFERENCES `s3` (`id`) ON DELETE CASCADE, - CONSTRAINT `fk_template_s3_ref__template_id` FOREIGN KEY `fk_template_s3_ref__template_id` (`template_id`) REFERENCES `vm_template` (`id`), - INDEX `i_template_s3_ref__s3_id`(`s3_id`), - INDEX `i_template_s3_ref__template_id`(`template_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - CREATE TABLE `cloud`.`op_host_transfer` ( `id` bigint unsigned UNIQUE NOT NULL COMMENT 'Id of the host', `initial_mgmt_server_id` bigint unsigned COMMENT 'management server the host is transfered from', @@ -2128,6 +2081,7 @@ CREATE TABLE `cloud`.`external_load_balancer_devices` ( `device_state` varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'state (enabled/disabled/shutdown) of the device', `allocation_state` varchar(32) NOT NULL DEFAULT 'Free' COMMENT 'Allocation state (Free/Shared/Dedicated/Provider) of the device', `is_dedicated` int(1) unsigned NOT NULL DEFAULT 0 COMMENT '1 if device/appliance is provisioned for dedicated use only', + `is_inline` int(1) unsigned NOT NULL DEFAULT 0 COMMENT '1 if load balancer will be used in in-line configuration with firewall', `is_managed` int(1) unsigned NOT NULL DEFAULT 0 COMMENT '1 if load balancer appliance is provisioned and its life cycle is managed by by cloudstack', `host_id` bigint unsigned NOT NULL COMMENT 'host id coresponding to the external load balancer device', `parent_host_id` bigint unsigned COMMENT 'if the load balancer appliance is cloudstack managed, then host id on which this appliance is provisioned', @@ -2304,16 +2258,6 @@ CREATE TABLE `cloud`.`netscaler_pod_ref` ( CONSTRAINT `fk_ns_pod_ref__device_id` FOREIGN KEY (`external_load_balancer_device_id`) REFERENCES `external_load_balancer_devices`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`region` ( - `id` int unsigned NOT NULL UNIQUE, - `name` varchar(255) NOT NULL UNIQUE, - `end_point` varchar(255) NOT NULL, - `api_key` varchar(255), - `secret_key` varchar(255), - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - CREATE TABLE `cloud`.`vpc` ( `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', `uuid` varchar(40) NOT NULL, @@ -2475,181 +2419,5 @@ CREATE TABLE `cloud`.`nicira_nvp_nic_map` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `cloud`.`nicira_nvp_router_map` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `logicalrouter_uuid` varchar(255) NOT NULL UNIQUE COMMENT 'nicira uuid of logical router', - `network_id` bigint unsigned NOT NULL UNIQUE COMMENT 'cloudstack id of the network', - PRIMARY KEY (`id`), - CONSTRAINT `fk_nicira_nvp_router_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`external_bigswitch_vns_devices` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `uuid` varchar(255) UNIQUE, - `physical_network_id` bigint unsigned NOT NULL COMMENT 'id of the physical network in to which bigswitch vns device is added', - `provider_name` varchar(255) NOT NULL COMMENT 'Service Provider name corresponding to this bigswitch vns device', - `device_name` varchar(255) NOT NULL COMMENT 'name of the bigswitch vns device', - `host_id` bigint unsigned NOT NULL COMMENT 'host id coresponding to the external bigswitch vns device', - PRIMARY KEY (`id`), - CONSTRAINT `fk_external_bigswitch_vns_devices__host_id` FOREIGN KEY (`host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_external_bigswitch_vns_devices__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`counter` ( - `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id', - `uuid` varchar(40), - `source` varchar(255) NOT NULL COMMENT 'source e.g. netscaler, snmp', - `name` varchar(255) NOT NULL COMMENT 'Counter name', - `value` varchar(255) NOT NULL COMMENT 'Value in case of source=snmp', - `removed` datetime COMMENT 'date removed if not null', - `created` datetime NOT NULL COMMENT 'date created', - PRIMARY KEY (`id`), - CONSTRAINT `uc_counter__uuid` UNIQUE (`uuid`), - INDEX `i_counter__removed`(`removed`), - INDEX `i_counter__source`(`source`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`conditions` ( - `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id', - `uuid` varchar(40), - `counter_id` bigint unsigned NOT NULL COMMENT 'Counter Id', - `threshold` bigint unsigned NOT NULL COMMENT 'threshold value for the given counter', - `relational_operator` char(2) COMMENT 'relational operator to be used upon the counter and condition', - `domain_id` bigint unsigned NOT NULL COMMENT 'domain the Condition belongs to', - `account_id` bigint unsigned NOT NULL COMMENT 'owner of this Condition', - `removed` datetime COMMENT 'date removed if not null', - `created` datetime NOT NULL COMMENT 'date created', - PRIMARY KEY (`id`), - CONSTRAINT `fk_conditions__counter_id` FOREIGN KEY `fk_condition__counter_id`(`counter_id`) REFERENCES `counter`(`id`), - CONSTRAINT `fk_conditions__account_id` FOREIGN KEY `fk_condition__account_id` (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_conditions__domain_id` FOREIGN KEY `fk_condition__domain_id` (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE, - CONSTRAINT `uc_conditions__uuid` UNIQUE (`uuid`), - INDEX `i_conditions__removed`(`removed`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`autoscale_vmprofiles` ( - `id` bigint unsigned NOT NULL auto_increment, - `uuid` varchar(40), - `zone_id` bigint unsigned NOT NULL, - `domain_id` bigint unsigned NOT NULL, - `account_id` bigint unsigned NOT NULL, - `autoscale_user_id` bigint unsigned NOT NULL, - `service_offering_id` bigint unsigned NOT NULL, - `template_id` bigint unsigned NOT NULL, - `other_deploy_params` varchar(1024) COMMENT 'other deployment parameters that is in addition to zoneid,serviceofferingid,domainid', - `destroy_vm_grace_period` int unsigned COMMENT 'the time allowed for existing connections to get closed before a vm is destroyed', - `counter_params` varchar(1024) COMMENT 'the parameters for the counter to be used to get metric information from VMs', - `created` datetime NOT NULL COMMENT 'date created', - `removed` datetime COMMENT 'date removed if not null', - PRIMARY KEY (`id`), - CONSTRAINT `fk_autoscale_vmprofiles__domain_id` FOREIGN KEY `fk_autoscale_vmprofiles__domain_id` (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_autoscale_vmprofiles__account_id` FOREIGN KEY `fk_autoscale_vmprofiles__account_id` (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_autoscale_vmprofiles__autoscale_user_id` FOREIGN KEY `fk_autoscale_vmprofiles__autoscale_user_id` (`autoscale_user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE, - CONSTRAINT `uc_autoscale_vmprofiles__uuid` UNIQUE (`uuid`), - INDEX `i_autoscale_vmprofiles__removed`(`removed`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`autoscale_policies` ( - `id` bigint unsigned NOT NULL auto_increment, - `uuid` varchar(40), - `domain_id` bigint unsigned NOT NULL, - `account_id` bigint unsigned NOT NULL, - `duration` int unsigned NOT NULL, - `quiet_time` int unsigned NOT NULL, - `action` varchar(15), - `created` datetime NOT NULL COMMENT 'date created', - `removed` datetime COMMENT 'date removed if not null', - PRIMARY KEY (`id`), - CONSTRAINT `fk_autoscale_policies__domain_id` FOREIGN KEY `fk_autoscale_policies__domain_id` (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_autoscale_policies__account_id` FOREIGN KEY `fk_autoscale_policies__account_id` (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE, - CONSTRAINT `uc_autoscale_policies__uuid` UNIQUE (`uuid`), - INDEX `i_autoscale_policies__removed`(`removed`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`autoscale_vmgroups` ( - `id` bigint unsigned NOT NULL auto_increment, - `uuid` varchar(40), - `zone_id` bigint unsigned NOT NULL, - `domain_id` bigint unsigned NOT NULL, - `account_id` bigint unsigned NOT NULL, - `load_balancer_id` bigint unsigned NOT NULL, - `min_members` int unsigned DEFAULT 1, - `max_members` int unsigned NOT NULL, - `member_port` int unsigned NOT NULL, - `interval` int unsigned NOT NULL, - `profile_id` bigint unsigned NOT NULL, - `state` varchar(255) NOT NULL COMMENT 'enabled or disabled, a vmgroup is disabled to stop autoscaling activity', - `created` datetime NOT NULL COMMENT 'date created', - `removed` datetime COMMENT 'date removed if not null', - PRIMARY KEY (`id`), - CONSTRAINT `fk_autoscale_vmgroup__autoscale_vmprofile_id` FOREIGN KEY(`profile_id`) REFERENCES `autoscale_vmprofiles`(`id`), - CONSTRAINT `fk_autoscale_vmgroup__load_balancer_id` FOREIGN KEY(`load_balancer_id`) REFERENCES `load_balancing_rules`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_autoscale_vmgroups__domain_id` FOREIGN KEY `fk_autoscale_vmgroups__domain_id` (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_autoscale_vmgroups__account_id` FOREIGN KEY `fk_autoscale_vmgroups__account_id` (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_autoscale_vmgroups__zone_id` FOREIGN KEY `fk_autoscale_vmgroups__zone_id`(`zone_id`) REFERENCES `data_center`(`id`), - CONSTRAINT `uc_autoscale_vmgroups__uuid` UNIQUE (`uuid`), - INDEX `i_autoscale_vmgroups__removed`(`removed`), - INDEX `i_autoscale_vmgroups__load_balancer_id`(`load_balancer_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`autoscale_policy_condition_map` ( - `id` bigint unsigned NOT NULL auto_increment, - `policy_id` bigint unsigned NOT NULL, - `condition_id` bigint unsigned NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_autoscale_policy_condition_map__policy_id` FOREIGN KEY `fk_autoscale_policy_condition_map__policy_id` (`policy_id`) REFERENCES `autoscale_policies` (`id`) ON DELETE CASCADE, - CONSTRAINT `fk_autoscale_policy_condition_map__condition_id` FOREIGN KEY `fk_autoscale_policy_condition_map__condition_id` (`condition_id`) REFERENCES `conditions` (`id`), - INDEX `i_autoscale_policy_condition_map__policy_id`(`policy_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`autoscale_vmgroup_policy_map` ( - `id` bigint unsigned NOT NULL auto_increment, - `vmgroup_id` bigint unsigned NOT NULL, - `policy_id` bigint unsigned NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_autoscale_vmgroup_policy_map__vmgroup_id` FOREIGN KEY `fk_autoscale_vmgroup_policy_map__vmgroup_id` (`vmgroup_id`) REFERENCES `autoscale_vmgroups` (`id`) ON DELETE CASCADE, - CONSTRAINT `fk_autoscale_vmgroup_policy_map__policy_id` FOREIGN KEY `fk_autoscale_vmgroup_policy_map__policy_id` (`policy_id`) REFERENCES `autoscale_policies` (`id`), - INDEX `i_autoscale_vmgroup_policy_map__vmgroup_id`(`vmgroup_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`region_sync` ( - `id` bigint unsigned NOT NULL auto_increment, - `region_id` int unsigned NOT NULL, - `api` varchar(1024) NOT NULL, - `created` datetime NOT NULL COMMENT 'date created', - `processed` tinyint NOT NULL default '0', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (1, UUID(), 'snmp','Linux User CPU - percentage', '1.3.6.1.4.1.2021.11.9.0', now()); -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`.`user_ipv6_address` ( - `id` bigint unsigned NOT NULL UNIQUE auto_increment, - `uuid` varchar(40), - `account_id` bigint unsigned NULL, - `domain_id` bigint unsigned NULL, - `ip_address` char(50) NOT NULL, - `data_center_id` bigint unsigned NOT NULL COMMENT 'zone that it belongs to', - `vlan_id` bigint unsigned NOT NULL, - `state` char(32) NOT NULL default 'Free' COMMENT 'state of the ip address', - `mac_address` varchar(40) NOT NULL COMMENT 'mac address of this ip', - `source_network_id` bigint unsigned NOT NULL COMMENT 'network id ip belongs to', - `network_id` bigint unsigned COMMENT 'network this public ip address is associated with', - `physical_network_id` bigint unsigned NOT NULL COMMENT 'physical network id that this configuration is based on', - `created` datetime NULL COMMENT 'Date this ip was allocated to someone', - PRIMARY KEY (`id`), - UNIQUE (`ip_address`, `source_network_id`), - CONSTRAINT `fk_user_ipv6_address__source_network_id` FOREIGN KEY (`source_network_id`) REFERENCES `networks`(`id`), - CONSTRAINT `fk_user_ipv6_address__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), - CONSTRAINT `fk_user_ipv6_address__account_id` FOREIGN KEY (`account_id`) REFERENCES `account`(`id`), - CONSTRAINT `fk_user_ipv6_address__vlan_id` FOREIGN KEY (`vlan_id`) REFERENCES `vlan`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_user_ipv6_address__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, - CONSTRAINT `uc_user_ipv6_address__uuid` UNIQUE (`uuid`), - CONSTRAINT `fk_user_ipv6_address__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - SET foreign_key_checks = 1; diff --git a/setup/db/db/schema-40to410-cleanup.sql b/setup/db/db/schema-40to410-cleanup.sql new file mode 100644 index 00000000000..411b568de4a --- /dev/null +++ b/setup/db/db/schema-40to410-cleanup.sql @@ -0,0 +1,21 @@ +-- 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. + +--; +-- Schema cleanup from 4.0.0 to 4.1.0; +--; + diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index a51ddb3fe8c..d89dac739ef 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -19,6 +19,93 @@ -- Schema upgrade from 4.0.0 to 4.1.0; --; +use cloud; +SET foreign_key_checks = 0; + +alter table vm_template add size bigint unsigned; +alter table vm_template add state varchar(255); +alter table vm_template add update_count bigint unsigned; +alter table vm_template add updated datetime; +alter table storage_pool add storage_provider_id bigint unsigned; +alter table storage_pool add scope varchar(255); +alter table storage_pool modify id bigint unsigned AUTO_INCREMENT UNIQUE NOT NULL; +alter table template_spool_ref add state varchar(255); +alter table template_spool_ref add update_count bigint unsigned; +alter table volumes add disk_type varchar(255); +alter table volumes drop foreign key `fk_volumes__account_id`; +alter table vm_instance add column disk_offering_id bigint unsigned; +alter table vm_instance add column cpu int(10) unsigned; +alter table vm_instance add column ram bigint unsigned; +alter table vm_instance add column owner varchar(255); +alter table vm_instance add column speed int(10) unsigned; +alter table vm_instance add column host_name varchar(255); +alter table vm_instance add column display_name varchar(255); +alter table vm_instance add column `desired_state` varchar(32) NULL; + +alter table data_center add column owner varchar(255); +alter table data_center add column created datetime COMMENT 'date created'; +alter table data_center add column lastUpdated datetime COMMENT 'last updated'; +alter table data_center add column engine_state varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'the engine state of the zone'; +alter table host_pod_ref add column owner varchar(255); +alter table host_pod_ref add column created datetime COMMENT 'date created'; +alter table host_pod_ref add column lastUpdated datetime COMMENT 'last updated'; +alter table host_pod_ref add column engine_state varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'the engine state of the zone'; +alter table host add column owner varchar(255); +alter table host add column lastUpdated datetime COMMENT 'last updated'; +alter table host add column engine_state varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'the engine state of the zone'; + +alter table cluster add column owner varchar(255); +alter table cluster add column created datetime COMMENT 'date created'; +alter table cluster add column lastUpdated datetime COMMENT 'last updated'; +alter table cluster add column engine_state varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'the engine state of the zone'; + +CREATE TABLE `cloud`.`vm_compute_tags` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', + `compute_tag` varchar(255) NOT NULL COMMENT 'name of tag', + PRIMARY KEY(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`vm_root_disk_tags` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', + `root_disk_tag` varchar(255) NOT NULL COMMENT 'name of tag', + PRIMARY KEY(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE `cloud`.`vm_network_map` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', + `network_id` bigint unsigned NOT NULL COMMENT 'network id', + PRIMARY KEY(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE `cloud`.`vm_reservation` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `uuid` varchar(40) NOT NULL COMMENT 'reservation id', + `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', + `data_center_id` bigint unsigned NOT NULL COMMENT 'zone id', + `pod_id` bigint unsigned NOT NULL COMMENT 'pod id', + `cluster_id` bigint unsigned NOT NULL COMMENT 'cluster id', + `host_id` bigint unsigned NOT NULL COMMENT 'host id', + `created` datetime COMMENT 'date created', + `removed` datetime COMMENT 'date removed if not null', + CONSTRAINT `uc_vm_reservation__uuid` UNIQUE (`uuid`), + PRIMARY KEY(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`volume_reservation` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `vm_reservation_id` bigint unsigned NOT NULL COMMENT 'id of the vm reservation', + `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', + `volume_id` bigint unsigned NOT NULL COMMENT 'volume id', + `pool_id` bigint unsigned NOT NULL COMMENT 'pool assigned to the volume', + CONSTRAINT `fk_vm_pool_reservation__vm_reservation_id` FOREIGN KEY (`vm_reservation_id`) REFERENCES `vm_reservation`(`id`) ON DELETE CASCADE, + PRIMARY KEY(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CREATE TABLE `cloud`.`s3` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `uuid` varchar(40), @@ -46,7 +133,7 @@ CREATE TABLE `cloud`.`template_s3_ref` ( CONSTRAINT `uc_template_s3_ref__template_id` UNIQUE (`template_id`), CONSTRAINT `fk_template_s3_ref__s3_id` FOREIGN KEY `fk_template_s3_ref__s3_id` (`s3_id`) REFERENCES `s3` (`id`) ON DELETE CASCADE, CONSTRAINT `fk_template_s3_ref__template_id` FOREIGN KEY `fk_template_s3_ref__template_id` (`template_id`) REFERENCES `vm_template` (`id`), - INDEX `i_template_s3_ref__swift_id`(`s3_id`), + INDEX `i_template_s3_ref__s3_id`(`s3_id`), INDEX `i_template_s3_ref__template_id`(`template_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -64,11 +151,19 @@ ALTER TABLE `cloud`.`external_load_balancer_devices` DROP COLUMN `is_inline`; INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Network','DEFAULT','NetworkManager','network.dhcp.nondefaultnetwork.setgateway.guestos','Windows','The guest OS\'s name start with this fields would result in DHCP server response gateway information even when the network it\'s on is not default network. Names are separated by comma.'); -ALTER TABLE `sync_queue` ADD `queue_size` SMALLINT NOT NULL DEFAULT '0' COMMENT 'number of items being processed by the queue'; +ALTER TABLE `cloud`.`sync_queue` ADD `queue_size` SMALLINT NOT NULL DEFAULT '0' COMMENT 'number of items being processed by the queue'; -ALTER TABLE `sync_queue` ADD `queue_size_limit` SMALLINT NOT NULL DEFAULT '1' COMMENT 'max number of items the queue can process concurrently'; +ALTER TABLE `cloud`.`sync_queue` ADD `queue_size_limit` SMALLINT NOT NULL DEFAULT '1' COMMENT 'max number of items the queue can process concurrently'; -ALTER TABLE `sync_queue_item` ADD `queue_proc_time` DATETIME NOT NULL COMMENT 'when processing started for the item' AFTER `queue_proc_number`; +ALTER TABLE `cloud`.`sync_queue` DROP INDEX `i_sync_queue__queue_proc_time`; + +ALTER TABLE `cloud`.`sync_queue` DROP COLUMN `queue_proc_time`; + +ALTER TABLE `cloud`.`sync_queue` DROP COLUMN `queue_proc_msid`; + +ALTER TABLE `cloud`.`sync_queue_item` ADD `queue_proc_time` DATETIME COMMENT 'when processing started for the item' AFTER `queue_proc_number`; + +ALTER TABLE `cloud`.`sync_queue_item` ADD INDEX `i_sync_queue__queue_proc_time`(`queue_proc_time`); ALTER TABLE `cloud`.`inline_load_balancer_nic_map` DROP FOREIGN KEY fk_inline_load_balancer_nic_map__load_balancer_id; @@ -128,7 +223,7 @@ UPDATE `cloud`.`swift` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`upload` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`user` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`user_ip_address` set uuid=id WHERE uuid is NULL; -UPDATE `cloud`.`user_vm_temp` set uuid=id WHERE uuid is NULL; +-- UPDATE `cloud`.`user_vm_temp` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`virtual_router_providers` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`virtual_supervisor_module` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`vlan` set uuid=id WHERE uuid is NULL; @@ -139,17 +234,261 @@ UPDATE `cloud`.`vpc_gateways` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`vpc_offerings` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`vpn_users` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`volumes` set uuid=id WHERE uuid is NULL; -UPDATE `cloud`.`autoscale_vmgroups` set uuid=id WHERE uuid is NULL; -UPDATE `cloud`.`autoscale_vmprofiles` set uuid=id WHERE uuid is NULL; -UPDATE `cloud`.`autoscale_policies` set uuid=id WHERE uuid is NULL; -UPDATE `cloud`.`counter` set uuid=id WHERE uuid is NULL; -UPDATE `cloud`.`conditions` set uuid=id WHERE uuid is NULL; +-- UPDATE `cloud`.`autoscale_vmgroups` set uuid=id WHERE uuid is NULL; +-- UPDATE `cloud`.`autoscale_vmprofiles` set uuid=id WHERE uuid is NULL; +-- UPDATE `cloud`.`autoscale_policies` set uuid=id WHERE uuid is NULL; +-- UPDATE `cloud`.`counter` set uuid=id WHERE uuid is NULL; +-- UPDATE `cloud`.`conditions` set uuid=id WHERE uuid is NULL; INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'detail.batch.query.size', '2000', 'Default entity detail batch query size for listing'); INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'api.throttling.interval', '1', 'Time interval (in seconds) to reset API count'); INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'api.throttling.max', '25', 'Max allowed number of APIs within fixed interval'); INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'api.throttling.cachesize', '50000', 'Account based API count cache size'); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'direct.agent.pool.size', '500', 'Default size for DirectAgentPool'); + +ALTER TABLE `cloud`.`op_dc_vnet_alloc` DROP INDEX i_op_dc_vnet_alloc__vnet__data_center_id; + +ALTER TABLE `cloud`.`op_dc_vnet_alloc` ADD CONSTRAINT UNIQUE `i_op_dc_vnet_alloc__vnet__data_center_id`(`vnet`, `physical_network_id`, `data_center_id`); + +CREATE TABLE `cloud`.`region` ( + `id` int unsigned NOT NULL UNIQUE, + `name` varchar(255) NOT NULL UNIQUE, + `end_point` varchar(255) NOT NULL, + `api_key` varchar(255), + `secret_key` varchar(255), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`region_sync` ( + `id` bigint unsigned NOT NULL auto_increment, + `region_id` int unsigned NOT NULL, + `api` varchar(1024) NOT NULL, + `created` datetime NOT NULL COMMENT 'date created', + `processed` tinyint NOT NULL default '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- INSERT INTO `cloud`.`region` values ('1','Local','http://localhost:8080/client/api','',''); +ALTER TABLE `cloud`.`account` ADD COLUMN `region_id` int unsigned NOT NULL DEFAULT '1'; +ALTER TABLE `cloud`.`user` ADD COLUMN `region_id` int unsigned NOT NULL DEFAULT '1'; +ALTER TABLE `cloud`.`domain` ADD COLUMN `region_id` int unsigned NOT NULL DEFAULT '1'; + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Account Defaults', 'DEFAULT', 'management-server', 'max.account.cpus', '40', 'The default maximum number of cpu cores that can be used for an account'); + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Account Defaults', 'DEFAULT', 'management-server', 'max.account.memory', '40960', 'The default maximum memory (in MB) that can be used for an account'); + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Project Defaults', 'DEFAULT', 'management-server', 'max.project.cpus', '40', 'The default maximum number of cpu cores that can be used for a project'); + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Project Defaults', 'DEFAULT', 'management-server', 'max.project.memory', '40960', 'The default maximum memory (in MB) that can be used for a project'); + +ALTER TABLE `cloud_usage`.`account` ADD COLUMN `region_id` int unsigned NOT NULL DEFAULT '1'; + +CREATE TABLE `cloud`.`nicira_nvp_router_map` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `logicalrouter_uuid` varchar(255) NOT NULL UNIQUE COMMENT 'nicira uuid of logical router', + `network_id` bigint unsigned NOT NULL UNIQUE COMMENT 'cloudstack id of the network', + PRIMARY KEY (`id`), + CONSTRAINT `fk_nicira_nvp_router_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`external_bigswitch_vns_devices` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `uuid` varchar(255) UNIQUE, + `physical_network_id` bigint unsigned NOT NULL COMMENT 'id of the physical network in to which bigswitch vns device is added', + `provider_name` varchar(255) NOT NULL COMMENT 'Service Provider name corresponding to this bigswitch vns device', + `device_name` varchar(255) NOT NULL COMMENT 'name of the bigswitch vns device', + `host_id` bigint unsigned NOT NULL COMMENT 'host id coresponding to the external bigswitch vns device', + PRIMARY KEY (`id`), + CONSTRAINT `fk_external_bigswitch_vns_devices__host_id` FOREIGN KEY (`host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_external_bigswitch_vns_devices__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`counter` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id', + `uuid` varchar(40), + `source` varchar(255) NOT NULL COMMENT 'source e.g. netscaler, snmp', + `name` varchar(255) NOT NULL COMMENT 'Counter name', + `value` varchar(255) NOT NULL COMMENT 'Value in case of source=snmp', + `removed` datetime COMMENT 'date removed if not null', + `created` datetime NOT NULL COMMENT 'date created', + PRIMARY KEY (`id`), + CONSTRAINT `uc_counter__uuid` UNIQUE (`uuid`), + INDEX `i_counter__removed`(`removed`), + INDEX `i_counter__source`(`source`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`conditions` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id', + `uuid` varchar(40), + `counter_id` bigint unsigned NOT NULL COMMENT 'Counter Id', + `threshold` bigint unsigned NOT NULL COMMENT 'threshold value for the given counter', + `relational_operator` char(2) COMMENT 'relational operator to be used upon the counter and condition', + `domain_id` bigint unsigned NOT NULL COMMENT 'domain the Condition belongs to', + `account_id` bigint unsigned NOT NULL COMMENT 'owner of this Condition', + `removed` datetime COMMENT 'date removed if not null', + `created` datetime NOT NULL COMMENT 'date created', + PRIMARY KEY (`id`), + CONSTRAINT `fk_conditions__counter_id` FOREIGN KEY `fk_condition__counter_id`(`counter_id`) REFERENCES `counter`(`id`), + CONSTRAINT `fk_conditions__account_id` FOREIGN KEY `fk_condition__account_id` (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_conditions__domain_id` FOREIGN KEY `fk_condition__domain_id` (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE, + CONSTRAINT `uc_conditions__uuid` UNIQUE (`uuid`), + INDEX `i_conditions__removed`(`removed`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`autoscale_vmprofiles` ( + `id` bigint unsigned NOT NULL auto_increment, + `uuid` varchar(40), + `zone_id` bigint unsigned NOT NULL, + `domain_id` bigint unsigned NOT NULL, + `account_id` bigint unsigned NOT NULL, + `autoscale_user_id` bigint unsigned NOT NULL, + `service_offering_id` bigint unsigned NOT NULL, + `template_id` bigint unsigned NOT NULL, + `other_deploy_params` varchar(1024) COMMENT 'other deployment parameters that is in addition to zoneid,serviceofferingid,domainid', + `destroy_vm_grace_period` int unsigned COMMENT 'the time allowed for existing connections to get closed before a vm is destroyed', + `counter_params` varchar(1024) COMMENT 'the parameters for the counter to be used to get metric information from VMs', + `created` datetime NOT NULL COMMENT 'date created', + `removed` datetime COMMENT 'date removed if not null', + PRIMARY KEY (`id`), + CONSTRAINT `fk_autoscale_vmprofiles__domain_id` FOREIGN KEY `fk_autoscale_vmprofiles__domain_id` (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_autoscale_vmprofiles__account_id` FOREIGN KEY `fk_autoscale_vmprofiles__account_id` (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_autoscale_vmprofiles__autoscale_user_id` FOREIGN KEY `fk_autoscale_vmprofiles__autoscale_user_id` (`autoscale_user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE, + CONSTRAINT `uc_autoscale_vmprofiles__uuid` UNIQUE (`uuid`), + INDEX `i_autoscale_vmprofiles__removed`(`removed`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`autoscale_policies` ( + `id` bigint unsigned NOT NULL auto_increment, + `uuid` varchar(40), + `domain_id` bigint unsigned NOT NULL, + `account_id` bigint unsigned NOT NULL, + `duration` int unsigned NOT NULL, + `quiet_time` int unsigned NOT NULL, + `action` varchar(15), + `created` datetime NOT NULL COMMENT 'date created', + `removed` datetime COMMENT 'date removed if not null', + PRIMARY KEY (`id`), + CONSTRAINT `fk_autoscale_policies__domain_id` FOREIGN KEY `fk_autoscale_policies__domain_id` (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_autoscale_policies__account_id` FOREIGN KEY `fk_autoscale_policies__account_id` (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE, + CONSTRAINT `uc_autoscale_policies__uuid` UNIQUE (`uuid`), + INDEX `i_autoscale_policies__removed`(`removed`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`autoscale_vmgroups` ( + `id` bigint unsigned NOT NULL auto_increment, + `uuid` varchar(40), + `zone_id` bigint unsigned NOT NULL, + `domain_id` bigint unsigned NOT NULL, + `account_id` bigint unsigned NOT NULL, + `load_balancer_id` bigint unsigned NOT NULL, + `min_members` int unsigned DEFAULT 1, + `max_members` int unsigned NOT NULL, + `member_port` int unsigned NOT NULL, + `interval` int unsigned NOT NULL, + `profile_id` bigint unsigned NOT NULL, + `state` varchar(255) NOT NULL COMMENT 'enabled or disabled, a vmgroup is disabled to stop autoscaling activity', + `created` datetime NOT NULL COMMENT 'date created', + `removed` datetime COMMENT 'date removed if not null', + PRIMARY KEY (`id`), + CONSTRAINT `fk_autoscale_vmgroup__autoscale_vmprofile_id` FOREIGN KEY(`profile_id`) REFERENCES `autoscale_vmprofiles`(`id`), + CONSTRAINT `fk_autoscale_vmgroup__load_balancer_id` FOREIGN KEY(`load_balancer_id`) REFERENCES `load_balancing_rules`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_autoscale_vmgroups__domain_id` FOREIGN KEY `fk_autoscale_vmgroups__domain_id` (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_autoscale_vmgroups__account_id` FOREIGN KEY `fk_autoscale_vmgroups__account_id` (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_autoscale_vmgroups__zone_id` FOREIGN KEY `fk_autoscale_vmgroups__zone_id`(`zone_id`) REFERENCES `data_center`(`id`), + CONSTRAINT `uc_autoscale_vmgroups__uuid` UNIQUE (`uuid`), + INDEX `i_autoscale_vmgroups__removed`(`removed`), + INDEX `i_autoscale_vmgroups__load_balancer_id`(`load_balancer_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`autoscale_policy_condition_map` ( + `id` bigint unsigned NOT NULL auto_increment, + `policy_id` bigint unsigned NOT NULL, + `condition_id` bigint unsigned NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_autoscale_policy_condition_map__policy_id` FOREIGN KEY `fk_autoscale_policy_condition_map__policy_id` (`policy_id`) REFERENCES `autoscale_policies` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_autoscale_policy_condition_map__condition_id` FOREIGN KEY `fk_autoscale_policy_condition_map__condition_id` (`condition_id`) REFERENCES `conditions` (`id`), + INDEX `i_autoscale_policy_condition_map__policy_id`(`policy_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`autoscale_vmgroup_policy_map` ( + `id` bigint unsigned NOT NULL auto_increment, + `vmgroup_id` bigint unsigned NOT NULL, + `policy_id` bigint unsigned NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_autoscale_vmgroup_policy_map__vmgroup_id` FOREIGN KEY `fk_autoscale_vmgroup_policy_map__vmgroup_id` (`vmgroup_id`) REFERENCES `autoscale_vmgroups` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_autoscale_vmgroup_policy_map__policy_id` FOREIGN KEY `fk_autoscale_vmgroup_policy_map__policy_id` (`policy_id`) REFERENCES `autoscale_policies` (`id`), + INDEX `i_autoscale_vmgroup_policy_map__vmgroup_id`(`vmgroup_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (1, UUID(), 'snmp','Linux User CPU - percentage', '1.3.6.1.4.1.2021.11.9.0', now()); +INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (2, UUID(), 'snmp','Linux System CPU - percentage', '1.3.6.1.4.1.2021.11.10.0', now()); +INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (3, UUID(), 'snmp','Linux CPU Idle - percentage', '1.3.6.1.4.1.2021.11.11.0', now()); +INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (100, UUID(), 'netscaler','Response Time - microseconds', 'RESPTIME', now()); +CREATE TABLE `cloud`.`vm_snapshots` ( + `id` bigint(20) unsigned NOT NULL auto_increment COMMENT 'Primary Key', + `uuid` varchar(40) NOT NULL, + `name` varchar(255) NOT NULL, + `display_name` varchar(255) default NULL, + `description` varchar(255) default NULL, + `vm_id` bigint(20) unsigned NOT NULL, + `account_id` bigint(20) unsigned NOT NULL, + `domain_id` bigint(20) unsigned NOT NULL, + `vm_snapshot_type` varchar(32) default NULL, + `state` varchar(32) NOT NULL, + `parent` bigint unsigned default NULL, + `current` int(1) unsigned default NULL, + `update_count` bigint unsigned NOT NULL DEFAULT 0, + `updated` datetime default NULL, + `created` datetime default NULL, + `removed` datetime default NULL, + PRIMARY KEY (`id`), + CONSTRAINT UNIQUE KEY `uc_vm_snapshots_uuid` (`uuid`), + INDEX `vm_snapshots_name` (`name`), + INDEX `vm_snapshots_vm_id` (`vm_id`), + INDEX `vm_snapshots_account_id` (`account_id`), + INDEX `vm_snapshots_display_name` (`display_name`), + INDEX `vm_snapshots_removed` (`removed`), + INDEX `vm_snapshots_parent` (`parent`), + CONSTRAINT `fk_vm_snapshots_vm_id__vm_instance_id` FOREIGN KEY `fk_vm_snapshots_vm_id__vm_instance_id` (`vm_id`) REFERENCES `vm_instance` (`id`), + CONSTRAINT `fk_vm_snapshots_account_id__account_id` FOREIGN KEY `fk_vm_snapshots_account_id__account_id` (`account_id`) REFERENCES `account` (`id`), + CONSTRAINT `fk_vm_snapshots_domain_id__domain_id` FOREIGN KEY `fk_vm_snapshots_domain_id__domain_id` (`domain_id`) REFERENCES `domain` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`user_ipv6_address` ( + `id` bigint unsigned NOT NULL UNIQUE auto_increment, + `uuid` varchar(40), + `account_id` bigint unsigned NULL, + `domain_id` bigint unsigned NULL, + `ip_address` char(50) NOT NULL, + `data_center_id` bigint unsigned NOT NULL COMMENT 'zone that it belongs to', + `vlan_id` bigint unsigned NOT NULL, + `state` char(32) NOT NULL default 'Free' COMMENT 'state of the ip address', + `mac_address` varchar(40) NOT NULL COMMENT 'mac address of this ip', + `source_network_id` bigint unsigned NOT NULL COMMENT 'network id ip belongs to', + `network_id` bigint unsigned COMMENT 'network this public ip address is associated with', + `physical_network_id` bigint unsigned NOT NULL COMMENT 'physical network id that this configuration is based on', + `created` datetime NULL COMMENT 'Date this ip was allocated to someone', + PRIMARY KEY (`id`), + UNIQUE (`ip_address`, `source_network_id`), + CONSTRAINT `fk_user_ipv6_address__source_network_id` FOREIGN KEY (`source_network_id`) REFERENCES `networks`(`id`), + CONSTRAINT `fk_user_ipv6_address__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), + CONSTRAINT `fk_user_ipv6_address__account_id` FOREIGN KEY (`account_id`) REFERENCES `account`(`id`), + CONSTRAINT `fk_user_ipv6_address__vlan_id` FOREIGN KEY (`vlan_id`) REFERENCES `vlan`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_user_ipv6_address__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, + CONSTRAINT `uc_user_ipv6_address__uuid` UNIQUE (`uuid`), + CONSTRAINT `fk_user_ipv6_address__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud`.`networks` ADD COLUMN `ip6_gateway` varchar(50) COMMENT 'IPv6 gateway for this network'; +ALTER TABLE `cloud`.`networks` ADD COLUMN `ip6_cidr` varchar(50) COMMENT 'IPv6 cidr for this network'; + +ALTER TABLE `cloud`.`nics` ADD COLUMN `ip6_gateway` varchar(50) COMMENT 'gateway for ip6 address'; +ALTER TABLE `cloud`.`nics` ADD COLUMN `ip6_cidr` varchar(50) COMMENT 'cidr for ip6 address'; + +ALTER TABLE `cloud`.`vlan` ADD COLUMN `ip6_gateway` varchar(255); +ALTER TABLE `cloud`.`vlan` ADD COLUMN `ip6_cidr` varchar(255); +ALTER TABLE `cloud`.`vlan` ADD COLUMN `ip6_range` varchar(255); -- DB views for list api @@ -229,6 +568,9 @@ CREATE VIEW `cloud`.`user_vm_view` AS nics.uuid nic_uuid, nics.network_id network_id, nics.ip4_address ip_address, + nics.ip6_address ip6_address, + nics.ip6_gateway ip6_gateway, + nics.ip6_cidr ip6_cidr, nics.default_nic is_default_nic, nics.gateway gateway, nics.netmask netmask, @@ -358,6 +700,9 @@ CREATE VIEW `cloud`.`domain_router_view` AS nics.uuid nic_uuid, nics.network_id network_id, nics.ip4_address ip_address, + nics.ip6_address ip6_address, + nics.ip6_gateway ip6_gateway, + nics.ip6_cidr ip6_cidr, nics.default_nic is_default_nic, nics.gateway gateway, nics.netmask netmask, @@ -953,6 +1298,10 @@ CREATE VIEW `cloud`.`account_view` AS projectcount.count projectTotal, networklimit.max networkLimit, networkcount.count networkTotal, + cpulimit.max cpuLimit, + cpucount.count cpuTotal, + memorylimit.max memoryLimit, + memorycount.count memoryTotal, async_job.id job_id, async_job.uuid job_uuid, async_job.job_status job_status, @@ -1021,6 +1370,18 @@ CREATE VIEW `cloud`.`account_view` AS `cloud`.`resource_count` networkcount ON account.id = networkcount.account_id and networkcount.type = 'network' left join + `cloud`.`resource_limit` cpulimit ON account.id = cpulimit.account_id + and cpulimit.type = 'cpu' + left join + `cloud`.`resource_count` cpucount ON account.id = cpucount.account_id + and cpucount.type = 'cpu' + left join + `cloud`.`resource_limit` memorylimit ON account.id = memorylimit.account_id + and memorylimit.type = 'memory' + left join + `cloud`.`resource_count` memorycount ON account.id = memorycount.account_id + and memorycount.type = 'memory' + left join `cloud`.`async_job` ON async_job.instance_id = account.id and async_job.instance_type = 'Account' and async_job.job_status = 0; @@ -1271,39 +1632,28 @@ CREATE VIEW `cloud`.`data_center_view` AS left join `cloud`.`domain` ON data_center.domain_id = domain.id; -INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'direct.agent.pool.size', '500', 'Default size for DirectAgentPool'); -ALTER TABLE `cloud`.`op_dc_vnet_alloc` DROP INDEX i_op_dc_vnet_alloc__vnet__data_center_id; - -ALTER TABLE `cloud`.`op_dc_vnet_alloc` ADD CONSTRAINT UNIQUE `i_op_dc_vnet_alloc__vnet__data_center_id`(`vnet`, `physical_network_id`, `data_center_id`); - -CREATE TABLE `cloud`.`region` ( - `id` int unsigned NOT NULL UNIQUE, - `name` varchar(255) NOT NULL UNIQUE, - `end_point` varchar(255) NOT NULL, - `api_key` varchar(255), - `secret_key` varchar(255), +CREATE TABLE `cloud`.`baremetal_dhcp_devices` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `uuid` varchar(40) UNIQUE, + `nsp_id` bigint unsigned DEFAULT NULL COMMENT 'Network Service Provider ID', + `pod_id` bigint unsigned DEFAULT NULL COMMENT 'Pod id where this dhcp server in', + `device_type` varchar(255) DEFAULT NULL COMMENT 'type of the external device', + `physical_network_id` bigint unsigned DEFAULT NULL COMMENT 'id of the physical network in to which external dhcp device is added', + `host_id` bigint unsigned DEFAULT NULL COMMENT 'host id coresponding to the external dhcp device', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `cloud`.`region_sync` ( - `id` bigint unsigned NOT NULL auto_increment, - `region_id` int unsigned NOT NULL, - `api` varchar(1024) NOT NULL, - `created` datetime NOT NULL COMMENT 'date created', - `processed` tinyint NOT NULL default '0', +CREATE TABLE `cloud`.`baremetal_pxe_devices` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `uuid` varchar(40) UNIQUE, + `nsp_id` bigint unsigned DEFAULT NULL COMMENT 'Network Service Provider ID', + `pod_id` bigint unsigned DEFAULT NULL COMMENT 'Pod id where this pxe server in, for pxe per zone this field is null', + `device_type` varchar(255) DEFAULT NULL COMMENT 'type of the pxe device', + `physical_network_id` bigint unsigned DEFAULT NULL COMMENT 'id of the physical network in to which external pxe device is added', + `host_id` bigint unsigned DEFAULT NULL COMMENT 'host id coresponding to the external pxe device', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `cloud`.`region` values ('1','Local','http://localhost:8080/client/api','',''); -ALTER TABLE `cloud`.`account` ADD COLUMN `region_id` int unsigned NOT NULL DEFAULT '1'; -ALTER TABLE `cloud`.`user` ADD COLUMN `region_id` int unsigned NOT NULL DEFAULT '1'; -ALTER TABLE `cloud`.`domain` ADD COLUMN `region_id` int unsigned NOT NULL DEFAULT '1'; - -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (208, UUID(), 6, 'Windows 8'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (209, UUID(), 6, 'Windows 8 (64 bit)'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (210, UUID(), 6, 'Windows 8 Server (64 bit)'); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8', 208); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 (64 bit)', 209); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 Server (64 bit)', 210); +SET foreign_key_checks = 1; diff --git a/setup/db/db/schema-410to420-cleanup.sql b/setup/db/db/schema-410to420-cleanup.sql new file mode 100644 index 00000000000..51970b21b89 --- /dev/null +++ b/setup/db/db/schema-410to420-cleanup.sql @@ -0,0 +1,21 @@ +-- 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. + +--; +-- Schema cleanup from 4.1.0 to 4.2.0; +--; + diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql new file mode 100644 index 00000000000..9d335c4d65e --- /dev/null +++ b/setup/db/db/schema-410to420.sql @@ -0,0 +1,110 @@ +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. + +--; +-- Schema upgrade from 4.1.0 to 4.2.0; +--; + +SET foreign_key_checks = 0; + +ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `max_hosts_per_cluster` int unsigned DEFAULT NULL COMMENT 'Max. hosts in cluster supported by hypervisor'; +UPDATE `cloud`.`hypervisor_capabilities` SET `max_hosts_per_cluster`=32 WHERE `hypervisor_type`='VMware'; +INSERT IGNORE INTO `cloud`.`hypervisor_capabilities`(hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_hosts_per_cluster) VALUES ('VMware', '5.1', 128, 0, 32); +DELETE FROM `cloud`.`configuration` where name='vmware.percluster.host.max'; +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xen.nics.max', '7', 'Maximum allowed nics for Vms created on Xen'); + +alter table template_host_ref add state varchar(255); +alter table template_host_ref add update_count bigint unsigned; +alter table template_host_ref add updated datetime; +alter table volume_host_ref add state varchar(255); +alter table volume_host_ref add update_count bigint unsigned; +alter table volume_host_ref add updated datetime; +alter table template_spool_ref add updated datetime; +CREATE TABLE `cloud`.`object_datastore_ref` ( + `id` bigint unsigned NOT NULL auto_increment, + `datastore_uuid` varchar(255) NOT NULL, + `datastore_role` varchar(255) NOT NULL, + `object_uuid` varchar(255) NOT NULL, + `object_type` varchar(255) NOT NULL, + `created` DATETIME NOT NULL, + `last_updated` DATETIME, + `job_id` varchar(255), + `download_pct` int(10) unsigned, + `download_state` varchar(255), + `url` varchar(255), + `format` varchar(255), + `checksum` varchar(255), + `error_str` varchar(255), + `local_path` varchar(255), + `install_path` varchar(255), + `size` bigint unsigned COMMENT 'the size of the template on the pool', + `state` varchar(255) NOT NULL, + `update_count` bigint unsigned NOT NULL, + `updated` DATETIME, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`data_store_provider` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `name` varchar(255) NOT NULL COMMENT 'name of primary data store provider', + `uuid` varchar(255) NOT NULL COMMENT 'uuid of primary data store provider', + PRIMARY KEY(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`image_data_store` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `name` varchar(255) NOT NULL COMMENT 'name of data store', + `image_provider_id` bigint unsigned NOT NULL COMMENT 'id of image_data_store_provider', + `protocol` varchar(255) NOT NULL COMMENT 'protocol of data store', + `data_center_id` bigint unsigned COMMENT 'datacenter id of data store', + `scope` varchar(255) COMMENT 'scope of data store', + `uuid` varchar(255) COMMENT 'uuid of data store', + PRIMARY KEY(`id`), + CONSTRAINT `fk_tags__image_data_store_provider_id` FOREIGN KEY(`image_provider_id`) REFERENCES `data_store_provider`(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud`.`vm_template` ADD COLUMN `image_data_store_id` bigint unsigned; + +ALTER TABLE `cloud`.`service_offering` ADD COLUMN `is_volatile` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if the vm needs to be volatile, i.e., on every reboot of vm from API root disk is discarded and creates a new root disk'; + +ALTER TABLE `cloud`.`networks` ADD COLUMN `network_cidr` VARCHAR(18) COMMENT 'The network cidr for the isolated guest network which uses IP Reservation facility.For networks not using IP reservation, network_cidr is always null.'; +ALTER TABLE `cloud`.`networks` CHANGE `cidr` `cidr` varchar(18) COMMENT 'CloudStack managed vms get IP address from cidr.In general this cidr also serves as the network CIDR. But in case IP reservation feature is being used by a Guest network, networkcidr is the Effective network CIDR for that network'; + + +CREATE TABLE `vpc_service_map` ( + `id` bigint unsigned NOT NULL auto_increment, + `vpc_id` bigint unsigned NOT NULL COMMENT 'vpc_id', + `service` varchar(255) NOT NULL COMMENT 'service', + `provider` varchar(255) COMMENT 'service provider', + `created` datetime COMMENT 'date created', + PRIMARY KEY (`id`), + CONSTRAINT `fk_vpc_service_map__vpc_id` FOREIGN KEY(`vpc_id`) REFERENCES `vpc`(`id`) ON DELETE CASCADE, + UNIQUE (`vpc_id`, `service`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +SET foreign_key_checks = 1; + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'vm.instancename.flag', 'false', 'Append guest VM display Name (if set) to the internal name of the VM'); + +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (208, UUID(), 6, 'Windows 8'); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (209, UUID(), 6, 'Windows 8 (64 bit)'); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (210, UUID(), 6, 'Windows 8 Server (64 bit)'); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8', 208); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 (64 bit)', 209); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 Server (64 bit)', 210); + diff --git a/setup/db/deploy-db-dev.sh b/setup/db/deploy-db-dev.sh index a40e278b002..29ec4db6050 100755 --- a/setup/db/deploy-db-dev.sh +++ b/setup/db/deploy-db-dev.sh @@ -55,11 +55,6 @@ if [ ! -f create-index-fk.sql ]; then exit 6; fi -if [ ! -f create-schema-view.sql ]; then - printf "Error: Unable to find create-schema-view.sql\n" - exit 7 -fi - PATHSEP=':' if [[ $OSTYPE == "cygwin" ]] ; then export CATALINA_HOME=`cygpath -m $CATALINA_HOME` @@ -105,12 +100,6 @@ if [ $? -ne 0 ]; then exit 11 fi -mysql --user=cloud --password=cloud cloud < create-schema-view.sql -if [ $? -ne 0 ]; then - printf "Error: Cannot execute create-schema-view.sql\n" - exit 11 -fi - CP=./ CP=${CP}$PATHSEP$CATALINA_HOME/conf diff --git a/setup/db/deploy-db-simulator.sh b/setup/db/deploy-db-simulator.sh index c918df43009..20e12d37794 100644 --- a/setup/db/deploy-db-simulator.sh +++ b/setup/db/deploy-db-simulator.sh @@ -55,11 +55,6 @@ if [ ! -f create-index-fk.sql ]; then exit 6; fi -if [ ! -f create-schema-view.sql ]; then - printf "Error: Unable to find create-schema-view.sql\n" - exit 7 -fi - PATHSEP=':' if [[ $OSTYPE == "cygwin" ]] ; then @@ -109,12 +104,6 @@ if [ $? -ne 0 ]; then exit 11 fi -mysql --user=cloud --password=cloud cloud < create-schema-view.sql -if [ $? -ne 0 ]; then - printf "Error: Cannot execute create-schema-view.sql\n" - exit 11 -fi - mysql --user=cloud --password=cloud cloud < create-schema-simulator.sql if [ $? -ne 0 ]; then printf "Error: Cannot execute create-schema-simulator.sql\n" diff --git a/setup/db/server-setup.xml b/setup/db/server-setup.xml index 912dd0b85d8..bb8878f8d37 100755 --- a/setup/db/server-setup.xml +++ b/setup/db/server-setup.xml @@ -446,7 +446,7 @@ under the License. diff --git a/setup/db/templates.sql b/setup/db/templates.sql index 34ec32d0ce7..2f95f1e00f8 100755 --- a/setup/db/templates.sql +++ b/setup/db/templates.sql @@ -16,12 +16,13 @@ -- under the License. INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type) - VALUES (1, UUID(), 'routing-1', 'SystemVM Template (XenServer)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.vhd.bz2', 'f613f38c96bf039f2e5cbf92fa8ad4f8', 0, 'SystemVM Template (XenServer)', 'VHD', 133, 0, 1, 'XenServer'); + VALUES (1, UUID(), 'routing-1', 'SystemVM Template (XenServer)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.vhd.bz2', 'f613f38c96bf039f2e5cbf92fa8ad4f8', 0, 'SystemVM Template (XenServer)', 'VHD', 133, 0, 1, 'XenServer' ); + INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, removed, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable) VALUES (2, UUID(), 'centos53-x86_64', 'CentOS 5.3(64-bit) no GUI (XenServer)', 1, now(), now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/templates/builtin/f59f18fb-ae94-4f97-afd2-f84755767aca.vhd.bz2', 'b63d854a9560c013142567bbae8d98cf', 0, 'CentOS 5.3(64-bit) no GUI (XenServer)', 'VHD', 12, 1, 1, 'XenServer', 1); INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type) - VALUES (3, UUID(), 'routing-3', 'SystemVM Template (KVM)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.qcow2.bz2', '2755de1f9ef2ce4d6f2bee2efbb4da92', 0, 'SystemVM Template (KVM)', 'QCOW2', 15, 0, 1, 'KVM'); + VALUES (3, UUID(), 'routing-3', 'SystemVM Template (KVM)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.qcow2.bz2', '2755de1f9ef2ce4d6f2bee2efbb4da92', 0, 'SystemVM Template (KVM)', 'QCOW2', 15, 0, 1, 'KVM' ); INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, display_text, enable_password, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable) VALUES (4, UUID(), 'centos55-x86_64', 'CentOS 5.5(64-bit) no GUI (KVM)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/releases/2.2.0/eec2209b-9875-3c8d-92be-c001bd8a0faf.qcow2.bz2', 'ed0e788280ff2912ea40f7f91ca7a249', 'CentOS 5.5(64-bit) no GUI (KVM)', 0, 'QCOW2', 112, 1, 1, 'KVM', 1); @@ -33,10 +34,10 @@ INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, VALUES (7, UUID(), 'centos53-x64', 'CentOS 5.3(64-bit) no GUI (vSphere)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/releases/2.2.0/CentOS5.3-x86_64.ova', 'f6f881b7f2292948d8494db837fe0f47', 0, 'CentOS 5.3(64-bit) no GUI (vSphere)', 'OVA', 12, 1, 1, 'VMware', 1); INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type) - VALUES (8, UUID(), 'routing-8', 'SystemVM Template (vSphere)', 0, now(), 'SYSTEM', 0, 32, 1, 'http://download.cloud.com/templates/burbank/burbank-systemvm-08012012.ova', '7137e453f950079ea2ba6feaafd939e8', 0, 'SystemVM Template (vSphere)', 'OVA', 15, 0, 1, 'VMware'); + VALUES (8, UUID(), 'routing-8', 'SystemVM Template (vSphere)', 0, now(), 'SYSTEM', 0, 32, 1, 'http://download.cloud.com/templates/burbank/burbank-systemvm-08012012.ova', '7137e453f950079ea2ba6feaafd939e8', 0, 'SystemVM Template (vSphere)', 'OVA', 15, 0, 1, 'VMware' ); INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type) - VALUES (9, UUID(), 'routing-9', 'SystemVM Template (HyperV)', 0, now(), 'SYSTEM', 0, 32, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.vhd.bz2', 'f613f38c96bf039f2e5cbf92fa8ad4f8', 0, 'SystemVM Template (HyperV)', 'VHD', 15, 0, 1, 'Hyperv'); + VALUES (9, UUID(), 'routing-9', 'SystemVM Template (HyperV)', 0, now(), 'SYSTEM', 0, 32, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.vhd.bz2', 'f613f38c96bf039f2e5cbf92fa8ad4f8', 0, 'SystemVM Template (HyperV)', 'VHD', 15, 0, 1, 'Hyperv' ); INSERT INTO `cloud`.`guest_os_category` (id, uuid, name) VALUES (1, UUID(), 'CentOS'); INSERT INTO `cloud`.`guest_os_category` (id, uuid, name) VALUES (2, UUID(), 'Debian'); @@ -219,11 +220,6 @@ INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (201 INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (202, UUID(), 5, 'Other SUSE Linux(32-bit)'); INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (203, UUID(), 5, 'Other SUSE Linux(64-bit)'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (208, UUID(), 6, 'Windows 8'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (209, UUID(), 6, 'Windows 8 (64 bit)'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (210, UUID(), 6, 'Windows 8 Server (64 bit)'); - - INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'CentOS 4.5 (32-bit)', 1); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'CentOS 4.6 (32-bit)', 2); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'CentOS 4.7 (32-bit)', 3); @@ -328,10 +324,6 @@ INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Microsoft Windows NT 4', 64); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Microsoft Windows 3.1', 65); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8', 208); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 (64 bit)', 209); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 Server (64 bit)', 210); - INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Red Hat Enterprise Linux 5.0(32-bit)', 30); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Red Hat Enterprise Linux 5.1(32-bit)', 32); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Red Hat Enterprise Linux 5.2(32-bit)', 34); diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index 3596ca244ba..8d65c00c896 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -854,9 +854,6 @@ class TestVMLifeCycle(cloudstackTestCase): ) expunge_delay = int(config[0].value) - if expunge_delay < 600: - expunge_delay = 600 - # Wait for some time more than expunge.delay time.sleep(expunge_delay * 2) #VM should be destroyed unless expunge thread hasn't run @@ -866,9 +863,6 @@ class TestVMLifeCycle(cloudstackTestCase): name='expunge.interval' ) expunge_cycle = int(config[0].value) - if expunge_cycle < 600: - expunge_cycle = 600 - wait_time = expunge_cycle * 2 while wait_time >= 0: list_vm_response = list_virtual_machines( diff --git a/test/pom.xml b/test/pom.xml index 4507e8cc916..d4b88326fa2 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/test/selenium/ReadMe.txt b/test/selenium/ReadMe.txt new file mode 100644 index 00000000000..30b0e0df7a0 --- /dev/null +++ b/test/selenium/ReadMe.txt @@ -0,0 +1,52 @@ +############################################## +This files contains following: + +1) Installation requirements +2) Test Pre requisites +3) Running the Test and Generating the report +############################################## + + + +########################################################################################################################################## + +1) Installtion Requirements + + +1)Firefox depending on your OS (Good to have Firebug and Selenium IDE for troubleshooting and dev work) + + +2)Install Python 2.7. Recommend to use Active State Python + + +3) Now Open CMD/Terminal and type all of following + +- pypm install pycrypto (Installs Pycrypto) +- pypm install paramiko (Install paramiko) +- pip install unittest-xml-reporting (Install XML Test Runner) +- pip install -U selenium (Installs Selenium) + + +5) Now get the HTMLTestRunner for nice looking report generation. +- http://tungwaiyip.info/software/HTMLTestRunner.html +- Download and put this file into Lib of your python installation. + + +########################################################################################################################################## + +2) Test Prerequisites + +- Download and install CS +- Log into the management server nad Add a Zone. (Must be Advance Zone and Hypervisor type must be Xen) + +########################################################################################################################################## + +3) Running the Test and Generating the report + +- Folder smoke contains main.py +- main.py is the file where all the tests are serialized. +- main.py supports HTML and XML reporting. Please refer to end of file to choose either. +- Typical usage is: python main.py for XML Reporting +- And python main.py >> results.html for HTML Reporting. + +########################################################################################################################################## diff --git a/test/selenium/lib/Global_Locators.py b/test/selenium/lib/Global_Locators.py new file mode 100644 index 00000000000..b2d93cd997e --- /dev/null +++ b/test/selenium/lib/Global_Locators.py @@ -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. + +''' +Variable Names are as follows +Logical Page Descriptor_____What Element Represents and/or where it is_____LocatorType + + +For Example :: + +instances_xpath = "//div[@id='navigation']/ul/li[2]/span[2]" + +Means this is:: xpath link for Instances which is present on Dashboard. +Any test cases that requires to go into Instances from Dashboard can use this variable now. + +This may not be intuitive as you go deep into the tree. + + + +for example + +stopinstanceforce_id + +The best way to know what this represents is to track by variable name +Under Instances / any instance is click on any instance (applies to any instance) / stop instance has a force stop check box when you click. +This link represents that. + + +Steps below do not have global locators. + +PF rule steps including and after filling port numbers. (Refer to vmLifeAndNetwork.py / def test_PF) +FW rule steps including and after filling port numbers. (Refer to vmLifeAndNetwork.py / def test_PF) +ADD Disk Offering page has Names, description, storage type etc etc +ADD Compute Offering page has Names, description, CPU Cores, CPU clocks type etc etc + +Create Acc, Delete Acc, Login and Logout are for test flow and are not test cases. They do not have global Locators. + +Such and many more data entry points that appear only once and hence we do not need glonal names for them. They are hard coded as and when needed in the scripts. + + +''' + +################################################################################################################################################################################################ + +## Links on the Main UI page (Dash board). Listed in the order they appear on screen +dashboard_xpath = "//div[@id='navigation']/ul/li" +instances_xpath = "//div[@id='navigation']/ul/li[2]/span[2]" # Link for Instance and following as self explanatory +storage_xpath = "//div[@id='navigation']/ul/li[3]/span[2]" +network_xpath = "//div[@id='navigation']/ul/li[4]/span[2]" +templates_xpath = "//div[@id='navigation']/ul/li[5]/span[2]" +events_xpath = "//div[@id='navigation']/ul/li[6]/span[2]" +projects_xpath = "//div[@id='navigation']/ul/li[7]/span[2]" +accounts_xpath = "//div[@id='navigation']/ul/li[8]/span[2]" +domains_xpath = "//div[@id='navigation']/ul/li[9]/span[2]" +infrastructure_xpath = "//div[@id='navigation']/ul/li[10]/span[2]" +globalSettings_xpath = "//div[@id='navigation']/ul/li[11]/span[2]" +serviceOfferings_xpath = "//div[@id='navigation']/ul/li[12]/span[2]" + +################################################################################################################################################################################################ + +## Instances Page +## Instances Main page + + +# Add Instance Button on top right corner of Instances page +add_instance_xpath = "//div[2]/div/div[2]/div/div[2]/span" + +# Add Instance Wizard next button +add_instance_next_xpath = "//div[4]/div[2]/div[3]/div[3]/span" + +# Table that lists all VM's under Instances page; General usage is to traverse through this table and search for the VM we are interested in. +instances_table_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/table/tbody/tr/td/span" + + +# Click any instance and following are available + +# Click ok on confirmation pop-up box for most actions listed below +actionconfirm_xpath = ("//button[@type='button']") + +# status of VM running. Click on VM > 3rd row in table +state_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div[2]/div[2]/div/div/div[2]/div/table/tbody/tr[3]/td[2]/span" + +# Stop instance icon +stopinstance_css = "a[alt=\"Stop Instance\"] > span.icon" + +# stop instance forcefully check box available after stop instance is executed in separate pop up +stopinstanceforce_id = ("force_stop") + +# start instance icon +startinstance_css = "a[alt=\"Start Instance\"] > span.icon" + +yesconfirmation_xapth = "(//button[@type='button'])[2]" + + +# Destroy instance icon +destroyinstance_css = "a[alt=\"Destroy Instance\"] > span.icon" + +#Restore Instance icon +restoreinstance_css = "a[alt=\"Restore Instance\"] > span.icon" + +# Reboot instance +rebootinstance_css = "a[alt=\"Reboot Instance\"] > span.icon" + +################################################################################################################################################################################################ + + +## Network Page + +# Table that lists all Networks under Network page; General usage is to traverse through this table and search for the network we are interested in. +network_networktable_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div[3]/div[2]/div/div[2]/table/tbody/tr/td/span" + +# View IP addresses button on each network page +viewIp_css="div.view-all > a > span" + +# Acquire a new ip +acquireIP_xpath="//div[2]/div/div/div[2]/span" +# List of IP's within a netork table +network_iptables_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div[3]/div[2]/div/div[2]/table/tbody/tr/td/span" +# Configuration tab for each IP +ipConfiguration_text="Configuration" +# PF under configuration for each IP +ip_PF = "li.portForwarding > div.view-details" + + +################################################################################################################################################################################################ + + +## Servivce Offering Page + +# Selects Compute offering from drop down menu +Offering_compute_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div/div[2]/div/div/div/select/option[1]" + +# Selects System offering from drop down menu +Offering_system_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div/div[2]/div/div/div/select/option[2]" + +# Selects Disk offering from drop down menu +Offering_disk_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div/div[2]/div/div/div/select/option[3]" + +# Selects Network offering from drop down menu +Offering_network_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div/div[2]/div/div/div/select/option[4]" + +# Add Offering +Offering_add_xpath ="//div[3]/span" + +# Points to tbale that lists Offerings +Offering_table_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/table/tbody/tr/td/span" + +# Edit Button +Offering_edit_css = "a[alt=\"Edit\"] > span.icon" + +# Edit name box +Offering_editname_name = "name" + +# Edit description box +Offering_editdescription_name = "displaytext" + +# Edit finished click ok +Offering_editdone_css="div.button.done" + +# delete offering button for Disk only +Offering_delete_css = "a[alt=\"Delete Disk Offering\"] > span.icon" + +# delete offering button for Compute only +Offering_deletecompute_css = "a[alt=\"Delete Service Offering\"] > span.icon" + + + + +################################################################################################################################################################################################ + + +#### Templates Page + +# Selects Templates from drop down +template_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div/div[2]/div/div/div/select/option[1]" + +# Selects ISO from drop down +iso_xpath = "/html/body/div/div/div[2]/div[2]/div[2]/div/div[2]/div/div/div/select/option[2]" + +# Add Template +AddTemplate_xpath = "//div[3]/span" + +# Points to table where all templates are +template_table_xpath ="/html/body/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/table/tbody/tr/td/span" + +# Edit Template Button +template_edit_css = "a[alt=\"Edit\"] > span.icon" + +# Edit finished click OK +template_editdone_css = "div.button.done" + +# Delete Template button +template_delete_css = "a[alt=\"Delete Template\"] > span.icon" + + +################################################################################################################################################################################################ + + +## Login Page + +# Username box +login_username_css = "body.login > div.login > form > div.fields > div.field.username > input[name=\"username\"]" # Login>Username TextBox + +# Password Box +login_password_css = "body.login > div.login > form > div.fields > div.field.password > input[name=\"password\"]" # LoginPassword TextBox + +# Click ok to login +login_submit_css = "body.login > div.login > form > div.fields > input[type=\"submit\"]" # Login>Login Button (Submit button) + + diff --git a/test/selenium/lib/initialize.py b/test/selenium/lib/initialize.py new file mode 100644 index 00000000000..e8cc49adff4 --- /dev/null +++ b/test/selenium/lib/initialize.py @@ -0,0 +1,31 @@ +# 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. +''' +This will help pass webdriver (Browser instance) across our test cases. +''' + + + +from selenium import webdriver + +DRIVER = None + +def getOrCreateWebdriver(): + global DRIVER + DRIVER = DRIVER or webdriver.Firefox() + return DRIVER + diff --git a/test/selenium/smoke/Login_and_Accounts.py b/test/selenium/smoke/Login_and_Accounts.py new file mode 100644 index 00000000000..c5132d9754c --- /dev/null +++ b/test/selenium/smoke/Login_and_Accounts.py @@ -0,0 +1,253 @@ +# 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. + +import sys, os +sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/'+'../lib')) + + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import Select +from selenium.common.exceptions import NoSuchElementException +import unittest, time +import Global_Locators +import initialize + + + +class login(unittest.TestCase): + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.base_url = "http://10.223.49.206:8080/" # Your management Server IP goes here + self.verificationErrors = [] + + + def test_login(self): + + # Here we will clear the test box for Username and Password and fill them with actual login data. + # After that we will click Login (Submit button) + driver = self.driver + driver.maximize_window() + driver.get(self.base_url + "client/") + driver.find_element_by_css_selector(Global_Locators.login_username_css).clear() + driver.find_element_by_css_selector(Global_Locators.login_username_css).send_keys("admin") + driver.find_element_by_css_selector(Global_Locators.login_password_css).clear() + driver.find_element_by_css_selector(Global_Locators.login_password_css).send_keys("password") + driver.find_element_by_css_selector(Global_Locators.login_submit_css).click() + time.sleep(5) + + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + + +################################################################################################################################################ + + + +class logout(unittest.TestCase): + + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.driver.implicitly_wait(100) + self.verificationErrors = [] + + + + def test_logout(self): + + # Here we will clear the test box for Username and Password and fill them with actual login data. + # After that we will click Login (Submit button) + driver = self.driver + driver.find_element_by_xpath("//div[@id='navigation']/ul/li").click() + driver.find_element_by_css_selector("div.icon.options").click() + driver.find_element_by_link_text("Logout").click() + + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + + +################################################################################################################################################ + + + +class login_test(unittest.TestCase): + + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + def test_logintest(self): + + # Here we will clear the test box for Username and Password and fill them with actual login data. + # After that we will click Login (Submit button) + driver = self.driver + driver.find_element_by_css_selector(Global_Locators.login_username_css).clear() + driver.find_element_by_css_selector(Global_Locators.login_username_css).send_keys("test") + driver.find_element_by_css_selector(Global_Locators.login_password_css).clear() + driver.find_element_by_css_selector(Global_Locators.login_password_css).send_keys("password") + driver.find_element_by_css_selector(Global_Locators.login_submit_css).click() + time.sleep(5) + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + +################################################################################################################################################ + + +class createAcc(unittest.TestCase): + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + + def test_createacc(self): + + driver = self.driver + self.driver.implicitly_wait(100) + driver.find_element_by_xpath("//div[@id='navigation']/ul/li[8]/span[2]").click() + driver.find_element_by_xpath("//div[3]/span").click() + driver.find_element_by_id("label_username").clear() + driver.find_element_by_id("label_username").send_keys("test") + driver.find_element_by_id("password").clear() + driver.find_element_by_id("password").send_keys("password") + driver.find_element_by_id("label_confirm_password").clear() + driver.find_element_by_id("label_confirm_password").send_keys("password") + driver.find_element_by_id("label_email").clear() + driver.find_element_by_id("label_email").send_keys("test@citrix.com") + driver.find_element_by_id("label_first_name").clear() + driver.find_element_by_id("label_first_name").send_keys("test") + driver.find_element_by_id("label_last_name").clear() + driver.find_element_by_id("label_last_name").send_keys("test") + driver.find_element_by_id("label_domain").click() + Select(driver.find_element_by_id("label_type")).select_by_visible_text("Admin") + Select(driver.find_element_by_id("label_timezone")).select_by_visible_text("[UTC-08:00] Pacific Standard Time") + driver.find_element_by_xpath("//button[@type='button']").click() + + # Go to Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(30) + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + + +################################################################################################################################################ + + +class tearAcc(unittest.TestCase): + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + + def test_tearacc(self): + + driver = self.driver + driver.find_element_by_css_selector("li.navigation-item.accounts").click() + driver.find_element_by_css_selector("tr.odd > td.name.first").click() + driver.find_element_by_css_selector("a[alt=\"Delete account\"] > span.icon").click() + driver.find_element_by_xpath("(//button[@type='button'])[2]").click() + + # Go to Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(30) + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + def tearDown(self): + + self.driver.quit() + self.assertEqual([], self.verificationErrors) + + + +################################################################################################################################################ diff --git a/test/selenium/smoke/Service_Offering.py b/test/selenium/smoke/Service_Offering.py new file mode 100644 index 00000000000..66478e60414 --- /dev/null +++ b/test/selenium/smoke/Service_Offering.py @@ -0,0 +1,426 @@ +# 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. + +import sys, os +sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/'+'../lib')) + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import Select +from selenium.common.exceptions import NoSuchElementException +import unittest, time +import initialize +import Global_Locators + + + + +class Disk_offering_Add(unittest.TestCase): + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + + def test_diskadd(self): + + driver = self.driver + self.driver.implicitly_wait(200) + + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + # Go to Service Offerings + driver.find_element_by_xpath(Global_Locators.serviceOfferings_xpath).click() + + #Select Disk offering + driver.find_element_by_xpath(Global_Locators.Offering_disk_xpath).click() + + # Add offering + driver.find_element_by_xpath(Global_Locators.Offering_add_xpath).click() + + # Following have names.. so they do not have their global entries. + driver.find_element_by_name("name").clear() + driver.find_element_by_name("name").send_keys("Test Disk Name") + driver.find_element_by_name("description").clear() + driver.find_element_by_name("description").send_keys("Test Disk Description") + driver.find_element_by_name("disksize").clear() + driver.find_element_by_name("disksize").send_keys("1") + driver.find_element_by_xpath("//button[@type='button']").click() + time.sleep(20) + + ##Verification will be if this offering shows up into table and we can actually edit it. + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + def tearDown(self): + self.assertEqual([], self.verificationErrors) + + + + + +class Disk_offering_Edit(unittest.TestCase): + + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + def test_diskedit(self): + + driver = self.driver + self.driver.implicitly_wait(200) + + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + # Go to Service Offerings + driver.find_element_by_xpath(Global_Locators.serviceOfferings_xpath).click() + + #Select Disk offering + driver.find_element_by_xpath(Global_Locators.Offering_disk_xpath).click() + + # We will be searching for our disk offering into the table + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.Offering_table_xpath) # This returns a list of all Offerings in table + + for link in linkclass: + + if link.text == "Test Disk Name": + link.click() + + time.sleep(2) + + # Click Edit + driver.find_element_by_css_selector(Global_Locators.Offering_edit_css).click() + + #Change name + driver.find_element_by_name(Global_Locators.Offering_editname_name).clear() + driver.find_element_by_name(Global_Locators.Offering_editname_name).send_keys("Test Name") + + # Change Description + driver.find_element_by_name(Global_Locators.Offering_editdescription_name).clear() + driver.find_element_by_name(Global_Locators.Offering_editdescription_name).send_keys("Test Description") + + #Click Done + driver.find_element_by_css_selector(Global_Locators.Offering_editdone_css).click() + time.sleep(10) + + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + self.assertEqual([], self.verificationErrors) + + # Now we will find this offering and delete it!! + + + + + + +class Disk_offering_Delete(unittest.TestCase): + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + def test_diskdelete(self): + + driver = self.driver + self.driver.implicitly_wait(200) + + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + # Go to Service Offerings + driver.find_element_by_xpath(Global_Locators.serviceOfferings_xpath).click() + + #Select Disk offering + driver.find_element_by_xpath(Global_Locators.Offering_disk_xpath).click() + + ## Action part + # We will be searching for our disk offering into the table + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.Offering_table_xpath) # This returns a list of all Offerings in table + + for link in linkclass: + + if link.text == "Test Name": + link.click() + + time.sleep(2) + + # Click Delete + driver.find_element_by_css_selector(Global_Locators.Offering_delete_css).click() + time.sleep(2) + driver.find_element_by_xpath(Global_Locators.yesconfirmation_xapth).click() + time.sleep(20) + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + + + + + + + +class Compute_offering_Add(unittest.TestCase): + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + + def test_computeadd(self): + + driver = self.driver + self.driver.implicitly_wait(200) + + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + # Go to Service Offerings + driver.find_element_by_xpath(Global_Locators.serviceOfferings_xpath).click() + + #Select Compute offering + driver.find_element_by_xpath(Global_Locators.Offering_compute_xpath).click() + + ## Action part + + # Add offering + driver.find_element_by_xpath(Global_Locators.Offering_add_xpath).click() + + # Following do not have Global locators + driver.find_element_by_id("label_name").clear() + driver.find_element_by_id("label_name").send_keys("Test Compute Name") + driver.find_element_by_id("label_description").clear() + driver.find_element_by_id("label_description").send_keys("Test Compute Description") + driver.find_element_by_id("label_num_cpu_cores").clear() + driver.find_element_by_id("label_num_cpu_cores").send_keys("2") + driver.find_element_by_id("label_cpu_mhz").clear() + driver.find_element_by_id("label_cpu_mhz").send_keys("2000") + driver.find_element_by_id("label_memory_mb").clear() + driver.find_element_by_id("label_memory_mb").send_keys("2048") + driver.find_element_by_id("label_network_rate").clear() + driver.find_element_by_id("label_network_rate").send_keys("10") + driver.find_element_by_id("label_offer_ha").click() + driver.find_element_by_xpath("//button[@type='button']").click() + + time.sleep(2) + + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + + time.sleep(30) + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + + + + + + +class Compute_offering_Edit(unittest.TestCase): + + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + + def test_computeedit(self): + + + driver = self.driver + self.driver.implicitly_wait(200) + + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + ## Action part + # Go to Service Offerings + driver.find_element_by_xpath(Global_Locators.serviceOfferings_xpath).click() + + #Select Compute offering + driver.find_element_by_xpath(Global_Locators.Offering_compute_xpath).click() + + # We will be searching for our disk offering into the table + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.Offering_table_xpath) # This returns a list of all Offerings in table + + for link in linkclass: + + if link.text == "Test Compute Name": + link.click() + + time.sleep(2) + + + # Click Edit + driver.find_element_by_css_selector(Global_Locators.Offering_edit_css).click() + + #Change name + driver.find_element_by_name(Global_Locators.Offering_editname_name).clear() + driver.find_element_by_name(Global_Locators.Offering_editname_name).send_keys("Test Name") + + # Change Description + driver.find_element_by_name(Global_Locators.Offering_editdescription_name).clear() + driver.find_element_by_name(Global_Locators.Offering_editdescription_name).send_keys("Test Description") + + #Click Done + driver.find_element_by_css_selector(Global_Locators.Offering_editdone_css).click() + time.sleep(10) + + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + self.assertEqual([], self.verificationErrors) + + + + + + +class Compute_offering_Delete(unittest.TestCase): + + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + + def test_computedelete(self): + + + driver = self.driver + self.driver.implicitly_wait(200) + + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + # Go to Service Offerings + driver.find_element_by_xpath(Global_Locators.serviceOfferings_xpath).click() + + #Select Compute offering + driver.find_element_by_xpath(Global_Locators.Offering_compute_xpath).click() + + ## Action part + # We will be searching for our disk offering into the table + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.Offering_table_xpath) # This returns a list of all Offerings in table + + for link in linkclass: + + if link.text == "Test Name": + link.click() + + time.sleep(2) + + # Click Delete + + driver.find_element_by_css_selector(Global_Locators.Offering_deletecompute_css).click() + driver.find_element_by_xpath(Global_Locators.yesconfirmation_xapth).click() + + time.sleep(20) + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) diff --git a/test/selenium/smoke/TemplatesAndISO.py b/test/selenium/smoke/TemplatesAndISO.py new file mode 100644 index 00000000000..120c8d10d9f --- /dev/null +++ b/test/selenium/smoke/TemplatesAndISO.py @@ -0,0 +1,244 @@ +# 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. + +''' +ISO PART YET TO BE ADDED:: remove this after adding it. +''' + +import sys, os +sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/'+'../lib')) + + + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import Select +from selenium.common.exceptions import NoSuchElementException +import unittest, time +import initialize +import Global_Locators + + + + +class Template_Add(unittest.TestCase): + + + + def setUp(self): + + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + + def test_templateadd(self): + + + driver = self.driver + + ## Action part + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + # Go to Templates + driver.find_element_by_xpath(Global_Locators.templates_xpath).click() + + #Select Template from drop down list + driver.find_element_by_xpath(Global_Locators.template_xpath).click() + + # Add Template + driver.find_element_by_xpath(Global_Locators.AddTemplate_xpath).click() + + # Following have names.. so they do not have their global entries. + driver.find_element_by_id("label_name").clear() + driver.find_element_by_id("label_name").send_keys("Test Template Ubuntu") + driver.find_element_by_id("label_description").clear() + driver.find_element_by_id("label_description").send_keys("Ubuntu 10.04") + driver.find_element_by_id("URL").clear() + driver.find_element_by_id("URL").send_keys("http://nfs1.lab.vmops.com/templates/Ubuntu/Ubuntuu-10-04-64bit-server.vhd") + Select(driver.find_element_by_id("label_os_type")).select_by_visible_text("Ubuntu 10.04 (64-bit)") + driver.find_element_by_id("label_public").click() + driver.find_element_by_id("label_featured").click() + driver.find_element_by_xpath("//button[@type='button']").click() + + time.sleep(2) + + # Go to Dash Board + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + + + time.sleep(600) + + ##Verification will be if this offering shows up into table and we can actually edit it. + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + + + + + + +class Template_Edit(unittest.TestCase): + + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + + def test_templateedit(self): + + driver = self.driver + + ## Action part + + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + # Go to Templates + driver.find_element_by_xpath(Global_Locators.templates_xpath).click() + + #Select Template from drop down list + driver.find_element_by_xpath(Global_Locators.template_xpath).click() + + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.template_table_xpath) # This returns a list + + for link in linkclass: + + if link.text == "Test Template Ubuntu": # We will search for our VM in this table + link.click() + + time.sleep(2) + + # Change name + driver.find_element_by_name("name").clear() + driver.find_element_by_name("name").send_keys("Test template") + + + # Change Description + driver.find_element_by_name("displaytext").clear() + driver.find_element_by_name("displaytext").send_keys("ubuntu") + + driver.find_element_by_css_selector(Global_Locators.template_editdone_css).click() + time.sleep(2) + + #Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(10) + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + +# Now we will find this offering and delete it!! + + + + + + +class Template_Delete(unittest.TestCase): + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + + def test_templatedelete(self): + + driver = self.driver + + ## Action part + #Make sure you are on Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + # Go to Templates + driver.find_element_by_xpath(Global_Locators.templates_xpath).click() + + #Select Template from drop down list + driver.find_element_by_xpath(Global_Locators.template_xpath).click() + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.template_table_xpath) # This returns a list + + for link in linkclass: + + if link.text == "Test Template": # We will search for our VM in this table + link.click() + + time.sleep(2) + + driver.find_element_by_css_selector(Gloabl_Locators.template_delete_css).click() + driver.find_element_by_xpath(Global_Locators.yesconfirmation_xapth).click() + + time.sleep(2) + + #Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + + time.sleep(20) + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) diff --git a/test/selenium/smoke/VM_lifeCycle.py b/test/selenium/smoke/VM_lifeCycle.py new file mode 100644 index 00000000000..845a5cb316f --- /dev/null +++ b/test/selenium/smoke/VM_lifeCycle.py @@ -0,0 +1,613 @@ +# 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. + +import sys, os +sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/'+'../lib')) + + + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import Select +from selenium.common.exceptions import NoSuchElementException +import unittest, time +import initialize +import Global_Locators + + + +class deployVM(unittest.TestCase): + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + def test_deployvm(self): + + + ## Action Part + # VM will be named Auto-VM and this VM will be used in all subsequent tests. + # Deploy an Instance named Auto-VM Default CentOS no GUI Template + + driver = self.driver + self.driver.implicitly_wait(30) + driver.refresh() ## Most Important step. Failure to do this will change XPATH location and Scripts will fail. + + + # Click on Instances link + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + + # Click on add Instance on Instances page + driver.find_element_by_xpath(Global_Locators.add_instance_xpath).click() + + # Following select template action will fire automatically... ignore it. And leave following commented. + # driver.find_element_by_xpath("(//input[@name='select-template'])[3]").click() + #Click on Next button on Instances Wizard. + driver.find_element_by_xpath(Global_Locators.add_instance_next_xpath).click() + + # Nothing to do here as we will be using all default settings. (Default CentOS no GUI template should be highlighted here. Click Next + driver.find_element_by_xpath(Global_Locators.add_instance_next_xpath).click() + + # Nothing to do here. Medium Instance compute offering should be selected here. Click Next + driver.find_element_by_xpath(Global_Locators.add_instance_next_xpath).click() + + # Nothing to do here. Data Disk Offering : No Thanks!!. Click Next + driver.find_element_by_xpath(Global_Locators.add_instance_next_xpath).click() + + # Since this is our first instance; we must provide a network name. We will use Test-Network as out network name. + driver.find_element_by_xpath("(//input[@name='new-network-name'])[2]").click() + driver.find_element_by_xpath("(//input[@name='new-network-name'])[2]").clear() + driver.find_element_by_xpath("(//input[@name='new-network-name'])[2]").send_keys("Test-Network") + + #Click next + driver.find_element_by_xpath(Global_Locators.add_instance_next_xpath).click() + + # Give our VM a name here. Use Auto-VM as name + driver.find_element_by_xpath("(//input[@name='displayname'])[2]").click() + + driver.find_element_by_xpath("(//input[@name='displayname'])[2]").clear() + + driver.find_element_by_xpath("(//input[@name='displayname'])[2]").send_keys("Auto-VM") + + # All data filled. Click Launch VM. (It has the same xpath as Next button. So we will use Next Variable here. + driver.find_element_by_xpath(Global_Locators.add_instance_next_xpath).click() + + print '\n' + '\n' + "VM Deployment is complete... wait for 5 mins to check deployment status" + '\n' + '\n' + + + + ## Verification Part + + + ## Now we must wait for some random time (Educated guess based on experience) and check if VM has been deployed and if it is in running state. + ## Should take about 4 min to deploy VM.. but we will wait 5 mins and check the status , we will do this twice. So total 2 check within 10 mins with first check occuring at 5th min. + + + driver.refresh() # Refresh UI Page; This polls latest status. + + # Click on Instances link + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + count = 1 + + while (count > 0): + + time.sleep(300) + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + print "found VM in table .. checking status..." + '\n' + '\n' + link.click() + + status = driver.find_element_by_xpath(Global_Locators.state_xpath).text ## get the status of our VM + + if status == "Running" : + print "VM is in running state... continuing with other tests."+ '\n' + '\n' + break + else: + print "Need to check one more time after 5 mins" + continue + count = count - 1 + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + + def tearDown(self): + self.assertEqual([], self.verificationErrors) + + + + + +################################################################################################################################################################################################ + + + +class destroyVM(unittest.TestCase): + + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + def test_destroyvm(self): + + driver = self.driver + self.driver.implicitly_wait(100) + + ## Action part + # Click on Instances link and find our instance + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + time.sleep(2) + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + link.click() + + # Click on Destroy Instance button and confirm + time.sleep(2) + driver.find_element_by_css_selector(Global_Locators.destroyinstance_css).click() + time.sleep(2) + + # Click ok on confirmation + driver.find_element_by_xpath(Global_Locators.yesconfirmation_xapth).click() + time.sleep(2) + + # Go to Dashboard + # driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + driver.refresh() + + ## Verification part + time.sleep(60) + + # Click on Instances link and find our instance + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + time.sleep(2) + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + link.click() + + + status = driver.find_element_by_xpath(Global_Locators.state_xpath).text ## get the status of our VM + if status == "Destroyed" : + print "VM is Destroyed...."+ '\n' + '\n' + else: + print "Something went wrong" + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + + + + +################################################################################################################################################################################################ + + + + +class rebootVM(unittest.TestCase): + + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + def test_rebootvm(self): + + driver = self.driver + self.driver.implicitly_wait(30) + print "Verify this test manually for now" + + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(vmLifeAndNetwork.Server_Ip, username='root', password='password') + print '\n' + '\n' + "Before Reboot ...Executing command date ... " + '\n' + '\n' + stdin, stdout, stderr = ssh.exec_command('date') + print stdout.readlines() + print '\n' + '\n' + "Before Reboot ...Executing command last reboot | head -1 ..." + '\n' + '\n' + stdin, stdout, stderr = ssh.exec_command('last reboot | head -1') + print '\n' + '\n' + "Before Reboot ...Executing command uptime..." + '\n' + '\n' + stdin, stdout, stderr = ssh.exec_command('uptime') + print stdout.readlines() + ssh.close() + + + driver.refresh() + + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + count = 1 + + while (count > 0): + + #time.sleep(300) + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + print "found VM in table .. Rebooting now..." + '\n' + '\n' + link.click() + + driver.find_element_by_css_selector(Global_Locators.rebootinstance_css).click() + driver.find_element_by_xpath(Global_Locators.actionconfirm_xpath).click() + + # Sleep for 5 mins to ensure system gets rebooted. + time.sleep(300) + + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(vmLifeAndNetwork.Server_Ip, username='root', password='password') + print '\n' + '\n' + "After Reboot ...Executing command date ... " + '\n' + '\n' + stdin, stdout, stderr = ssh.exec_command('date') + print stdout.readlines() + print '\n' + '\n' + "After Reboot ...Executing command last reboot | head -1 ..." + '\n' + '\n' + stdin, stdout, stderr = ssh.exec_command('last reboot | head -1') + print '\n' + '\n' + "After Reboot ...Executing command uptime..." + '\n' + '\n' + stdin, stdout, stderr = ssh.exec_command('uptime') + print stdout.readlines() + ssh.close() + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + def tearDown(self): + self.assertEqual([], self.verificationErrors) + + +######################################################################################################################################################### + + + +class restoreVM(unittest.TestCase): + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + def test_restorevm(self): + + driver = self.driver + self.driver.implicitly_wait(100) + + ## Action part + # Click on Instances link and find our instance + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + + link.click() + + # Click on Destroy Instance button and confirm + driver.find_element_by_css_selector(Global_Locators.restoreinstance_css).click() + + # Click ok on confirmation + driver.find_element_by_xpath(Global_Locators.yesconfirmation_xapth).click() + + # Go to Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + + + ## Verification part + + time.sleep(60) + + # Click on Instances link and find our instance + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + link.click() + + + status = driver.find_element_by_xpath(Global_Locators.state_xpath).text ## get the status of our VM + + if status == "Stopped" : + print "VM is Restored. but in stopped state.. will start now."+ '\n' + '\n' + + else: + print "Something went wrong" + + + + + #VM will be in stop state so we must start it now + # Click on Instances link and find our instance + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + link.click() + + # Click on Start Instance. + driver.find_element_by_css_selector(Global_Locators.startinstance_css).click() + time.sleep(2) + + # Dismiss confirmation by clicking Yes + driver.find_element_by_xpath(Global_Locators.yesconfirmation_xapth).click() + time.sleep(2) + + # Go to Dashboard + driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + time.sleep(2) + + print "VM is Started."+ '\n' + '\n' + + # status = None + time.sleep(60) + + # Dismiss the Start Instance information box. + driver.find_element_by_xpath(Global_Locators.actionconfirm_xpath).click() + time.sleep(2) + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + + +######################################################################################################################################################### + + + +class startVM(unittest.TestCase): + + + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + def test_startvm(self): + + driver = self.driver + self.driver.implicitly_wait(100) + + ## Action part + #driver.refresh() ## Most Important step. Failure to do this will change XPATH location and Scripts will fail. + # Click on Instances link and find our instance + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + print "found VM in table .. checking status..." + '\n' + '\n' + link.click() + + + + # Click on Start Instance. + driver.find_element_by_css_selector(Global_Locators.startinstance_css).click() + time.sleep(2) + + # Dismiss confirmation by clicking Yes + driver.find_element_by_xpath(Global_Locators.yesconfirmation_xapth).click() + time.sleep(2) + + # Go to Dashboard + #driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + driver.refresh() + + + ## Verification part + # status = None + time.sleep(60) + + # Dismiss the Start Instance information box. + driver.find_element_by_xpath(Global_Locators.actionconfirm_xpath).click() + time.sleep(2) + + # Click on Instances link and find our instance + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + time.sleep(2) + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + link.click() + + + status = driver.find_element_by_xpath(Global_Locators.state_xpath).text ## get the status of our VM + + if status == "Running" : + print "VM is in Running state..."+ '\n' + '\n' + + else: + print "Something went wrong" + + # Go to Dashboard + driver.refresh() + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + + + +######################################################################################################################################################### + + + +class stopVM(unittest.TestCase): + + def setUp(self): + + self.driver = initialize.getOrCreateWebdriver() + self.verificationErrors = [] + + + def test_stopvm(self): + + driver = self.driver + self.driver.implicitly_wait(100) + + ## Action part + driver.refresh() ## Important step. + + # Click on Instances link and find our instance + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + print "found VM in table .. checking status..." + '\n' + '\n' + link.click() + + + # HWe are on our VM information page. + driver.find_element_by_css_selector(Global_Locators.stopinstance_css).click() + time.sleep(2) + + # a Pop up must appear; below we will check the force stop check box and then we will click ok. + driver.find_element_by_id(Global_Locators.stopinstanceforce_id).click() + driver.find_element_by_xpath(Global_Locators.actionconfirm_xpath).click() + time.sleep(2) + + # Go to Dahsboard + #driver.find_element_by_xpath(Global_Locators.dashboard_xpath).click() + driver.refresh() + + # Should take less than min to stop the instance. We will check twice at interval of 45 seconds o be safe. + ## Verification part + time.sleep(60) + + # Click on Instances link and find our instance + driver.find_element_by_xpath(Global_Locators.instances_xpath).click() + + linkclass = None + linkclass = driver.find_elements_by_xpath(Global_Locators.instances_table_xpath) # This returns a list of all VM names in tables + + for link in linkclass: + + if link.text == "Auto-VM": # We will search for our VM in this table + link.click() + + + status = driver.find_element_by_xpath(Global_Locators.state_xpath).text ## get the status of our VM + + if status == "Stopped" : + print "VM is in Stopped state...."+ '\n' + '\n' + else: + print "Something went wrong" + + + + def is_element_present(self, how, what): + + try: self.driver.find_element(by=how, value=what) + except NoSuchElementException, e: return False + return True + + + + def tearDown(self): + + self.assertEqual([], self.verificationErrors) + + +######################################################################################################################################################### diff --git a/test/selenium/smoke/main.py b/test/selenium/smoke/main.py new file mode 100644 index 00000000000..86bb9308c2f --- /dev/null +++ b/test/selenium/smoke/main.py @@ -0,0 +1,145 @@ +# 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. + +import unittest +import HTMLTestRunner +import xmlrunner + + +global DRIVER + + +# Import test cases + +################################## +from Login_and_Accounts import * +from Service_Offering import * + +from TemplatesAndISO import * +from VM_lifeCycle import * + +################################### + + +# Following are BVT Tests +# serialize the test cases + + +suite = unittest.TestSuite() # setup new test suite + + +#################################################################################################### + +# Following logs admin user in and creates test account then logs admin user out and logs in as test to run tests. +# You should leave this as is for all the tests. + +suite.addTest(unittest.makeSuite(login)) #Login Admin + +time.sleep(5) +suite.addTest(unittest.makeSuite(createAcc)) # Create an Account test. We will use test account for all our tests + +time.sleep(5) +suite.addTest(unittest.makeSuite(logout)) #Logout Admin + +time.sleep(5) +suite.addTest(unittest.makeSuite(login_test)) # Login Test + + + +#################################################################################################### + + + +time.sleep(5) +suite.addTest(unittest.makeSuite(Disk_offering_Add)) + +time.sleep(5) +suite.addTest(unittest.makeSuite(Disk_offering_Edit)) + +time.sleep(5) +suite.addTest(unittest.makeSuite(Disk_offering_Delete)) + +time.sleep(5) +suite.addTest(unittest.makeSuite(Compute_offering_Add)) + +time.sleep(5) +suite.addTest(unittest.makeSuite(Compute_offering_Edit)) + +time.sleep(5) +suite.addTest(unittest.makeSuite(Compute_offering_Delete)) + + +# time.sleep(5) +# suite.addTest(unittest.makeSuite(deployVM)) + +# time.sleep(5) +# suite.addTest(unittest.makeSuite(stopVM)) + +# time.sleep(5) +# suite.addTest(unittest.makeSuite(startVM)) + +# time.sleep(5) +# suite.addTest(unittest.makeSuite(destroyVM)) + +# time.sleep(5) +# suite.addTest(unittest.makeSuite(restoreVM)) + + +# time.sleep(5) +# suite.addTest(unittest.makeSuite(Template_Add)) + +# time.sleep(5) +# suite.addTest(unittest.makeSuite(Template_Edit)) + +# time.sleep(5) +# suite.addTest(unittest.makeSuite(Template_Delete)) + + +#################################################################################################### + +# Following logs test user out and logs back in as Admin and tears down the test account. +# You should leave this as is for all the tests. + +suite.addTest(unittest.makeSuite(logout)) #Logout test +time.sleep(5) +suite.addTest(unittest.makeSuite(login)) #Login Admin +time.sleep(5) +suite.addTest(unittest.makeSuite(tearAcc)) # Delete Account test + +#################################################################################################### + + + +# If XML reports compatible with junit's XML output are desired then leave folowing code as is. +# If HTML reports are desired follow instructions + + +#Comment following line for HTML and uncomment for XML +runner = xmlrunner.XMLTestRunner(output='test-reports') + +#Comment following line for XML and uncomment for HTML +#runner = HTMLTestRunner.HTMLTestRunner() + +#header is required for displaying the website +#Comment following line for XML and uncomment for HTML +#print "Content-Type: text/html\n" + +# Leave following as is for either XML or HTML +runner.run(suite) + + + diff --git a/tools/apidoc/pom.xml b/tools/apidoc/pom.xml index 6b159ff54eb..b324ad4b567 100644 --- a/tools/apidoc/pom.xml +++ b/tools/apidoc/pom.xml @@ -12,24 +12,16 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 cloud-apidoc - Apache CloudStack apidoc Tools + Apache CloudStack apidocs pom org.apache.cloudstack - cloudstack - 4.1.0-SNAPSHOT - ../../pom.xml + cloud-tools + 4.2.0-SNAPSHOT + ../pom.xml - - - org.apache.cloudstack - cloud-client-ui - ${project.version} - war - - - ../../client/target/cloud-client-ui-4.1.0-SNAPSHOT/WEB-INF/ + ../../client/target/cloud-client-ui-4.2.0-SNAPSHOT/WEB-INF/ ${client.config.base}/lib ${client.config.base}/classes diff --git a/tools/appliance/README.md b/tools/appliance/README.md index aa1001e1b1b..2f6f656212d 100644 --- a/tools/appliance/README.md +++ b/tools/appliance/README.md @@ -19,6 +19,8 @@ under the License. # Setting up Tools and Environment + - Install VirtualBox 4.2 or latest + - Tool for exporting appliances: qemu-img, vboxmanage, vhd-util - Install [RVM](https://rvm.io/rvm/install) - Setup paths: export PATH=~/.rvm/bin:$PATH @@ -36,7 +38,14 @@ Note, gem may require gcc-4.2, make sure link exists: sudo ln -s /usr/bin/gcc /usr/bin/gcc-4.2 -# How to build SystemVM template appliance +# How to build SystemVMs automatically + +Just run build.sh, it will export archived appliances for KVM, Xen, +VMWare and HyperV in `dist`: + + sh build.sh + +# Building SystemVM template appliance manually List available appliances one can build: @@ -50,3 +59,9 @@ Build systemvm template appliance: Start the box: veewee vbox up 'systemvmtemplate' + +Halt the box: + + veewee vbox halt 'systemvmtemplate' + +Now VirtualBox can be used to export appliance. diff --git a/tools/appliance/build.sh b/tools/appliance/build.sh new file mode 100644 index 00000000000..366b246fbe2 --- /dev/null +++ b/tools/appliance/build.sh @@ -0,0 +1,69 @@ +#!/bin/bash -xl +# 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. + +set -x +set -e + +appliance="systemvmtemplate" +build_date=`date +%Y-%m-%d` +branch="master" +rootdir=$PWD + +# Initialize veewee and dependencies +bundle + +# Clean and start building the appliance +veewee vbox destroy $appliance +veewee vbox build $appliance --nogui +veewee vbox halt $appliance + +while [[ `vboxmanage list runningvms | grep $appliance | wc -l` -ne 0 ]]; +do + echo "Waiting for $appliance to shutdown" + sleep 2; +done + +# Get appliance uuids +machine_uuid=`vboxmanage showvminfo $appliance | grep UUID | head -1 | awk '{print $2}'` +hdd_uuid=`vboxmanage showvminfo $appliance | grep vmdk | head -1 | awk '{print $8}' | cut -d ')' -f 1` + +# Start exporting +rm -fr dist +mkdir dist + +# Export for VMWare vSphere +vboxmanage export $machine_uuid --output dist/$appliance-$build_date-$branch-vmware.ova +echo "$appliance exported for VMWare: dist/$appliance-$build_date-$branch-vmware.ova" + +# Export for HyperV +vboxmanage clonehd $hdd_uuid dist/$appliance-$build_date-$branch-hyperv.vhd --format VHD +bzip2 dist/$appliance-$build_date-$branch-hyperv.vhd +echo "$appliance exported for HyperV: dist/$appliance-$build_date-$branch-hyperv.vhd.bz2" + +# Export for KVM +vboxmanage clonehd $hdd_uuid dist/raw.img --format RAW +qemu-img convert -f raw -O qcow2 dist/raw.img dist/$appliance-$build_date-$branch-kvm.qcow2 +bzip2 dist/$appliance-$build_date-$branch-kvm.qcow2 +echo "$appliance exported for KVM: dist/$appliance-$build_date-$branch-kvm.qcow2.bz2" + +# Export for Xen +# This will be an overwrite convert so, do it at the end +vhd-util convert -s 0 -t 1 -i dist/raw.img -o dist/$appliance-$build_date-$branch-xen.vhd +bzip2 dist/$appliance-$build_date-$branch-xen.vhd +echo "$appliance exported for Xen: dist/$appliance-$build_date-$branch-xen.vhd.bz2" + diff --git a/tools/appliance/definitions/systemvmtemplate/LICENSE b/tools/appliance/definitions/systemvmtemplate/LICENSE deleted file mode 100644 index c33c3bba2ae..00000000000 --- a/tools/appliance/definitions/systemvmtemplate/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (c) 2010-2012 Patrick Debois - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/tools/appliance/definitions/systemvmtemplate/base.sh b/tools/appliance/definitions/systemvmtemplate/base.sh index 5b35b56c9e3..a6b69e6f096 100644 --- a/tools/appliance/definitions/systemvmtemplate/base.sh +++ b/tools/appliance/definitions/systemvmtemplate/base.sh @@ -1,21 +1,3 @@ -# 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. - - # Update the box apt-get -y update #below are needed for ruby perhaps diff --git a/tools/appliance/definitions/systemvmtemplate/cleanup.sh b/tools/appliance/definitions/systemvmtemplate/cleanup.sh index 42d0fd64769..6009aad8e78 100644 --- a/tools/appliance/definitions/systemvmtemplate/cleanup.sh +++ b/tools/appliance/definitions/systemvmtemplate/cleanup.sh @@ -1,20 +1,3 @@ -# 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. - # Clean up #apt-get -y remove linux-headers-$(uname -r) build-essential apt-get -y remove dictionaries-common busybox @@ -34,4 +17,3 @@ rm /lib/udev/rules.d/75-persistent-net-generator.rules echo "Adding a 2 sec delay to the interface up, to make the dhclient happy" echo "pre-up sleep 2" >> /etc/network/interfaces - diff --git a/tools/appliance/definitions/systemvmtemplate/cloudstack-packages.sh b/tools/appliance/definitions/systemvmtemplate/cloudstack-packages.sh deleted file mode 100644 index 9a402535463..00000000000 --- a/tools/appliance/definitions/systemvmtemplate/cloudstack-packages.sh +++ /dev/null @@ -1,152 +0,0 @@ -# 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. - - -ROOTPW=password -HOSTNAME=systemvm -CLOUDSTACK_RELEASE=4.2.0 - - -install_packages() { - DEBIAN_FRONTEND=noninteractive - DEBIAN_PRIORITY=critical - - #basic stuff - apt-get --no-install-recommends -q -y --force-yes install rsyslog logrotate cron chkconfig insserv net-tools ifupdown vim-tiny netbase iptables - apt-get --no-install-recommends -q -y --force-yes install openssh-server grub-legacy e2fsprogs dhcp3-client dnsmasq tcpdump socat wget - apt-get --no-install-recommends -q -y --force-yes install python bzip2 sed gawk diffutils grep gzip less tar telnet ftp rsync traceroute psmisc lsof procps monit inetutils-ping iputils-arping httping - apt-get --no-install-recommends -q -y --force-yes install dnsutils zip unzip ethtool uuid file iproute acpid virt-what sudo - - #sysstat - echo 'sysstat sysstat/enable boolean true' | debconf-set-selections - apt-get --no-install-recommends -q -y --force-yes install sysstat - #apache - apt-get --no-install-recommends -q -y --force-yes install apache2 ssl-cert - #haproxy - apt-get --no-install-recommends -q -y --force-yes install haproxy - #dnsmasq - apt-get --no-install-recommends -q -y --force-yes install dnsmasq - #nfs client - apt-get --no-install-recommends -q -y --force-yes install nfs-common - - #vpn stuff - apt-get --no-install-recommends -q -y --force-yes install xl2tpd bcrelay ppp ipsec-tools tdb-tools - echo "openswan openswan/install_x509_certificate boolean false" | debconf-set-selections - echo "openswan openswan/install_x509_certificate seen true" | debconf-set-selections - apt-get --no-install-recommends -q -y --force-yes install openswan - - #vmware tools - apt-get --no-install-recommends -q -y --force-yes install open-vm-tools - #xenstore utils - apt-get --no-install-recommends -q -y --force-yes install xenstore-utils libxenstore3.0 - #keepalived and conntrackd for redundant router - apt-get --no-install-recommends -q -y --force-yes install keepalived conntrackd ipvsadm libnetfilter-conntrack3 libnl1 - #ipcalc - apt-get --no-install-recommends -q -y --force-yes install ipcalc - #java - apt-get --no-install-recommends -q -y --force-yes install default-jre-headless - - echo "iptables-persistent iptables-persistent/autosave_v4 boolean true" | debconf-set-selections - echo "iptables-persistent iptables-persistent/autosave_v6 boolean true" | debconf-set-selections - apt-get --no-install-recommends -q -y --force-yes install iptables-persistent -} - -accounts() { - # Setup sudo to allow no-password sudo for "admin" - groupadd -r admin - #create a 'cloud' user - useradd -G admin cloud - echo "root:$PASSWORD" | chpasswd - #FIXME: create random password for cloud - #FIXME: disable password auth in sshd (final step, after veewee is done) - #echo "cloud:password" | chpasswd - sed -i -e '/Defaults\s\+env_reset/a Defaults\texempt_group=admin' /etc/sudoers - sed -i -e 's/%admin ALL=(ALL) ALL/%admin ALL=NOPASSWD:ALL/g' /etc/sudoers - - mkdir -p /home/cloud/.ssh - chmod 700 /home/cloud/.ssh - -} - -fix_nameserver() { - #replace /etc/resolv.conf also - cat > /etc/resolv.conf << EOF -nameserver 8.8.8.8 -nameserver 4.4.4.4 -EOF - -} - -do_fixes() { - #fix hostname in openssh-server generated keys - sed -i "s/root@\(.*\)$/root@$HOSTNAME/g" /etc/ssh/ssh_host_*.pub - #fix hostname to override one provided by dhcp during vm build - echo "$HOSTNAME" > /etc/hostname - hostname $HOSTNAME - #delete entry in /etc/hosts derived from dhcp - sed -i '/127.0.1.1/d' /etc/hosts - - #fix_nameserver FIXME needed after veewee finishes -} - -configure_apache2() { - #enable ssl, rewrite and auth - a2enmod ssl rewrite auth_basic auth_digest - a2ensite default-ssl - #backup stock apache configuration since we may modify it in Secondary Storage VM - cp /etc/apache2/sites-available/default /etc/apache2/sites-available/default.orig - cp /etc/apache2/sites-available/default-ssl /etc/apache2/sites-available/default-ssl.orig -} - -services() { - mkdir -p /var/www/html - mkdir -p /opt/cloud/bin - mkdir -p /var/cache/cloud - mkdir -p /usr/share/cloud - mkdir -p /usr/local/cloud - mkdir -p /root/.ssh - #Fix haproxy directory issue - mkdir -p /var/lib/haproxy - - wget 'https://git-wip-us.apache.org/repos/asf?p=incubator-cloudstack.git;a=blob_plain;f=patches/systemvm/debian/config/etc/init.d/cloud-early-config;hb=HEAD' -O /etc/init.d/cloud-early-config - chkconfig --add cloud-early-config - chkconfig cloud-early-config on - wget 'https://git-wip-us.apache.org/repos/asf?p=incubator-cloudstack.git;a=blob_plain;f=patches/systemvm/debian/config/etc/init.d/cloud-passwd-srvr;hb=HEAD' -O /etc/init.d/cloud-passwd-srvr - chkconfig --add cloud-passwd-srvr - chkconfig cloud-passwd-srvr off - wget 'https://git-wip-us.apache.org/repos/asf?p=incubator-cloudstack.git;a=blob_plain;f=patches/systemvm/debian/config/etc/init.d/cloud;hb=HEAD' -O /etc/init.d/cloud - chkconfig --add cloud - chkconfig cloud off - chkconfig monit off - chkconfig xl2tpd off -} - -signature() { - mkdir -p /var/cache/cloud/ - touch /var/cache/cloud/cloud-scripts-signature - #FIXME: signature should be generated from scripts package that can get updated - echo "Cloudstack Release $CLOUDSTACK_RELEASE $(date)" > /etc/cloudstack-release -} - -echo "*************INSTALLING PACKAGES********************" -install_packages -echo "*************DONE INSTALLING PACKAGES********************" -accounts -do_fixes -configure_apache2 -services -signature diff --git a/tools/appliance/definitions/systemvmtemplate/config.dat b/tools/appliance/definitions/systemvmtemplate/config.dat deleted file mode 100644 index bc71fb981db..00000000000 --- a/tools/appliance/definitions/systemvmtemplate/config.dat +++ /dev/null @@ -1,878 +0,0 @@ -Name: adduser/homedir-permission -Template: adduser/homedir-permission -Value: true -Owners: adduser - -Name: adduser/title -Template: adduser/title -Owners: adduser - -Name: apt-listchanges/confirm -Template: apt-listchanges/confirm -Value: false -Owners: apt-listchanges - -Name: apt-listchanges/email-address -Template: apt-listchanges/email-address -Value: root -Owners: apt-listchanges - -Name: apt-listchanges/frontend -Template: apt-listchanges/frontend -Value: pager -Owners: apt-listchanges - -Name: apt-listchanges/save-seen -Template: apt-listchanges/save-seen -Value: true -Owners: apt-listchanges - -Name: apt-listchanges/which -Template: apt-listchanges/which -Value: news -Owners: apt-listchanges - -Name: ca-certificates/enable_crts -Template: ca-certificates/enable_crts -Value: cacert.org/cacert.org.crt, debconf.org/ca.crt, mozilla/ACEDICOM_Root.crt, mozilla/AC_Raíz_Certicámara_S.A..crt, mozilla/Actalis_Authentication_Root_CA.crt, mozilla/AddTrust_External_Root.crt, mozilla/AddTrust_Low-Value_Services_Root.crt, mozilla/AddTrust_Public_Services_Root.crt, mozilla/AddTrust_Qualified_Certificates_Root.crt, mozilla/AffirmTrust_Commercial.crt, mozilla/AffirmTrust_Networking.crt, mozilla/AffirmTrust_Premium.crt, mozilla/AffirmTrust_Premium_ECC.crt, mozilla/America_Online_Root_Certification_Authority_1.crt, mozilla/America_Online_Root_Certification_Authority_2.crt, mozilla/ApplicationCA_-_Japanese_Government.crt, mozilla/A-Trust-nQual-03.crt, mozilla/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.crt, mozilla/Baltimore_CyberTrust_Root.crt, mozilla/Buypass_Class_2_CA_1.crt, mozilla/Buypass_Class_2_Root_CA.crt, mozilla/Buypass_Class_3_CA_1.crt, mozilla/Buypass_Class_3_Root_CA.crt, mozilla/CA_Disig.crt, mozilla/Camerfirma_Chambers_of_Commerce_Root.crt, mozilla/Camerfirma_Global_Chambersign_Root.crt, mozilla/Certigna.crt, mozilla/Certinomis_-_Autorité_Racine.crt, mozilla/Certplus_Class_2_Primary_CA.crt, mozilla/certSIGN_ROOT_CA.crt, mozilla/Certum_Root_CA.crt, mozilla/Certum_Trusted_Network_CA.crt, mozilla/Chambers_of_Commerce_Root_-_2008.crt, mozilla/CNNIC_ROOT.crt, mozilla/Comodo_AAA_Services_root.crt, mozilla/COMODO_Certification_Authority.crt, mozilla/COMODO_ECC_Certification_Authority.crt, mozilla/Comodo_Secure_Services_root.crt, mozilla/Comodo_Trusted_Services_root.crt, mozilla/ComSign_CA.crt, mozilla/ComSign_Secured_CA.crt, mozilla/Cybertrust_Global_Root.crt, mozilla/Deutsche_Telekom_Root_CA_2.crt, mozilla/DigiCert_Assured_ID_Root_CA.crt, mozilla/DigiCert_Global_Root_CA.crt, mozilla/DigiCert_High_Assurance_EV_Root_CA.crt, mozilla/Digital_Signature_Trust_Co._Global_CA_1.crt, mozilla/Digital_Signature_Trust_Co._Global_CA_3.crt, mozilla/DST_ACES_CA_X6.crt, mozilla/DST_Root_CA_X3.crt, mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt, mozilla/EC-ACC.crt, mozilla/EE_Certification_Centre_Root_CA.crt, mozilla/E-Guven_Kok_Elektronik_Sertifika_Hizmet_Saglayicisi.crt, mozilla/Entrust.net_Premium_2048_Secure_Server_CA.crt, mozilla/Entrust.net_Secure_Server_CA.crt, mozilla/Entrust_Root_Certification_Authority.crt, mozilla/ePKI_Root_Certification_Authority.crt, mozilla/Equifax_Secure_CA.crt, mozilla/Equifax_Secure_eBusiness_CA_1.crt, mozilla/Equifax_Secure_eBusiness_CA_2.crt, mozilla/Equifax_Secure_Global_eBusiness_CA.crt, mozilla/Firmaprofesional_Root_CA.crt, mozilla/GeoTrust_Global_CA_2.crt, mozilla/GeoTrust_Global_CA.crt, mozilla/GeoTrust_Primary_Certification_Authority.crt, mozilla/GeoTrust_Primary_Certification_Authority_-_G2.crt, mozilla/GeoTrust_Primary_Certification_Authority_-_G3.crt, mozilla/GeoTrust_Universal_CA_2.crt, mozilla/GeoTrust_Universal_CA.crt, mozilla/Global_Chambersign_Root_-_2008.crt, mozilla/GlobalSign_Root_CA.crt, mozilla/GlobalSign_Root_CA_-_R2.crt, mozilla/GlobalSign_Root_CA_-_R3.crt, mozilla/Go_Daddy_Class_2_CA.crt, mozilla/Go_Daddy_Root_Certificate_Authority_-_G2.crt, mozilla/GTE_CyberTrust_Global_Root.crt, mozilla/Hellenic_Academic_and_Research_Institutions_RootCA_2011.crt, mozilla/Hongkong_Post_Root_CA_1.crt, mozilla/IGC_A.crt, mozilla/Izenpe.com.crt, mozilla/Juur-SK.crt, mozilla/Microsec_e-Szigno_Root_CA_2009.crt, mozilla/Microsec_e-Szigno_Root_CA.crt, mozilla/NetLock_Arany_=Class_Gold=_Főtanúsítvány.crt, mozilla/NetLock_Business_=Class_B=_Root.crt, mozilla/NetLock_Express_=Class_C=_Root.crt, mozilla/NetLock_Notary_=Class_A=_Root.crt, mozilla/NetLock_Qualified_=Class_QA=_Root.crt, mozilla/Network_Solutions_Certificate_Authority.crt, mozilla/OISTE_WISeKey_Global_Root_GA_CA.crt, mozilla/QuoVadis_Root_CA_2.crt, mozilla/QuoVadis_Root_CA_3.crt, mozilla/QuoVadis_Root_CA.crt, mozilla/Root_CA_Generalitat_Valenciana.crt, mozilla/RSA_Root_Certificate_1.crt, mozilla/RSA_Security_2048_v3.crt, mozilla/Secure_Global_CA.crt, mozilla/SecureSign_RootCA11.crt, mozilla/SecureTrust_CA.crt, mozilla/Security_Communication_EV_RootCA1.crt, mozilla/Security_Communication_RootCA2.crt, mozilla/Security_Communication_Root_CA.crt, mozilla/Sonera_Class_1_Root_CA.crt, mozilla/Sonera_Class_2_Root_CA.crt, mozilla/Staat_der_Nederlanden_Root_CA.crt, mozilla/Staat_der_Nederlanden_Root_CA_-_G2.crt, mozilla/Starfield_Class_2_CA.crt, mozilla/Starfield_Root_Certificate_Authority_-_G2.crt, mozilla/Starfield_Services_Root_Certificate_Authority_-_G2.crt, mozilla/StartCom_Certification_Authority.crt, mozilla/StartCom_Certification_Authority_G2.crt, mozilla/S-TRUST_Authentication_and_Encryption_Root_CA_2005_PN.crt, mozilla/Swisscom_Root_CA_1.crt, mozilla/SwissSign_Gold_CA_-_G2.crt, mozilla/SwissSign_Platinum_CA_-_G2.crt, mozilla/SwissSign_Silver_CA_-_G2.crt, mozilla/TÜBİTAK_UEKAE_Kök_Sertifika_Hizmet_Sağlayıcısı_-_Sürüm_3.crt, mozilla/Taiwan_GRCA.crt, mozilla/TC_TrustCenter_Class_2_CA_II.crt, mozilla/TC_TrustCenter_Class_3_CA_II.crt, mozilla/TC_TrustCenter_Universal_CA_I.crt, mozilla/TC_TrustCenter_Universal_CA_III.crt, mozilla/TDC_Internet_Root_CA.crt, mozilla/TDC_OCES_Root_CA.crt, mozilla/Thawte_Premium_Server_CA.crt, mozilla/thawte_Primary_Root_CA.crt, mozilla/thawte_Primary_Root_CA_-_G2.crt, mozilla/thawte_Primary_Root_CA_-_G3.crt, mozilla/Thawte_Server_CA.crt, mozilla/Trustis_FPS_Root_CA.crt, mozilla/T-TeleSec_GlobalRoot_Class_3.crt, mozilla/TURKTRUST_Certificate_Services_Provider_Root_1.crt, mozilla/TURKTRUST_Certificate_Services_Provider_Root_2.crt, mozilla/TWCA_Root_Certification_Authority.crt, mozilla/UTN_DATACorp_SGC_Root_CA.crt, mozilla/UTN_USERFirst_Email_Root_CA.crt, mozilla/UTN_USERFirst_Hardware_Root_CA.crt, mozilla/ValiCert_Class_1_VA.crt, mozilla/ValiCert_Class_2_VA.crt, mozilla/Verisign_Class_1_Public_Primary_Certification_Authority.crt, mozilla/Verisign_Class_1_Public_Primary_Certification_Authority_-_G2.crt, mozilla/Verisign_Class_1_Public_Primary_Certification_Authority_-_G3.crt, mozilla/Verisign_Class_2_Public_Primary_Certification_Authority_-_G2.crt, mozilla/Verisign_Class_2_Public_Primary_Certification_Authority_-_G3.crt, mozilla/Verisign_Class_3_Public_Primary_Certification_Authority.crt, mozilla/Verisign_Class_3_Public_Primary_Certification_Authority_-_G2.crt, mozilla/Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.crt, mozilla/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G4.crt, mozilla/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5.crt, mozilla/Verisign_Class_4_Public_Primary_Certification_Authority_-_G3.crt, mozilla/VeriSign_Universal_Root_Certification_Authority.crt, mozilla/Visa_eCommerce_Root.crt, mozilla/Wells_Fargo_Root_CA.crt, mozilla/WellsSecure_Public_Root_Certificate_Authority.crt, mozilla/XRamp_Global_CA_Root.crt, spi-inc.org/spi-ca-2003.crt, spi-inc.org/spi-cacert-2008.crt -Owners: ca-certificates -Variables: - enable_crts = cacert.org/cacert.org.crt, debconf.org/ca.crt, mozilla/ACEDICOM_Root.crt, mozilla/AC_Raíz_Certicámara_S.A..crt, mozilla/Actalis_Authentication_Root_CA.crt, mozilla/AddTrust_External_Root.crt, mozilla/AddTrust_Low-Value_Services_Root.crt, mozilla/AddTrust_Public_Services_Root.crt, mozilla/AddTrust_Qualified_Certificates_Root.crt, mozilla/AffirmTrust_Commercial.crt, mozilla/AffirmTrust_Networking.crt, mozilla/AffirmTrust_Premium.crt, mozilla/AffirmTrust_Premium_ECC.crt, mozilla/America_Online_Root_Certification_Authority_1.crt, mozilla/America_Online_Root_Certification_Authority_2.crt, mozilla/ApplicationCA_-_Japanese_Government.crt, mozilla/A-Trust-nQual-03.crt, mozilla/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.crt, mozilla/Baltimore_CyberTrust_Root.crt, mozilla/Buypass_Class_2_CA_1.crt, mozilla/Buypass_Class_2_Root_CA.crt, mozilla/Buypass_Class_3_CA_1.crt, mozilla/Buypass_Class_3_Root_CA.crt, mozilla/CA_Disig.crt, mozilla/Camerfirma_Chambers_of_Commerce_Root.crt, mozilla/Camerfirma_Global_Chambersign_Root.crt, mozilla/Certigna.crt, mozilla/Certinomis_-_Autorité_Racine.crt, mozilla/Certplus_Class_2_Primary_CA.crt, mozilla/certSIGN_ROOT_CA.crt, mozilla/Certum_Root_CA.crt, mozilla/Certum_Trusted_Network_CA.crt, mozilla/Chambers_of_Commerce_Root_-_2008.crt, mozilla/CNNIC_ROOT.crt, mozilla/Comodo_AAA_Services_root.crt, mozilla/COMODO_Certification_Authority.crt, mozilla/COMODO_ECC_Certification_Authority.crt, mozilla/Comodo_Secure_Services_root.crt, mozilla/Comodo_Trusted_Services_root.crt, mozilla/ComSign_CA.crt, mozilla/ComSign_Secured_CA.crt, mozilla/Cybertrust_Global_Root.crt, mozilla/Deutsche_Telekom_Root_CA_2.crt, mozilla/DigiCert_Assured_ID_Root_CA.crt, mozilla/DigiCert_Global_Root_CA.crt, mozilla/DigiCert_High_Assurance_EV_Root_CA.crt, mozilla/Digital_Signature_Trust_Co._Global_CA_1.crt, mozilla/Digital_Signature_Trust_Co._Global_CA_3.crt, mozilla/DST_ACES_CA_X6.crt, mozilla/DST_Root_CA_X3.crt, mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt, mozilla/EC-ACC.crt, mozilla/EE_Certification_Centre_Root_CA.crt, mozilla/E-Guven_Kok_Elektronik_Sertifika_Hizmet_Saglayicisi.crt, mozilla/Entrust.net_Premium_2048_Secure_Server_CA.crt, mozilla/Entrust.net_Secure_Server_CA.crt, mozilla/Entrust_Root_Certification_Authority.crt, mozilla/ePKI_Root_Certification_Authority.crt, mozilla/Equifax_Secure_CA.crt, mozilla/Equifax_Secure_eBusiness_CA_1.crt, mozilla/Equifax_Secure_eBusiness_CA_2.crt, mozilla/Equifax_Secure_Global_eBusiness_CA.crt, mozilla/Firmaprofesional_Root_CA.crt, mozilla/GeoTrust_Global_CA_2.crt, mozilla/GeoTrust_Global_CA.crt, mozilla/GeoTrust_Primary_Certification_Authority.crt, mozilla/GeoTrust_Primary_Certification_Authority_-_G2.crt, mozilla/GeoTrust_Primary_Certification_Authority_-_G3.crt, mozilla/GeoTrust_Universal_CA_2.crt, mozilla/GeoTrust_Universal_CA.crt, mozilla/Global_Chambersign_Root_-_2008.crt, mozilla/GlobalSign_Root_CA.crt, mozilla/GlobalSign_Root_CA_-_R2.crt, mozilla/GlobalSign_Root_CA_-_R3.crt, mozilla/Go_Daddy_Class_2_CA.crt, mozilla/Go_Daddy_Root_Certificate_Authority_-_G2.crt, mozilla/GTE_CyberTrust_Global_Root.crt, mozilla/Hellenic_Academic_and_Research_Institutions_RootCA_2011.crt, mozilla/Hongkong_Post_Root_CA_1.crt, mozilla/IGC_A.crt, mozilla/Izenpe.com.crt, mozilla/Juur-SK.crt, mozilla/Microsec_e-Szigno_Root_CA_2009.crt, mozilla/Microsec_e-Szigno_Root_CA.crt, mozilla/NetLock_Arany_=Class_Gold=_Főtanúsítvány.crt, mozilla/NetLock_Business_=Class_B=_Root.crt, mozilla/NetLock_Express_=Class_C=_Root.crt, mozilla/NetLock_Notary_=Class_A=_Root.crt, mozilla/NetLock_Qualified_=Class_QA=_Root.crt, mozilla/Network_Solutions_Certificate_Authority.crt, mozilla/OISTE_WISeKey_Global_Root_GA_CA.crt, mozilla/QuoVadis_Root_CA_2.crt, mozilla/QuoVadis_Root_CA_3.crt, mozilla/QuoVadis_Root_CA.crt, mozilla/Root_CA_Generalitat_Valenciana.crt, mozilla/RSA_Root_Certificate_1.crt, mozilla/RSA_Security_2048_v3.crt, mozilla/Secure_Global_CA.crt, mozilla/SecureSign_RootCA11.crt, mozilla/SecureTrust_CA.crt, mozilla/Security_Communication_EV_RootCA1.crt, mozilla/Security_Communication_RootCA2.crt, mozilla/Security_Communication_Root_CA.crt, mozilla/Sonera_Class_1_Root_CA.crt, mozilla/Sonera_Class_2_Root_CA.crt, mozilla/Staat_der_Nederlanden_Root_CA.crt, mozilla/Staat_der_Nederlanden_Root_CA_-_G2.crt, mozilla/Starfield_Class_2_CA.crt, mozilla/Starfield_Root_Certificate_Authority_-_G2.crt, mozilla/Starfield_Services_Root_Certificate_Authority_-_G2.crt, mozilla/StartCom_Certification_Authority.crt, mozilla/StartCom_Certification_Authority_G2.crt, mozilla/S-TRUST_Authentication_and_Encryption_Root_CA_2005_PN.crt, mozilla/Swisscom_Root_CA_1.crt, mozilla/SwissSign_Gold_CA_-_G2.crt, mozilla/SwissSign_Platinum_CA_-_G2.crt, mozilla/SwissSign_Silver_CA_-_G2.crt, mozilla/TÜBİTAK_UEKAE_Kök_Sertifika_Hizmet_Sağlayıcısı_-_Sürüm_3.crt, mozilla/Taiwan_GRCA.crt, mozilla/TC_TrustCenter_Class_2_CA_II.crt, mozilla/TC_TrustCenter_Class_3_CA_II.crt, mozilla/TC_TrustCenter_Universal_CA_I.crt, mozilla/TC_TrustCenter_Universal_CA_III.crt, mozilla/TDC_Internet_Root_CA.crt, mozilla/TDC_OCES_Root_CA.crt, mozilla/Thawte_Premium_Server_CA.crt, mozilla/thawte_Primary_Root_CA.crt, mozilla/thawte_Primary_Root_CA_-_G2.crt, mozilla/thawte_Primary_Root_CA_-_G3.crt, mozilla/Thawte_Server_CA.crt, mozilla/Trustis_FPS_Root_CA.crt, mozilla/T-TeleSec_GlobalRoot_Class_3.crt, mozilla/TURKTRUST_Certificate_Services_Provider_Root_1.crt, mozilla/TURKTRUST_Certificate_Services_Provider_Root_2.crt, mozilla/TWCA_Root_Certification_Authority.crt, mozilla/UTN_DATACorp_SGC_Root_CA.crt, mozilla/UTN_USERFirst_Email_Root_CA.crt, mozilla/UTN_USERFirst_Hardware_Root_CA.crt, mozilla/ValiCert_Class_1_VA.crt, mozilla/ValiCert_Class_2_VA.crt, mozilla/Verisign_Class_1_Public_Primary_Certification_Authority.crt, mozilla/Verisign_Class_1_Public_Primary_Certification_Authority_-_G2.crt, mozilla/Verisign_Class_1_Public_Primary_Certification_Authority_-_G3.crt, mozilla/Verisign_Class_2_Public_Primary_Certification_Authority_-_G2.crt, mozilla/Verisign_Class_2_Public_Primary_Certification_Authority_-_G3.crt, mozilla/Verisign_Class_3_Public_Primary_Certification_Authority.crt, mozilla/Verisign_Class_3_Public_Primary_Certification_Authority_-_G2.crt, mozilla/Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.crt, mozilla/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G4.crt, mozilla/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5.crt, mozilla/Verisign_Class_4_Public_Primary_Certification_Authority_-_G3.crt, mozilla/VeriSign_Universal_Root_Certification_Authority.crt, mozilla/Visa_eCommerce_Root.crt, mozilla/Wells_Fargo_Root_CA.crt, mozilla/WellsSecure_Public_Root_Certificate_Authority.crt, mozilla/XRamp_Global_CA_Root.crt, spi-inc.org/spi-ca-2003.crt, spi-inc.org/spi-cacert-2008.crt - -Name: ca-certificates/new_crts -Template: ca-certificates/new_crts -Owners: ca-certificates -Variables: - new_crts = - -Name: ca-certificates/title -Template: ca-certificates/title -Owners: ca-certificates - -Name: ca-certificates/trust_new_crts -Template: ca-certificates/trust_new_crts -Value: yes -Owners: ca-certificates - -Name: console-setup/charmap47 -Template: console-setup/charmap47 -Value: ISO-8859-1 -Owners: console-setup -Variables: - CHOICES = ARMSCII-8, CP1251, CP1255, CP1256, GEORGIAN-ACADEMY, GEORGIAN-PS, IBM1133, ISIRI-3342, ISO-8859-1, ISO-8859-10, ISO-8859-11, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, KOI8-R, KOI8-U, TIS-620, UTF-8, VISCII - -Name: console-setup/codeset47 -Template: console-setup/codeset47 -Value: # Latin1 and Latin5 - western Europe and Turkic languages -Owners: console-setup - -Name: console-setup/codesetcode -Template: console-setup/codesetcode -Value: Lat15 -Owners: console-setup - -Name: console-setup/fontface47 -Template: console-setup/fontface47 -Value: Fixed -Owners: console-setup -Variables: - CHOICES = Fixed, Terminus, TerminusBold, TerminusBoldVGA, VGA, Do not change the boot/kernel font, Let the system select a suitable font - -Name: console-setup/fontsize -Template: console-setup/fontsize -Value: 8x16 -Owners: console-setup - -Name: console-setup/fontsize-fb47 -Template: console-setup/fontsize-fb47 -Value: 8x16 -Owners: console-setup -Variables: - CHOICES = 8x13, 8x14, 8x15, 8x16, 8x18 - -Name: console-setup/fontsize-text47 -Template: console-setup/fontsize-text47 -Value: 8x16 -Owners: console-setup - -Name: console-setup/framebuffer_only -Template: console-setup/framebuffer_only -Owners: console-setup - -Name: console-setup/guess_font -Template: console-setup/guess_font -Owners: console-setup - -Name: console-setup/store_defaults_in_debconf_db -Template: console-setup/store_defaults_in_debconf_db -Value: true -Owners: console-setup - -Name: console-setup/use_system_font -Template: console-setup/use_system_font -Owners: console-setup - -Name: dash/sh -Template: dash/sh -Value: true -Owners: dash -Flags: seen - -Name: debconf-apt-progress/info -Template: debconf-apt-progress/info -Owners: debconf - -Name: debconf-apt-progress/media-change -Template: debconf-apt-progress/media-change -Owners: debconf - -Name: debconf-apt-progress/preparing -Template: debconf-apt-progress/preparing -Owners: debconf - -Name: debconf-apt-progress/title -Template: debconf-apt-progress/title -Owners: debconf - -Name: debconf/frontend -Template: debconf/frontend -Value: Dialog -Owners: debconf - -Name: debconf/priority -Template: debconf/priority -Value: high -Owners: debconf - -Name: debian-installer/console-setup-udeb/title -Template: debian-installer/console-setup-udeb/title -Owners: keyboard-configuration - -Name: debian-installer/country -Template: debian-installer/country -Value: US -Owners: d-i - -Name: debian-installer/language -Template: debian-installer/language -Value: en -Owners: d-i - -Name: dictionaries-common/default-ispell -Template: dictionaries-common/default-ispell -Value: american (American English) -Owners: dictionaries-common -Flags: seen -Variables: - choices = american (American English), british (British English) - echoices = american (American English), british (British English) - -Name: dictionaries-common/default-wordlist -Template: dictionaries-common/default-wordlist -Value: american (American English) -Owners: dictionaries-common -Flags: seen -Variables: - choices = american (American English) - echoices = american (American English) - -Name: dictionaries-common/invalid_debconf_value -Template: dictionaries-common/invalid_debconf_value -Owners: dictionaries-common - -Name: dictionaries-common/ispell-autobuildhash-message -Template: dictionaries-common/ispell-autobuildhash-message -Owners: dictionaries-common - -Name: dictionaries-common/move_old_usr_dict -Template: dictionaries-common/move_old_usr_dict -Owners: dictionaries-common - -Name: dictionaries-common/old_wordlist_link -Template: dictionaries-common/old_wordlist_link -Owners: dictionaries-common - -Name: dictionaries-common/remove_old_usr_dict_link -Template: dictionaries-common/remove_old_usr_dict_link -Value: false -Owners: dictionaries-common - -Name: dictionaries-common/selecting_ispell_wordlist_default -Template: dictionaries-common/selecting_ispell_wordlist_default -Owners: dictionaries-common - -Name: discover/install_hw_packages -Template: discover/install_hw_packages -Owners: discover - -Name: exim4-base/drec -Template: exim4-base/drec -Owners: exim4-base - -Name: exim4-daemon-light/drec -Template: exim4-daemon-light/drec -Owners: exim4-daemon-light - -Name: exim4/dc_eximconfig_configtype -Template: exim4/dc_eximconfig_configtype -Value: local delivery only; not on a network -Owners: exim4-config - -Name: exim4/dc_local_interfaces -Template: exim4/dc_local_interfaces -Value: 127.0.0.1 ; ::1 -Owners: exim4-config - -Name: exim4/dc_localdelivery -Template: exim4/dc_localdelivery -Value: mbox format in /var/mail/ -Owners: exim4-config - -Name: exim4/dc_minimaldns -Template: exim4/dc_minimaldns -Value: false -Owners: exim4-config - -Name: exim4/dc_other_hostnames -Template: exim4/dc_other_hostnames -Value: ahha.citrite.net -Owners: exim4-config -Flags: mailname -Variables: - fqdn = ahha.citrite.net - -Name: exim4/dc_postmaster -Template: exim4/dc_postmaster -Value: vagrant -Owners: exim4-config - -Name: exim4/dc_readhost -Template: exim4/dc_readhost -Owners: exim4-config - -Name: exim4/dc_relay_domains -Template: exim4/dc_relay_domains -Owners: exim4-config - -Name: exim4/dc_relay_nets -Template: exim4/dc_relay_nets -Owners: exim4-config - -Name: exim4/dc_smarthost -Template: exim4/dc_smarthost -Owners: exim4-config - -Name: exim4/drec -Template: exim4/drec -Owners: exim4 - -Name: exim4/exim4-config-title -Template: exim4/exim4-config-title -Owners: exim4-config - -Name: exim4/hide_mailname -Template: exim4/hide_mailname -Owners: exim4-config - -Name: exim4/mailname -Template: exim4/mailname -Value: ahha.citrite.net -Owners: exim4-config - -Name: exim4/no_config -Template: exim4/no_config -Owners: exim4-config - -Name: exim4/purge_spool -Template: exim4/purge_spool -Owners: exim4-base - -Name: exim4/use_split_config -Template: exim4/use_split_config -Value: false -Owners: exim4-config - -Name: glibc/disable-screensaver -Template: glibc/disable-screensaver -Owners: libc6, libc6:i386 - -Name: glibc/restart-failed -Template: glibc/restart-failed -Owners: libc6, libc6:i386 - -Name: glibc/restart-services -Template: glibc/restart-services -Owners: libc6, libc6:i386 - -Name: glibc/upgrade -Template: glibc/upgrade -Owners: libc6, libc6:i386 - -Name: grub-pc/chainload_from_menu.lst -Template: grub-pc/chainload_from_menu.lst -Owners: grub-pc - -Name: grub-pc/disk_description -Template: grub-pc/disk_description -Owners: grub-pc -Variables: - DEVICE = /dev/mapper/ahha-root - MODEL = ahha-root - SIZE = 1753 - -Name: grub-pc/install_devices -Template: grub-pc/install_devices -Value: /dev/disk/by-id/ata-VBOX_HARDDISK_VBe38481e3-55a686f1 -Owners: grub-pc -Flags: seen -Variables: - CHOICES = /dev/sda (2147 MB; VBOX_HARDDISK), - /dev/sda1 (254 MB; /boot), /dev/mapper/ahha-root (1753 MB; ahha-root) - RAW_CHOICES = /dev/disk/by-id/ata-VBOX_HARDDISK_VBe38481e3-55a686f1, /dev/disk/by-id/ata-VBOX_HARDDISK_VBe38481e3-55a686f1-part1, /dev/mapper/ahha-root - -Name: grub-pc/install_devices_disks_changed -Template: grub-pc/install_devices_disks_changed -Owners: grub-pc - -Name: grub-pc/install_devices_empty -Template: grub-pc/install_devices_empty -Value: false -Owners: grub-pc - -Name: grub-pc/install_devices_failed -Template: grub-pc/install_devices_failed -Owners: grub-pc - -Name: grub-pc/install_devices_failed_upgrade -Template: grub-pc/install_devices_failed_upgrade -Owners: grub-pc - -Name: grub-pc/kopt_extracted -Template: grub-pc/kopt_extracted -Owners: grub-pc - -Name: grub-pc/mixed_legacy_and_grub2 -Template: grub-pc/mixed_legacy_and_grub2 -Owners: grub-pc - -Name: grub-pc/partition_description -Template: grub-pc/partition_description -Owners: grub-pc -Variables: - DEVICE = /dev/sda1 - PATH = /boot - SIZE = 254 - -Name: grub-pc/postrm_purge_boot_grub -Template: grub-pc/postrm_purge_boot_grub -Owners: grub-pc - -Name: grub2/device_map_regenerated -Template: grub2/device_map_regenerated -Owners: grub-pc - -Name: grub2/kfreebsd_cmdline -Template: grub2/kfreebsd_cmdline -Owners: grub-pc - -Name: grub2/kfreebsd_cmdline_default -Template: grub2/kfreebsd_cmdline_default -Owners: grub-pc - -Name: grub2/linux_cmdline -Template: grub2/linux_cmdline -Value: debian-installer=en_US -Owners: grub-pc -Flags: seen - -Name: grub2/linux_cmdline_default -Template: grub2/linux_cmdline_default -Value: quiet -Owners: grub-pc -Flags: seen - -Name: iamerican/languages -Template: iamerican/languages -Owners: iamerican - -Name: ibritish/languages -Template: ibritish/languages -Owners: ibritish - -Name: keyboard-configuration/altgr -Template: keyboard-configuration/altgr -Value: The default for the keyboard layout -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/compose -Template: keyboard-configuration/compose -Value: No compose key -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/ctrl_alt_bksp -Template: keyboard-configuration/ctrl_alt_bksp -Value: false -Owners: d-i, keyboard-configuration - -Name: keyboard-configuration/layout -Template: keyboard-configuration/layout -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/layoutcode -Template: keyboard-configuration/layoutcode -Value: us -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/model -Template: keyboard-configuration/model -Value: Generic 105-key (Intl) PC -Owners: d-i, keyboard-configuration -Flags: seen -Variables: - CHOICES = A4Tech KB-21, A4Tech KBS-8, A4Tech Wireless Desktop RFKB-23, Acer AirKey V, Acer C300, Acer Ferrari 4000, Acer Laptop, Advance Scorpius KI, Amiga, Apple, Apple Aluminium Keyboard (ANSI), Apple Aluminium Keyboard (ISO), Apple Aluminium Keyboard (JIS), Apple Laptop, Asus Laptop, Atari TT, Azona RF2300 wireless Internet Keyboard, BenQ X-Touch, BenQ X-Touch 730, BenQ X-Touch 800, Brother Internet Keyboard, BTC 5090, BTC 5113RF Multimedia, BTC 5126T, BTC 6301URF, BTC 9000, BTC 9000A, BTC 9001AH, BTC 9019U, BTC 9116U Mini Wireless Internet and Gaming, Cherry Blue Line CyBo@rd, Cherry Blue Line CyBo@rd (alternate option), Cherry B.UNLIMITED, Cherry CyBo@rd USB-Hub, Cherry CyMotion Expert, Cherry CyMotion Master Linux, Cherry CyMotion Master XPress, Chicony Internet Keyboard, Chicony KB-9885, Chicony KU-0108, Chicony KU-0420, Classmate PC, Compaq Easy Access Keyboard, Compaq Internet Keyboard (13 keys), Compaq Internet Keyboard (18 keys), Compaq Internet Keyboard (7 keys), Compaq iPaq Keyboard, Creative Desktop Wireless 7000, Dell, Dell 101-key PC, Dell Laptop/notebook Inspiron 6xxx/8xxx, Dell Laptop/notebook Precision M series, Dell Latitude series laptop, Dell Precision M65, Dell SK-8125, Dell SK-8135, Dell USB Multimedia Keyboard, Dexxa Wireless Desktop Keyboard, Diamond 9801 / 9802 series, DTK2000, Ennyah DKB-1008, Everex STEPnote, FL90, Fujitsu-Siemens Computers AMILO laptop, Generic 101-key PC, Generic 102-key (Intl) PC, Generic 104-key PC, Generic 105-key (Intl) PC, Genius Comfy KB-12e, Genius Comfy KB-16M / Genius MM Keyboard KWD-910, Genius Comfy KB-21e-Scroll, Genius KB-19e NB, Genius KKB-2050HS, Gyration, Happy Hacking Keyboard, Happy Hacking Keyboard for Mac, Hewlett-Packard Internet Keyboard, Hewlett-Packard Mini 110 Notebook, Hewlett-Packard nx9020, Hewlett-Packard Omnibook 500 FA, Hewlett-Packard Omnibook 5xx, Hewlett-Packard Omnibook 6000/6100, Hewlett-Packard Omnibook XE3 GC, Hewlett-Packard Omnibook XE3 GF, Hewlett-Packard Omnibook XT1000, Hewlett-Packard Pavilion dv5, Hewlett-Packard Pavilion ZT11xx, Hewlett-Packard SK-250x Multimedia Keyboard, Honeywell Euroboard, HTC Dream, Htc Dream phone, IBM Rapid Access, IBM Rapid Access II, IBM Space Saver, IBM ThinkPad 560Z/600/600E/A22E, IBM ThinkPad R60/T60/R61/T61, IBM ThinkPad Z60m/Z60t/Z61m/Z61t, Keytronic FlexPro, Kinesis, Laptop/notebook Compaq (eg. Armada) Laptop Keyboard, Laptop/notebook Compaq (eg. Presario) Internet Keyboard, Laptop/notebook eMachines m68xx, Logitech Access Keyboard, Logitech Cordless Desktop, Logitech Cordless Desktop (alternate option), Logitech Cordless Desktop EX110, Logitech Cordless Desktop iTouch, Logitech Cordless Desktop LX-300, Logitech Cordless Desktop Navigator, Logitech Cordless Desktop Optical, Logitech Cordless Desktop Pro (alternate option 2), Logitech Cordless Freedom/Desktop Navigator, Logitech diNovo Edge Keyboard, Logitech diNovo Keyboard, Logitech G15 extra keys via G15daemon, Logitech Generic Keyboard, Logitech Internet 350 Keyboard, Logitech Internet Keyboard, Logitech Internet Navigator Keyboard, Logitech iTouch, Logitech iTouch Cordless Keyboard (model Y-RB6), Logitech iTouch Internet Navigator Keyboard SE, Logitech iTouch Internet Navigator Keyboard SE (USB), Logitech Media Elite Keyboard, Logitech Ultra-X Cordless Media Desktop Keyboard, Logitech Ultra-X Keyboard, MacBook/MacBook Pro, MacBook/MacBook Pro (Intl), Macintosh, Macintosh Old, Memorex MX1998, Memorex MX2500 EZ-Access Keyboard, Memorex MX2750, Microsoft Comfort Curve Keyboard 2000, Microsoft Internet Keyboard, Microsoft Internet Keyboard Pro\, Swedish, Microsoft Natural, Microsoft Natural Keyboard Elite, Microsoft Natural Keyboard Pro OEM, Microsoft Natural Keyboard Pro / Microsoft Internet Keyboard Pro, Microsoft Natural Keyboard Pro USB / Microsoft Internet Keyboard Pro, Microsoft Natural Wireless Ergonomic Keyboard 4000, Microsoft Natural Wireless Ergonomic Keyboard 7000, Microsoft Office Keyboard, Microsoft Wireless Multimedia Keyboard 1.0A, Northgate OmniKey 101, OLPC, Ortek MCK-800 MM/Internet keyboard, PC-98xx Series, Propeller Voyager (KTEZ-1000), QTronix Scorpius 98N+, Samsung SDM 4500P, Samsung SDM 4510P, Sanwa Supply SKB-KG3, SILVERCREST Multimedia Wireless Keyboard, SK-1300, SK-2500, SK-6200, SK-7100, Sun Type 4, Sun Type 5, Sun Type 5/6, Super Power Multimedia Keyboard, SVEN Ergonomic 2500, SVEN Slim 303, Symplon PaceBook (tablet PC), Targa Visionary 811, Toshiba Satellite S3000, Trust Direct Access Keyboard, Trust Slimline, Trust Wireless Keyboard Classic, TypeMatrix EZ-Reach 2020, TypeMatrix EZ-Reach 2030 PS2, TypeMatrix EZ-Reach 2030 USB, TypeMatrix EZ-Reach 2030 USB (102/105:EU mode), TypeMatrix EZ-Reach 2030 USB (106:JP mode), Unitek KB-1925, ViewSonic KU-306 Internet Keyboard, Winbook Model XP5, Yahoo! Internet Keyboard - -Name: keyboard-configuration/modelcode -Template: keyboard-configuration/modelcode -Value: pc105 -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/optionscode -Template: keyboard-configuration/optionscode -Value: -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/other -Template: keyboard-configuration/other -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/store_defaults_in_debconf_db -Template: keyboard-configuration/store_defaults_in_debconf_db -Value: true -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/switch -Template: keyboard-configuration/switch -Value: No temporary switch -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/toggle -Template: keyboard-configuration/toggle -Value: No toggling -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/unsupported_config_layout -Template: keyboard-configuration/unsupported_config_layout -Value: true -Owners: d-i, keyboard-configuration - -Name: keyboard-configuration/unsupported_config_options -Template: keyboard-configuration/unsupported_config_options -Value: true -Owners: d-i, keyboard-configuration - -Name: keyboard-configuration/unsupported_layout -Template: keyboard-configuration/unsupported_layout -Value: true -Owners: d-i, keyboard-configuration - -Name: keyboard-configuration/unsupported_options -Template: keyboard-configuration/unsupported_options -Value: true -Owners: d-i, keyboard-configuration - -Name: keyboard-configuration/variant -Template: keyboard-configuration/variant -Value: English (US) -Owners: d-i, keyboard-configuration -Flags: seen -Variables: - CHOICES = English (US), English (US) - Cherokee, English (US) - English (classic Dvorak), English (US) - English (Colemak), English (US) - English (Dvorak), English (US) - English (Dvorak alternative international no dead keys), English (US) - English (Dvorak international with dead keys), English (US) - English (international AltGr dead keys), English (US) - English (layout toggle on multiply/divide key), English (US) - English (left handed Dvorak), English (US) - English (Macintosh), English (US) - English (programmer Dvorak), English (US) - English (right handed Dvorak), English (US) - English (US\, alternative international), English (US) - English (US\, international with dead keys), English (US) - English (US\, with euro on 5), English (US) - Russian (US\, phonetic), English (US) - Serbo-Croatian (US), Other - -Name: keyboard-configuration/variantcode -Template: keyboard-configuration/variantcode -Value: -Owners: d-i, keyboard-configuration -Flags: seen - -Name: keyboard-configuration/xkb-keymap -Template: keyboard-configuration/xkb-keymap -Value: us -Owners: d-i, keyboard-configuration -Flags: seen - -Name: libpam-modules/disable-screensaver -Template: libpam-modules/disable-screensaver -Owners: libpam-modules - -Name: libpam-runtime/conflicts -Template: libpam-runtime/conflicts -Owners: libpam-runtime - -Name: libpam-runtime/no_profiles_chosen -Template: libpam-runtime/no_profiles_chosen -Owners: libpam-runtime - -Name: libpam-runtime/override -Template: libpam-runtime/override -Value: false -Owners: libpam-runtime - -Name: libpam-runtime/profiles -Template: libpam-runtime/profiles -Value: unix -Owners: libpam-runtime -Variables: - profile_names = unix - profiles = Unix authentication - -Name: libpam-runtime/title -Template: libpam-runtime/title -Owners: libpam-runtime - -Name: libpam0g/restart-failed -Template: libpam0g/restart-failed -Owners: libpam0g:i386 - -Name: libpam0g/restart-services -Template: libpam0g/restart-services -Owners: libpam0g:i386 - -Name: libpam0g/xdm-needs-restart -Template: libpam0g/xdm-needs-restart -Owners: libpam0g:i386 - -Name: libraries/restart-without-asking -Template: libraries/restart-without-asking -Owners: libc6, libc6:i386, libpam0g:i386 - -Name: libssl1.0.0/restart-failed -Template: libssl1.0.0/restart-failed -Owners: libssl1.0.0:i386 - -Name: libssl1.0.0/restart-services -Template: libssl1.0.0/restart-services -Owners: libssl1.0.0:i386 - -Name: linux-base/disk-id-convert-auto -Template: linux-base/disk-id-convert-auto -Owners: linux-base - -Name: linux-base/disk-id-convert-plan -Template: linux-base/disk-id-convert-plan -Owners: linux-base - -Name: linux-base/disk-id-convert-plan-no-relabel -Template: linux-base/disk-id-convert-plan-no-relabel -Owners: linux-base - -Name: linux-base/disk-id-manual -Template: linux-base/disk-id-manual -Owners: linux-base - -Name: linux-base/disk-id-manual-boot-loader -Template: linux-base/disk-id-manual-boot-loader -Owners: linux-base - -Name: linux-base/disk-id-update-failed -Template: linux-base/disk-id-update-failed -Owners: linux-base - -Name: linux-base/do-bootloader-default-changed -Template: linux-base/do-bootloader-default-changed -Owners: linux-base - -Name: linux-image-3.2.0-4-686-pae/postinst/depmod-error-initrd-3.2.0-4-686-pae -Template: linux-image-3.2.0-4-686-pae/postinst/depmod-error-initrd-3.2.0-4-686-pae -Owners: linux-image-3.2.0-4-686-pae - -Name: linux-image-3.2.0-4-686-pae/postinst/ignoring-ramdisk -Template: linux-image-3.2.0-4-686-pae/postinst/ignoring-ramdisk -Owners: linux-image-3.2.0-4-686-pae - -Name: linux-image-3.2.0-4-686-pae/postinst/missing-firmware-3.2.0-4-686-pae -Template: linux-image-3.2.0-4-686-pae/postinst/missing-firmware-3.2.0-4-686-pae -Owners: linux-image-3.2.0-4-686-pae - -Name: linux-image-3.2.0-4-686-pae/prerm/removing-running-kernel-3.2.0-4-686-pae -Template: linux-image-3.2.0-4-686-pae/prerm/removing-running-kernel-3.2.0-4-686-pae -Owners: linux-image-3.2.0-4-686-pae - -Name: locales/default_environment_locale -Template: locales/default_environment_locale -Owners: locales - -Name: locales/locales_to_be_generated -Template: locales/locales_to_be_generated -Value: -Owners: locales -Variables: - locales = aa_DJ ISO-8859-1, aa_DJ.UTF-8 UTF-8, aa_ER UTF-8, aa_ER@saaho UTF-8, aa_ET UTF-8, af_ZA ISO-8859-1, af_ZA.UTF-8 UTF-8, am_ET UTF-8, an_ES ISO-8859-15, an_ES.UTF-8 UTF-8, ar_AE ISO-8859-6, ar_AE.UTF-8 UTF-8, ar_BH ISO-8859-6, ar_BH.UTF-8 UTF-8, ar_DZ ISO-8859-6, ar_DZ.UTF-8 UTF-8, ar_EG ISO-8859-6, ar_EG.UTF-8 UTF-8, ar_IN UTF-8, ar_IQ ISO-8859-6, ar_IQ.UTF-8 UTF-8, ar_JO ISO-8859-6, ar_JO.UTF-8 UTF-8, ar_KW ISO-8859-6, ar_KW.UTF-8 UTF-8, ar_LB ISO-8859-6, ar_LB.UTF-8 UTF-8, ar_LY ISO-8859-6, ar_LY.UTF-8 UTF-8, ar_MA ISO-8859-6, ar_MA.UTF-8 UTF-8, ar_OM ISO-8859-6, ar_OM.UTF-8 UTF-8, ar_QA ISO-8859-6, ar_QA.UTF-8 UTF-8, ar_SA ISO-8859-6, ar_SA.UTF-8 UTF-8, ar_SD ISO-8859-6, ar_SD.UTF-8 UTF-8, ar_SY ISO-8859-6, ar_SY.UTF-8 UTF-8, ar_TN ISO-8859-6, ar_TN.UTF-8 UTF-8, ar_YE ISO-8859-6, ar_YE.UTF-8 UTF-8, as_IN.UTF-8 UTF-8, ast_ES ISO-8859-15, ast_ES.UTF-8 UTF-8, az_AZ.UTF-8 UTF-8, be_BY CP1251, be_BY.UTF-8 UTF-8, be_BY@latin UTF-8, bem_ZM UTF-8, ber_DZ UTF-8, ber_MA UTF-8, bg_BG CP1251, bg_BG.UTF-8 UTF-8, bn_BD UTF-8, bn_IN UTF-8, bo_CN UTF-8, bo_IN UTF-8, br_FR ISO-8859-1, br_FR.UTF-8 UTF-8, br_FR@euro ISO-8859-15, bs_BA ISO-8859-2, bs_BA.UTF-8 UTF-8, byn_ER UTF-8, ca_AD ISO-8859-15, ca_AD.UTF-8 UTF-8, ca_ES ISO-8859-1, ca_ES.UTF-8 UTF-8, ca_ES.UTF-8@valencia UTF-8, ca_ES@euro ISO-8859-15, ca_ES@valencia ISO-8859-15, ca_FR ISO-8859-15, ca_FR.UTF-8 UTF-8, ca_IT ISO-8859-15, ca_IT.UTF-8 UTF-8, crh_UA UTF-8, cs_CZ ISO-8859-2, cs_CZ.UTF-8 UTF-8, csb_PL UTF-8, cv_RU UTF-8, cy_GB ISO-8859-14, cy_GB.UTF-8 UTF-8, da_DK ISO-8859-1, da_DK.UTF-8 UTF-8, de_AT ISO-8859-1, de_AT.UTF-8 UTF-8, de_AT@euro ISO-8859-15, de_BE ISO-8859-1, de_BE.UTF-8 UTF-8, de_BE@euro ISO-8859-15, de_CH ISO-8859-1, de_CH.UTF-8 UTF-8, de_DE ISO-8859-1, de_DE.UTF-8 UTF-8, de_DE@euro ISO-8859-15, de_LI.UTF-8 UTF-8, de_LU ISO-8859-1, de_LU.UTF-8 UTF-8, de_LU@euro ISO-8859-15, dv_MV UTF-8, dz_BT UTF-8, el_CY ISO-8859-7, el_CY.UTF-8 UTF-8, el_GR ISO-8859-7, el_GR.UTF-8 UTF-8, en_AG UTF-8, en_AU ISO-8859-1, en_AU.UTF-8 UTF-8, en_BW ISO-8859-1, en_BW.UTF-8 UTF-8, en_CA ISO-8859-1, en_CA.UTF-8 UTF-8, en_DK ISO-8859-1, en_DK.ISO-8859-15 ISO-8859-15, en_DK.UTF-8 UTF-8, en_GB ISO-8859-1, en_GB.ISO-8859-15 ISO-8859-15, en_GB.UTF-8 UTF-8, en_HK ISO-8859-1, en_HK.UTF-8 UTF-8, en_IE ISO-8859-1, en_IE.UTF-8 UTF-8, en_IE@euro ISO-8859-15, en_IN UTF-8, en_NG UTF-8, en_NZ ISO-8859-1, en_NZ.UTF-8 UTF-8, en_PH ISO-8859-1, en_PH.UTF-8 UTF-8, en_SG ISO-8859-1, en_SG.UTF-8 UTF-8, en_US ISO-8859-1, en_US.ISO-8859-15 ISO-8859-15, en_US.UTF-8 UTF-8, en_ZA ISO-8859-1, en_ZA.UTF-8 UTF-8, en_ZM UTF-8, en_ZW ISO-8859-1, en_ZW.UTF-8 UTF-8, eo ISO-8859-3, eo.UTF-8 UTF-8, es_AR ISO-8859-1, es_AR.UTF-8 UTF-8, es_BO ISO-8859-1, es_BO.UTF-8 UTF-8, es_CL ISO-8859-1, es_CL.UTF-8 UTF-8, es_CO ISO-8859-1, es_CO.UTF-8 UTF-8, es_CR ISO-8859-1, es_CR.UTF-8 UTF-8, es_DO ISO-8859-1, es_DO.UTF-8 UTF-8, es_EC ISO-8859-1, es_EC.UTF-8 UTF-8, es_ES ISO-8859-1, es_ES.UTF-8 UTF-8, es_ES@euro ISO-8859-15, es_GT ISO-8859-1, es_GT.UTF-8 UTF-8, es_HN ISO-8859-1, es_HN.UTF-8 UTF-8, es_MX ISO-8859-1, es_MX.UTF-8 UTF-8, es_NI ISO-8859-1, es_NI.UTF-8 UTF-8, es_PA ISO-8859-1, es_PA.UTF-8 UTF-8, es_PE ISO-8859-1, es_PE.UTF-8 UTF-8, es_PR ISO-8859-1, es_PR.UTF-8 UTF-8, es_PY ISO-8859-1, es_PY.UTF-8 UTF-8, es_SV ISO-8859-1, es_SV.UTF-8 UTF-8, es_US ISO-8859-1, es_US.UTF-8 UTF-8, es_UY ISO-8859-1, es_UY.UTF-8 UTF-8, es_VE ISO-8859-1, es_VE.UTF-8 UTF-8, et_EE ISO-8859-1, et_EE.ISO-8859-15 ISO-8859-15, et_EE.UTF-8 UTF-8, eu_ES ISO-8859-1, eu_ES.UTF-8 UTF-8, eu_ES@euro ISO-8859-15, eu_FR ISO-8859-1, eu_FR.UTF-8 UTF-8, eu_FR@euro ISO-8859-15, fa_IR UTF-8, ff_SN UTF-8, fi_FI ISO-8859-1, fi_FI.UTF-8 UTF-8, fi_FI@euro ISO-8859-15, fil_PH UTF-8, fo_FO ISO-8859-1, fo_FO.UTF-8 UTF-8, fr_BE ISO-8859-1, fr_BE.UTF-8 UTF-8, fr_BE@euro ISO-8859-15, fr_CA ISO-8859-1, fr_CA.UTF-8 UTF-8, fr_CH ISO-8859-1, fr_CH.UTF-8 UTF-8, fr_FR ISO-8859-1, fr_FR.UTF-8 UTF-8, fr_FR@euro ISO-8859-15, fr_LU ISO-8859-1, fr_LU.UTF-8 UTF-8, fr_LU@euro ISO-8859-15, fur_IT UTF-8, fy_DE UTF-8, fy_NL UTF-8, ga_IE ISO-8859-1, ga_IE.UTF-8 UTF-8, ga_IE@euro ISO-8859-15, gd_GB ISO-8859-15, gd_GB.UTF-8 UTF-8, gez_ER UTF-8, gez_ER@abegede UTF-8, gez_ET UTF-8, gez_ET@abegede UTF-8, gl_ES ISO-8859-1, gl_ES.UTF-8 UTF-8, gl_ES@euro ISO-8859-15, gu_IN UTF-8, gv_GB ISO-8859-1, gv_GB.UTF-8 UTF-8, ha_NG UTF-8, he_IL ISO-8859-8, he_IL.UTF-8 UTF-8, hi_IN UTF-8, hne_IN UTF-8, hr_HR ISO-8859-2, hr_HR.UTF-8 UTF-8, hsb_DE ISO-8859-2, hsb_DE.UTF-8 UTF-8, ht_HT UTF-8, hu_HU ISO-8859-2, hu_HU.UTF-8 UTF-8, hy_AM UTF-8, hy_AM.ARMSCII-8 ARMSCII-8, ia UTF-8, id_ID ISO-8859-1, id_ID.UTF-8 UTF-8, ig_NG UTF-8, ik_CA UTF-8, is_IS ISO-8859-1, is_IS.UTF-8 UTF-8, it_CH ISO-8859-1, it_CH.UTF-8 UTF-8, it_IT ISO-8859-1, it_IT.UTF-8 UTF-8, it_IT@euro ISO-8859-15, iu_CA UTF-8, iw_IL ISO-8859-8, iw_IL.UTF-8 UTF-8, ja_JP.EUC-JP EUC-JP, ja_JP.UTF-8 UTF-8, ka_GE GEORGIAN-PS, ka_GE.UTF-8 UTF-8, kk_KZ PT154, kk_KZ RK1048, kk_KZ.UTF-8 UTF-8, kl_GL ISO-8859-1, kl_GL.UTF-8 UTF-8, km_KH UTF-8, kn_IN UTF-8, ko_KR.EUC-KR EUC-KR, ko_KR.UTF-8 UTF-8, kok_IN UTF-8, ks_IN UTF-8, ks_IN@devanagari UTF-8, ku_TR ISO-8859-9, ku_TR.UTF-8 UTF-8, kw_GB ISO-8859-1, kw_GB.UTF-8 UTF-8, ky_KG UTF-8, lg_UG ISO-8859-10, lg_UG.UTF-8 UTF-8, li_BE UTF-8, li_NL UTF-8, lo_LA UTF-8, lt_LT ISO-8859-13, lt_LT.UTF-8 UTF-8, lv_LV ISO-8859-13, lv_LV.UTF-8 UTF-8, mai_IN UTF-8, mg_MG ISO-8859-15, mg_MG.UTF-8 UTF-8, mi_NZ ISO-8859-13, mi_NZ.UTF-8 UTF-8, mk_MK ISO-8859-5, mk_MK.UTF-8 UTF-8, ml_IN UTF-8, mn_MN UTF-8, mr_IN UTF-8, ms_MY ISO-8859-1, ms_MY.UTF-8 UTF-8, mt_MT ISO-8859-3, mt_MT.UTF-8 UTF-8, my_MM UTF-8, nan_TW@latin UTF-8, nb_NO ISO-8859-1, nb_NO.UTF-8 UTF-8, nds_DE UTF-8, nds_NL UTF-8, ne_NP UTF-8, nl_AW UTF-8, nl_BE ISO-8859-1, nl_BE.UTF-8 UTF-8, nl_BE@euro ISO-8859-15, nl_NL ISO-8859-1, nl_NL.UTF-8 UTF-8, nl_NL@euro ISO-8859-15, nn_NO ISO-8859-1, nn_NO.UTF-8 UTF-8, nr_ZA UTF-8, nso_ZA UTF-8, oc_FR ISO-8859-1, oc_FR.UTF-8 UTF-8, om_ET UTF-8, om_KE ISO-8859-1, om_KE.UTF-8 UTF-8, or_IN UTF-8, os_RU UTF-8, pa_IN UTF-8, pa_PK UTF-8, pap_AN UTF-8, pl_PL ISO-8859-2, pl_PL.UTF-8 UTF-8, ps_AF UTF-8, pt_BR ISO-8859-1, pt_BR.UTF-8 UTF-8, pt_PT ISO-8859-1, pt_PT.UTF-8 UTF-8, pt_PT@euro ISO-8859-15, ro_RO ISO-8859-2, ro_RO.UTF-8 UTF-8, ru_RU ISO-8859-5, ru_RU.CP1251 CP1251, ru_RU.KOI8-R KOI8-R, ru_RU.UTF-8 UTF-8, ru_UA KOI8-U, ru_UA.UTF-8 UTF-8, rw_RW UTF-8, sa_IN UTF-8, sc_IT UTF-8, sd_IN UTF-8, sd_IN@devanagari UTF-8, se_NO UTF-8, shs_CA UTF-8, si_LK UTF-8, sid_ET UTF-8, sk_SK ISO-8859-2, sk_SK.UTF-8 UTF-8, sl_SI ISO-8859-2, sl_SI.UTF-8 UTF-8, so_DJ ISO-8859-1, so_DJ.UTF-8 UTF-8, so_ET UTF-8, so_KE ISO-8859-1, so_KE.UTF-8 UTF-8, so_SO ISO-8859-1, so_SO.UTF-8 UTF-8, sq_AL ISO-8859-1, sq_AL.UTF-8 UTF-8, sq_MK UTF-8, sr_ME UTF-8, sr_RS UTF-8, sr_RS@latin UTF-8, ss_ZA UTF-8, st_ZA ISO-8859-1, st_ZA.UTF-8 UTF-8, sv_FI ISO-8859-1, sv_FI.UTF-8 UTF-8, sv_FI@euro ISO-8859-15, sv_SE ISO-8859-1, sv_SE.ISO-8859-15 ISO-8859-15, sv_SE.UTF-8 UTF-8, sw_KE UTF-8, sw_TZ UTF-8, ta_IN UTF-8, te_IN UTF-8, tg_TJ KOI8-T, tg_TJ.UTF-8 UTF-8, th_TH TIS-620, th_TH.UTF-8 UTF-8, ti_ER UTF-8, ti_ET UTF-8, tig_ER UTF-8, tk_TM UTF-8, tl_PH ISO-8859-1, tl_PH.UTF-8 UTF-8, tn_ZA UTF-8, tr_CY ISO-8859-9, tr_CY.UTF-8 UTF-8, tr_TR ISO-8859-9, tr_TR.UTF-8 UTF-8, ts_ZA UTF-8, tt_RU.UTF-8 UTF-8, tt_RU.UTF-8@iqtelif UTF-8, ug_CN UTF-8, uk_UA KOI8-U, uk_UA.UTF-8 UTF-8, ur_PK UTF-8, uz_UZ ISO-8859-1, uz_UZ.UTF-8 UTF-8, uz_UZ@cyrillic UTF-8, ve_ZA UTF-8, vi_VN UTF-8, vi_VN.TCVN TCVN5712-1, wa_BE ISO-8859-1, wa_BE.UTF-8 UTF-8, wa_BE@euro ISO-8859-15, wo_SN UTF-8, xh_ZA ISO-8859-1, xh_ZA.UTF-8 UTF-8, yi_US CP1255, yi_US.UTF-8 UTF-8, yo_NG UTF-8, zh_CN GB2312, zh_CN.GB18030 GB18030, zh_CN.GBK GBK, zh_CN.UTF-8 UTF-8, zh_HK BIG5-HKSCS, zh_HK.UTF-8 UTF-8, zh_SG GB2312, zh_SG.GBK GBK, zh_SG.UTF-8 UTF-8, zh_TW BIG5, zh_TW.EUC-TW EUC-TW, zh_TW.UTF-8 UTF-8, zu_ZA ISO-8859-1, zu_ZA.UTF-8 UTF-8 - -Name: make-ssl-cert/altname -Template: make-ssl-cert/altname -Owners: ssl-cert - -Name: make-ssl-cert/hostname -Template: make-ssl-cert/hostname -Owners: ssl-cert - -Name: make-ssl-cert/title -Template: make-ssl-cert/title -Owners: ssl-cert - -Name: make-ssl-cert/vulnerable_prng -Template: make-ssl-cert/vulnerable_prng -Owners: ssl-cert - -Name: man-db/auto-update -Template: man-db/auto-update -Owners: man-db - -Name: man-db/install-setuid -Template: man-db/install-setuid -Value: false -Owners: man-db - -Name: openswan/existing_x509_certificate_filename -Template: openswan/existing_x509_certificate_filename -Owners: openswan - -Name: openswan/existing_x509_key_filename -Template: openswan/existing_x509_key_filename -Owners: openswan - -Name: openswan/existing_x509_rootca_filename -Template: openswan/existing_x509_rootca_filename -Owners: openswan - -Name: openswan/how_to_get_x509_certificate -Template: openswan/how_to_get_x509_certificate -Owners: openswan - -Name: openswan/install_x509_certificate -Template: openswan/install_x509_certificate -Value: false -Owners: openswan -Flags: seen - -Name: openswan/no-oe_include_file -Template: openswan/no-oe_include_file -Owners: openswan - -Name: openswan/restart -Template: openswan/restart -Value: true -Owners: openswan - -Name: openswan/rsa_key_length -Template: openswan/rsa_key_length -Owners: openswan - -Name: openswan/runlevel_changes -Template: openswan/runlevel_changes -Owners: openswan - -Name: openswan/x509_common_name -Template: openswan/x509_common_name -Owners: openswan - -Name: openswan/x509_country_code -Template: openswan/x509_country_code -Owners: openswan - -Name: openswan/x509_email_address -Template: openswan/x509_email_address -Owners: openswan - -Name: openswan/x509_locality_name -Template: openswan/x509_locality_name -Owners: openswan - -Name: openswan/x509_organization_name -Template: openswan/x509_organization_name -Owners: openswan - -Name: openswan/x509_organizational_unit -Template: openswan/x509_organizational_unit -Owners: openswan - -Name: openswan/x509_self_signed -Template: openswan/x509_self_signed -Owners: openswan - -Name: openswan/x509_state_name -Template: openswan/x509_state_name -Owners: openswan - -Name: passwd/username -Template: passwd/username -Value: vagrant -Owners: user-setup-udeb -Flags: seen - -Name: shared/packages-ispell -Template: shared/packages-ispell -Owners: iamerican, ibritish - -Name: shared/packages-wordlist -Template: shared/packages-wordlist -Owners: wamerican - -Name: ssh/disable_cr_auth -Template: ssh/disable_cr_auth -Owners: openssh-server - -Name: ssh/encrypted_host_key_but_no_keygen -Template: ssh/encrypted_host_key_but_no_keygen -Owners: openssh-server - -Name: ssh/use_old_init_script -Template: ssh/use_old_init_script -Value: true -Owners: openssh-server -Flags: seen - -Name: ssh/vulnerable_host_keys -Template: ssh/vulnerable_host_keys -Owners: openssh-server - -Name: sysstat/enable -Template: sysstat/enable -Value: true -Owners: sysstat -Flags: seen - -Name: sysstat/remove_files -Template: sysstat/remove_files -Value: true -Owners: sysstat - -Name: tasksel/desktop -Template: tasksel/desktop -Owners: tasksel - -Name: tasksel/first -Template: tasksel/first -Value: ssh-server -Owners: tasksel -Variables: - CHOICES = Debian desktop environment, Web server, Print server, SQL database, DNS Server, File server, Mail server, SSH server, Laptop, Standard system utilities - CHOICES_C = desktop, web-server, print-server, database-server, dns-server, file-server, mail-server, ssh-server, laptop, standard - -Name: tasksel/tasks -Template: tasksel/tasks -Owners: tasksel - -Name: tasksel/title -Template: tasksel/title -Owners: tasksel - -Name: tzdata/Areas -Template: tzdata/Areas -Value: Etc -Owners: tzdata -Flags: seen - -Name: tzdata/Zones/Africa -Template: tzdata/Zones/Africa -Owners: tzdata - -Name: tzdata/Zones/America -Template: tzdata/Zones/America -Owners: tzdata - -Name: tzdata/Zones/Antarctica -Template: tzdata/Zones/Antarctica -Owners: tzdata - -Name: tzdata/Zones/Arctic -Template: tzdata/Zones/Arctic -Owners: tzdata - -Name: tzdata/Zones/Asia -Template: tzdata/Zones/Asia -Owners: tzdata - -Name: tzdata/Zones/Atlantic -Template: tzdata/Zones/Atlantic -Owners: tzdata - -Name: tzdata/Zones/Australia -Template: tzdata/Zones/Australia -Owners: tzdata - -Name: tzdata/Zones/Etc -Template: tzdata/Zones/Etc -Value: UTC -Owners: tzdata -Flags: seen - -Name: tzdata/Zones/Europe -Template: tzdata/Zones/Europe -Owners: tzdata - -Name: tzdata/Zones/Indian -Template: tzdata/Zones/Indian -Owners: tzdata - -Name: tzdata/Zones/Pacific -Template: tzdata/Zones/Pacific -Owners: tzdata - -Name: tzdata/Zones/SystemV -Template: tzdata/Zones/SystemV -Owners: tzdata - -Name: tzdata/Zones/US -Template: tzdata/Zones/US -Owners: tzdata - -Name: ucf/changeprompt -Template: ucf/changeprompt -Owners: ucf - -Name: ucf/changeprompt_threeway -Template: ucf/changeprompt_threeway -Owners: ucf - -Name: ucf/conflicts_found -Template: ucf/conflicts_found -Owners: ucf - -Name: ucf/show_diff -Template: ucf/show_diff -Owners: ucf - -Name: ucf/title -Template: ucf/title -Owners: ucf - -Name: udev/new_kernel_needed -Template: udev/new_kernel_needed -Owners: udev - -Name: udev/reboot_needed -Template: udev/reboot_needed -Owners: udev - -Name: udev/sysfs_deprecated_incompatibility -Template: udev/sysfs_deprecated_incompatibility -Owners: udev - -Name: udev/title/upgrade -Template: udev/title/upgrade -Owners: udev - -Name: wamerican/languages -Template: wamerican/languages -Owners: wamerican - diff --git a/tools/appliance/definitions/systemvmtemplate/definition.rb b/tools/appliance/definitions/systemvmtemplate/definition.rb index ec591ba7f3d..a839182bbd9 100644 --- a/tools/appliance/definitions/systemvmtemplate/definition.rb +++ b/tools/appliance/definitions/systemvmtemplate/definition.rb @@ -1,20 +1,3 @@ -# 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. - Veewee::Definition.declare({ :cpu_count => '1', :memory_size=> '256', @@ -54,7 +37,7 @@ Veewee::Definition.declare({ :shutdown_cmd => "halt -p", :postinstall_files => [ "base.sh", - "cloudstack-packages.sh", + "postinstall.sh", "cleanup.sh", "zerodisk.sh" ], diff --git a/tools/appliance/definitions/systemvmtemplate/postinstall.sh b/tools/appliance/definitions/systemvmtemplate/postinstall.sh index 40064325a2b..97de81abbb7 100644 --- a/tools/appliance/definitions/systemvmtemplate/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate/postinstall.sh @@ -15,55 +15,21 @@ # specific language governing permissions and limitations # under the License. -set -e set -x -IMAGENAME=systemvm -LOCATION=/var/lib/images/systemvm -PASSWORD=password +ROOTPW=password HOSTNAME=systemvm -SIZE=2048 -DEBIAN_MIRROR=ftp.us.debian.org/debian -MINIMIZE=true -CLOUDSTACK_RELEASE=4.1.0 - -init() { - # Update the box - apt-get -y update - apt-get -y install linux-headers-$(uname -r) build-essential - apt-get -y install zlib1g-dev libssl-dev libreadline-gplv2-dev - apt-get -y install curl unzip - apt-get clean - - # Set up sudo - echo 'vagrant ALL=NOPASSWD:ALL' > /etc/sudoers.d/vagrant - - # Tweak sshd to prevent DNS resolution (speed up logins) - echo 'UseDNS no' >> /etc/ssh/sshd_config - - # Remove 5s grub timeout to speed up booting - echo < /etc/default/grub -# If you change this file, run 'update-grub' afterwards to update -# /boot/grub/grub.cfg. - -GRUB_DEFAULT=0 -GRUB_TIMEOUT=0 -GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian` -GRUB_CMDLINE_LINUX_DEFAULT="quiet" -GRUB_CMDLINE_LINUX="debian-installer=en_US" -EOF - - update-grub -} +CLOUDSTACK_RELEASE=4.2.0 install_packages() { DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical #basic stuff - apt-get --no-install-recommends -q -y --force-yes install rsyslog logrotate cron chkconfig insserv net-tools ifupdown vim-tiny netbase iptables openssh-server grub-legacy e2fsprogs dhcp3-client dnsmasq tcpdump socat wget python bzip2 sed gawk diff grep gzip less tar telnet ftp rsync traceroute psmisc lsof procps monit inetutils-ping iputils-arping httping dnsutils zip unzip ethtool uuid file iproute acpid iptables-persistent virt-what sudo - #fix hostname in openssh-server generated keys - sed -i "s/root@\(.*\)$/root@systemvm/g" etc/ssh/ssh_host_*.pub + apt-get --no-install-recommends -q -y --force-yes install rsyslog logrotate cron chkconfig insserv net-tools ifupdown vim-tiny netbase iptables + apt-get --no-install-recommends -q -y --force-yes install openssh-server openssl grub-legacy e2fsprogs dhcp3-client dnsmasq tcpdump socat wget + apt-get --no-install-recommends -q -y --force-yes install python bzip2 sed gawk diffutils grep gzip less tar telnet ftp rsync traceroute psmisc lsof procps monit inetutils-ping iputils-arping httping + apt-get --no-install-recommends -q -y --force-yes install dnsutils zip unzip ethtool uuid file iproute acpid virt-what sudo #sysstat echo 'sysstat sysstat/enable boolean true' | debconf-set-selections @@ -76,72 +42,115 @@ install_packages() { apt-get --no-install-recommends -q -y --force-yes install dnsmasq #nfs client apt-get --no-install-recommends -q -y --force-yes install nfs-common + #vpn stuff - apt-get --no-install-recommends -q -y --force-yes install xl2tpd openswan bcrelay ppp ipsec-tools tdb-tools + apt-get --no-install-recommends -q -y --force-yes install xl2tpd bcrelay ppp ipsec-tools tdb-tools + echo "openswan openswan/install_x509_certificate boolean false" | debconf-set-selections + echo "openswan openswan/install_x509_certificate seen true" | debconf-set-selections + apt-get --no-install-recommends -q -y --force-yes install openswan + #vmware tools apt-get --no-install-recommends -q -y --force-yes install open-vm-tools #xenstore utils apt-get --no-install-recommends -q -y --force-yes install xenstore-utils libxenstore3.0 - #keepalived and conntrackd + #keepalived and conntrackd for redundant router apt-get --no-install-recommends -q -y --force-yes install keepalived conntrackd ipvsadm libnetfilter-conntrack3 libnl1 #ipcalc apt-get --no-install-recommends -q -y --force-yes install ipcalc #java apt-get --no-install-recommends -q -y --force-yes install default-jre-headless + echo "iptables-persistent iptables-persistent/autosave_v4 boolean true" | debconf-set-selections + echo "iptables-persistent iptables-persistent/autosave_v6 boolean true" | debconf-set-selections + apt-get --no-install-recommends -q -y --force-yes install iptables-persistent +} + +setup_accounts() { # Setup sudo to allow no-password sudo for "admin" groupadd -r admin - usermod -a -G admin cloud - echo "root:password" | chpasswd + #create a 'cloud' user + useradd -G admin cloud + echo "root:$ROOTPW" | chpasswd + echo "cloud:`openssl rand -base64 32`" | chpasswd sed -i -e '/Defaults\s\+env_reset/a Defaults\texempt_group=admin' /etc/sudoers sed -i -e 's/%admin ALL=(ALL) ALL/%admin ALL=NOPASSWD:ALL/g' /etc/sudoers - - mkdir /home/cloud/.ssh + # Disable password based authentication via ssh, this will take effect on next reboot + sed -i -e 's/^.*PasswordAuthentication .*$/PasswordAuthentication no/g' /etc/ssh/sshd_config + # Secure ~/.ssh + mkdir -p /home/cloud/.ssh chmod 700 /home/cloud/.ssh +} + +fix_nameserver() { + #replace /etc/resolv.conf also + cat > /etc/resolv.conf << EOF +nameserver 8.8.8.8 +nameserver 4.4.4.4 +EOF } -cleanup() { - # Clean up - apt-get -y remove linux-headers-$(uname -r) build-essential - apt-get -y autoremove +do_fixes() { + #fix hostname in openssh-server generated keys + sed -i "s/root@\(.*\)$/root@$HOSTNAME/g" /etc/ssh/ssh_host_*.pub + #fix hostname to override one provided by dhcp during vm build + echo "$HOSTNAME" > /etc/hostname + hostname $HOSTNAME + #delete entry in /etc/hosts derived from dhcp + sed -i '/127.0.1.1/d' /etc/hosts - # Removing leftover leases and persistent rules - echo "cleaning up dhcp leases" - rm /var/lib/dhcp/* - - # Make sure Udev doesn't block our network - echo "cleaning up udev rules" - rm /etc/udev/rules.d/70-persistent-net.rules - mkdir /etc/udev/rules.d/70-persistent-net.rules - rm -rf /dev/.udev/ - rm /lib/udev/rules.d/75-persistent-net-generator.rules - - echo "Adding a 2 sec delay to the interface up, to make the dhclient happy" - echo "pre-up sleep 2" >> /etc/network/interfaces + fix_nameserver } -finalize() { - # Zero out the free space to save space in the final image: - dd if=/dev/zero of=/EMPTY bs=1M - rm -f /EMPTY +configure_apache2() { + #enable ssl, rewrite and auth + a2enmod ssl rewrite auth_basic auth_digest + a2ensite default-ssl + #backup stock apache configuration since we may modify it in Secondary Storage VM + cp /etc/apache2/sites-available/default /etc/apache2/sites-available/default.orig + cp /etc/apache2/sites-available/default-ssl /etc/apache2/sites-available/default-ssl.orig } +configure_services() { + mkdir -p /var/www/html + mkdir -p /opt/cloud/bin + mkdir -p /var/cache/cloud + mkdir -p /usr/share/cloud + mkdir -p /usr/local/cloud + mkdir -p /root/.ssh + #Fix haproxy directory issue + mkdir -p /var/lib/haproxy + + wget 'https://git-wip-us.apache.org/repos/asf?p=incubator-cloudstack.git;a=blob_plain;f=patches/systemvm/debian/config/etc/init.d/cloud-early-config;hb=HEAD' -O /etc/init.d/cloud-early-config + chkconfig --add cloud-early-config + chkconfig cloud-early-config on + wget 'https://git-wip-us.apache.org/repos/asf?p=incubator-cloudstack.git;a=blob_plain;f=patches/systemvm/debian/config/etc/init.d/cloud-passwd-srvr;hb=HEAD' -O /etc/init.d/cloud-passwd-srvr + chkconfig --add cloud-passwd-srvr + chkconfig cloud-passwd-srvr off + wget 'https://git-wip-us.apache.org/repos/asf?p=incubator-cloudstack.git;a=blob_plain;f=patches/systemvm/debian/config/etc/init.d/cloud;hb=HEAD' -O /etc/init.d/cloud + chkconfig --add cloud + chkconfig cloud off + chkconfig monit off + chkconfig xl2tpd off +} + +do_signature() { + mkdir -p /var/cache/cloud/ + touch /var/cache/cloud/cloud-scripts-signature + #FIXME: signature should be generated from scripts package that can get updated + echo "Cloudstack Release $CLOUDSTACK_RELEASE $(date)" > /etc/cloudstack-release +} -echo "*************STARTING POSTINST SCRIPT********************" begin=$(date +%s) -echo "*************INITIALIZING BASE SYSTEM********************" -init - echo "*************INSTALLING PACKAGES********************" install_packages - -echo "*************CLEANING UP********************" -cleanup - -echo "*************FINALIZING IMAGE********************" -finalize +echo "*************DONE INSTALLING PACKAGES********************" +setup_accounts +configure_apache2 +configure_services +do_fixes +do_signature fin=$(date +%s) t=$((fin-begin)) diff --git a/tools/appliance/definitions/systemvmtemplate/preseed.cfg b/tools/appliance/definitions/systemvmtemplate/preseed.cfg index 0643ce3329b..b4d28955473 100644 --- a/tools/appliance/definitions/systemvmtemplate/preseed.cfg +++ b/tools/appliance/definitions/systemvmtemplate/preseed.cfg @@ -1,20 +1,3 @@ -# 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. - #### Contents of the preconfiguration file (for squeeze) ### Localization # Locale sets language and country. @@ -116,29 +99,28 @@ d-i clock-setup/ntp boolean true d-i partman-auto/disk string /dev/sda # In addition, you'll need to specify the method to use. # The presently available methods are: "regular", "lvm" and "crypto" -d-i partman-auto/method string lvm +d-i partman-auto/method string regular # If one of the disks that are going to be automatically partitioned # contains an old LVM configuration, the user will normally receive a # warning. This can be preseeded away... -d-i partman-lvm/device_remove_lvm boolean true +#d-i partman-lvm/device_remove_lvm boolean true # The same applies to pre-existing software RAID array: -d-i partman-md/device_remove_md boolean true +#d-i partman-md/device_remove_md boolean true # And the same goes for the confirmation to write the lvm partitions. -d-i partman-lvm/confirm boolean true -d-i partman-lvm/confirm_nooverwrite boolean true +#d-i partman-lvm/confirm boolean true +#d-i partman-lvm/confirm_nooverwrite boolean true - -d-i partman/choose_partition select finish -d-i partman-auto-lvm/guided_size string max +#d-i partman/choose_partition select finish +#d-i partman-auto-lvm/guided_size string max # You can choose one of the three predefined partitioning recipes: # - atomic: all files in one partition # - home: separate /home partition # - multi: separate /home, /usr, /var, and /tmp partitions -d-i partman-auto/choose_recipe select multi -d-i partman/default_filesystem string ext3 +d-i partman-auto/choose_recipe select atomic +#d-i partman/default_filesystem string ext3 # Or provide a recipe of your own... # The recipe format is documented in the file devel/partman-auto-recipe.txt. @@ -146,6 +128,48 @@ d-i partman/default_filesystem string ext3 # just point at it. #d-i partman-auto/expert_recipe_file string /hd-media/recipe +d-i partman-auto/expert_recipe string \ + boot-root :: \ + 40 50 100 ext4 \ + $primary{ } $bootable{ } \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + mountpoint{ /boot } \ + . \ + 400 40 500 ext4 \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + mountpoint{ / } \ + . \ + 60 100 200 ext4 \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + mountpoint{ /home } \ + . \ + 500 30 1000 ext4 \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + mountpoint{ /usr } \ + . \ + 400 40 500 ext4 \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + mountpoint{ /opt } \ + . \ + 500 60 1000 ext4 \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + mountpoint{ /var } \ + . \ + 100 70 400 ext4 \ + method{ format } format{ } \ + use_filesystem{ } filesystem{ ext4 } \ + mountpoint{ /tmp } \ + . \ + 64 512 300% linux-swap \ + method{ swap } format{ } \ + . + # If not, you can put an entire recipe into the preconfiguration file in one # (logical) line. This example creates a small /boot partition, suitable # swap, and uses the rest of the space for the root partition: @@ -171,11 +195,12 @@ d-i partman/default_filesystem string ext3 # This makes partman automatically partition without confirmation, provided # that you told it what to do using one of the methods above. +#d-i partman-partitioning/confirm_write_new_label boolean true d-i partman/confirm_write_new_label boolean true +d-i partman/choose_partition select finish d-i partman/confirm boolean true d-i partman/confirm_nooverwrite boolean true - ### Base system installation # Select the initramfs generator used to generate the initrd for 2.6 kernels. #d-i base-installer/kernel/linux/initramfs-generators string yaird diff --git a/tools/appliance/definitions/systemvmtemplate/zerodisk.sh b/tools/appliance/definitions/systemvmtemplate/zerodisk.sh index fef5b705572..9fc9f6f8693 100644 --- a/tools/appliance/definitions/systemvmtemplate/zerodisk.sh +++ b/tools/appliance/definitions/systemvmtemplate/zerodisk.sh @@ -1,23 +1,7 @@ -# 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. - #clean up stuff copied in by veewee rm -f /root/* # Zero out the free space to save space in the final image: dd if=/dev/zero of=/EMPTY bs=1M rm -f /EMPTY + diff --git a/tools/cli/pom.xml b/tools/cli/pom.xml index d99d6fb3aec..b4820cd1e36 100644 --- a/tools/cli/pom.xml +++ b/tools/cli/pom.xml @@ -20,13 +20,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 cloud-cli - Apache CloudStack Developer Tools: cloudmonkey cli + Apache CloudStack cloudmonkey cli pom org.apache.cloudstack - cloudstack - 4.1.0-SNAPSHOT - ../../pom.xml + cloud-tools + 4.2.0-SNAPSHOT + ../pom.xml diff --git a/tools/devcloud-kvm/pom.xml b/tools/devcloud-kvm/pom.xml index f29e8375219..9ae36ee6788 100644 --- a/tools/devcloud-kvm/pom.xml +++ b/tools/devcloud-kvm/pom.xml @@ -16,9 +16,9 @@ pom org.apache.cloudstack - cloudstack - 4.1.0-SNAPSHOT - ../../pom.xml + cloud-tools + 4.2.0-SNAPSHOT + ../pom.xml @@ -94,7 +94,7 @@ create-schema - process-test-resources + process-resources execute diff --git a/tools/devcloud/pom.xml b/tools/devcloud/pom.xml index 8a7a7ca1f8b..d7b82c9d7fe 100644 --- a/tools/devcloud/pom.xml +++ b/tools/devcloud/pom.xml @@ -16,9 +16,9 @@ pom org.apache.cloudstack - cloudstack - 4.1.0-SNAPSHOT - ../../pom.xml + cloud-tools + 4.2.0-SNAPSHOT + ../pom.xml @@ -62,8 +62,8 @@ - ${project.parent.basedir}/utils/conf/db.properties - ${project.parent.basedir}/utils/conf/db.properties.override + ${project.parent.parent.basedir}/utils/conf/db.properties + ${project.parent.parent.basedir}/utils/conf/db.properties.override true @@ -94,7 +94,7 @@ create-schema - process-test-resources + process-resources execute diff --git a/tools/devcloud/src/deps/boxes/basebox-build/definition.rb b/tools/devcloud/src/deps/boxes/basebox-build/definition.rb index 24668421c5d..f7e3c114993 100644 --- a/tools/devcloud/src/deps/boxes/basebox-build/definition.rb +++ b/tools/devcloud/src/deps/boxes/basebox-build/definition.rb @@ -1,20 +1,3 @@ -# 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. - Veewee::Session.declare({ :cpu_count => '1', :memory_size=> '2048', diff --git a/tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg b/tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg index 00bae613647..dd6a24a3b65 100644 --- a/tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg +++ b/tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg @@ -1,20 +1,3 @@ -# 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. - ## Options to set on the command line d-i debian-installer/locale string en_US.utf8 d-i console-setup/ask_detect boolean false diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index e4f7eace9bd..cec920c5ff0 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -19,16 +19,16 @@ import configGenerator import cloudstackException import cloudstackTestClient -import sys -import os import logging from cloudstackAPI import * +from os import path from optparse import OptionParser class deployDataCenters(): def __init__(self, cfgFile): - if not os.path.exists(cfgFile): + if not path.exists(cfgFile) \ + and not path.exists(path.abspath(cfgFile)): raise IOError("config file %s not found. please specify a valid config file"%cfgFile) self.configFile = cfgFile @@ -444,7 +444,7 @@ if __name__ == "__main__": parser = OptionParser() - parser.add_option("-i", "--intput", action="store", \ + parser.add_option("-i", "--input", action="store", \ default="./datacenterCfg", dest="input", help="the path \ where the json config file generated, by default is \ ./datacenterCfg") diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index 51c70cd92b8..80099be1ecb 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -12,15 +12,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 cloud-marvin - Apache CloudStack Developer Tools: marvin + Apache CloudStack marvin pom org.apache.cloudstack - cloudstack - 4.1.0-SNAPSHOT - ../../pom.xml + cloud-tools + 4.2.0-SNAPSHOT + ../pom.xml - install @@ -29,14 +28,15 @@ 1.7 - generate-resource - generate-resources + clean + clean run - + + Deleting ${project.artifactId} API sources @@ -54,12 +54,13 @@ exec - marvin + ${basedir}/marvin python codegenerator.py -s ${basedir}/../apidoc/target/commands.xml + Generating ${project.artifactId} API classes} @@ -78,23 +79,42 @@ - - deploy - deploy - - exec - - - dist - pip - - install - Marvin-0.1.0.tar.gz - - - + - + + + + marvin + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + package + + exec + + + + + ${basedir}/marvin + python + + deployDataCenter.py + -i + ${user.dir}/${marvin.config} + + + + + + + diff --git a/tools/pom.xml b/tools/pom.xml new file mode 100644 index 00000000000..09961bb28d8 --- /dev/null +++ b/tools/pom.xml @@ -0,0 +1,44 @@ + + + + 4.0.0 + + Apache CloudStack Developer Tools + org.apache.cloudstack + cloud-tools + pom + + org.apache.cloudstack + cloudstack + 4.2.0-SNAPSHOT + ../pom.xml + + + install + + + apidoc + marvin + cli + devcloud + devcloud-kvm + + diff --git a/tools/whisker/LICENSE b/tools/whisker/LICENSE index 025cb33136b..2e17633f464 100644 --- a/tools/whisker/LICENSE +++ b/tools/whisker/LICENSE @@ -748,7 +748,7 @@ Within the deps/awsapi-lib directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. � + computer software" (as that term is defined at 48 C.F.R. ¤ 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -1138,7 +1138,7 @@ Within the deps/awsapi-lib directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. � + computer software" (as that term is defined at 48 C.F.R. ¤ 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -1526,7 +1526,7 @@ Within the deps/awsapi-lib directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. � + computer software" (as that term is defined at 48 C.F.R. ¤ 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -1867,9 +1867,7 @@ Within the deps/awsapi-lib directory slf4j-api-1.5.11.jar from https://github.com/qos-ch/slf4j slf4j-jdk14-1.5.11.jar from https://github.com/qos-ch/slf4j - licensed under the Mozilla Public License, Version 1.1 http://www.mozilla.org/MPL/1.1/ (as follows) - MOZILLA PUBLIC LICENSE @@ -2346,71 +2344,70 @@ Within the deps/awsapi-lib directory from Shigeru Chiba http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ javassist-3.9.0.GA.jar from http://sourceforge.net/projects/jboss/files/Javassist/ - licensed under the Mozilla Public License, Version 1.1 http://www.mozilla.org/MPL/1.1/ (as follows) - Copyright (c) 2007-2012 VMware, Inc. All Rights Reserved. - + Copyright (c) 2007-2012 VMware, Inc. All Rights Reserved. + MOZILLA PUBLIC LICENSE Version 1.1 - + --------------- - + 1. Definitions. - + 1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. - + 1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications. - + 1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. - + 1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. - + 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data. - + 1.5. "Executable" means Covered Code in any form other than Source Code. - + 1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. - + 1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. - + 1.8. "License" means this document. - + 1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. - + 1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. - + B. Any new file that contains any part of the Original Code or previous Modifications. - + 1.10. "Original Code" means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. - + 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. - + 1.11. "Source Code" means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control @@ -2420,7 +2417,7 @@ Within the deps/awsapi-lib directory Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. - + 1.12. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. @@ -2431,9 +2428,9 @@ Within the deps/awsapi-lib directory contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. - + 2. Source Code License. - + 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property @@ -2443,33 +2440,33 @@ Within the deps/awsapi-lib directory modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and - + (b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). - + (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. - + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. - + 2.2. Contributor Grant. Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license - + (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and - + (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions @@ -2478,11 +2475,11 @@ Within the deps/awsapi-lib directory Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). - + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code. - + (d) Notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; @@ -2492,9 +2489,9 @@ Within the deps/awsapi-lib directory Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. - + 3. Distribution Obligations. - + 3.1. Application of License. The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation @@ -2507,7 +2504,7 @@ Within the deps/awsapi-lib directory License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. - + 3.2. Availability of Source Code. Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License @@ -2520,7 +2517,7 @@ Within the deps/awsapi-lib directory has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. - + 3.3. Description of Modifications. You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and @@ -2530,7 +2527,7 @@ Within the deps/awsapi-lib directory Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. - + 3.4. Intellectual Property Matters (a) Third Party Claims. If Contributor has knowledge that a license under a third party's @@ -2546,20 +2543,20 @@ Within the deps/awsapi-lib directory (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. - + (b) Contributor APIs. If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. - + (c) Representations. Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. - + 3.5. Required Notices. You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source @@ -2579,7 +2576,7 @@ Within the deps/awsapi-lib directory Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. - + 3.6. Distribution of Executable Versions. You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, @@ -2602,15 +2599,15 @@ Within the deps/awsapi-lib directory Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. - + 3.7. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. - + 4. Inability to Comply Due to Statute or Regulation. - + If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with @@ -2621,19 +2618,19 @@ Within the deps/awsapi-lib directory extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. - + 5. Application of this License. - + This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. - + 6. Versions of the License. - + 6.1. New Versions. Netscape Communications Corporation ("Netscape") may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. - + 6.2. Effect of New Versions. Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that @@ -2641,7 +2638,7 @@ Within the deps/awsapi-lib directory of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. - + 6.3. Derivative Works. If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code @@ -2655,9 +2652,9 @@ Within the deps/awsapi-lib directory Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) - + 7. DISCLAIMER OF WARRANTY. - + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF @@ -2668,9 +2665,9 @@ Within the deps/awsapi-lib directory COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - + 8. TERMINATION. - + 8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All @@ -2678,12 +2675,12 @@ Within the deps/awsapi-lib directory survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. - + 8.2. If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that: - + (a) such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License @@ -2698,14 +2695,14 @@ Within the deps/awsapi-lib directory is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. - + (b) any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. - + 8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as @@ -2714,14 +2711,14 @@ Within the deps/awsapi-lib directory granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. - + 8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. - + 9. LIMITATION OF LIABILITY. - + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, @@ -2736,9 +2733,9 @@ Within the deps/awsapi-lib directory PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - + 10. U.S. GOVERNMENT END USERS. - + The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such @@ -2746,9 +2743,9 @@ Within the deps/awsapi-lib directory C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. - + 11. MISCELLANEOUS. - + This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent @@ -2767,44 +2764,44 @@ Within the deps/awsapi-lib directory Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. - + 12. RESPONSIBILITY FOR CLAIMS. - + As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. - + 13. MULTIPLE-LICENSED CODE. - + Initial Developer may designate portions of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the NPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. - + EXHIBIT A -Mozilla Public License. - + ``The contents of this file are subject to the Mozilla Public License Version 1.1 (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.mozilla.org/MPL/ - + Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - + The Original Code is RabbitMQ. - + The Initial Developer of the Original Code is VMware, Ltd.. - Portions created by VMware, Ltd. are Copyright (C) + Portions created by VMware, Ltd. are Copyright (C) 2007-2012 VMware, Inc.. All Rights Reserved. - + Contributor(s): . - + Alternatively, the contents of this file may be used under the terms of the GNU General Public License Version 2 license (the "[GPL] License"), in which case the provisions of [GPL] License are applicable instead of those @@ -2815,17 +2812,16 @@ Within the deps/awsapi-lib directory other provisions required by the [GPL] License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [GPL] License." - + [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications.] - - - from VMware, Inc http://www.vmware.com/ + + + from VMware, Inc http://www.vmware.com/ rabbitmq-client.jar from http://www.rabbitmq.com/java-client.html - Within the patches/systemvm/debian/config/etc directory placed in the public domain by Adiscon GmbH http://www.adiscon.com/ @@ -2998,6 +2994,50 @@ Within the target/jar directory jetty-6.1.26.jar from http://repo1.maven.org/maven2/org/mortbay/jetty/jetty/6.1.26/jetty-6.1.26-sources.jar jetty-util-6.1.26.jar from http://repo1.maven.org/maven2/org/mortbay/jetty/jetty-util/6.1.26/jetty-util-6.1.26-sources.jar + licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above) + Copyright 2013 Jan Van Besien + from Jan Van Besien mailto:janvanbesien@gmail.com + java-ipv6.jar from http://code.google.com/p/java-ipv6 + + licensed under the Apache License, Version 2 http://www.apache.org/licenses/LICENSE-2.0.txt (as above) + Copyright 2002-2012 the original author or authors. + from SpringSource, a division of VMware. http://www.springsource.org/ + spring-context-3.1.2.RELEASE.jar from https://github.com/SpringSource/spring-framework + spring-core-3.1.2.RELEASE.jar from https://github.com/SpringSource/spring-framework + spring-web-3.1.2.RELEASE.jar from https://github.com/SpringSource/spring-framework + + licensed under the BSD (2-clause) http://www.opensource.org/licenses/BSD-2-Clause (as follows) + + Copyright (c) 2007, The OWASP Foundation + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. Redistributions in binary form must + reproduce the above copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the + distribution. + + Neither the name of the author nor the names of contributors may be used to + endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + from OWASP Foundation Inc. https://www.owasp.org/ + esapi-2.0.1.jar from http://code.google.com/p/owasp-esapi-java/ + licensed under the BSD (3-clause) http://www.opensource.org/licenses/BSD-3-Clause (as follows) Copyright (c) 2009, Caringo, Inc. @@ -3462,7 +3502,7 @@ Within the target/jar directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. � + computer software" (as that term is defined at 48 C.F.R. ¤ 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -3851,7 +3891,7 @@ Within the target/jar directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. � + computer software" (as that term is defined at 48 C.F.R. ¤ 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -4377,7 +4417,7 @@ Within the target/jar directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) - Copyright (C) 2008 T�th Istv�n + Copyright (C) 2008 Tóth István 2008-2012 Daniel Veillard 2009-2011 Bryan Kearney @@ -4480,6 +4520,31 @@ Within the ui/lib directory from George McGinley Smith jquery.easing.js + licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) + + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + from The Dojo Foundation http://dojofoundation.org/ + require.js from http://github.com/jrburke/requirejs + licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) Copyright (c) 2011, John Resig @@ -4508,7 +4573,7 @@ Within the ui/lib directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) - Copyright (c) 2006 - 2011 J�rn Zaefferer + Copyright (c) 2006 - 2011 Jörn Zaefferer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -4703,7 +4768,7 @@ Within the ui/lib/jquery-ui directory Within the ui/lib/qunit directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) - Copyright (c) 2012 John Resig, J�rn Zaefferer + Copyright (c) 2012 John Resig, Jörn Zaefferer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/tools/whisker/NOTICE b/tools/whisker/NOTICE index 18679580c47..69869906cf4 100644 --- a/tools/whisker/NOTICE +++ b/tools/whisker/NOTICE @@ -242,6 +242,14 @@ this distribution. + For + java-ipv6.jar + + + Java IPv6 + Copyright 2013 Jan Van Besien + + For cloud-jasypt-1.9.jar diff --git a/tools/whisker/descriptor-for-packaging.xml b/tools/whisker/descriptor-for-packaging.xml index 29a8284686b..ed2c9360112 100644 --- a/tools/whisker/descriptor-for-packaging.xml +++ b/tools/whisker/descriptor-for-packaging.xml @@ -2261,6 +2261,10 @@ The Apache Software Foundation (http://www.apache.org/). This product includes software Copyright University of Southampton IT Innovation Centre, 2006 (http://www.it-innovation.soton.ac.uk). + + Java IPv6 + Copyright 2013 Jan Van Besien + + + + + Copyright (c) 2013 The Apache Software Foundation @@ -2508,6 +2528,14 @@ Copyright (c) 2009, John Resig + + +Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + + + + + Copyright (c) 2006 Google Inc. @@ -2815,6 +2843,33 @@ All rights reserved. + + +Copyright 2013 Jan Van Besien + + + + + + + +Copyright 2002-2012 the original author or authors. + + + + + + + + + +Copyright (c) 2007, The OWASP Foundation +All rights reserved. + + + + + diff --git a/tools/whisker/descriptor.xml b/tools/whisker/descriptor.xml index 5f324a5c28f..0b3e508a124 100644 --- a/tools/whisker/descriptor.xml +++ b/tools/whisker/descriptor.xml @@ -2423,6 +2423,14 @@ Innovation Centre, 2006 (http://www.it-innovation.soton.ac.uk). id='adiscon.com' name='Adiscon GmbH' url='http://www.adiscon.com/' /> + + Copyright (c) 2013 The Apache Software Foundation @@ -2504,6 +2512,14 @@ Copyright (c) 2009, John Resig + + +Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + + + + + Copyright (c) 2006 Google Inc. @@ -2653,5 +2669,30 @@ Copyright (c) 2010-2011 OpenStack, LLC. - + + + + +Copyright (c) 2010-2012 Patrick Debois + + + + + + + + + + + + + +Copyright (c) 2010-2012 Patrick Debois + + + + + + + diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 6cb82f2ea25..cf18ab215e6 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -1276,14 +1276,14 @@ div.list-view td.state.off span { /** Quick view tooltip*/ .quick-view-tooltip { - width: 400px; + width: 470px; display: inline-block; - margin-left: -359px; + margin-left: -462px; padding-top: 50px; } .quick-view-tooltip > div.title { - width: 376px; + width: 444px; position: absolute; top: 71px; left: 10px; @@ -1320,7 +1320,7 @@ div.list-view td.state.off span { .quick-view-tooltip .container { border: 1px solid #9EA2A5; background: #CCCFD6; - width: 400px; + width: 470px; min-height: 100px; height: auto; overflow: hidden; @@ -1337,7 +1337,7 @@ div.list-view td.state.off span { } .quick-view-tooltip .detail-view .main-groups { - width: 394px; + width: 456px; height: 132px; position: absolute; top: 55px; @@ -1484,7 +1484,7 @@ div.list-view td.state.off span { } .quick-view-tooltip .detail-view .detail-group.actions .detail-actions { - width: 400px; + width: 460px; height: auto; background: none; vertical-align: top; @@ -1495,7 +1495,7 @@ div.list-view td.state.off span { position: relative; left: 0px; float: left; - width: 394px; + width: 460px; height: 22px; border-top: 1px solid #808080; /*+box-shadow:inset 0px 1px #FFFFFF;*/ @@ -1911,6 +1911,20 @@ div.details .main-groups label.error { top: 6px; } +.detail-view td.view-all.multiple { + width: 123px !important; + height: 22px; + float: left; + display: block; + margin: 8px 2px 8px 8px; + border: none !important; + /*+box-shadow:none;*/ + -moz-box-shadow: none !important; + -webkit-box-shadow: none !important; + -o-box-shadow: none !important; + box-shadow: none !important; +} + /*** Actions*/ div.detail-group.actions { padding: 0; @@ -1931,10 +1945,16 @@ div.detail-group.actions td { } .detail-group table td.detail-actions { - width: 55%; + width: 59%; height: 26px; } +.detail-group table td.detail-actions.full-length { + display: block; + width: 99%; + border-bottom: 1px solid #AAAAAA; +} + .detail-group table td.detail-actions .action.text { padding: 0px 6px 0px 0px; cursor: pointer; @@ -2336,6 +2356,28 @@ div.detail-group.actions td { top: 18px; } +#navigation ul li.custom-icon span.icon { + display: block; + width: 50px; + height: 50px; + position: relative; + float: left; + margin-right: -47px; + background: none; +} + +#navigation ul li.custom-icon span.icon img { + width: 50px; + height: 50px; + float: left; + /*+placement:shift -6px -17px;*/ + position: relative; + left: -6px; + top: -17px; + position: absolute; + margin-right: -14px; +} + #navigation ul li.last.active, #navigation ul li.last:hover { height: 52px; @@ -2392,6 +2434,10 @@ div.detail-group.actions td { background-position: -519px -24px; } +#navigation ul li.plugins span.icon { + background: url(../images/sprites.png) no-repeat -140px -291px; +} + /*Browser*/ #browser { width: 794px; @@ -10929,6 +10975,73 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it font-size: 11px; } +/*Plugins listing*/ +.plugins-listing { +} + +.plugins-listing ul { + width: 100%; +} + +.plugins-listing ul li { + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + /*+box-shadow:0px 2px 6px #D3D3D3;*/ + -moz-box-shadow: 0px 2px 6px #D3D3D3; + -webkit-box-shadow: 0px 2px 6px #D3D3D3; + -o-box-shadow: 0px 2px 6px #D3D3D3; + box-shadow: 0px 2px 6px #D3D3D3; + border: 1px solid #A8A3A3; + background: url(../images/bg-gradients.png) 0px -29px; + width: 98%; + height: 66px; + margin: 9px auto 12px; + cursor: pointer; +} + +.plugins-listing ul li:hover { + /*+box-shadow:inset 0px 2px 4px #B9B9B9;*/ + -moz-box-shadow: inset 0px 2px 4px #B9B9B9; + -webkit-box-shadow: inset 0px 2px 4px #B9B9B9; + -o-box-shadow: inset 0px 2px 4px #B9B9B9; + box-shadow: inset 0px 2px 4px #B9B9B9; +} + +.plugins-listing ul li .title { + display: block; + float: left; + width: 90%; + font-weight: bold; + /*+text-shadow:0px 1px 1px #FFFFFF;*/ + -moz-text-shadow: 0px 1px 1px #FFFFFF; + -webkit-text-shadow: 0px 1px 1px #FFFFFF; + -o-text-shadow: 0px 1px 1px #FFFFFF; + text-shadow: 0px 1px 1px #FFFFFF; + color: #4A5A6A; + margin: 13px 0 7px; +} + +.plugins-listing ul li .desc { + color: #524E4E; + font-size: 13px; +} + +.plugins-listing ul li .icon { + display: block; + width: 50px; + height: 50px; + float: left; + margin: 8px 13px 13px 11px; +} + +.plugins-listing ul li .icon img { + width: 100%; + height: 100%; +} + /*Action icons*/ .action.edit .icon { background-position: 1px -1px; diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index 508135611e3..3a10258029d 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -25,6 +25,11 @@ under the License. <% long now = System.currentTimeMillis(); %> diff --git a/ui/images/sample-wizard/step1.png b/ui/images/sample-wizard/step1.png deleted file mode 100644 index 1e0d40d2687..00000000000 Binary files a/ui/images/sample-wizard/step1.png and /dev/null differ diff --git a/ui/images/sample-wizard/step2.png b/ui/images/sample-wizard/step2.png deleted file mode 100644 index 955ee7eb276..00000000000 Binary files a/ui/images/sample-wizard/step2.png and /dev/null differ diff --git a/ui/images/sample-wizard/step3.png b/ui/images/sample-wizard/step3.png deleted file mode 100644 index b04a0eac1e0..00000000000 Binary files a/ui/images/sample-wizard/step3.png and /dev/null differ diff --git a/ui/images/sample-wizard/step4.png b/ui/images/sample-wizard/step4.png deleted file mode 100644 index a5857bc7296..00000000000 Binary files a/ui/images/sample-wizard/step4.png and /dev/null differ diff --git a/ui/images/sample-wizard/step5.png b/ui/images/sample-wizard/step5.png deleted file mode 100644 index 036a0c832b9..00000000000 Binary files a/ui/images/sample-wizard/step5.png and /dev/null differ diff --git a/ui/images/sample-wizard/step6.png b/ui/images/sample-wizard/step6.png deleted file mode 100644 index 0e681d57591..00000000000 Binary files a/ui/images/sample-wizard/step6.png and /dev/null differ diff --git a/ui/images/screens/Dashboard.jpg b/ui/images/screens/Dashboard.jpg deleted file mode 100644 index a793cf2d780..00000000000 Binary files a/ui/images/screens/Dashboard.jpg and /dev/null differ diff --git a/ui/images/screens/Dashboard2.jpg b/ui/images/screens/Dashboard2.jpg deleted file mode 100644 index dd14eeb5cf3..00000000000 Binary files a/ui/images/screens/Dashboard2.jpg and /dev/null differ diff --git a/ui/images/screens/Events-Details.jpg b/ui/images/screens/Events-Details.jpg deleted file mode 100644 index 3adfa09f5d7..00000000000 Binary files a/ui/images/screens/Events-Details.jpg and /dev/null differ diff --git a/ui/images/screens/Events.jpg b/ui/images/screens/Events.jpg deleted file mode 100644 index df22149816d..00000000000 Binary files a/ui/images/screens/Events.jpg and /dev/null differ diff --git a/ui/images/screens/MultiEdit.jpg b/ui/images/screens/MultiEdit.jpg deleted file mode 100644 index 5a5bb4697c5..00000000000 Binary files a/ui/images/screens/MultiEdit.jpg and /dev/null differ diff --git a/ui/images/screens/Network-Details.jpg b/ui/images/screens/Network-Details.jpg deleted file mode 100644 index 32f374e51dd..00000000000 Binary files a/ui/images/screens/Network-Details.jpg and /dev/null differ diff --git a/ui/images/screens/Network.jpg b/ui/images/screens/Network.jpg deleted file mode 100644 index f33f54cd70d..00000000000 Binary files a/ui/images/screens/Network.jpg and /dev/null differ diff --git a/ui/images/screens/ProjectDashboard.png b/ui/images/screens/ProjectDashboard.png deleted file mode 100644 index 51319260786..00000000000 Binary files a/ui/images/screens/ProjectDashboard.png and /dev/null differ diff --git a/ui/images/screens/Projects-Details.jpg b/ui/images/screens/Projects-Details.jpg deleted file mode 100644 index 9f457cb1390..00000000000 Binary files a/ui/images/screens/Projects-Details.jpg and /dev/null differ diff --git a/ui/images/screens/Projects.jpg b/ui/images/screens/Projects.jpg deleted file mode 100644 index 0684a89d689..00000000000 Binary files a/ui/images/screens/Projects.jpg and /dev/null differ diff --git a/ui/images/screens/Storage-Details.jpg b/ui/images/screens/Storage-Details.jpg deleted file mode 100644 index 9f5d6321968..00000000000 Binary files a/ui/images/screens/Storage-Details.jpg and /dev/null differ diff --git a/ui/images/screens/Storage.jpg b/ui/images/screens/Storage.jpg deleted file mode 100644 index 3f8789ce658..00000000000 Binary files a/ui/images/screens/Storage.jpg and /dev/null differ diff --git a/ui/images/screens/Templates-Details.jpg b/ui/images/screens/Templates-Details.jpg deleted file mode 100644 index a2ffd6c3721..00000000000 Binary files a/ui/images/screens/Templates-Details.jpg and /dev/null differ diff --git a/ui/images/screens/Templates.jpg b/ui/images/screens/Templates.jpg deleted file mode 100644 index 35985cc88ce..00000000000 Binary files a/ui/images/screens/Templates.jpg and /dev/null differ diff --git a/ui/images/screens/ZoneWizard-AddCluster.jpg b/ui/images/screens/ZoneWizard-AddCluster.jpg deleted file mode 100644 index e47d9661178..00000000000 Binary files a/ui/images/screens/ZoneWizard-AddCluster.jpg and /dev/null differ diff --git a/ui/images/screens/ZoneWizard-AddHost.jpg b/ui/images/screens/ZoneWizard-AddHost.jpg deleted file mode 100644 index 92752b81562..00000000000 Binary files a/ui/images/screens/ZoneWizard-AddHost.jpg and /dev/null differ diff --git a/ui/images/screens/ZoneWizard-AddPrimaryStorage.jpg b/ui/images/screens/ZoneWizard-AddPrimaryStorage.jpg deleted file mode 100644 index afa09d58b31..00000000000 Binary files a/ui/images/screens/ZoneWizard-AddPrimaryStorage.jpg and /dev/null differ diff --git a/ui/images/screens/ZoneWizard-AddSecondaryStorage.jpg b/ui/images/screens/ZoneWizard-AddSecondaryStorage.jpg deleted file mode 100644 index 8c9f1987340..00000000000 Binary files a/ui/images/screens/ZoneWizard-AddSecondaryStorage.jpg and /dev/null differ diff --git a/ui/images/screens/ZoneWizard-SetupGuestTraffic.jpg b/ui/images/screens/ZoneWizard-SetupGuestTraffic.jpg deleted file mode 100644 index a9545ca5e45..00000000000 Binary files a/ui/images/screens/ZoneWizard-SetupGuestTraffic.jpg and /dev/null differ diff --git a/ui/images/screens/ZoneWizard-StorageTraffic.jpg b/ui/images/screens/ZoneWizard-StorageTraffic.jpg deleted file mode 100644 index eab4e3b58ce..00000000000 Binary files a/ui/images/screens/ZoneWizard-StorageTraffic.jpg and /dev/null differ diff --git a/ui/images/sprites.png b/ui/images/sprites.png index a3ad9e4862f..ba4ae454cb1 100644 Binary files a/ui/images/sprites.png and b/ui/images/sprites.png differ diff --git a/ui/index.jsp b/ui/index.jsp index fdacd9e99d4..462ddaf292e 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -1607,8 +1607,9 @@ under the License. - - + + + @@ -1674,6 +1675,12 @@ under the License. + + + + + + diff --git a/ui/lib/require.js b/ui/lib/require.js new file mode 100644 index 00000000000..0e7b81bc49f --- /dev/null +++ b/ui/lib/require.js @@ -0,0 +1,1993 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.1.2 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +//Not using strict: uneven strict support in browsers, #392, and causes +//problems with requirejs.exec()/transpiler plugins that may not be strict. +/*jslint regexp: true, nomen: true, sloppy: true */ +/*global window, navigator, document, importScripts, jQuery, setTimeout, opera */ + +var requirejs, require, define; +(function (global) { + var req, s, head, baseElement, dataMain, src, + interactiveScript, currentlyAddingScript, mainScript, subPath, + version = '2.1.2', + commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, + cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, + jsSuffixRegExp = /\.js$/, + currDirRegExp = /^\.\//, + op = Object.prototype, + ostring = op.toString, + hasOwn = op.hasOwnProperty, + ap = Array.prototype, + aps = ap.slice, + apsp = ap.splice, + isBrowser = !!(typeof window !== 'undefined' && navigator && document), + isWebWorker = !isBrowser && typeof importScripts !== 'undefined', + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is 'loading', 'loaded', execution, + // then 'complete'. The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? + /^complete$/ : /^(complete|loaded)$/, + defContextName = '_', + //Oh the tragedy, detecting opera. See the usage of isOpera for reason. + isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', + contexts = {}, + cfg = {}, + globalDefQueue = [], + useInteractive = false; + + function isFunction(it) { + return ostring.call(it) === '[object Function]'; + } + + function isArray(it) { + return ostring.call(it) === '[object Array]'; + } + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + /** + * Helper function for iterating over an array backwards. If the func + * returns a true value, it will break out of the loop. + */ + function eachReverse(ary, func) { + if (ary) { + var i; + for (i = ary.length - 1; i > -1; i -= 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + function getOwn(obj, prop) { + return hasProp(obj, prop) && obj[prop]; + } + + /** + * Cycles over properties in an object and calls a function for each + * property value. If the function returns a truthy value, then the + * iteration is stopped. + */ + function eachProp(obj, func) { + var prop; + for (prop in obj) { + if (hasProp(obj, prop)) { + if (func(obj[prop], prop)) { + break; + } + } + } + } + + /** + * Simple function to mix in properties from source into target, + * but only if target does not already have a property of the same name. + */ + function mixin(target, source, force, deepStringMixin) { + if (source) { + eachProp(source, function (value, prop) { + if (force || !hasProp(target, prop)) { + if (deepStringMixin && typeof value !== 'string') { + if (!target[prop]) { + target[prop] = {}; + } + mixin(target[prop], value, force, deepStringMixin); + } else { + target[prop] = value; + } + } + }); + } + return target; + } + + //Similar to Function.prototype.bind, but the 'this' object is specified + //first, since it is easier to read/figure out what 'this' will be. + function bind(obj, fn) { + return function () { + return fn.apply(obj, arguments); + }; + } + + function scripts() { + return document.getElementsByTagName('script'); + } + + //Allow getting a global that expressed in + //dot notation, like 'a.b.c'. + function getGlobal(value) { + if (!value) { + return value; + } + var g = global; + each(value.split('.'), function (part) { + g = g[part]; + }); + return g; + } + + /** + * Constructs an error with a pointer to an URL with more information. + * @param {String} id the error ID that maps to an ID on a web page. + * @param {String} message human readable error. + * @param {Error} [err] the original error, if there is one. + * + * @returns {Error} + */ + function makeError(id, msg, err, requireModules) { + var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); + e.requireType = id; + e.requireModules = requireModules; + if (err) { + e.originalError = err; + } + return e; + } + + if (typeof define !== 'undefined') { + //If a define is already in play via another AMD loader, + //do not overwrite. + return; + } + + if (typeof requirejs !== 'undefined') { + if (isFunction(requirejs)) { + //Do not overwrite and existing requirejs instance. + return; + } + cfg = requirejs; + requirejs = undefined; + } + + //Allow for a require config object + if (typeof require !== 'undefined' && !isFunction(require)) { + //assume it is a config object. + cfg = require; + require = undefined; + } + + function newContext(contextName) { + var inCheckLoaded, Module, context, handlers, + checkLoadedTimeoutId, + config = { + waitSeconds: 7, + baseUrl: './', + paths: {}, + pkgs: {}, + shim: {}, + map: {}, + config: {} + }, + registry = {}, + undefEvents = {}, + defQueue = [], + defined = {}, + urlFetched = {}, + requireCounter = 1, + unnormalizedCounter = 1; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i += 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @param {Boolean} applyMap apply the map config to the value. Should + * only be done if this normalization is for a dependency ID. + * @returns {String} normalized name + */ + function normalize(name, baseName, applyMap) { + var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment, + foundMap, foundI, foundStarMap, starI, + baseParts = baseName && baseName.split('/'), + normalizedBaseParts = baseParts, + map = config.map, + starMap = map && map['*']; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + if (getOwn(config.pkgs, baseName)) { + //If the baseName is a package name, then just treat it as one + //name to concat the name with. + normalizedBaseParts = baseParts = [baseName]; + } else { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + } + + name = normalizedBaseParts.concat(name.split('/')); + trimDots(name); + + //Some use of packages may use a . path to reference the + //'main' module name, so normalize for that. + pkgConfig = getOwn(config.pkgs, (pkgName = name[0])); + name = name.join('/'); + if (pkgConfig && name === pkgName + '/' + pkgConfig.main) { + name = pkgName; + } + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if (applyMap && (baseParts || starMap) && map) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join('/'); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = getOwn(map, baseParts.slice(0, j).join('/')); + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = getOwn(mapValue, nameSegment); + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { + foundStarMap = getOwn(starMap, nameSegment); + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function removeScript(name) { + if (isBrowser) { + each(scripts(), function (scriptNode) { + if (scriptNode.getAttribute('data-requiremodule') === name && + scriptNode.getAttribute('data-requirecontext') === context.contextName) { + scriptNode.parentNode.removeChild(scriptNode); + return true; + } + }); + } + } + + function hasPathFallback(id) { + var pathConfig = getOwn(config.paths, id); + if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { + removeScript(id); + //Pop off the first array value, since it failed, and + //retry + pathConfig.shift(); + context.require.undef(id); + context.require([id]); + return true; + } + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Creates a module mapping that includes plugin prefix, module + * name, and path. If parentModuleMap is provided it will + * also normalize the name via require.normalize() + * + * @param {String} name the module name + * @param {String} [parentModuleMap] parent module map + * for the module name, used to resolve relative names. + * @param {Boolean} isNormalized: is the ID already normalized. + * This is true if this call is done for a define() module ID. + * @param {Boolean} applyMap: apply the map config to the ID. + * Should only be true if this map is for a dependency. + * + * @returns {Object} + */ + function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { + var url, pluginModule, suffix, nameParts, + prefix = null, + parentName = parentModuleMap ? parentModuleMap.name : null, + originalName = name, + isDefine = true, + normalizedName = ''; + + //If no name, then it means it is a require call, generate an + //internal name. + if (!name) { + isDefine = false; + name = '_@r' + (requireCounter += 1); + } + + nameParts = splitPrefix(name); + prefix = nameParts[0]; + name = nameParts[1]; + + if (prefix) { + prefix = normalize(prefix, parentName, applyMap); + pluginModule = getOwn(defined, prefix); + } + + //Account for relative paths if there is a base name. + if (name) { + if (prefix) { + if (pluginModule && pluginModule.normalize) { + //Plugin is loaded, use its normalize method. + normalizedName = pluginModule.normalize(name, function (name) { + return normalize(name, parentName, applyMap); + }); + } else { + normalizedName = normalize(name, parentName, applyMap); + } + } else { + //A regular module. + normalizedName = normalize(name, parentName, applyMap); + + //Normalized name may be a plugin ID due to map config + //application in normalize. The map config values must + //already be normalized, so do not need to redo that part. + nameParts = splitPrefix(normalizedName); + prefix = nameParts[0]; + normalizedName = nameParts[1]; + isNormalized = true; + + url = context.nameToUrl(normalizedName); + } + } + + //If the id is a plugin id that cannot be determined if it needs + //normalization, stamp it with a unique ID so two matching relative + //ids that may conflict can be separate. + suffix = prefix && !pluginModule && !isNormalized ? + '_unnormalized' + (unnormalizedCounter += 1) : + ''; + + return { + prefix: prefix, + name: normalizedName, + parentMap: parentModuleMap, + unnormalized: !!suffix, + url: url, + originalName: originalName, + isDefine: isDefine, + id: (prefix ? + prefix + '!' + normalizedName : + normalizedName) + suffix + }; + } + + function getModule(depMap) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (!mod) { + mod = registry[id] = new context.Module(depMap); + } + + return mod; + } + + function on(depMap, name, fn) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (hasProp(defined, id) && + (!mod || mod.defineEmitComplete)) { + if (name === 'defined') { + fn(defined[id]); + } + } else { + getModule(depMap).on(name, fn); + } + } + + function onError(err, errback) { + var ids = err.requireModules, + notified = false; + + if (errback) { + errback(err); + } else { + each(ids, function (id) { + var mod = getOwn(registry, id); + if (mod) { + //Set error on module, so it skips timeout checks. + mod.error = err; + if (mod.events.error) { + notified = true; + mod.emit('error', err); + } + } + }); + + if (!notified) { + req.onError(err); + } + } + } + + /** + * Internal method to transfer globalQueue items to this context's + * defQueue. + */ + function takeGlobalQueue() { + //Push all the globalDefQueue items into the context's defQueue + if (globalDefQueue.length) { + //Array splice in the values since the context code has a + //local var ref to defQueue, so cannot just reassign the one + //on context. + apsp.apply(defQueue, + [defQueue.length - 1, 0].concat(globalDefQueue)); + globalDefQueue = []; + } + } + + handlers = { + 'require': function (mod) { + if (mod.require) { + return mod.require; + } else { + return (mod.require = context.makeRequire(mod.map)); + } + }, + 'exports': function (mod) { + mod.usingExports = true; + if (mod.map.isDefine) { + if (mod.exports) { + return mod.exports; + } else { + return (mod.exports = defined[mod.map.id] = {}); + } + } + }, + 'module': function (mod) { + if (mod.module) { + return mod.module; + } else { + return (mod.module = { + id: mod.map.id, + uri: mod.map.url, + config: function () { + return (config.config && getOwn(config.config, mod.map.id)) || {}; + }, + exports: defined[mod.map.id] + }); + } + } + }; + + function cleanRegistry(id) { + //Clean up machinery used for waiting modules. + delete registry[id]; + } + + function breakCycle(mod, traced, processed) { + var id = mod.map.id; + + if (mod.error) { + mod.emit('error', mod.error); + } else { + traced[id] = true; + each(mod.depMaps, function (depMap, i) { + var depId = depMap.id, + dep = getOwn(registry, depId); + + //Only force things that have not completed + //being defined, so still in the registry, + //and only if it has not been matched up + //in the module already. + if (dep && !mod.depMatched[i] && !processed[depId]) { + if (getOwn(traced, depId)) { + mod.defineDep(i, defined[depId]); + mod.check(); //pass false? + } else { + breakCycle(dep, traced, processed); + } + } + }); + processed[id] = true; + } + } + + function checkLoaded() { + var map, modId, err, usingPathFallback, + waitInterval = config.waitSeconds * 1000, + //It is possible to disable the wait interval by using waitSeconds of 0. + expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), + noLoads = [], + reqCalls = [], + stillLoading = false, + needCycleCheck = true; + + //Do not bother if this call was a result of a cycle break. + if (inCheckLoaded) { + return; + } + + inCheckLoaded = true; + + //Figure out the state of all the modules. + eachProp(registry, function (mod) { + map = mod.map; + modId = map.id; + + //Skip things that are not enabled or in error state. + if (!mod.enabled) { + return; + } + + if (!map.isDefine) { + reqCalls.push(mod); + } + + if (!mod.error) { + //If the module should be executed, and it has not + //been inited and time is up, remember it. + if (!mod.inited && expired) { + if (hasPathFallback(modId)) { + usingPathFallback = true; + stillLoading = true; + } else { + noLoads.push(modId); + removeScript(modId); + } + } else if (!mod.inited && mod.fetched && map.isDefine) { + stillLoading = true; + if (!map.prefix) { + //No reason to keep looking for unfinished + //loading. If the only stillLoading is a + //plugin resource though, keep going, + //because it may be that a plugin resource + //is waiting on a non-plugin cycle. + return (needCycleCheck = false); + } + } + } + }); + + if (expired && noLoads.length) { + //If wait time expired, throw error of unloaded modules. + err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); + err.contextName = context.contextName; + return onError(err); + } + + //Not expired, check for a cycle. + if (needCycleCheck) { + each(reqCalls, function (mod) { + breakCycle(mod, {}, {}); + }); + } + + //If still waiting on loads, and the waiting load is something + //other than a plugin resource, or there are still outstanding + //scripts, then just try back later. + if ((!expired || usingPathFallback) && stillLoading) { + //Something is still waiting to load. Wait for it, but only + //if a timeout is not already in effect. + if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { + checkLoadedTimeoutId = setTimeout(function () { + checkLoadedTimeoutId = 0; + checkLoaded(); + }, 50); + } + } + + inCheckLoaded = false; + } + + Module = function (map) { + this.events = getOwn(undefEvents, map.id) || {}; + this.map = map; + this.shim = getOwn(config.shim, map.id); + this.depExports = []; + this.depMaps = []; + this.depMatched = []; + this.pluginMaps = {}; + this.depCount = 0; + + /* this.exports this.factory + this.depMaps = [], + this.enabled, this.fetched + */ + }; + + Module.prototype = { + init: function (depMaps, factory, errback, options) { + options = options || {}; + + //Do not do more inits if already done. Can happen if there + //are multiple define calls for the same module. That is not + //a normal, common case, but it is also not unexpected. + if (this.inited) { + return; + } + + this.factory = factory; + + if (errback) { + //Register for errors on this module. + this.on('error', errback); + } else if (this.events.error) { + //If no errback already, but there are error listeners + //on this module, set up an errback to pass to the deps. + errback = bind(this, function (err) { + this.emit('error', err); + }); + } + + //Do a copy of the dependency array, so that + //source inputs are not modified. For example + //"shim" deps are passed in here directly, and + //doing a direct modification of the depMaps array + //would affect that config. + this.depMaps = depMaps && depMaps.slice(0); + + this.errback = errback; + + //Indicate this module has be initialized + this.inited = true; + + this.ignore = options.ignore; + + //Could have option to init this module in enabled mode, + //or could have been previously marked as enabled. However, + //the dependencies are not known until init is called. So + //if enabled previously, now trigger dependencies as enabled. + if (options.enabled || this.enabled) { + //Enable this module and dependencies. + //Will call this.check() + this.enable(); + } else { + this.check(); + } + }, + + defineDep: function (i, depExports) { + //Because of cycles, defined callback for a given + //export can be called more than once. + if (!this.depMatched[i]) { + this.depMatched[i] = true; + this.depCount -= 1; + this.depExports[i] = depExports; + } + }, + + fetch: function () { + if (this.fetched) { + return; + } + this.fetched = true; + + context.startTime = (new Date()).getTime(); + + var map = this.map; + + //If the manager is for a plugin managed resource, + //ask the plugin to load it now. + if (this.shim) { + context.makeRequire(this.map, { + enableBuildCallback: true + })(this.shim.deps || [], bind(this, function () { + return map.prefix ? this.callPlugin() : this.load(); + })); + } else { + //Regular dependency. + return map.prefix ? this.callPlugin() : this.load(); + } + }, + + load: function () { + var url = this.map.url; + + //Regular dependency. + if (!urlFetched[url]) { + urlFetched[url] = true; + context.load(this.map.id, url); + } + }, + + /** + * Checks is the module is ready to define itself, and if so, + * define it. + */ + check: function () { + if (!this.enabled || this.enabling) { + return; + } + + var err, cjsModule, + id = this.map.id, + depExports = this.depExports, + exports = this.exports, + factory = this.factory; + + if (!this.inited) { + this.fetch(); + } else if (this.error) { + this.emit('error', this.error); + } else if (!this.defining) { + //The factory could trigger another require call + //that would result in checking this module to + //define itself again. If already in the process + //of doing that, skip this work. + this.defining = true; + + if (this.depCount < 1 && !this.defined) { + if (isFunction(factory)) { + //If there is an error listener, favor passing + //to that instead of throwing an error. + if (this.events.error) { + try { + exports = context.execCb(id, factory, depExports, exports); + } catch (e) { + err = e; + } + } else { + exports = context.execCb(id, factory, depExports, exports); + } + + if (this.map.isDefine) { + //If setting exports via 'module' is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + cjsModule = this.module; + if (cjsModule && + cjsModule.exports !== undefined && + //Make sure it is not already the exports value + cjsModule.exports !== this.exports) { + exports = cjsModule.exports; + } else if (exports === undefined && this.usingExports) { + //exports already set the defined value. + exports = this.exports; + } + } + + if (err) { + err.requireMap = this.map; + err.requireModules = [this.map.id]; + err.requireType = 'define'; + return onError((this.error = err)); + } + + } else { + //Just a literal value + exports = factory; + } + + this.exports = exports; + + if (this.map.isDefine && !this.ignore) { + defined[id] = exports; + + if (req.onResourceLoad) { + req.onResourceLoad(context, this.map, this.depMaps); + } + } + + //Clean up + delete registry[id]; + + this.defined = true; + } + + //Finished the define stage. Allow calling check again + //to allow define notifications below in the case of a + //cycle. + this.defining = false; + + if (this.defined && !this.defineEmitted) { + this.defineEmitted = true; + this.emit('defined', this.exports); + this.defineEmitComplete = true; + } + + } + }, + + callPlugin: function () { + var map = this.map, + id = map.id, + //Map already normalized the prefix. + pluginMap = makeModuleMap(map.prefix); + + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(pluginMap); + + on(pluginMap, 'defined', bind(this, function (plugin) { + var load, normalizedMap, normalizedMod, + name = this.map.name, + parentName = this.map.parentMap ? this.map.parentMap.name : null, + localRequire = context.makeRequire(map.parentMap, { + enableBuildCallback: true, + skipMap: true + }); + + //If current map is not normalized, wait for that + //normalized name to load instead of continuing. + if (this.map.unnormalized) { + //Normalize the ID if the plugin allows it. + if (plugin.normalize) { + name = plugin.normalize(name, function (name) { + return normalize(name, parentName, true); + }) || ''; + } + + //prefix and name should already be normalized, no need + //for applying map config again either. + normalizedMap = makeModuleMap(map.prefix + '!' + name, + this.map.parentMap); + on(normalizedMap, + 'defined', bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true, + ignore: true + }); + })); + + normalizedMod = getOwn(registry, normalizedMap.id); + if (normalizedMod) { + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(normalizedMap); + + if (this.events.error) { + normalizedMod.on('error', bind(this, function (err) { + this.emit('error', err); + })); + } + normalizedMod.enable(); + } + + return; + } + + load = bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true + }); + }); + + load.error = bind(this, function (err) { + this.inited = true; + this.error = err; + err.requireModules = [id]; + + //Remove temp unnormalized modules for this module, + //since they will never be resolved otherwise now. + eachProp(registry, function (mod) { + if (mod.map.id.indexOf(id + '_unnormalized') === 0) { + cleanRegistry(mod.map.id); + } + }); + + onError(err); + }); + + //Allow plugins to load other code without having to know the + //context or how to 'complete' the load. + load.fromText = bind(this, function (text, textAlt) { + /*jslint evil: true */ + var moduleName = map.name, + moduleMap = makeModuleMap(moduleName), + hasInteractive = useInteractive; + + //As of 2.1.0, support just passing the text, to reinforce + //fromText only being called once per resource. Still + //support old style of passing moduleName but discard + //that moduleName in favor of the internal ref. + if (textAlt) { + text = textAlt; + } + + //Turn off interactive script matching for IE for any define + //calls in the text, then turn it back on at the end. + if (hasInteractive) { + useInteractive = false; + } + + //Prime the system by creating a module instance for + //it. + getModule(moduleMap); + + //Transfer any config to this other module. + if (hasProp(config.config, id)) { + config.config[moduleName] = config.config[id]; + } + + try { + req.exec(text); + } catch (e) { + throw new Error('fromText eval for ' + moduleName + + ' failed: ' + e); + } + + if (hasInteractive) { + useInteractive = true; + } + + //Mark this as a dependency for the plugin + //resource + this.depMaps.push(moduleMap); + + //Support anonymous modules. + context.completeLoad(moduleName); + + //Bind the value of that module to the value for this + //resource ID. + localRequire([moduleName], load); + }); + + //Use parentName here since the plugin's name is not reliable, + //could be some weird string with no path that actually wants to + //reference the parentName's path. + plugin.load(map.name, localRequire, load, config); + })); + + context.enable(pluginMap, this); + this.pluginMaps[pluginMap.id] = pluginMap; + }, + + enable: function () { + this.enabled = true; + + //Set flag mentioning that the module is enabling, + //so that immediate calls to the defined callbacks + //for dependencies do not trigger inadvertent load + //with the depCount still being zero. + this.enabling = true; + + //Enable each dependency + each(this.depMaps, bind(this, function (depMap, i) { + var id, mod, handler; + + if (typeof depMap === 'string') { + //Dependency needs to be converted to a depMap + //and wired up to this module. + depMap = makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap), + false, + !this.skipMap); + this.depMaps[i] = depMap; + + handler = getOwn(handlers, depMap.id); + + if (handler) { + this.depExports[i] = handler(this); + return; + } + + this.depCount += 1; + + on(depMap, 'defined', bind(this, function (depExports) { + this.defineDep(i, depExports); + this.check(); + })); + + if (this.errback) { + on(depMap, 'error', this.errback); + } + } + + id = depMap.id; + mod = registry[id]; + + //Skip special modules like 'require', 'exports', 'module' + //Also, don't call enable if it is already enabled, + //important in circular dependency cases. + if (!hasProp(handlers, id) && mod && !mod.enabled) { + context.enable(depMap, this); + } + })); + + //Enable each plugin that is used in + //a dependency + eachProp(this.pluginMaps, bind(this, function (pluginMap) { + var mod = getOwn(registry, pluginMap.id); + if (mod && !mod.enabled) { + context.enable(pluginMap, this); + } + })); + + this.enabling = false; + + this.check(); + }, + + on: function (name, cb) { + var cbs = this.events[name]; + if (!cbs) { + cbs = this.events[name] = []; + } + cbs.push(cb); + }, + + emit: function (name, evt) { + each(this.events[name], function (cb) { + cb(evt); + }); + if (name === 'error') { + //Now that the error handler was triggered, remove + //the listeners, since this broken Module instance + //can stay around for a while in the registry. + delete this.events[name]; + } + } + }; + + function callGetModule(args) { + //Skip modules already defined. + if (!hasProp(defined, args[0])) { + getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); + } + } + + function removeListener(node, func, name, ieName) { + //Favor detachEvent because of IE9 + //issue, see attachEvent/addEventListener comment elsewhere + //in this file. + if (node.detachEvent && !isOpera) { + //Probably IE. If not it will throw an error, which will be + //useful to know. + if (ieName) { + node.detachEvent(ieName, func); + } + } else { + node.removeEventListener(name, func, false); + } + } + + /** + * Given an event from a script node, get the requirejs info from it, + * and then removes the event listeners on the node. + * @param {Event} evt + * @returns {Object} + */ + function getScriptData(evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + var node = evt.currentTarget || evt.srcElement; + + //Remove the listeners once here. + removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); + removeListener(node, context.onScriptError, 'error'); + + return { + node: node, + id: node && node.getAttribute('data-requiremodule') + }; + } + + function intakeDefines() { + var args; + + //Any defined modules in the global queue, intake them now. + takeGlobalQueue(); + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); + } else { + //args are id, deps, factory. Should be normalized by the + //define() function. + callGetModule(args); + } + } + } + + context = { + config: config, + contextName: contextName, + registry: registry, + defined: defined, + urlFetched: urlFetched, + defQueue: defQueue, + Module: Module, + makeModuleMap: makeModuleMap, + nextTick: req.nextTick, + + /** + * Set a configuration for the context. + * @param {Object} cfg config object to integrate. + */ + configure: function (cfg) { + //Make sure the baseUrl ends in a slash. + if (cfg.baseUrl) { + if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { + cfg.baseUrl += '/'; + } + } + + //Save off the paths and packages since they require special processing, + //they are additive. + var pkgs = config.pkgs, + shim = config.shim, + objs = { + paths: true, + config: true, + map: true + }; + + eachProp(cfg, function (value, prop) { + if (objs[prop]) { + if (prop === 'map') { + mixin(config[prop], value, true, true); + } else { + mixin(config[prop], value, true); + } + } else { + config[prop] = value; + } + }); + + //Merge shim + if (cfg.shim) { + eachProp(cfg.shim, function (value, id) { + //Normalize the structure + if (isArray(value)) { + value = { + deps: value + }; + } + if ((value.exports || value.init) && !value.exportsFn) { + value.exportsFn = context.makeShimExports(value); + } + shim[id] = value; + }); + config.shim = shim; + } + + //Adjust packages if necessary. + if (cfg.packages) { + each(cfg.packages, function (pkgObj) { + var location; + + pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj; + location = pkgObj.location; + + //Create a brand new object on pkgs, since currentPackages can + //be passed in again, and config.pkgs is the internal transformed + //state for all package configs. + pkgs[pkgObj.name] = { + name: pkgObj.name, + location: location || pkgObj.name, + //Remove leading dot in main, so main paths are normalized, + //and remove any trailing .js, since different package + //envs have different conventions: some use a module name, + //some use a file name. + main: (pkgObj.main || 'main') + .replace(currDirRegExp, '') + .replace(jsSuffixRegExp, '') + }; + }); + + //Done with modifications, assing packages back to context config + config.pkgs = pkgs; + } + + //If there are any "waiting to execute" modules in the registry, + //update the maps for them, since their info, like URLs to load, + //may have changed. + eachProp(registry, function (mod, id) { + //If module already has init called, since it is too + //late to modify them, and ignore unnormalized ones + //since they are transient. + if (!mod.inited && !mod.map.unnormalized) { + mod.map = makeModuleMap(id); + } + }); + + //If a deps array or a config callback is specified, then call + //require with those args. This is useful when require is defined as a + //config object before require.js is loaded. + if (cfg.deps || cfg.callback) { + context.require(cfg.deps || [], cfg.callback); + } + }, + + makeShimExports: function (value) { + function fn() { + var ret; + if (value.init) { + ret = value.init.apply(global, arguments); + } + return ret || (value.exports && getGlobal(value.exports)); + } + return fn; + }, + + makeRequire: function (relMap, options) { + options = options || {}; + + function localRequire(deps, callback, errback) { + var id, map, requireMod; + + if (options.enableBuildCallback && callback && isFunction(callback)) { + callback.__requireJsBuild = true; + } + + if (typeof deps === 'string') { + if (isFunction(callback)) { + //Invalid call + return onError(makeError('requireargs', 'Invalid require call'), errback); + } + + //If require|exports|module are requested, get the + //value for them from the special handlers. Caveat: + //this only works while module is being defined. + if (relMap && hasProp(handlers, deps)) { + return handlers[deps](registry[relMap.id]); + } + + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + if (req.get) { + return req.get(context, deps, relMap); + } + + //Normalize module name, if it contains . or .. + map = makeModuleMap(deps, relMap, false, true); + id = map.id; + + if (!hasProp(defined, id)) { + return onError(makeError('notloaded', 'Module name "' + + id + + '" has not been loaded yet for context: ' + + contextName + + (relMap ? '' : '. Use require([])'))); + } + return defined[id]; + } + + //Grab defines waiting in the global queue. + intakeDefines(); + + //Mark all the dependencies as needing to be loaded. + context.nextTick(function () { + //Some defines could have been added since the + //require call, collect them. + intakeDefines(); + + requireMod = getModule(makeModuleMap(null, relMap)); + + //Store if map config should be applied to this require + //call for dependencies. + requireMod.skipMap = options.skipMap; + + requireMod.init(deps, callback, errback, { + enabled: true + }); + + checkLoaded(); + }); + + return localRequire; + } + + mixin(localRequire, { + isBrowser: isBrowser, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt) { + var index = moduleNamePlusExt.lastIndexOf('.'), + ext = null; + + if (index !== -1) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + return context.nameToUrl(normalize(moduleNamePlusExt, + relMap && relMap.id, true), ext); + }, + + defined: function (id) { + return hasProp(defined, makeModuleMap(id, relMap, false, true).id); + }, + + specified: function (id) { + id = makeModuleMap(id, relMap, false, true).id; + return hasProp(defined, id) || hasProp(registry, id); + } + }); + + //Only allow undef on top level require calls + if (!relMap) { + localRequire.undef = function (id) { + //Bind any waiting define() calls to this context, + //fix for #408 + takeGlobalQueue(); + + var map = makeModuleMap(id, relMap, true), + mod = getOwn(registry, id); + + delete defined[id]; + delete urlFetched[map.url]; + delete undefEvents[id]; + + if (mod) { + //Hold on to listeners in case the + //module will be attempted to be reloaded + //using a different config. + if (mod.events.defined) { + undefEvents[id] = mod.events; + } + + cleanRegistry(id); + } + }; + } + + return localRequire; + }, + + /** + * Called to enable a module if it is still in the registry + * awaiting enablement. parent module is passed in for context, + * used by the optimizer. + */ + enable: function (depMap, parent) { + var mod = getOwn(registry, depMap.id); + if (mod) { + getModule(depMap).enable(); + } + }, + + /** + * Internal method used by environment adapters to complete a load event. + * A load event could be a script load or just a load pass from a synchronous + * load call. + * @param {String} moduleName the name of the module to potentially complete. + */ + completeLoad: function (moduleName) { + var found, args, mod, + shim = getOwn(config.shim, moduleName) || {}, + shExports = shim.exports; + + takeGlobalQueue(); + + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + args[0] = moduleName; + //If already found an anonymous module and bound it + //to this name, then this is some other anon module + //waiting for its completeLoad to fire. + if (found) { + break; + } + found = true; + } else if (args[0] === moduleName) { + //Found matching define call for this script! + found = true; + } + + callGetModule(args); + } + + //Do this after the cycle of callGetModule in case the result + //of those calls/init calls changes the registry. + mod = getOwn(registry, moduleName); + + if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { + if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { + if (hasPathFallback(moduleName)) { + return; + } else { + return onError(makeError('nodefine', + 'No define call for ' + moduleName, + null, + [moduleName])); + } + } else { + //A script that does not call define(), so just simulate + //the call for it. + callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); + } + } + + checkLoaded(); + }, + + /** + * Converts a module name to a file path. Supports cases where + * moduleName may actually be just an URL. + * Note that it **does not** call normalize on the moduleName, + * it is assumed to have already been normalized. This is an + * internal API, not a public one. Use toUrl for the public API. + */ + nameToUrl: function (moduleName, ext) { + var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, + parentPath; + + //If a colon is in the URL, it indicates a protocol is used and it is just + //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) + //or ends with .js, then assume the user meant to use an url and not a module id. + //The slash is important for protocol-less URLs as well as full paths. + if (req.jsExtRegExp.test(moduleName)) { + //Just a plain path, not module name lookup, so just return it. + //Add extension if it is included. This is a bit wonky, only non-.js things pass + //an extension, this method probably needs to be reworked. + url = moduleName + (ext || ''); + } else { + //A module that needs to be converted to a path. + paths = config.paths; + pkgs = config.pkgs; + + syms = moduleName.split('/'); + //For each module name segment, see if there is a path + //registered for it. Start with most specific name + //and work up from it. + for (i = syms.length; i > 0; i -= 1) { + parentModule = syms.slice(0, i).join('/'); + pkg = getOwn(pkgs, parentModule); + parentPath = getOwn(paths, parentModule); + if (parentPath) { + //If an array, it means there are a few choices, + //Choose the one that is desired + if (isArray(parentPath)) { + parentPath = parentPath[0]; + } + syms.splice(0, i, parentPath); + break; + } else if (pkg) { + //If module name is just the package name, then looking + //for the main module. + if (moduleName === pkg.name) { + pkgPath = pkg.location + '/' + pkg.main; + } else { + pkgPath = pkg.location; + } + syms.splice(0, i, pkgPath); + break; + } + } + + //Join the path parts together, then figure out if baseUrl is needed. + url = syms.join('/'); + url += (ext || (/\?/.test(url) ? '' : '.js')); + url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; + } + + return config.urlArgs ? url + + ((url.indexOf('?') === -1 ? '?' : '&') + + config.urlArgs) : url; + }, + + //Delegates to req.load. Broken out as a separate function to + //allow overriding in the optimizer. + load: function (id, url) { + req.load(context, id, url); + }, + + /** + * Executes a module callack function. Broken out as a separate function + * solely to allow the build system to sequence the files in the built + * layer in the right sequence. + * + * @private + */ + execCb: function (name, callback, args, exports) { + return callback.apply(exports, args); + }, + + /** + * callback for script loads, used to check status of loading. + * + * @param {Event} evt the event from the browser for the script + * that was loaded. + */ + onScriptLoad: function (evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + if (evt.type === 'load' || + (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { + //Reset interactive script so a script node is not held onto for + //to long. + interactiveScript = null; + + //Pull out the name of the module and the context. + var data = getScriptData(evt); + context.completeLoad(data.id); + } + }, + + /** + * Callback for script errors. + */ + onScriptError: function (evt) { + var data = getScriptData(evt); + if (!hasPathFallback(data.id)) { + return onError(makeError('scripterror', 'Script error', evt, [data.id])); + } + } + }; + + context.require = context.makeRequire(); + return context; + } + + /** + * Main entry point. + * + * If the only argument to require is a string, then the module that + * is represented by that string is fetched for the appropriate context. + * + * If the first argument is an array, then it will be treated as an array + * of dependency string names to fetch. An optional function callback can + * be specified to execute when all of those dependencies are available. + * + * Make a local req variable to help Caja compliance (it assumes things + * on a require that are not standardized), and to give a short + * name for minification/local scope use. + */ + req = requirejs = function (deps, callback, errback, optional) { + + //Find the right context, use default + var context, config, + contextName = defContextName; + + // Determine if have config object in the call. + if (!isArray(deps) && typeof deps !== 'string') { + // deps is a config object + config = deps; + if (isArray(callback)) { + // Adjust args if there are dependencies + deps = callback; + callback = errback; + errback = optional; + } else { + deps = []; + } + } + + if (config && config.context) { + contextName = config.context; + } + + context = getOwn(contexts, contextName); + if (!context) { + context = contexts[contextName] = req.s.newContext(contextName); + } + + if (config) { + context.configure(config); + } + + return context.require(deps, callback, errback); + }; + + /** + * Support require.config() to make it easier to cooperate with other + * AMD loaders on globally agreed names. + */ + req.config = function (config) { + return req(config); + }; + + /** + * Execute something after the current tick + * of the event loop. Override for other envs + * that have a better solution than setTimeout. + * @param {Function} fn function to execute later. + */ + req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { + setTimeout(fn, 4); + } : function (fn) { fn(); }; + + /** + * Export require as a global, but only if it does not already exist. + */ + if (!require) { + require = req; + } + + req.version = version; + + //Used to filter out dependencies that are already paths. + req.jsExtRegExp = /^\/|:|\?|\.js$/; + req.isBrowser = isBrowser; + s = req.s = { + contexts: contexts, + newContext: newContext + }; + + //Create default context. + req({}); + + //Exports some context-sensitive methods on global require. + each([ + 'toUrl', + 'undef', + 'defined', + 'specified' + ], function (prop) { + //Reference from contexts instead of early binding to default context, + //so that during builds, the latest instance of the default context + //with its config gets used. + req[prop] = function () { + var ctx = contexts[defContextName]; + return ctx.require[prop].apply(ctx, arguments); + }; + }); + + if (isBrowser) { + head = s.head = document.getElementsByTagName('head')[0]; + //If BASE tag is in play, using appendChild is a problem for IE6. + //When that browser dies, this can be removed. Details in this jQuery bug: + //http://dev.jquery.com/ticket/2709 + baseElement = document.getElementsByTagName('base')[0]; + if (baseElement) { + head = s.head = baseElement.parentNode; + } + } + + /** + * Any errors that require explicitly generates will be passed to this + * function. Intercept/override it if you want custom error handling. + * @param {Error} err the error object. + */ + req.onError = function (err) { + throw err; + }; + + /** + * Does the request to load a module for the browser case. + * Make this a separate function to allow other environments + * to override it. + * + * @param {Object} context the require context to find state. + * @param {String} moduleName the name of the module. + * @param {Object} url the URL to the module. + */ + req.load = function (context, moduleName, url) { + var config = (context && context.config) || {}, + node; + if (isBrowser) { + //In the browser so use a script tag + node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + + node.setAttribute('data-requirecontext', context.contextName); + node.setAttribute('data-requiremodule', moduleName); + + //Set up load listener. Test attachEvent first because IE9 has + //a subtle issue in its addEventListener and script onload firings + //that do not match the behavior of all other browsers with + //addEventListener support, which fire the onload event for a + //script right after the script execution. See: + //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution + //UNFORTUNATELY Opera implements attachEvent but does not follow the script + //script execution mode. + if (node.attachEvent && + //Check if node.attachEvent is artificially added by custom script or + //natively supported by browser + //read https://github.com/jrburke/requirejs/issues/187 + //if we can NOT find [native code] then it must NOT natively supported. + //in IE8, node.attachEvent does not have toString() + //Note the test for "[native code" with no closing brace, see: + //https://github.com/jrburke/requirejs/issues/273 + !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && + !isOpera) { + //Probably IE. IE (at least 6-8) do not fire + //script onload right after executing the script, so + //we cannot tie the anonymous define call to a name. + //However, IE reports the script as being in 'interactive' + //readyState at the time of the define call. + useInteractive = true; + + node.attachEvent('onreadystatechange', context.onScriptLoad); + //It would be great to add an error handler here to catch + //404s in IE9+. However, onreadystatechange will fire before + //the error handler, so that does not help. If addEvenListener + //is used, then IE will fire error before load, but we cannot + //use that pathway given the connect.microsoft.com issue + //mentioned above about not doing the 'script execute, + //then fire the script load event listener before execute + //next script' that other browsers do. + //Best hope: IE10 fixes the issues, + //and then destroys all installs of IE 6-9. + //node.attachEvent('onerror', context.onScriptError); + } else { + node.addEventListener('load', context.onScriptLoad, false); + node.addEventListener('error', context.onScriptError, false); + } + node.src = url; + + //For some cache cases in IE 6-8, the script executes before the end + //of the appendChild execution, so to tie an anonymous define + //call to the module name (which is stored on the node), hold on + //to a reference to this node, but clear after the DOM insertion. + currentlyAddingScript = node; + if (baseElement) { + head.insertBefore(node, baseElement); + } else { + head.appendChild(node); + } + currentlyAddingScript = null; + + return node; + } else if (isWebWorker) { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation that a build has been done so that + //only one script needs to be loaded anyway. This may need to be + //reevaluated if other use cases become common. + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } + }; + + function getInteractiveScript() { + if (interactiveScript && interactiveScript.readyState === 'interactive') { + return interactiveScript; + } + + eachReverse(scripts(), function (script) { + if (script.readyState === 'interactive') { + return (interactiveScript = script); + } + }); + return interactiveScript; + } + + //Look for a data-main script attribute, which could also adjust the baseUrl. + if (isBrowser) { + //Figure out baseUrl. Get it from the script tag with require.js in it. + eachReverse(scripts(), function (script) { + //Set the 'head' where we can append children by + //using the script's parent. + if (!head) { + head = script.parentNode; + } + + //Look for a data-main attribute to set main script for the page + //to load. If it is there, the path to data main becomes the + //baseUrl, if it is not already set. + dataMain = script.getAttribute('data-main'); + if (dataMain) { + //Set final baseUrl if there is not already an explicit one. + if (!cfg.baseUrl) { + //Pull off the directory of data-main for use as the + //baseUrl. + src = dataMain.split('/'); + mainScript = src.pop(); + subPath = src.length ? src.join('/') + '/' : './'; + + cfg.baseUrl = subPath; + dataMain = mainScript; + } + + //Strip off any trailing .js since dataMain is now + //like a module name. + dataMain = dataMain.replace(jsSuffixRegExp, ''); + + //Put the data-main script in the files to load. + cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain]; + + return true; + } + }); + } + + /** + * The function that handles definitions of modules. Differs from + * require() in that a string for the module should be the first argument, + * and the function to execute after dependencies are loaded should + * return a value to define the module corresponding to the first argument's + * name. + */ + define = function (name, deps, callback) { + var node, context; + + //Allow for anonymous modules + if (typeof name !== 'string') { + //Adjust args appropriately + callback = deps; + deps = name; + name = null; + } + + //This module may not have dependencies + if (!isArray(deps)) { + callback = deps; + deps = []; + } + + //If no name, and callback is a function, then figure out if it a + //CommonJS thing with dependencies. + if (!deps.length && isFunction(callback)) { + //Remove comments from the callback string, + //look for require calls, and pull them into the dependencies, + //but only if there are function args. + if (callback.length) { + callback + .toString() + .replace(commentRegExp, '') + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + + //May be a CommonJS thing even without require calls, but still + //could use exports, and module. Avoid doing exports and module + //work though if it just needs require. + //REQUIRES the function to expect the CommonJS variables in the + //order listed below. + deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); + } + } + + //If in IE 6-8 and hit an anonymous define() call, do the interactive + //work. + if (useInteractive) { + node = currentlyAddingScript || getInteractiveScript(); + if (node) { + if (!name) { + name = node.getAttribute('data-requiremodule'); + } + context = contexts[node.getAttribute('data-requirecontext')]; + } + } + + //Always save off evaluating the def call until the script onload handler. + //This allows multiple modules to be in a file without prematurely + //tracing dependencies, and allows for anonymous module support, + //where the module name is not known until the script onload event + //occurs. If no context, use the global queue, and get it processed + //in the onscript load callback. + (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); + }; + + define.amd = { + jQuery: true + }; + + + /** + * Executes the text. Normally just uses eval, but can be modified + * to use a better, environment-specific call. Only used for transpiling + * loader plugins, not for plain JS modules. + * @param {String} text the text to execute/evaluate. + */ + req.exec = function (text) { + /*jslint evil: true */ + return eval(text); + }; + + //Set up with config info. + req(cfg); +}(this)); diff --git a/server/src/com/cloud/baremetal/BareMetalVmManager.java b/ui/plugins/plugins.js similarity index 86% rename from server/src/com/cloud/baremetal/BareMetalVmManager.java rename to ui/plugins/plugins.js index 900c57fdf80..386ec062bb0 100644 --- a/server/src/com/cloud/baremetal/BareMetalVmManager.java +++ b/ui/plugins/plugins.js @@ -14,9 +14,8 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.baremetal; - -import com.cloud.vm.UserVmManager; - -public interface BareMetalVmManager extends UserVmManager { -} +(function($, cloudStack) { + cloudStack.plugins = [ + // 'testPlugin' + ]; +}(jQuery, cloudStack)); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDao.java b/ui/plugins/testPlugin/config.js old mode 100755 new mode 100644 similarity index 73% rename from plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDao.java rename to ui/plugins/testPlugin/config.js index 0f20c677f5d..71cb3791c18 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDao.java +++ b/ui/plugins/testPlugin/config.js @@ -5,21 +5,21 @@ // 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. -// -// Automatically generated by addcopyright.py at 01/29/2013 -package com.cloud.baremetal.database; - -import com.cloud.utils.db.GenericDao; - -public interface BaremetalCmdbDao extends GenericDao { - -} +(function (cloudStack) { + cloudStack.plugins.testPlugin.config = { + title: 'Test Plugin', + desc: 'Sample plugin', + externalLink: 'http://www.cloudstack.org/', + authorName: 'Test Plugin Developer', + authorEmail: 'plugin.developer@example.com' + }; +}(cloudStack)); \ No newline at end of file diff --git a/ui/plugins/testPlugin/icon.png b/ui/plugins/testPlugin/icon.png new file mode 100644 index 00000000000..a313d35328c Binary files /dev/null and b/ui/plugins/testPlugin/icon.png differ diff --git a/ui/plugins/testPlugin/testPlugin.css b/ui/plugins/testPlugin/testPlugin.css new file mode 100644 index 00000000000..f26216fadb4 --- /dev/null +++ b/ui/plugins/testPlugin/testPlugin.css @@ -0,0 +1,20 @@ +/* +* 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. +*/ + +/* Put your CSS here */ diff --git a/ui/plugins/testPlugin/testPlugin.js b/ui/plugins/testPlugin/testPlugin.js new file mode 100644 index 00000000000..e340ae5b8ec --- /dev/null +++ b/ui/plugins/testPlugin/testPlugin.js @@ -0,0 +1,30 @@ +// 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.plugins.testPlugin = function(plugin) { + plugin.ui.addSection({ + id: 'testPlugin', + title: 'TestPlugin', + preFilter: function(args) { + return isAdmin(); + }, + show: function() { + return $('
').html('Test plugin section'); + } + }); + }; +}(cloudStack)); \ No newline at end of file diff --git a/ui/scripts/autoscaler.js b/ui/scripts/autoscaler.js index a56fd94e441..05011a3c4ff 100644 --- a/ui/scripts/autoscaler.js +++ b/ui/scripts/autoscaler.js @@ -847,7 +847,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); @@ -900,7 +900,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); @@ -915,7 +915,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); @@ -986,7 +986,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); @@ -1040,7 +1040,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); @@ -1058,7 +1058,7 @@ args.response.error(parseXMLHttpResponse(XMLHttpResponse)); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); }); @@ -1144,7 +1144,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); @@ -1214,7 +1214,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); @@ -1283,7 +1283,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); @@ -1328,7 +1328,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); @@ -1370,7 +1370,7 @@ } } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index fab6f7d839d..3c5dfe15ad0 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -19,18 +19,26 @@ home: 'dashboard', sectionPreFilter: function(args) { + var sections = []; + if(isAdmin()) { - return ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects"]; } else if(isDomainAdmin()) { - return ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects"]; } else if (g_userProjectsEnabled) { - return ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "projects"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "projects"]; } else { //normal user - return ["dashboard", "instances", "storage", "network", "templates", "accounts", "events"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events"]; } + + if (cloudStack.plugins.length) { + sections.push('plugins'); + } + + return sections; }, sections: { /** @@ -49,7 +57,8 @@ system: {}, //root-admin only 'global-settings': {}, //root-admin only - configuration: {} //root-admin only + configuration: {}, //root-admin only + plugins: {} } }); @@ -157,6 +166,13 @@ g_cloudstackversion = json.listcapabilitiesresponse.capability.cloudstackversion; + if(json.listcapabilitiesresponse.capability.apilimitinterval != null && json.listcapabilitiesresponse.capability.apilimitmax != null) { + var intervalLimit = ((json.listcapabilitiesresponse.capability.apilimitinterval * 1000) / json.listcapabilitiesresponse.capability.apilimitmax ) * 3; //multiply 3 to be on safe side + //intervalLimit = 9999; //this line is for testing only, comment it before check in + if(intervalLimit > g_queryAsyncJobResultInterval) + g_queryAsyncJobResultInterval = intervalLimit; + } + userValid = true; }, error: function(xmlHTTP) { @@ -283,7 +299,14 @@ $.cookie('userProjectsEnabled', g_userProjectsEnabled, { expires: 1 }); g_cloudstackversion = json.listcapabilitiesresponse.capability.cloudstackversion; - + + if(json.listcapabilitiesresponse.capability.apilimitinterval != null && json.listcapabilitiesresponse.capability.apilimitmax != null) { + var intervalLimit = ((json.listcapabilitiesresponse.capability.apilimitinterval * 1000) / json.listcapabilitiesresponse.capability.apilimitmax ) * 3; //multiply 3 to be on safe side + //intervalLimit = 8888; //this line is for testing only, comment it before check in + if(intervalLimit > g_queryAsyncJobResultInterval) + g_queryAsyncJobResultInterval = intervalLimit; + } + args.response.success({ data: { user: $.extend(true, {}, loginresponse, { diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index c85a98acf9e..4a64eeac1a5 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -136,6 +136,14 @@ isChecked: true, docID: 'helpComputeOfferingPublic' }, + + isVolatile:{ + label:'isVolatile', + isBoolean:true, + isChecked:false + + }, + domainId: { label: 'label.domain', docID: 'helpComputeOfferingDomain', @@ -196,6 +204,10 @@ $.extend(data, { limitcpuuse: (args.data.cpuCap == "on") }); + + $.extend(data, { + isvolatile: (args.data.isVolatile == "on") + }); if(args.$form.find('.form-item[rel=domainId]').css("display") != "none") { $.extend(data, { @@ -349,6 +361,7 @@ label: 'label.CPU.cap', converter: cloudStack.converters.toBooleanText }, + isvolatile:{ label:'Volatile' , converter: cloudStack.converters.toBooleanText }, tags: { label: 'label.storage.tags' }, hosttags: { label: 'label.host.tags' }, domain: { label: 'label.domain' }, diff --git a/ui/scripts/globalSettings.js b/ui/scripts/globalSettings.js index e65a00b290c..598c9c542c8 100644 --- a/ui/scripts/globalSettings.js +++ b/ui/scripts/globalSettings.js @@ -14,6 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. + (function(cloudStack) { cloudStack.sections['global-settings'] = { title: 'label.menu.global.settings', @@ -81,6 +82,129 @@ } } }, + + ldapConfiguration:{ + type:'select', + title:'LDAP Configuration', + listView:{ + id:'ldap', + label:'LDAP Configuration', + fields:{ + hostname: {label: 'Hostname'}, + queryfilter: {label: 'Query Filter'}, + searchbase: {label: 'Search Base'}, + port: {label: 'LDAP Port'}, + ssl: { + label: 'SSL' + + } + + }, + dataProvider:function(args){ + var data = {}; + listViewDataProvider(args, data); + $.ajax({ + url: createURL('ldapConfig&listall=true'), //Need a list LDAP configuration API call which needs to be implemented + data: data, + success: function(json) { + var items = json.ldapconfigresponse.ldapconfig; + args.response.success({data:items}); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + actions: { + add:{ + + label: 'Configure LDAP', + + messages: { + confirm: function(args) { + return 'Do you really want to configure LDAP ? '; + }, + notification: function(args) { + return 'LDAP configured'; + } + }, + + createForm: { + + title: 'Configure LDAP', + fields:{ + name:{label: 'Bind Username' , validation: {required:true} }, + password: {label: 'Bind Password', validation: {required: true },isPassword:true }, + hostname: {label:'Hostname' , validation:{required:true}}, + queryfilter: {label:'Query Filter' , validation: {required:true}}, + searchbase: {label:'SearchBase',validation:{required:true}}, + ssl: { + label:'SSL' , + isBoolean:true, + isChecked:false + + }, + port: { label: 'Port' , defaultValue: '389' }, + truststore:{ label:'Trust Store' , isHidden:true , dependsOn:'ssl',validation:{required:true} }, + truststorepassword:{ label:'Trust Store Password' ,isHidden:true , dependsOn:'ssl', validation:{required:true}} + + } + + + }, + + + action:function(args) { + var array = []; + array.push("&binddn=" + todb(args.data.name)); + array.push("&bindpass=" + todb(args.data.password)); + array.push("&hostname=" + todb(args.data.hostname)); + array.push("&searchbase=" +todb(args.data.searchbase)); + array.push("&queryfilter=" +todb(args.data.queryfilter)); + array.push("&port=" +todb(args.data.port)); + + if(args.$form.find('.form-item[rel=ssl]').find('input[type=checkbox]').is(':Checked')== true) { + + array.push("&ssl=true"); + if(args.data.truststore != "") + array.push("&truststore=" +todb(args.data.truststore)); + + if(args.data.truststorepassword !="") + array.push("&truststorepass=" +todb(args.data.truststorepassword)); + + } + + else + array.push("&ssl=false"); + + $.ajax({ + url: createURL("ldapConfig" + array.join("")), + dataType: "json", + async: true, + success: function(json) { + var items = json.ldapconfigresponse.ldapconfig; + args.response.success({ + data: items + }); + + } + + }); + + + } + } + + } + + + + } + + + + }, hypervisorCapabilities: { type: 'select', title: 'label.hypervisor.capabilities', diff --git a/ui/scripts/installWizard.js b/ui/scripts/installWizard.js index dff12a0c0b7..a5e13b8c640 100644 --- a/ui/scripts/installWizard.js +++ b/ui/scripts/installWizard.js @@ -278,6 +278,7 @@ }, pluginFrom: { name: 'installWizard', + selectedNetworkOffering: selectedNetworkOffering, selectedNetworkOfferingHavingSG: true } }, diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 5b5ed1853e7..8a7c7ad3af1 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -34,21 +34,21 @@ }, label: 'state.Destroyed' } - }, + }, preFilter: function(args) { var hiddenFields = []; - if(!isAdmin()) { + if(!isAdmin()) { hiddenFields.push('instancename'); - } + } return hiddenFields; - }, - fields: { + }, + fields: { name: { label: 'label.name' }, instancename: { label: 'label.internal.name' }, displayname: { label: 'label.display.name' }, zonename: { label: 'label.zone.name' }, state: { - label: 'label.state', + label: 'label.state', indicator: { 'Running': 'on', 'Stopped': 'off', @@ -57,18 +57,18 @@ } } }, - + advSearchFields: { name: { label: 'Name' }, - zoneid: { - label: 'Zone', - select: function(args) { + zoneid: { + label: 'Zone', + select: function(args) { $.ajax({ url: createURL('listZones'), data: { listAll: true }, - success: function(json) { + success: function(json) { var zones = json.listzonesresponse.zone; args.response.success({ @@ -81,16 +81,16 @@ }); } }); - } - }, - - domainid: { - label: 'Domain', + } + }, + + domainid: { + label: 'Domain', select: function(args) { if(isAdmin() || isDomainAdmin()) { $.ajax({ url: createURL('listDomains'), - data: { + data: { listAll: true, details: 'min' }, @@ -120,21 +120,21 @@ else return true; } - }, - account: { + }, + account: { label: 'Account', isHidden: function(args) { if(isAdmin() || isDomainAdmin()) return false; else return true; - } + } }, - + tagKey: { label: 'Tag Key' }, - tagValue: { label: 'Tag Value' } - }, - + tagValue: { label: 'Tag Value' } + }, + // List view actions actions: { // Add instance wizard @@ -145,9 +145,9 @@ custom: cloudStack.uiCustom.instanceWizard(cloudStack.instanceWizard) }, - messages: { - notification: function(args) { - return 'label.vm.add'; + messages: { + notification: function(args) { + return 'label.vm.add'; } }, notification: { @@ -158,49 +158,49 @@ dataProvider: function(args) { var data = {}; - listViewDataProvider(args, data); - + listViewDataProvider(args, data); + if(args.filterBy != null) { //filter dropdown if(args.filterBy.kind != null) { switch(args.filterBy.kind) { - case "all": + case "all": break; case "mine": if (!args.context.projects) { $.extend(data, { - domainid: g_domainid, + domainid: g_domainid, account: g_account - }); - } + }); + } break; case "running": $.extend(data, { state: 'Running' - }); + }); break; case "stopped": $.extend(data, { state: 'Stopped' - }); + }); break; case "destroyed": $.extend(data, { state: 'Destroyed' - }); + }); break; } - } + } } - - if("hosts" in args.context) { + + if("hosts" in args.context) { $.extend(data, { hostid: args.context.hosts[0].id }); } - + $.ajax({ url: createURL('listVirtualMachines'), - data: data, + data: data, success: function(json) { var items = json.listvirtualmachinesresponse.virtualmachine; // Code for hiding "Expunged VMs" @@ -231,7 +231,34 @@ detailView: { name: 'Instance details', - viewAll: { path: 'storage.volumes', label: 'label.volumes' }, + viewAll: [ + { path: 'storage.volumes', label: 'label.volumes' }, + { path: 'vmsnapshots', label: 'label.snapshots' }, + { + path: '_zone.hosts', + label: 'label.hosts', + preFilter: function(args) { + return isAdmin(); + }, + updateContext: function(args) { + var instance = args.context.instances[0]; + var zone; + + $.ajax({ + url: createURL('listZones'), + data: { + id: instance.zoneid + }, + async: false, + success: function(json) { + zone = json.listzonesresponse.zone[0] + } + }); + + return { zones: [zone] }; + } + } + ], tabFilter: function(args) { var hiddenTabs = []; @@ -409,6 +436,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 +1323,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 +1349,7 @@ allowedActions.push("start"); allowedActions.push("destroy"); allowedActions.push("reset"); - + allowedActions.push("snapshot"); if(isAdmin()) allowedActions.push("migrateToAnotherStorage"); diff --git a/ui/scripts/plugins.js b/ui/scripts/plugins.js new file mode 100644 index 00000000000..5a33d56ef9f --- /dev/null +++ b/ui/scripts/plugins.js @@ -0,0 +1,76 @@ +// 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, require) { + var loadCSS = function(path) { + var $link = $(''); + + $link.attr({ + rel: 'stylesheet', + type: 'text/css', + href: path + }); + + $('head').append($link); + }; + + var pluginAPI = { + pollAsyncJob: pollAsyncJobResult, + apiCall: function(command, args) { + $.ajax({ + url: createURL(command), + data: args.data, + success: args.success, + error: function(json) { + args.error(parseXMLHttpResponse(json)); + } + }) + }, + addSection: function(section) { + cloudStack.sections[section.id] = $.extend(section, { + customIcon: 'plugins/' + section.id + '/icon.png' + }); + }, + extend: function(obj) { + $.extend(true, cloudStack, obj); + } + }; + + cloudStack.sections.plugins = { + title: 'label.plugins', + show: cloudStack.uiCustom.plugins + }; + + // Load plugins + $(cloudStack.plugins).map(function(index, pluginID) { + var basePath = 'plugins/' + pluginID + '/'; + var pluginJS = basePath + pluginID + '.js'; + var configJS = basePath + 'config.js'; + var pluginCSS = basePath + pluginID + '.css'; + + require([pluginJS], function() { + require([configJS]); + loadCSS(pluginCSS); + + // Execute plugin + cloudStack.plugins[pluginID]({ + ui: pluginAPI + }); + }); + + // Load CSS + }); +}(jQuery, cloudStack, require)); diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 51c4fdb5902..ad26b34196e 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -26,6 +26,7 @@ var g_timezone = null; var g_supportELB = null; var g_userPublicTemplateEnabled = "true"; var g_cloudstackversion = null; +var g_queryAsyncJobResultInterval = 3000; //keyboard keycode var keycode_Enter = 13; diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index 73a496e4df6..5c19bd0a2dc 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -1282,6 +1282,7 @@ dataProvider: function(args) { var data = {}; + var instanceVolumeIds = []; listViewDataProvider(args, data); if(args.context != null) { @@ -1289,6 +1290,21 @@ $.extend(data, { volumeid: args.context.volumes[0].id }); + } else if (args.context.instances) { + $.ajax({ + url: createURL('listVolumes'), + data: { + virtualmachineid: args.context.instances[0].id, + listAll: true + }, + async: false, + success: function(json) { + instanceVolumeIds = $.map(json.listvolumesresponse.volume, function(volume) { + return volume.id; + }) + } + }); + data.volumeid = instanceVolumeIds.join(','); } } diff --git a/ui/scripts/system.js b/ui/scripts/system.js index cb09a851742..3d996129280 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -3165,7 +3165,7 @@ alert("addNetworkServiceProvider&name=Netscaler failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -3406,7 +3406,7 @@ alert("addNetworkServiceProvider&name=F5BigIpfailed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -3669,7 +3669,7 @@ alert("addNetworkServiceProvider&name=JuniperSRX failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -3988,7 +3988,7 @@ alert("addNetworkServiceProvider&name=NiciraNvp failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -6240,7 +6240,7 @@ alert("addNetworkServiceProvider&name=Netscaler failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -6435,7 +6435,7 @@ alert("addNetworkServiceProvider&name=F5BigIpfailed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -6646,7 +6646,7 @@ alert("addNetworkServiceProvider&name=JuniperSRX failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -6812,7 +6812,7 @@ alert("addNetworkServiceProvider&name=NiciraNvp failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -7440,6 +7440,18 @@ validation: { required: true } }, + cpuovercommit:{ + label: 'CPU overcommit ratio', + defaultValue:'1' + + }, + + memoryovercommit:{ + label: 'RAM overcommit ratio', + defaultValue:'1' + + }, + //hypervisor==VMWare begins here vCenterHost: { label: 'label.vcenter.host', @@ -7497,6 +7509,13 @@ array1.push("&podId=" + args.data.podId); var clusterName = args.data.name; + + if(args.data.cpuovercommit != "") + array1.push("&cpuovercommitratio=" + todb(args.data.cpuovercommit)); + + if(args.data.memoryovercommit != "") + array1.push("&memoryovercommitratio=" + todb(args.data.memoryovercommit)); + if(args.data.hypervisor == "VMware") { array1.push("&username=" + todb(args.data.vCenterUsername)); array1.push("&password=" + todb(args.data.vCenterPassword)); @@ -7572,6 +7591,38 @@ }, actions: { + + edit: { + label: 'label.edit', + action: function(args) { + var array1 = []; + + if (args.data.cpuovercommitratio != "" && args.data.cpuovercommitratio > 0) + array1.push("&cpuovercommitratio=" + args.data.cpuovercommitratio); + + if (args.data.memoryovercommitratio != "" && args.data.memoryovercommitratio > 0) + array1.push("&memoryovercommitratio=" + args.data.memoryovercommitratio); + + $.ajax({ + + url: createURL("updateCluster&id=" + args.context.clusters[0].id + array1.join("")), + dataType: "json", + async: true, + success: function(json) { + var item = json.updateclusterresponse.cluster; + args.context.clusters[0].cpuovercommitratio = item.cpuovercommitratio; + args.context.clusters[0].memoryovercommitratio = item.memoryovercommitratio; + addExtraPropertiesToClusterObject(item); + args.response.success({ + actionFilter: clusterActionfilter, + data:item + }); + + } + }); + } + }, + enable: { label: 'label.action.enable.cluster', messages: { @@ -7741,6 +7792,8 @@ podname: { label: 'label.pod' }, hypervisortype: { label: 'label.hypervisor' }, clustertype: { label: 'label.cluster.type' }, + cpuovercommitratio:{ label: 'CPU overcommit Ratio', isEditable:true}, + memoryovercommitratio:{ label: 'Memory overcommit Ratio', isEditable:true}, //allocationstate: { label: 'label.allocation.state' }, //managedstate: { label: 'Managed State' }, state: { label: 'label.state' } @@ -7965,11 +8018,17 @@ } } } - array1.push("&zoneid=" + args.context.zones[0].id); - if("pods" in args.context) - array1.push("&podid=" + args.context.pods[0].id); - if("clusters" in args.context) - array1.push("&clusterid=" + args.context.clusters[0].id); + + if (!args.context.instances) { + array1.push("&zoneid=" + args.context.zones[0].id); + if("pods" in args.context) + array1.push("&podid=" + args.context.pods[0].id); + if("clusters" in args.context) + array1.push("&clusterid=" + args.context.clusters[0].id); + } else { + array1.push("&hostid=" + args.context.instances[0].hostid); + } + $.ajax({ url: createURL("listHosts&type=Routing" + array1.join("") + "&page=" + args.page + "&pagesize=" + pageSize), dataType: "json", @@ -10222,7 +10281,7 @@ alert("updateNetworkServiceProvider failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -10303,7 +10362,7 @@ alert("updateNetworkServiceProvider failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -10317,7 +10376,7 @@ alert("configureVirtualRouterElement failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); } @@ -10331,7 +10390,7 @@ alert("updatePhysicalNetwork failed. Error: " + errorMsg); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); } }); }; @@ -10407,10 +10466,14 @@ if(jsonObj.state == "Enabled") {//managed, allocation enabled allowedActions.push("unmanage"); allowedActions.push("disable"); + allowedActions.push("edit"); + } else if(jsonObj.state == "Disabled") { //managed, allocation disabled allowedActions.push("unmanage"); allowedActions.push("enable"); + allowedActions.push("edit"); + } else { //Unmanaged, PrepareUnmanaged , PrepareUnmanagedError allowedActions.push("manage"); diff --git a/ui/scripts/ui-custom/physicalResources.js b/ui/scripts/ui-custom/physicalResources.js index a247dcfe2c2..69c0295c08d 100644 --- a/ui/scripts/ui-custom/physicalResources.js +++ b/ui/scripts/ui-custom/physicalResources.js @@ -111,7 +111,7 @@ $loading.remove(); } }); - }, 3000); + }, g_queryAsyncJobResultInterval); }, error: function(XMLHttpResponse) { cloudStack.dialog.notice({ message: 'Failed to update SSL Certificate. ' + parseXMLHttpResponse(XMLHttpResponse) }); diff --git a/ui/scripts/ui-custom/plugins.js b/ui/scripts/ui-custom/plugins.js new file mode 100644 index 00000000000..aaf95319da1 --- /dev/null +++ b/ui/scripts/ui-custom/plugins.js @@ -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 +// 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) { + var elems = { + pluginItem: function(args) { + var id = args.id; + var title = args.title; + var desc = args.desc; + var iconURL = args.iconURL; + var $pluginItem = $('
  • ').addClass('plugin-item').addClass(id); + var $title = $('').addClass('title').html(title); + var $desc = $('').addClass('desc').html(desc); + var $icon = $('').addClass('icon').append( + $('').attr({ src: iconURL }) + ); + + $pluginItem.append( + $icon, $title, $desc + ); + + return $pluginItem; + }, + pluginListing: function(args) { + var plugins = args.plugins; + var $plugins = $('