Commit 99d1575b by source_reader

bug fixes for raspberry pi and more support for running joule in a virtual environment

parent 4a7e5b22
......@@ -4,53 +4,15 @@
#
class common {
# note: chromium for Ubuntu is a snap and cannot be installed in a container
$pkgs=['build-essential','screen','emacs','openvpn',
$pkgs=['build-essential','screen','emacs','openvpn','libhdf5-dev',
'nmap','wget', 'sqlite3', 'gparted', 'net-tools',
'openssh-server','zlib1g-dev','curl',
'openssh-server','zlib1g-dev','curl','wireguard',
'imagemagick','libfreetype6-dev','python3-tk','libatlas-base-dev']
package { $pkgs:
ensure => present
}
# configure python virtual environments
file{'/var/venvs':
ensure => directory,
owner => 'root',
group => 'root'
}
python::pyvenv{'joule_venv':
ensure => present,
version => 'system',
systempkgs => false,
venv_dir => '/var/venvs/joule',
require => File['/var/venvs']
}
python::pip{'joule_pkg':
pkgname => 'joule',
virtualenv => '/var/venvs/joule',
require => Python::Pyvenv['joule_venv']
}
if $facts['image_type']=='nilm'{
$nilmdb_pip_pkgs=['cython', 'uwsgi', 'nilmdb','nilmtools']
$nilmdb_pip_url = "https://pypi.wattsworth.net"
python::pyvenv{'nilmdb_venv':
ensure => present,
version => 'system',
systempkgs => false,
venv_dir => '/var/venvs/nilmdb',
require => File['/var/venvs']
}
python::pip{$nilmdb_pip_pkgs:
virtualenv => '/var/venvs/nilmdb',
install_args => "--extra-index-url $nilmdb_pip_url",
require => [Python::Pyvenv['nilmdb_venv']]#,Package[$apt_pkgs]]
}
}
$global_pip_pkgs = ['scipy', 'sklearn', 'pandas', 'matplotlib']
package { $global_pip_pkgs:
......
[Unit]
Description = "Joule Daemon"
After = syslog.target
[Service]
Type = simple
ExecStart = /var/venvs/joule/bin/jouled
StandardOutput = journal
StandardError = journal
Restart = always
RestartSec = 5
User = joule
[Install]
WantedBy = multi-user.target
......@@ -6,5 +6,5 @@ joule ALL=(ALL) NOPASSWD:/usr/bin/journalctl -u joule*
joule ALL=(ALL) NOPASSWD:/bin/systemctl status joule
joule ALL=(ALL) NOPASSWD:/bin/systemctl restart joule
joule ALL=(ALL) NOPASSWD:/bin/journalctl -u joule*
joule ALL=(ALL) NOPASSWD:SETENV:/usr/local/bin/joule admin authorize
joule ALL=(ALL) NOPASSWD:SETENV:/var/venvs/joule/bin/joule admin authorize
......@@ -31,18 +31,25 @@ class joule::config {
}
$dsn = 'joule:joule@localhost:5432/joule'
if $facts['image_type']=='nilm' {
$cmd = "joule admin initialize --dsn=${dsn} --nilmdb=http://localhost/nilmdb"
$cmd = "joule admin initialize --dsn=${dsn} --nilmdb=http://127.0.0.1/nilmdb"
} else {
$cmd = "joule admin initialize --dsn=${dsn}"
}
exec{'initialize_joule':
command => $cmd,
path => ['/usr/local/bin','/usr/sbin','/bin'],
path => ['/var/venvs/joule/bin','/usr/local/bin','/usr/sbin','/bin'],
creates => '/etc/joule/main.conf',
require => Exec['custom_sql']
}
file{'/etc/systemd/system/joule.service':
source => 'puppet:///modules/joule/joule.service',
owner => root,
group => root,
mode => '0644',
require => Exec['initialize_joule']
}
postgresql::server::pg_hba_rule { 'allow remote access for modules':
description => 'allow network access to joule database',
type => 'host',
......
class joule {
require python_venvs
contain joule::install
contain joule::config
contain joule::service
......
class joule::install{
require common
require timescaledb
require python_venvs
#add symlinks to /usr/local/bin so we can use joule commands
#without activating the venv
user{'joule':
ensure => present,
uid => 901,
groups => 'dialout',
managehome => true
}
#add symlinks to /usr/local/bin so we can use joule commands
#without activating the venv (needed for sudo and helpful for systemd services)
file{'/usr/local/bin/joule':
ensure => link,
target => '/var/venvs/joule/bin/joule'
......@@ -11,12 +19,5 @@ class joule::install{
file{'/usr/local/bin/jouled':
ensure => link,
target => '/var/venvs/joule/bin/jouled'
}
user{'joule':
ensure => present,
uid => 901,
groups => 'dialout',
managehome => true
}
}
}
class joule_labjack {
require joule
require python_venvs
$pip_url='https://pypi.wattsworth.net/'
$pip_cmd="pip3 install --upgrade --extra-index-url ${pip_url}"
package{'libusb-1.0.0-dev':
ensure => present,
}
exec{'install labjack':
command => "${pip_cmd} LabJackPython joulelabjack",
timeout => 0,
path => ['/usr/local/bin','/usr/bin'],
}
$exodriver_zip="https://github.com/labjack/exodriver/archive/master.zip"
exec{'install exodriver':
......
......@@ -9,10 +9,14 @@
"This notebook shows how to use the Joule Application Programming Interface (API).\n",
"\n",
"\n",
"Before running this notebook, you must authorize API access for the Joule user. To do this run the following command from the terminal:\n",
"Before running this notebook, you must authorize API access for the Joule user and switch to the joule kernel. \n",
"\n",
"1. Run the following command from the terminal to authorize API access:\n",
"```\n",
" $> sudo -E joule admin authorize\n",
" ```"
" ```\n",
" \n",
"2. Switch the kernel to ``joule`` from the menu Kernel->Change Kernel"
]
},
{
......@@ -24,7 +28,7 @@
"# run this cell first to import the packages\n",
"import joule\n",
"# convenience imports to make code more compact\n",
"from joule.api import Stream, Element, Annotation\n",
"from joule.api import EventStream, Event, DataStream, Element, Annotation\n",
"from joule.errors import EmptyPipeError\n",
"import numpy as np\n",
"from matplotlib import pyplot as plt"
......@@ -60,7 +64,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create streams and write data"
"### Create data streams and write data"
]
},
{
......@@ -87,8 +91,8 @@
"outputs": [],
"source": [
"# create a stream on the Joule Node that can store this data\n",
"stream = Stream(name=\"waves\", elements=[Element(name=\"sine\"), Element(name=\"cosine\")])\n",
"stream = await node.stream_create(stream,\"/Demos\") # now stream is a registered model and can be used with API calls\n",
"stream = DataStream(name=\"waves\", elements=[Element(name=\"sine\"), Element(name=\"cosine\")])\n",
"stream = await node.data_stream_create(stream,\"/Demos\") # now stream is a registered model and can be used with API calls\n",
"\n",
"# refresh the node in the Data Explorer and you should see the new stream\n",
"# *NOTE* if you run this code more than once you will receive an error that the stream already exists"
......@@ -125,7 +129,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Manipulate streams and data"
"### Manipulate data streams and data"
]
},
{
......@@ -135,14 +139,14 @@
"outputs": [],
"source": [
"# get information about a stream\n",
"print(\"Stream Info:\\t\", await node.stream_info(stream))\n",
"print(\"Stream Info:\\t\", await node.data_stream_info(stream))\n",
"\n",
"# get the data intervals (regions of the stream with data)\n",
"print(\"Intervals:\\t\", await node.data_intervals(stream))\n",
"\n",
"# change the display type of an element to discrete\n",
"stream.elements[1].display_type=\"discrete\"\n",
"await node.stream_update(stream) # refresh the node to see this change\n",
"await node.data_stream_update(stream) # refresh the node to see this change\n",
"\n",
"# remove data from a stream \n",
"# ***DANGEROUS: OMITTING START and END will remove ALL DATA***\n",
......@@ -168,42 +172,45 @@
"source": [
"# Annotate a range of data in Lumen then run this cell\n",
"#\n",
"RUN_THIS=False\n",
"\n",
"# retrieve a list of annotations (include start,end parameters to limit query to a time range)\n",
"annotations = await node.annotation_get(stream)\n",
"if RUN_THIS:\n",
"\n",
"if len(annotations) == 0:\n",
" print(\"ERROR: Create an annotation in Lumen then run this cell\")\n",
"elif annotations[0].end is None:\n",
" print(\"ERROR: Annotate a range in Lumen, not an event\")\n",
"else:\n",
" annotation = annotations[0]\n",
" \n",
" # read the data associated with the annotation\n",
" pipe = await node.data_read(stream,start=annotation.start, end=annotation.end)\n",
" data = await pipe.read_all() # this automatically closes the pipe\n",
" \n",
" # plot the data\n",
" plt.plot(data['timestamp']/1e6, data['data'])\n",
" plt.title(annotation.title)\n",
" plt.xlabel('Time (sec)')\n",
" plt.show()\n",
" # retrieve a list of annotations (include start,end parameters to limit query to a time range)\n",
" annotations = await node.annotation_get(stream)\n",
"\n",
"# Annotations can also be created with the API\n",
"#\n",
" if len(annotations) == 0:\n",
" print(\"ERROR: Create an annotation in Lumen then run this cell\")\n",
" elif annotations[0].end is None:\n",
" print(\"ERROR: Annotate a range in Lumen, not an event\")\n",
" else:\n",
" annotation = annotations[0]\n",
"\n",
" # read the data associated with the annotation\n",
" pipe = await node.data_read(stream,start=annotation.start, end=annotation.end)\n",
" data = await pipe.read_all() # this automatically closes the pipe\n",
"\n",
" annotation = Annotation(title='API Annotation', start=0.8*1e6)\n",
" await node.annotation_create(annotation, stream)\n",
" # plot the data\n",
" plt.plot(data['timestamp']/1e6, data['data'])\n",
" plt.title(annotation.title)\n",
" plt.xlabel('Time (sec)')\n",
" plt.show()\n",
"\n",
"# refresh the annotations in the Plot Tab of Lumen to see this new annotation\n",
"# *NOTE* If you run this cell multiple times it will create multiple annotations"
" # Annotations can also be created with the API\n",
" #\n",
"\n",
" annotation = Annotation(title='API Annotation', start=0.8*1e6)\n",
" await node.annotation_create(annotation, stream)\n",
"\n",
" # refresh the annotations in the Plot Tab of Lumen to see this new annotation\n",
" # *NOTE* If you run this cell multiple times it will create multiple annotations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Explore Streams and Read Data"
"### Explore data streams and read data"
]
},
{
......@@ -220,7 +227,7 @@
" for child in folder.children:\n",
" print(\" \"*indent + child.name)\n",
" print_folder(child, indent+1)\n",
" for stream in folder.streams:\n",
" for stream in folder.data_streams:\n",
" print(\" \"*indent + \"[%s: %s]\" % (stream.name, stream.layout))\n",
" \n",
"# print the folder directory structure\n",
......@@ -234,7 +241,7 @@
"outputs": [],
"source": [
"# streams can be accessed by API object (as shown in previous cells) or by path\n",
"info = await node.stream_info(\"/Demos/waves\")\n",
"info = await node.data_stream_info(\"/Demos/waves\")\n",
"print(\"The demo stream has %d rows of data\" % info.rows)\n",
"\n",
"# To read data, first create a pipe to the stream\n",
......@@ -269,6 +276,49 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Event Streams"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Event streams store unstructured JSON data with start and end timestamps"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# create a stream on the Joule Node that can store this data\n",
"stream = EventStream(name=\"Events\")\n",
"stream = await node.event_stream_create(stream,\"/Demos\") # now stream is a registered model and can be used with API calls\n",
"\n",
"# refresh the node in the Data Explorer and you should see the new stream\n",
"# *NOTE* if you run this code more than once you will receive an error that the stream already exists"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# events have a start, end, and content which can contain any JSON serializable data\n",
"event1 = Event(start_time=0, end_time=0.1e6, \n",
" content={'height':1,'color':'red','description':'first one'})\n",
"event2 = Event(start_time=.3e6, end_time=0.5e6, \n",
" content={'height':2,'color':'blue','description':'second one'})\n",
"\n",
"await node.event_stream_write(stream, [event1, event2])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Reset the Node to original state\n",
"**Run this cell to undo all changes created by this notebook**"
]
......@@ -279,15 +329,15 @@
"metadata": {},
"outputs": [],
"source": [
"await node.folder_delete(\"/Demos\")"
"#await node.folder_delete(\"/Demos\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "joule",
"language": "python",
"name": "python3"
"name": "joule"
},
"language_info": {
"codemirror_mode": {
......@@ -299,7 +349,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.2"
"version": "3.9.2"
}
},
"nbformat": 4,
......
......@@ -7,6 +7,11 @@ class jupyter::config{
owner => joule,
group => joule,
}
exec{'configure_joule_for_jupyter':
command => '/var/venvs/joule/bin/python -m ipykernel install --user --name=joule',
user => 'joule',
creates => "/home/joule/.local/share/jupyter/kernels/joule"
}
file{'/home/joule/API_demo.ipynb':
source => 'puppet:///modules/jupyter/API_demo.ipynb',
owner => joule,
......
passenger_root /var/lib/gems/2.5.0/gems/passenger-6.0.4;
passenger_ruby /usr/bin/ruby2.5;
passenger_root /var/lib/gems/2.7.0/gems/passenger-6.0.12;
passenger_ruby /usr/bin/ruby2.7;
......@@ -11,7 +11,7 @@ class nginx::sites {
group => root,
mode => '0644',
}
$lumen_cmd = "wget http://docs.wattsworth.net/lumen.tar > /dev/null &&\
$lumen_cmd = "wget http://cloud.wattsworth.net/docs/lumen.tar > /dev/null &&\
rm -rf /var/www/frontend/* &&\
tar -xf lumen.tar -C /var/www/frontend &&\
rm lumen.tar"
......@@ -30,7 +30,7 @@ class nginx::sites {
group => root,
mode => '0644',
}
$docs_cmd = "wget http://docs.wattsworth.net/docs.tar > /dev/null &&\
$docs_cmd = "wget http://cloud.wattsworth.net/docs/docs.tar > /dev/null &&\
rm -rf /var/www/docs/* &&\
tar -xf docs.tar -C /var/www/docs &&\
mv /var/www/docs/standalone_index.html /var/www/docs/index.html &&\
......
class nilm {
require common
require python_venvs
contain nilm::install
contain nilm::config
......
......@@ -13,7 +13,8 @@
class nilmdb {
require 'common'
require 'joule'
require 'python_venvs'
contain nilmdb::install
contain nilmdb::config
# contain nilmdb::service
......
......@@ -40,20 +40,6 @@ class nilmdb::install{
uid => 902,
managehome=>true
}
#add symlinks to /usr/local/bin so we can use nilmdb commands
#without activating the venv
file{'/usr/local/bin/nilmtool':
ensure => link,
target => '/var/venvs/nilmdb/bin/nilmtool'
}
file{'/usr/local/bin/nilmdb-server':
ensure => link,
target => '/var/venvs/nilmdb/bin/nilmdb-server'
}
file{'/usr/local/bin/nilmdb-fsck':
ensure => link,
target => '/var/venvs/nilmdb/bin/nilmdb-fsck'
}
file{'/opt/data':
ensure => directory,
......
source ENV['GEM_SOURCE'] || 'https://rubygems.org'
puppetversion = ENV.key?('PUPPET_VERSION') ? ENV['PUPPET_VERSION'] : ['>= 3.3']
gem 'metadata-json-lint'
gem 'puppet', puppetversion
gem 'puppetlabs_spec_helper', '>= 1.2.0'
gem 'puppet-lint', '>= 1.0.0'
gem 'facter', '>= 1.7.0'
gem 'rspec-puppet'
# rspec must be v2 for ruby 1.8.7
if RUBY_VERSION >= '1.8.7' && RUBY_VERSION < '1.9'
gem 'rspec', '~> 2.0'
gem 'rake', '~> 10.0'
else
# rubocop requires ruby >= 1.9
gem 'rubocop'
end
# python_venvs
#### Table of Contents
1. [Description](#description)
1. [Setup - The basics of getting started with python_venvs](#setup)
* [What python_venvs affects](#what-python_venvs-affects)
* [Setup requirements](#setup-requirements)
* [Beginning with python_venvs](#beginning-with-python_venvs)
1. [Usage - Configuration options and additional functionality](#usage)
1. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
1. [Limitations - OS compatibility, etc.](#limitations)
1. [Development - Guide for contributing to the module](#development)
## Description
Start with a one- or two-sentence summary of what the module does and/or what
problem it solves. This is your 30-second elevator pitch for your module.
Consider including OS/Puppet version it works with.
You can give more descriptive information in a second paragraph. This paragraph
should answer the questions: "What does this module *do*?" and "Why would I use
it?" If your module has a range of functionality (installation, configuration,
management, etc.), this is the time to mention it.
## Setup
### What python_venvs affects **OPTIONAL**
If it's obvious what your module touches, you can skip this section. For
example, folks can probably figure out that your mysql_instance module affects
their MySQL instances.
If there's more that they should know about, though, this is the place to mention:
* A list of files, packages, services, or operations that the module will alter,
impact, or execute.
* Dependencies that your module automatically installs.
* Warnings or other important notices.
### Setup Requirements **OPTIONAL**
If your module requires anything extra before setting up (pluginsync enabled,
etc.), mention it here.
If your most recent release breaks compatibility or requires particular steps
for upgrading, you might want to include an additional "Upgrading" section
here.
### Beginning with python_venvs
The very basic steps needed for a user to get the module up and running. This
can include setup steps, if necessary, or it can be an example of the most
basic use of the module.
## Usage
This section is where you describe how to customize, configure, and do the
fancy stuff with your module here. It's especially helpful if you include usage
examples and code samples for doing things with your module.
## Reference
Users need a complete list of your module's classes, types, defined types providers, facts, and functions, along with the parameters for each. You can provide this list either via Puppet Strings code comments or as a complete list in this Reference section.
* If you are using Puppet Strings code comments, this Reference section should include Strings information so that your users know how to access your documentation.
* If you are not using Puppet Strings, include a list of all of your classes, defined types, and so on, along with their parameters. Each element in this listing should include:
* The data type, if applicable.
* A description of what the element does.
* Valid values, if the data type doesn't make it obvious.
* Default value, if any.
## Limitations
This is where you list OS compatibility, version compatibility, etc. If there
are Known Issues, you might want to include them under their own heading here.
## Development
Since your module is awesome, other users will want to play with it. Let them
know what the ground rules for contributing are.
## Release Notes/Contributors/Etc. **Optional**
If you aren't using changelog, put your release notes here (though you should
consider using changelog). You can also add any additional sections you feel
are necessary or important to include here. Please use the `## ` header.
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
require 'metadata-json-lint/rake_task'
if RUBY_VERSION >= '1.9'
require 'rubocop/rake_task'
RuboCop::RakeTask.new
end
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.relative = true
PuppetLint.configuration.ignore_paths = ['spec/**/*.pp', 'pkg/**/*.pp']
desc 'Validate manifests, templates, and ruby files'
task :validate do
Dir['manifests/**/*.pp'].each do |manifest|
sh "puppet parser validate --noop #{manifest}"
end
Dir['spec/**/*.rb', 'lib/**/*.rb'].each do |ruby_file|
sh "ruby -c #{ruby_file}" unless ruby_file =~ %r{spec/fixtures}
end
Dir['templates/**/*.erb'].each do |template|
sh "erb -P -x -T '-' #{template} | ruby -c"
end
end
desc 'Run lint, validate, and spec tests.'
task :test do
[:lint, :validate, :spec].each do |test|
Rake::Task[test].invoke
end
end
# The baseline for module testing used by Puppet Inc. is that each manifest
# should have a corresponding test manifest that declares that class or defined
# type.
#
# Tests are then run by using puppet apply --noop (to check for compilation
# errors and view a log of events) or by fully applying the test in a virtual
# environment (to compare the resulting system state to the desired state).
#
# Learn more about module testing here:
# https://puppet.com/docs/puppet/latest/bgtm.html#testing-your-module
#
include ::python_venvs
class python_venvs::config{
if $facts['image_type'] == 'nilm'{
$nilmdb=true
} else {
$nilmdb = false
}
if $facts['platform'] == 'ubuntu'{
file {'/etc/environment.d/90venvs.conf':
content => template('python_venvs/90venvs.conf.erb'),
owner => root,
group => root,
mode => '0644'
}
} else {
file {'/etc/profile.d/venvs.sh':
content => template('python_venvs/venvs.sh.erb'),
owner => root,
group => root,
mode => '0644'
}
}
}
\ No newline at end of file
# Class: python_venvs
# ===========================
#
class python_venvs {
contain python_venvs::install
contain python_venvs::config
Class['::python_venvs::install']
-> Class['::python_venvs::config']
}
class python_venvs::install{
require common
# configure python virtual environments
file{'/var/venvs':
ensure => directory,
owner => 'root',
group => 'root'
}
python::pyvenv{'joule_venv':
ensure => present,
version => 'system',
systempkgs => false,
venv_dir => '/var/venvs/joule',
require => File['/var/venvs']
}
$ww_pip_url = "https://pypi.wattsworth.net"
$joule_pip_pkgs=['joule','LabJackPython','joulelabjack','ipykernel']
python::pip{$joule_pip_pkgs:
install_args => "--upgrade --extra-index-url $ww_pip_url",
virtualenv => '/var/venvs/joule',
require => Python::Pyvenv['joule_venv']
}
if $facts['image_type']=='nilm'{
$nilmdb_pip_pkgs=['cython', 'uwsgi', 'nilmdb','nilmtools']
python::pyvenv{'nilmdb_venv':
ensure => present,
version => 'system',
systempkgs => false,
venv_dir => '/var/venvs/nilmdb',
require => File['/var/venvs']
}
python::pip{$nilmdb_pip_pkgs:
virtualenv => '/var/venvs/nilmdb',
install_args => "--upgrade --extra-index-url $ww_pip_url",
require => [Python::Pyvenv['nilmdb_venv']]
}
}
}
\ No newline at end of file
{
"name": "jdonnal-python_venvs",
"version": "0.1.0",
"author": "jdonnal",
"summary": "configure venvs for joule and nilmdb",
"license": "Apache-2.0",
"source": "",
"project_page": null,
"issues_url": null,
"dependencies": [
{
"name": "puppetlabs-stdlib",
"version_requirement": ">= 1.0.0"
}
],
"data_provider": null
}
require 'spec_helper'
describe 'python_venvs' do
context 'with default values for all parameters' do
it { should contain_class('python_venvs') }
end
end
require 'puppetlabs_spec_helper/module_spec_helper'
PATH=$PATH:/var/venvs/joule/bin
<% if @nilmdb -%>
PATH=$PATH:/var/venvs/nilmdb/bin
<% end -%>
\ No newline at end of file
export PATH=$PATH:/var/venvs/joule/bin
<% if @nilmdb -%>
export PATH=$PATH:/var/venvs/nilmdb/bin
<% end -%>
\ No newline at end of file
......@@ -27,9 +27,9 @@ class timescaledb {
class{ 'postgresql::globals':
version => '12',
}
} else { # on the pi use version 11
} else { # on the pi use version 13
class{ 'postgresql::globals':
version => '11',
version => '13',
}
}
class{ 'postgresql::server':
......
......@@ -13,25 +13,25 @@ set -e
echo "SET LOCALE"
raspi-config
echo "deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi" >> /etc/apt/sources.list
echo "deb-src http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi" >> /etc/apt/sources.list
apt update
apt upgrade -y
apt install puppet git r10k -y
# install wireguard
apt install raspberrypi-kernel-headers
git clone https://git.zx2c4.com/WireGuard
cd WireGuard/src
make install
cd -
#apt install raspberrypi-kernel-headers
#git clone https://git.zx2c4.com/WireGuard
#cd WireGuard/src
#make install
#cd -
# install postgres and timescale
apt install postgresql libpq-dev postgresql-server-dev-11 libssl-dev clang-format cmake -y
apt install postgresql libkrb5-dev libpq-dev postgresql-server-dev-13 libssl-dev clang-format cmake -y
git clone https://github.com/timescale/timescaledb.git
cd timescaledb
git checkout 1.4.0
echo "installing timescale version 1.4.0"
git checkout 2.5.1
echo "installing timescale version 2.5.1"
./bootstrap
cd build && make
make install
......
......@@ -3,6 +3,7 @@ node 'default' {
include common
include timescaledb
include rails_api
include python_venvs
include joule_labjack
include hostapd
include joule
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment