Ejemplo n.º 1
0
        public void ClusterChanges()
        {
            ConsoleLogger.Log("[cluster] applying changes");
            ClusterConfiguration.Prepare();
            var clusterConfig = ClusterConfiguration.GetClusterInfo();
            var publicIp      = clusterConfig.VirtualIpAddress;

            if (string.IsNullOrEmpty(publicIp))
            {
                ConsoleLogger.Warn("[cluster] public ip not valid");
                return;
            }
            var nodes = ClusterConfiguration.GetNodes();

            if (!nodes.Any())
            {
                ConsoleLogger.Warn("[cluster] configuration not valid");
                return;
            }

            SaveKeepalived(publicIp, nodes);
            SaveHaproxy(publicIp, nodes);

            SaveFileSystemSync(clusterConfig, nodes);
        }
Ejemplo n.º 2
0
        private void SaveKeepalived(string publicIp, List <NodeModel> nodes)
        {
            ConsoleLogger.Log("[cluster] init keepalived");
            const string keepalivedService = "keepalived.service";

            if (Systemctl.IsActive(keepalivedService))
            {
                ConsoleLogger.Log("[cluster] stop service");
                Systemctl.Stop(keepalivedService);
            }
            ConsoleLogger.Log("[cluster] set configuration file");
            var clusterInfo = ClusterConfiguration.GetClusterInfo();
            var lines       = new List <string> {
                "vrrp_script chk_haproxy {",
                "    script \"killall -0 haproxy\"",
                "    interval 2",
                "    weight 2",
                "}",
                "",
                "vrrp_instance RH_INT {",
                $"    interface {clusterInfo.NetworkInterface}",
                "    state MASTER",
                "    virtual_router_id 51",
                $"    priority {clusterInfo.Priority}",
                "    virtual_ipaddress {",
                $"        {clusterInfo.VirtualIpAddress}",
                "    }",
                "    track_script {",
                "        chk_haproxy",
                "    }",
                "}",
            };

            FileWithAcl.WriteAllLines(KeepalivedFileOutput, lines);
            //if(Systemctl.IsEnabled(keepalivedService) == false) {
            //    Systemctl.Enable(keepalivedService);
            //    ConsoleLogger.Log("[cluster] keepalived enabled");
            //}
            //if(Systemctl.IsActive(keepalivedService) == false) {
            //    Systemctl.Restart(keepalivedService);
            //    ConsoleLogger.Log("[cluster] keepalived restarted");
            //}
            Systemctl.Enable(keepalivedService);
            ConsoleLogger.Log("[cluster] keepalived enabled");
            Systemctl.Restart(keepalivedService);
            ConsoleLogger.Log("[cluster] keepalived restarted");
        }
Ejemplo n.º 3
0
        private void SaveHaproxy(string publicIp, List <NodeModel> nodes)
        {
            ConsoleLogger.Log("[cluster] init haproxy");
            CommandLauncher.Launch("haproxy-stop");
            if (File.Exists(_haproxyFileOutput))
            {
                File.Copy(_haproxyFileOutput, $"{_haproxyFileOutput}.bck", true);
            }
            ConsoleLogger.Log("[cluster] set haproxy file");
            var clusterInfo = ClusterConfiguration.GetClusterInfo();
            var ports       = clusterInfo.PortMapping;

            if (!ports.Any())
            {
                return;
            }
            var lines = new List <string> {
                "global",
                "    daemon",
                "    log 127.0.0.1   local0",
                "    log 127.0.0.1   local1 notice",
                "    maxconn 4096",
                "    user haproxy",
                "    group haproxy",
                "",
                "defaults",
                "    log     global",
                "    mode    http",
                "    option  httplog",
                "    option  dontlognull",
                "    retries 3",
                "    option  redispatch",
                "    maxconn 2000",
                "    timeout connect 5000",
                "    timeout client  50000",
                "    timeout server  50000",
                ""
            };
            var localport     = new AppConfiguration().Get().AntdUiPort;
            var localServices = new ApiConsumer().Get <List <RssdpServiceModel> >($"http://localhost:{localport}/device/services");

            foreach (var portMapping in ports)
            {
                portMapping.ServicePort = localServices.FirstOrDefault(_ => _.Name == portMapping.ServiceName)?.Port;
                if (string.IsNullOrEmpty(portMapping.ServicePort))
                {
                    continue;
                }
                var frontEndLabel = $"fe_in{portMapping.ServicePort}_out{portMapping.VirtualPort}";
                var backEndLabel  = $"be_in{portMapping.ServicePort}_out{portMapping.VirtualPort}";
                lines.Add($"frontend {frontEndLabel}");
                lines.Add("    mode http");
                lines.Add($"    bind {clusterInfo.VirtualIpAddress}:{portMapping.VirtualPort} transparent");
                lines.Add("    stats enable");
                lines.Add("    stats auth admin:Anthilla");
                lines.Add("    option httpclose");
                lines.Add("    option forwardfor");
                lines.Add($"    default_backend {backEndLabel}");
                lines.Add("");
                lines.Add($"backend {backEndLabel}");
                lines.Add("    balance roundrobin");
                lines.Add("    cookie JSESSIONID prefix");
                lines.Add("    option httpchk HEAD /check.txt HTTP/1.0");
                foreach (var node in nodes)
                {
                    lines.Add($"    server {node.Hostname} {node.PublicIp}:{portMapping.ServicePort} check");
                }
                lines.Add("");
            }

            File.WriteAllLines(_haproxyFileOutput, lines);
            CommandLauncher.Launch("haproxy-start", new Dictionary <string, string> {
                { "$file", _haproxyFileOutput }
            });
            ConsoleLogger.Log("[cluster] haproxy started");
        }
Ejemplo n.º 4
0
        public AssetClusterModule()
        {
            Get["/cluster"] = x => {
                var syncedMachines = ClusterConfiguration.GetNodes();
                var config         = ClusterConfiguration.GetClusterInfo();
                foreach (var node in syncedMachines)
                {
                    var services = _api.Get <List <RssdpServiceModel> >(node.ModelUrl + "device/services");
                    node.Services = services;
                }
                var importPortMapping = syncedMachines
                                        .Select(_ => _.Services)
                                        .Merge()
                                        .Select(_ => _.Name)
                                        .ToHashSet()
                                        .Select(_ => new Cluster.PortMapping {
                    ServiceName = _, ServicePort = "", VirtualPort = ""
                })
                                        .ToList()
                ;
                var existingPortMapping = config.PortMapping.ToList();
                foreach (var i in importPortMapping)
                {
                    if (existingPortMapping.FirstOrDefault(_ => _.ServiceName == i.ServiceName) == null)
                    {
                        existingPortMapping.Add(i);
                    }
                }
                config.PortMapping = existingPortMapping.ToList();
                var model = new PageAssetClusterModel {
                    Info            = config,
                    ClusterNodes    = syncedMachines.OrderBy(_ => _.Hostname).ThenBy(_ => _.PublicIp).ToList(),
                    NetworkAdapters = IPv4.GetAllLocalDescription().ToList()
                };
                return(JsonConvert.SerializeObject(model));
            };

            Post["/cluster/save"] = x => {
                string config = Request.Form.Config;
                string ip     = Request.Form.Ip;
                var    model  = JsonConvert.DeserializeObject <List <NodeModel> >(config);
                var    model2 = JsonConvert.DeserializeObject <Cluster.Configuration>(ip);
                ClusterConfiguration.SaveNodes(model);
                ClusterConfiguration.SaveConfiguration(model2);
                new Do().ClusterChanges();
                DeployClusterConfiguration();
                return(HttpStatusCode.OK);
            };

            Post["Accept Configuration", "/cluster/accept"] = x => {
                string file    = Request.Form.File;
                string content = Request.Form.Content;
                if (string.IsNullOrEmpty(file))
                {
                    return(HttpStatusCode.BadRequest);
                }
                if (string.IsNullOrEmpty(content))
                {
                    return(HttpStatusCode.BadRequest);
                }
                ConsoleLogger.Log($"[cluster] received config for file: {file}");

                DirectoryWatcherCluster.Stop();
                try {
                    FileWithAcl.WriteAllText(file, content, "644", "root", "wheel");
                }
                catch (Exception) {
                    ConsoleLogger.Warn("");
                    DirectoryWatcherCluster.Start();
                    return(HttpStatusCode.InternalServerError);
                }
                DirectoryWatcherCluster.Start();

                var dict = Dicts.DirsAndServices;
                if (dict.ContainsKey(file))
                {
                    ConsoleLogger.Log("[cluster] restart service bind to config file");
                    var services = dict[file];
                    foreach (var svc in services)
                    {
                        Systemctl.Enable(svc);
                        Systemctl.Restart(svc);
                    }
                }
                ConsoleLogger.Log("[cluster] apply changes after new config");
                new Do().HostChanges();
                new Do().NetworkChanges();
                DeployClusterConfiguration();
                return(HttpStatusCode.OK);
            };

            #region [    Handshake + cluster init    ]
            Post["/asset/handshake/start", true] = async(x, ct) => {
                string conf       = Request.Form.HostJson;
                var    remoteNode = JsonConvert.DeserializeObject <NodeModel>(conf);
                if (remoteNode == null)
                {
                    return(HttpStatusCode.InternalServerError);
                }
                const string pathToPrivateKey = "/root/.ssh/id_rsa";
                const string pathToPublicKey  = "/root/.ssh/id_rsa.pub";
                if (!File.Exists(pathToPublicKey))
                {
                    var k = Bash.Execute($"ssh-keygen -t rsa -N '' -f {pathToPrivateKey}");
                    ConsoleLogger.Log(k);
                }
                var key = File.ReadAllText(pathToPublicKey);
                if (string.IsNullOrEmpty(key))
                {
                    return(HttpStatusCode.InternalServerError);
                }
                var dict = new Dictionary <string, string> {
                    { "ApplePie", key }
                };
                var r = new ApiConsumer().Post($"{remoteNode.ModelUrl}asset/handshake", dict);
                if (r != HttpStatusCode.OK)
                {
                    return(HttpStatusCode.InternalServerError);
                }
                //ho fatto l'handshake, quindi il nodo richiesto è pronto per essere integrato nel cluster
                //1. controllo la configurazione
                var clusterConfiguration = ClusterConfiguration.GetClusterInfo();
                if (string.IsNullOrEmpty(clusterConfiguration.Guid))
                {
                    clusterConfiguration.Guid = Guid.NewGuid().ToString();
                }
                if (string.IsNullOrEmpty(clusterConfiguration.Priority))
                {
                    clusterConfiguration.Priority = "100";
                }
                if (string.IsNullOrEmpty(clusterConfiguration.NetworkInterface))
                {
                    clusterConfiguration.NetworkInterface = "";
                }
                if (string.IsNullOrEmpty(clusterConfiguration.VirtualIpAddress))
                {
                    clusterConfiguration.VirtualIpAddress = "";
                }
                //2. salvo la configurazione
                ClusterConfiguration.SaveConfiguration(clusterConfiguration);
                //3. controllo i nodi presenti nella configurazione
                var clusterNodes = ClusterConfiguration.GetNodes();
                var iplocals     = IPv4.GetAllLocalAddress().ToList();
                var disc         = await ServiceDiscovery.Rssdp.Discover();

                //4. per prima cosa controllo l'host locale
                var localNode = disc.FirstOrDefault(_ => iplocals.Contains(_.PublicIp));
                //5. se non c'è lo aggiungo
                if (clusterNodes.FirstOrDefault(_ => _.MachineUid == localNode.MachineUid && _.PublicIp == localNode.PublicIp) == null)
                {
                    clusterNodes.Add(localNode);
                }
                //7. se non c'è lo aggiungo
                if (clusterNodes.FirstOrDefault(_ => _.MachineUid == remoteNode.MachineUid && _.PublicIp == remoteNode.PublicIp) == null)
                {
                    clusterNodes.Add(remoteNode);
                }
                //8. salvo la configurazione dei nodi
                ClusterConfiguration.SaveNodes(clusterNodes);
                //9. riavvio/avvio il servizio di cluster
                new Do().ClusterChanges();
                DeployClusterConfiguration();
                return(HttpStatusCode.OK);
            };

            Post["/asset/handshake"] = x => {
                string apple = Request.Form.ApplePie;
                var    info  = apple.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                if (info.Length < 2)
                {
                    return(HttpStatusCode.InternalServerError);
                }
                var          key        = info[0];
                var          remoteUser = info[1];
                const string user       = "******";
                var          model      = new AuthorizedKeyModel {
                    RemoteUser = remoteUser,
                    User       = user,
                    KeyValue   = key
                };
                var authorizedKeysConfiguration = new AuthorizedKeysConfiguration();
                authorizedKeysConfiguration.AddKey(model);
                try {
                    DirectoryWithAcl.CreateDirectory("/root/.ssh");
                    const string authorizedKeysPath = "/root/.ssh/authorized_keys";
                    if (File.Exists(authorizedKeysPath))
                    {
                        var f = File.ReadAllText(authorizedKeysPath);
                        if (!f.Contains(apple))
                        {
                            FileWithAcl.AppendAllLines(authorizedKeysPath, new List <string> {
                                apple
                            }, "644", "root", "wheel");
                        }
                    }
                    else
                    {
                        FileWithAcl.WriteAllLines(authorizedKeysPath, new List <string> {
                            apple
                        }, "644", "root", "wheel");
                    }
                    Bash.Execute($"chmod 600 {authorizedKeysPath}", false);
                    Bash.Execute($"chown {user}:{user} {authorizedKeysPath}", false);
                    return(HttpStatusCode.OK);
                }
                catch (Exception ex) {
                    ConsoleLogger.Log(ex);
                    return(HttpStatusCode.InternalServerError);
                }
            };

            Post["/cluster/deploy"] = x => {
                var clusterConfiguration = Request.Form.Cluster;
                Cluster.DeployConf model = Newtonsoft.Json.JsonConvert.DeserializeObject <Cluster.DeployConf>(clusterConfiguration);
                ClusterConfiguration.SaveConfiguration(model.Configuration);
                ClusterConfiguration.SaveNodes(model.Nodes);
                new Do().ClusterChanges();
                return(HttpStatusCode.OK);
            };

            //Post["/asset/wol"] = x => {
            //    string mac = Request.Form.MacAddress;
            //    CommandLauncher.Launch("wol", new Dictionary<string, string> { { "$mac", mac } });
            //    return HttpStatusCode.OK;
            //};

            //Get["/asset/nmasp/{ip}"] = x => {
            //    string ip = x.ip;
            //    var result = CommandLauncher.Launch("nmap-ip-fast", new Dictionary<string, string> { { "$ip", ip } }).Where(_ => !_.Contains("MAC Address")).Skip(5).Reverse().Skip(1).Reverse();
            //    var list = new List<NmapScanStatus>();
            //    foreach(var r in result) {
            //        var a = r.SplitToList(" ").ToArray();
            //        var mo = new NmapScanStatus {
            //            Protocol = a[0],
            //            Status = a[1],
            //            Type = a[2]
            //        };
            //        list.Add(mo);
            //    }
            //    list = list.OrderBy(_ => _.Protocol).ToList();
            //    return JsonConvert.SerializeObject(list);
            //};
            #endregion
        }