commit 5578cada684fdab36c0b3c1e6e2acdde10f96947 Author: Greg Karékinian Date: Fri Aug 10 16:35:14 2018 +0200 Initial commit diff --git a/.delivery/project.toml b/.delivery/project.toml new file mode 100644 index 0000000..6d5e361 --- /dev/null +++ b/.delivery/project.toml @@ -0,0 +1 @@ +remote_file = "https://raw.githubusercontent.com/chef-cookbooks/community_cookbook_tools/master/delivery/project.toml" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c15fe86 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.kitchen/ diff --git a/.kitchen.dokken.yml b/.kitchen.dokken.yml new file mode 100644 index 0000000..856fa9a --- /dev/null +++ b/.kitchen.dokken.yml @@ -0,0 +1,40 @@ +--- +driver: + name: dokken + privileged: true # because Docker and SystemD/Upstart + chef_version: <%= ENV['CHEF_VERSION'] || 'current' %> + +transport: + name: dokken + +provisioner: + name: dokken + deprecations_as_errors: true + +verifier: + name: inspec + +platforms: + - name: ubuntu-16.04 + driver: + image: dokken/ubuntu-16.04 + pid_one_command: /bin/systemd + - name: ubuntu-18.04 + driver: + image: dokken/ubuntu-18.04 + pid_one_command: /bin/systemd + - name: debian-9 + driver: + image: dokken/debian-9 + pid_one_command: /bin/systemd + +suites: + - name: default + run_list: + - recipe[ipfs::default] + attributes: + - name: cluster + run_list: + - recipe[ipfs::cluster] + - recipe[ipfs::cluster_service] + attributes: diff --git a/.kitchen.yml b/.kitchen.yml new file mode 100644 index 0000000..5c9425c --- /dev/null +++ b/.kitchen.yml @@ -0,0 +1,22 @@ +--- +driver: + name: vagrant + +provisioner: + name: chef_zero + +platforms: + - name: ubuntu-16.04 + - name: ubuntu-18.04 + - name: debian-9 + +suites: + - name: default + run_list: + - recipe[ipfs::default] + attributes: + - name: cluster + run_list: + - recipe[ipfs::cluster] + - recipe[ipfs::cluster_service] + attributes: diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c323b91 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,39 @@ +sudo: required +dist: trusty + +addons: + apt: + sources: + - chef-current-trusty + packages: + - chefdk + +# Don't `bundle install` which takes about 1.5 mins +install: echo "skip bundle install" + +branches: + only: + - master + +services: docker + +env: + matrix: + - INSTANCE=default-debian-9 + - INSTANCE=default-ubuntu-1604 + - INSTANCE=default-ubuntu-1804 + +before_script: + - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER ) + - eval "$(chef shell-init bash)" + - chef --version + - cookstyle --version + - foodcritic --version + +script: KITCHEN_LOCAL_YAML=.kitchen.dokken.yml CHEF_VERSION=13.10.4 kitchen verify ${INSTANCE} + +matrix: + include: + - script: + - chef exec delivery local all + env: UNIT_AND_LINT=1 diff --git a/Berksfile b/Berksfile new file mode 100644 index 0000000..44bc4fc --- /dev/null +++ b/Berksfile @@ -0,0 +1,3 @@ +source 'https://api.berkshelf.com' + +metadata diff --git a/Berksfile.lock b/Berksfile.lock new file mode 100644 index 0000000..6bea0a7 --- /dev/null +++ b/Berksfile.lock @@ -0,0 +1,19 @@ +DEPENDENCIES + ipfs + path: . + metadata: true + +GRAPH + ark (4.0.0) + build-essential (>= 0.0.0) + seven_zip (>= 0.0.0) + build-essential (8.1.1) + mingw (>= 1.1) + seven_zip (>= 0.0.0) + ipfs (0.1.0) + ark (>= 0.0.0) + mingw (2.1.0) + seven_zip (>= 0.0.0) + seven_zip (3.0.0) + windows (>= 0.0.0) + windows (5.0.0) diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1523cdc --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# ipfs CHANGELOG + +## 0.1.0 +- [gregkare] - Initial release of ipfs diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..41c8973 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Kosmos + + 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9c48257 --- /dev/null +++ b/README.md @@ -0,0 +1,83 @@ +# ipfs Cookbook + +This cookbook installs ipfs and starts it as a daemon + +## Requirements + +### Platforms + +This cookbook is tested on Ubuntu 16.06, 14.04 and Debian 8 using Test Kitchen. +It currently only supports 64bit platforms + +### Chef + +- Chef 12.5 or later (we are providing a + [https://docs.chef.io/custom_resources.html](Custom Resource) to configure + IPFS + +### Cookbook dependencies + +- `ark` to download and uncompress the Go IPFS package + +## Usage + +### ipfs::default + +Just include `ipfs` in your node's `run_list`: + +```json +{ + "name":"my_node", + "run_list": [ + "recipe[ipfs]" + ] +} +``` + +## Attributes + +- `node.['ipfs']['version']` - the Go IPFS version to download from the official +site (64bit) +- `node['ipfs']['checksum']` - the SHA256 checksum for the package +- `node['ipfs']['config']['swarm']['addr_filter']` - the network ranges to not +connect to. This will stop platforms like Hetzner to block your server +(https://github.com/ipfs/go-ipfs/issues/1226) + +## Resources + +`ipfs_config` sets the config. Supports hashes, arrays, booleans and strings. +Does not change anything if the config already has that value, and restarts +the server automatically + +```ruby +ipfs_config "Gateway.Writable" do + value "true" + end +``` + +## Running the specs and integrations tests + +Install the latest [Chef DK](https://downloads.chef.io/chefdk). + +``` +chef exec delivery local all # Run the linting check, syntax check and unit tests +kitchen verify # Run the integration tests for Ubuntu 16.04, 18.06 and Debian 9 +``` + +## License and Authors + +Authors: Kosmos + +``` +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. +``` diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..981af6b --- /dev/null +++ b/Rakefile @@ -0,0 +1,65 @@ +#!/usr/bin/env rake + +# Style tests. cookstyle (rubocop) and Foodcritic +namespace :style do + begin + require 'cookstyle' + require 'rubocop/rake_task' + + desc 'Run Ruby style checks' + RuboCop::RakeTask.new(:ruby) + rescue LoadError => e + puts ">>> Gem load error: #{e}, omitting #{task.name}" unless ENV['CI'] + end + + begin + require 'foodcritic' + + desc 'Run Chef style checks' + FoodCritic::Rake::LintTask.new(:chef) do |t| + t.options = { + fail_tags: ['any'], + progress: true, + } + end + rescue LoadError + puts ">>> Gem load error: #{e}, omitting #{task.name}" unless ENV['CI'] + end +end + +desc 'Run all style checks' +task style: ['style:chef', 'style:ruby'] + +# ChefSpec +begin + desc 'Run ChefSpec examples' + require 'rspec/core/rake_task' + RSpec::Core::RakeTask.new(:spec) +rescue LoadError => e + puts ">>> Gem load error: #{e}, omitting #{task.name}" unless ENV['CI'] +end + +# Integration tests. Kitchen.ci +namespace :integration do + begin + require 'kitchen/rake_tasks' + + desc 'Run kitchen integration tests' + Kitchen::RakeTasks.new + rescue StandardError => e + puts ">>> Gem load error: #{e}, omitting #{task.name}" unless ENV['CI'] + end +end + +namespace :supermarket do + begin + desc 'Publish cookbook to Supermarket with Stove' + require 'stove/rake_task' + Stove::RakeTask.new + rescue LoadError => e + puts ">>> Gem load error: #{e}, omitting #{task.name}" unless ENV['CI'] + end +end + +# Default +task default: %w(style spec) diff --git a/attributes/default.rb b/attributes/default.rb new file mode 100644 index 0000000..f6e82fb --- /dev/null +++ b/attributes/default.rb @@ -0,0 +1,7 @@ +node.default['ipfs']['version'] = '0.4.9' +node.default['ipfs']['checksum'] = 'ae50c760f58548adc7c6dade4cf549059b6bc73ebc25ff4ea9fece06a15ac0a6' +# Do not contact local network addresses. This will stop platforms like Hetzner +# to block your server (https://github.com/ipfs/go-ipfs/issues/1226) +node.default['ipfs']['config']['swarm']['addr_filter'] = ['/ip4/10.0.0.0/ipcidr/8', '/ip4/100.64.0.0/ipcidr/10', '/ip4/169.254.0.0/ipcidr/16', '/ip4/172.16.0.0/ipcidr/12', '/ip4/192.0.0.0/ipcidr/24', '/ip4/192.0.0.0/ipcidr/29', '/ip4/192.0.0.8/ipcidr/32', '/ip4/192.0.0.170/ipcidr/32', '/ip4/192.0.0.171/ipcidr/32', '/ip4/192.0.2.0/ipcidr/24', '/ip4/192.168.0.0/ipcidr/16', '/ip4/198.18.0.0/ipcidr/15', '/ip4/198.51.100.0/ipcidr/24', '/ip4/203.0.113.0/ipcidr/24', '/ip4/240.0.0.0/ipcidr/4'] + +node.default['ipfs']['cluster']['version'] = '0.4.0' diff --git a/chefignore b/chefignore new file mode 100644 index 0000000..7be3c6d --- /dev/null +++ b/chefignore @@ -0,0 +1 @@ +.kitchen diff --git a/metadata.rb b/metadata.rb new file mode 100644 index 0000000..f70099a --- /dev/null +++ b/metadata.rb @@ -0,0 +1,15 @@ +name 'ipfs' +maintainer 'Kosmos' +maintainer_email 'mail@kosmos.org' +license 'Apache-2.0' +description 'Installs/Configures ipfs' +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version '0.1.0' + +supports %w(ubuntu debian) + +depends 'ark' + +source_url 'https://github.com/67P/ipfs-cookbook' +issues_url 'https://github.com/67P/ipfs-cookbook/issues' +chef_version '>= 12.14' if respond_to?(:chef_version) diff --git a/recipes/_user.rb b/recipes/_user.rb new file mode 100644 index 0000000..d4da731 --- /dev/null +++ b/recipes/_user.rb @@ -0,0 +1,30 @@ +# +# Cookbook Name:: ipfs +# Recipe:: _user +# +# Copyright 2018, Kosmos +# +# 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. +# + +group 'ipfs' do + gid 4737 +end + +user 'ipfs' do + comment 'ipfs' + uid 4737 + gid 4737 + home '/home/ipfs' + manage_home true +end diff --git a/recipes/cluster.rb b/recipes/cluster.rb new file mode 100644 index 0000000..fde4cae --- /dev/null +++ b/recipes/cluster.rb @@ -0,0 +1,41 @@ +# +# Cookbook Name:: ipfs +# Recipe:: cluster +# +# Copyright 2018, Kosmos +# +# 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. +# + +include_recipe 'ipfs::_user' + +version = node['ipfs']['cluster']['version'] + +ark 'ipfs-cluster-service' do + url "https://dist.ipfs.io/ipfs-cluster-service/v#{version}/ipfs-cluster-service_v#{version}_linux-amd64.tar.gz" + has_binaries ['ipfs-cluster-service'] +end + +ark 'ipfs-cluster-ctl' do + url "https://dist.ipfs.io/ipfs-cluster-ctl/v#{version}/ipfs-cluster-ctl_v#{version}_linux-amd64.tar.gz" + has_binaries ['ipfs-cluster-ctl'] +end + +credentials = data_bag_item('credentials', 'ipfs_cluster') + +execute 'ipfs-cluster-service init' do + user 'ipfs' + environment 'CLUSTER_SECRET' => credentials['secret'], + 'IPFS_CLUSTER_PATH' => '/home/ipfs/.ipfs-cluster' + not_if { File.exist? '/home/ipfs/.ipfs-cluster/service.json' } +end diff --git a/recipes/cluster_bootstrap.rb b/recipes/cluster_bootstrap.rb new file mode 100644 index 0000000..1d784a0 --- /dev/null +++ b/recipes/cluster_bootstrap.rb @@ -0,0 +1,26 @@ +# +# Cookbook Name:: ipfs +# Recipe:: cluster_bootstrap +# +# Copyright 2018, Kosmos +# +# 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. +# + +include_recipe 'ipfs::_user' + +execute "ipfs-cluster-service daemon --bootstrap #{peer}" do + user 'ipfs' + environment 'IPFS_CLUSTER_PATH' => '/home/ipfs/.ipfs-cluster' + not_if { File.exist? '/home/ipfs/.ipfs-cluster/service.json' } +end diff --git a/recipes/cluster_service.rb b/recipes/cluster_service.rb new file mode 100644 index 0000000..c2a73f0 --- /dev/null +++ b/recipes/cluster_service.rb @@ -0,0 +1,57 @@ +# +# Cookbook Name:: ipfs +# Recipe:: cluster_service +# +# Copyright 2018, Kosmos +# +# 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. +# + +if platform?('ubuntu') && node['platform_version'].to_f < 15.04 || + platform?('debian') && node['platform_version'].to_f < 8 + template 'ipfs.initd-cluster.service.erb' do + path '/etc/init.d/ipfs-cluster' + source 'ipfs-cluster.initd.service.erb' + owner 'root' + group 'root' + mode '0750' + notifies :restart, 'service[ipfs-cluster]', :delayed + end + + service 'ipfs-cluster' do + provider Chef::Provider::Service::Init::Debian + action [:enable] + supports start: true, stop: true, restart: true, reload: false, status: true + end + +else + execute 'systemctl daemon-reload' do + command 'systemctl daemon-reload' + action :nothing + end + + template 'ipfs-cluster.systemd.service.erb' do + path '/lib/systemd/system/ipfs-cluster.service' + source 'ipfs-cluster.systemd.service.erb' + owner 'root' + group 'root' + mode '0644' + notifies :run, 'execute[systemctl daemon-reload]', :delayed + notifies :restart, 'service[ipfs-cluster]', :delayed + end + + service 'ipfs-cluster' do + provider Chef::Provider::Service::Systemd + action [:enable] + end +end diff --git a/recipes/default.rb b/recipes/default.rb new file mode 100644 index 0000000..97be32b --- /dev/null +++ b/recipes/default.rb @@ -0,0 +1,78 @@ +# +# Cookbook Name:: ipfs +# Recipe:: default +# +# Copyright 2017-2018, Kosmos +# +# 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. +# + +include_recipe 'ipfs::_user' + +version = node['ipfs']['version'] + +ark 'ipfs' do + url "https://dist.ipfs.io/go-ipfs/v#{version}/go-ipfs_v#{version}_linux-amd64.tar.gz" + checksum node['ipfs']['checksum'] + has_binaries ['ipfs'] +end + +execute 'ipfs init --empty-repo' do + environment 'IPFS_PATH' => '/home/ipfs/.ipfs' + user 'ipfs' + not_if { File.directory? '/home/ipfs/.ipfs' } +end + +if platform?('ubuntu') && node['platform_version'].to_f < 15.04 || + platform?('debian') && node['platform_version'].to_f < 8 + template 'ipfs.initd.service.erb' do + path '/etc/init.d/ipfs' + source 'ipfs.initd.service.erb' + owner 'root' + group 'root' + mode '0750' + notifies :restart, 'service[ipfs]', :delayed + end + + service 'ipfs' do + provider Chef::Provider::Service::Init::Debian + action [:enable] + supports start: true, stop: true, restart: true, reload: false, status: true + end + +else + execute 'systemctl daemon-reload' do + command 'systemctl daemon-reload' + action :nothing + end + + template 'ipfs.systemd.service.erb' do + path '/lib/systemd/system/ipfs.service' + source 'ipfs.systemd.service.erb' + owner 'root' + group 'root' + mode '0644' + notifies :run, 'execute[systemctl daemon-reload]', :delayed + notifies :restart, 'service[ipfs]', :delayed + end + + service 'ipfs' do + provider Chef::Provider::Service::Systemd + action [:enable] + end +end + +# Configure ipfs to not contact local network addresses +ipfs_config 'Swarm.AddrFilters' do + value node['ipfs']['config']['swarm']['addr_filter'] +end diff --git a/resources/config.rb b/resources/config.rb new file mode 100644 index 0000000..67d4756 --- /dev/null +++ b/resources/config.rb @@ -0,0 +1,26 @@ +require 'json' +require 'mixlib/shellout' + +property :key, String, name_property: true +property :value, [String, Hash, Array, TrueClass, FalseClass], required: true + +action :create do + include_recipe 'ipfs' + + execute "ipfs config --json #{new_resource.key} '#{JSON.generate(new_resource.value)}'" do + environment 'IPFS_PATH' => '/home/ipfs/.ipfs' + user 'ipfs' + not_if do + cmd = Mixlib::ShellOut.new('ipfs', 'config', new_resource.key, + user: 'ipfs', + env: { 'IPFS_PATH' => '/home/ipfs/.ipfs' }) + cmd.run_command + begin + JSON.parse(cmd.stdout) == JSON.parse(JSON.generate(new_resource.value)) + rescue JSON::ParserError + cmd.stdout.include?(new_resource.value.to_s) + end + end + notifies :restart, 'service[ipfs]', :delayed + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..052d78a --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true +require 'chefspec' +require 'chefspec/berkshelf' diff --git a/spec/unit/recipes/cluster_service_spec.rb b/spec/unit/recipes/cluster_service_spec.rb new file mode 100644 index 0000000..f4f7047 --- /dev/null +++ b/spec/unit/recipes/cluster_service_spec.rb @@ -0,0 +1,48 @@ +# +# Cookbook:: ipfs +# Spec:: default +# +# Copyright 2018, Kosmos +# +# 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 'spec_helper' + +describe 'ipfs::cluster_service' do + context 'When all attributes are default, on Ubuntu 16.04' do + let(:chef_run) do + # for a complete list of available platforms and versions see: + # https://github.com/customink/fauxhai/blob/master/PLATFORMS.md + runner = ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '16.04') + runner.converge(described_recipe) + end + + it 'enables the service' do + expect(chef_run).to enable_service('ipfs-cluster') + end + end + + context 'When all attributes are default, on Ubuntu 18.04' do + let(:chef_run) do + # for a complete list of available platforms and versions see: + # https://github.com/customink/fauxhai/blob/master/PLATFORMS.md + runner = ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '18.04') + runner.converge(described_recipe) + end + + it 'enables the service' do + expect(chef_run).to enable_service('ipfs-cluster') + end + end +end diff --git a/spec/unit/recipes/default_spec.rb b/spec/unit/recipes/default_spec.rb new file mode 100644 index 0000000..4c9264b --- /dev/null +++ b/spec/unit/recipes/default_spec.rb @@ -0,0 +1,48 @@ +# +# Cookbook:: ipfs +# Spec:: default +# +# Copyright 2018, Kosmos +# +# 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 'spec_helper' + +describe 'ipfs::default' do + context 'When all attributes are default, on Ubuntu 16.04' do + let(:chef_run) do + # for a complete list of available platforms and versions see: + # https://github.com/customink/fauxhai/blob/master/PLATFORMS.md + runner = ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '16.04') + runner.converge(described_recipe) + end + + it 'converges successfully' do + expect { chef_run }.to_not raise_error + end + end + + context 'When all attributes are default, on Ubuntu 18.04' do + let(:chef_run) do + # for a complete list of available platforms and versions see: + # https://github.com/customink/fauxhai/blob/master/PLATFORMS.md + runner = ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '18.04') + runner.converge(described_recipe) + end + + it 'converges successfully' do + expect { chef_run }.to_not raise_error + end + end +end diff --git a/templates/default/ipfs-cluster.initd.service.erb b/templates/default/ipfs-cluster.initd.service.erb new file mode 100644 index 0000000..1b8c2ff --- /dev/null +++ b/templates/default/ipfs-cluster.initd.service.erb @@ -0,0 +1,102 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: ipfs-cluster daemon +# Required-Start: $local_fs $remote_fs $network $syslog $named +# Required-Stop: $local_fs $remote_fs $network $syslog $named +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Starts the ipfs-cluster daemon +# Description: Starts the ipfs-cluster daemon using the start-stop-daemon +### END INIT INFO + +# Author: Dylan Powers = 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() { + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test >/dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \ + --background --chuid $IPFS_USER --no-close \ + --exec /usr/bin/env IPFS_PATH="$IPFS_PATH" $DAEMON 2>>$IPFS_PATH/daemon.log 1>/dev/null \ + -- $DAEMON_ARGS \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() { + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + + # Delete the pid + rm -f $PIDFILE + return "$RETVAL" +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + restart) + do_stop + do_start + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2 + exit 3 + ;; +esac diff --git a/templates/default/ipfs-cluster.systemd.service.erb b/templates/default/ipfs-cluster.systemd.service.erb new file mode 100644 index 0000000..08bf2f0 --- /dev/null +++ b/templates/default/ipfs-cluster.systemd.service.erb @@ -0,0 +1,11 @@ +[Unit] +Description=Start ipfs-cluster + +[Service] +ExecStart=/usr/local/bin/ipfs-cluster-service daemon +User=ipfs +Group=ipfs +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/templates/default/ipfs.initd.service.erb b/templates/default/ipfs.initd.service.erb new file mode 100644 index 0000000..38e5d74 --- /dev/null +++ b/templates/default/ipfs.initd.service.erb @@ -0,0 +1,102 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: ipfs daemon +# Required-Start: $local_fs $remote_fs $network $syslog $named +# Required-Stop: $local_fs $remote_fs $network $syslog $named +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Starts the ipfs daemon +# Description: Starts the ipfs daemon using the start-stop-daemon +### END INIT INFO + +# Author: Dylan Powers = 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() { + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test >/dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \ + --background --chuid $IPFS_USER --no-close \ + --exec /usr/bin/env IPFS_PATH="$IPFS_PATH" $DAEMON 2>>$IPFS_PATH/daemon.log 1>/dev/null \ + -- $DAEMON_ARGS \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() { + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + + # Delete the pid + rm -f $PIDFILE + return "$RETVAL" +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + restart) + do_stop + do_start + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2 + exit 3 + ;; +esac diff --git a/templates/default/ipfs.systemd.service.erb b/templates/default/ipfs.systemd.service.erb new file mode 100644 index 0000000..2217b29 --- /dev/null +++ b/templates/default/ipfs.systemd.service.erb @@ -0,0 +1,11 @@ +[Unit] +Description=Start ipfs + +[Service] +ExecStart=/usr/local/bin/ipfs daemon +User=ipfs +Group=ipfs +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/test/integration/cluster/serverspec/ipfs_cluster_spec.rb b/test/integration/cluster/serverspec/ipfs_cluster_spec.rb new file mode 100644 index 0000000..23ba688 --- /dev/null +++ b/test/integration/cluster/serverspec/ipfs_cluster_spec.rb @@ -0,0 +1,27 @@ +require 'serverspec' + +# Required by serverspec +set :backend, :exec + +describe 'ipfs-cluster-ctl' do + # It is in the PATH + describe command('which ipfs-cluster-ctl') do + its(:exit_status) { should eq 0 } + end +end + +describe 'ipfs-cluster-service' do + # It is in the PATH + describe command('which ipfs-cluster-service') do + its(:exit_status) { should eq 0 } + end + + it 'is listening on port 9096' do + expect(port(9096)).to be_listening + end + + it 'runs the ipfs-cluster-service' do + expect(service('ipfs-cluster')).to be_running + expect(service('ipfs-cluster')).to be_enabled + end +end diff --git a/test/integration/data_bags/.kitchen/logs/kitchen.log b/test/integration/data_bags/.kitchen/logs/kitchen.log new file mode 100644 index 0000000..3f6cf59 --- /dev/null +++ b/test/integration/data_bags/.kitchen/logs/kitchen.log @@ -0,0 +1,30 @@ +I, [2018-08-10T16:28:48.996619 #26331] INFO -- Kitchen: -----> Starting Kitchen (v1.15.0) +E, [2018-08-10T16:28:48.997042 #26331] ERROR -- Kitchen: ------Exception------- +E, [2018-08-10T16:28:48.997089 #26331] ERROR -- Kitchen: Class: Kitchen::UserError +E, [2018-08-10T16:28:48.997122 #26331] ERROR -- Kitchen: Message: Kitchen YAML file /Users/kare/code/kosmos/cookbooks/ipfs/test/integration/data_bags/.kitchen.yml does not exist. +E, [2018-08-10T16:28:48.997151 #26331] ERROR -- Kitchen: ---------------------- +E, [2018-08-10T16:28:48.997178 #26331] ERROR -- Kitchen: ------Backtrace------- +E, [2018-08-10T16:28:48.997205 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/loader/yaml.rb:71:in `read' +E, [2018-08-10T16:28:48.997239 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/config.rb:152:in `data' +E, [2018-08-10T16:28:48.997266 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/config.rb:131:in `suites' +E, [2018-08-10T16:28:48.997294 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/config.rb:182:in `filter_instances' +E, [2018-08-10T16:28:48.997321 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/config.rb:141:in `build_instances' +E, [2018-08-10T16:28:48.997347 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/config.rb:117:in `instances' +E, [2018-08-10T16:28:48.997374 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/command.rb:112:in `filtered_instances' +E, [2018-08-10T16:28:48.997402 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/command.rb:142:in `parse_subcommand' +E, [2018-08-10T16:28:48.997431 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/command/action.rb:35:in `block in call' +E, [2018-08-10T16:28:48.997459 #26331] ERROR -- Kitchen: /Users/kare/.rubies/ruby-2.4.2/lib/ruby/2.4.0/benchmark.rb:293:in `measure' +E, [2018-08-10T16:28:48.997515 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/command/action.rb:34:in `call' +E, [2018-08-10T16:28:48.997566 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/cli.rb:53:in `perform' +E, [2018-08-10T16:28:48.997600 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/cli.rb:187:in `block (2 levels) in ' +E, [2018-08-10T16:28:48.997631 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/thor-0.20.0/lib/thor/command.rb:27:in `run' +E, [2018-08-10T16:28:48.997666 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/thor-0.20.0/lib/thor/invocation.rb:126:in `invoke_command' +E, [2018-08-10T16:28:48.997696 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/cli.rb:334:in `invoke_task' +E, [2018-08-10T16:28:48.997726 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/thor-0.20.0/lib/thor.rb:387:in `dispatch' +E, [2018-08-10T16:28:48.997766 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/thor-0.20.0/lib/thor/base.rb:466:in `start' +E, [2018-08-10T16:28:48.997796 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/bin/kitchen:13:in `block in ' +E, [2018-08-10T16:28:48.997826 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/lib/kitchen/errors.rb:171:in `with_friendly_errors' +E, [2018-08-10T16:28:48.997855 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/gems/test-kitchen-1.15.0/bin/kitchen:13:in `' +E, [2018-08-10T16:28:48.997882 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/bin/kitchen:23:in `load' +E, [2018-08-10T16:28:48.997918 #26331] ERROR -- Kitchen: /Users/kare/.gem/ruby/2.4.2/bin/kitchen:23:in `
' +E, [2018-08-10T16:28:48.997949 #26331] ERROR -- Kitchen: ----End Backtrace----- diff --git a/test/integration/data_bags/credentials/ipfs_cluster.json b/test/integration/data_bags/credentials/ipfs_cluster.json new file mode 100644 index 0000000..d2458b2 --- /dev/null +++ b/test/integration/data_bags/credentials/ipfs_cluster.json @@ -0,0 +1,4 @@ +{ + "id": "ipfs_cluster", + "secret": "d9de2f31ca7e9989949010fed2e704f42b8e96fa1e8e60a0ad26611f0a01cf07" +} diff --git a/test/integration/default/serverspec/ipfs_spec.rb b/test/integration/default/serverspec/ipfs_spec.rb new file mode 100644 index 0000000..7db110d --- /dev/null +++ b/test/integration/default/serverspec/ipfs_spec.rb @@ -0,0 +1,24 @@ +require 'serverspec' + +# Required by serverspec +set :backend, :exec + +describe 'IPFS' do + # It is in the PATH + describe command('which ipfs') do + its(:exit_status) { should eq 0 } + end + + it 'is listening on port 4001' do + expect(port(4001)).to be_listening + end + + it 'is listening on port 8080 (gateway)' do + expect(port(8080)).to be_listening + end + + it 'has a running service of ipfs' do + expect(service('ipfs')).to be_running + expect(service('ipfs')).to be_enabled + end +end