Remove upgrade feature. Add env and path parameters. Bump agent version. Fix dependencies

This commit is contained in:
Dmitry Ivanov 2016-08-17 15:32:48 +02:00
Родитель 704e8bf20b
Коммит 4660fd5034
14 изменённых файлов: 309 добавлений и 216 удалений

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

@ -15,7 +15,7 @@ HashSyntax:
- '**/Berksfile'
Metrics/MethodLength:
Max: 20
Max: 30
Metrics/AbcSize:
Max: 20
Max: 30

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

@ -39,6 +39,8 @@ This resource installs and configures the vsts build and release agent
- `agent_name`: Name attribute. The name of the vsts agent
- `version`: an agent version to install. Default version from an attribute
- `install_dir`: A target directory to install the vsts agent
- `path`: Overwrite system PATH environment variable values. Linux and Mac OS X only
- `env`: Additional environment variables. Linux and Mac OS X only
- `user`: Set a local user to run the vsts agent
- `group`: Set a local group to run the vsts agent
- `runasservice`: run agent as a service. Default 'true'
@ -69,6 +71,8 @@ vsts_agent 'agent_01' do
install_dir dir
user 'vagrant'
group 'vagrant'
path '/usr/local/bin/:/usr/bin:/opt/bin/' # only works on nix systems
env('M2_HOME' => '/opt/maven', 'JAVA_HOME' => '/opt/java') # only works on nix systems
vsts_url 'https://contoso.visualstudio.com'
vsts_pool 'default'
vsts_token 'my_secret_token_from_vsts'

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

@ -1,4 +1,4 @@
default['vsts_agent']['binary']['version'] = '2.102.1'
default['vsts_agent']['binary']['version'] = '2.105.0'
case node['platform_family']
when 'windows'
@ -6,7 +6,12 @@ when 'windows'
when 'rhel'
default['vsts_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_agent']['binary']['url'] = 'https://github.com/Microsoft/vsts-agent/releases/download/v%s/vsts-agent-ubuntu.14.04-x64-%s.tar.gz'
default['vsts_agent']['binary']['url'] =
if platform?('ubuntu') && node['platform_version'].to_i >= 16
'https://github.com/Microsoft/vsts-agent/releases/download/v%s/vsts-agent-ubuntu.16.04-x64-%s.tar.gz'
else
'https://github.com/Microsoft/vsts-agent/releases/download/v%s/vsts-agent-ubuntu.14.04-x64-%s.tar.gz'
end
when 'mac_os_x', 'mac_os_x_server'
default['vsts_agent']['binary']['url'] = 'https://github.com/Microsoft/vsts-agent/releases/download/v%s/vsts-agent-osx.10.11-x64-%s.tar.gz'
end

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

@ -1,134 +1,118 @@
module VSTS
module Build
module Agent
# Helper methods for VSTS Build Agent installation
module Helpers
include Chef::DSL::PlatformIntrospection
module Agent
# Helper methods for VSTS Build Agent installation
module Helpers
include Chef::DSL::PlatformIntrospection
require 'json'
require 'json'
VARS_TO_SAVE = %w(install_dir version user group).freeze
VARS_TO_SAVE = %w(install_dir user group).freeze
def service_name(resource)
return nil unless resource.vsts_url
hostname = URI.parse(resource.vsts_url).host
hostname = hostname[0, hostname.index('.')] if hostname.include?('.')
if windows?
"vstsagent.#{hostname}.#{resource.agent_name}"
else
"vsts.agent.#{hostname}.#{resource.agent_name}"
end
def archive_name(resource)
name = 'vsts_agent'
name += '_' + resource.version if resource.version
name
end
def download_url(version, node)
url = node['vsts_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 osx?
platform_family?('mac_os_x') || platform_family?('mac_os_x_server')
end
def service_exist?(install_dir)
::File.exist?("#{install_dir}/.service")
end
def agent_exists?(install_dir)
::File.exist?("#{install_dir}/.agent")
end
def save_vars(resource, node)
VARS_TO_SAVE.each { |var| node.set['vsts_agent']['agents'][resource.agent_name][var] = resource.send(var) if resource.respond_to?(var.to_sym) }
node.save
end
def load_vars(resource, node)
VARS_TO_SAVE.each { |var| resource.send(var, node['vsts_agent']['agents'][resource.agent_name][var]) if resource.respond_to?(var.to_sym) }
end
def load_current_state(resource, node)
resource.exists = false
return unless agent_attribute?(resource.agent_name, node)
load_vars(resource, node)
return unless agent_exists?(resource.install_dir)
load_data_from_json(resource)
resource.runasservice(service_exist?(resource.install_dir))
resource.exists = true
end
def load_data_from_json(resource)
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'])
end
def agent_attribute?(agent_name, node)
if node['vsts_agent']['agents'].nil? ||
node['vsts_agent']['agents'][agent_name].nil? ||
node['vsts_agent']['agents'][agent_name]['install_dir'].nil? ||
node['vsts_agent']['agents'][agent_name]['install_dir'].empty?
return false
else
return true
end
end
def service_config(resource)
service_name = service_name(resource)
if osx?
"/Users/#{resource.user}/Library/LaunchAgents/#{service_name}.plist"
else
"/etc/systemd/system/#{service_name}.service"
end
end
def remove_current_state(resource, node)
node.set['vsts_agent']['agents'][resource.agent_name] = {}
node.save
end
def archive_name(resource)
name = 'vsts_agent'
name += '_' + resource.version if resource.version
name
def set_auth(args, resource)
args['auth'] = resource.vsts_auth
if resource.vsts_auth == 'PAT'
args['token'] = resource.vsts_token
elsif (resource.vsts_auth == 'Negotiate') || (resource.vsts_auth == 'ALT')
args['--username'] = resource.vsts_username
args['--password'] = resource.vsts_password
end
end
def download_url(version, node)
url = node['vsts_agent']['binary']['url']
url = url.gsub '%s', version
url
end
def vsagentexec(args = {})
command = 'Agent.Listener '
command = './' + command unless windows?
args.each { |key, value| command += append_arguments(key, value) + ' ' }
command
end
def windows?
platform_family?('windows')
end
def debian?
platform_family?('debian')
end
def rhel?
platform_family?('rhel')
end
def osx?
platform_family?('mac_os_x') || platform_family?('mac_os_x_server')
end
def save_vars(resource, node)
VARS_TO_SAVE.each { |var| node.set['vsts_agent']['agents'][resource.agent_name][var] = resource.send(var) if resource.respond_to?(var.to_sym) }
node.save
end
def load_vars(resource, node)
VARS_TO_SAVE.each { |var| resource.send(var, node['vsts_agent']['agents'][resource.agent_name][var]) if resource.respond_to?(var.to_sym) }
end
def load_current_state(resource, node)
resource.exists = false
if agent_attribute?(resource.agent_name, node)
load_vars(resource, node)
if ::File.exist?(::File.join(resource.install_dir, '.agent'))
load_data_from_json(resource)
resource.runasservice(::File.exist?(::File.join(resource.install_dir, '.service')))
resource.exists = true
end
end
end
def load_data_from_json(resource)
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'])
end
def agent_attribute?(agent_name, node)
if node['vsts_agent']['agents'].nil? ||
node['vsts_agent']['agents'][agent_name].nil? ||
node['vsts_agent']['agents'][agent_name]['install_dir'].nil? ||
node['vsts_agent']['agents'][agent_name]['install_dir'].empty?
return false
else
return true
end
end
def remove_current_state(resource, node)
node.set['vsts_agent']['agents'][resource.agent_name] = {}
node.save
end
def set_auth(args, resource)
args['auth'] = resource.vsts_auth
if resource.vsts_auth == 'PAT'
args['token'] = resource.vsts_token
elsif (resource.vsts_auth == 'Negotiate') || (resource.vsts_auth == 'ALT')
args['--username'] = resource.vsts_username
args['--password'] = resource.vsts_password
end
end
def vsagentexec(args = {})
command = 'Agent.Listener '
command = './' + command unless windows?
args.each { |key, value| command += append_arguments(key, value) + ' ' }
command
end
def append_arguments(key, value)
result = ''
if key == 'configure' || key == 'remove'
result += key
else
result += "--#{key}"
result += " \"#{value}\"" unless value.nil?
end
result
def append_arguments(key, value)
result = ''
if key == 'configure' || key == 'remove'
result += key
else
result += "--#{key}"
result += " \"#{value}\"" unless value.nil?
end
result
end
end
end

110
libraries/service.rb Normal file
Просмотреть файл

@ -0,0 +1,110 @@
require 'chef/resource/lwrp_base'
require 'chef/provider/lwrp_base'
require 'chef/mixin/shell_out'
require 'chef/mixin/language'
class Chef
class Resource
# Internal Resource/Provider to manage agent service
class VstsAgentService < Chef::Resource::LWRPBase
provides :vsts_agent_service
resource_name :vsts_agent_service
actions :enable, :start, :stop, :restart, :disable
default_action :enable
attribute :name, :kind_of => String, :name_attribute => true
attribute :install_dir, :kind_of => String
attribute :user, :kind_of => String
attribute :group, :kind_of => String
end
end
end
class Chef
class Provider
# Internal Resource/Provider to manage agent service
class VstsAgentService < Chef::Provider::LWRPBase
include Chef::Mixin::ShellOut
include Windows::Helper
include VSTS::Agent::Helpers
use_inline_resources
action :enable do
unless service_exist?(new_resource.install_dir) && windows?
vsts_service 'install'
new_resource.updated_by_last_action(true)
end
end
action :start do
if service_exist?(new_resource.install_dir)
vsts_service 'start'
new_resource.updated_by_last_action(true)
end
end
action :stop do
if service_exist?(new_resource.install_dir)
vsts_service 'stop'
new_resource.updated_by_last_action(true)
end
end
action :restart do
if service_exist?(new_resource.install_dir)
vsts_service 'stop'
vsts_service 'start'
new_resource.updated_by_last_action(true)
end
end
action :disable do
if service_exist?(new_resource.install_dir)
vsts_service 'disable'
new_resource.updated_by_last_action(true)
end
end
def service_name
@service_name ||= ::File.read("#{new_resource.install_dir}/.service").strip
end
def vsts_service(operation)
if windows?
vsts_windows_service(operation)
else
vsts_unix_service(operation)
end
end
def vsts_windows_service(operation)
return if action == 'install'
service service_name do
action operation
retries 3
end
end
def vsts_unix_service(operation)
if operation == 'install'
operation = "#{operation} #{new_resource.user}"
elsif operation == 'disable'
operation = 'uninstall'
end
envvars = { 'HOME' => "/Users/#{new_resource.user}" }
execute "Run action '#{operation}' on service '#{new_resource.name}'" do
cwd new_resource.install_dir
command "./svc.sh #{operation}"
user new_resource.user if osx?
group new_resource.group if osx?
environment envvars if osx?
action :run
retries 3
end
end
end
end
end

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

@ -6,7 +6,7 @@ description 'Installs/Configures visualstudio team services build agents'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
source_url 'https://github.com/Microsoft/vsts-agent-cookbook' if respond_to?(:source_url)
issues_url 'https://github.com/Microsoft/vsts-agent-cookbook/issues' if respond_to?(:issues_url)
version '1.0.0'
version '1.1.0'
%w( ubuntu debian mac_os_x mac_os_x_server windows ).each do |os|
supports os

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

@ -1,7 +1,7 @@
require 'chef/mixin/shell_out'
require 'json'
include ::VSTS::Build::Agent::Helpers
include ::VSTS::Agent::Helpers
include ::Windows::Helper
use_inline_resources
@ -13,35 +13,33 @@ end
def load_current_resource
@current_resource = Chef::Resource::VstsAgent.new(@new_resource.name)
@current_resource.agent_name(@new_resource.agent_name)
@current_resource.vsts_token(@new_resource.vsts_token)
load_current_state(@current_resource, node)
@current_resource
end
action :install do
condidate_version = new_resource.version || node['vsts_agent']['binary']['version']
need_upgrade = current_resource.version != condidate_version
if @current_resource.exists && !need_upgrade
version = new_resource.version || node['vsts_agent']['binary']['version']
vsts_agent_service new_resource.agent_name do
install_dir new_resource.install_dir
user new_resource.user
group new_resource.group
action :nothing
end
service_id = "vsts_agent_service[#{new_resource.agent_name}]"
if @current_resource.exists
Chef::Log.info "'#{new_resource.agent_name}' agent '#{current_resource.version}' already exists - nothing to do"
else
converge_by("Installing agent '#{new_resource.agent_name}' version '#{condidate_version}'") do
version = condidate_version
converge_by("Installing agent '#{new_resource.agent_name}' version '#{version}'") do
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?
if current_resource.exists && need_upgrade
Chef::Log.info "'#{new_resource.agent_name}' agent will be upgradet to version '#{current_resource.version}'"
remove_agent(current_resource, new_resource)
end
config = service_config(new_resource)
execute "Remove service config file #{config}" do
command "rm -rf #{config}"
action :run
not_if { windows? }
end
remove_agent(new_resource)
directory unpack_dir do
recursive true
@ -117,8 +115,9 @@ action :install do
only_if { osx? }
end
manage_service("install #{new_resource.user}", new_resource) if new_resource.runasservice
manage_service('restart', new_resource) if new_resource.runasservice
log "Trigger service installation for agent #{new_resource.agent_name}" do
notifies :enable, service_id, :immediately
end
ruby_block "save state for agent '#{new_resource.agent_name}'" do
block do
@ -130,12 +129,35 @@ action :install do
new_resource.updated_by_last_action(true)
end
end
template "#{new_resource.install_dir}/.path" do
source 'path.erb'
variables(:path => new_resource.path)
user new_resource.user
group new_resource.group
mode '0755'
action :create
cookbook 'vsts_agent'
notifies :restart, service_id, :immediately
only_if { new_resource.path }
end
template "#{new_resource.install_dir}/.env" do
source 'env.erb'
variables(:env => new_resource.env)
user new_resource.user
group new_resource.group
mode '0755'
cookbook 'vsts_agent'
notifies :restart, service_id, :immediately
action :create
end
end
action :remove do
if @current_resource.exists
if @current_resource.exists # ~FC023
converge_by("Removing agent '#{current_resource.agent_name}'") do
remove_agent(current_resource, new_resource)
remove_agent(current_resource)
ruby_block "remove state for agent '#{current_resource.agent_name}'" do
block do
remove_current_state(current_resource, node)
@ -149,77 +171,50 @@ action :remove do
end
action :restart do
if @current_resource.exists
if @current_resource.exists # ~FC023
converge_by("Restarting agent '#{current_resource.agent_name}'") do
manage_service('restart', current_resource) if current_resource.runasservice
vsts_agent_service current_resource.agent_name do
install_dir current_resource.install_dir
user current_resource.user
group current_resource.group
action :restart
end
log "'#{current_resource.agent_name}' agent was restarted"
new_resource.updated_by_last_action(true)
end
end
end
def remove_agent(current_resource, new_resource)
manage_service('uninstall', current_resource) if current_resource.runasservice
# rubocop:disable all
def remove_agent(resource)
vsts_agent_service "Restart service #{resource.agent_name}" do
name resource.agent_name
install_dir resource.install_dir
user resource.user
group resource.group
action [:stop, :disable]
only_if { service_exist?(resource.install_dir) }
end
args = {
'remove' => nil,
'unattended' => nil
}
set_auth(args, new_resource)
set_auth(args, resource)
execute "Unconfiguring agent '#{current_resource.agent_name}'" do
cwd "#{current_resource.install_dir}/bin"
execute "Unconfiguring agent '#{resource.agent_name}'" do
cwd "#{resource.install_dir}/bin"
command vsagentexec(args)
sensitive true if respond_to?(:sensitive)
action :run
only_if { agent_exists?(resource.install_dir) }
end
directory current_resource.install_dir do
directory resource.install_dir do
recursive true
action :delete
end
end
def manage_service(operation, resource)
if windows?
manage_windows_service(operation, resource)
else
manage_unix_service(operation, resource)
end
end
def manage_windows_service(operation, resource)
if operation == 'restart' || operation == 'stop'
a = [operation.to_sym]
elsif operation == 'uninstall'
a = [:stop, :disable]
else
return # unsupported operations
end
sn = service_name(resource)
service sn do
action a
ignore_failure true
end
end
def manage_unix_service(operation, resource)
cmd = if operation == 'restart'
'./svc.sh stop && ./svc.sh start'
elsif operation == 'uninstall'
'./svc.sh stop && ./svc.sh uninstall'
else
"./svc.sh #{operation}"
end
envvars = { 'HOME' => "/Users/#{resource.user}" }
execute "Run action '#{operation}' on service for '#{resource.agent_name}'" do
cwd resource.install_dir
command cmd
user resource.user if osx?
group resource.group if osx?
environment envvars if osx?
action :run
ignore_failure true
end
end
# rubocop:enable all

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

@ -3,19 +3,10 @@ include_recipe 'ark::default'
if platform_family?('debian') && node['vsts_agent']['prerequisites']['debian']['install']
package 'libunwind8'
package 'libcurl3'
if platform?('ubuntu') && node['platform_version'].to_i >= 16
remote_file "#{Chef::Config[:file_cache_path]}/libicu52_52.1-8ubuntu0.2_amd64.deb" do
source node['vsts_agent']['prerequisites']['debian']['libicu52']['url']
mode 0644
end
dpkg_package 'libicu52' do
source "#{Chef::Config[:file_cache_path]}/libicu52_52.1-8ubuntu0.2_amd64.deb"
version '52.1-8ubuntu0.2'
action :install
end
else
unless platform?('ubuntu') && node['platform_version'].to_i >= 16
package 'libicu52'
end
elsif (platform_family?('mac_os_x') || platform_family?('mac_os_x_server')) && node['vsts_agent']['prerequisites']['osx']['install']
cpu = node['cpu'] ? node['cpu']['total'].to_i : 2
version = node['vsts_agent']['prerequisites']['osx']['openssl']['version']

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

@ -15,6 +15,8 @@ attribute :windowslogonpassword, :kind_of => String
# environment
attribute :version, :kind_of => String
attribute :path, :kind_of => String
attribute :env, :kind_of => Hash, :default => {}
# VSTS Access
attribute :vsts_url, :kind_of => String

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

@ -0,0 +1,3 @@
<% @env.each do |key, value| -%>
<%= key %>=<%= value %>
<% end -%>

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

@ -0,0 +1 @@
<%= @path %>

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

@ -37,7 +37,7 @@ vsts_agent agent2_name do
action :remove
end
# Agent1
# # Agent1
vsts_agent agent1_name do
install_dir "#{agents_dir}/#{agent1_name}"
user 'vagrant'
@ -59,10 +59,11 @@ end
# Agent2
vsts_agent agent2_name do
version '2.102.1'
install_dir "#{agents_dir}/#{agent2_name}"
user 'builder'
group 'builder'
path '/usr/local/bin/:/usr/bin:/opt/bin/'
env('M2_HOME' => '/opt/maven', 'JAVA_HOME' => '/opt/java')
vsts_url node['vsts_agent_test']['vsts_url']
vsts_pool node['vsts_agent_test']['vsts_pool']
vsts_token node['vsts_agent_test']['vsts_token']

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

@ -17,7 +17,6 @@ end
# Agent1
vsts_agent agent1_name do
version '2.102.0'
install_dir "#{agents_dir}/#{agent1_name}"
user 'vagrant'
group 'staff'
@ -38,10 +37,11 @@ end
# Agent2
vsts_agent agent2_name do
version '2.102.1'
install_dir "#{agents_dir}/#{agent2_name}"
user 'vagrant'
group 'staff'
path '/usr/local/bin/:/usr/bin:/opt/bin/'
env('M2_HOME' => '/opt/maven', 'JAVA_HOME' => '/opt/java')
vsts_url node['vsts_agent_test']['vsts_url']
vsts_pool node['vsts_agent_test']['vsts_pool']
vsts_token node['vsts_agent_test']['vsts_token']

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

@ -37,7 +37,6 @@ end
# Agent1
vsts_agent agent1_name do
version '2.102.0'
install_dir "#{agents_dir}/#{agent1_name}"
user 'vagrant'
vsts_url node['vsts_agent_test']['vsts_url']
@ -59,7 +58,6 @@ end
# Agent2
vsts_agent agent2_name do
version '2.102.0'
install_dir "#{agents_dir}/#{agent2_name}"
user 'builder'
vsts_url node['vsts_agent_test']['vsts_url']
@ -75,7 +73,6 @@ end
# Agent3
vsts_agent agent3_name do
version '2.102.1'
install_dir "#{agents_dir}/#{agent3_name}"
user 'builder'
vsts_url node['vsts_agent_test']['vsts_url']