4 using System.Collections.Generic;
5 using System.ComponentModel;
6 using System.Windows.Forms;
7 using System.Runtime.InteropServices;
8 using System.Security.Cryptography.X509Certificates;
9 using System.Threading;
10 using System.Net.NetworkInformation;
11 using System.IO.Compression;
12 using System.Diagnostics;
13 using System.ServiceProcess;
14 using System.Security.AccessControl;
18 public partial class SetupWizard : Form
20 private string _TrustedFile;
24 InitializeComponent();
26 txtInstanceName.Text = Icinga2InstanceName;
29 private void Warning(string message)
31 MessageBox.Show(this, message, Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
34 private string Icinga2InstanceName
38 IPGlobalProperties props = IPGlobalProperties.GetIPGlobalProperties();
40 string fqdn = props.HostName;
42 if (props.DomainName != "")
43 fqdn += "." + props.DomainName;
49 private bool GetMasterHostPort(out string host, out string port)
51 foreach (ListViewItem lvi in lvwEndpoints.Items) {
52 if (lvi.SubItems.Count > 1) {
53 host = lvi.SubItems[1].Text;
54 port = lvi.SubItems[2].Text;
64 private void EnableFeature(string feature)
68 fp = File.Open(Program.Icinga2InstallDir + String.Format("\\etc\\icinga2\\features-enabled\\{0}.conf", feature), FileMode.Create);
69 using (StreamWriter sw = new StreamWriter(fp, Encoding.ASCII)) {
71 sw.Write(String.Format("include \"../features-available/{0}.conf\"\n", feature));
79 private void SetRetrievalStatus(int pct)
82 Invoke((MethodInvoker)delegate { SetRetrievalStatus(pct); });
86 prgRetrieveCertificate.Value = pct;
89 private void SetConfigureStatus(int pct, string message)
92 Invoke((MethodInvoker)delegate { SetConfigureStatus(pct, message); });
96 prgConfig.Value = pct;
97 lblConfigStatus.Text = message;
100 private void ShowErrorText(string text)
102 if (InvokeRequired) {
103 Invoke((MethodInvoker)delegate { ShowErrorText(text); });
107 txtError.Text = text;
108 tbcPages.SelectedTab = tabError;
111 private bool RunProcess(string filename, string arguments, out string output)
113 ProcessStartInfo psi = new ProcessStartInfo();
114 psi.FileName = filename;
115 psi.Arguments = arguments;
116 psi.CreateNoWindow = true;
117 psi.UseShellExecute = false;
118 psi.RedirectStandardOutput = true;
119 psi.RedirectStandardError = true;
123 using (Process proc = Process.Start(psi)) {
124 proc.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs args) {
125 result += args.Data + "\r\n";
127 proc.OutputDataReceived += delegate(object sender, DataReceivedEventArgs args) {
128 result += args.Data + "\r\n";
130 proc.BeginOutputReadLine();
131 proc.BeginErrorReadLine();
136 if (proc.ExitCode != 0)
143 private void VerifyCertificate(string host, string port)
145 SetRetrievalStatus(25);
147 string pathPrefix = Program.Icinga2InstallDir + "\\etc\\icinga2\\pki\\" + txtInstanceName.Text;
148 string processArguments = "pki new-cert --cn \"" + txtInstanceName.Text + "\" --key \"" + pathPrefix + ".key\" --cert \"" + pathPrefix + ".crt\"";
151 if (!File.Exists(pathPrefix + ".crt")) {
152 if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe",
155 ShowErrorText("Running command 'icinga2.exe " + processArguments + "' produced the following output:\n" + output);
160 SetRetrievalStatus(50);
162 _TrustedFile = Path.GetTempFileName();
164 processArguments = "pki save-cert --host \"" + host + "\" --port \"" + port + "\" --key \"" + pathPrefix + ".key\" --cert \"" + pathPrefix + ".crt\" --trustedcert \"" + _TrustedFile + "\"";
165 if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe",
168 ShowErrorText("Running command 'icinga2.exe " + processArguments + "' produced the following output:\n" + output);
172 SetRetrievalStatus(100);
174 X509Certificate2 cert = new X509Certificate2(_TrustedFile);
175 Invoke((MethodInvoker)delegate { ShowCertificatePrompt(cert); });
178 private void ConfigureService()
180 SetConfigureStatus(0, "Updating configuration files...");
186 if (rdoNewMaster.Checked)
189 Invoke((MethodInvoker)delegate {
190 string master_host, master_port;
191 GetMasterHostPort(out master_host, out master_port);
193 args += " --master_host " + master_host + "," + master_port;
195 foreach (ListViewItem lvi in lvwEndpoints.Items) {
196 args += " --endpoint " + lvi.SubItems[0].Text;
198 if (lvi.SubItems.Count > 1)
199 args += "," + lvi.SubItems[1].Text + "," + lvi.SubItems[2].Text;
203 if (rdoListener.Checked)
204 args += " --listen ::," + txtListenerPort.Text;
206 if (chkAcceptConfig.Checked)
207 args += " --accept-config";
209 if (chkAcceptCommands.Checked)
210 args += " --accept-commands";
212 args += " --ticket \"" + txtTicket.Text + "\"";
213 args += " --trustedcert \"" + _TrustedFile + "\"";
214 args += " --cn \"" + txtInstanceName.Text + "\"";
215 args += " --zone \"" + txtInstanceName.Text + "\"";
217 if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe",
220 ShowErrorText("Running command 'icinga2.exe " + "node setup" + args + "' produced the following output:\n" + output);
224 SetConfigureStatus(50, "Setting ACLs for the Icinga 2 directory...");
225 DirectoryInfo di = new DirectoryInfo(Program.Icinga2InstallDir);
226 DirectorySecurity ds = di.GetAccessControl();
227 FileSystemAccessRule rule = new FileSystemAccessRule("NT AUTHORITY\\NetworkService",
228 FileSystemRights.Modify,
229 InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow);
230 ds.AddAccessRule(rule);
231 di.SetAccessControl(ds);
233 SetConfigureStatus(75, "Installing the Icinga 2 service...");
235 RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe",
239 if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe",
242 ShowErrorText("Running command 'icinga2.exe daemon --validate' produced the following output:\n" + output);
246 if (!RunProcess(Program.Icinga2InstallDir + "\\sbin\\icinga2.exe",
247 "--scm-install daemon",
249 ShowErrorText("Running command 'icinga2.exe daemon --scm-install daemon' produced the following output:\n" + output);
253 if (chkInstallNSCP.Checked)
255 SetConfigureStatus(85, "Waiting for NSClient++ installation to complete...");
257 Process proc = new Process();
258 proc.StartInfo.FileName = "msiexec.exe";
259 proc.StartInfo.Arguments = "/i \"" + Program.Icinga2InstallDir + "\\sbin\\NSCP.msi\"";
264 SetConfigureStatus(100, "Finished.");
269 private void FinishConfigure()
271 if (InvokeRequired) {
272 Invoke((MethodInvoker)FinishConfigure);
276 tbcPages.SelectedTab = tabFinish;
279 private void AgentWizard_Shown(object sender, EventArgs e)
281 string installDir = Program.Icinga2InstallDir;
283 /* TODO: This is something the NSIS installer should do */
284 Directory.CreateDirectory(installDir + "\\etc\\icinga2\\pki");
285 Directory.CreateDirectory(installDir + "\\var\\cache\\icinga2");
286 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\pki");
287 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\agent\\inventory");
288 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\api\\config");
289 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\api\\log");
290 Directory.CreateDirectory(installDir + "\\var\\lib\\icinga2\\api\\zones");
291 Directory.CreateDirectory(installDir + "\\var\\log\\icinga2\\compat\\archive");
292 Directory.CreateDirectory(installDir + "\\var\\log\\icinga2\\crash");
293 Directory.CreateDirectory(installDir + "\\var\\run\\icinga2\\cmd");
294 Directory.CreateDirectory(installDir + "\\var\\spool\\icinga2\\perfdata");
295 Directory.CreateDirectory(installDir + "\\var\\spool\\icinga2\\tmp");
298 private void btnBack_Click(object sender, EventArgs e)
300 if (tbcPages.SelectedTab == tabError) {
301 tbcPages.SelectedIndex = 0;
307 if (tbcPages.SelectedTab == tabVerifyCertificate)
310 tbcPages.SelectedIndex -= offset;
313 private void btnNext_Click(object sender, EventArgs e)
315 if (tbcPages.SelectedTab == tabParameters) {
316 if (txtInstanceName.Text.Length == 0) {
317 Warning("Please enter an instance name.");
321 if (txtTicket.Text.Length == 0) {
322 Warning("Please enter an agent ticket.");
326 if (rdoNoMaster.Checked) {
327 if (lvwEndpoints.Items.Count == 0) {
328 Warning("You need to add at least one master endpoint.");
333 if (!GetMasterHostPort(out host, out port)) {
334 Warning("Please enter a remote host and port for at least one of your endpoints.");
339 if (rdoListener.Checked && (txtListenerPort.Text == "")) {
340 Warning("You need to specify a listener port.");
345 if (tbcPages.SelectedTab == tabFinish || tbcPages.SelectedTab == tabError)
348 tbcPages.SelectedIndex++;
351 private void btnCancel_Click(object sender, EventArgs e)
356 private void tbcPages_SelectedIndexChanged(object sender, EventArgs e)
360 btnBack.Enabled = (tbcPages.SelectedTab == tabVerifyCertificate || tbcPages.SelectedTab == tabError);
361 btnNext.Enabled = (tbcPages.SelectedTab == tabParameters || tbcPages.SelectedTab == tabVerifyCertificate || tbcPages.SelectedTab == tabFinish);
363 if (tbcPages.SelectedTab == tabFinish) {
364 btnNext.Text = "&Finish >";
365 btnCancel.Enabled = false;
368 if (tbcPages.SelectedTab == tabRetrieveCertificate) {
369 ListViewItem lvi = lvwEndpoints.Items[0];
371 string master_host, master_port;
372 GetMasterHostPort(out master_host, out master_port);
374 Thread thread = new Thread((ThreadStart)delegate { VerifyCertificate(master_host, master_port); });
378 /*if (tbcPages.SelectedTab == tabParameters &&
379 !File.Exists(Icinga2InstallDir + "\\etc\\icinga2\\pki\\agent\\agent.crt")) {
380 byte[] bytes = Convert.FromBase64String(txtBundle.Text);
381 MemoryStream ms = new MemoryStream(bytes);
382 GZipStream gz = new GZipStream(ms, CompressionMode.Decompress);
383 MemoryStream ms2 = new MemoryStream();
385 byte[] buffer = new byte[512];
387 while ((rc = gz.Read(buffer, 0, buffer.Length)) > 0)
388 ms2.Write(buffer, 0, rc);
390 TarReader tr = new TarReader(ms2);
391 tr.ReadToEnd(Icinga2InstallDir + "\\etc\\icinga2\\pki\\agent");
394 if (tbcPages.SelectedTab == tabConfigure) {
395 Thread thread = new Thread(ConfigureService);
400 private void RadioMaster_CheckedChanged(object sender, EventArgs e)
402 lvwEndpoints.Enabled = !rdoNewMaster.Checked;
403 btnAddEndpoint.Enabled = !rdoNewMaster.Checked;
404 btnRemoveEndpoint.Enabled = !rdoNewMaster.Checked && lvwEndpoints.SelectedItems.Count > 0;
407 private void RadioListener_CheckedChanged(object sender, EventArgs e)
409 txtListenerPort.Enabled = rdoListener.Checked;
412 private void AddCertificateField(string name, string shortValue, string longValue = null)
414 ListViewItem lvi = new ListViewItem();
416 lvi.SubItems.Add(shortValue);
417 if (longValue == null)
418 longValue = shortValue;
420 lvwX509Fields.Items.Add(lvi);
423 private string PadText(string input)
427 for (int i = 0; i < input.Length; i += 2) {
432 if (input.Length - i < 2)
433 len = input.Length - i;
434 output += input.Substring(i, len);
440 private void ShowCertificatePrompt(X509Certificate2 certificate)
442 txtX509Issuer.Text = certificate.Issuer;
443 txtX509Subject.Text = certificate.Subject;
445 lvwX509Fields.Items.Clear();
447 AddCertificateField("Version", "V" + certificate.Version.ToString());
448 AddCertificateField("Serial number", certificate.SerialNumber);
449 AddCertificateField("Signature algorithm", certificate.SignatureAlgorithm.FriendlyName);
450 AddCertificateField("Valid from", certificate.NotBefore.ToString());
451 AddCertificateField("Valid to", certificate.NotAfter.ToString());
453 string pkey = BitConverter.ToString(certificate.PublicKey.EncodedKeyValue.RawData).Replace("-", " ");
454 AddCertificateField("Public key", certificate.PublicKey.Oid.FriendlyName + " (" + certificate.PublicKey.Key.KeySize + " bits)", pkey);
456 string thumbprint = PadText(certificate.Thumbprint);
457 AddCertificateField("Thumbprint", thumbprint);
459 tbcPages.SelectedTab = tabVerifyCertificate;
462 private void btnAddEndpoint_Click(object sender, EventArgs e)
464 EndpointInputBox eib = new EndpointInputBox();
466 if (eib.ShowDialog(this) == DialogResult.Cancel)
469 ListViewItem lvi = new ListViewItem();
470 lvi.Text = eib.txtInstanceName.Text;
472 if (eib.chkConnect.Checked) {
473 lvi.SubItems.Add(eib.txtHost.Text);
474 lvi.SubItems.Add(eib.txtPort.Text);
477 lvwEndpoints.Items.Add(lvi);
480 private void lvwEndpoints_SelectedIndexChanged(object sender, EventArgs e)
482 btnRemoveEndpoint.Enabled = lvwEndpoints.SelectedItems.Count > 0;
485 private void lvwX509Fields_SelectedIndexChanged(object sender, EventArgs e)
487 if (lvwX509Fields.SelectedItems.Count == 0)
490 ListViewItem lvi = lvwX509Fields.SelectedItems[0];
492 txtX509Field.Text = (string)lvi.Tag;
495 private void btnRemoveEndpoint_Click(object sender, EventArgs e)
497 while (lvwEndpoints.SelectedItems.Count > 0) {
498 lvwEndpoints.Items.Remove(lvwEndpoints.SelectedItems[0]);