diff --git a/scripts/installer/windows/acs.wxs b/scripts/installer/windows/acs.wxs
new file mode 100644
index 00000000000..79674781d7b
--- /dev/null
+++ b/scripts/installer/windows/acs.wxs
@@ -0,0 +1,229 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NOT Installed
+ NOT Installed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/installer/windows/client.wxs b/scripts/installer/windows/client.wxs
new file mode 100644
index 00000000000..c6fc52c764b
--- /dev/null
+++ b/scripts/installer/windows/client.wxs
@@ -0,0 +1,2414 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scripts/installer/windows/start.bat b/scripts/installer/windows/start.bat
new file mode 100644
index 00000000000..e819fa210e4
--- /dev/null
+++ b/scripts/installer/windows/start.bat
@@ -0,0 +1,12 @@
+:: 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.
+echo Starting Apache CloudStack > C:\Work\tmp.out
+START %CATALINA_HOME%\bin\startup.bat
+echo Started Aoache CloudStack >> C:\Work\tmp.out
\ No newline at end of file
diff --git a/scripts/vm/systemvm/injectkeys.py b/scripts/vm/systemvm/injectkeys.py
new file mode 100644
index 00000000000..bd840f98e78
--- /dev/null
+++ b/scripts/vm/systemvm/injectkeys.py
@@ -0,0 +1,142 @@
+#!/bin/bash
+# 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.
+
+
+# Copies keys that enable SSH communication with system vms
+# $1 = new public key
+# $2 = new private key
+'''
+All imports go here...
+'''
+import os
+import shutil
+import os.path
+import sys
+import subprocess
+import commands
+import traceback
+import filecmp
+
+pathSep=os.sep
+TMP=os.path.expanduser("~") + os.sep + "tmp" #Get Home Directory
+MOUNTPATH=TMP + pathSep + "systemvm_mnt"
+TMPDIR=TMP + pathSep + "cloud" + pathSep + "systemvm"
+osType=os.name
+
+os.makedirs(TMP)
+os.makedirs(MOUNTPATH)
+os.makedirs(TMPDIR)
+
+def clean_up():
+ shutil.rmtree(TMP)
+ #$SUDO umount $MOUNTPATH
+
+def inject_into_iso(pubKey,systemiso):
+ isofile=systemvmpath
+ newpubkey=pubKey
+ backup=isofile + ".bak"
+ tmpiso=TMP + pathSep + systemiso
+ if not os.path.exists(isofile):
+ print("Could not open %s" % isofile)
+ clean_up()
+ sys.exit(IOError)
+ command = "7z x -y " + isofile + " -o" + MOUNTPATH
+ status = os.system(command)
+ if status != 0:
+ print ("Failed to mount original iso %" % isofile)
+ clean_up()
+ sys.exit(status)
+ pubKeyFileOld=open(MOUNTPATH + pathSep + "authorized_keys", 'r')
+ pubKeyFileNew=open(newpubkey, 'r')
+ for line1 in pubKeyFileOld:
+ for line2 in pubKeyFileNew:
+ if line1 == line2:
+ pubKeyFileOld.close()
+ pubKeyFileNew.close()
+ return 0
+ pubKeyFileOld.close()
+ pubKeyFileNew.close()
+ try:
+ shutil.copy(isofile, backup)
+ except:
+ print("Failed to backup original iso %" % isofile)
+ clean_up()
+ sys.exit(IOError)
+ shutil.rmtree(TMPDIR)
+ try :
+ shutil.copytree(MOUNTPATH, TMPDIR)
+ except :
+ print ("Failed to copy from original iso %s" % isofile)
+ clean_up()
+ sys.exit(IOError)
+ try :
+ shutil.copyfile(newpubkey, TMPDIR + pathSep + "authorized_keys")
+ except :
+ print ("Failed to copy key %s from original iso to new iso" % newpubkey)
+ traceback.print_exc(file=sys.stdout)
+ clean_up()
+ sys.exit(IOError)
+ command = "mkisofs -quiet -r -o " + tmpiso + " " + TMPDIR
+ try :
+ status = os.system(command)
+ except :
+ print("Failed to create new iso %s from %s" % (tmpiso, TMPDIR))
+ clean_up()
+ sys.exit(IOError)
+ shutil.rmtree(MOUNTPATH)
+ try :
+ shutil.copyfile(tmpiso, isofile)
+ except :
+ print ("Failed to overwrite old iso %s with %s" % (isofile,tmpiso))
+ traceback.print_exc(file=sys.stdout)
+ clean_up()
+ sys.exit(IOError)
+ shutil.rmtree(TMPDIR)
+
+def copy_priv_key(newKey):
+ currDir = os.path.dirname(os.path.abspath(__file__))
+ if filecmp.cmp(currDir + pathSep + "id_rsa.cloud", newKey):
+ return 0
+ print ("Copying new private key file as it is not matching with old file")
+ shutil.copyfile(newKey, currDir + pathSep + "id_rsa.cloud")
+ os.chmod(currDir + pathSep + "id_rsa.cloud", 0644)
+ return 0
+
+if len(sys.argv) != 4:
+ print("Usage: injectkeys.py ")
+ clean_up()
+ sys.exit(None)
+newpubkey=sys.argv[1]
+newprivkey=sys.argv[2]
+systemvmpath=sys.argv[3]
+
+if not os.path.exists(newpubkey):
+ print("Could not open %s" % newpubkey)
+ clean_up()
+ sys.exit(IOError)
+if not os.path.exists(newprivkey):
+ print("Could not open %s" % newprivkey)
+ clean_up()
+ sys.exit(IOError)
+#Verify all needed commands exists before calling
+inject_into_iso(newpubkey,"systemvm.iso")
+
+copy_priv_key(newprivkey)
+
+clean_up()
+#exit $?
diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java
index 478101027cc..13135b0e192 100755
--- a/server/src/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/com/cloud/server/ConfigurationServerImpl.java
@@ -737,7 +737,10 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
s_logger.info("Systemvm keypairs not found in database. Need to store them in the database");
}
// FIXME: take a global database lock here for safety.
- Script.runSimpleBashScript("if [ -f " + privkeyfile + " ]; then rm -f " + privkeyfile + "; fi; ssh-keygen -t rsa -N '' -f " + privkeyfile + " -q");
+ boolean onWindows = isOnWindows();
+ if(!onWindows) {
+ Script.runSimpleBashScript("if [ -f " + privkeyfile + " ]; then rm -f " + privkeyfile + "; fi; ssh-keygen -t rsa -N '' -f " + privkeyfile + " -q");
+ }
byte[] arr1 = new byte[4094]; // configuration table column value size
try {
@@ -872,7 +875,8 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
}
protected void injectSshKeysIntoSystemVmIsoPatch(String publicKeyPath, String privKeyPath) {
- String injectScript = "scripts/vm/systemvm/injectkeys.sh";
+ s_logger.info("Trying to inject public and private keys into systemvm iso");
+ String injectScript = getInjectScript();
String scriptPath = Script.findScript("", injectScript);
String systemVmIsoPath = Script.findScript("", "vms/systemvm.iso");
if (scriptPath == null) {
@@ -881,19 +885,42 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
if (systemVmIsoPath == null) {
throw new CloudRuntimeException("Unable to find systemvm iso vms/systemvm.iso");
}
- final Script command = new Script("/bin/bash", s_logger);
+ Script command = null;
+ if(isOnWindows()) {
+ command = new Script("python", s_logger);
+ } else {
+ command = new Script("/bin/bash", s_logger);
+ }
command.add(scriptPath);
command.add(publicKeyPath);
command.add(privKeyPath);
command.add(systemVmIsoPath);
final String result = command.execute();
+ s_logger.info("Injected public and private keys into systemvm iso with result : " + result);
if (result != null) {
s_logger.warn("Failed to inject generated public key into systemvm iso " + result);
throw new CloudRuntimeException("Failed to inject generated public key into systemvm iso " + result);
}
}
+ protected String getInjectScript() {
+ String injectScript = null;
+ boolean onWindows = isOnWindows();
+ if(onWindows) {
+ injectScript = "scripts/vm/systemvm/injectkeys.py";
+ } else {
+ injectScript = "scripts/vm/systemvm/injectkeys.sh";
+ }
+ return injectScript;
+ }
+
+ protected boolean isOnWindows() {
+ String os = System.getProperty("os.name", "generic").toLowerCase();
+ boolean onWindows = (os != null && os.startsWith("windows"));
+ return onWindows;
+ }
+
@DB
protected void generateSecStorageVmCopyPassword() {
String already = _configDao.getValue("secstorage.copy.password");
diff --git a/server/test/com/cloud/server/ConfigurationServerImplTest.java b/server/test/com/cloud/server/ConfigurationServerImplTest.java
index 08a20974f9a..38dc1bc0e09 100644
--- a/server/test/com/cloud/server/ConfigurationServerImplTest.java
+++ b/server/test/com/cloud/server/ConfigurationServerImplTest.java
@@ -21,9 +21,26 @@ import java.io.IOException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
+import org.junit.Assert;
import org.junit.Test;
+import org.mockito.Spy;
public class ConfigurationServerImplTest {
+
+ @Spy
+ ConfigurationServerImpl windowsImpl = new ConfigurationServerImpl() {
+ protected boolean isOnWindows() {
+ return true;
+ }
+ };
+
+ @Spy
+ ConfigurationServerImpl linuxImpl = new ConfigurationServerImpl() {
+ protected boolean isOnWindows() {
+ return false;
+ }
+ };
+
final static String TEST = "the quick brown fox jumped over the lazy dog";
@Test(expected = IOException.class)
@@ -58,4 +75,13 @@ public class ConfigurationServerImplTest {
temp.delete();
}
}
+
+ @Test
+ public void testWindowsScript() {
+ Assert.assertTrue(windowsImpl.isOnWindows());
+ Assert.assertEquals("scripts/vm/systemvm/injectkeys.py", windowsImpl.getInjectScript());
+
+ Assert.assertFalse(linuxImpl.isOnWindows());
+ Assert.assertEquals("scripts/vm/systemvm/injectkeys.sh", linuxImpl.getInjectScript());
+ }
}