Set up an instance of Mastodon for Kosmos

Refs #19

Use new application cookbook, update our cookbooks
This commit is contained in:
Greg Karékinian
2017-04-06 21:20:51 +02:00
parent a3f5c5f646
commit de11c0d691
345 changed files with 22591 additions and 3473 deletions

View File

@@ -0,0 +1,83 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/mixin/which'
require 'chef/provider/execute'
require 'chef/resource/execute'
require 'poise'
require 'poise_javascript/javascript_command_mixin'
module PoiseJavascript
module Resources
# (see JavascriptExecute::Resource)
# @since 1.0.0
module JavascriptExecute
# A `javascript_execute` resource to run Javascript scripts and commands.
#
# @provides javascript_execute
# @action run
# @example
# javascript_execute 'myapp.js' do
# user 'myuser'
# end
class Resource < Chef::Resource::Execute
include PoiseJavascript::JavascriptCommandMixin
provides(:javascript_execute)
actions(:run)
end
# The default provider for `javascript_execute`.
#
# @see Resource
# @provides javascript_execute
class Provider < Chef::Provider::Execute
include Chef::Mixin::Which
provides(:javascript_execute)
private
# Command to pass to shell_out.
#
# @return [String, Array<String>]
def command
if new_resource.command.is_a?(Array)
[new_resource.javascript] + new_resource.command
else
"#{new_resource.javascript} #{new_resource.command}"
end
end
# Environment variables to pass to shell_out.
#
# @return [Hash]
def environment
if new_resource.parent_javascript
environment = new_resource.parent_javascript.javascript_environment
if new_resource.environment
environment = environment.merge(new_resource.environment)
end
environment
else
new_resource.environment
end
end
end
end
end
end

View File

@@ -0,0 +1,85 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/resource'
require 'poise'
module PoiseJavascript
module Resources
# (see JavascriptRuntime::Resource)
# @since 1.0.0
module JavascriptRuntime
# A `javascript_runtime` resource to manage Javascript installations.
#
# @provides javascript_runtime
# @action install
# @action uninstall
# @example
# javascript_runtime '2.7'
class Resource < Chef::Resource
include Poise(inversion: true, container: true)
provides(:javascript_runtime)
actions(:install, :uninstall)
# @!attribute version
# Version of Javascript to install. This is generally a NodeJS version
# but because of io.js there are shenanigans.
# @return [String]
# @example Install any version
# javascript_runtime 'any' do
# version ''
# end
attribute(:version, kind_of: String, name_attribute: true)
# The path to the `node` binary for this Javascript installation. This is
# an output property.
#
# @return [String]
# @example
# execute "#{resources('javascript_runtime[nodejs]').javascript_binary} myapp.js"
def javascript_binary
provider_for_action(:javascript_binary).javascript_binary
end
# The environment variables for this Javascript installation. This is an
# output property.
#
# @return [Hash<String, String>]
# @example
# execute '/opt/myapp.js' do
# environment resources('javascript_runtime[nodejs]').javascript_environment
# end
def javascript_environment
provider_for_action(:javascript_environment).javascript_environment
end
# The path to the `npm` binary for this Javascript installation. This is
# an output property. Can raise an exception if NPM is not supported for
# this runtime.
#
# @return [String]
# @example
# execute "#{resources('javascript_runtime[nodejs]').npm_binary} install"
def npm_binary
provider_for_action(:npm_binary).npm_binary
end
end
# Providers can be found under lib/poise_javascript/javascript_providers/
end
end
end

View File

@@ -0,0 +1,226 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/provider'
require 'chef/resource'
require 'poise'
module PoiseJavascript
module Resources
# (see JavascriptRuntimeTest::Resource)
# @since 1.0.0
# @api private
module JavascriptRuntimeTest
# A `javascript_runtime_test` resource for integration testing of this
# cookbook. This is an internal API and can change at any time.
#
# @provides javascript_runtime_test
# @action run
class Resource < Chef::Resource
include Poise
provides(:javascript_runtime_test)
actions(:run)
attribute(:version, kind_of: String, name_attribute: true)
attribute(:runtime_provider, kind_of: Symbol)
attribute(:path, kind_of: String, default: lazy { default_path })
attribute(:test_yo, equal_to: [true, false], default: true)
def default_path
::File.join('', 'root', "javascript_test_#{name}")
end
end
# The default provider for `javascript_runtime_test`.
#
# @see Resource
# @provides javascript_runtime_test
class Provider < Chef::Provider
include Poise
provides(:javascript_runtime_test)
# The `run` action for the `javascript_runtime_test` resource.
#
# @return [void]
def action_run
notifying_block do
# Top level directory for this test.
directory new_resource.path
# Install and log the version.
javascript_runtime new_resource.name do
provider new_resource.runtime_provider if new_resource.runtime_provider
version new_resource.version
end
test_version
# Create a package and test npm_install.
pkg_path = ::File.join(new_resource.path, 'pkg')
directory pkg_path
file ::File.join(pkg_path, 'package.json') do
content <<-EOH
{
"name": "mypkg",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "4.13.3"
},
"devDependencies": {
"handlebars": "4.0.2"
}
}
EOH
end
npm_install pkg_path do
notifies :create, sentinel_file('npm_install_one'), :immediately
end
npm_install pkg_path+'2' do
path pkg_path
notifies :create, sentinel_file('npm_install_two'), :immediately
end
test_require('express', pkg_path)
test_require('handlebars', pkg_path)
# Test node_package.
test1_path = ::File.join(new_resource.path, 'test1')
directory test1_path
node_package 'express' do
path test1_path
notifies :create, sentinel_file('test1_express_one'), :immediately
end
node_package 'express two' do
package_name 'express'
path test1_path
notifies :create, sentinel_file('test1_express_two'), :immediately
end
node_package %w{gulp less} do
path test1_path
notifies :create, sentinel_file('test1_multi'), :immediately
end
node_package %w{express bower} do
path test1_path
notifies :create, sentinel_file('test1_multi_overlap'), :immediately
end
node_package 'bower' do
path test1_path
notifies :create, sentinel_file('test1_bower'), :immediately
end
node_package 'yo' do
path test1_path
version '1.4.5'
end if new_resource.test_yo
node_package 'forever' do
path test1_path
version '0.13.0'
end
test_require('express', test1_path, 'node_package_express')
test_require('gulp', test1_path)
test_require('less', test1_path)
test_require('bower', test1_path)
if new_resource.test_yo
test_require('yo', test1_path)
else
file ::File.join(new_resource.path, 'no_yo')
end
test_require('forever', test1_path)
# Check we don't get cross talk between paths.
test2_path = ::File.join(new_resource.path, 'test2')
directory test2_path
node_package 'express' do
path test2_path
notifies :create, sentinel_file('test2_express'), :immediately
end
# Test global installs.
node_package 'grunt-cli' do
notifies :create, sentinel_file('grunt_one'), :immediately
end
node_package 'grunt-cli two' do
package_name 'grunt-cli'
notifies :create, sentinel_file('grunt_two'), :immediately
end
test_require('grunt-cli', new_resource.path)
javascript_execute 'grunt-cli --version' do
command lazy {
# Check local/bin first and then just bin/.
grunt_path = ::File.expand_path('../../local/bin/grunt', javascript)
grunt_path = ::File.expand_path('../grunt', javascript) unless ::File.exist?(grunt_path)
"#{grunt_path} --version > #{::File.join(new_resource.path, 'grunt_version')}"
}
end
end
end
def sentinel_file(name)
file ::File.join(new_resource.path, "sentinel_#{name}") do
action :nothing
end
end
private
def test_version(javascript: new_resource.name)
# Only queue up this resource once, the ivar is just for tracking.
@javascript_version_test ||= file ::File.join(new_resource.path, 'javascript_version.js') do
user 'root'
group 'root'
mode '644'
content <<-EOH
var fs = require('fs');
fs.writeFileSync(process.argv[2], process.version);
EOH
end
javascript_execute "#{@javascript_version_test.path} #{::File.join(new_resource.path, 'version')}" do
javascript javascript if javascript
end
end
def test_require(name, cwd, path=name, javascript: new_resource.name)
javascript_require_test = file ::File.join(cwd, 'javascript_require.js') do
user 'root'
group 'root'
mode '644'
content <<-EOH
var fs = require('fs');
try {
var version = require(process.argv[2] + '/package.json').version;
fs.writeFileSync(process.argv[3], version);
} catch(e) {
}
EOH
end
javascript_execute "#{javascript_require_test.path} #{name} #{::File.join(new_resource.path, "require_#{path}")}" do
javascript javascript if javascript
cwd cwd
end
end
end
end
end
end

View File

@@ -0,0 +1,254 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/json_compat'
require 'chef/provider/package'
require 'chef/resource/package'
require 'poise'
require 'poise_javascript/error'
require 'poise_javascript/javascript_command_mixin'
module PoiseJavascript
module Resources
# (see NodePackage::Resource)
# @since 1.0.0
module NodePackage
# A `node_package` resource to manage Node.js packages using npm.
#
# @provides node_package
# @action install
# @action upgrade
# @action uninstall
# @example
# node_package 'express' do
# javascript '0.10'
# version '1.8.3'
# end
class Resource < Chef::Resource::Package
include PoiseJavascript::JavascriptCommandMixin
provides(:node_package)
# Manually create matchers because #actions is unreliable.
%i{install upgrade remove}.each do |action|
Poise::Helpers::ChefspecMatchers.create_matcher(:node_package, action)
end
# @!attribute group
# System group to install the package.
# @return [String, Integer, nil]
attribute(:group, kind_of: [String, Integer, NilClass])
# @!attribute path
# Path to install the package in to. If unset install using --global.
# @return [String, nil, false]
attribute(:path, kind_of: [String, NilClass, FalseClass])
# @!attribute unsafe_perm
# Enable --unsafe-perm.
# @return [Boolean, nil]
attribute(:unsafe_perm, equal_to: [true, false, nil], default: true)
# @!attribute user
# System user to install the package.
# @return [String, Integer, nil]
attribute(:user, kind_of: [String, Integer, NilClass])
def initialize(*args)
super
# For older Chef.
@resource_name = :node_package
# We don't have these actions.
@allowed_actions.delete(:purge)
@allowed_actions.delete(:reconfig)
end
# Upstream attribute we don't support. Sets are an error and gets always
# return nil.
#
# @api private
# @param arg [Object] Ignored
# @return [nil]
def response_file(arg=nil)
raise NoMethodError if arg
end
# (see #response_file)
def response_file_variables(arg=nil)
raise NoMethodError if arg && arg != {}
end
end
# The default provider for the `node_package` resource.
#
# @see Resource
class Provider < Chef::Provider::Package
include PoiseJavascript::JavascriptCommandMixin
provides(:node_package)
# Load current and candidate versions for all needed packages.
#
# @api private
# @return [Chef::Resource]
def load_current_resource
@current_resource = new_resource.class.new(new_resource.name, run_context)
current_resource.package_name(new_resource.package_name)
check_package_versions(current_resource)
current_resource
end
# Populate current and candidate versions for all needed packages.
#
# @api private
# @param resource [PoiseJavascript::Resources::NodePackage::Resource]
# Resource to load for.
# @return [void]
def check_package_versions(resource)
version_data = Hash.new {|hash, key| hash[key] = {current: nil, candidate: nil} }
# Get the version for everything currently installed.
list_args = npm_version?('>= 1.4.16') ? %w{--depth 0} : []
npm_shell_out!('list', list_args).fetch('dependencies', {}).each do |pkg_name, pkg_data|
version_data[pkg_name][:current] = pkg_data['version']
end
# If any requested packages are currently installed, run npm outdated
# to look for candidate versions. Older npm doesn't support --json
# here so you get slow behavior, sorry.
requested_packages = Set.new(Array(resource.package_name))
if npm_version?('>= 1.3.16') && version_data.any? {|pkg_name, _pkg_vers| requested_packages.include?(pkg_name) }
outdated = npm_shell_out!('outdated') || {}
version_data.each do |pkg_name, pkg_vers|
pkg_vers[:candidate] = if outdated.include?(pkg_name)
outdated[pkg_name]['wanted']
else
# If it was already installed and not listed in outdated, it
# must have been up to date already.
pkg_vers[:current]
end
end
end
# Check for candidates for anything else we didn't get from outdated.
requested_packages.each do |pkg_name|
version_data[pkg_name][:candidate] ||= npm_shell_out!('show', [pkg_name])['version']
end
# Populate the current resource and candidate versions. Youch this is
# a gross mix of data flow.
if(resource.package_name.is_a?(Array))
@candidate_version = []
versions = []
[resource.package_name].flatten.each do |name|
ver = version_data[name.downcase]
versions << ver[:current]
@candidate_version << ver[:candidate]
end
resource.version(versions)
else
ver = version_data[resource.package_name.downcase]
resource.version(ver[:current])
@candidate_version = ver[:candidate]
end
end
# Install package(s) using npm.
#
# @param name [String, Array<String>] Name(s) of package(s).
# @param version [String, Array<String>] Version(s) of package(s).
# @return [void]
def install_package(name, version)
args = []
# Set --unsafe-perm unless the property is nil.
unless new_resource.unsafe_perm.nil?
args << '--unsafe-perm'
args << new_resource.unsafe_perm.to_s
end
# Build up the actual package install args.
if new_resource.source
args << new_resource.source
else
Array(name).zip(Array(version)) do |pkg_name, pkg_ver|
args << "#{pkg_name}@#{pkg_ver}"
end
end
npm_shell_out!('install', args, parse_json: false)
end
# Upgrade and install are the same for NPM.
alias_method :upgrade_package, :install_package
# Uninstall package(s) using npm.
#
# @param name [String, Array<String>] Name(s) of package(s).
# @param version [String, Array<String>] Version(s) of package(s).
# @return [void]
def remove_package(name, version)
npm_shell_out!('uninstall', [name].flatten, parse_json: false)
end
private
# Run an npm command.
#
# @param subcmd [String] Subcommand to run.
# @param args [Array<String>] Command arguments.
# @param parse_json [Boolean] Parse the JSON on stdout.
# @return [Hash]
def npm_shell_out!(subcmd, args=[], parse_json: true)
cmd = [new_resource.npm_binary, subcmd, '--json']
# If path is nil, we are in global mode.
cmd << '--global' unless new_resource.path
# Add the rest.
cmd.concat(args)
# If we are in global mode, cwd will be nil so probably just fine. Add
# the directory for the node binary to $PATH for post-install stuffs.
new_path = [::File.dirname(new_resource.javascript), ENV['PATH'].to_s].join(::File::PATH_SEPARATOR)
out = javascript_shell_out!(cmd, cwd: new_resource.path, group: new_resource.group, user: new_resource.user, environment: {'PATH' => new_path})
if parse_json
# Parse the JSON.
if out.stdout.strip.empty?
{}
else
Chef::JSONCompat.parse(out.stdout)
end
else
out
end
end
# Find the version of the current npm binary.
#
# @return [Gem::Version]
def npm_version
@npm_version ||= begin
out = javascript_shell_out!([new_resource.npm_binary, 'version'])
# Older NPM doesn't support --json here we get to regex!
# The line we want looks like:
# npm: '2.12.1'
if out.stdout =~ /npm: '([^']+)'/
Gem::Version.new($1)
else
raise PoiseJavascript::Error.new("Unable to parse NPM version from #{out.stdout.inspect}")
end
end
end
# Check the NPM version against a requirement.
#
# @param req [String] Requirement string in Gem::Requirement format.
# @return [Boolean]
def npm_version?(req)
Gem::Requirement.new(req).satisfied_by?(npm_version)
end
end
end
end
end

View File

@@ -0,0 +1,98 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/provider'
require 'chef/resource'
require 'poise'
require 'poise_javascript/javascript_command_mixin'
module PoiseJavascript
module Resources
# (see NpmInstall::Resource)
# @since 1.0.0
module NpmInstall
# A `npm_install` resource to install NPM packages based on a package.json.
#
# @provides npm_install
# @action install
# @example
# npm_install '/opt/myapp'
class Resource < Chef::Resource
include PoiseJavascript::JavascriptCommandMixin
provides(:npm_install)
actions(:install)
# @!attribute path
# Directory to run `npm install` from.
# @return [String]
attribute(:path, kind_of: String, name_attribute: true)
# @!attribute group
# System group to install the packages.
# @return [String, Integer, nil]
attribute(:group, kind_of: [String, Integer, NilClass])
# @!attribute production
# Enable production install mode.
# @return [Boolean]
attribute(:production, equal_to: [true, false], default: true)
# @!attribute timeout
# Command execution timeout.
# @return [Integer]
attribute(:timeout, kind_of: Integer, default: 900)
# @!attribute unsafe_perm
# Enable --unsafe-perm.
# @return [Boolean, nil]
attribute(:unsafe_perm, equal_to: [true, false, nil], default: true)
# @!attribute user
# System user to install the packages.
# @return [String, Integer, nil]
attribute(:user, kind_of: [String, Integer, NilClass])
end
# The default provider for `npm_install`.
#
# @see Resource
# @provides npm_install
class Provider < Chef::Provider
include Poise
include PoiseJavascript::JavascriptCommandMixin
provides(:npm_install)
# The `install` action for the `npm_install` resource.
#
# @return [void]
def action_install
cmd = [new_resource.npm_binary, 'install']
cmd << '--production' if new_resource.production
# Set --unsafe-perm unless the property is nil.
unless new_resource.unsafe_perm.nil?
cmd << '--unsafe-perm'
cmd << new_resource.unsafe_perm.to_s
end
# Add the directory for the node binary to $PATH for post-install stuffs.
new_path = [::File.dirname(new_resource.javascript), ENV['PATH'].to_s].join(::File::PATH_SEPARATOR)
output = javascript_shell_out!(cmd, cwd: new_resource.path, user: new_resource.user, group: new_resource.group, environment: {'PATH' => new_path}, timeout: new_resource.timeout).stdout
unless output.strip.empty?
# Any output means it did something.
new_resource.updated_by_last_action(true)
end
end
end
end
end
end