@@ -0,0 +1,6 @@ | |||
*.pyc | |||
venv | |||
build | |||
dist | |||
*.egg-info | |||
.eggs |
@@ -0,0 +1,24 @@ | |||
This is free and unencumbered software released into the public domain. | |||
Anyone is free to copy, modify, publish, use, compile, sell, or | |||
distribute this software, either in source code form or as a compiled | |||
binary, for any purpose, commercial or non-commercial, and by any | |||
means. | |||
In jurisdictions that recognize copyright laws, the author or authors | |||
of this software dedicate any and all copyright interest in the | |||
software to the public domain. We make this dedication for the benefit | |||
of the public at large and to the detriment of our heirs and | |||
successors. We intend this dedication to be an overt act of | |||
relinquishment in perpetuity of all present and future rights to this | |||
software under copyright law. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |||
OTHER DEALINGS IN THE SOFTWARE. | |||
For more information, please refer to <http://unlicense.org/> |
@@ -0,0 +1,70 @@ | |||
Python library for http://sporestack.com/ | |||
# Installation | |||
* `pip install sporestack` | |||
# Usage | |||
Spawn one from your terminal. | |||
``` | |||
import sporestack | |||
from uuid import uuid4 as random_uuid | |||
node_uuid = str(random_uuid()) | |||
ssh_key_path = '{}/.ssh/id_rsa.pub'.format(os.getenv('HOME')) | |||
with open(ssh_key_path) as ssh_key_file: | |||
sshkey = ssh_key_file.read() | |||
while True: | |||
node = sporestack.node(days=28, | |||
sshkey=sshkey, | |||
unique=node_uuid) | |||
if node.payment_status is False: | |||
amount = "{0:.8f}".format(node.satoshis * | |||
0.00000001) | |||
uri = 'bitcoin:{}?amount={}'.format(node.address, amount) | |||
qr = pyqrcode.create(uri) | |||
print(qr.terminal()) | |||
print(uri) | |||
print('Pay with Bitcoin. Resize your terminal if QR code is unclear.') | |||
else: | |||
print('Node being built...') | |||
if node.creation_status is True: | |||
break | |||
sleep(5) | |||
banner = ''' | |||
UUID: {} | |||
IPv6: {} | |||
IPv4: {} | |||
End of Life: {} | |||
May take a few more moments to come online. | |||
'''.format(node_uuid, | |||
node.ip6, | |||
node.ip4, | |||
node.end_of_life) | |||
print(banner) | |||
``` | |||
Spawn one and SSH into it. | |||
``` | |||
nodemeup | |||
``` | |||
# Examples | |||
* [Launch a tor relay](examples/torrelay.py) | |||
# Licence | |||
[Unlicense/Public domain](LICENSE.txt) |
@@ -0,0 +1,73 @@ | |||
""" | |||
Creates a 28 day Bitcoin Unlimited node in Dallas. | |||
Doesn't work. | |||
""" | |||
from uuid import uuid4 as random_uuid | |||
from time import sleep | |||
import os | |||
import pyqrcode | |||
import sporestack | |||
# 1 - 28 | |||
DAYS = 28 | |||
# 3 is DFW. | |||
DCID = 3 | |||
# FreeBSD 11. Will need to change the startupscript if you adjust this. | |||
OSID = 230 | |||
# 4GiB memory, 90GiB disk | |||
FLAVOR=95 | |||
node_uuid = str(random_uuid()) | |||
ssh_key_path = '{}/.ssh/id_rsa.pub'.format(os.getenv('HOME')) | |||
with open(ssh_key_path) as ssh_key_file: | |||
sshkey = ssh_key_file.read() | |||
with open('bitcoinunlimited.sh') as startup_file: | |||
startupscript = startup_file.read() | |||
# This is broken. | |||
while False: | |||
node = sporestack.node(days=28, | |||
sshkey=sshkey, | |||
startupscript=startupscript, | |||
unique=node_uuid, | |||
flavor=FLAVOR, | |||
osid=OSID, | |||
dcid=DCID) | |||
if node.payment_status is False: | |||
amount = "{0:.8f}".format(node.satoshis * | |||
0.00000001) | |||
uri = 'bitcoin:{}?amount={}'.format(node.address, amount) | |||
qr = pyqrcode.create(uri) | |||
print(qr.terminal()) | |||
print(uri) | |||
print('Pay with Bitcoin. Resize your terminal if QR code is unclear.') | |||
else: | |||
print('Node being built...') | |||
if node.creation_status is True: | |||
break | |||
sleep(5) | |||
banner = ''' | |||
UUID: {} | |||
IPv6: {} | |||
IPv4: {} | |||
End of Life: {} | |||
May take a few more moments to come online. | |||
'''.format(node_uuid, | |||
node.ip6, | |||
node.ip4, | |||
node.end_of_life) | |||
print(banner) |
@@ -0,0 +1,76 @@ | |||
#!/bin/sh | |||
# Stops/breaks at: | |||
# In file included from leveldb/db/builder.cc:7: | |||
# In file included from ./leveldb/db/filename.h:14: | |||
# In file included from ./leveldb/port/port.h:14: | |||
# ./leveldb/port/port_posix.h:38:12: fatal error: 'endian.h' file not found | |||
# #include <endian.h> | |||
# ^ | |||
# 1 warning and 1 error generated. | |||
# gmake[2]: *** [Makefile:3874: leveldb/db/leveldb_libleveldb_a-builder.o] Error 1 | |||
# | |||
progress() { | |||
echo "bitcoinunlimited: $*" > /dev/console | |||
echo "bitcoinunlimited: $*" | |||
} | |||
# This runs at the top of cloud-init. We don't even have SSHD running without | |||
# this. | |||
# <- Does it still do that? | |||
export ASSUME_ALWAYS_YES=yes | |||
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin | |||
progress 'Starting pkg upgrade' | |||
pkg upgrade | |||
progress 'Starting pkg install' | |||
pkg upgrade | |||
pkg install ca_root_nss autotools pkgconf gmake boost-libs libevent2 openssl db48 git micro_httpd micro_inetd #FIXME TODO: Remove git | |||
chmod 700 /root | |||
mkdir /root/.bitcoin | |||
echo 'rpcuser=bitcoinunlimited | |||
rpcpassword=bitcoinunlimitedpassword' > /root/.bitcoin/bitcoin.conf | |||
# ^ If the user and password are the same, it will fail. | |||
mkdir /root/BitcoinUnlimited | |||
# tmpfs for speed and because / is too small otherwise. | |||
# growfs seems to have problems, not sure why. | |||
mount -t tmpfs tmpfs /root/BitcoinUnlimited | |||
cd /root/BitcoinUnlimited | |||
#FIXME This seems to have a 302 loop right now. | |||
#fetch -qo - https://github.com/bitcoinunlimited/bitcoinunlimited/archive/$TAG.tar.gz | tar xzf - | |||
progress 'Starting git clone' | |||
git clone --depth 1 https://github.com/BitcoinUnlimited/BitcoinUnlimited.git bu-src | |||
cd BitcoinUnlimited | |||
./autogen.sh | |||
./configure --with-gui=no --without-miniupnpc --disable-wallet | |||
progress 'About to compile' | |||
gmake -j 2 | |||
gmake install | |||
cd / | |||
umount /root/BitcoinUnlimited | |||
fetch -q \ | |||
https://raw.githubusercontent.com/teran-mckinney/bitnoder/master/fs/etc/rc.local \ | |||
-o /etc/rc.local | |||
fetch -q \ | |||
https://raw.githubusercontent.com/teran-mckinney/bitnoder/master/fs/usr/local/bin/honeybadgermoneystats \ | |||
-o /usr/local/bin/honeybadgermoneystats | |||
echo > /usr/local/etc/bitnoder.conf | |||
echo 'ntpd_enable="YES"' >> /etc/rc.conf | |||
chmod 500 /etc/rc.local | |||
chmod 500 /usr/local/bin/honeybadgermoneystats | |||
# Let the boot process start rc.local on its own. | |||
#/etc/rc.local |
@@ -0,0 +1,66 @@ | |||
""" | |||
Creates a 28 day tor relay in Dallas. | |||
""" | |||
from uuid import uuid4 as random_uuid | |||
from time import sleep | |||
import os | |||
import pyqrcode | |||
import sporestack | |||
# 1 - 28 | |||
DAYS = 28 | |||
# 3 is DFW. | |||
DCID = 3 | |||
# FreeBSD 11. Will need to change the startupscript if you adjust this. | |||
OSID = 230 | |||
node_uuid = str(random_uuid()) | |||
ssh_key_path = '{}/.ssh/id_rsa.pub'.format(os.getenv('HOME')) | |||
with open(ssh_key_path) as ssh_key_file: | |||
sshkey = ssh_key_file.read() | |||
with open('torrelay.sh') as startup_file: | |||
startupscript = startup_file.read() | |||
while True: | |||
node = sporestack.node(days=28, | |||
sshkey=sshkey, | |||
startupscript=startupscript, | |||
unique=node_uuid, | |||
osid=OSID, | |||
dcid=DCID) | |||
if node.payment_status is False: | |||
amount = "{0:.8f}".format(node.satoshis * | |||
0.00000001) | |||
uri = 'bitcoin:{}?amount={}'.format(node.address, amount) | |||
qr = pyqrcode.create(uri) | |||
print(qr.terminal()) | |||
print(uri) | |||
print('Pay with Bitcoin. Resize your terminal if QR code is unclear.') | |||
else: | |||
print('Node being built...') | |||
if node.creation_status is True: | |||
break | |||
sleep(5) | |||
banner = ''' | |||
UUID: {} | |||
IPv6: {} | |||
IPv4: {} | |||
End of Life: {} | |||
May take a few more moments to come online. | |||
'''.format(node_uuid, | |||
node.ip6, | |||
node.ip4, | |||
node.end_of_life) | |||
print(banner) |
@@ -0,0 +1,74 @@ | |||
#!/bin/sh | |||
progress() { | |||
echo "$NAME: $*" > /dev/console | |||
echo "$NAME: $*" | |||
} | |||
# This runs at the top of cloud-init. We don't even have SSHD running without | |||
# this. | |||
export ASSUME_ALWAYS_YES=yes | |||
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin | |||
# pkg isn't installed by default on vultr, but this will bootstrap it | |||
# with the above option of ASSUME_ALWAYS_YES=yes | |||
progress 'Starting pkg upgrade' | |||
pkg upgrade | |||
progress 'Starting pkg install' | |||
pkg upgrade | |||
pkg install tor | |||
sysctl net.inet.ip.random_id=1 | |||
echo 'net.inet.ip.random_id=1' >> /etc/sysctl.conf | |||
# May need to consider bandwidth allowances with the plan and how high the | |||
# rate limit is. This is 2.6TiB theoretical max, but probably would be a little | |||
# higher in one month. | |||
# IPv6 global address has to be specified manually. | |||
# We also may not have it unless we probe for it explictly. | |||
echo 'ifconfig_vtnet0_ipv6="inet6 accept_rtadv" | |||
rtsold_enable=YES | |||
ipv6_activate_all_interfaces=YES | |||
dumpdev="NO" | |||
moused_enable="NO" | |||
sendmail_enable="NONE" | |||
ip6addrctl_policy="ipv6_prefer"' >> /etc/rc.conf | |||
# This is rather ugly, I'm sorry. | |||
ifconfig vtnet0 inet6 auto_linklocal | |||
ifconfig vtnet0 inet6 accept_rtadv | |||
ifconfig vtnet0 inet6 -ifdisabled | |||
service rtsold start | |||
rtsold -fd1 vtnet0 | |||
sleep 10 | |||
rtsold -fd1 vtnet0 | |||
IPV6="$(ifconfig vtnet0 | grep inet6 | grep -v 'inet6 fe80' | awk '{print $2}')" | |||
if [ -n "$IPV6" ]; then | |||
echo "ORPort [$IPV6]:443" > /usr/local/etc/tor/torrc | |||
fi | |||
echo 'ORPort 443 | |||
Nickname BuiltAutomatically | |||
RelayBandwidthRate 1024 KB | |||
RelayBandwidthBurst 1024 KB | |||
ContactInfo IThinkIWasBuiltAutomatically | |||
ExitPolicy reject *:* | |||
ExitPolicy reject6 *:*' >> /usr/local/etc/tor/torrc | |||
# Running tor as root, partly for port 443 use. Since this server hopefully | |||
# only runs tor, it's safe to do. | |||
echo 'ntpd_enable="YES" | |||
tor_enable="YES" | |||
tor_user="root"' >> /etc/rc.conf | |||
chown 0:0 /var/db/tor | |||
service ntpd start | |||
service tor start |
@@ -0,0 +1,2 @@ | |||
pyyaml | |||
pyqrcode |
@@ -0,0 +1,2 @@ | |||
[metadata] | |||
description-file = README.md |
@@ -0,0 +1,32 @@ | |||
#!/usr/bin/env python | |||
from setuptools import setup | |||
VERSION = '0.1.0' | |||
DOWNLOAD_URL = 'https://github.com/sporestack/sporestack-python/tarball/{}' | |||
setup( | |||
name='sporestack', | |||
version=VERSION, | |||
author='Teran McKinney', | |||
author_email='sega01@go-beyond.org', | |||
description='Create servers for Bitcoin. sporestack.com library.', | |||
keywords=['bitcoin', 'servers', 'infrastructure'], | |||
license='Unlicense', | |||
url='http://sporestack.com/', | |||
download_url=DOWNLOAD_URL.format(VERSION), | |||
packages=['sporestack'], | |||
setup_requires=[ | |||
'flake8' | |||
], | |||
install_requires=[ | |||
'pyyaml', | |||
'pyqrcode' | |||
], | |||
entry_points={ | |||
'console_scripts': [ | |||
'nodemeup = sporestack.nodemeup:fakemain' | |||
] | |||
} | |||
) |
@@ -0,0 +1,87 @@ | |||
""" | |||
sporestack.com Python API interface | |||
Released into the public domain. | |||
""" | |||
from collections import namedtuple | |||
from warnings import warn | |||
from base64 import b64encode | |||
import json | |||
import urllib2 | |||
import yaml | |||
ENDPOINT = 'http://sporestack.com/node' | |||
# ENDPOINT = 'http://localhost:8082/node' | |||
TIMEOUT = 30 | |||
def node(days, | |||
unique, | |||
sshkey=None, | |||
cloudinit=None, | |||
startupscript=None, | |||
osid=None, | |||
dcid=None, | |||
flavor=None, | |||
endpoint=ENDPOINT): | |||
""" | |||
Returns a node | |||
Returns: | |||
node.payment_status | |||
node.end_of_life | |||
node.ip6 | |||
node.ip4 | |||
""" | |||
pre_data = {'days': days, | |||
'unique': unique} | |||
# There must be a better way to do this... | |||
if cloudinit is not None: | |||
b64_cloudinit = b64encode(cloudinit) | |||
pre_data['cloudinit'] = b64_cloudinit | |||
if sshkey is not None: | |||
pre_data['sshkey'] = sshkey | |||
if startupscript is not None: | |||
pre_data['startupscript'] = startupscript | |||
if osid is not None: | |||
pre_data['osid'] = osid | |||
if dcid is not None: | |||
pre_data['dcid'] = dcid | |||
if flavor is not None: | |||
pre_data['flavor'] = flavor | |||
post_data = json.dumps(pre_data) | |||
try: | |||
http_return = urllib2.urlopen(endpoint, | |||
data=post_data, | |||
timeout=TIMEOUT) | |||
except urllib2.HTTPError as http_error: | |||
if http_error.code == 400: | |||
# Throw exception with output from endpoint.. | |||
raise Exception(http_error.read()) | |||
else: | |||
raise | |||
if http_return.getcode() == 200: | |||
data = yaml.safe_load(http_return.read()) | |||
if 'deprecated' in data: | |||
if data['deprecated'] is not False: | |||
warn(str(data['deprecated']), DeprecationWarning) | |||
node = namedtuple('node', | |||
data.keys()) | |||
node.end_of_life = data['end_of_life'] | |||
node.payment_status = data['payment_status'] | |||
node.creation_status = data['creation_status'] | |||
node.address = data['address'] | |||
node.satoshis = data['satoshis'] | |||
node.ip4 = data['ip4'] | |||
node.ip6 = data['ip6'] | |||
return node | |||
else: | |||
raise Exception('Fatal issue with sporestack.') |
@@ -0,0 +1,97 @@ | |||
""" | |||
Build a server and SSH into it. Server will last for a day. | |||
""" | |||
import argparse | |||
from uuid import uuid4 as random_uuid | |||
from time import sleep | |||
import os | |||
from socket import create_connection | |||
import pyqrcode | |||
import sporestack | |||
node_uuid = str(random_uuid()) | |||
ssh_key_path = '{}/.ssh/id_rsa.pub'.format(os.getenv('HOME')) | |||
with open(ssh_key_path) as ssh_key_file: | |||
sshkey = ssh_key_file.read() | |||
parser = argparse.ArgumentParser() | |||
parser.add_argument('--osid', help='Operating System ID ' | |||
'230: FreeBSD 11, 215: Ubuntu 16.04, ' | |||
'179: CoreOS Stable, 193: Debian 8, ' | |||
'167: CentOS 7', | |||
type=int) | |||
parser.add_argument('--dcid', help='Datacenter ID ' | |||
'3: Dallas, 2: Chicago, ' | |||
'12: San Jose, 5: Los Angeles, ' | |||
'6: Atlanta, 1: New Jersey, ' | |||
'39: Miami, 4: Seattle', | |||
type=int) | |||
args = parser.parse_args() | |||
while True: | |||
node = sporestack.node(days=1, | |||
sshkey=sshkey, | |||
unique=node_uuid, | |||
osid=args.osid, | |||
dcid=args.dcid) | |||
if node.payment_status is False: | |||
amount = "{0:.8f}".format(node.satoshis * | |||
0.00000001) | |||
uri = 'bitcoin:{}?amount={}'.format(node.address, amount) | |||
qr = pyqrcode.create(uri) | |||
print(qr.terminal()) | |||
print(uri) | |||
print('Pay with Bitcoin. Resize your terminal if QR code is unclear.') | |||
else: | |||
print('Node being built...') | |||
if node.creation_status is True: | |||
break | |||
sleep(5) | |||
print('Waiting for node to come online.') | |||
ipaddress = None | |||
while True: | |||
for ip in [node.ip6, node.ip4]: | |||
try: | |||
socket = create_connection((ip, 22), timeout=2) | |||
socket.close() | |||
ipaddress = ip | |||
break | |||
except: | |||
print('Waiting for node to come online.') | |||
sleep(2) | |||
if ipaddress is not None: | |||
break | |||
banner = ''' | |||
UUID: {} | |||
IPv6: {} | |||
IPv4: {} | |||
End of Life: {} | |||
'''.format(node_uuid, | |||
node.ip6, | |||
node.ip4, | |||
node.end_of_life) | |||
print(banner) | |||
command = ('ssh root@{} -p 22 -oStrictHostKeyChecking=no' | |||
' -oUserKnownHostsFile=/dev/null'.format(ipaddress)) | |||
os.system(command) | |||
print(banner) | |||
def fakemain(): | |||
''' | |||
NOOP | |||
I need to fix this. | |||
''' | |||
a = 0 |
@@ -0,0 +1,35 @@ | |||
""" | |||
Just some basic tests. | |||
Kinda broken. | |||
""" | |||
from uuid import uuid4 as random_uuid | |||
import os | |||
import sporestack | |||
script = """#!/bin/sh | |||
date > /date | |||
""" | |||
new_uuid = str(random_uuid()) | |||
ssh_key_path = '{}/.ssh/id_rsa.pub'.format(os.getenv('HOME')) | |||
with open(ssh_key_path) as ssh_key_file: | |||
sshkey = ssh_key_file.read() | |||
for unique in ['3b69d7c9-ad4d-4d31-b04e-b224f02de4d4', | |||
'4a79a54b-b763-4a52-9d1e-d0d72ec7f67d', | |||
new_uuid]: | |||
node = sporestack.node(days=1, | |||
sshkey=sshkey, | |||
unique=unique, | |||
cloudinit=script, | |||
startupscript=script) | |||
print('Payment status: ' + str(node.payment_status)) | |||
print('Creation status: ' + str(node.creation_status)) | |||
print(node.address) | |||
print(node.satoshis) | |||
print(node.ip6) | |||
print(node.ip4) |
@@ -0,0 +1,5 @@ | |||
#!/bin/sh | |||
set -e | |||
python -W all -W error coinfee_test.py |