📜 ⬆️ ⬇️

Sandbox with SCVMM

With the release of System Center Virtual Machine Manager 2012, we have the opportunity to create so-called services: i.e. to stamp virtual machines not one by one or even from templates, but to combine different profiles, templates, machines, and after that - to configure the relationship between virtual equipment. Having seen TechEd speeches, having read articles and books, and, of course, having received a magical task from the authorities on one of the projects, I decided that the available tools in SCVMM are enough to create a full-fledged sandbox service, i.e. a set of virtual machines, isolated from the rest of the infrastructure of the enterprise, but at the same time seamlessly interacting with each other.
But everything turned out to be not so smooth and beautiful as that of the ashapo at the demonstrations, so you are welcome under the cat for a dose of file processing.

Let's start with the fact that Microsoft’s service-oriented cloud ideology almost ideally falls on the task of creating a sandbox: here, please, you have a pool of resources, here, please, you are a sandbox, the sandbox runs in the cloud, people, for example, developers themselves, through the self-service portal, this sandbox create, delete, scale if necessary, receive reports on resource consumption, they do not care about what equipment the sandbox is running, do not care how it is reserved or who the hypervisor manages.
But when it comes to practice, to, in fact, automate the deployment of the service, there are limitations. In order to make them clearer, I’ll turn to Microsoft’s famous and beaten-up, Microsoft’s training application - Pet Shop .Net , by the way, already the 4th version.
Pet Shop is a common three-client client-server application: there is a DBMS server, there is an application server, and there is a web-snout that allows potential buyers to enter and select parrots via a browser. Therefore, when we deploy this application as a cloud service, we:

1. Deploy three virtual machines, a couple of empty ones, one with a SQL server, they will later become our links;
2. Install the application database on the SQL server, register users;
3. On the application server, roll out the App-V package with the store application, configure the connection lines to the SQL server;
4. Install web pages on the web-page, configure the web application to connect to the application server.

How is the deployment? First, when deploying Virtual Machine Manager, it creates a virtual floppy disk, writes a response file to the floppy disk and when the virtual machine is deployed, it reads the answer file, assigns itself a name, sets the network interface parameters and even includes itself in the Active Directory domain. At the second stage, SCVMM installs its agent and integration services to virtual machines, and at the third stage, it creates an ISO image with applications, databases, other configuration scripts, mounts this ISO image into a virtual drive and starts installing applications from it. As you can see, the interaction with the virtual machine occurs only with the help of primitive things: a virtual diskette and a virtual DVD, because the installation of the agent, as well as the installation of integration services, is also the installation from the corresponding ISO image in the drive.
')


It's like that? So, not so. The fact is that in order to build a connection string to a SQL server, you need to at least know the name of this SQL server. In order to collect the connection string to the application, you also need to know the server address of this application. Meanwhile, in System Center Virtual Machine Manager 2012, there are three ways to set the server name:

1. Set it simply with text, for example, “SQLServer”;
2. Set it with a template with digits, for example “SQLServer ##”, in this case, when the first server is created, SCVMM will give it the name SQLServer01, the second one - SQLServer02, etc .;
3. Set it to a variable, for example, "@ SQLServer @", in this case, the administrator will have to type in "SQLServerForPetShop" or something like the one that will later become the server name before deployment into the dialog box.

We dismiss the first option immediately, because we assume that we have a lot of services, which means that there are many machines with the same name, and it is bad to have machines with the same name. The second option is good, but the appearance of numbers at the end excludes the server being deterministic. Simply put, on link 2, we don’t know which SCVMM exactly assigned the number 1. In fact, we know what is at the beginning of SQLServer, and then what is 01? 05? Or maybe 25? The third option is good, no doubt, but in this case, the administrator himself, personally has to take care of the first, the uniqueness of the server names, and second, the correspondence of the names of the servers of the naming convention adopted in the organization. In general, it turns out that all three options are there, and all three are bad. How does Microsoft recommend getting out of this kind of situation? No way.

This picture from Aidan Finn’s Microsoft Private Cloud Computing book, published by Sybex, clearly shows that in order to deploy the Petshop service, you need to look into the upper part of the screen, see the words MidSvr01 and write these words down in the lobComputerName field.



Moreover, such a rewriting of letters from the screen onto the same screen is apparently the official position of Microsoft, which is repeated, for example, here in the Technet blogs.

That is, once again : they offer to see a line on the screen and drive this line with pens on the same screen .

Is this acceptable to us? Well, of course not! Information appears only in one place, unreasonable duplication of information is fraught with errors, and we will use this approach a little less than never in our life.

Let's return to our sandbox. Suppose we have a domain controller in an Active Directory forest and the server is a member of that domain. Theoretically, this is sufficient provided the service can be scaled, i.e. duplicating this domain member server yet, another, and another.

Formulating the technical task to the sandbox system, we can say that the system should contain an Active Directory domain controller that is not connected to other forests by any relationships, including trust relationships, and the system should also contain a server included in the Active domain A directory that could effortlessly be replicated. In this case, if you wish, we can roll onto the Exchange server, SQL Server, and much, much more.

Creating an Active Directory domain controller from SCVMM is not easy: a domain controller does not lend itself to App-V application virtualization, so we will install a domain controller from the command line. There is a dcpromo utility that creates a domain, even a forest, even a universe, and I can tell you, despite various articles from the category “The end of dcpromo has come, long live PowerShell!” Dcpromo is saved in Windows Server 2012, but only as a command tool lines. You can read about it, for example, here . Pay attention to the line:

If you run dcpromo / unattend from a command prompt, you can still perform unattended installations that use Dcpromo.exe

That is, unattend-installation can be perfectly used in Windows Server 2012, which, in fact, we need. Although, of course, PowerShell, we all love with unfading love, and with respect to innovations in 12, I even have a couple of articles. But for the sake of compatibility, we use the response file, because it works in both 2008R2 and 2012. So, to raise the Active Directory domain controller, we will run this cmd file associated with the application profile in the sandbox service:

%systemroot%\System32\WindowsPowerShell\v1.0\powershell.exe Set-ExecutionPolicy Unrestricted %systemroot%\System32\WindowsPowerShell\v1.0\powershell.exe .\CreateAnswerFile.ps1 -Domain %1 dcpromo /unattend:%systemroot%\Temp\dcpromo.ini shutdown -r -t 30 

Notice how it starts right from the start.
 Set-ExecutionPolicy Unrestricted 

For the simple reason that I have unsigned PowerShell scripts. PowerShell scripts can and should be signed: it depends on your security, the security of your organization. About how to sign, a couple of topics have already flown here, but if not, I will gladly describe this funny, but informative process.

Now look, a certain CreateAnswerFile.ps1 script is called , to which a domain is given as an input parameter. Here is the script:

 Param ([string]$Domain) [Reflection.Assembly]::LoadWithPartialName(“System.Web”) Enable-PSRemoting -force import-module servermanager add-windowsfeature DNS $RandPassLength = [int] 30 $DSRMPass = [System.Web.Security.Membership]::GeneratePassword($RandPassLength,2) $SafeModePWD = $DSRMPass $NetBIOSName=($Domain.Split(".")[0]).ToUpper() $DCPromoFile = @" [DCINSTALL] ReplicaOrNewDomain=Domain NewDomain=Forest NewDomainDNSName=$Domain ForestLevel=4 DomainNetBIOSName=$NetBIOSName DomainLevel=4 InstallDNS=Yes ConfirmGc=Yes CreateDNSDelegation=No DatabasePath=`"C:\Windows\NTDS`" LogPath=`"C:\Windows\NTDS`" SYSVOLPath=`"C:\Windows\SYSVOL`" RebootOnCompletion=No SafeModeAdminPassword=$SafeModePWD "@ $DCPromoFile | out-file C:\windows\temp\dcpromo.ini -force 

But again, note that I have% windir% here as C: \ windows, it is unlikely that you will have a different way, but I still have to warn you.

Okay, the domain controller we have raised, we like it. But in order for a server to be included as members of this domain, it must, first, get the address of this domain controller, and second, get the setting on its network interface: this domain controller must be installed as the DNS server, and thirdly, to receive a command for inclusion in the domain. And how do we get the ip address of the DNS server? After all, according to the condition of the problem, we are in an isolated network from everywhere and do not know anything, not even the name of the domain controller, which is being developed in parallel with us.

There is a way. Remember that SCVMM was once a guest agent? So, during the deployment of this guest agent, a configuration file with a service configuration is magically created inside it. This file contains information, firstly, terribly cropped, and secondly, available only to the system account (SYSTEM). But this, as you understand, the file will not save, because if the information is manifested, then it will not be destroyed. From this file, which is very similar to XML, except for the first 16 bits, we extract the name of the domain controller. Yes, yes, the one that was dynamically generated during service deployment. Having a name, we can resolve this name in the ip address, right?

No, it is not right, because we do not have a DNS server that would answer us, we simply do not know who to contact. Therefore, we call for help the good old NetBIOS protocol, which understands what a broadcast name resolution request is. In other words, we, knowing the name of the server, shout a loud shout to the network: "Well, such and such, respond!" And he replies: "Here I am, just don't hit me please!". We take its address as a DNS server, and then we include ourselves in the domain. Mission Accomplished .

Considering that this script is executed every time the service is scaled, we can execute it endlessly and thus our sandbox will turn into a “domain controller + (empty_server x N)”.

Well, now, please, the script itself:

 Start-Sleep 90 $scvmmGuestAgentProcess = Get-Process ScvmmGuestService $guestDirectory = $scvmmGuestAgentProcess.Path $settingsDirectory = (Split-Path $guestDirectory -Parent)+"\Settings" $uname = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name takeown /F $settingsDirectory /A /R /DY $goalStateFile = $settingsDirectory + "\DesiredGoalState.dat" $rule = $uname+":(R)" icacls $goalStateFile /grant $rule $goalStateText = [string](Get-Content $goalStateFile) $goalState = [xml]($goalStateText.Substring($goalStateText.IndexOf("<"))) $computerNames=($goalState.GuestGoalState.ServiceSettings.ServiceSetting | Where-Object {$_.name -eq "ServiceVMComputerNames"}).value $namesArray = $computerNames.Split("[]") $dCName = $namesArray[[array]::IndexOf($namesArray,"Domain controller")+1] $dCIP = (([System.Net.Dns]::gethostentry($dCName)).AddressList | Where-Object {$_.AddressFamily -eq "InterNetwork"}).IPAddressToString $wmi = Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = 'true'" $wmi.SetDNSServerSearchOrder($dCIP) $domain = ($goalState.GuestGoalState.ServiceSettings.ServiceSetting | Where-Object {$_.name -eq "Domain"}).value $domainUserName = $domain+"\administrator" $domainPassword = "Pa`$`$w0rd" $credentials = new-object -typename System.Management.Automation.PSCredential -ArgumentList $domainUserName,($domainPassword | ConvertTo-SecureString -AsPlainText -Force) Add-Computer -Credential $credentials -DomainName $domain Restart-Computer 

Please note, here I have a username / password clearly indicated. It is obvious that you will have to hide them for safety.
So, by including this script in the application profile, and executing it when deploying to N servers, we get our sandbox.



Now we can modify our sandbox as we please, write programs there, delete programs from there, create users, delete, modify the scheme, attributes, do what our heart desires. Well, if suddenly we spoil it, then remove the sandbox and create a new one in half an hour! Or even two sandboxes to create we will not be difficult. This is just a paradise for the developer and tester!
Idah Finn's blog is recommended for reading, he writes very nice things there.

Source: https://habr.com/ru/post/167665/


All Articles