Esempio n. 1
0
        /// <summary>
        /// Finds open VM's/IP addresses for EPRS.  Will follow these placement rules:
        /// (1) Use targeted VM's whenever possible (for Jedi and Oz - #of network connections)
        /// (2) Use small pools first to reduce fragmentation
        /// (3) Start as many EPRs as possible - notify if # cannot be fully satisfied
        /// </summary>
        /// <param name="pHosts">List of VM's to use</param>
        /// <param name="pOpts">Options form the command line</param>
        /// <returns>true if EPRs started, false if there was a problem</returns>
        static bool FitEPRs(List <HostVM> pHosts, Options pOpts)
        {
            List <int> _sorted = new List <int>();
            int        _hostNdx;
            int        _sortNdx;
            bool       _inserted;
            string     _targetVMIdentifier  = pOpts.IsJedi ? "255" : "765";
            string     _foreignVMIdentifier = pOpts.IsJedi ? "765" : "255";
            int        _numEPRs             = pOpts.StartNum > 0 ? pOpts.StartNum : pOpts.IsOz ? 765 : 255;

            //---------------------------------------------------------------------------------------------------------
            // First thing - remove all VM's from the list that either do not have any EPR instancs available, or
            // do not support the profile that was requested.
            _hostNdx = 0;
            bool _good2Use = false;

            do
            {
                for ( ; _hostNdx < pHosts.Count; _hostNdx++)
                {
                    //-----------------------------------------------------------------------------------------------------
                    // Because we allow the use of a Partial string for the Profile name, we need to resolve what was
                    // specified on the command line to a real profile (if it exists).  So - resolve the profile.
                    _good2Use = true;
                    string _tProf = pHosts[_hostNdx].FindProfile(pOpts.Profile);
                    if ((pHosts[_hostNdx].EPRInstancesAvailable == 0) || (string.IsNullOrEmpty(_tProf)))
                    {
                        _good2Use = false;
                        break;
                    }
                    if (!pOpts.AllowMix)
                    {
                        foreach (EPRInstance _locEpr in pHosts[_hostNdx].EPRs.Where(_inst => _inst.WasAlreadyExecuting))
                        {
//                            if ((_locEpr.WasAlreadyExecuting) && (string.Compare(_locEpr.Profile, _tProf, true) != 0))
                            if (string.Compare(_locEpr.Profile, _tProf, true) != 0)
                            {
                                _good2Use = false;
                                break;
                            }
                        }
                    }
                    if (!_good2Use)
                    {
                        break;
                    }
                    pHosts[_hostNdx].ProfileToStart = _tProf;
                }
                if (!_good2Use)
                {
                    GenUtils.Exclaim("Removing VM " + pHosts[_hostNdx].HostName + " because it does not match requirements.");
                    pHosts.RemoveAt(_hostNdx);
                }
            }while (_hostNdx < pHosts.Count);
            if (pHosts.Count == 0)
            {
                GenUtils.HangError("There are no VM's that match the requirements ?");
                return(false);
            }

            //---------------------------------------------------------------------------------------------------------
            // Sort the VM's that *could* be used according to the following rules:
            // 1 - The VM's that are "tailored" for the specified architecture, should be first in the list
            // 2 - The VM's with the fewest available EPR's should be before those with more available EPRS (to reduce
            //				fragmentation
            for (_hostNdx = 0; _hostNdx < pHosts.Count; _hostNdx++)
            {
                _inserted = false;
                for (_sortNdx = 0; _sortNdx < _sorted.Count; _sortNdx++)
                {
                    //-----------------------------------------------------------------------------------------------------
                    // Check for the case where what is on the front of the sorted list is NOT the targeted VM - and what
                    // is being placed now is a targeted VM - then put the targeted VM in the first spot  regardless of
                    // how many available EPRs it has.
                    if ((pHosts[_hostNdx].HostName.Contains(_targetVMIdentifier)) && (pHosts[_sorted[_sortNdx]].HostName.Contains(_foreignVMIdentifier)))
                    {
                        _inserted = true;
                        _sorted.Insert(_sortNdx, _hostNdx);
                        break;
                        //-----------------------------------------------------------------------------------------------------
                        // Ok - if the current Vm is the same tagretted platform as the one in the sorted list, then compare
                        // the numebr of available VM's - and sort them smallest to greatest.
                    }
                    else if (((pHosts[_hostNdx].HostName.Contains(_targetVMIdentifier)) && (pHosts[_sorted[_sortNdx]].HostName.Contains(_targetVMIdentifier))) ||
                             ((pHosts[_hostNdx].HostName.Contains(_foreignVMIdentifier)) && (pHosts[_sorted[_sortNdx]].HostName.Contains(_foreignVMIdentifier))))
                    {
                        if (pHosts[_hostNdx].EPRInstancesAvailable <= pHosts[_sorted[_sortNdx]].EPRInstancesAvailable)
                        {
                            _inserted = true;
                            _sorted.Insert(_sortNdx, _hostNdx);
                            break;
                        }
                    }
                }
                //-------------------------------------------------------------------------------------------------------
                // It may not be obvious, BUT if we reach here and have not yet inserted the current Host, then it has to
                // go at the end of the _sorted list.
                if (!_inserted)
                {
                    _sorted.Add(_hostNdx);
                }
            }

            // Now that we have the VM's sorted such that the VM's with the fewest available EPRs are first
            // in the list, we can start to use those VM's to bring up the EPRs requested. This is a cross between a first fit
            // and a best fit algorithm - and it should result in reducing "fragmentation" of EPR usage across Host VMs.
            _hostNdx = 0;
            int _cnt = _sorted.Count;

            do
            {
                //-------------------------------------------------------------------------------------------------------
                // The VM will not allow us to assign more EPR's to start than it has available - so, we can just assign
                // how many we need and then subtract what VM reorts is the number we can start.
                HostVM _vm = pHosts[_sorted[_hostNdx]];
                _vm.EPRsToStart      = _numEPRs;
                _vm.ProtocolsToStart = pOpts.EPRProtocols;
                _vm.WorkQ.Add(HostVM.HostOperations.Start);
                _vm.WorkStatus = HostVM.HostVMStatus.Pending;
                _numEPRs      -= _vm.EPRsToStart;
                ++_hostNdx;
            }while ((_numEPRs > 0) && (_hostNdx < _cnt));

            if (_numEPRs > 0)
            {
                GenUtils.Exclaim("There are not enough available EPR instances. Only " + (pOpts.StartNum - _numEPRs).ToString() +
                                 " will be started!\n\n");
            }
            return(true);
        }
Esempio n. 2
0
        /// <summary>
        /// Will read in a snapshot file and then exactly duplicate that snapshot on all specified VM's
        /// (if they are also in the snapshot file), or on all VM's that were in the snapshot file
        /// </summary>
        /// <param name="pHosts">List of VMs to load (specified or from the xml file)</param>
        /// <param name="pSnap"></param>
        static void LoadSnapShot(List <HostVM> pHosts, string pSnap)
        {
            //---------------------------------------------------------------------------------------------------------
            // We want the filename to always use .xml as an extension.  So - if the filename does not end in .xml -
            // append .xml to the filename.  Then, see if the file exists and carry on.
            string _extension = Path.GetExtension(pSnap);

            if (string.Compare(_extension, @".xml", true) != 0)
            {
                GenUtils.Exclaim("Snapshot file name must use .xml extension. Appending .xml to " + pSnap);
                pSnap += ".xml";
            }
            if (!File.Exists(pSnap))
            {
                GenUtils.HangError("Cannot find file : " + pSnap);
                GenUtils.Exclaim("Press Enter to exit...");
                Console.ReadLine();
                Environment.Exit(2);
            }
            GenUtils.Exclaim("Loading " + pSnap + "....");
            List <HostVM> Loaded   = new List <HostVM>();
            XmlDocument   _xReader = new XmlDocument();

            _xReader.Load(pSnap);

            //---------------------------------------------------------------------------------------------------------
            //Read the XML file and reconstruct the list of VM's and all the EPRs on each VM (EPR Host) from the file.
            //
            foreach (XmlNode _vmHost in _xReader.SelectSingleNode(@"EPRSnapShot"))
            {
                HostVM _tmpVM = new HostVM(_vmHost.Attributes.GetNamedItem(@"HostName").FirstChild.Value.Trim(), HostVM.HostOperations.Connect, true);
                foreach (XmlNode _eprInst in _vmHost.ChildNodes)
                {
                    string      _ip  = _eprInst.Attributes.GetNamedItem(@"EPR").FirstChild.Value;
                    EPRInstance _epr = new EPRInstance(IPAddress.Parse(_ip));
                    _tmpVM.EPRs.Add(_epr);
                    if (_eprInst.Attributes.GetNamedItem(@"Profile") != null)
                    {
                        string _prots = _eprInst.Attributes.GetNamedItem(@"Protocols").FirstChild.Value;
                        _epr.Profile = _eprInst.Attributes.GetNamedItem(@"Profile").FirstChild.Value;
                        _epr.SetProtocols(_prots);
                    }
                }
                Loaded.Add(_tmpVM);
            }

            //---------------------------------------------------------------------------------------------------------
            // To apply the snapshot, we have to follow this pattern:
            //	For every EPRHostVM that remains in the List of VMs (from the -VM option or the default hosts file)
            //					If there is not a match for it in the Snapshot file - remove it from the Hosts List
            //	For every EPRHostVM that remains in the list:
            //		Stop all EPR instances on the host
            //		Replicate, EPR Instance for EPR instance from the snapshot file to the host VM
            GenUtils.Exclaim("Applying snapshot....");
            bool _done;
            int  _hostNdx = 0;

            //-------------------------------------------------------------------------------------------------------
            // First - eliminate any Hosts that are in the main list and the not snapshot file...
            do
            {
                _done = true;
                for ( ; _hostNdx < pHosts.Count; _hostNdx++)
                {
                    if (Loaded.Find(_hst => string.Compare(_hst.HostName, pHosts[_hostNdx].HostName, true) == 0) == null)
                    {
                        _done = false;
                        break;
                    }
                }
                if (_hostNdx < pHosts.Count)
                {
                    GenUtils.Exclaim(pHosts[_hostNdx].HostName + " was not found in the Snapshot.  Removing Host from main list.");
                    pHosts.RemoveAt(_hostNdx);
                }
            }while (!_done);
            if (pHosts.Count == 0)
            {
                GenUtils.HangError("There are no EPR Host VMs left in the list of specified Hosts.");
                return;
            }

            //-------------------------------------------------------------------------------------------------------
            // Next, report on any hosts that were in the Snapshot file, but are NOT in the main Action List...
            _hostNdx = 0;
            do
            {
                _done = true;
                for ( ; _hostNdx < Loaded.Count; _hostNdx++)
                {
                    if (pHosts.Find(_hst => string.Compare(_hst.HostName, Loaded[_hostNdx].HostName, true) == 0) == null)
                    {
                        _done = false;
                        break;
                    }
                }
                if (_hostNdx < pHosts.Count)
                {
                    GenUtils.Exclaim(Loaded[_hostNdx].HostName + " was not found in the main List of EPR Host VMs.  Removing Host from snapshot list.");
                    Loaded.RemoveAt(_hostNdx);
                }
            }while (!_done);

            //---------------------------------------------------------------------------------------------------------
            // For the VMs that remain, they have been started because we could communciate with them and get their EPR
            // info) -- but now we must destroy any existing EPR instances.
            foreach (HostVM _host in pHosts)
            {
                _host.WorkQ.Add(HostVM.HostOperations.Stop);
                _host.WorkStatus = HostVM.HostVMStatus.Pending;
            }
            Dispatch(pHosts, true);

            //---------------------------------------------------------------------------------------------------------
            // Finally, we need to clone the snapshot Host EPR instances in the new HostVMs.
            foreach (HostVM _host in pHosts)
            {
                // Find the matching Host from the snapshot file...
                HostVM _clone = Loaded.Find(_hst => string.Compare(_hst.HostName, _host.HostName, true) == 0);
                if (_clone == null)
                {
                    throw new Exception("Could not find Expected EPR Host VM to clone (" + _host.HostName + ") ?!");
                }
                _host.EPRs = _clone.EPRs;
                _host.WorkQ.Add(HostVM.HostOperations.Clone);
                _host.WorkStatus = HostVM.HostVMStatus.Pending;
            }
            Dispatch(pHosts, true);
        }
Esempio n. 3
0
        /// <summary>
        /// Manages operations we want to perform on Host VM's.  Each VM utilizes a separate
        /// thread for the operation - but we want to be careful we do not get so many threads
        /// active that we just slow to a crawl or crash because we are out of resources.
        /// </summary>
        /// <param name="pHosts">List of Host VM's to use for the operation</param>
        /// <param name="pWait">Flag indicating to Wait until all threads complete. (Default = true)</param>
        static void Dispatch(List <HostVM> pHosts, bool pWait = true)
        {
            int  _threadsAvailable = NetDrive.Instance.MaxThreads;
            bool _done;
            bool _allStarted;
            int  _ndx;
            int  _removeNdx;

            do
            {
                //-------------------------------------------------------------------------------------------------------
                // We may have to traverse the inner loop multiple times - either if we run out of threads &/Or if we
                // are supposed to wait here until all threads complete. Reset )removeNdx so that we know not to remove]
                // any of the hosts.
                _done      = _allStarted = true;
                _removeNdx = -1;
                for (_ndx = 0; _ndx < pHosts.Count; _ndx++)
                {
                    HostVM _vm = pHosts[_ndx];
                    //-----------------------------------------------------------------------------------------------------
                    // The Workstatus field will tell us what we want to know.  Idle means there is nothing for the VM
                    // Object to do.  Pending means that there is an operation waiting to be executed (the normal state).
                    // Working means that the thread is currently active.  Done means that the thread has completed its
                    // task.
                    switch (_vm.WorkStatus)
                    {
                    //---------------------------------------------------------------------------------------------------
                    // If the work status is pending, then the WorkQ has one or more items on it that need to be started.
                    // In order to start an operation, we must be under the thread threshold. if we are at the threshold
                    // then we just skip it and try again next time through.  Because we set _allStarted to false, the
                    // Loop will not exit.
                    case HostVM.HostVMStatus.Pending:
                        _allStarted = _done = false;
                        if (_threadsAvailable > 0)
                        {
                            --_threadsAvailable;
                            GenUtils.Exclaim("Starting thread for " + _vm.WorkQ[0].ToString() + " on " + _vm.HostName);
                            _vm.DoWork();
                        }
                        break;

                    //---------------------------------------------------------------------------------------------------
                    // If the VM has a thread running, then we are not _done (if that matters) - so just set _done to
                    // false.
                    case HostVM.HostVMStatus.Working:
                        _done = false;
                        break;

                    //---------------------------------------------------------------------------------------------------
                    // If this VM's thread has completed, then we can return that thread (logically) to the available
                    // pool and potentially use it to start other threads.  We change the WorkStatus here ebcause this
                    // is where the threads are managed from.
                    case HostVM.HostVMStatus.Done:
                        _vm.WorkStatus = HostVM.HostVMStatus.Idle;
                        ++_threadsAvailable;
                        GenUtils.Exclaim(_vm.HostName + " worker thread has finished");
                        break;

                    //---------------------------------------------------------------------------------------------------
                    // Idle is the state that means that the VM has nothing on its workQ.
                    case HostVM.HostVMStatus.Idle:
                        break;

                    //---------------------------------------------------------------------------------------------------
                    // NotConnected means that we can not use this VM.  We were either unable to find it (perhaps it is
                    // powered down, or the Hostname was incorrect...) or we could not find/start the EPR Service.  When
                    // this happens, we have to remove the VM from out Host List because we cannot use it.
                    case HostVM.HostVMStatus.NotConnected:
                    case HostVM.HostVMStatus.Error:
                        _removeNdx  = _ndx;
                        _allStarted = false;
                        GenUtils.Exclaim(_vm.HostName + " is being removed from the use list.");
                        break;
                    }
                    if (_removeNdx >= 0)
                    {
                        // This is a bit of guerilla code -- we need to remove this VM from the list - but we can't remove
                        // it from within the for loop or the handler will die.  So - we have to trap it here, then break
                        // out of the for loop and then trap it again so we can remove it. Sigh.  Sometimes I REALLY miss c++
                        break;
                    }
                }
                //-----------------------------------------------------------------------------------------------------
                // If there is still stuff to do, and we arrive here, then sleep for a second to allow some other
                // work to happen.  Might be better to sleep for 2 or 3 seconds?
                if ((!_allStarted) || ((pWait) && (!_done)))
                {
                    if (_removeNdx >= 0)
                    {
                        pHosts.RemoveAt(_removeNdx);
                    }
                    Thread.Sleep(1000);
                }
            }while ((!_allStarted) || ((pWait) && (!_done)));

            if (pHosts.Count == 0)
            {
                throw new Exception("There are no VM's that can be used to satisfy the request");
            }
        }