├── .github ├── stale.yml └── workflows │ └── greetings.yml ├── .gitignore ├── Berksfile ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── TESTING.md ├── attributes └── default.rb ├── chefignore ├── kitchen.yml ├── libraries ├── helpers.rb └── service.rb ├── metadata.rb ├── recipes └── default.rb ├── resources └── default.rb ├── supermarket.pem.enc ├── templates └── default │ ├── env.erb │ └── path.erb └── test ├── cookbooks ├── linux-basic │ ├── attributes │ │ └── default.rb │ ├── metadata.rb │ └── recipes │ │ └── default.rb ├── osx-basic │ ├── attributes │ │ └── default.rb │ ├── metadata.rb │ └── recipes │ │ └── default.rb └── windows-basic │ ├── attributes │ └── default.rb │ ├── metadata.rb │ ├── recipes │ └── default.rb │ └── solo.json ├── integration └── xplat-basic │ └── serverspec │ └── xplat_spec.rb └── solo.rb /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 60 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 8 | daysUntilClose: 7 9 | 10 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 11 | onlyLabels: [] 12 | 13 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 14 | exemptLabels: 15 | - pinned 16 | - security 17 | - "[Status] Maybe Later" 18 | 19 | # Set to true to ignore issues in a project (defaults to false) 20 | exemptProjects: false 21 | 22 | # Set to true to ignore issues in a milestone (defaults to false) 23 | exemptMilestones: false 24 | 25 | # Set to true to ignore issues with an assignee (defaults to false) 26 | exemptAssignees: false 27 | 28 | # Label to use when marking as stale 29 | staleLabel: wontfix 30 | 31 | # Comment to post when marking as stale. Set to `false` to disable 32 | markComment: > 33 | This issue has been automatically marked as stale because it has not had 34 | recent activity. It will be closed if no further activity occurs. Thank you 35 | for your contributions. 36 | 37 | # Comment to post when removing the stale label. 38 | # unmarkComment: > 39 | # Your comment here. 40 | 41 | # Comment to post when closing a stale Issue or Pull Request. 42 | # closeComment: > 43 | # Your comment here. 44 | 45 | # Limit the number of actions per hour, from 1-30. Default is 30 46 | limitPerRun: 30 47 | 48 | # Limit to only `issues` or `pulls` 49 | # only: issues 50 | 51 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': 52 | # pulls: 53 | # daysUntilStale: 30 54 | # markComment: > 55 | # This pull request has been automatically marked as stale because it has not had 56 | # recent activity. It will be closed if no further activity occurs. Thank you 57 | # for your contributions. 58 | 59 | # issues: 60 | # exemptLabels: 61 | # - confirmed -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: [pull_request, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/first-interaction@v1 10 | with: 11 | repo-token: ${{ secrets.GITHUB_TOKEN }} 12 | issue-message: 'Welcome contributor! Congratulations on submitting your first issue on this project!'' first issue' 13 | pr-message: 'Welcome contributor! Congratulations on submitting your first PR for this project!'' first pr' 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | .vagrant.d 3 | Gemfile.lock 4 | Berksfile.lock 5 | .bundle 6 | .cache 7 | .kitchen 8 | bin 9 | .kitchen.local.yml 10 | .coverage 11 | .kitchen/ 12 | .idea/ 13 | solo-cookbooks/ 14 | chef_guid 15 | nodes/ 16 | cache/ -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | source 'https://supermarket.chef.io' 2 | 3 | metadata 4 | 5 | group :integration do 6 | cookbook 'linux-basic', path: './test/cookbooks/linux-basic' 7 | cookbook 'windows-basic', path: './test/cookbooks/windows-basic' 8 | cookbook 'osx-basic', path: './test/cookbooks/osx-basic' 9 | end 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Azure Pipelines Agent Cookbook Changelog 2 | 3 | ## [v3.2.0](https://github.com/Microsoft/azure-pipelines-agent-cookbook/tree/v3.2.0) - (2020-06-26) 4 | 5 | ### Removed 6 | 7 | - Removed `Rakefile` 8 | - Removed `.foodcritic` 9 | - Removed `.rspec` 10 | - Removed `.rubocop.yml` 11 | 12 | ### Changed 13 | 14 | - Cookbook supports Chef Infra Client 14 or newer. 15 | - Cookstyle fixes for Chef 16 16 | - Updated line endings to `LF` for files that were marked as `CRLF` 17 | - Utilize `kitchen-azurerm` driver for Linux and Windows VM's 18 | 19 | ### Added 20 | 21 | - Proxy support - Thanks @perryflynn! Closed #39. 22 | 23 | ## [v3.0.1](https://github.com/Microsoft/azure-pipelines-agent-cookbook/tree/v3.0.1) - (2018-09-29) 24 | 25 | ### Removed 26 | 27 | - Remove require of `chef/mixin/language` 28 | 29 | This mixin was removed from Chef 14. See [this stackoverflow](https://stackoverflow.com/questions/49909084/cannot-load-such-file-chef-mixin-language) 30 | 31 | Fixes following compile error in Chef 14.3.37: 32 | 33 | ```ruby 34 | ================================================================================ 35 | Recipe Compile Error in /tmp/kitchen/cache/cookbooks/vsts_agent/libraries/service.rb 36 | ================================================================================ 37 | LoadError 38 | --------- 39 | cannot load such file -- chef/mixin/language 40 | 41 | Cookbook Trace: 42 | --------------- 43 | /tmp/kitchen/cache/cookbooks/vsts_agent/libraries/service.rb:4:in '' 44 | 45 | Relevant File Content: 46 | ---------------------- 47 | /tmp/kitchen/cache/cookbooks/vsts_agent/libraries/service.rb: 48 | 49 | 1: require 'chef/resource/lwrp_base' 50 | 2: require 'chef/provider/lwrp_base' 51 | 3: require 'chef/mixin/shell_out' 52 | 4>> require 'chef/mixin/language' 53 | 5: 54 | 6: module VSTS 55 | 7: module Agent 56 | 8: # The service operations for vsts_agent 57 | 9: class Service 58 | 10: include Windows::Helper 59 | 11: include VSTS::Agent::Helpers 60 | 12: include Chef::DSL::PlatformIntrospection 61 | 13: 62 | 63 | System Info: 64 | ------------ 65 | chef_version=14.3.37 66 | platform=debian 67 | platform_version=8.11 68 | ruby=ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux] 69 | program_name=/opt/chef/bin/chef-client 70 | executable=/opt/chef/bin/chef-client 71 | 72 | Running handlers: 73 | [2018-08-17T17:57:39-07:00] ERROR: Running exception handlers 74 | [2018-08-17T17:57:39-07:00] ERROR: Running exception handlers 75 | Running handlers complete 76 | [2018-08-17T17:57:39-07:00] ERROR: Exception handlers complete 77 | [2018-08-17T17:57:39-07:00] ERROR: Exception handlers complete 78 | Chef Client failed. 0 resources updated in 01 seconds 79 | [2018-08-17T17:57:39-07:00] FATAL: Stacktrace dumped to /tmp/kitchen/cache/chef-stacktrace.out 80 | [2018-08-17T17:57:39-07:00] FATAL: Stacktrace dumped to /tmp/kitchen/cache/chef-stacktrace.out 81 | [2018-08-17T17:57:39-07:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report 82 | [2018-08-17T17:57:39-07:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report 83 | [2018-08-17T17:57:39-07:00] FATAL: LoadError: cannot load such file -- chef/mixin/language 84 | [2018-08-17T17:57:39-07:00] FATAL: LoadError: cannot load such file -- chef/mixin/language 85 | ``` 86 | 87 | Closed #32 88 | 89 | ### Changed 90 | 91 | - `build-essential::default` is broken in `8.1.1`. Implemented resource in place of recipe. 92 | 93 | ### Added 94 | 95 | - Add missing installation of **7zip**. 96 | - Copy `win_friendly_path` method to helpers library. 97 | - Add Windows Server 2016 to kitchen.yml 98 | 99 | ## [v3.0.0](https://github.com/Microsoft/azure-pipelines-agent-cookbook/tree/v3.0.0) - (2018-08-05) 100 | 101 | ### Added 102 | 103 | - Add deployment groups support. Closed #27 104 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | One of the easiest ways to contribute is to participate in discussions and discuss issues. You can also contribute by submitting pull requests with code changes. 3 | 4 | ## General feedback and discussions? 5 | Please start a discussion on the [issue tracker](https://github.com/Microsoft/vsts-agent-cookbook/issues). 6 | 7 | ## Contributing code and content 8 | Get familiar with GitHub pull requests https://help.github.com/articles/using-pull-requests/ 9 | 10 | You will need to sign a [Contributor License Agreement](https://cla2.dotnetfoundation.org/) before submitting your pull request. 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Visual Studio Team Services Build and Release Agent Cookbook 2 | ================ 3 | 4 | [![Join the chat at https://gitter.im/Microsoft/vsts-agent-cookbook](https://badges.gitter.im/Microsoft/vsts-agent-cookbook.svg)](https://gitter.im/Microsoft/vsts-agent-cookbook?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | [![Build Status](https://travis-ci.org/Microsoft/vsts-agent-cookbook.svg?branch=master)](https://travis-ci.org/Microsoft/vsts-agent-cookbook) 6 | [![Cookbook Version](https://img.shields.io/cookbook/v/vsts_agent.svg)](https://supermarket.chef.io/cookbooks/vsts_agent) 7 | 8 | Installs and configures Visual Studio Team Services [Build and Release Agent](https://github.com/Microsoft/vsts-agent/) 9 | 10 | Please check [Wiki](https://github.com/Microsoft/vsts-agent-cookbook/wiki) for more examples 11 | 12 | Requirements 13 | ------------ 14 | - Chef 12.5.0 or higher 15 | 16 | ### Platforms 17 | The following platforms are tested and supported: 18 | - Debian 8 x64 (Jessie) 19 | - Debian 9 x64 (Stretch) 20 | - Ubuntu 16.04 (Xenial Xerus) 21 | - Ubuntu 18.04 (Bionic) 22 | - Ubuntu 17.10 (Artful Aardvark) 23 | - CentOS 7 24 | - Windows 10 25 | - Windows Server 2012 R2 26 | - OS X 10.10.5 27 | - OS X 10.11.4 28 | 29 | Attributes 30 | ---------- 31 | * `node['vsts_agent']['binary']['version']` - set version of package to install 32 | * `node['vsts_agent']['prerequisites']['redhat']['install']` - control dependencies installation for redhat based distros(redhat, centos etc.) . Default true 33 | * `node['vsts_agent']['prerequisites']['debian']['install']` - control dependencies installation for debian based distros(debian, ubuntu etc.). Default true 34 | 35 | Resource/Provider 36 | ----------------- 37 | ### vsts_agent 38 | This resource installs and configures the vsts build and release agent 39 | #### Actions 40 | - `:install`: Install and configure the agent 41 | - `:remove`: Remove the agent and unregister it from VSTS 42 | - `:restart`: Restart the agent service 43 | 44 | #### Parameters 45 | - `agent_name`: name attribute. The name of the vsts agent 46 | - `deploymentGroup`: deploy the agent into the [deployment group](https://docs.microsoft.com/en-us/vsts/pipelines/release/deployment-groups/?view=vsts). Default '`false`' 47 | * `deploymentGroupName`: name of the deployment group. Only applies if `deploymentGroup==true` 48 | * `projectName`: name of the vsts/tfs project where to deploy the agent. Only applies if `deploymentGroup==true` 49 | * `collectionName`: name of the vsts/tfs collection where to deploy the agent. Only applies if `deploymentGroup==true`. Dafault value is `DefaultCollection` 50 | * `deploymentGroupTags`: a comma-separated list of tags to set for the agent. Only applies if `deploymentGroup==true` 51 | - `version`: an agent version to install. Default version from an attribute 52 | - `install_dir`: A target directory to install the vsts agent 53 | - `path`: Overwrite system PATH environment variable values. Linux and macOS only 54 | - `env`: Additional environment variables. Linux and macOS only 55 | - `user`: Set a local user to run the vsts agent 56 | - `group`: Set a local group to run the vsts agent 57 | - `runasservice`: run agent as a service. Default '`true`' 58 | - `windowslogonaccount`: Set a user name to run a windows service. Possible values are "NT AUTHORITY\NetworkService", "NT AUTHORITY\LocalService" or any system valid username 59 | - `windowslogonpassword`: Set password for windowslogonaccount unless it is equal to NetworkService or LocalService 60 | - `vsts_url`: url to VSTS instance 61 | - `vsts_pool`: A pool to connect an agent 62 | - `vsts_auth`: Authentication type. Default PAT auth. Valid options are: 63 | * PAT - Personal Access Token (requires vsts_token), 64 | * Negotiate - Kerberos or NTLM (requires vsts_username and vsts_password), 65 | * ALT - Alternate Credentials (requires vsts_username and vsts_password), 66 | * Integrated - Windows default credentials (doesn't require any credentials). 67 | - `vsts_token`: A personal access token for VSTS. Used with PAT auth type. [See](http://roadtoalm.com/2015/07/22/using-personal-access-tokens-to-access-visual-studio-online/) 68 | - `vsts_username`: A user to connect to VSTS. Used with Negotiate and ALT auth 69 | - `vsts_password`: A user to connect to VSTS. Used with Negotiate and ALT auth 70 | - `work_folder`: Set different workspace location. Default is "install_dir/\_work" 71 | - `proxy_url`: Set the forward proxy (example value: `http://192.168.1.1:8080`) 72 | - `proxy_sslcacert`: Set the root certificate which is used for communicating through the forward proxy (example value: `/usr/local/share/ca-certificates/Internal-CA.crt`) 73 | 74 | #### Examples 75 | Install, configure, restart and remove a build agent. 76 | Check [windows](test/cookbooks/windows-basic/recipes/default.rb), [linux](test/cookbooks/linux-basic/recipes/default.rb) or [osx](test/cookbooks/osx-basic/recipes/default.rb) tests for more examples. 77 | 78 | ```ruby 79 | include_recipe 'vsts_agent::default' 80 | 81 | if platform_family?('windows') 82 | dir = 'c:\\agents' 83 | else 84 | dir = '/tmp/agents' 85 | end 86 | 87 | vsts_agent 'agent_01' do 88 | install_dir dir 89 | user 'vagrant' 90 | group 'vagrant' 91 | path '/usr/local/bin/:/usr/bin:/opt/bin/' # only works on nix systems 92 | env('M2_HOME' => '/opt/maven', 'JAVA_HOME' => '/opt/java') # only works on nix systems 93 | vsts_url 'https://contoso.visualstudio.com' 94 | vsts_pool 'default' 95 | vsts_token 'my_secret_token_from_vsts' 96 | windowslogonaccount 'builder' # will be used only on windows 97 | windowslogonpassword 'Pas$w0r_d' # will be used only on windows 98 | action :install 99 | end 100 | 101 | vsts_agent 'agent_01' do 102 | action :restart 103 | end 104 | 105 | vsts_agent 'agent_01' do 106 | vsts_token 'my_secret_token_from_vsts' 107 | action :remove 108 | end 109 | ``` 110 | 111 | Install, configure, restart and remove a deployment agent. 112 | 113 | ```ruby 114 | vsts_agent 'deployment_agent_01' do 115 | install_dir dir 116 | deploymentGroup true 117 | deploymentGroupName 'project1-deployment-group' 118 | projectName 'project1' 119 | collectionName 'DefaultCollection' 120 | deploymentGroupTags "web, db" 121 | user 'vagrant' 122 | group 'vagrant' 123 | path '/usr/local/bin/:/usr/bin:/opt/bin/' # only works on nix systems 124 | env('M2_HOME' => '/opt/maven', 'JAVA_HOME' => '/opt/java') # only works on nix systems 125 | vsts_url 'https://contoso.visualstudio.com' 126 | vsts_token 'my_secret_token_from_vsts' 127 | windowslogonaccount 'builder' # will be used only on windows 128 | windowslogonpassword 'Pas$w0r_d' # will be used only on windows 129 | action :install 130 | end 131 | 132 | ``` 133 | 134 | # How to contribute 135 | Check [Contribution Guide](CONTRIBUTING.md) and [Testing Guide](TESTING.md) 136 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code 6 | repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), 7 | [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), 8 | [Xamarin](https://github.com/xamarin), and [many more](https://opensource.microsoft.com/). 9 | 10 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's 11 | [definition](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security 12 | vulnerability, please report it to us as described below. 13 | 14 | ## Reporting Security Issues 15 | 16 | **Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to the 17 | Microsoft Security Response Center at [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your 18 | message with our PGP key; please download it from the 19 | [Microsoft Security Response Center PGP Key page](https://technet.microsoft.com/en-us/security/dn606155). 20 | 21 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we 22 | received your original message. Additional information can be found at 23 | [microsoft.com/msrc](https://www.microsoft.com/msrc). 24 | 25 | Please include the requested information listed below (as much as you can provide) to help us better understand the 26 | nature and scope of the possible issue: 27 | 28 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 29 | * Full paths of source file(s) related to the manifestation of the issue 30 | * The location of the affected source code (tag/branch/commit or direct URL) 31 | * Any special configuration required to reproduce the issue 32 | * Step-by-step instructions to reproduce the issue 33 | * Proof-of-concept or exploit code (if possible) 34 | * Impact of the issue, including how an attacker might exploit the issue 35 | 36 | This information will help us triage your report more quickly. 37 | 38 | ## Preferred Languages 39 | 40 | We prefer all communications to be in English. 41 | 42 | ## Policy 43 | 44 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 45 | 46 | 47 | -------------------------------------------------------------------------------- /TESTING.md: -------------------------------------------------------------------------------- 1 | # Testing Documentation 2 | 3 | ## Prerequisites 4 | VSTS Build Agent cookbook requires ChefDK installation - download it [here](https://downloads.chef.io/chef-dk/). 5 | 6 | Integration testing uses Hashicorp's [Vagrant](https://www.vagrantup.com/downloads.html) and Oracle's [Virtualbox](https://www.virtualbox.org/wiki/Downloads), which must be installed first. 7 | 8 | You'll also need the following from VSTS: 9 | - Username 10 | - [Account URL](https://www.visualstudio.com/en-us/get-started/setup/sign-up-for-visual-studio-online) 11 | - [Personal access token](http://roadtoalm.com/2015/07/22/using-personal-access-tokens-to-access-visual-studio-online/) 12 | - [Build pool name](http://blog.devmatter.com/understanding-pools-and-queues-in-vso/) 13 | 14 | ### Integration testing using boxes and Virtualbox 15 | Integration tests are orchestrated by [test-kitchen](https://github.com/test-kitchen/test-kitchen). 16 | Although Linux boxes are freely available from Vagrant's repository, for Mac and Windows, you'll need to build your own using Hashicorp's [Packer](https://www.packer.io/). 17 | 18 | #### Guides for building Mac and Windows boxes 19 | - [Mac VM templates for Packer and VeeWee](https://github.com/timsutton/osx-vm-templates) 20 | - [Windows Packer templates](https://github.com/joefitzgerald/packer-windows) 21 | - [Boxcutter](https://github.com/boxcutter) (All platforms) 22 | 23 | 24 | ### Running the tests 25 | #### Set environment variables 26 | 27 | Windows: 28 | ``` 29 | set VSTS_URL='https://account.visualstudio.com' 30 | set VSTS_POOL=default 31 | set VSTS_USER=username 32 | set VSTS_TOKEN=my_secret_token_from_vsts 33 | set VSTS_DEPLOYMENT_GROUP_NAME=test-chef-deployment 34 | set VSTS_DEPLOYMENT_GROUP_PROJECT=test 35 | ``` 36 | Linux / Mac: 37 | ``` 38 | export VSTS_URL='https://account.visualstudio.com' 39 | export VSTS_POOL=default 40 | export VSTS_USER=username 41 | export VSTS_TOKEN=my_secret_token_from_vsts 42 | export VSTS_DEPLOYMENT_GROUP_NAME=test-chef-deployment 43 | export VSTS_DEPLOYMENT_GROUP_PROJECT=test 44 | ``` 45 | 46 | If the username of the box you're testing differs from standard "vagrant": 47 | ``` 48 | export BOX_USERNAME=username 49 | ``` 50 | 51 | #### Executing the tests 52 | The `kitchen test` instance states are in order: destroy, create, converge, setup, verify, destroy. `kitchen test` changes the state of one or more instances to destroyed, then executes the actions for each state up to destroy. At any sign of failure, executing the actions stops and the instance is left in the last successful execution state. 53 | ``` 54 | kitchen test VAGRANT_BOX_NAME 55 | ``` 56 | 57 | #### Examples: 58 | `$ kitchen test osx1010` 59 | `$ kitchen test windows_2012_r2` 60 | `$ kitchen test ubuntu1604` 61 | 62 | 63 | :small_red_triangle: The Windows and Mac boxes must be [built](#guides-for-building-mac-and-windows-boxes) prior to testing. Once built, you'll need to modify the `.kitchen.yml` file. To find out list of available boxes and their names, simply execute `vagrant box list`. See the [Chef documentation](https://docs.chef.io/config_yml_kitchen.html) or comments in `.kitchen.yml` for how to modify it for your boxes. 64 | 65 | #### Style Testing 66 | Several style checks can be performed by running any of the following: 67 | 68 | `$ chef exec rake style` 69 | `$ rake style` 70 | `$ foodcritic .` 71 | `$ rubocop .` 72 | -------------------------------------------------------------------------------- /attributes/default.rb: -------------------------------------------------------------------------------- 1 | default['vsts_agent']['binary']['version'] = '2.136.1' 2 | 3 | case node['platform_family'] 4 | when 'windows' 5 | default['vsts_agent']['binary']['url'] = 'https://vstsagentpackage.azureedge.net/agent/%s/vsts-agent-win-x64-%s.zip' 6 | when 'debian', 'rhel' 7 | default['vsts_agent']['binary']['url'] = 'https://vstsagentpackage.azureedge.net/agent/%s/vsts-agent-linux-x64-%s.tar.gz' 8 | when 'mac_os_x' 9 | default['vsts_agent']['binary']['url'] = 'https://vstsagentpackage.azureedge.net/agent/%s/vsts-agent-osx-x64-%s.tar.gz' 10 | end 11 | 12 | # applies for debian based distros: ubuntu, debian etc... 13 | default['vsts_agent']['prerequisites']['debian']['install'] = true 14 | 15 | # applies for redhat based distros: redhat, centos etc... 16 | default['vsts_agent']['prerequisites']['redhat']['install'] = true 17 | -------------------------------------------------------------------------------- /chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # or sharing to the community site. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | Icon? 9 | nohup.out 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | 14 | # Testing # 15 | ########### 16 | .rspec 17 | .rubocop.yml 18 | spec/* 19 | spec/fixtures/* 20 | test/* 21 | features/* 22 | examples/* 23 | Guardfile 24 | Procfile 25 | test/* 26 | spec/* 27 | .kitchen.yml 28 | 29 | # SCM # 30 | ####### 31 | .git 32 | */.git 33 | .gitignore 34 | 35 | 36 | # Berkshelf # 37 | ############# 38 | Berksfile 39 | Berksfile.lock 40 | 41 | # Cookbooks # 42 | ############# 43 | CONTRIBUTING* 44 | CHANGELOG* 45 | 46 | # Travis # 47 | ########## 48 | .travis.yml 49 | -------------------------------------------------------------------------------- /kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: azurerm 4 | location: "westus2" 5 | machine_size: "Standard_A4_v2" 6 | explicit_resource_group_name: azure-pipelines-agent-cicd-rg 7 | destroy_explicit_resource_group: true 8 | destroy_resource_group_contents: true 9 | 10 | provisioner: 11 | name: chef_zero 12 | product_name: chef 13 | product_version: 16 14 | chef_license: accept 15 | channel: stable 16 | 17 | transport: 18 | ssh_key: ~/.ssh/id_kitchen-azurerm 19 | 20 | verifier: 21 | name: inspec 22 | sudo: true 23 | reporter: 24 | - cli 25 | - junit:/tmp/%{suite}-%{platform}-inspec.xml 26 | inspec_tests: 27 | - test/integration/default 28 | 29 | platforms: 30 | - name: debian-10 31 | driver: 32 | image_urn: Debian:debian-10:10:latest 33 | vm_name: buster-pipelines-agent-vm 34 | 35 | - name: ubuntu-18.04 36 | driver: 37 | image_urn: Canonical:UbuntuServer:18.04-LTS:latest 38 | vm_name: bionic-pipelines-agent-vm 39 | 40 | - name: ubuntu-20.04 41 | driver: 42 | image_urn: Canonical:UbuntuServer:20.04-LTS:latest 43 | vm_name: focal-pipelines-agent-vm 44 | 45 | - name: centos-7 46 | driver_config: 47 | image_urn: OpenLogic:CentOS:7.5:latest 48 | 49 | suites: 50 | - name: linux-basic 51 | run_list: 52 | - recipe[linux-basic::default] 53 | includes: 54 | - debian-10 55 | - ubuntu-18.04 56 | - ubuntu-20.04 57 | - centos-7 58 | 59 | attributes: 60 | vsts_agent_test: 61 | username: <%= ENV['BOX_USERNAME'] %> 62 | vsts_url: <%= ENV['VSTS_URL'] %> 63 | vsts_pool: <%= ENV['VSTS_POOL'] %> 64 | vsts_token: <%= ENV['VSTS_TOKEN'] %> 65 | deployment_group_name: <%= ENV['VSTS_DEPLOYMENT_GROUP_NAME'] %> 66 | deployment_group_project: <%= ENV['VSTS_DEPLOYMENT_GROUP_PROJECT'] %> 67 | -------------------------------------------------------------------------------- /libraries/helpers.rb: -------------------------------------------------------------------------------- 1 | module VSTS 2 | module Agent 3 | # Helper methods for VSTS Build Agent installation 4 | module Helpers 5 | include Chef::DSL::PlatformIntrospection 6 | 7 | require 'json' 8 | require 'fileutils' 9 | 10 | def get_archive_name(version) 11 | name = 'vsts_agent' 12 | name += '_' + version if version 13 | name 14 | end 15 | 16 | def download_url(version) 17 | url = Chef.run_context.node['vsts_agent']['binary']['url'] 18 | url.gsub '%s', version 19 | end 20 | 21 | def windows? 22 | platform_family?('windows') 23 | end 24 | 25 | def debian? 26 | platform_family?('debian') 27 | end 28 | 29 | def rhel? 30 | platform_family?('rhel') 31 | end 32 | 33 | def osx? 34 | platform_family?('mac_os_x') 35 | end 36 | 37 | def service_exist?(install_dir) 38 | ::File.exist?("#{install_dir}/.service") 39 | end 40 | 41 | def agent_exists?(install_dir) 42 | ::File.exist?("#{install_dir}/.agent") 43 | end 44 | 45 | def save_state(agent_name, hash = {}) 46 | ::File.write(state_file(agent_name), hash.to_json) 47 | end 48 | 49 | def load_state(agent_name) 50 | state_file = state_file(agent_name) 51 | return unless ::File.exist?(state_file) 52 | state = ::File.read(state_file(agent_name)) 53 | JSON.parse(state) 54 | end 55 | 56 | def state_file(agent_name) 57 | save_dir = "#{Chef::Config[:file_cache_path]}/vsts_agent" 58 | ::FileUtils.mkdir_p save_dir unless ::File.directory?(save_dir) 59 | "#{save_dir}/#{agent_name}-state.json" 60 | end 61 | 62 | def remove_current_state(agent_name) 63 | state_file = state_file(agent_name) 64 | ::File.delete(state_file) if ::File.exist?(state_file) 65 | end 66 | 67 | def set_auth(args, resource) 68 | args['auth'] = resource.vsts_auth.downcase 69 | if args['auth'] == 'pat' 70 | args['token'] = resource.vsts_token 71 | elsif (args['auth'] == 'negotiate') || (args['auth'] == 'alt') 72 | args['username'] = resource.vsts_username 73 | args['password'] = resource.vsts_password 74 | end 75 | end 76 | 77 | def vsagentexec(args = {}) 78 | command = 'Agent.Listener ' 79 | command = './' + command unless windows? 80 | args.each { |key, value| command += append_arguments(key.to_s, value) + ' ' } 81 | command 82 | end 83 | 84 | def append_arguments(key, value) 85 | result = '' 86 | if key.include?('configure') || key.include?('remove') 87 | result += key 88 | else 89 | result += "--#{key}" 90 | result += " \"#{value}\"" unless value.nil? 91 | end 92 | result 93 | end 94 | end 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /libraries/service.rb: -------------------------------------------------------------------------------- 1 | require 'chef/resource/lwrp_base' 2 | require 'chef/provider/lwrp_base' 3 | require 'chef/mixin/shell_out' 4 | require 'chef/dsl/platform_introspection' 5 | 6 | module VSTS 7 | module Agent 8 | # The service operations for vsts_agent 9 | class Service 10 | include Windows::Helper 11 | include VSTS::Agent::Helpers 12 | include Chef::DSL::PlatformIntrospection 13 | 14 | def initialize(agent_name, install_dir, user, group) 15 | @agent_name = agent_name 16 | @install_dir = install_dir 17 | @user = user 18 | @group = group 19 | end 20 | 21 | def enable 22 | vsts_service 'enable' unless service_exist?(@install_dir) 23 | end 24 | 25 | def start 26 | vsts_service 'start' if service_exist?(@install_dir) 27 | end 28 | 29 | def stop 30 | vsts_service 'stop' if service_exist?(@install_dir) 31 | end 32 | 33 | def restart 34 | return unless service_exist?(@install_dir) 35 | vsts_service 'stop' 36 | vsts_service 'start' 37 | end 38 | 39 | def disable 40 | vsts_service 'disable' if service_exist?(@install_dir) 41 | end 42 | 43 | # used by platforms introspection 44 | def node 45 | Chef.run_context.node 46 | end 47 | 48 | def service_name 49 | return unless service_exist?(@install_dir) 50 | @service_name ||= ::File.read("#{@install_dir}/.service").strip 51 | end 52 | 53 | def vsts_service(action) 54 | if windows? 55 | vsts_windows_service(action) 56 | else 57 | vsts_unix_service(action) 58 | end 59 | end 60 | 61 | def vsts_windows_service(action) 62 | return if action == 'enable' # service is installed by agent 63 | win_service = Chef::Resource::WindowsService.new(service_name, Chef.run_context) 64 | win_service.retries(3) 65 | win_service.run_action(action.to_sym) 66 | end 67 | 68 | def vsts_unix_service(action) 69 | if action == 'enable' 70 | action = "install #{@user}" 71 | elsif action == 'disable' 72 | action = 'uninstall' 73 | end 74 | envvars = { HOME: "/Users/#{@user}" } 75 | execute = Chef::Resource::Execute.new("Run action '#{action}' on service for agent '#{@agent_name}'", Chef.run_context) 76 | execute.cwd(@install_dir) 77 | execute.command("./svc.sh #{action}") 78 | if osx? 79 | execute.user(@user) 80 | execute.group(@group) 81 | execute.environment(envvars) 82 | end 83 | execute.run_action(:run) 84 | end 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | name 'vsts_agent' 2 | maintainer 'Microsoft' 3 | maintainer_email 'eahanl@microsoft.com' 4 | license 'MIT' 5 | description 'Installs/Configures visualstudio team services build agents' 6 | source_url 'https://github.com/Microsoft/azure-pipelines-agent-cookbook' 7 | issues_url 'https://github.com/Microsoft/azure-pipelines-agent-cookbook/issues' 8 | chef_version '>= 14' 9 | version '3.2.0' 10 | 11 | %w(ubuntu debian redhat centos mac_os_x windows).each do |operating_system| 12 | supports operating_system 13 | end 14 | 15 | depends 'ark' 16 | depends 'seven_zip', '>= 2.0.0' 17 | -------------------------------------------------------------------------------- /recipes/default.rb: -------------------------------------------------------------------------------- 1 | 2 | if platform_family?('debian') && node['vsts_agent']['prerequisites']['debian']['install'] 3 | 4 | %w(libunwind8 liblttng-ust0 curl libuuid1 libkrb5-3 zlib1g).each do |pkg| 5 | package pkg 6 | end 7 | 8 | package 'libssl1.1' if node['platform_version'] =~ /^10.*/ 9 | package 'libssl1.0.2' if node['platform_version'] =~ /^9.*/ 10 | package 'libicu52' if node['platform_version'] =~ /^14.*/ || node['platform_version'] =~ /^8.*/ 11 | package 'libicu55' if node['platform_version'] =~ /^16.*/ 12 | package 'libicu57' if node['platform_version'] =~ /^17.*/ || node['platform_version'] =~ /^9.*/ 13 | 14 | elsif platform_family?('rhel') && node['vsts_agent']['prerequisites']['redhat']['install'] 15 | 16 | %w(libunwind libcurl openssl-libs libuuid krb5-libs libicu zlib).each do |pkg| 17 | package pkg 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /resources/default.rb: -------------------------------------------------------------------------------- 1 | provides :vsts_agent 2 | 3 | default_action :install 4 | 5 | property :agent_name, String, name_property: true 6 | property :install_dir, String 7 | 8 | property :user, String, desired_state: false 9 | property :group, String, desired_state: false 10 | 11 | property :work_folder, String, default: '_work' 12 | 13 | property :runasservice, [true, false], default: true 14 | property :windowslogonaccount, String, desired_state: false 15 | property :windowslogonpassword, String, desired_state: false 16 | 17 | # environment 18 | property :version, String, desired_state: false 19 | property :path, String, desired_state: false 20 | property :env, Hash, default: {}, desired_state: false 21 | 22 | # Proxy 23 | property :proxy_url, String 24 | property :proxy_sslcacert, String 25 | 26 | # VSTS Access 27 | property :vsts_url, String, regex: %r{^https?://.*$} 28 | property :vsts_pool, String 29 | property :vsts_auth, String, default: 'PAT', desired_state: false 30 | property :vsts_username, String, desired_state: false 31 | property :vsts_password, String, sensitive: true, desired_state: false 32 | property :vsts_token, String, sensitive: true, desired_state: false 33 | 34 | # Deployment Groups 35 | property :deploymentGroup, [true, false], default: false 36 | property :deploymentGroupName, String 37 | property :deploymentGroupTags, String 38 | property :projectName, String 39 | property :collectionName, String, default: 'DefaultCollection' 40 | 41 | include ::VSTS::Agent::Helpers 42 | 43 | load_current_value do 44 | state = load_state(agent_name) 45 | current_value_does_not_exist! unless state 46 | install_dir state['install_dir'] 47 | current_value_does_not_exist! unless install_dir 48 | current_value_does_not_exist! unless agent_exists?(install_dir) 49 | user state['user'] 50 | group state['group'] 51 | vsts_url state['vsts_url'] 52 | vsts_pool state['vsts_pool'] 53 | work_folder state['work_folder'] 54 | deploymentGroup state['deploymentGroup'] 55 | deploymentGroupName state['deploymentGroupName'] 56 | deploymentGroupTags state['deploymentGroupTags'] 57 | projectName state['projectName'] 58 | collectionName state['collectionName'] 59 | proxy_url state['proxy_url'] 60 | proxy_sslcacert state['proxy_sslcacert'] 61 | 62 | runasservice service_exist?(install_dir) 63 | end 64 | 65 | action :install do 66 | version = new_resource.version || node['vsts_agent']['binary']['version'] 67 | 68 | ruby_block "Restart vsts_agent #{new_resource.agent_name} service" do 69 | block do 70 | service = ::VSTS::Agent::Service.new(new_resource.agent_name, new_resource.install_dir, new_resource.user, new_resource.group) 71 | service.restart 72 | end 73 | action :nothing 74 | end 75 | 76 | converge_if_changed do 77 | archive_url = download_url(version) 78 | archive_name = get_archive_name(version) 79 | unpack_dir = ::File.join(Chef::Config[:file_cache_path], 'unpack_agent') 80 | unpack_dir = win_friendly_path(unpack_dir) if windows? 81 | 82 | remove_agent(new_resource) 83 | 84 | directory unpack_dir do 85 | recursive true 86 | action :delete 87 | end 88 | 89 | ark archive_name do 90 | url archive_url 91 | backup false 92 | path unpack_dir 93 | owner new_resource.user 94 | strip_components 0 if windows? 95 | action :put 96 | end 97 | 98 | directory new_resource.install_dir do 99 | recursive true 100 | rights :full_control, new_resource.user, applies_to_children: true if windows? 101 | user new_resource.user 102 | group new_resource.group 103 | mode '0755' unless windows? 104 | action :create 105 | end 106 | 107 | execute "Move #{new_resource.agent_name} agent from intermidiate folder" do 108 | command "cp -r #{unpack_dir}/#{archive_name}/* #{new_resource.install_dir}" unless windows? 109 | command "xcopy #{unpack_dir}\\#{archive_name}\\* #{win_friendly_path(new_resource.install_dir)} /s /e /q" if windows? 110 | action :run 111 | end 112 | 113 | args = { 114 | configure: nil, 115 | unattended: nil, 116 | replace: nil, 117 | url: new_resource.vsts_url, 118 | agent: new_resource.agent_name, 119 | work: new_resource.work_folder, 120 | } 121 | 122 | if new_resource.deploymentGroup 123 | args[:deploymentGroup] = nil 124 | args[:deploymentGroupName] = new_resource.deploymentGroupName || new_resource.vsts_pool 125 | args[:projectName] = new_resource.projectName 126 | args[:collectionName] = new_resource.collectionName if new_resource.collectionName 127 | 128 | args[:addDeploymentGroupTags] = nil if new_resource.deploymentGroupTags 129 | args[:deploymentGroupTags] = new_resource.deploymentGroupTags if new_resource.deploymentGroupTags 130 | else 131 | args[:pool] = new_resource.vsts_pool 132 | end 133 | 134 | if new_resource.runasservice 135 | args[:runasservice] = nil 136 | args[:windowslogonaccount] = new_resource.windowslogonaccount if windows? 137 | if windows? && new_resource.windowslogonpassword 138 | args[:windowslogonpassword] = new_resource.windowslogonpassword 139 | end 140 | end 141 | 142 | args[:proxyurl] = new_resource.proxy_url || nil 143 | args[:sslcacert] = new_resource.proxy_sslcacert || nil 144 | 145 | set_auth(args, new_resource) 146 | 147 | execute "Configuring agent '#{new_resource.agent_name}'" do 148 | cwd "#{new_resource.install_dir}/bin" 149 | sensitive true if respond_to?(:sensitive) 150 | command vsagentexec(args) 151 | action :run 152 | end 153 | 154 | execute "Fix permissions for agent '#{new_resource.agent_name}'" do 155 | command "chown -R #{new_resource.user}:#{new_resource.group} #{new_resource.install_dir}" 156 | action :run 157 | not_if { windows? } 158 | end 159 | 160 | directory "/Users/#{new_resource.user}/Library/LaunchAgents" do 161 | owner new_resource.user 162 | group new_resource.group 163 | mode '0755' 164 | action :create 165 | only_if { osx? && new_resource.runasservice } 166 | end 167 | 168 | ruby_block "Install service for agent '#{new_resource.agent_name}'" do 169 | block do 170 | service = ::VSTS::Agent::Service.new(new_resource.agent_name, new_resource.install_dir, new_resource.user, new_resource.group) 171 | service.enable 172 | service.start 173 | end 174 | only_if { new_resource.runasservice } 175 | end 176 | 177 | ruby_block "Save '#{new_resource.agent_name}' agent state" do 178 | block do 179 | save_state(new_resource.agent_name, install_dir: new_resource.install_dir, 180 | user: new_resource.user, 181 | group: new_resource.group, 182 | vsts_url: new_resource.vsts_url, 183 | vsts_pool: new_resource.vsts_pool, 184 | work_folder: new_resource.work_folder, 185 | deploymentGroup: new_resource.deploymentGroup, 186 | deploymentGroupName: new_resource.deploymentGroupName, 187 | deploymentGroupTags: new_resource.deploymentGroupTags, 188 | projectName: new_resource.projectName, 189 | collectionName: new_resource.collectionName, 190 | proxy_url: new_resource.proxy_url, 191 | proxy_sslcacert: new_resource.proxy_sslcacert) 192 | Chef::Log.info "'#{new_resource.agent_name}' agent was installed" 193 | end 194 | action :run 195 | end 196 | end 197 | 198 | template "#{new_resource.install_dir}/.path" do 199 | source 'path.erb' 200 | variables(path: new_resource.path) 201 | user new_resource.user 202 | group new_resource.group 203 | mode '0755' unless windows? 204 | action :create 205 | cookbook 'vsts_agent' 206 | notifies :run, "ruby_block[Restart vsts_agent #{new_resource.agent_name} service]", :delayed if new_resource.runasservice 207 | not_if { new_resource.path.nil? } 208 | end 209 | 210 | template "#{new_resource.install_dir}/.env" do 211 | source 'env.erb' 212 | variables(env: new_resource.env) 213 | user new_resource.user 214 | group new_resource.group 215 | mode '0755' unless windows? 216 | cookbook 'vsts_agent' 217 | notifies :run, "ruby_block[Restart vsts_agent #{new_resource.agent_name} service]", :delayed if new_resource.runasservice 218 | action :create 219 | not_if { new_resource.env.nil? || new_resource.env.empty? } 220 | end 221 | end 222 | 223 | action :remove do 224 | if current_resource && current_resource.install_dir 225 | converge_by("Removing agent '#{current_resource.agent_name}'") do 226 | remove_agent(current_resource) 227 | ruby_block "remove state for agent '#{current_resource.agent_name}'" do 228 | block do 229 | remove_current_state(current_resource) 230 | Chef::Log.info "'#{current_resource.agent_name}' agent was removed" 231 | end 232 | action :run 233 | end 234 | end 235 | end 236 | end 237 | 238 | action :restart do 239 | if current_resource && current_resource.install_dir && current_resource.runasservice 240 | converge_by("Restarting agent '#{current_resource.agent_name}'") do 241 | ruby_block "Restart vsts_agent #{current_resource.agent_name} service" do 242 | block do 243 | service = ::VSTS::Agent::Service.new(current_resource.agent_name, current_resource.install_dir, current_resource.user, current_resource.group) 244 | service.restart 245 | Chef::Log.info "'#{current_resource.agent_name}' agent was restarted" 246 | end 247 | action :run 248 | end 249 | end 250 | end 251 | end 252 | 253 | action_class do 254 | include Windows::Helper 255 | require 'json' 256 | 257 | # rubocop:disable all 258 | def remove_agent(resource) 259 | 260 | ruby_block "Disable vsts_agent['#{resource.agent_name}'] service" do 261 | block do 262 | service = ::VSTS::Agent::Service.new(resource.agent_name, resource.install_dir, resource.user, resource.group) 263 | service.stop 264 | service.disable 265 | end 266 | action :run 267 | end 268 | 269 | args = { 270 | remove: nil, 271 | unattended: nil 272 | } 273 | 274 | set_auth(args, resource) 275 | 276 | execute "Unconfiguring agent '#{resource.agent_name}'" do 277 | cwd "#{resource.install_dir}/bin" 278 | command vsagentexec(args) 279 | sensitive true if respond_to?(:sensitive) 280 | action :run 281 | only_if { agent_exists?(resource.install_dir) } 282 | end 283 | 284 | directory resource.install_dir do 285 | recursive true 286 | action :delete 287 | end 288 | end 289 | # rubocop:enable all 290 | end 291 | -------------------------------------------------------------------------------- /supermarket.pem.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/azure-pipelines-agent-cookbook/d31e2253e5d01477185b6732f3f0d2a7a55c1d9e/supermarket.pem.enc -------------------------------------------------------------------------------- /templates/default/env.erb: -------------------------------------------------------------------------------- 1 | <% @env.each do |key, value| -%> 2 | <%= key %>=<%= value %> 3 | <% end -%> -------------------------------------------------------------------------------- /templates/default/path.erb: -------------------------------------------------------------------------------- 1 | <%= @path %> -------------------------------------------------------------------------------- /test/cookbooks/linux-basic/attributes/default.rb: -------------------------------------------------------------------------------- 1 | # set attributes through test kitchen 2 | default['vsts_agent_test']['vsts_url'] = nil 3 | default['vsts_agent_test']['vsts_pool'] = nil 4 | default['vsts_agent_test']['vsts_token'] = nil 5 | default['vsts_agent_test']['deployment_group_name'] = nil 6 | default['vsts_agent_test']['deployment_group_project'] = nil 7 | default['vsts_agent_test']['username'] = 'vagrant' 8 | -------------------------------------------------------------------------------- /test/cookbooks/linux-basic/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'linux-basic' 2 | version '0.0.1' 3 | 4 | depends 'vsts_agent' 5 | 6 | depends 'apt' 7 | -------------------------------------------------------------------------------- /test/cookbooks/linux-basic/recipes/default.rb: -------------------------------------------------------------------------------- 1 | apt_update if platform_family?('debian') 2 | build_essential 'install compilation tools' 3 | 4 | user node['vsts_agent_test']['username'].to_s do 5 | manage_home true 6 | comment 'Vagrant user' 7 | home "/home/#{node['vsts_agent_test']['username']}" 8 | shell '/bin/bash' 9 | not_if "id -u #{node['vsts_agent_test']['username']}" 10 | end 11 | 12 | user 'builder' do 13 | manage_home true 14 | comment 'Builder user' 15 | home '/home/builder' 16 | shell '/bin/bash' 17 | end 18 | 19 | include_recipe 'vsts_agent::default' 20 | 21 | agent1_name = "#{node['hostname']}_01" 22 | agent2_name = "#{node['hostname']}_02" 23 | agent3_name = "#{node['hostname']}_deployment_03" 24 | 25 | agents_dir = '/opt/agents' 26 | 27 | # cleanup 28 | vsts_agent agent1_name do 29 | vsts_token node['vsts_agent_test']['vsts_token'] 30 | action :remove 31 | end 32 | 33 | vsts_agent agent2_name do 34 | vsts_token node['vsts_agent_test']['vsts_token'] 35 | action :remove 36 | end 37 | 38 | vsts_agent agent3_name do 39 | vsts_token node['vsts_agent_test']['vsts_token'] 40 | action :remove 41 | end 42 | 43 | log 'Test notification' do 44 | action :nothing 45 | end 46 | 47 | # # Agent1 48 | vsts_agent agent1_name do 49 | install_dir "#{agents_dir}/#{agent1_name}" 50 | user node['vsts_agent_test']['username'] 51 | group node['vsts_agent_test']['username'] 52 | vsts_url node['vsts_agent_test']['vsts_url'] 53 | vsts_pool node['vsts_agent_test']['vsts_pool'] 54 | vsts_token node['vsts_agent_test']['vsts_token'] 55 | action :install 56 | notifies :write, 'log[Test notification]', :immediately 57 | end 58 | 59 | vsts_agent agent1_name do 60 | action :restart 61 | end 62 | 63 | vsts_agent agent1_name do 64 | vsts_token node['vsts_agent_test']['vsts_token'] 65 | action :remove 66 | end 67 | 68 | # Agent2 69 | vsts_agent agent2_name do 70 | install_dir "#{agents_dir}/#{agent2_name}" 71 | user 'builder' 72 | group 'builder' 73 | path '/usr/local/bin/:/usr/bin:/opt/bin/:/tmp/' 74 | env('M2_HOME' => '/opt/maven', 'JAVA_HOME' => '/opt/java') 75 | vsts_url node['vsts_agent_test']['vsts_url'] 76 | vsts_pool node['vsts_agent_test']['vsts_pool'] 77 | vsts_token node['vsts_agent_test']['vsts_token'] 78 | work_folder '/tmp/work' 79 | action :install 80 | end 81 | 82 | vsts_agent agent2_name do 83 | action :restart 84 | end 85 | 86 | # Agent 3 deployment group 87 | vsts_agent agent3_name do 88 | deploymentGroup true 89 | deploymentGroupName node['vsts_agent_test']['deployment_group_name'] 90 | projectName node['vsts_agent_test']['deployment_group_project'] 91 | deploymentGroupTags 'web, db' 92 | install_dir "#{agents_dir}/#{agent3_name}" 93 | user 'builder' 94 | group 'builder' 95 | path '/usr/local/bin/:/usr/bin:/opt/bin/:/tmp/' 96 | env('M2_HOME' => '/opt/maven', 'JAVA_HOME' => '/opt/java') 97 | vsts_url node['vsts_agent_test']['vsts_url'] 98 | vsts_token node['vsts_agent_test']['vsts_token'] 99 | work_folder '/tmp/work' 100 | action :install 101 | end 102 | 103 | vsts_agent agent3_name do 104 | action :restart 105 | end 106 | -------------------------------------------------------------------------------- /test/cookbooks/osx-basic/attributes/default.rb: -------------------------------------------------------------------------------- 1 | # set vsts attributes through test kitchen 2 | default['vsts_agent_test']['vsts_url'] = nil 3 | default['vsts_agent_test']['vsts_pool'] = nil 4 | default['vsts_agent_test']['vsts_token'] = nil 5 | default['vsts_agent_test']['username'] = 'vagrant' 6 | -------------------------------------------------------------------------------- /test/cookbooks/osx-basic/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'osx-basic' 2 | version '0.0.1' 3 | 4 | depends 'vsts_agent' 5 | -------------------------------------------------------------------------------- /test/cookbooks/osx-basic/recipes/default.rb: -------------------------------------------------------------------------------- 1 | #### Begin prepare system #### 2 | build_essential 'install compilation tools' 3 | #### End prepare system #### 4 | 5 | include_recipe 'vsts_agent::default' 6 | 7 | agent1_name = "osx_#{node['hostname']}_01" 8 | agent2_name = "osx_#{node['hostname']}_02" 9 | 10 | agents_dir = "/Users/#{node['vsts_agent_test']['username']}/agents" 11 | 12 | # cleanup 13 | vsts_agent agent1_name do 14 | vsts_token node['vsts_agent_test']['vsts_token'] 15 | action :remove 16 | end 17 | 18 | vsts_agent agent2_name do 19 | vsts_token node['vsts_agent_test']['vsts_token'] 20 | action :remove 21 | end 22 | 23 | # Agent1 24 | vsts_agent agent1_name do 25 | install_dir "#{agents_dir}/#{agent1_name}" 26 | user node['vsts_agent_test']['username'] 27 | group 'staff' 28 | vsts_url node['vsts_agent_test']['vsts_url'] 29 | vsts_pool node['vsts_agent_test']['vsts_pool'] 30 | vsts_token node['vsts_agent_test']['vsts_token'] 31 | action :install 32 | end 33 | 34 | vsts_agent agent1_name do 35 | action :restart 36 | end 37 | 38 | vsts_agent agent1_name do 39 | vsts_token node['vsts_agent_test']['vsts_token'] 40 | action :remove 41 | end 42 | 43 | # Agent2 44 | vsts_agent agent2_name do 45 | install_dir "#{agents_dir}/#{agent2_name}" 46 | user node['vsts_agent_test']['username'] 47 | group 'staff' 48 | path '/usr/local/bin/:/usr/bin:/opt/bin/' 49 | env('M2_HOME' => '/opt/maven', 'JAVA_HOME' => '/opt/java') 50 | vsts_url node['vsts_agent_test']['vsts_url'] 51 | vsts_pool node['vsts_agent_test']['vsts_pool'] 52 | vsts_token node['vsts_agent_test']['vsts_token'] 53 | action :install 54 | end 55 | 56 | vsts_agent agent2_name do 57 | action :restart 58 | end 59 | 60 | vsts_agent agent2_name do 61 | vsts_token node['vsts_agent_test']['vsts_token'] 62 | action :remove 63 | end 64 | -------------------------------------------------------------------------------- /test/cookbooks/windows-basic/attributes/default.rb: -------------------------------------------------------------------------------- 1 | # set attributes through test kitchen 2 | default['vsts_agent_test']['vsts_url'] = nil 3 | default['vsts_agent_test']['vsts_pool'] = nil 4 | default['vsts_agent_test']['vsts_token'] = nil 5 | default['vsts_agent_test']['username'] = 'vagrant' 6 | -------------------------------------------------------------------------------- /test/cookbooks/windows-basic/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'windows-basic' 2 | version '0.0.1' 3 | 4 | depends 'vsts_agent' 5 | depends 'grant_logon_as_service' 6 | -------------------------------------------------------------------------------- /test/cookbooks/windows-basic/recipes/default.rb: -------------------------------------------------------------------------------- 1 | #### Begin prepare system #### 2 | user 'builder' do 3 | comment 'Builder user' 4 | home '/home/builder' 5 | shell '/bin/bash' 6 | password 'Pas$w0r_d' 7 | end 8 | 9 | grant_logon_as_service node['vsts_agent_test']['username'] 10 | grant_logon_as_service 'builder' 11 | 12 | include_recipe 'seven_zip::default' 13 | 14 | #### End prepare system #### 15 | 16 | include_recipe 'vsts_agent::default' 17 | 18 | agent1_name = "win_#{node['hostname']}_01" 19 | agent2_name = "win_#{node['hostname']}_02" 20 | agent3_name = "win_#{node['hostname']}_deployment_03" 21 | 22 | agents_dir = 'C:\\agents' 23 | 24 | log 'Test notification' do 25 | action :nothing 26 | end 27 | 28 | # cleanup 29 | vsts_agent agent1_name do 30 | vsts_token node['vsts_agent_test']['vsts_token'] 31 | action :remove 32 | end 33 | 34 | vsts_agent agent2_name do 35 | vsts_token node['vsts_agent_test']['vsts_token'] 36 | action :remove 37 | end 38 | 39 | vsts_agent agent3_name do 40 | vsts_token node['vsts_agent_test']['vsts_token'] 41 | action :remove 42 | end 43 | 44 | # Agent1 45 | vsts_agent agent1_name do 46 | install_dir "#{agents_dir}\\#{agent1_name}" 47 | user node['vsts_agent_test']['username'] 48 | vsts_url node['vsts_agent_test']['vsts_url'] 49 | vsts_pool node['vsts_agent_test']['vsts_pool'] 50 | vsts_token node['vsts_agent_test']['vsts_token'] 51 | windowslogonaccount node['vsts_agent_test']['username'] 52 | windowslogonpassword node['vsts_agent_test']['username'] 53 | notifies :write, 'log[Test notification]', :immediately 54 | action :install 55 | end 56 | 57 | vsts_agent agent1_name do 58 | vsts_token node['vsts_agent_test']['vsts_token'] 59 | action :restart 60 | end 61 | 62 | vsts_agent agent1_name do 63 | vsts_token node['vsts_agent_test']['vsts_token'] 64 | action :remove 65 | end 66 | 67 | # Agent2 68 | vsts_agent agent2_name do 69 | install_dir "#{agents_dir}\\#{agent2_name}" 70 | user 'builder' 71 | vsts_url node['vsts_agent_test']['vsts_url'] 72 | vsts_pool node['vsts_agent_test']['vsts_pool'] 73 | vsts_token node['vsts_agent_test']['vsts_token'] 74 | windowslogonaccount 'NT AUTHORITY\\NetworkService' 75 | action :install 76 | end 77 | 78 | vsts_agent agent2_name do 79 | action :restart 80 | end 81 | 82 | # Agent3 83 | vsts_agent agent3_name do 84 | deploymentGroup true 85 | deploymentGroupName node['vsts_agent_test']['deployment_group_name'] 86 | projectName node['vsts_agent_test']['deployment_group_project'] 87 | deploymentGroupTags 'web, db' 88 | install_dir "#{agents_dir}\\#{agent2_name}" 89 | user 'builder' 90 | vsts_url node['vsts_agent_test']['vsts_url'] 91 | vsts_pool node['vsts_agent_test']['vsts_pool'] 92 | vsts_token node['vsts_agent_test']['vsts_token'] 93 | windowslogonaccount 'NT AUTHORITY\\NetworkService' 94 | action :install 95 | end 96 | 97 | vsts_agent agent3_name do 98 | action :restart 99 | end 100 | -------------------------------------------------------------------------------- /test/cookbooks/windows-basic/solo.json: -------------------------------------------------------------------------------- 1 | { 2 | "run_list": [ "recipe[windows-basic]" ] 3 | } -------------------------------------------------------------------------------- /test/integration/xplat-basic/serverspec/xplat_spec.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | 3 | set :backend, :exec 4 | 5 | # home_dir = if os[:family] == 'darwin' 6 | # '/Users/vagrant' 7 | # else 8 | # '/home/vagrant' 9 | # end 10 | 11 | # describe file("#{home_dir}/agents/agent_01/.agent") do 12 | # it { should_not exist } 13 | # end 14 | 15 | # describe file("#{home_dir}/agents/agent_02/.agent") do 16 | # it { should be_file } 17 | # end 18 | 19 | # describe service('agent2'), :unless => os[:family] == 'darwin' do 20 | # it { should be_running } 21 | # end 22 | -------------------------------------------------------------------------------- /test/solo.rb: -------------------------------------------------------------------------------- 1 | pwd = File.expand_path(File.dirname(__FILE__)) 2 | file_cache_path "#{pwd}/../cache" 3 | cookbook_path "#{pwd}/../solo-cookbooks" 4 | --------------------------------------------------------------------------------