diff --git a/.rubocop.yml b/.rubocop.yml index c0fd488..4bbf72e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,2 +1,4 @@ +Style/TrailingCommaInLiteral: + Enabled: false inherit_gem: voxpupuli-test: rubocop.yml diff --git a/README.md b/README.md index 46e6b88..aa1cdea 100644 --- a/README.md +++ b/README.md @@ -62,12 +62,59 @@ class { 'hyperglass::server': } ``` +An example showing devices populated. + +```puppet +class { 'hyperglass::server': + data => {...}, + commands => {...}, + devices => { + 'routers' => [ + { + 'name' => 'atl_router01', + 'address' => '10.0.0.2', + 'network' => { + 'name' => 'secondary', + 'display_name' => 'That Other Network', + }, + 'credential' => { + 'username' => 'user2', + 'password' => ' secret2', + }, + 'display_name' => 'Atlanta, GA', + 'port' => 22, + 'nos' => 'juniper', + 'vrfs' => [ + { + 'name' => 'default', + 'display_name' => 'Global', + 'ipv4' => { + 'source_address' => '192.0.2.2', + }, + }, + ], + }, + ], + }, +} +``` + Please take a look at the official [hyperglass documentation](https://hyperglass.io/docs/parameters). It explains the three different options very well. You can pass the hashes from the documentation 1:1 to the three parameters. +### Beginning with Hyperglass + +This module provides Vagrant definitions that can be used to get started +with Hyperglass. The following will produce VM's for a Hyperglass server +and an agent. + +```bash +vagrant up +``` + ## Tests This module has several unit tests and linters configured. You can execute them diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..3616801 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,53 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : +# +# Environment variables may be used to control the behavior of the Vagrant VM's +# defined in this file. This is intended as a special-purpose affordance and +# should not be necessary in normal situations. If there is a need to run +# multiple backend instances simultaneously, avoid the IP conflict by setting +# the ALTERNATE_IP environment variable: +# +# ALTERNATE_IP=192.168.52.9 vagrant up hyperglass-server +# +# NOTE: The agent VM instances assume the backend VM is accessible on the +# default IP address, therefore using an ALTERNATE_IP is not expected to behave +# well with agent instances. +if not Vagrant.has_plugin?('vagrant-vbguest') + abort <<-EOM + +vagrant plugin vagrant-vbguest >= 0.16.0 is required. +https://github.com/dotless-de/vagrant-vbguest +To install the plugin, please run, 'vagrant plugin install vagrant-vbguest'. + + EOM +end + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + + config.vm.synced_folder ".", "/vagrant", type: "virtualbox" + + config.vm.provider :virtualbox do |vb| + vb.customize ["modifyvm", :id, "--memory", "1024"] + end + + config.vm.define "hyperglass-server", primary: true, autostart: true do |c| + c.vm.box = "centos/7" + c.vm.hostname = 'hyperglass-server.example.com' + c.vm.network :private_network, ip: ENV['ALTERNATE_IP'] || '192.168.73.10' + c.vm.network :forwarded_port, guest: 8001, host: 8001, auto_correct: true + c.vm.provision :shell, :path => "vagrant/provision_basic_el.sh" + c.vm.provision :shell, :inline => "puppet apply /vagrant/vagrant/server.pp" + end + + config.vm.define "el7-agent", primary: true, autostart: true do |c| + c.vm.box = "centos/7" + c.vm.hostname = 'el7-agent.example.com' + c.vm.network :private_network, ip: ENV['ALTERNATE_IP'] || '192.168.73.20' + c.vm.network :forwarded_port, guest: 8080, host: 8080, auto_correct: true + c.vm.provision :shell, :path => "vagrant/provision_basic_el.sh" + c.vm.provision :shell, :inline => "puppet apply /vagrant/vagrant/agent.pp" + end +end diff --git a/data/beaker/true.yaml b/data/beaker/true.yaml new file mode 100644 index 0000000..7b8d4ae --- /dev/null +++ b/data/beaker/true.yaml @@ -0,0 +1,22 @@ +--- +hyperglass::server::data: + listen_address: 0.0.0.0 + +hyperglass::server::devices: + routers: + - name: atl_router01 + address: 10.0.0.2 + network: + name: secondary + display_name: That Other Network + credential: + username: user2 + password: " secret2" + display_name: Atlanta, GA + port: 22 + nos: juniper + vrfs: + - name: default + display_name: Global + ipv4: + source_address: 192.0.2.2 diff --git a/data/common.yaml b/data/common.yaml new file mode 100644 index 0000000..2fbf0ff --- /dev/null +++ b/data/common.yaml @@ -0,0 +1 @@ +--- {} diff --git a/hiera.yaml b/hiera.yaml new file mode 100644 index 0000000..9c63743 --- /dev/null +++ b/hiera.yaml @@ -0,0 +1,11 @@ +--- +version: 5 +defaults: + datadir: data + data_hash: yaml_data +hierarchy: + - name: "Acceptance testing with Beaker" + path: "beaker/%{facts.beaker}.yaml" + - name: "common" + path: "common.yaml" + diff --git a/manifests/agent.pp b/manifests/agent.pp index 61d87a6..5a46b42 100644 --- a/manifests/agent.pp +++ b/manifests/agent.pp @@ -1,16 +1,24 @@ # @summary installs the hyperglass linux agent # -# @param manage_python installs python3 -# @param manage_gcc installs gcc -# @param data generic hyperglass configuration hash. +# @param manage_python +# installs python3 +# @param manage_gcc +# installs gcc +# @param manage_user +# When true, the user 'hyperglass-agent' is managed. +# @param manage_group +# When true, the group 'hyperglass-agent' is managed. +# @param data +# generic hyperglass configuration hash. # # @see https://github.com/checktheroads/hyperglass-agent # -# @author Tim Meusel class hyperglass::agent ( Boolean $manage_python = true, - Boolean $manage_gcc = true, - Hash $data = { + Boolean $manage_gcc = true, + Boolean $manage_user = true, + Boolean $manage_group = true, + Hash $data = { 'debug' => true, 'listen_address' => '127.0.0.1', 'mode' => 'bird', @@ -20,11 +28,80 @@ }, }, ) { - require hyperglass::hyperglassdir - contain hyperglass::agent::install - contain hyperglass::agent::config - contain hyperglass::agent::service - Class['hyperglass::agent::install'] - -> Class['hyperglass::agent::config'] - ~> Class['hyperglass::agent::service'] + include hyperglass + + if $manage_python { + ensure_resource('class', 'python', { 'version' => '3', 'dev' => 'present' }) + } + + if $manage_gcc { + ensure_resource('package', 'gcc', { 'ensure' => 'installed' }) + } + + if $manage_user { + user { 'hyperglass-agent': + ensure => 'present', + managehome => true, + purge_ssh_keys => true, + system => true, + home => '/opt/hyperglass/hyperglass-agent', + } + } + + if $manage_group { + group { 'hyperglass-agent': + ensure => 'present', + system => true, + } + } + + file { '/opt/hyperglass/hyperglass-agent': + ensure => 'directory', + owner => 'hyperglass-agent', + group => 'hyperglass-agent', + mode => '0700', + notify => Systemd::Unit_file['hyperglass-agent.service'], + } + + # we need to explicitly set the version here. During the first puppet run, python3 will be installed but isn't present yet + # due to that the fact is undef and fails. the default of the `version` attribute is the fact. We workaround this by hardcoding + # the python version + python::pyvenv { '/opt/hyperglass/hyperglass-agent/virtualenv': + ensure => 'present', + owner => 'hyperglass-agent', + group => 'hyperglass-agent', + systempkgs => false, + version => pick($facts['python3_version'], '3.6'), + notify => Systemd::Unit_file['hyperglass-agent.service'], + } + + python::pip { 'hyperglass-agent': + virtualenv => '/opt/hyperglass/hyperglass-agent/virtualenv', + owner => 'hyperglass-agent', + group => 'hyperglass-agent', + notify => Systemd::Unit_file['hyperglass-agent.service'], + } + + file { '/opt/hyperglass/hyperglass-agent/hyperglass-agent': + ensure => 'directory', + owner => 'hyperglass-agent', + group => 'hyperglass-agent', + mode => '0755', + notify => Systemd::Unit_file['hyperglass-agent.service'], + } + + file { '/opt/hyperglass/hyperglass-agent/hyperglass-agent/config.yaml': + ensure => 'file', + owner => 'hyperglass-agent', + group => 'hyperglass-agent', + mode => '0400', + content => to_yaml($data), + notify => Systemd::Unit_file['hyperglass-agent.service'], + } + + systemd::unit_file { 'hyperglass-agent.service': + source => 'puppet:///modules/hyperglass/hyperglass-agent.service', + enable => true, + active => true, + } } diff --git a/manifests/agent/config.pp b/manifests/agent/config.pp deleted file mode 100644 index 3f3dd97..0000000 --- a/manifests/agent/config.pp +++ /dev/null @@ -1,17 +0,0 @@ -# @summary configures the hyperglass looking agent -# -# @api private -# -class hyperglass::agent::config ( - Hash $data = $hyperglass::agent::data, -) { - assert_private() - - file { '/opt/hyperglass/hyperglass-agent/hyperglass-agent/config.yaml': - ensure => 'file', - owner => 'hyperglass-agent', - group => 'hyperglass-agent', - mode => '0400', - content => to_yaml($data), - } -} diff --git a/manifests/agent/install.pp b/manifests/agent/install.pp deleted file mode 100644 index 07de3c2..0000000 --- a/manifests/agent/install.pp +++ /dev/null @@ -1,58 +0,0 @@ -# @summary installs the hyperglass agent on linux nodes -# -# @api private -# -# @author Tim Meusel -class hyperglass::agent::install ( - Boolean $manage_python = $hyperglass::agent::manage_python, - Boolean $manage_gcc = $hyperglass::agent::manage_gcc, -) { - assert_private() - - if $manage_python { - require hyperglass::python - } - if $manage_gcc { - require hyperglass::gcc - } - user { 'hyperglass-agent': - ensure => 'present', - managehome => true, - purge_ssh_keys => true, - system => true, - home => '/opt/hyperglass/hyperglass-agent', - } - group { 'hyperglass-agent': - ensure => 'present', - system => true, - } - - file { '/opt/hyperglass/hyperglass-agent': - ensure => 'directory', - owner => 'hyperglass-agent', - group => 'hyperglass-agent', - } - - # we need to explicitly set the version here. During the first puppet run, python3 will be installed but isn't present yet - # due to that the fact is undef and fails. the default of the `version` attribute is the fact. We workaround this by hardcoding - # the python version - python::pyvenv { '/opt/hyperglass/hyperglass-agent/virtualenv': - ensure => 'present', - owner => 'hyperglass-agent', - group => 'hyperglass-agent', - systempkgs => false, - version => pick($facts['python3_version'], '3.6'), - } - - python::pip { 'hyperglass-agent': - virtualenv => '/opt/hyperglass/hyperglass-agent/virtualenv', - owner => 'hyperglass-agent', - group => 'hyperglass-agent', - } - - file { '/opt/hyperglass/hyperglass-agent/hyperglass-agent': - ensure => 'directory', - owner => 'hyperglass-agent', - group => 'hyperglass-agent', - } -} diff --git a/manifests/agent/service.pp b/manifests/agent/service.pp deleted file mode 100644 index 21911cc..0000000 --- a/manifests/agent/service.pp +++ /dev/null @@ -1,13 +0,0 @@ -# @summary manages the hyperglass agent service + unit file -# -# @api private -# -# @author Tim Meusel -class hyperglass::agent::service { - assert_private() - systemd::unit_file { 'hyperglass-agent.service': - source => "puppet:///modules/${module_name}/hyperglass-agent.service", - enable => true, - active => true, - } -} diff --git a/manifests/gcc.pp b/manifests/gcc.pp deleted file mode 100644 index 5e34748..0000000 --- a/manifests/gcc.pp +++ /dev/null @@ -1,11 +0,0 @@ -# @summary module to workaround the broken puppetlabs/gcc class. Installs just gcc -# -# @api private -# -# @author Tim Meusel -class hyperglass::gcc { - assert_private() - package { 'gcc': - ensure => 'installed', - } -} diff --git a/manifests/hyperglassdir.pp b/manifests/hyperglassdir.pp deleted file mode 100644 index 9292682..0000000 --- a/manifests/hyperglassdir.pp +++ /dev/null @@ -1,14 +0,0 @@ -# @summary private class to create the main dir for hyperglass server and agent -# -# @api private -# -# @author Tim Meusel -class hyperglass::hyperglassdir { - assert_private() - - file { '/opt/hyperglass/': - ensure => 'directory', - owner => 'root', - group => 'root', - } -} diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..1850806 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,12 @@ +# @summary Manage the Hyperglass bits that are common to both agent and server. +# +# @api private +# +class hyperglass { + file { '/opt/hyperglass': + ensure => 'directory', + owner => 'root', + group => 'root', + mode => '0755', + } +} diff --git a/manifests/python.pp b/manifests/python.pp deleted file mode 100644 index 26863c7..0000000 --- a/manifests/python.pp +++ /dev/null @@ -1,13 +0,0 @@ -# @summary private class used by server/agent to install python3 -# -# @api private -# -# @author Tim Meusel -class hyperglass::python { - assert_private() - - class { 'python': - version => '3', - dev => 'present', - } -} diff --git a/manifests/server.pp b/manifests/server.pp index e2a3f68..185940c 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -1,64 +1,218 @@ -# @summary installs the hyperglass looking glass +# @summary Manage Hyperglass looking glass server software # -# @param manage_depended_services if true, installs all other services that hyperglass requires, like redis, yarn, nginx, python -# @param manage_python installs python3 -# @param manage_gcc installs gcc -# @param devices hash containing all the devices hyperglass can connect to. Defaults to demo data so the service starts properly. -# @param commands specific commands that can be used by the devices -# @param data generic hyperglass configuration hash. +# @param manage_depended_services +# if true, installs all other services that hyperglass requires, like redis, +# yarn, nginx, python +# @param manage_gcc +# installs gcc +# @param manage_node +# Includes the nodejs class using version 14.x +# @param manage_nginx +# Includes the nginx class +# @param manage_python +# installs python3 +# @param manage_redis +# Installs redis5 from SCL. +# @param manage_yarn +# Manages yarn repo and package. +# @param manage_user +# When true, the user 'hyperglass' is managed. +# @param manage_group +# When true, the group 'hyperglass' is managed. +# @param python_version +# Specifies which version of python will be used by python::pyvenv if the +# `python3_version` fact is not found. +# @param devices +# Hash containing all the devices managed by hyperglass. +# @param commands +# Specific commands that can be used by the devices +# @param data +# Generic hyperglass configuration hash. # # @see https://hyperglass.io/ # -# @author Tim Meusel class hyperglass::server ( Boolean $manage_depended_services = true, - Boolean $manage_python = true, - Boolean $manage_gcc = true, - Hash $data = {}, - Hash $commands = {}, - Hash $devices = { - 'routers' => [ - { - 'name' => 'atl_router01', - 'address' => '10.0.0.2', - 'network' => { - 'name' => 'secondary', - 'display_name' => 'That Other Network', - }, - 'credential' => { - 'username' => 'user2', - 'password' => ' secret2', - }, - 'display_name' => 'Atlanta, GA', - 'port' => 22, - 'nos' => 'juniper', - 'vrfs' => [ - { - 'name' => 'default', - 'display_name' => 'Global', - 'ipv4' => { - 'source_address' => '192.0.2.2', - }, - }, - ], - }, - ], - }, + Boolean $manage_gcc = true, + Boolean $manage_node = true, + Boolean $manage_nginx = true, + Boolean $manage_python = true, + Boolean $manage_redis = true, + Boolean $manage_yarn = true, + Boolean $manage_user = true, + Boolean $manage_group = true, + String[1] $python_version = '3.6', + Hash $data = {}, + Hash $commands = {}, + Hash $devices = {}, ) { - unless $facts['os']['name'] in ['CentOS', 'RedHat', 'VirtuozzoLinux'] { - fail('the hyperglass::server class currently only works on CentOS/RedHat') + if $facts['os']['family'] != 'RedHat' { + warning('This module only supports the RedHat family of platforms.') } + include hyperglass + if $manage_depended_services { - require hyperglass::server::dependencies + if $manage_nginx { + include nginx + } + + if $manage_python { + ensure_resource('class', 'python', { 'version' => '3', 'dev' => 'present' }) + } + + if $manage_gcc { + ensure_resource('package', 'gcc', { 'ensure' => 'installed' }) + } + + if $manage_redis { + class { 'redis::globals': + scl => 'rh-redis5', + before => Class['redis'], + } + + class { 'redis': + manage_repo => true, + } + } + + if $manage_node { + class { 'nodejs': + repo_url_suffix => '14.x', + } + } + + if $manage_yarn { + yumrepo { 'yarn': + ensure => 'present', + baseurl => 'https://dl.yarnpkg.com/rpm/', + gpgcheck => 1, + gpgkey => 'https://dl.yarnpkg.com/rpm/pubkey.gpg', + descr => 'Yarn Repository', + } + + package { 'yarn': + ensure => 'present', + require => Yumrepo['yarn'], + } + } + } + + if $manage_user { + user { 'hyperglass': + ensure => 'present', + managehome => true, + purge_ssh_keys => true, + system => true, + home => '/opt/hyperglass/hyperglass-server', + } + } + + if $manage_group { + group { 'hyperglass': + ensure => 'present', + system => true, + } + } + + file { '/opt/hyperglass/hyperglass-server/hyperglass': + ensure => 'directory', + owner => 'hyperglass', + group => 'hyperglass', + mode => '0755', + notify => Systemd::Unit_file['hyperglass.service'], + } + + file { '/opt/hyperglass/hyperglass-server/hyperglass/static': + ensure => 'directory', + owner => 'hyperglass', + group => 'hyperglass', + mode => '0755', + notify => Systemd::Unit_file['hyperglass.service'], + } + + file { '/opt/hyperglass/hyperglass-server/hyperglass/static/custom': + ensure => 'directory', + owner => 'hyperglass', + group => 'hyperglass', + mode => '0755', + notify => Systemd::Unit_file['hyperglass.service'], } - require hyperglass::hyperglassdir - contain hyperglass::server::install - contain hyperglass::server::config - contain hyperglass::server::service + file { '/opt/hyperglass/hyperglass-server/hyperglass/static/ui': + ensure => 'directory', + owner => 'hyperglass', + group => 'hyperglass', + mode => '0755', + notify => Systemd::Unit_file['hyperglass.service'], + } - Class['hyperglass::server::install'] - -> Class['hyperglass::server::config'] - ~> Class['hyperglass::server::service'] + file { '/opt/hyperglass/hyperglass-server/hyperglass/static/images': + ensure => 'directory', + owner => 'hyperglass', + group => 'hyperglass', + mode => '0755', + notify => Systemd::Unit_file['hyperglass.service'], + } + + file { '/opt/hyperglass/hyperglass-server/hyperglass/static/images/favicons': + ensure => 'directory', + owner => 'hyperglass', + group => 'hyperglass', + mode => '0755', + notify => Systemd::Unit_file['hyperglass.service'], + } + + # we need to explicitly set the version here. During the first puppet run, + # python3 will be installed but isn't present yet due to that the fact is + # undef and fails. the default of the `version` attribute is the fact. We + # workaround this by hardcoding the python version + python::pyvenv { '/opt/hyperglass/hyperglass-server/virtualenv': + ensure => 'present', + owner => 'hyperglass', + group => 'hyperglass', + systempkgs => false, + version => pick($facts['python3_version'], $python_version), + notify => Systemd::Unit_file['hyperglass.service'], + } + + python::pip { 'hyperglass': + virtualenv => '/opt/hyperglass/hyperglass-server/virtualenv', + owner => 'hyperglass', + group => 'hyperglass', + notify => Systemd::Unit_file['hyperglass.service'], + } + + file { '/opt/hyperglass/hyperglass-server/hyperglass/hyperglass.yaml': + ensure => 'file', + owner => 'hyperglass', + group => 'hyperglass', + mode => '0644', + content => to_yaml($data), + notify => Systemd::Unit_file['hyperglass.service'], + } + + file { '/opt/hyperglass/hyperglass-server/hyperglass/commands.yaml': + ensure => 'file', + owner => 'hyperglass', + group => 'hyperglass', + mode => '0644', + content => to_yaml($commands), + notify => Systemd::Unit_file['hyperglass.service'], + } + + file { '/opt/hyperglass/hyperglass-server/hyperglass/devices.yaml': + ensure => 'file', + owner => 'hyperglass', + group => 'hyperglass', + mode => '0644', + content => to_yaml($devices), + notify => Systemd::Unit_file['hyperglass.service'], + } + + systemd::unit_file { 'hyperglass.service': + source => 'puppet:///modules/hyperglass/hyperglass.service', + enable => true, + active => true, + } } diff --git a/manifests/server/config.pp b/manifests/server/config.pp deleted file mode 100644 index b644e89..0000000 --- a/manifests/server/config.pp +++ /dev/null @@ -1,35 +0,0 @@ -# @summary writes the hyperglass config files -# -# @param devices hash containing all the devices hyperglass can connect to. Defaults to demo data so the service starts properly. -# @param commands specific commands that can be used by the devices -# @param data generic hyperglass configuration hash -# -# @api private -# -# @author Tim Meusel -class hyperglass::server::config ( - Hash $devices = $hyperglass::server::devices, - Hash $data = $hyperglass::server::data, - Hash $commands = $hyperglass::server::commands, -) { - assert_private() - file { '/opt/hyperglass/hyperglass-server/hyperglass/hyperglass.yaml': - ensure => 'file', - owner => 'hyperglass', - group => 'hyperglass', - content => to_yaml($data), - } - file { '/opt/hyperglass/hyperglass-server/hyperglass/commands.yaml': - ensure => 'file', - owner => 'hyperglass', - group => 'hyperglass', - content => to_yaml($commands), - } - - file { '/opt/hyperglass/hyperglass-server/hyperglass/devices.yaml': - ensure => 'file', - owner => 'hyperglass', - group => 'hyperglass', - content => to_yaml($devices), - } -} diff --git a/manifests/server/dependencies.pp b/manifests/server/dependencies.pp deleted file mode 100644 index 0f92961..0000000 --- a/manifests/server/dependencies.pp +++ /dev/null @@ -1,43 +0,0 @@ -# @summary private class that installs all the services hyperglass depends on -# -# @api private -# -# @author Tim Meusel -class hyperglass::server::dependencies ( - Boolean $manage_python = $hyperglass::server::manage_python, - Boolean $manage_gcc = $hyperglass::server::manage_gcc, -) { - assert_private() - - if $manage_python { - require hyperglass::python - } - if $manage_gcc { - require hyperglass::gcc - } - class { 'redis::globals': - scl => 'rh-redis5', - } - -> class { 'redis': - manage_repo => true, - } - - class { 'nodejs': - repo_url_suffix => '14.x', - } - - yumrepo { 'yarn': - ensure => 'present', - baseurl => 'https://dl.yarnpkg.com/rpm/', - gpgcheck => 1, - gpgkey => 'https://dl.yarnpkg.com/rpm/pubkey.gpg', - descr => 'Yarn Repository', - } - - package { 'yarn': - ensure => 'present', - require => Yumrepo['yarn'], - } - - include nginx -} diff --git a/manifests/server/install.pp b/manifests/server/install.pp deleted file mode 100644 index 55ea061..0000000 --- a/manifests/server/install.pp +++ /dev/null @@ -1,61 +0,0 @@ -# @summary installs the hyperglass server -# -# @api private -# -# @author Tim Meusel -class hyperglass::server::install { - assert_private() - user { 'hyperglass': - ensure => 'present', - managehome => true, - purge_ssh_keys => true, - system => true, - home => '/opt/hyperglass/hyperglass-server', - } - group { 'hyperglass': - ensure => 'present', - system => true, - } - - file { '/opt/hyperglass/hyperglass-server/hyperglass': - ensure => 'directory', - owner => 'hyperglass', - group => 'hyperglass', - } - - file { '/opt/hyperglass/hyperglass-server/hyperglass/static': - ensure => 'directory', - owner => 'hyperglass', - group => 'hyperglass', - require => File['/opt/hyperglass/hyperglass-server/hyperglass'], - } - file { ['/opt/hyperglass/hyperglass-server/hyperglass/static/ui', '/opt/hyperglass/hyperglass-server/hyperglass/static/images', '/opt/hyperglass/hyperglass-server/hyperglass/static/custom']: - ensure => 'directory', - owner => 'hyperglass', - group => 'hyperglass', - require => File['/opt/hyperglass/hyperglass-server/hyperglass/static'], - } - file { '/opt/hyperglass/hyperglass-server/hyperglass/static/images/favicons': - ensure => 'directory', - owner => 'hyperglass', - group => 'hyperglass', - require => File['/opt/hyperglass/hyperglass-server/hyperglass/static/images'], - } - - # we need to explicitly set the version here. During the first puppet run, python3 will be installed but isn't present yet - # due to that the fact is undef and fails. the default of the `version` attribute is the fact. We workaround this by hardcoding - # the python version - python::pyvenv { '/opt/hyperglass/hyperglass-server/virtualenv': - ensure => 'present', - owner => 'hyperglass', - group => 'hyperglass', - systempkgs => false, - version => pick($facts['python3_version'], '3.6'), - } - - python::pip { 'hyperglass': - virtualenv => '/opt/hyperglass/hyperglass-server/virtualenv', - owner => 'hyperglass', - group => 'hyperglass', - } -} diff --git a/manifests/server/service.pp b/manifests/server/service.pp deleted file mode 100644 index fd278cc..0000000 --- a/manifests/server/service.pp +++ /dev/null @@ -1,14 +0,0 @@ -# @summary manages the hyperglass service + unit file -# -# @api private -# -# @author Tim Meusel -class hyperglass::server::service { - assert_private() - systemd::unit_file { 'hyperglass.service': - source => "puppet:///modules/${module_name}/hyperglass.service", - enable => true, - active => true, - require => File['/opt/hyperglass/hyperglass-server/hyperglass/static/images'], - } -} diff --git a/spec/acceptance/agent_and_server_spec.rb b/spec/acceptance/agent_and_server_spec.rb deleted file mode 100644 index 37ba6d5..0000000 --- a/spec/acceptance/agent_and_server_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'spec_helper_acceptance' - -describe 'hyperglass::server class' do - context 'default parameters' do - # Using puppet_apply as a helper - it 'works with no errors' do - pp = <<-PUPPET - include hyperglass::agent - include hyperglass::server - # workaround for https://github.com/checktheroads/hyperglass/issues/85 - file { '/opt/hyperglass/hyperglass-agent/hyperglass-agent/agent_cert.pem': - ensure => 'file', - owner => 'hyperglass-agent', - group => 'hyperglass-agent', - before => Service['hyperglass-agent.service'], - } - file { '/opt/hyperglass/hyperglass-agent/hyperglass-agent/agent_key.pem': - ensure => 'file', - owner => 'hyperglass-agent', - group => 'hyperglass-agent', - before => Service['hyperglass-agent.service'], - } - package { 'bird2': - ensure => 'installed', - before => Service['hyperglass-agent.service'], - require => Yumrepo['epel'], - } - PUPPET - - # Run it twice and test for idempotency - apply_manifest(pp, catch_failures: true) - if fact('selinux') == true - # redis dependency needs two runs to start properly on selinux nodes - # https://tickets.puppetlabs.com/browse/PUP-10548 - apply_manifest(pp, catch_failures: true) - end - apply_manifest(pp, catch_changes: true) - end - end -end diff --git a/spec/acceptance/server_spec.rb b/spec/acceptance/server_spec.rb index 7153648..66933ff 100644 --- a/spec/acceptance/server_spec.rb +++ b/spec/acceptance/server_spec.rb @@ -2,6 +2,10 @@ describe 'hyperglass::server class' do context 'default parameters' do + # This will allow hiera to lookup test data as hyperglass::server::devices + # must be populated for the service to start. + on(hosts, 'mkdir -p /etc/facter/facts.d && echo -e "---\nbeaker: true" > /etc/facter/facts.d/beaker.yaml') + # Using puppet_apply as a helper it 'works with no errors' do pp = 'include hyperglass::server' @@ -21,10 +25,14 @@ it { is_expected.to be_enabled } end + describe file('/opt/hyperglass/hyperglass-server/hyperglass/devices.yaml') do + its(:content) { is_expected.to match %r{atl_router01} } + end + # This sleeps because hyperglass can take a long time to start. The service # check above returns successfully as the service is running though it has # not even bound to a port. - describe command('sleep 60; curl http://localhost:8001') do + describe command('sleep 60; curl http://0.0.0.0:8001') do its(:stdout) { is_expected.to match %r{hyperglass} } end end diff --git a/spec/classes/hyperglass_agent_spec.rb b/spec/classes/hyperglass_agent_spec.rb index 18dccb3..d8b45ce 100644 --- a/spec/classes/hyperglass_agent_spec.rb +++ b/spec/classes/hyperglass_agent_spec.rb @@ -2,17 +2,124 @@ describe 'hyperglass::agent' do let :node do - 'rspec.puppet.com' + 'rspec.example.com' end on_supported_os.each do |os, facts| context "on #{os} " do let :facts do - facts + facts.merge( + python3_version: '3.6.8' + ) end context 'with all defaults' do it { is_expected.to compile.with_all_deps } + + it { is_expected.to contain_class('hyperglass') } + + it { is_expected.not_to contain_class('hyperglass::server') } + + it { is_expected.to contain_class('python').with_version('3').with_dev('present') } + + it { is_expected.to contain_package('gcc').with_ensure('installed') } + + it { + is_expected.to contain_user('hyperglass-agent').with( + { + 'ensure' => 'present', + 'managehome' => true, + 'purge_ssh_keys' => true, + 'system' => true, + 'home' => '/opt/hyperglass/hyperglass-agent', + } + ) + } + + it { is_expected.to contain_group('hyperglass-agent').with_ensure('present').with_system(true) } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-agent').with( + { + 'ensure' => 'directory', + 'owner' => 'hyperglass-agent', + 'group' => 'hyperglass-agent', + 'mode' => '0700', + 'notify' => 'Systemd::Unit_file[hyperglass-agent.service]', + } + ) + } + + it { + is_expected.to contain_python__pyvenv('/opt/hyperglass/hyperglass-agent/virtualenv').with( + { + 'ensure' => 'present', + 'owner' => 'hyperglass-agent', + 'group' => 'hyperglass-agent', + 'systempkgs' => false, + 'version' => '3.6.8', + 'notify' => 'Systemd::Unit_file[hyperglass-agent.service]', + } + ) + } + + it { + is_expected.to contain_python__pip('hyperglass-agent').with( + { + 'virtualenv' => '/opt/hyperglass/hyperglass-agent/virtualenv', + 'owner' => 'hyperglass-agent', + 'group' => 'hyperglass-agent', + 'notify' => 'Systemd::Unit_file[hyperglass-agent.service]', + } + ) + } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-agent/hyperglass-agent').with( + { + 'ensure' => 'directory', + 'owner' => 'hyperglass-agent', + 'group' => 'hyperglass-agent', + 'mode' => '0755', + 'notify' => 'Systemd::Unit_file[hyperglass-agent.service]', + } + ) + } + + # The value for secret is constructed with fqdn_rand_string() and the + # fqdn is specified at the top of this file. + config_yaml_content = <<-END.gsub(%r{^\s+\|}, '') + |--- + |debug: true + |listen_address: 127.0.0.1 + |mode: bird + |secret: zPWG9WEVHdqYpSPUHy2Z + |ssl: + | enable: false + END + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-agent/hyperglass-agent/config.yaml').with( + { + 'ensure' => 'file', + 'owner' => 'hyperglass-agent', + 'group' => 'hyperglass-agent', + 'mode' => '0400', + 'content' => config_yaml_content, + 'notify' => 'Systemd::Unit_file[hyperglass-agent.service]', + } + ) + } + + it { + is_expected.to contain_systemd__unit_file('hyperglass-agent.service').with( + { + 'source' => 'puppet:///modules/hyperglass/hyperglass-agent.service', + 'enable' => true, + 'active' => true, + } + ) + } end end end diff --git a/spec/classes/hyperglass_server_spec.rb b/spec/classes/hyperglass_server_spec.rb index 7f0e678..11024d2 100644 --- a/spec/classes/hyperglass_server_spec.rb +++ b/spec/classes/hyperglass_server_spec.rb @@ -2,7 +2,7 @@ describe 'hyperglass::server' do let :node do - 'rspec.puppet.com' + 'rspec.example.com' end on_supported_os.each do |os, facts| @@ -15,19 +15,193 @@ context 'with all defaults' do it { is_expected.to compile.with_all_deps } - it { is_expected.to contain_class('Hyperglass::Server::Config') } - it { is_expected.to contain_class('Hyperglass::Server::Dependencies') } - it { is_expected.to contain_class('Hyperglass::Server::Install') } - it { is_expected.to contain_class('Hyperglass::Server::Service') } - it { is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/commands.yaml').with_ensure('file').with_owner('hyperglass').with_group('hyperglass') } - it { is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/devices.yaml').with_ensure('file').with_owner('hyperglass').with_group('hyperglass') } - it { is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/hyperglass.yaml').with_ensure('file').with_owner('hyperglass').with_group('hyperglass') } - it { is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static/custom').with_ensure('directory').with_owner('hyperglass').with_group('hyperglass') } - it { is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static/images/favicons').with_ensure('directory').with_owner('hyperglass').with_group('hyperglass') } - it { is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static/images').with_ensure('directory').with_owner('hyperglass').with_group('hyperglass') } - it { is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static/ui').with_ensure('directory').with_owner('hyperglass').with_group('hyperglass') } - it { is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static').with_ensure('directory').with_owner('hyperglass').with_group('hyperglass') } - it { is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass').with_ensure('directory').with_owner('hyperglass').with_group('hyperglass') } + + it { is_expected.to contain_class('hyperglass') } + + it { is_expected.not_to contain_class('hyperglass::agent') } + + it { is_expected.to contain_class('nginx') } + + it { is_expected.to contain_class('python').with_version('3').with_dev('present') } + + it { is_expected.to contain_package('gcc').with_ensure('installed') } + + it { is_expected.to contain_class('redis::globals').with_scl('rh-redis5').that_comes_before('Class[Redis]') } + + it { is_expected.to contain_class('redis').with_manage_repo(true) } + + it { + is_expected.to contain_yumrepo('yarn').with( + { + 'ensure' => 'present', + 'baseurl' => 'https://dl.yarnpkg.com/rpm/', + 'gpgcheck' => 1, + 'gpgkey' => 'https://dl.yarnpkg.com/rpm/pubkey.gpg', + 'descr' => 'Yarn Repository', + } + ) + } + + it { is_expected.to contain_package('yarn').with_ensure('present').that_requires('Yumrepo[yarn]') } + + it { + is_expected.to contain_user('hyperglass').with( + { + 'ensure' => 'present', + 'managehome' => true, + 'purge_ssh_keys' => true, + 'system' => true, + 'home' => '/opt/hyperglass/hyperglass-server', + } + ) + } + + it { is_expected.to contain_group('hyperglass').with_ensure('present').with_system(true) } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass').with( + { + 'ensure' => 'directory', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'mode' => '0755', + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static').with( + { + 'ensure' => 'directory', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'mode' => '0755', + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static/custom').with( + { + 'ensure' => 'directory', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'mode' => '0755', + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static/ui').with( + { + 'ensure' => 'directory', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'mode' => '0755', + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static/images').with( + { + 'ensure' => 'directory', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'mode' => '0755', + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/static/images/favicons').with( + { + 'ensure' => 'directory', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'mode' => '0755', + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_python__pyvenv('/opt/hyperglass/hyperglass-server/virtualenv').with( + { + 'ensure' => 'present', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'systempkgs' => false, + 'version' => '3.6.8', + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_python__pip('hyperglass').with( + { + 'virtualenv' => '/opt/hyperglass/hyperglass-server/virtualenv', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/hyperglass.yaml').with( + { + 'ensure' => 'file', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'mode' => '0644', + 'content' => "--- {}\n", + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/commands.yaml').with( + { + 'ensure' => 'file', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'mode' => '0644', + 'content' => "--- {}\n", + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_file('/opt/hyperglass/hyperglass-server/hyperglass/devices.yaml').with( + { + 'ensure' => 'file', + 'owner' => 'hyperglass', + 'group' => 'hyperglass', + 'mode' => '0644', + 'content' => "--- {}\n", + 'notify' => 'Systemd::Unit_file[hyperglass.service]', + } + ) + } + + it { + is_expected.to contain_systemd__unit_file('hyperglass.service').with( + { + 'source' => 'puppet:///modules/hyperglass/hyperglass.service', + 'enable' => true, + 'active' => true, + } + ) + } end end end diff --git a/spec/classes/hyperglass_spec.rb b/spec/classes/hyperglass_spec.rb new file mode 100644 index 0000000..c3f9b95 --- /dev/null +++ b/spec/classes/hyperglass_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'hyperglass::agent' do + let :node do + 'rspec.example.com' + end + + on_supported_os.each do |os, facts| + context "on #{os} " do + let :facts do + facts.merge( + python3_version: '3.6.8' + ) + end + + context 'with all defaults' do + it { is_expected.to compile.with_all_deps } + + it { is_expected.to contain_class('hyperglass') } + + it { + is_expected.to contain_file('/opt/hyperglass').with( + { + 'ensure' => 'directory', + 'owner' => 'root', + 'group' => 'root', + 'mode' => '0755', + } + ) + } + end + end + end +end diff --git a/vagrant/agent.pp b/vagrant/agent.pp new file mode 100644 index 0000000..5410f43 --- /dev/null +++ b/vagrant/agent.pp @@ -0,0 +1,31 @@ +file { '/opt/hyperglass/hyperglass-agent/hyperglass-agent/agent_cert.pem': + ensure => 'file', + owner => 'hyperglass-agent', + group => 'hyperglass-agent', + before => Service['hyperglass-agent.service'], +} + +file { '/opt/hyperglass/hyperglass-agent/hyperglass-agent/agent_key.pem': + ensure => 'file', + owner => 'hyperglass-agent', + group => 'hyperglass-agent', + before => Service['hyperglass-agent.service'], +} + +package { 'bird2': + ensure => 'installed', + before => Service['hyperglass-agent.service'], + require => Yumrepo['epel'], +} + +class { 'hyperglass::agent': + data => { + 'debug' => true, + 'listen_address' => '0.0.0.0', + 'mode' => 'bird', + 'secret' => fqdn_rand_string(20), + 'ssl' => { + 'enable' => false, + }, + }, +} diff --git a/vagrant/provision_basic_el.sh b/vagrant/provision_basic_el.sh new file mode 100644 index 0000000..3c4bd9a --- /dev/null +++ b/vagrant/provision_basic_el.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# using this instead of "rpm -Uvh" to resolve dependencies +function rpm_install() { + package=$(echo $1 | awk -F "/" '{print $NF}') + wget --quiet $1 + yum install -y ./$package + rm -f $package +} + +release=$(awk -F \: '{print $5}' /etc/system-release-cpe) + +rpm --import http://download-ib01.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-${release} +rpm --import http://yum.puppetlabs.com/RPM-GPG-KEY-puppet +rpm --import http://vault.centos.org/RPM-GPG-KEY-CentOS-${release} + +yum install -y wget + +# install and configure puppet +rpm -qa | grep -q puppet +if [ $? -ne 0 ] +then + + rpm_install http://yum.puppetlabs.com/puppet5-release-el-${release}.noarch.rpm + yum -y install puppet-agent + ln -s /opt/puppetlabs/puppet/bin/puppet /usr/bin/puppet +fi + +# use local hyperglass module +puppet resource file /etc/puppetlabs/code/environments/production/modules/hyperglass ensure=link target=/vagrant + +# install module dependencies +puppet module install puppetlabs/stdlib --version ">= 6.4.0 < 7.0.0" +puppet module install camptocamp/systemd --version ">= 2.10.0 < 3.0.0" +puppet module install puppet/redis --version ">= 6.1.0 < 7.0.0" +puppet module install puppet/nginx --version ">= 2.0.0 < 3.0.0" +puppet module install puppet/nodejs --version ">= 8.0.0 < 9.0.0" +puppet module install puppet/python --version ">= 4.1.1 < 5.0.0" + +# Install selinux so redis works in vagrant. This is used in hyperglass-server.pp. +puppet module install puppet/selinux --version ">= 3.0.0 < 4.0.0" + +puppet resource host hyperglass-server.example.com ensure=present ip=192.168.73.10 host_aliases=hyperglass-server diff --git a/vagrant/server.pp b/vagrant/server.pp new file mode 100644 index 0000000..56b8c14 --- /dev/null +++ b/vagrant/server.pp @@ -0,0 +1,42 @@ +# If you enable selinux, redis will not be able to write to its data directory +# and will not properly start without the following. +selinux::permissive { 'redis_t': + ensure => 'present', + before => Class['redis::service'], +} + +class { 'hyperglass::server': + # Without this, hyperglass binds to localhost and port forwarding with + # vagrant will not work. + data => { + 'listen_address' => '0.0.0.0', + }, + devices => { + 'routers' => [ + { + 'name' => 'atl_router01', + 'address' => '10.0.0.2', + 'network' => { + 'name' => 'secondary', + 'display_name' => 'That Other Network', + }, + 'credential' => { + 'username' => 'user2', + 'password' => ' secret2', + }, + 'display_name' => 'Atlanta, GA', + 'port' => 22, + 'nos' => 'juniper', + 'vrfs' => [ + { + 'name' => 'default', + 'display_name' => 'Global', + 'ipv4' => { + 'source_address' => '192.0.2.2', + }, + }, + ], + }, + ], + }, +}