http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/f38b9e7b/guide/blueprints/winrm/index.md ---------------------------------------------------------------------- diff --git a/guide/blueprints/winrm/index.md b/guide/blueprints/winrm/index.md new file mode 100644 index 0000000..0d29dbc --- /dev/null +++ b/guide/blueprints/winrm/index.md @@ -0,0 +1,630 @@ +--- +title: Windows Blueprints +layout: website-normal +children: +- client.md +--- + +Brooklyn can deploy to Windows servers using WinRM to run commands. These deployments can be +expressed in pure YAML, and utilise Powershell to install and manage the software process. +This approach is similar to the use of SSH for UNIX-like servers. + + +About WinRM +----------- + +WinRM - or *Windows Remote Management* to give its full title - is a system administration service provided in all +recent Windows Server operating systems. It allows remote access to system information (provided via WMI) and the +ability to execute commands. For more information refer to [Microsoft's MSDN article on Windows Remote +Management](https://msdn.microsoft.com/en-us/library/aa384426(v=vs.85).aspx). + +WinRM is available by default in Windows Server, but is not enabled by default. Brooklyn will, in most cases, be able +to switch on WinRM support, but this is dependent on your cloud provider supporting a user metadata service with script +execution (see [below](#user-metadata-service-requirement)). + + +Locations for Windows +--------------------- + +You must define a new location in Brooklyn for Windows deployments. Windows deployments require a different VM image +ID to Linux, as well as some other special configuration, so you must have separate Brooklyn locations for Windows and +Linux deployments. + +In particular, you will most likely want to set these properties on your location: + +* `imageId` or `imageNameRegex` - select your preferred Windows Server image from your cloud provider. +* `hardwareId` or `minRam`/`minCores` - since Windows machines generally require more powerful servers, ensure you get + a machine with the required specification. +* `useJcloudsSshInit` - this must be set to `false`. Without this setting, jclouds will attempt to connect to the new + VMs using SSH, which will fail on Windows Server. +* `templateOptions` - you may also wish to request a larger disk size. This setting is cloud specific; on AWS, you can + request a 100GB disk by setting this property to `{mapNewVolumeToDeviceName: ["/dev/sda1", 100, true]}`. + +In your YAML blueprint: + + ... + location: + jclouds:aws-ec2: + region: us-west-2 + identity: AKA_YOUR_ACCESS_KEY_ID + credential: <access-key-hex-digits> + imageNameRegex: Windows_Server-2012-R2_RTM-English-64Bit-Base-.* + imageOwner: 801119661308 + hardwareId: m3.medium + useJcloudsSshInit: false + templateOptions: {mapNewVolumeToDeviceName: ["/dev/sda1", 100, true]} + ... + +Alternatively, you can define a new named location in `brooklyn.properties`: + + brooklyn.location.named.AWS\ Oregon\ Win = jclouds:aws-ec2:us-west-2 + brooklyn.location.named.AWS\ Oregon\ Win.displayName = AWS Oregon (Windows) + brooklyn.location.named.AWS\ Oregon\ Win.imageNameRegex = Windows_Server-2012-R2_RTM-English-64Bit-Base-.* + brooklyn.location.named.AWS\ Oregon\ Win.imageOwner = 801119661308 + brooklyn.location.named.AWS\ Oregon\ Win.hardwareId = m3.medium + brooklyn.location.named.AWS\ Oregon\ Win.useJcloudsSshInit = false + brooklyn.location.named.AWS\ Oregon\ Win.templateOptions = {mapNewVolumeToDeviceName: ["/dev/sda1", 100, true]} + + + +A Sample Blueprint +------------------ + +Creating a Windows VM is done using the `org.apache.brooklyn.entity.software.base.VanillaWindowsProcess` entity type. This is very similar +to `VanillaSoftwareProcess`, but adapted to work for Windows and WinRM instead of Linux. We suggest you read the +[documentation for VanillaSoftwareProcess]({{ site.path.guide }}/blueprints/custom-entities.html#vanilla-software-using-bash) to find out what you +can do with this entity. + +Entity authors are strongly encouraged to write Windows Powershell or Batch scripts as separate +files, to configure these to be uploaded, and then to configure the appropriate command as a +single line that executes given script. + +For example - here is a simplified blueprint (but see [Tips and Tricks](#tips-and-tricks) below!): + + name: Server with 7-Zip + + location: + jclouds:aws-ec2: + region: us-west-2 + identity: AKA_YOUR_ACCESS_KEY_ID + credential: <access-key-hex-digits> + imageNameRegex: Windows_Server-2012-R2_RTM-English-64Bit-Base-.* + imageOwner: 801119661308 + hardwareId: m3.medium + useJcloudsSshInit: false + templateOptions: {mapNewVolumeToDeviceName: ["/dev/sda1", 100, true]} + + services: + - type: org.apache.brooklyn.entity.software.base.VanillaWindowsProcess + brooklyn.config: + templates.preinstall: + file:///Users/richard/install7zip.ps1: "C:\\install7zip.ps1" + install.command: powershell -command "C:\\install7zip.ps1" + customize.command: echo true + launch.command: echo true + stop.command: echo true + checkRunning.command: echo true + installer.download.url: http://www.7-zip.org/a/7z938-x64.msi + +The installation script - referred to as `/Users/richard/install7zip.ps1` in the example above - is: + + $Path = "C:\InstallTemp" + New-Item -ItemType Directory -Force -Path $Path + + $Url = "${config['installer.download.url']}" + $Dl = [System.IO.Path]::Combine($Path, "installer.msi") + $WebClient = New-Object System.Net.WebClient + $WebClient.DownloadFile( $Url, $Dl ) + + Start-Process "msiexec" -ArgumentList '/qn','/i',$Dl -RedirectStandardOutput ( [System.IO.Path]::Combine($Path, "stdout.txt") ) -RedirectStandardError ( [System.IO.Path]::Combine($Path, "stderr.txt") ) -Wait + +Where security-related operation are to be executed, it may require the use of `CredSSP` to obtain +the correct Administrator privileges: you may otherwise get an access denied error. See the sub-section +[How and Why to re-authenticate within a powershell script](#how-and-why-to-re-authenticate-within-a-powershell-script) for more details. + +This is only a very simple example. A more complex example can be found in the [Microsoft SQL Server blueprint in the +Brooklyn source code]({{ site.brooklyn.url.git }}/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql). + + +Tips and Tricks +--------------- + +The best practices for other entities (e.g. using [VanillaSoftwareProcess]({{ site.path.guide }}/blueprints/custom-entities.html#vanilla-software-using-bash)) +apply for WinRM as well. + +### Execution Phases + +Blueprint authors are strongly encouraged to provide an implementation for install, launch, stop +and checkRunning. These are vital for the generic effectors such as stopping and restarting the +process. + +### Powershell + +Powershell commands can be supplied using config options such as `launch.powershell.command`. + +This is an alternative to supplying a standard batch command using config such as `launch.command`. +For a given phase, only one of the commands (Powershell or Batch) should be supplied. + +### Getting the Right Exit Codes + +WinRM (or at least the chosen WinRM client!) can return a zero exit code even on error in certain +circumstances. It is therefore advisable to follow the guidelines below. + +*For a given command, write the Powershell or Batch script as a separate multi-command file. +Upload this (e.g. by including it in the `files.preinstall` configuration). For the configuration +of the given command, execute the file.* + +When you have a command inside the powershell script which want to report its non zero exiting, +please consider adding a check for its exit code after it. +Example: + + & "C:\install.exe" + If ($lastexitcode -ne 0) { + exit $lastexitcode + } + +For Powershell files, consider including + + $ErrorActionPreference = "Stop" + +at the start of the file. +`$ErrorActionPreference` Determines how Windows PowerShell responds to a non-terminating +error (an error that does not stop the cmdlet processing) at the +command line or in a script, cmdlet, or provider, such as the +errors generated by the Write-Error cmdlet. +https://technet.microsoft.com/en-us/library/hh847796.aspx + +See [Incorrect Exit Codes](#incorrect-exit-codes) under Known Limitations below. + +### Executing Scripts From Batch Commands + +In a batch command, you can execute a batch file or Powershell file. For example: + + install.command: powershell -NonInteractive -NoProfile -Command "C:\\install7zip.ps1" + +Or alternatively: + + install.command: C:\\install7zip.bat + +### Executing Scripts From Powershell + +In a Powershell command, you can execute a batch file or Powershell file. There are many ways +to do this (see official Powershell docs). For example: + + install.powershell.command: "& C:\\install7zip.ps1" + +Or alternatively: + + install.powershell.command: "& C:\\install7zip.bat" + +Note the quotes around the command. This is because the "&" has special meaning in a YAML value. + +### Uploading Script and Configuration Files + +Often, blueprints will require that (parameterized) scripts and configuration files are available to be copied to the +target VM. These must be URLs resolvable from the Brooklyn instance, or on the Brooklyn classpath. One simple way +to achieve this is to compile the support files into a .jar, which is then added to AMP's 'dropins' folder. Alternatively, +an OSGi bundle can be used, referenced from the catalog item. + +Ensure that these scripts end each line with "\r\n", rather than just "\n". + +There are two types of file that can be uploaded: plain files and templated files. A plain +file is uploaded unmodified. A templated file is interpreted as a [FreeMarker](http://freemarker.org) +template. This supports a powerful set of substitutions. In brief, anything (unescaped) of the form +`${name}` will be substituted, in this case looking up "name" for the value to use. + +Templated files (be they configuration files or scripts) gives a powerful way to inject dependent +configuration when installing an entity (e.g. for customising the install, or for referencing the +connection details of another entity). A common substitution is of the form `${config['mykey']}`. +This looks up a config key (in this case named "mykey") and will insert the value into the file. +Another common substitution is is of the form `${attribute['myattribute']}` - this looks up the +attribute named "myattribute" of this entity. + +Files can be referenced as URLs. This includes support for things like `classpath://mypath/myfile.bat`. +This looks for the given (fully qualified) resource on the Brooklyn classpath. + +The destination for the file upload is specified in the entity's configuration. Note that "\" must +be escaped. For example `"C:\\install7zip.ps1"`. + +A list of plain files to be uploaded can be configured under `files.preinstall`, `files.install` and +`files.runtime`. These are uploaded respectively prior to executing the `pre.install.command`, +prior to `install.command` and prior to `pre.launch.command`. + +A list of templated files to be uploaded can be configured under `templates.preinstall`, `templates.install` +and `templates.runtime`. The times these are uploaded is as for the plain files. The templates +substitutions will be resolved only at the point when the file is to be uploaded. + +For example: + + files.preinstall: + - classpath://com/acme/installAcme.ps1 + - classpath://com/acme/acme.conf + +### Parameterised Scripts + +Calling parameterised Batch and Powershell scripts is done in the normal Windows way - see +offical Microsoft docs. For example: + + install.command: "c:\\myscript.bat myarg1 myarg2" + +Or as a Powershell example: + + install.powershell.command: "& c:\\myscript.ps1 -key1 myarg1 -key2 myarg2" + +It is also possible to construct the script parameters by referencing attributes of this or +other entities using the standard `attributeWhenReady` mechanism. For example: + + install.command: $brooklyn:formatString("c:\\myscript.bat %s", component("db").attributeWhenReady("datastore.url")) + +### Powershell - Using Start-Process + +When you are invoking a command from a powershell script with `Start-Process` cmdlet, +please use the `-Wait` and the `-PassThru` arguments. +Example `Start-Process C:\mycommand -Wait -PassThru` + +Using `-Wait` guarantees that the script process and its children and thus the winrm session won't be terminated until it is finished. +`-PassThru` Returns a process object for each process that the cmdlet started. By default, this cmdlet does not generate any output. +See https://technet.microsoft.com/en-us/library/hh849848.aspx + +### Rebooting + +Where a reboot is required as part of the entity setup, this can be configured using +config like `pre.install.reboot.required` and `install.reboot.required`. If required, the +installation commands can be split between the pre-install, install and post-install phases +in order to do a reboot at the appropriate point of the VM setup. + +We Strongly recommend to **write blueprints in a way that they do NOT restart automatically windows** and +use one of the `pre.install.reboot.required` or `install.reboot.required` parameters to perform restart. + +### Install Location + +Blueprint authors are encouraged to explicitly specify the full path for file uploads, and +for paths in their Powershell scripts (e.g. for installation, configuration files, log files, etc). + +### How and Why to re-authenticate within a powershell script + +Some installation scripts require the use of security-related operations. In some environments, +these fail by default when executed over WinRM, even though the script may succeed when run locally +(e.g. by using RDP to connect to the machine and running the script manually). There may be no +clear indication from Windows why it failed (e.g. for MSSQL install, the only clue is a +security exception in the installation log). + +When a script is run over WinRM, the credentials under which the script are run are marked as +'remote' credentials, which are prohibited from running certain security-related operations. The +solution is to obtain a new set of credentials within the script and use those credentials to +required commands. + +The WinRM client uses Negotiate+NTLM to authenticate against the machine. +This mechanism applies certain restrictions to executing commands on the windows host. + +For this reason you should enable CredSSP on the windows host which grants all privileges available to the user. + https://technet.microsoft.com/en-us/library/hh849719.aspx#sectionSection4 + +To use `Invoke-Command -Authentication CredSSP` the Windows Machine has to have: +- Up and running WinRM over http. The custom-enable-credssp.ps1 script enables winrm over http because `Invoke-Command` use winrm over http by default. + Invoke-Command can be used with -UseSSL option but this will lead to modifying powershell scripts. + With always enabling winrm over http on the host, blueprint's powershell scripts remain consistent and not depend on the winrm https/http environments. + We hope future versions of winrm4j will support CredSSP out of the box and wrapping commands in Invoke-Command will not be needed. +- Added trusted host entries which will use Invoke-Command +- Allowed CredSSP + +All the above requirements are enabled in Apache Brooklyn through [brooklyn-server/software/base/src/main/resources/org/apache/brooklyn/software/base/custom-enable-credssp.ps1](https://github.com/apache/brooklyn-server/blob/master/software/base/src/main/resources/org/apache/brooklyn/software/base/custom-enable-credssp.ps1) +script which enables executing commands with CredSSP in the general case. +The script works for most of the Windows images out there version 2008 and later. + +Please ensure that Brooklyn's changes are compatible with your organisation's security policy. + +Check Microsoft Documentation for more information about [Negotiate authenticate mechanism on technet.microsoft.com](https://msdn.microsoft.com/en-us/library/windows/desktop/aa378748(v=vs.85).aspx) + +Re-authentication also requires that the password credentials are passed in plain text within the +script. Please be aware that it is normal for script files - and therefore the plaintext password - +to be saved to the VM's disk. The scripts are also accessible via the Brooklyn web-console's +activity view. Access to the latter can be controlled via +[Entitlements]({{site.path.guide}}/blueprints/java/entitlements.html). + +As an example (taken from MSSQL install), the command below works when run locally, but fails over +WinRM: + + ( $driveLetter + "setup.exe") /ConfigurationFile=C:\ConfigurationFile.ini + +The code below can be used instead (note this example uses Freemarker templating): + + & winrm set winrm/config/service/auth '@{CredSSP="true"}' + & winrm set winrm/config/client/auth '@{CredSSP="true"}' + # + $pass = '${attribute['windows.password']}' + $secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force + $mycreds = New-Object System.Management.Automation.PSCredential ($($env:COMPUTERNAME + "\${location.user}"), $secpasswd) + # + $exitCode = Invoke-Command -ComputerName $env:COMPUTERNAME -Credential $mycreds -ScriptBlock { + param($driveLetter) + $process = Start-Process ( $driveLetter + "setup.exe") -ArgumentList "/ConfigurationFile=C:\ConfigurationFile.ini" -RedirectStandardOutput "C:\sqlout.txt" -RedirectStandardError "C:\sqlerr.txt" -Wait -PassThru -NoNewWindow + $process.ExitCode + } -Authentication CredSSP -ArgumentList $driveLetter + # + exit $exitCode + +In this example, the `${...}` format is FreeMarker templating. Those sections will be substituted +before the script is uploaded for execution. To explain this example in more detail: + +* `${attribute['windows.password']}` is substituted for the entity's attribute "windows.password". + This (clear-text) password is sent as part of the script. Assuming that HTTPS and NTLM is used, + the script will be encrypted while in-flight. + +* The `${location.user}` gets (from the entity's machine location) the username, substituting this + text for the actual username. In many cases, this will be "Administrator". However, on some + clouds a different username (with admin privileges) will be used. + +* The username and password are used to create a new credential object (having first converted the + password to a secure string). + +* Credential Security Service Provider (CredSSP) is used for authentication, to pass the explicit + credentials when using `Invoke-Command`. + + +### Windows AMIs on AWS + +Windows AMIs in AWS change regularly (to include the latest Windows updates). If using the community +AMI, it is recommended to use an AMI name regex, rather than an image id, so that the latest AMI is +always picked up. If an image id is used, it may fail as Amazon will delete their old Windows AMIs. + +If using an image regex, it is recommended to include the image owner in case someone else uploads +a similarly named AMI. For example: + + brooklyn.location.named.AWS\ Oregon\ Win = jclouds:aws-ec2:us-west-2 + brooklyn.location.named.AWS\ Oregon\ Win.imageNameRegex = Windows_Server-2012-R2_RTM-English-64Bit-Base-.* + brooklyn.location.named.AWS\ Oregon\ Win.imageOwner = 801119661308 + ... + +## stdout and stderr in a Powershell script + +When calling an executable in a Powershell script, the stdout and stderr will usually be output to the console. +This is captured by Brooklyn, and shown in the activities view under the specific tasks. + +An alternative is to redirect stdout and stderr to a file on the VM, which can be helpful if one expects sys admins +to log into the VM. However, be warned that this would hide the stdout/stderr from Brooklyn's activities view. + +For example, instead of running the following: + + D:\setup.exe /ConfigurationFile=C:\ConfigurationFile.ini + + The redirect can be achieved by using the `Start-Process` scriptlet: + + Start-Process D:\setup.exe -ArgumentList "/ConfigurationFile=C:\ConfigurationFile.ini" -RedirectStandardOutput "C:\sqlout.txt" -RedirectStandardError "C:\sqlerr.txt" -PassThru -Wait + +The `-ArgumentList` is simply the arguments that are to be passed to the executable, `-RedirectStandardOutput` and +`RedirectStandardError` take file locations for the output (if the file already exists, it will be overwritten). The +`-PassThru` argument indicates that Powershell should write to the file *in addition* to the console, rather than +*instead* of the console. The `-Wait` argument will cause the scriptlet to block until the process is complete. + +Further details can be found on the [Start-Process documentation page](https://technet.microsoft.com/en-us/library/hh849848.aspx) +on the Microsoft TechNet site. + + +Troubleshooting +--------------- + +Much of the [operations troubleshooting guide]({{ site.path.guide }}/ops/troubleshooting/) is applicable for Windows blueprints. + +### User metadata service requirement + +WinRM requires activation and configuration before it will work in a standard Windows Server deployment. To automate +this, Brooklyn will place a setup script in the user metadata blob. Services such as Amazon EC2's `Ec2ConfigService` +will automatically load and execute this script. If your chosen cloud provider does not support `Ec2ConfigService` or +a similar package, or if your cloud provider does not support user metadata, then you must pre-configure a Windows image +with the required WinRM setup and make Brooklyn use this image. + +If the configuration options `userMetadata` or `userMetadataString` are used on the location, then this will override +the default setup script. This allows one to supply a custom setup script. However, if userMetadata contains something +else then the setup will not be done and the VM may not not be accessible remotely over WinRM. + +### Credentials issue requiring special configuration + +When a script is run over WinRM over HTTP, the credentials under which the script are run are marked as +'remote' credentials, which are prohibited from running certain security-related operations. This may prevent certain +operations. The installer from Microsoft SQL Server is known to fail in this case, for example. For a workaround, please +refer to [How and Why to re-authenticate withing a powershell script](#how-and-why-to-re-authenticate-within-a-powershell-script) +above. + +### WebServiceException: Could not send Message + +We detected a `WebServiceException` and different `SocketException` +during deployment of long lasting Application Blueprint against VcloudDirector. + +Launching the blueprint bellow was giving constantly this type of error on launch step. + + services: + type: org.apache.brooklyn.entity.software.base.VanillaWindowsProcess + brooklyn.config: + pre.install.command: echo preInstallCommand + install.command: echo installCommand > C:\\install.txt + post.install.command: echo postInstallCommand + customize.command: echo customizeCommand + pre.launch.command: echo preLaunchCommand + launch.powershell.command: | + Start-Sleep -s 400 + Write-Host Test Completed + post.launch.command: echo postLaunchCommand + checkRunning.command: echo checkRunningCommand + stop.command: echo stopCommand + +With series of tests we concluded that on the Vcloud Director environment we were using +a restart was happening ~2 minutes after the VM is provisioned. +Logging in the host and search for System event of type 1074 in Windows Event Viewer, we found two 1074 events where the second one was + + The process C:\Windows\system32\winlogon.exe (W2K12-STD) has initiated the restart of computer WIN-XXXX on behalf of user + NT AUTHORITY\SYSTEM for the following reason: Operating System: Upgrade (Planned) Reason Code: 0x80020003 Shutdown Type: restart Comment: + +Normally on other clouds only one restart event is registered and the first time winrm connection is made the Windows VM is ready for use. + +For this particular case when you want this second restart to finish we made `waitWindowsToStart` location parameter +which basically adds additional check assuring the Windows VM provisioning is done. + + +For example when using `waitWindowsToStart: 5m` location parameter, Apache Brooklyn will wait 5 minutes to see if a disconnect occurs. +If it does, then it will again wait 5m for the machine to come back up. +The default behaviour in Apache Brooklyn is to consider provisioning done on the first successful winrm connection, without waiting for restart. + + +To determine whether you should use this parameter you should carefully inspect how the image you choose to provision is behaving. +If the description above matches your case and you are getting **connection failure message in the middle of the installation process** for your blueprints, +a restart probably occurred and you should try this parameter. + +Before using this parameter we advice to check whether this is really your case. +To verify the behavior check as described above. + +### AMIs not found + +If using the imageId of a Windows community AMI, you may find that the AMI is deleted after a few weeks. +See [Windows AMIs on AWS](#windows-amis-on-aws) above. + +### VM Provisioning Times Out + +In some environments, provisioning of Windows VMs can take a very long time to return a usable VM. +If the image is old, it may install many security updates (and reboot several times) before it is +usable. + +On a VMware vCloud Director environment, the guest customizations can cause the VM to reboot (sometimes +several times) before the VM is usable. + +This could cause the WinRM connection attempts to timeout. The location configuration option +`waitForWinRmAvailable` defaults to `30m` (i.e. 30 minutes). This can be increased if required. + +Incorrectly prepared Windows template can cause the deployment to time-out expecting an interaction by the user. +You can verify if this is the case by RDP to the deployment which is taking to much time to complete. +It is recommended to manually deploy a single VM for every newly created Windows template to verify that it can be +used for unattended installations and it doesn't wait and/or require an input by the user. +See [Windows template settings for an Unattended Installation](#windows-template-settings-for-an-unattended-installation) under Known Limitations below. + +### Windows log files + +Details of the commands executed, and their results, can be found in the Brooklyn log and in the Brooklyn +web-console's activity view. + +There will also be log files on the Windows Server. System errors in Windows are usually reported in the Windows Event Log - +see [https://technet.microsoft.com/en-us/library/cc766042.aspx](https://technet.microsoft.com/en-us/library/cc766042.aspx) +for more information. + +Additional logs may be created by some Windows programs. For example, MSSQL creates a log in +`%programfiles%\Microsoft SQL Server\130\Setup Bootstrap\Log\` - for more information see +[https://msdn.microsoft.com/en-us/library/ms143702.aspx](https://msdn.microsoft.com/en-us/library/ms143702.aspx). + + +Known Limitations +----------------- + +WinRM 2.0 supports encryption mechanisms on top of HTTP. However those are not supported in Apache Brooklyn. +For production adoptions please make sure you follow Microsoft Guidelines https://msdn.microsoft.com/en-us/library/ee309366(v=vs.85).aspx + +### Apache Brooklyn limitations on using WinRM over HTTP and HTTPS + +By default Apache Brooklyn is currently using unencrypted HTTP for WinRM communication. It does not support encrypted HTTP for WinRM. + +HTTPS is supported but there is no mechanism of specifying which certificates to trust. +Currently Apache Brooklyn will accept any certificate used in a HTTPS WinRM connection. + +### Incorrect Exit Codes + +Some limitations with WinRM (or at least the chosen WinRM Client!) are listed below: + +##### Single-line Powershell files + +When a Powershell file contains just a single command, the execution of that file over WinRM returns exit code 0 +even if the command fails! This is the case for even simple examples like `exit 1` or `thisFileDoesNotExist.exe`. + +A workaround is to add an initial command, for example: + + Write-Host dummy line for workaround + exit 1 + +##### Direct Configuration of Powershell commands + +If a command is directly configured with Powershell that includes `exit`, the return code over WinRM +is not respected. For example, the command below will receive an exit code of 0. + + launch.powershell.command: | + echo first + exit 1 + +##### Direct Configuration of Batch commands + +If a command is directly configured with a batch exit, the return code over WinRM +is not respected. For example, the command below will receive an exit code of 0. + + launch.command: exit /B 1 + +##### Non-zero Exit Code Returned as One + +If a batch or Powershell file exits with an exit code greater than one (or negative), this will +be reported as 1 over WinRM. + +We advise you to use native commands (non-powershell ones) since executing it as a native command +will return the exact exit code rather than 1. +For instance if you have installmssql.ps1 script use `install.command: powershell -command "C:\\installmssql.ps1"` +rather than using `install.powershell.command: "C:\\installmssql.ps1"` +The first will give you an exact exit code rather than 1 + +### PowerShell "Preparing modules for first use" + +The first command executed over WinRM has been observed to include stderr saying "Preparing +modules for first use", such as that below: + + < CLIXML + <Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S="progress" RefId="1"><TNRef RefId="0" /><MS><I64 N="SourceId">2</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs> + +The command still succeeded. This has only been observed on private clouds (e.g. not on +AWS). It could be related to the specific Windows images in use. It is recommended that +VM images are prepared carefully, e.g. so that security patches are up-to-date and the +VM is suitably initialised. + +### WinRM executeScript failed: httplib.BadStatusLine: '' + +As described in https://issues.apache.org/jira/browse/BROOKLYN-173, a failure has been +observed where the 10 attempts to execute the command over WinRM failed with: + + httplib.BadStatusLine: '' + +Subsequently retrying the command worked. It is unclear what caused the failure, but could +have been that the Windows VM was not yet in the right state. + +One possible workaround is to ensure the Windows VM is in a good state for immediate use (e.g. +security updates are up-to-date). Another option is to increase the number of retries, +which defaults to 10. This is a configuration option on the machine location, so can be set on +the location's brooklyn.properties or in the YAML: + + execTries: 20 + +### Direct Configuration of Multi-line Batch Commands Not Executed + +If a command is directly configured with multi-line batch commands, then only the first line +will be executed. For example the command below will only output "first": + + launch.command: | + echo first + echo second + +The workaround is to write a file with the batch commands, have that file uploaded, and execute it. + +Note this is not done automatically because that could affect the capture and returning +of the exit code for the commands executed. + +### Install location + +Work is required to better configure a default install location on the VM (e.g. so that +environment variables are set). The installation pattern for linux-based blueprints, +of using brooklyn-managed-processes/installs, is not used or recommended on Windows. +Files will be uploaded to C:\ if no explicit directory is supplied, which is untidy, +unnecessarily exposes the scripts to the user, and could cause conflicts if multiple +entities are installed. + +Blueprint authors are strongly encourages to explicitly specific directories for file +uploads and in their Powershell scripts. + +### Windows template settings for an Unattended Installation + +Windows template needs certain configuration to be applied to prevent windows setup UI from being displayed. +The default behavior is to display it if there are incorrect or empty settings. Showing Setup UI will prevent the proper +deployment, because it will expect interaction by the user such as agreeing on the license agreement or some of the setup dialogs. + +Detailed instruction how to prepare an Unattended installation are provided at [https://technet.microsoft.com/en-us/library/cc722411%28v=ws.10%29.aspx](https://technet.microsoft.com/en-us/library/cc722411%28v=ws.10%29.aspx). +
http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/f38b9e7b/guide/blueprints/yaml-reference.md ---------------------------------------------------------------------- diff --git a/guide/blueprints/yaml-reference.md b/guide/blueprints/yaml-reference.md new file mode 100644 index 0000000..7a46970 --- /dev/null +++ b/guide/blueprints/yaml-reference.md @@ -0,0 +1,253 @@ +--- +title: YAML Blueprint Reference +layout: website-normal +--- + +## Root Elements + +* `name`: human readable names +* `services`: a list of `ServiceSpecification` elements +* `location` (or `locations` taking a list): a `LocationSpecification` element as a string or a map + + +## Service Specification Elements + +Within the `services` block, a list of maps should be supplied, with each map +defining a `ServiceSpecification`. Each `ServiceSpecification` should declare the +service `type` (synonyms `serviceType` and `service_type`), indicating what type of +service is being specified there. The following formats are supported for +defining types: + +* `com.acme.brooklyn.package.JavaEntityClass` +* `java:com.acme.brooklyn.package.JavaEntityClass` +* `java-entity-class` (where this has been added to the [catalog]({{ site.path.guide }}/blueprints/catalog/)) + +A reference of some of the common service `type` instances used is included in a section below. + +Within the `ServiceSpecification`, other key-value pairs can be supplied to customize +the entity being defined, with these being the most common: + +* `id`: an ID string, used to refer to this service + +* `location` (or `locations`): as defined in the root element + +* `brooklyn.config`: configuration key-value pairs passed to the service entity being created + +* `brooklyn.children`: a list of `ServiceSpecifications` which will be configured as children of this entity + +* `brooklyn.policies`: a list of policies, each as a map described with their `type` and their `brooklyn.config` as keys + +* `brooklyn.enrichers`: a list of enrichers, each as a map described with their `type` and their `brooklyn.config` as keys; + see the keys declared on individual enrichers; + also see [this enricher example](example_yaml/test-app-with-enrichers-slightly-simpler.yaml) for a detailed and commented illustration + <!-- TODO assert that this yaml maches the yaml we test against --> + +* `brooklyn.initializers`: a list of `EntityInitializer` instances to be constructed and run against the entity, + each as a map described with their `type` and their `brooklyn.config` as keys. + An `EntityInitiailzer` can perform arbitrary customization to an entity whilst it is being constructed, + such as adding dynamic sensors and effectors. These classes must expose a public constructor taking + a single `Map` where the `brooklyn.config` is passed in. + Some common initializers are: + + * `org.apache.brooklyn.core.effector.ssh.SshCommandEffector`: takes a `name` and `command`, + and optionally a map of named `parameters` to their `description` and `defaultValue`, + to define an effector with the given name implemented by the given SSH command + (on an entity which as an ssh-able machine) + + * `org.apache.brooklyn.core.sensor.ssh.SshCommandSensor`: takes a `name` and `command`, + and optionally a `period`, to create a sensor feed which populates the sensor with + the given name by running the given command (on an entity which as an ssh-able machine) + + * `org.apache.brooklyn.core.sensor.windows.WinRmCommandSensor`: For a command supplied via WinRm. Takes a `name`, `command`, + and optionally a `period` and `executionDir`, to create a sensor feed which populates the sensor with + the given name by running the given command (on an entity which as an winrm-able machine).<br/> + _`"~"` will use the default execution directory for the WinRm session which is usually `%USERPROFILE%`_ + +* `brooklyn.parameters`: documents a list of typed parameters the entity accepts. If none + are specified the config keys declared in the entity's class are used (including the + information from the `@CatalogConfig` annotation). The items have the following properties: + * `name` (required): identifier by which to reference the parameter when setting + or retrieving its value + * `label`: a value to present to the user, same as `name` if empty + * `description`: short text describing the parameter behaviour/usage, presented + to the user + * `type`: the type of the parameter, one of `string`, `integer`, `long`, `float`, + `double`, `timestamp`, `duration`, `port`, or a fully qualified Java type name; + the default is `string`; + obvious coercion is supported so + `timestamp` accepts most common ISO date formats, `duration` accepts `5m`, and port accepts `8080+` + * `default`: a default value; this will be coerced to the declared `type` + * `pinned`: mark the parameter as pinned (always displayed) for the UI. The default is `true` + * `constraints`: a list of constraints the parameter should meet; + for details, see [Entity Configuration]({{ site.path.guide }}/blueprints/entity-configuration.html#config-key-constraints). + + A shorthand notation is also supported where just the name of the parameter is supplied + as an item in the list, with the other values being unset or the default. + See `displayName` in the following example for an illustration of this: + + ~~~ yaml + brooklyn.parameters: + # user.age parameter is required, pinned and fully specified + - name: user.age + type: integer + label: Age + description: the age of the user + pinned: true + constraints: + - required + # user.name is optional, is not pinned and has a default + - name: user.name + default: You + pinned: false + # shorthand notation: displayName will be an optional config of type string with no default + - displayName + ~~~ + + Entities, policies, and initializers may accept additional key-value pairs, + usually documented in their documentation (e.g. javadoc), or in the case of Java + often as static fields in the underlying Java class. + Often there are config keys or flags (indicated by `@SetFromFlag`) declared on the class; + these declared flags and config keys may be passed in at the root of the `ServiceSpecification` or in `brooklyn.config`. + (Undeclared config is only accepted in the `brooklyn.config` map.) + Referencing the parameters from within java classes is identical to using config keys. In yaml it's + usually referenced using `$brooklyn:scopeRoot().config("displayName")`. See below for more details on scopes. + +* `brooklyn.tags`: documents a list of tag objects which should be assigned to the entity. + + +## Location Specification Elements + +<!-- TODO - expand this, currently it's concise notes --> + +In brief, location specs are supplied as follows, either for the entire application (at the root) +or for a specific `ServiceSpecification`: + + location: + jclouds:aws-ec2: + region: us-east-1 + identity: AKA_YOUR_ACCESS_KEY_ID + credential: <access-key-hex-digits> + +Or in many cases it can be in-lined: + + location: localhost + location: named:my_openstack + location: aws-ec2:us-west-1 + +For the first immediately, you'll need password-less ssh access to localhost. +For the second, you'll need to define a named location in `brooklyn.properties`, +using `brooklyn.location.named.my_openstack....` properties. +For the third, you'll need to have the identity and credentials defined in +`brooklyn.properties`, using `brooklyn.location.jclouds.aws-ec2....` properties. + +If specifying multiple locations, e.g. for a fabric: + + locations: + - localhost + - named:my_openstack + - aws-ec2:us-east-2 # if credentials defined in `brooklyn.properties + - jclouds:aws-ec2: + region: us-east-1 + identity: AKA_YOUR_ACCESS_KEY_ID + credential: <access-key-hex-digits> + +If you have pre-existing nodes, you can use the `byon` provider, either in this format: + + location: + byon: + user: root + privateKeyFile: ~/.ssh/key.pem + hosts: + - 81.95.144.58 + - 81.95.144.59 + - [email protected] + - [email protected] + +or: + + location: + byon: + user: root + privateKeyFile: ~/.ssh/key.pem + hosts: "{81.95.144.{58,59},[email protected].{139-140}" + +You cannot use glob expansions with the list notation, nor can you specify per-host +information apart from user within a single `byon` declaration. +However you can combine locations using `multi`: + + location: + multi: + targets: + - byon: + user: root + privateKeyFile: ~/.ssh/key.pem + hosts: + - 81.95.144.58 + - 81.95.144.59 + - byon: + privateKeyFile: ~/.ssh/brooklyn_key.pem + hosts: [email protected]{139-140} + + +## DSL Commands + +Dependency injection other powerful references and types can be built up within the YAML using the +concise DSL defined here: + +* `$brooklyn:attributeWhenReady("sensor")` will store a future which will be blocked when it is accessed, + until the given `sensor` from this entity "truthy" (i.e. non-trivial, non-empty, non-zero) value + (see below on `component` for looking up values on other sensors) +* `$brooklyn:config("key")` will insert the value set against the given key at this entity (or nearest ancestor); + can be used to supply config at the root which is used in multiple places in the plan +* `$brooklyn:sensor("sensor.name")` returns the given sensor on the current entity if found, or an untyped (Object) sensor; + `$brooklyn:sensor("com.acme.brooklyn.ContainingEntityClass", "sensor.name")` returns the strongly typed sensor defined in the given class +* `$brooklyn:entity("ID")` refers to a Brooklyn entity with the given ID; you can then access the following subfields, + using the same syntax as defined above but with a different reference entity, + e.g. `$brooklyn:entity("ID").attributeWhenReady("sensor")`: + * `.attributeWhenReady("sensor")` + * `.config("key")` + * `.sensor("sensor.name")` +* `$brooklyn:component("scope", "ID")` is also supported, to limit scope to any of + * `global`: looks for the `ID` anywhere in the plan + * `child`: looks for the `ID` anywhere in the child only + * `descendant`: looks for the `ID` anywhere in children or their descendants + * `sibling`: looks for the `ID` anywhere among children of the parent entity + * `parent`: returns the parent entity (ignores the `ID`) + * `this`: returns this entity (ignores the `ID`) +* `$brooklyn:root()` will return the topmost entity (the application) +* `$broopklyn:scopeRoot()` will return the root entity in the current plan scope. + For catalog items it's the topmost entity in the plan, for application plans it is the same as + `$brooklyn:root()`. +* `$brooklyn:formatString("pattern e.g. %s %s", "field 1", "field 2")` returns a future which creates the formatted string + with the given parameters, where parameters may be strings *or* other tasks such as `attributeWhenReady` +* `$brooklyn:urlEncode("val")` returns a future which creates a string with the characters escaped + so it is a valid part of a URL. The parameter can be a string *or* another task. For example, + `$brooklyn:urlEncode($brooklyn:config(\"mykey\"))`. It uses "www-form-urlencoded" for the encoding, + which is appropriate for query parameters but not for some other parts of the URL (e.g. space is encoded as '+'). +* `$brooklyn:literal("string")` returns the given string as a literal (suppressing any `$brooklyn:` expansion) +* `$brooklyn:object(Map)` creates an object, using keys `type` to define the java type, + and either `object.fields` or `brooklyn.config` to supply bean/constructor/flags to create an instance +* `$brooklyn:entitySpec(Map)` returns a new `ServiceSpecification` as defined by the given `Map`, + but as an `EntitySpec` suitable for setting as the value of `ConfigKey<EntitySpec>` config items + (such as `dynamiccluster.memberspec` in `DynamicCluster`) + +<!-- TODO examples for object and entitySpec --> + +Parameters above can be supplied either as strings or as lists and maps in YAML, +and the `$brooklyn:` syntax can be used within those parameters. + + +## Some Powerful YAML Entities + +All entities support configuration via YAML, but these entities in particular +have been designed for general purpose use from YAML. Consult the Javadoc for these +elements for more information: + +* **Vanilla Software** in `VanillaSoftwareProcess`: makes it very easy to build entities + which use `bash` commands to install and the PID to stop and restart +* **Chef** in `ChefSoftwareProcess`: makes it easy to use Chef cookbooks to build entities, + either with recipes following conventions or with configuration in the `ServiceSpecification` + to use artibitrary recipes +* `DynamicCluster`: provides resizable clusters given a `dynamiccluster.memberspec` set with `$brooklyn.entitySpec(Map)` as described above +* `DynamicFabric`: provides a set of homogeneous instances started in different locations, + with an effector to `addLocation`, i.e. add a new instance in a given location, at runtime http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/f38b9e7b/guide/index.md ---------------------------------------------------------------------- diff --git a/guide/index.md b/guide/index.md index cdb3b46..f3dbfff 100644 --- a/guide/index.md +++ b/guide/index.md @@ -8,8 +8,7 @@ children: - { path: /guide/start/index.md } - { path: /guide/misc/download.md } - { path: /guide/concepts/index.md } -- { path: /guide/yaml/index.md } -- { path: /guide/java/index.md } +- { path: /guide/blueprints/index.md } - { path: /guide/ops/index.md } - { path: /guide/misc/index.md } --- http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/f38b9e7b/guide/java/archetype.md ---------------------------------------------------------------------- diff --git a/guide/java/archetype.md b/guide/java/archetype.md deleted file mode 100644 index 4bc7325..0000000 --- a/guide/java/archetype.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: Creating from a Maven Archetype -layout: website-normal -toc: ../guide_toc.json -categories: [use, guide, defining-applications] ---- - -### Maven Archetype - -Brooklyn includes a maven archetype, which can be used to create the project structure for -developing a new Java entity, and generating the OSGi bundle for it. - - -#### Generating the Project - -The archetype can be used interactively, by running: -{% highlight bash %} -$ mvn archetype:generate -{% endhighlight %} - -The user will be prompted for the archetype to use (i.e. group "org.apache.brooklyn" -and artifact "brooklyn-archetype-quickstart"), as well as options for the project -to be created. - -Alternatively, all options can be supplied at the command line. For example, -if creating a project named "autobrick" for "com.acme": - -{% highlight bash %} -$ BROOKLYN_VERSION={{ site.brooklyn-version }} -$ mvn archetype:generate \ - -DarchetypeGroupId=org.apache.brooklyn \ - -DarchetypeArtifactId=brooklyn-archetype-quickstart \ - -DarchetypeVersion=${BROOKLYN_VERSION} \ - -DgroupId=com.acme \ - -DartifactId=autobrick \ - -Dversion=0.1.0-SNAPSHOT \ - -DpackageName=com.acme.autobrick \ - -DinteractiveMode=false -{% endhighlight %} - -This will create a directory with the artifact name (e.g. "autobrick" in the example above). -Note that if run from a directory containing a pom, it will also modify that pom to add this as -a module! - -The project will contain an example Java entity. You can test this using the supplied unit tests, -and also replace it with your own code. - -The `README.md` file within the project gives further guidance. - - -#### Building - -To build, run the commands: - -{% highlight bash %} -$ cd autobrick -$ mvn clean install -{% endhighlight %} - - -#### Adding to the Catalog - -The build will produce an OSGi bundle in `target/autobrick-0.1.0-SNAPSHOT.jar`, suitable for -use in the [Brooklyn catalog]({{ site.path.guide }}/ops/catalog/) (using `brooklyn.libraries`). - -To use this in your Brooklyn catalog you will first have to copy the target jar to a suitable location. -For developing/testing purposes storing on the local filesystem is fine. -For production use, we recommend uploading to a remote maven repository or similar. - -Once your jar is in a suitable location the next step is to add a new catalog item to Brooklyn. -The project comes with a `catalog.bom` file, located in `src/main/resources`. -Modify this file by adding a 'brooklyn.libraries' statement to the bom pointing to the jar. -For example: - -{% highlight yaml %} -brooklyn.catalog: - brooklyn.libraries: - - file:///path/to/jar/autobrick-0.1.0-SNAPSHOT.jar - version: "0.1.0-SNAPSHOT" - itemType: entity - items: - - id: com.acme.autobrick.MySample - item: - type: com.acme.autobrick.MySample -{% endhighlight %} - -The command below will use the CLI to add this to the catalog of a running Brooklyn instance: - -{% highlight bash %} - br catalog add catalog.bom -{% endhighlight %} - -After running that command, the OSGi bundle will have been added to the OSGi container, and the -entity will have been added to your catalog. It can then be used in the same way as regular AMP -entities. - -For example, you can use the blueprint: - -{% highlight yaml %} -services: -- type: com.acme.autobrick.MySample -{% endhighlight %} - - -### Testing Entities - -The project comes with unit tests that demonstrate how to test entities, both within Java and -also using YAML-based blueprints. - -A strongly recommended way is to write a YAML test blueprint using the test framework, and making -this available to anyone who will use your entity. This will allow users to easily run the test -blueprint in their own environment (simply by deploying it to their own Brooklyn server) to confirm -that the entity is working as expected. An example is contained within the project at -`src/test/resources/sample-test.yaml`. http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/f38b9e7b/guide/java/bundle-dependencies.md ---------------------------------------------------------------------- diff --git a/guide/java/bundle-dependencies.md b/guide/java/bundle-dependencies.md deleted file mode 100644 index 5a894eb..0000000 --- a/guide/java/bundle-dependencies.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: Handling Bundle Dependencies -layout: website-normal ---- - -Some Java blueprints will require third party libraries. These need to be made available to the -Apache Brooklyn runtime. There are a number of ways this can be achieved. - -### Classic Mode: Dropins Folder - -In Brooklyn classic mode (i.e. when not using Karaf), jars can be added to `./lib/dropins/`. -After restarting Brooklyn, these will be available on the classpath. - -In Brooklyn classic mode, there is an embedded OSGi container. This is used for installing -libraries referenced in catalog items. - -### OSGi Bundles - -#### Introduction to OSGi Bundles - -An [OSGi bundle](https://en.wikipedia.org/wiki/OSGi#Bundles) is a jar file with additional -metadata in its manifest file. The `MANIFEST.MF` file contains the symbolic name and version -of the bundle, along with details of its dependencies and of the packages it exports -(which are thus visible to other bundles). - -The [maven-bundle-plugin](http://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html) -is a convenient way of building OSGi bundles. - -#### OSGi Bundles Declared in Catalog Items - -Within a [catalog item]({{ site.path.guide}}/ops/catalog/), a list of URLs can be supplied under -`brooklyn.libraries`. Each URL should point to an OSGi bundle. This list should include the OSGi -bundle that has the Java code for your blueprint, and also the OSGi bundles that it depends -on (including all transitive dependencies). - -It is vital that these jars are built correctly as OSGi bundles, and that all transitive -dependencies are included. The bundles will be added to Karaf in the order given, so a bundle's -dependencies should be listed before the bundle(s) that depend on them. - -In the [GistGenerator example]({{ site.path.guide}}/java/defining-and-deploying.html), the -[catalog.bom file]({{ site.path.guide}}/java/gist_generator/gist_generator.bom) included -the URL of the dependency `org.eclipse.egit.github.core`. It also (before that line) included -its transitive dependency, which is a specific version of `gson`. - -For Java blueprint developers, this is often the most convenient way to share a blueprint. - -Similarly for those wishing to use a new blueprint, this is often the simplest mechanism: the -dependencies are fully described in the catalog item, which makes it convenient for deploying -to Apache Brooklyn instances where there is not direct access to Karaf or the file system. - - -#### Adding Bundles and Features Directly to Karaf - -Bundles and features can be added manually, directly to Karaf. - -However, note this only affects the single Karaf instance. If running in HA mode or if provisioning -a new instance of Apache Brooklyn, the bundles will also need to be added to these Karaf instances. - - -##### Karaf Console - -Login to the [Karaf console](https://karaf.apache.org/manual/latest/#_shell_console_basics) -using `./bin/client`, and add the bundles and features as desired. - -Examples of some useful commands are shown below: - -{% highlight bash %} -karaf@amp> bundle:install -s http://repo1.maven.org/maven2/org/apache/servicemix/bundles/org.apache.servicemix.bundles.egit.github.core/2.1.5_1/org.apache.servicemix.bundles.egit.github.core-2.1.5_1.jar -Bundle ID: 316 - -karaf@amp> bundle:list -t 0 -s | grep github -318 | Active | 80 | 2.1.5.1 | org.apache.servicemix.bundles.egit.github.core - -karaf@amp> bundle:headers org.apache.servicemix.bundles.egit.github.core -... - -karaf@amp> bundle:uninstall org.apache.servicemix.bundles.egit.github.core -{% endhighlight %} - - -##### Karaf Deploy Folder - -Karaf support [hot deployment](https://karaf.apache.org/manual/latest/#_deployers). There are a -set of deployers, such as feature and KAR deployers, that handle deployment of artifacts added -to the `deploy` folder. - -Note that the Karaf console can give finer control (including for uninstall). - - -### Karaf KAR files - -[Karaf KAR](https://karaf.apache.org/manual/latest/kar) is an archive format (Karaf ARchive). -A KAR is a jar file (so a zip file), which contains a set of feature descriptors and bundle jar files. - -This can be a useful way to bundle a more complex Java blueprint (along with its dependencies), to -make it easier for others to install. - -A KAR file can be built using the -[maven plugin org.apache.karaf.tooling:features-maven-plugin](https://karaf.apache.org/manual/latest/#_maven). - - -### Karaf Features - -A [karaf feature.xml](https://karaf.apache.org/manual/latest/#_create_a_features_xml_karaf_feature_archetype) -defines a set of bundles that make up a feature. Once a feature is defined, one can add it to a Karaf instance: -either directly (e.g. using the [Karaf console](https://karaf.apache.org/manual/latest/#_shell_console_basics)), or -by referencing it in another feature.xml file. - - -### Embedded Dependencies - -An OSGi bundle can -[embed jar dependencies](http://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html#embedding-dependencies) -within it. This allows dependencies to be kept private within a bundle, and easily shipped with that bundle. - -To keep these private, it is vital that the OSGi bundle does not import or export the packages -contained within those embedded jars, and does not rely on any of those packages in the public -signatures of any packages that are exported or imported. - - -### Converting Non-OSGi Dependencies to Bundles - -If a dependencies is not available as an OSGi bundle (and you don't want to just [embed the jar](#embedded-dependencies)), -there are a few options for getting an equivalent OSGi bundle: - -* Use a ServiceMix re-packaged jar, if available. ServiceMix have re-packed many common dependencies as - OSGi bundles, and published them on [Maven Central](https://search.maven.org). - -* Use the `wrap:` prefix. The [PAX URL Wrap protocol](https://ops4j1.jira.com/wiki/display/paxurl/Wrap+Protocol) - is an OSGi URL handler that can process your legacy jar at runtime and transform it into an OSGi bundle. - This can be used when declaring a dependency in your feature.xml, and when using the Karaf console's - `bundle:install`. Note that it is not yet supported in Brooklyn's `brooklyn.libraries` catalog items. - -* Re-package the bundle yourself, offline, to produce a valid OSGi bundle. - http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/f38b9e7b/guide/java/common-usage.md ---------------------------------------------------------------------- diff --git a/guide/java/common-usage.md b/guide/java/common-usage.md deleted file mode 100644 index ccafd9b..0000000 --- a/guide/java/common-usage.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: Common Classes and Entities -layout: website-normal ---- - -<!-- TODO old, needs work (refactoring!) and use of java_link --> - -### Entity Class Hierarchy - -By convention in Brooklyn the following words have a particular meaning: - -* *Group* - a homogeneous grouping of entities (which need not all be managed by the same parent - entity) -* *Cluster* - a homogeneous collection of entities (all managed by the "cluster" entity) -* *Fabric* - a multi-location collection of entities, with one per location; often used with a cluster per location -* *Application* - a top-level entity, which can have one or more child entities. - -The following constructs are often used for Java entities: - -* *entity spec* defines an entity to be created; used to define a child entity, or often to - define the type of entity in a cluster. -* *traits* (mixins) providing certain capabilities, such as *Resizable* and *Startable*. -* *Resizable* entities can re-sized dynamically, to increase/decrease the number of child entities. - For example, scaling up or down a cluster. It could similarly be used to vertically scale a VM, - or to resize a disk. -* *Startable* indicates the effector to be executed on initial deployment (`start()`) and on - tear down (`stop()`). - - -### Configuration - -Configuration keys are typically defined as static named fields on the Entity interface. These -define the configuration values that can be passed to the entity during construction. For -example: - -{% highlight java %} -public static final ConfigKey<String> ROOT_WAR = new ConfigKeys.newStringConfigKey( - "wars.root", - "WAR file to deploy as the ROOT, as URL (supporting file: and classpath: prefixes)"); -{% endhighlight %} - -One can optionally define a `@SetFromFlag("war")`. This defines a short-hand for configuring the -entity. However, it should be used with caution - when using configuration set on a parent entity -(and thus inherited), the `@SetFromFlag` short-form names are not checked. The long form defined -in the constructor should be meaningful and sufficient. The usage of `@SetFromFlag` is therefore -discouraged. - -The type `AttributeSensorAndConfigKey<?>` can be used to indicate that a config key should be resolved, -and its value set as a sensor on the entity (when `ConfigToAttributes.apply(entity)` is called). - -A special case of this is `PortAttributeSensorAndConfigKey`. This is resolved to find an available -port (by querying the target location). For example, the value `8081+` means that then next available -port starting from 8081 will be used. - - -### Declaring Sensors - -Sensors are typically defined as static named fields on the Entity interface. These define -the events published by the entity, which interested parties can subscribe to. For example: - -{% highlight java %} -AttributeSensor<String> MANAGEMENT_URL = Sensors.newStringSensor( - "crate.managementUri", - "The address at which the Crate server listens"); -{% endhighlight %} - - -### Declaring Effectors - -Effectors are the operations that an entity supports. There are multiple ways that an entity can -be defined. Examples of each are given below. - -#### Effector Annotation - -A method on the entity interface can be annotated to indicate it is an effector, and to provide -metadata about the effector and its parameters. - -{% highlight java %} [email protected](description="Retrieve a Gist") -public String getGist(@EffectorParam(name="id", description="Gist id") String id); -{% endhighlight %} - - -#### Static Field Effector Declaration - -A static field can be defined on the entity to define an effector, giving metadata about that effector. - -{% highlight java %} -public static final Effector<String> EXECUTE_SCRIPT = Effectors.effector(String.class, "executeScript") - .description("invokes a script") - .parameter(ExecuteScriptEffectorBody.SCRIPT) - .impl(new ExecuteScriptEffectorBody()) - .build(); -{% endhighlight %} - -In this example, the implementation of the effector is an instance of `ExecuteScriptEffectorBody`. -This implements `EffectorBody`. It will be invoked whenever the effector is called. - - -#### Dynamically Added Effectors - -An effector can be added to an entity dynamically - either as part of the entity's `init()` -or as separate initialization code. This allows the implementation of the effector to be shared -amongst multiple entities, without sub-classing. For example: - -{% highlight java %} -Effector<Void> GET_GIST = Effectors.effector(Void.class, "createGist") - .description("Create a Gist") - .parameter(String.class, "id", "Gist id") - .buildAbstract(); - -public static void CreateGistEffectorBody implements EffectorBody<Void>() { - @Override - public Void call(ConfigBag parameters) { - // impl - return null; - } -} - -@Override -public void init() { - getMutableEntityType().addEffector(CREATE_GIST, new CreateGistEffectorBody()); -} -{% endhighlight %} - - -### Effector Invocation - -There are several ways to invoke an effector programmatically: - -* Where there is an annotated method, simply call the method on the interface. - -* Call the `invoke` method on the entity, using the static effector declaration. For example: - `entity.invoke(CREATE_GIST, ImmutableMap.of("id", id));`. - -* Call the utility method `org.apache.brooklyn.core.entity.Entities.invokeEffector`. For example: - `Entities.invokeEffector(this, targetEntity, CREATE_GIST, ImmutableMap.of("id", id));`. - -When an effector is invoked, the call is intercepted to wrap it in a task. In this way, the -effector invocation is tracked - it is shown in the Activity view. - -When `invoke` or `invokeEffector` is used, the call returns a `Task` object (which extends -`Future`). This allows the caller to understand progress and errors on the task, as well as -calling `task.get()` to retrieve the return value. Be aware that `task.get()` is a blocking -function that will wait until a value is available before returning. - - -### Tasks - -_Warning: the task API may be changed in a future release. However, backwards compatibility -will be maintained where possible._ - -When implementing entities and policies, all work done within Brooklyn is executed as Tasks. -This makes it trackable and visible to administrators. For the activity list to show a break-down -of an effector's work (in real-time, and also after completion), tasks and sub-tasks must be -created. - -In common situations, tasks are implicitly created and executed. For example, when implementing -an effector using the `@Effector` annotation on a method, the method invocation is automatically -wrapped as a task. Similarly, when a subscription is passed an event (e.g. when using -`SensorEventListener.onEvent(SensorEvent<T> event)`, that call is done inside a task. - -Within a task, it is possible to create and execute sub-tasks. A common way to do this is to -use `DynamicTasks.queue`. If called from within a a "task queuing context" (e.g. from inside an -effector implementation), it will add the task to be executed. By default, the outer task will not be -marked as done until its queued sub-tasks are complete. - -When creating tasks, the `TaskBuilder` can be used to create simple tasks or to create compound tasks -whose sub-tasks are to be executed either sequentially or in parallel. For example: - -{% highlight java %} -TaskBuilder.<Integer>builder() - .displayName("stdout-example") - .body(new Callable<Integer>() { public Integer call() { System.out.println("example"; } }) - .build(); -{% endhighlight %} - -There are also builder and factory utilities for common types of operation, such as executing SSH -commands using `SshTasks`. - -A lower level way to submit tasks within an entity is to call `getExecutionContext().submit(...)`. -This automatically tags the task to indicate that its context is the given entity. - -An even lower level way to execute tasks (to be ignored except for power-users) is to go straight -to the `getManagementContext().getExecutionManager().submit(...)`. This is similar to the standard -Java `Executor`, but also supports more metadata about tasks such as descriptions and tags. -It also supports querying for tasks. There is also support for submitting `ScheduledTask` -instances which run periodically. - -The `Tasks` and `BrooklynTaskTags` classes supply a number of conveniences including builders to -make working with tasks easier. - - -### Subscriptions and the Subscription Manager - -Entities, locations, policies and enrichers can subscribe to events. These events could be -attribute-change events from other entities, or other events explicitly published by the entities. - -A subscription is created by calling `subscriptions().subscribe(entity, sensorType, sensorEventListener)`. -The `sensorEventListener` will be called with the event whenever the given entity emits a sensor of -the given type. If `null` is used for either the entity or sensor type, this is treated as a -wildcard. - -It is very common for a policy or enricher to subscribe to events, to kick off actions or to -publish other aggregated attributes or events. http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/f38b9e7b/guide/java/defining-and-deploying.md ---------------------------------------------------------------------- diff --git a/guide/java/defining-and-deploying.md b/guide/java/defining-and-deploying.md deleted file mode 100644 index 8c1fc6e..0000000 --- a/guide/java/defining-and-deploying.md +++ /dev/null @@ -1,177 +0,0 @@ ---- -title: Defining and Deploying -layout: website-normal ---- - -## Intro - -This walkthrough will set up a simple entity, add it to the catalog, and provision it. - -For illustration purposes, we will write an integration with [Github Gist](https://gist.github.com/), -with an effector to create new gists. - - -## Project Setup - -Follow the instructions to create a new Java project using the [archetype](archetype.html), and -import it into your [favorite IDE]({{ site.path.guide }}/dev/env/ide/). This example assumes you -used the groupId `com.acme` and artifact id `autobrick`. - -First ensure you can build this project at the command line, using `mvn clean install`. - - -## Java Entity Classes - -For this particular example, we will use a third party Gist library, so will need to add that as -a dependency. Add the following to your `pom.xml` inside the `<dependencies>` section -(see [Maven](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html) -for more details): - -{% highlight xml %} -<dependency> - <groupId>org.eclipse.mylyn.github</groupId> - <artifactId>org.eclipse.egit.github.core</artifactId> - <version>2.1.5</version> -</dependency> -{% endhighlight %} - -Create a new Java interface, `GistGenerator`, to describe the entity's interface (i.e. the -configuration options, sensors, and effectors). The code below assumes you have created this -in the package `com.acme` for `src/main/java`. - -{% highlight java %} -{% readj gist_generator/GistGenerator.java %} -{% endhighlight %} - -To describe each part of this: - -* The `@ImplementedBy` indicates the implementation class for this entity type - i.e. the class - to instantiate when an entity of this type is created. -* By extending `Entity`, we indicate that this interface is an Entity type. We could alternatively - have extended one of the other sub-types of Entity. -* The `OAUTH_KEY` is a configuration key - it is configuration that can be set on the entity when - it is being instantiated. -* The `@Effector` annotation indicates that the given method is an effector, so should be presented - and tracked as such. Execution of the effector is intercepted, to track it as a task and show its - execution in the Activity view. -* The `@EffectorParam` annotations give metadata about the effector's parameters. This metadata, - such as the parameter description, is available to those using the client CLI, rest API and - web-console. - -Note there is an alternative way of defining effectors - adding them to the entity dynamically, -discussed in the section [Dynamically Added Effectors](common-usage.html#dynamically-added-effectors). - -Next lets add the implementation. Create a new Java class named `GistGeneratorImpl`. - -{% highlight java %} -{% readj gist_generator/GistGeneratorImpl.java %} -{% endhighlight %} - -To describe each part of this: - -* Extends `AbstractEntity` - all entity implementations should extend this, or one of its - sub-types. -* Implements `GistGenerator`: this is the Entity type definition, so must be implemented. - Users of the entity will only refer to the interface; they will never be given an instance - of the concrete class - instead a [dynamic proxy](https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html) - is used (to allow remoting). -* `org.slf4j.Logger` is the logger used throughout Apache Brooklyn. -* Implements the `createGist` effector - we do not need to re-declare all the annotations. -* If no `oath.key` parameter was passed in, then use the configuration set on the entity. -* Use the third party library to create the gist. - - -### Configuring GitHub - -First, create a github.com account, if you do not already have one. - -Before running the blueprint, we'll need to generate an access token that has permissions to -create a gist programmatically. - -First [create a new access token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) -that our blueprint will use to create a gist: - -[](gist_generator/gist_create_token.png) - -Next, grant the token rights to create gists: - -[](gist_generator/gist_grant_access.png) - - -### Testing - -The archetype project comes with example unit tests that demonstrate how to test entities, -both within Java and also using YAML-based blueprints. - -We will create a similar Java-based test for this blueprint. Create a new Java class named -`GistGeneratorTest` in the package `com.acme`, inside `src/test/java`. - -You will need to substitute the github access token you generated in the previous section for -the placeholder text `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`. - -{% highlight java %} -{% readj gist_generator/GistGeneratorTest.java %} -{% endhighlight %} - -Similarly, we can write a test that uses the `GistGenerator` from a YAML blueprint. -Create a new Java class named `GistGeneratorYamlTest` in the package `com.acme`, -inside `src/test/java`. - -Again you will need to substitute the github access token you generated in the previous section for -the placeholder text `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`. See the section on -[externalised configuration]({{ site.path.guide }}/ops/externalized-configuration.html) -for how to store these credentials more securely. - -{% highlight java %} -{% readj gist_generator/GistGeneratorYamlTest.java %} -{% endhighlight %} - - -## Building the OSGi Bundle - -Next we will build this example as an [OSGi Bundle](https://www.osgi.org/developer/architecture/) -so that it can be added to the Apache Brooklyn server at runtime, and so multiple versions of the -blueprint can be managed. - -The `mvn clean install` will automatically do this, creating a jar inside the `target/` sub-directory -of the project. This works by using the -[Maven Bundle Plugin](http://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html) -which we get automatically by declaring the `pom.xml`'s parent as `brooklyn-downstream-parent`. - - -## Adding to the catalog - -Similar to the `sample.bom` entity that ships with the archetype, we will define a `.bom` file -to add our `GistGenerator` to the catalog. Substitute the URL below for your own newly built -artifact (which will be in the `target` sub-directory after running `mvn clean install`). - -{% highlight yaml %} -{% readj gist_generator/gist_generator.bom %} -{% endhighlight %} - -See [Handling Bundle Dependencies]({{ site.path.guide}}/java/bundle-dependencies.html) -for a description of the `brooklyn.libraries` used above, and for other alternative approaches. - -The command below will use the `br` CLI to add this to the catalog of a running Brooklyn instance. -Substitute the credentials, URL and port for those of your server. - -{% highlight bash %} -$ br login https://127.0.0.1:8443 admin pa55w0rd -$ br catalog add gist_generator.bom -{% endhighlight %} - - -## Using the blueprint - -The YAML blueprint below shows an example usage of this blueprint: - - name: my sample - services: - - type: example.GistGenerator - brooklyn.config: - oauth.key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - -Note the type name matches the id defined in the `.bom` file. - -You can now call the effector by any of the standard means - [web console]({{ site.path.guide }}/ops/gui/), -[REST api]({{ site.path.guide }}/ops/rest.html), or [Client CLI]({{ site.path.guide }}/ops/cli/). http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/f38b9e7b/guide/java/enrichers.md ---------------------------------------------------------------------- diff --git a/guide/java/enrichers.md b/guide/java/enrichers.md deleted file mode 100644 index 436a423..0000000 --- a/guide/java/enrichers.md +++ /dev/null @@ -1,180 +0,0 @@ ---- -title: Enrichers -layout: website-normal -toc: ../guide_toc.json -categories: [use, guide, defining-applications] ---- - -Enrichers provide advanced manipulation of an entity's sensor values. -See below for documentation of the stock enrichers available in Apache Brooklyn. - -#### Transformer - -[`org.apache.brooklyn.enricher.stock.Transformer`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/enricher/stock/Transformer.html) - -Takes a source sensor and modifies it in some way before publishing the result in a new sensor. See below an example using `$brooklyn:formatString`. - -{% highlight yaml %} -brooklyn.enrichers: -- type: org.apache.brooklyn.enricher.stock.Transformer - brooklyn.config: - enricher.sourceSensor: $brooklyn:sensor("urls.tcp.string") - enricher.targetSensor: $brooklyn:sensor("urls.tcp.withBrackets") - enricher.targetValue: $brooklyn:formatString("[%s]", $brooklyn:attributeWhenReady("urls.tcp.string")) -{% endhighlight %} - -#### Propagator - -[`org.apache.brooklyn.enricher.stock.Propagator`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/enricher/stock/Propagator.html) - -Use propagator to duplicate one sensor as another, giving the supplied sensor mapping. -The other use of Propagator is where you specify a producer (using `$brooklyn:entity(...)` as below) -from which to take sensors; in that mode you can specify `propagate` as a list of sensors whose names are unchanged, instead of (or in addition to) this map. - -{% highlight yaml %} -brooklyn.enrichers: -- type: org.apache.brooklyn.enricher.stock.Propagator - brooklyn.config: - producer: $brooklyn:entity("cluster") -- type: org.apache.brooklyn.enricher.stock.Propagator - brooklyn.config: - sensorMapping: - $brooklyn:sensor("url"): $brooklyn:sensor("org.apache.brooklyn.core.entity.Attributes", "main.uri") -{% endhighlight %} - -#### Custom Aggregating - -[`org.apache.brooklyn.enricher.stock.Aggregator`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/enricher/stock/Aggregator.html) - -Aggregates multiple sensor values (usually across a tier, esp. a cluster) and performs a supplied aggregation method to them to return an aggregate figure, e.g. sum, mean, median, etc. - -{% highlight yaml %} -brooklyn.enrichers: -- type: org.apache.brooklyn.enricher.stock.Aggregator - brooklyn.config: - enricher.sourceSensor: $brooklyn:sensor("webapp.reqs.perSec.windowed") - enricher.targetSensor: $brooklyn:sensor("webapp.reqs.perSec.perNode") - enricher.aggregating.fromMembers: true - transformation: average -{% endhighlight %} - -There are a number of additional configuration keys available for the Aggregators: - -| Configuration Key | Default | Description | -|-----------------------------------|---------|---------------------------------------------------------------------| -| enricher.transformation.untyped | list | Specifies a transformation, as a function from a collection to the value, or as a string matching a pre-defined named transformation, such as 'average' (for numbers), 'sum' (for numbers), 'isQuorate' (to compute a quorum), or 'list' (the default, putting any collection of items into a list) | -| quorum.check.type | | The requirement to be considered quorate -- possible values: 'all', 'allAndAtLeastOne', 'atLeastOne', 'atLeastOneUnlessEmpty', 'alwaysHealthy'", "allAndAtLeastOne" | -| quorum.total.size | 1 | The total size to consider when determining if quorate | - -#### Joiner - -[`org.apache.brooklyn.enricher.stock.Joiner`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/enricher/stock/Joiner.html) - -Joins a sensor whose output is a list into a single item joined by a separator. - -{% highlight yaml %} -brooklyn.enrichers: -- type: org.apache.brooklyn.enricher.stock.Joiner - brooklyn.config: - enricher.sourceSensor: $brooklyn:sensor("urls.tcp.list") - enricher.targetSensor: $brooklyn:sensor("urls.tcp.string") - uniqueTag: urls.quoted.string -{% endhighlight %} - -There are a number of additional configuration keys available for the joiner: - -| Configuration Key | Default | Description | -|-----------------------------------|---------|---------------------------------------------------------------------| -| enricher.joiner.separator | , | Separator string to insert between each argument | -| enricher.joiner.keyValueSeparator | = | Separator string to insert between each key-value pair | -| enricher.joiner.joinMapEntries | false | Whether to add map entries as key-value pairs or just use the value | -| enricher.joiner.quote | true | Whether to bash-escape each parameter and wrap in double-quotes | -| enricher.joiner.minimum | 0 | Minimum number of elements to join; if fewer than this, sets null | -| enricher.joiner.maximum | null | Maximum number of elements to join (null means all elements taken) | - -#### Delta Enricher - -[`org.apache.brooklyn.policy.enricher.DeltaEnricher`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/policy/enricher/DeltaEnricher.html) - -Converts an absolute sensor into a delta sensor (i.e. the difference between the current and previous value) - -#### Time-weighted Delta - -[`org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.html) - -Converts absolute sensor values into a difference over time. The `enricher.delta.period` indicates the measurement interval. - -{% highlight yaml %} -brooklyn.enrichers: -- type: org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher - brooklyn.config: - enricher.sourceSensor: reqs.count - enricher.targetSensor: reqs.per_sec - enricher.delta.period: 1s -{% endhighlight %} - -#### Rolling Mean - -[`org.apache.brooklyn.policy.enricher.RollingMeanEnricher`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.html) - -Transforms a sensor into a rolling average based on a fixed window size. This is useful for smoothing sample type metrics, such as latency or CPU time - -#### Rolling Time-window Mean - -[`org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.html) - -Transforms a sensor's data into a rolling average based on a time window. This time window can be specified with the config key `confidenceRequired` - Minimum confidence level (ie period covered) required to publish a rolling average (default `8d`). - -#### Http Latency Detector - -[`org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher.HttpLatencyDetector`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.html) - -An Enricher which computes latency in accessing a URL, normally by periodically polling that URL. This is then published in the sensors `web.request.latency.last` and `web.request.latency.windowed`. - -There are a number of additional configuration keys available for the Http Latency Detector: - -| Configuration Key | Default | Description | -|-----------------------------------|---------|----------------------------------------------------------------------| -| latencyDetector.url | | The URL to compute the latency of | -| latencyDetector.urlSensor | | A sensor containing the URL to compute the latency of | -| latencyDetector.urlPostProcessing | | Function applied to the urlSensor value, to determine the URL to use | -| latencyDetector.rollup | | The window size (in duration) over which to compute | -| latencyDetector.requireServiceUp | false | Require the service is up | -| latencyDetector.period | 1s | The period of polling | - -#### Combiner - -[`org.apache.brooklyn.enricher.stock.Combiner`](https://brooklyn.apache.org/v/latest/misc/javadoc/org/apache/brooklyn/enricher/stock/Combiner.html) - -Can be used to combine the values of sensors. This enricher should be instantiated using `Enrichers.builder().combining(..)`. -This enricher is only available in Java blueprints and cannot be used in YAML. - -#### Note On Enricher Producers - -If an entity needs an enricher whose source sensor (`enricher.sourceSensor`) belongs to another entity, then the enricher -configuration must include an `enricher.producer` key referring to the other entity. - -For example, if we consider the Transfomer from above, suppose that `enricher.sourceSensor: $brooklyn:sensor("urls.tcp.list")` -is actually a sensor on a different entity called `load.balancer`. In this case, we would need to supply an -`enricher.producer` value. - -{% highlight yaml %} -brooklyn.enrichers: -- type: org.apache.brooklyn.enricher.stock.Transformer - brooklyn.config: - enricher.producer: $brooklyn:entity("load.balancer") - enricher.sourceSensor: $brooklyn:sensor("urls.tcp.string") - enricher.targetSensor: $brooklyn:sensor("urls.tcp.withBrackets") - enricher.targetValue: | - $brooklyn:formatString("[%s]", $brooklyn:attributeWhenReady("urls.tcp.string")) -{% endhighlight %} - -It is important to note that the value supplied to `enricher.producer` must be immediately resolvable. While it would be valid -DSL syntax to write: - -{% highlight yaml %} -enricher.producer: brooklyn:entity($brooklyn:attributeWhenReady("load.balancer.entity")) -{% endhighlight %} - -(assuming the `load.balancer.entity` sensor returns a Brooklyn entity), this will not function properly because `enricher.producer` -will unsuccessfully attempt to get the supplied entity immediately.
