Refactoring to use new type of VSTS Build Agent

This commit is contained in:
Dmitry Ivanov 2016-06-15 13:30:09 +02:00
Родитель 324fea617c
Коммит a28f36a5a7
26 изменённых файлов: 478 добавлений и 775 удалений

Просмотреть файл

@ -16,7 +16,7 @@ platforms:
driver_config:
box: debian/jessie64
provisioner:
require_chef_omnibus: 11.18.6
require_chef_omnibus: 12.4.3
- name: ubuntu1404
driver_config:
@ -51,7 +51,7 @@ platforms:
communicator: 'winrm'
box: win81x64-enterprise #private
provisioner:
require_chef_omnibus: 11.18.6
require_chef_omnibus: 12.4.3
suites:
@ -60,28 +60,12 @@ suites:
- recipe[xplat-basic::default]
includes:
- debian8
- ubuntu1404
- centos6
- windows10
- osx109-desktop
attributes:
vsts_build_agent_test:
vsts_url: <%= ENV['VSTS_URL'] %>
vsts_pool: <%= ENV['VSTS_POOL'] %>
vsts_user: <%= ENV['VSTS_USER'] %>
vsts_token: <%= ENV['VSTS_TOKEN'] %>
- name: windows-basic
run_list:
- recipe[windows-basic::default]
includes:
- windows10
- windows81
attributes:
vsts_build_agent_test:
vsts_url: <%= ENV['VSTS_URL'] %>
vsts_pool: <%= ENV['VSTS_POOL'] %>
vsts_user: <%= ENV['VSTS_USER'] %>
vsts_token: <%= ENV['VSTS_TOKEN'] %>

Просмотреть файл

@ -1,8 +1,8 @@
source 'https://supermarket.chef.io'
cookbook 'ark', git: 'git://github.com/ivadim/ark.git'
metadata
group :integration do
cookbook 'windows-basic', :path => './test/cookbooks/windows-basic'
cookbook 'xplat-basic', :path => './test/cookbooks/xplat-basic'
end

Просмотреть файл

@ -1,8 +1,12 @@
default['vsts_build_agent']['xplat']['package_name'] = 'vsoagent-installer'
default['vsts_build_agent']['xplat']['package_version'] = 'latest'
default['vsts_build_agent']['xplat']['skip_vsoagent_installer'] = false
default['vsts_build_agent']['binary']['version'] = '2.102.0'
default['vsts_build_agent']['binary']['windows'] = 'tbd'
default['vsts_build_agent']['binary']['ubuntu'] = 'https://github.com/Microsoft/vsts-agent/releases/download/v2.101.1/vsts-agent-ubuntu.14.04-x64-2.101.1.tar.gz'
default['vsts_build_agent']['binary']['rhel'] = 'https://github.com/Microsoft/vsts-agent/releases/download/v2.101.1/vsts-agent-rhel.7.2-x64-2.101.1.tar.gz'
default['vsts_build_agent']['binary']['osx'] = 'https://github.com/Microsoft/vsts-agent/releases/download/v2.101.1/vsts-agent-osx.10.11-x64-2.101.1.tar.gz'
case node['platform_family']
when 'windows'
default['vsts_build_agent']['binary']['url'] = 'https://github.com/Microsoft/vsts-agent/releases/download/v%s/vsts-agent-win7-x64-%s.zip'
when 'rhel'
default['vsts_build_agent']['binary']['url'] = 'https://github.com/Microsoft/vsts-agent/releases/download/v%s/vsts-agent-rhel.7.2-x64-%s.tar.gz'
when 'debian'
default['vsts_build_agent']['binary']['url'] = 'https://github.com/Microsoft/vsts-agent/releases/download/v%s/vsts-agent-ubuntu.14.04-x64-%s.tar.gz'
when 'mac_os_x', 'mac_os_x_server'
default['vsts_build_agent']['binary']['url'] = 'https://github.com/Microsoft/vsts-agent/releases/download/v%s/vsts-agent-osx.10.11-x64-%s.tar.gz'
end

Просмотреть файл

@ -1,57 +0,0 @@
var cfgm = require("./configuration");
var cm = require('./common');
var webapi = require('vso-node-api/WebApi');;
var cfgr = new cfgm.Configurator();
var _creds;
cm.readBasicCreds().then(function (credentials) {
_creds = credentials;
action = process.argv.slice(2)[0];
settings = cfgm.read();
var agentPoolId;
if (action == 'install') {
console.info("Trying to create agent")
return cfgr.create(credentials).fail(function (err) {
// we couldn't create agent, then we try to update
console.info("Trying to update agent")
cfgr.update(credentials, settings)
})
} else if (action == 'remove') {
console.info("Trying to remove agent")
var agentApi = new webapi.WebApi(settings.serverUrl, cm.basicHandlerFromCreds(credentials)).getQTaskAgentApi();
agentApi.connect()
.then(function (connected) {
console.log('successful connect as ' + connected.authenticatedUser.customDisplayName);
return agentApi.getAgentPools(settings.poolName, null);
}).then(function (agentPools) {
if (agentPools.length == 0) {
throw new Error(settings.poolName + ' pool does not exist.');
}
// we queried by name so should only get 1
agentPoolId = agentPools[0].id;
console.log('Retrieved agent pool: ' + agentPools[0].name + ' (' + agentPoolId + ')');
return agentApi.getAgents(agentPoolId, settings.agentName);
}).then(function (agents) {
if (agents.length == 1) {
console.log('Found agent in pool ' + agents[0].name + ' (' + agentPoolId + ')');
var agentId = agents[0].id;
agentApi.deleteAgent(agentPoolId, agentId);
} else {
console.log('Not found agents in pool '+ agentPoolId);
}
});
} else {
console.error("Wrong action. Must be install or remove")
process.exit(1);
}
}).fail(function (err) {
console.error('Error starting the agent');
console.error(err.message);
process.exit(1);
});

Просмотреть файл

@ -1,50 +1,82 @@
module VSTS
module Build
module Agent
# Helper methods for VSTS Build Agent installation
module Helpers
VARS_TO_SAVE = %w(vsts_url vsts_pool vsts_user install_dir sv_name sv_session user group user_home).freeze
def agent_installed?(resource, node)
agent_attribute?(resource.agent_name, node) &&
(::File.exist?("#{resource.install_dir}/.agent") ||
::File.file?("#{resource.install_dir}\\Agent\\VsoAgent.exe"))
end
include Chef::DSL::PlatformIntrospection
require 'json'
# def agent_installed?(resource, node)
# agent_attribute?(resource.agent_name, node) && (::File.exist?("#{resource.install_dir}/.Agent"))
# end
def service_name(resource)
return resource.sv_name if resource.sv_name
return nil unless resource.vsts_url
hostname = URI.parse(resource.vsts_url).host
hostname = hostname[0, hostname.index('.')] if hostname.include?('.')
"vsoagent.#{hostname}.#{resource.agent_name}"
end
def get_npm_install_cmd(node)
npm_cmd = "npm install -global #{node['vsts_build_agent']['xplat']['package_name']}"
unless node['vsts_build_agent']['xplat']['package_version'] == 'latest'
npm_cmd += "@#{node['vsts_build_agent']['xplat']['package_version']}"
if windows?
"vstsagent.#{hostname}.#{resource.agent_name}"
else
"vsts.agent.#{hostname}.#{resource.agent_name}"
end
npm_cmd
end
def archive_name(resource)
name = "vsts_build_agent"
name += "_" + resource.version if resource.version
name
end
def download_url(version, node)
url = node['vsts_build_agent']['binary']['url']
url = url.gsub '%s', version
url
end
def windows?
platform_family?('windows')
end
def debian?
platform_family?('debian')
end
def rhel?
platform_family?('rhel')
end
def mac_os_x?
platform_family?('mac_os_x') || platform_family?('mac_os_x_server')
end
def save_current_state(resource, node)
VARS_TO_SAVE.each do |var|
node.set['vsts_build_agent']['agents'][resource.agent_name][var] = resource.send(var) if resource.respond_to?(var.to_sym)
end
node.set['vsts_build_agent']['agents'][resource.agent_name]['install_dir'] = resource.install_dir
node.save
end
def load_current_state(resource, node)
resource.exists = false
return unless agent_attribute?(resource.agent_name, node)
VARS_TO_SAVE.each do |var|
resource.send(var, node['vsts_build_agent']['agents'][resource.agent_name][var]) if resource.respond_to?(var.to_sym)
end
resource.install_dir(node['vsts_build_agent']['agents'][resource.agent_name]['install_dir']) unless resource.install_dir
return unless ::File.exist?(::File.join(resource.install_dir, '.agent'))
f = ::File.read(::File.join(resource.install_dir, '.agent'), mode: 'r:bom|utf-8').strip
agent = JSON.parse(f)
resource.vsts_url(agent['serverUrl'])
resource.vsts_pool(agent['poolName'])
resource.work_folder(agent['workFolder'])
resource.exists = true
end
def agent_attribute?(agent_name, node)
node['vsts_build_agent']['agents'] && node['vsts_build_agent']['agents'][agent_name]
if node['vsts_build_agent']['agents'] != nil &&
node['vsts_build_agent']['agents'][agent_name] != nil &&
node['vsts_build_agent']['agents'][agent_name]['install_dir'] != nil &&
!node['vsts_build_agent']['agents'][agent_name]['install_dir'].empty?
return true
else
return false
end
end
def remove_current_state(resource, node)
@ -52,36 +84,41 @@ module VSTS
node.save
end
def plist_path(resource)
path = if resource.sv_session
"/Library/LaunchAgents/#{resource.sv_name}.plist"
else
"/Library/LaunchDaemons/#{resource.sv_name}.plist"
end
# def plist_path(resource)
# path = if resource.sv_session
# "/Library/LaunchAgents/#{resource.sv_name}.plist"
# else
# "/Library/LaunchDaemons/#{resource.sv_name}.plist"
# end
path = "#{resource.user_home}#{path}" if resource.user_home
path
end
# path = "#{resource.user_home}#{path}" if resource.user_home
# path
# end
def launchctl_load(resource)
plist = plist_path resource
command = 'launchctl load -w '
command += "-S #{resource.sv_session} " if resource.sv_session
command += plist
command
end
# def launchctl_load(resource)
# plist = plist_path resource
# command = 'launchctl load -w '
# command += "-S #{resource.sv_session} " if resource.sv_session
# command += plist
# command
# end
def launchctl_unload(resource)
plist = plist_path resource
command = "launchctl unload #{plist}"
command
end
# def launchctl_unload(resource)
# plist = plist_path resource
# command = "launchctl unload #{plist}"
# command
# end
def vsagentexec(args = {})
command = 'Agent\\VsoAgent.exe '
command = 'Agent.Listener '
command = './' + command unless windows?
args.each do |key, value|
command += "/#{key}"
command += ":\"#{value}\"" unless value.nil?
if key == 'configure' || key == 'remove'
command += key
else
command += "--#{key}"
command += " \"#{value}\"" unless value.nil?
end
command += ' '
end
command

Просмотреть файл

@ -12,8 +12,6 @@ version '1.0.0'
supports os
end
suggests 'nodejs'
depends 'runit'
depends 'windows'
depends 'ark'
depends 'seven_zip', '~> 2.0.0'

199
providers/default.rb Normal file
Просмотреть файл

@ -0,0 +1,199 @@
require 'chef/mixin/shell_out'
require 'json'
include ::VSTS::Build::Agent::Helpers
include ::Windows::Helper
use_inline_resources
def whyrun_supported?
true
end
def load_current_resource
@current_resource = Chef::Resource::VstsBuildAgent.new(@new_resource.name)
@current_resource.agent_name(@new_resource.agent_name)
load_current_state(@current_resource, node)
@current_resource
end
action :install do
log "Install: #{@current_resource.exists}"
log "Install: #{@current_resource.install_dir}"
if @current_resource.exists
Chef::Log.info "#{new_resource.agent_name} agent already exists - nothing to do"
else
converge_by("Installing agent '#{new_resource.agent_name}'") do
version = new_resource.version || node['vsts_build_agent']['binary']['version']
archive_url = download_url(version, node)
archive_name = archive_name(new_resource)
unpack_dir = ::File.join(Chef::Config[:file_cache_path], "unpack_agent")
unpack_dir = win_friendly_path(unpack_dir) if windows?
directory new_resource.install_dir do
recursive true
action :delete
end
directory unpack_dir do
recursive true
action :delete
end
ark archive_name do
url archive_url
backup false
path unpack_dir
owner new_resource.user
strip_components 0 if windows?
action :put
end
directory new_resource.install_dir do
recursive true
rights :full_control, new_resource.user, :applies_to_children => true if windows?
user new_resource.user
group new_resource.group
mode '0755'
action :create
end
execute "Move #{new_resource.agent_name} agent from intermidiate folder" do
command "cp -r #{unpack_dir}/#{archive_name}/* #{new_resource.install_dir}" unless windows?
command "xcopy #{unpack_dir}\\#{archive_name}\\* #{win_friendly_path(new_resource.install_dir)} /s /e" if windows?
action :run
end
args = {
'configure' => nil,
'unattended' => nil,
'replace' => nil,
'url' => new_resource.vsts_url,
'pool' => new_resource.vsts_pool,
'agent' => new_resource.agent_name,
'work' => new_resource.work_folder
}
if new_resource.runasservice
args['runasservice'] = nil
if windows?
args['windowslogonaccount'] = new_resource.windowslogonaccount
args['windowslogonpassword'] = new_resource.windowslogonpassword if new_resource.windowslogonpassword
end
else
args['nostart'] = nil
end
args['auth'] = new_resource.vsts_auth
if new_resource.vsts_auth == 'PAT'
args['token'] = new_resource.vsts_token
elsif (new_resource.vsts_auth == 'Negotiate') || (new_resource.vsts_auth == 'ALT')
args['--username'] = new_resource.vsts_username
args['--password'] = new_resource.vsts_password
else
#Integrated Auth: does not take any additional arguments
end
execute "Configuring agent '#{new_resource.agent_name}'" do
cwd "#{new_resource.install_dir}/bin"
sensitive true if respond_to?(:sensitive)
command vsagentexec(args)
action :run
end
execute "Fix permissions for agent '#{new_resource.agent_name}'" do
command "chown -R #{new_resource.user}:#{new_resource.group} #{new_resource.install_dir}"
action :run
not_if { windows? }
end
execute "Install nix service for '#{new_resource.agent_name}'" do
cwd new_resource.install_dir
command "./svc.sh install"
action :run
not_if { windows? }
end
ruby_block "save state for agent '#{new_resource.agent_name}'" do
block do
save_current_state(new_resource, node)
Chef::Log.info "'#{new_resource.agent_name}' agent was installed"
end
action :run
end
new_resource.updated_by_last_action(true)
end
end
end
action :remove do
log "Remove: #{@current_resource.exists}"
log "Remove: #{@current_resource.install_dir}"
if @current_resource.exists
converge_by("Removing agent '#{current_resource.agent_name}'") do
sn = service_name(@current_resource)
service sn do
action [:stop, :disable]
ignore_failure true
end
execute "Uninstall nix service for '#{new_resource.agent_name}'" do
cwd current_resource.install_dir
command "./svc.sh uninstall"
action :run
not_if { windows? }
end
args = {
'remove' => nil,
'unattended' => nil
}
args['auth'] = new_resource.vsts_auth
if new_resource.vsts_auth == 'PAT'
args['token'] = new_resource.vsts_token
elsif (new_resource.vsts_auth == 'Negotiate') || (new_resource.vsts_auth == 'ALT')
args['--username'] = new_resource.vsts_username
args['--password'] = new_resource.vsts_password
else
#Integrated Auth: does not take any additional arguments
end
execute "Unconfiguring agent '#{current_resource.agent_name}'" do
cwd "#{current_resource.install_dir}/bin"
command vsagentexec(args)
action :run
end
ruby_block "remove state for agent '#{current_resource.agent_name}'" do
block do
remove_current_state(current_resource, node)
Chef::Log.info "'#{current_resource.agent_name}' agent was removed"
end
action :run
end
new_resource.updated_by_last_action(true)
end
end
end
action :restart do
log "Restart: #{@current_resource.exists}"
log "Restart: #{@current_resource.install_dir}"
if @current_resource.exists
converge_by("Restarting agent '#{current_resource.agent_name}'") do
sn = service_name(@current_resource)
service sn do
action :restart
end
log "'#{current_resource.agent_name}' agent was restarted"
new_resource.updated_by_last_action(true)
end
end
end

Просмотреть файл

@ -1,136 +0,0 @@
require 'chef/mixin/shell_out'
include Chef::Mixin::ShellOut
include ::VSTS::Build::Agent::Helpers
use_inline_resources
def whyrun_supported?
true
end
def load_current_resource
@current_resource = Chef::Resource::VstsBuildAgentWindows.new(@new_resource.name)
@current_resource.agent_name(@new_resource.agent_name)
@current_resource.exists = false
load_current_state(@current_resource, node)
@new_resource.sv_name(service_name(@new_resource))
if agent_installed?(@current_resource, node)
@current_resource.vsts_token(@new_resource.vsts_token)
@current_resource.exists = true
end
@current_resource
end
action :install do
if @current_resource.exists
Chef::Log.info "#{new_resource.agent_name} agent already exists - nothing to do"
else
converge_by("Installing agent \"#{new_resource.agent_name}\"") do
powershell_script 'Downloading vsoagent' do
code <<-EOH
$username = "#{new_resource.vsts_user}"
$patToken = "#{new_resource.vsts_token}"
$OutFile = "#{Chef::Config[:file_cache_path]}/vso_agent.zip"
$auth = ('{0}:{1}' -f $username,$patToken)
$auth = [System.Text.Encoding]::UTF8.GetBytes($auth)
$auth = [System.Convert]::ToBase64String($auth)
$h = @{Authorization=('Basic {0}' -f $auth)}
$wc = New-Object Net.WebClient
$wc.Headers.add('Authorization', 'Basic {0}' -f $auth)
$wc.DownloadFile( "#{new_resource.vsts_url}/_apis/distributedtask/packages/agent", $OutFile )
EOH
not_if { ::File.exist?("#{Chef::Config[:file_cache_path]}/vso_agent.zip") }
end
directory new_resource.install_dir do
rights :full_control, new_resource.sv_user, :applies_to_children => true
recursive true
action :create
end
windows_zipfile new_resource.install_dir do
source "#{Chef::Config[:file_cache_path]}/vso_agent.zip"
action :unzip
end
powershell_script 'Removing the ZoneIdentifier from files downloaded from the internet' do
cwd new_resource.install_dir
code <<-EOH
Get-ChildItem -Path #{new_resource.install_dir} | Unblock-File | out-null
Get-ChildItem -Recurse -Path #{new_resource.install_dir}\\Agent | Unblock-File | out-null
EOH
end
args = {
'configure' => nil,
'RunningAsService' => nil,
'serverUrl' => new_resource.vsts_url,
'WindowsServiceName' => new_resource.sv_name,
'WindowsServiceLogonAccount' => new_resource.sv_user,
'WindowsServiceLogonPassword' => new_resource.sv_password,
'name' => new_resource.agent_name,
'PoolName' => new_resource.vsts_pool,
'WorkFolder' => new_resource.work_folder,
'Login' => "#{new_resource.vsts_user},#{new_resource.vsts_token}",
'force' => nil,
'NoPrompt' => nil
}
execute "Configuring agent \"#{new_resource.agent_name}\"" do
cwd new_resource.install_dir
command vsagentexec(args)
action :run
end
end
save_current_state(new_resource, node)
new_resource.updated_by_last_action(true)
Chef::Log.info "\"#{new_resource.agent_name}\" agent was installed"
end
end
action :remove do
if @current_resource.exists
converge_by("Removing agent \"#{@current_resource.agent_name}\"") do
args = {
'unconfigure' => nil,
'Login' => "#{@current_resource.vsts_user},#{@current_resource.vsts_token}",
'force' => nil,
'NoPrompt' => nil
}
execute "Unconfiguring agent \"#{@current_resource.agent_name}\"" do
cwd current_resource.install_dir
command vsagentexec(args)
action :run
retries 3
retry_delay 15
end
directory current_resource.install_dir do
recursive true
action :delete
end
end
remove_current_state(@current_resource, node)
new_resource.updated_by_last_action(true)
Chef::Log.info "\"#{new_resource.agent_name}\" agent was removed"
end
end
action :restart do
if @current_resource.exists
converge_by("Restarting agent \"#{@current_resource.agent_name}\"") do
service @current_resource.sv_name do
action :restart
end
end
new_resource.updated_by_last_action(true)
Chef::Log.info "\"#{@current_resource.agent_name}\" agent was restarted"
end
end

Просмотреть файл

@ -1,211 +0,0 @@
require 'chef/mixin/shell_out'
require 'json'
include ::VSTS::Build::Agent::Helpers
use_inline_resources
def whyrun_supported?
true
end
def load_current_resource
@current_resource = Chef::Resource::VstsBuildAgentXplat.new(@new_resource.name)
@current_resource.agent_name(@new_resource.agent_name)
@current_resource.exists = false
load_current_state(@current_resource, node)
@new_resource.sv_name(service_name(@new_resource))
if agent_installed?(@current_resource, node)
@current_resource.vsts_token(@new_resource.vsts_token)
@current_resource.exists = true
end
@current_resource
end
action :install do
if @current_resource.exists
Chef::Log.info "#{new_resource.agent_name} agent already exists - nothing to do"
else
converge_by("Installing agent \"#{new_resource.agent_name}\"") do
npm_cmd = get_npm_install_cmd(node)
execute 'Install vsoagent-installer npm package' do
command npm_cmd
not_if { node['vsts_build_agent']['xplat']['skip_vsoagent_installer'] }
end
directory new_resource.install_dir do
user new_resource.user
group new_resource.group
mode '0755'
recursive true
action [:delete, :create]
end
execute "Initializing agent \"#{new_resource.agent_name}\"" do
cwd new_resource.install_dir
command 'vsoagent-installer'
user new_resource.user
group new_resource.group
end
template "#{new_resource.install_dir}/.agent" do
source 'agent_conf.erb'
variables(:agent => new_resource)
owner new_resource.user
group new_resource.group
cookbook 'vsts_build_agent'
end
cookbook_file "#{new_resource.install_dir}/agent/vsoagent_configurator.js" do
source 'vsoagent_configurator.js'
owner new_resource.user
group new_resource.group
cookbook 'vsts_build_agent'
end
execute "Configuring agent \"#{new_resource.agent_name}\"" do
cwd new_resource.install_dir
command "node agent/vsoagent_configurator install -u #{new_resource.vsts_user} -p #{new_resource.vsts_token} -s #{new_resource.vsts_url} -a #{new_resource.agent_name} -l #{new_resource.vsts_pool} -b false"
user new_resource.user
group new_resource.group
end
if new_resource.user_home && !new_resource.sv_envs.key?('HOME')
new_resource.sv_envs['HOME'] = new_resource.user_home
end
if mac_os_x?
plist = plist_path new_resource
directory "#{new_resource.user_home}/Library/LaunchDaemons" do
user new_resource.user
group new_resource.group
mode '0755'
action :create
only_if { new_resource.user_home }
end
template plist do
source "#{new_resource.sv_template}.plist.erb"
cookbook new_resource.sv_cookbook
user new_resource.user if new_resource.user_home
group new_resource.group if new_resource.user_home
variables(
:agent => new_resource
)
end
cmd = launchctl_load @new_resource
execute cmd do
user new_resource.user if new_resource.user_home
group new_resource.group if new_resource.user_home
action :run
end
else
runit_service new_resource.sv_name do
options(
:agent => new_resource
)
owner new_resource.user
group new_resource.group
cookbook new_resource.sv_cookbook
run_template_name new_resource.sv_template
log_template_name new_resource.sv_template
sv_timeout new_resource.sv_timeout
sv_verbose true
action :enable
end
ruby_block 'Wait for service setup' do
block do
# TODO: remove when runit cookbook will wait for service setup
sleep new_resource.sv_wait_timeout
end
end
runit_service new_resource.sv_name do
action :start
end
end
save_current_state(new_resource, node)
Chef::Log.info "\"#{new_resource.agent_name}\" agent was installed"
new_resource.updated_by_last_action(true)
end
end
end
action :remove do
if @current_resource.exists
converge_by("Removing agent \"#{@current_resource.agent_name}\"") do
if mac_os_x?
plist = plist_path @current_resource
cmd = launchctl_unload @current_resource
execute "Unload service for #{@current_resource.agent_name}" do
user current_resource.user if current_resource.user_home
group current_resource.group if current_resource.user_home
command cmd
only_if { ::File.exist?(plist) }
action :run
end
file plist do
action :delete
end
else
runit_service @current_resource.sv_name do
action [:stop, :disable]
end
end
execute "Delete agent \"#{@current_resource.agent_name}\" from server" do
cwd current_resource.install_dir
command "node agent/vsoagent_configurator remove -u #{current_resource.vsts_user} -p #{current_resource.vsts_token} -s #{current_resource.vsts_url} -a #{current_resource.agent_name} -l #{current_resource.vsts_pool} -b false"
user current_resource.user
group current_resource.group
end
directory @current_resource.install_dir do
recursive true
action :delete
end
remove_current_state(@current_resource, node)
Chef::Log.info "\"#{@current_resource.agent_name}\" agent was removed"
new_resource.updated_by_last_action(true)
end
end
end
action :restart do
if @current_resource.exists
converge_by("Restarting agent \"#{@current_resource.agent_name}\"") do
if mac_os_x?
cmd = launchctl_unload @current_resource
execute cmd do
user current_resource.user if current_resource.user_home
group current_resource.group if current_resource.user_home
action :run
end
cmd = launchctl_load @current_resource
execute cmd do
user current_resource.user if current_resource.user_home
group current_resource.group if current_resource.user_home
action :run
end
else
runit_service @current_resource.sv_name do
action :restart
end
end
Chef::Log.info "\"#{@current_resource.agent_name}\" agent was restarted"
new_resource.updated_by_last_action(true)
end
end
end
private
def mac_os_x?
platform_family?('mac_os_x') || platform_family?('mac_os_x_server')
end

Просмотреть файл

@ -1,3 +1,7 @@
if %w(debian rhel fedora gentoo).include?(node['platform_family'])
include_recipe 'runit::default'
end
include_recipe 'ark::default'
if platform_family?('debian')
package 'libunwind8' do
action :install
end
end

28
resources/default.rb Normal file
Просмотреть файл

@ -0,0 +1,28 @@
actions :install, :remove, :restart
default_action :install
attribute :agent_name, :name_attribute => true
attribute :install_dir, :kind_of => String
attribute :user, :kind_of => String
attribute :group, :kind_of => String
attribute :work_folder, :kind_of => String, :default => '_work'
# Windows Service
attribute :runasservice, :kind_of => [ TrueClass, FalseClass ], :default => true
attribute :windowslogonaccount, :kind_of => String
attribute :windowslogonpassword, :kind_of => String
# environment
attribute :version, :kind_of => String
# VSTS Access
attribute :vsts_url, :kind_of => String
attribute :vsts_pool, :kind_of => String
attribute :vsts_auth, :kind_of => String, :default => 'PAT'
attribute :vsts_username, :kind_of => String
attribute :vsts_password, :kind_of => String
attribute :vsts_token, :kind_of => String
attr_accessor :exists

Просмотреть файл

@ -1,18 +0,0 @@
actions :install, :remove, :restart
default_action :install
attribute :agent_name, :name_attribute => true
attribute :install_dir, :kind_of => String
attribute :sv_name, :kind_of => String
attribute :sv_user, :kind_of => String
attribute :sv_password, :kind_of => String
attribute :vsts_url, :kind_of => String
attribute :vsts_pool, :kind_of => String
attribute :vsts_user, :kind_of => String
attribute :vsts_token, :kind_of => String
attribute :work_folder, :kind_of => String, :default => '_work' # not supported on client side
attr_accessor :exists

Просмотреть файл

@ -1,24 +0,0 @@
actions :install, :remove, :restart
default_action :install
attribute :agent_name, :name_attribute => true
attribute :install_dir, :kind_of => String
attribute :user, :kind_of => String
attribute :group, :kind_of => String
attribute :user_home, :kind_of => String
attribute :sv_name, :kind_of => String # Default vsoagent.host.agent_name
attribute :sv_cookbook, :kind_of => String, :default => 'vsts_build_agent'
attribute :sv_template, :kind_of => String, :default => 'vsts_build_agent'
attribute :sv_timeout, :kind_of => Integer, :default => 120
attribute :sv_envs, :kind_of => Hash, :default => {}
attribute :sv_session, :kind_of => String, :default => nil # used by MacOsX. Can be Aqua for interact with GUI
attribute :sv_wait_timeout, :kind_of => Integer, :default => 5
attribute :vsts_url, :kind_of => String
attribute :vsts_pool, :kind_of => String
attribute :vsts_user, :kind_of => String
attribute :vsts_token, :kind_of => String
attr_accessor :exists

Просмотреть файл

@ -1,5 +0,0 @@
{
"poolName": "<%= @agent.vsts_pool %>",
"serverUrl": "<%= @agent.vsts_url %>",
"agentName": "<%= @agent.agent_name %>"
}

Просмотреть файл

@ -1,2 +0,0 @@
#!/bin/sh
exec svlogd -tt ./main

Просмотреть файл

@ -1,11 +0,0 @@
#!/bin/sh
ulimit -Hn 65550
ulimit -Sn 65550
exec 2>&1
cd <%= @options[:agent].install_dir %>
exec env <% unless @options[:agent].sv_envs.empty? -%><%= @options[:agent].sv_envs.map{|k,v| "#{k}=#{v}"}.join(' ') %><% end -%> \
chpst -u <%= @options[:agent].user %>:<%= @options[:agent].group %> \
-U <%= @options[:agent].user %>:<%= @options[:agent].group %> \
node ./agent/vsoagent.js -u <%= @options[:agent].vsts_user %> -p <%= @options[:agent].vsts_token %>

Просмотреть файл

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string><%= @agent.sv_name %></string>
<key>ProgramArguments</key>
<array>
<string>node</string>
<string><%= @agent.install_dir %>/agent/vsoagent.js</string>
<string>-u</string>
<string><%= @agent.vsts_user %> </string>
<string>-p</string>
<string><%= @agent.vsts_token %></string>
</array>
<key>UserName</key>
<string><%= @agent.user %></string>
<% if @session -%>
<key>LimitLoadToSessionType</key>
<string><%= @agent.sv_session %></string>
<% end -%>
<key>WorkingDirectory</key>
<string><%= @agent.install_dir %></string>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string><%= @agent.install_dir %>/service.log</string>
<key>StandardErrorPath</key>
<string><%= @agent.install_dir %>/service.err.log</string>
<% unless @agent.sv_envs.empty? -%>
<key>EnvironmentVariables</key>
<dict>
<% @agent.sv_envs.each do |key, val| -%>
<key><%= key %></key>
<string><%= val %></string>
<% end -%>
</dict>
<% end -%>
</dict>
</plist>

Просмотреть файл

@ -1,5 +0,0 @@
# set attributes through test kitchen
default['vsts_build_agent_test']['vsts_url'] = nil
default['vsts_build_agent_test']['vsts_pool'] = nil
default['vsts_build_agent_test']['vsts_user'] = nil
default['vsts_build_agent_test']['vsts_token'] = nil

Просмотреть файл

@ -1,5 +0,0 @@
name 'windows-basic'
version '0.0.1'
depends 'vsts_build_agent'
depends 'windows'

Просмотреть файл

@ -1,73 +0,0 @@
include_recipe 'vsts_build_agent::default'
agent_prefix = node['hostname']
sys_user = 'vagrant'
sys_passwd = 'vagrant'
# clean previous run
vsts_build_agent_windows "#{agent_prefix}_01" do
vsts_token node['vsts_build_agent_test']['vsts_token']
action :remove
end
vsts_build_agent_windows "#{agent_prefix}_02" do
vsts_token node['vsts_build_agent_test']['vsts_token']
action :remove
end
vsts_build_agent_windows "#{agent_prefix}_03" do
install_dir "c:\\agents\\#{agent_prefix}_03"
vsts_user node['vsts_build_agent_test']['vsts_user']
vsts_token node['vsts_build_agent_test']['vsts_token']
action :remove
end
# install agents
# agent with default service name
vsts_build_agent_windows "#{agent_prefix}_01" do
install_dir 'c:\\agents\\agent_01'
sv_user sys_user
sv_password sys_passwd
vsts_url node['vsts_build_agent_test']['vsts_url']
vsts_pool node['vsts_build_agent_test']['vsts_pool']
vsts_user node['vsts_build_agent_test']['vsts_user']
vsts_token node['vsts_build_agent_test']['vsts_token']
action :install
end
vsts_build_agent_windows "#{agent_prefix}_01" do
action :restart
end
# agent with overriden service name
# run as Local Service user
vsts_build_agent_windows "#{agent_prefix}_02" do
install_dir 'c:\\agents\\agent_02'
sv_user 'NT AUTHORITY\\LocalService'
sv_name 'agent_02.service'
vsts_url node['vsts_build_agent_test']['vsts_url']
vsts_pool node['vsts_build_agent_test']['vsts_pool']
vsts_user node['vsts_build_agent_test']['vsts_user']
vsts_token node['vsts_build_agent_test']['vsts_token']
action :install
end
vsts_build_agent_windows "#{agent_prefix}_02" do
action :restart
end
# agent to remove
vsts_build_agent_windows "#{agent_prefix}_03" do
install_dir 'c:\\agents\\agent_03'
sv_user 'NT AUTHORITY\\NetworkService'
vsts_url node['vsts_build_agent_test']['vsts_url']
vsts_pool node['vsts_build_agent_test']['vsts_pool']
vsts_user node['vsts_build_agent_test']['vsts_user']
vsts_token node['vsts_build_agent_test']['vsts_token']
action :install
end
vsts_build_agent_windows "#{agent_prefix}_03" do
vsts_token node['vsts_build_agent_test']['vsts_token']
action :remove
end

Просмотреть файл

@ -1,11 +1,4 @@
default['nodejs']['version'] = '4.2.3'
default['nodejs']['source']['checksum'] = nil
default['nodejs']['binary']['checksum']['linux_x64'] = nil
default['nodejs']['binary']['checksum']['linux_x86'] = nil
default['nodejs']['install_method'] = 'binary'
# set attributes through test kitchen
default['vsts_build_agent_test']['vsts_url'] = nil
default['vsts_build_agent_test']['vsts_pool'] = nil
default['vsts_build_agent_test']['vsts_user'] = nil
default['vsts_build_agent_test']['vsts_token'] = nil

Просмотреть файл

@ -0,0 +1,79 @@
# Desc: Grants log on as service rights on the computer. This script needs to run in elevated mode (admin)
# created by: Sachin Patil
# more info and tips: http://technet.microsoft.com/en-us/library/ff730940.aspx
Param (
[string]$userDomain="",
[string]$userAlias="myUser"
)
if ( $userDomain -eq "." )
{
$userDomain = ""
}
Write-host "Domain: $userDomain"
Write-host "User: $userAlias"
$scriptPath = (Get-Location).Path
$infFile = Join-Path $scriptPath "GrantLogOnAsService.inf"
$logFile = Join-Path $scriptPath "OutputLog.txt"
if(Test-Path $infFile)
{
Remove-Item -Path $infFile -Force
}
$objUser = New-Object System.Security.Principal.NTAccount($userDomain, $userAlias)
Write-host "User obj: $objUser"
$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
$sid = $strSID.Value
#NT Service/ALL SERVICES
$objUser2 = New-Object System.Security.Principal.NTAccount("NT SERVICE", "ALL SERVICES")
$strSID2 = $objUser2.Translate([System.Security.Principal.SecurityIdentifier])
$sid2 = $strSID2.Value
Write-Host "User SID: $sid"
Write-Host "Creating template file $infFile"
Add-Content $infFile "[Unicode]"
Add-Content $infFile "Unicode=yes"
Add-Content $infFile "[Version]"
Add-Content $infFile "signature=`"`$CHICAGO$`""
Add-Content $infFile "Revision=1"
Add-Content $infFile "[Registry Values]"
Add-Content $infFile "[Profile Description]"
Add-Content $infFile "Description=This is security template to grant log on as service access"
Add-Content $infFile "[Privilege Rights]"
Add-Content $infFile "SeServiceLogonRight = *$sid,*$sid2" #add more users here if needed
$seceditFile = "c:\Windows\security\database\secedit.sdb"
#Make sure it exists
if((Test-Path $seceditFile) -eq $false)
{
Write-Error "Security database does not exist $seceditFile"
}
write-host "Validating new security template .inf file"
#validate if template is correct
secedit /validate $infFile
$exitcode = $LASTEXITCODE
if($exitcode -ne 0)
{
Write-Error "Error in validating template file, $infFile exit code $exitcode"
exit $exitcode
}
write-host "Appliying security template to default secedit.sdb"
secedit /configure /db secedit.sdb /cfg "$infFile" /log "$logFile"
$exitcode = $LASTEXITCODE
if($exitcode -ne 0)
{
Write-Error "Error in secedit call, exit code $exitcode"
exit $exitcode
}
get-content "$logFile"
write-host "Successfully granted log on as service access to user $userAlias" -ForegroundColor Green
gpupdate /force
exit 0

Просмотреть файл

@ -5,6 +5,3 @@ depends 'vsts_build_agent'
depends 'apt'
depends 'build-essential'
depends 'nodejs'
depends 'runit'
depends 'homebrew'

Просмотреть файл

@ -1,94 +1,85 @@
#### Begin prepare system ####
include_recipe 'apt::default' if platform_family?('debian')
include_recipe 'vsts_build_agent::default'
if platform_family?('windows')
cookbook_file "#{Chef::Config[:file_cache_path]}/Grant-LogOnAsService.ps1" do
source 'Grant-LogOnAsService.ps1'
action :create_if_missing
end
# grant ServiceLogon rights
batch "grant servicelogon rights to vagrant" do
cwd Chef::Config[:file_cache_path]
code <<-EOH
powershell -ExecutionPolicy Bypass ./Grant-LogOnAsService.ps1 -userAlias vagrant
if %ERRORLEVEL% == 0 echo "Service logon access to vagrant granted" > "#{Chef::Config[:file_cache_path]}\\logon.guard"
EOH
not_if {::File.exists?("#{Chef::Config[:file_cache_path]}\\logon.guard")}
end
end
include_recipe 'build-essential::default' unless platform_family?('windows')
#### End prepare system ####
include_recipe 'build-essential::default'
include_recipe 'vsts_build_agent::default'
agent1_name = "#{node['hostname']}_01"
agent2_name = "#{node['hostname']}_02"
if platform_family?('mac_os_x')
home_dir = '/Users/vagrant'
agents_dir = '/home/vagrant/agents'
agents_dir = '/Users/vagrant/agents' if platform_family?('mac_os_x')
agents_dir = 'C:\\Users\\vagrant\\agents' if platform_family?('windows')
bash 'Prepare dirs for the homebrew' do
code <<-EOH
mkdir -p /usr/local
chown -R vagrant:staff /usr/local
EOH
end
node.set['homebrew']['owner'] = 'vagrant'
include_recipe 'homebrew'
execute 'Install nodejs from brew' do
command 'brew install node'
user 'vagrant'
group 'staff'
action :run
end
else
home_dir = '/home/vagrant'
include_recipe 'nodejs::default'
include_recipe 'nodejs::npm'
execute 'Set npm global prefix' do
command 'npm config set prefix /usr/local'
end
end
# # cleanup
vsts_build_agent_xplat agent1_name do
# cleanup
vsts_build_agent agent1_name do
vsts_token node['vsts_build_agent_test']['vsts_token']
action :remove
end
vsts_build_agent_xplat agent2_name do
vsts_build_agent agent2_name do
vsts_token node['vsts_build_agent_test']['vsts_token']
action :remove
end
vsts_build_agent_xplat agent1_name do
install_dir "#{home_dir}/agents/agent_01"
# Agent1
vsts_build_agent agent1_name do
version '2.102.0'
install_dir "#{agents_dir}/#{agent1_name}"
user 'vagrant'
group 'vagrant'
sv_envs(
'PATH' => '/usr/local/bin/:/opt/local/bin:/sbin:/usr/sbin:/bin:/usr/bin',
'TEST' => 'agent1'
)
vsts_url node['vsts_build_agent_test']['vsts_url']
vsts_pool node['vsts_build_agent_test']['vsts_pool']
vsts_user node['vsts_build_agent_test']['vsts_user']
vsts_token node['vsts_build_agent_test']['vsts_token']
windowslogonaccount 'vagrant'
windowslogonpassword 'vagrant'
action :install
end
vsts_build_agent_xplat agent2_name do
install_dir "#{home_dir}/agents/agent_02"
user 'vagrant'
group 'vagrant'
user_home home_dir
sv_name 'agent2'
sv_envs(
'PATH' => '/usr/local/bin/:/opt/local/bin:/sbin:/usr/sbin:/bin:/usr/bin',
'TEST' => 'agent2'
)
vsts_url node['vsts_build_agent_test']['vsts_url']
vsts_pool node['vsts_build_agent_test']['vsts_pool']
vsts_user node['vsts_build_agent_test']['vsts_user']
vsts_token node['vsts_build_agent_test']['vsts_token']
action :install
notifies :restart, "vsts_build_agent_xplat[#{agent2_name}]", :delayed
end
vsts_build_agent_xplat "Restart '#{agent1_name}'" do
agent_name agent1_name
vsts_build_agent agent1_name do
action :restart
end
vsts_build_agent_xplat "Remove '#{agent1_name}'" do
agent_name agent1_name
vsts_build_agent agent1_name do
vsts_token node['vsts_build_agent_test']['vsts_token']
action :remove
end
# Agent2
vsts_build_agent agent2_name do
version '2.102.0'
install_dir "#{agents_dir}/#{agent2_name}"
user 'vagrant'
group 'vagrant'
vsts_url node['vsts_build_agent_test']['vsts_url']
vsts_pool node['vsts_build_agent_test']['vsts_pool']
vsts_token node['vsts_build_agent_test']['vsts_token']
windowslogonaccount 'NT AUTHORITY\\NetworkService'
action :install
end
vsts_build_agent agent2_name do
action :restart
end

Просмотреть файл

@ -1,20 +0,0 @@
require 'serverspec'
set :backend, :cmd
set :os, :family => 'windows'
describe file('c:\\agents\\agent_01\\Agent\\VsoAgent.exe') do
it { should be_file }
end
describe file('c:\\agents\\agent_02\\Agent\\VsoAgent.exe') do
it { should be_file }
end
describe file('c:\\agents\\agent_03\\Agent\\VsoAgent.exe') do
it { should_not be_file }
end
describe service('agent_02.service') do
it { should be_running }
end

Просмотреть файл

@ -8,14 +8,14 @@ home_dir = if os[:family] == 'darwin'
'/home/vagrant'
end
describe file("#{home_dir}/agents/agent_01/.agent") do
it { should_not exist }
end
# describe file("#{home_dir}/agents/agent_01/.agent") do
# it { should_not exist }
# end
describe file("#{home_dir}/agents/agent_02/.agent") do
it { should be_file }
end
# describe file("#{home_dir}/agents/agent_02/.agent") do
# it { should be_file }
# end
describe service('agent2'), :unless => os[:family] == 'darwin' do
it { should be_running }
end
# describe service('agent2'), :unless => os[:family] == 'darwin' do
# it { should be_running }
# end