Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/src/foundation/python-packages/pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,5 +108,5 @@ cryptography = { appliances = ["server"] }
jinja2 = { appliances = ["server"], bootstrap = true }
markupsafe = { appliances = ["server"] }
pycparser = { appliances = ["server"] }
pyyaml = { appliances = ["server"], bootstrap = true }
pyyaml = { appliances = ["server", "client"], bootstrap = true }
six = { appliances = ["server"] }
69 changes: 51 additions & 18 deletions common/src/stack/mq/pylib/mq/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,8 @@
import socket
import sys
import os
import yaml
from pathlib import Path

# We need the "ports" class when we are inside the installer, but don't need to
# setup and zmq based services. The alternative is to add zmq and dependencies
Expand All@@ -23,26 +25,57 @@



class ports:
class PortsMeta(type):
"""
Socket port numbers used by the Stack Message Queue daemons.

:var publish: UDP socket service for publishing a message
:var subscribe: zmq.SUB socket for subscribing to a channel
:var control: TCP socket service for enabling/disabling channel propagation
:publish: UDP socket service for publishing a message
:subscribe: zmq.SUB socket for subscribing to a channel
:control: TCP socket service for enabling/disabling channel propagation
"""
publish = 5000
subscribe = 5001
control = 5002

# Stacki settings file location
# and default ports
SETTINGS = Path('/opt/stack/etc/stacki.yml')
pub_port = 5000
sub_port = 5001
con_port = 5002

def load_settings(cls):
config = {}
if cls.SETTINGS.is_file():
with cls.SETTINGS.open() as f:
config = yaml.safe_load(f)
return config

@property
def publish(cls):
config = cls.load_settings()
port = int(config.get('smq.pub.port', cls.pub_port))
return port

@property
def subscribe(cls):
config = cls.load_settings()
port = int(config.get('smq.sub.port', cls.sub_port))
return port

@property
def control(cls):
config = cls.load_settings()
port = int(config.get('smq.control.port', cls.con_port))
return port

class ports(metaclass=PortsMeta):
pass

class Message():
"""
Stack Message Queue Message

A Message is composed of header fields and the *message* text body. For many
applications only body is manipulated and other fields are controlled by
lower software levels.
lower software levels.

For simple Messages the *message* body can be a string. For more complex Messages
the body should be a json encoded python dictionary.
Expand DownExpand Up@@ -87,7 +120,7 @@ def __init__(self, payload=None, *, message=None, channel=None, hops=None, ttl=N

# JSON does not override parameters, this allows loading an
# existing Message and overwriting some of the fields

self.channel = channel if channel else msg.get('channel')
self.id = id if id else msg.get('id')
self.payload = payload if payload else msg.get('payload')
Expand DownExpand Up@@ -160,7 +193,7 @@ def getPayload(self):
def setPayload(self, payload):
"""
Sets the payload text

:param payload: text
:type payload: string
"""
Expand All@@ -169,7 +202,7 @@ def setPayload(self, payload):

def getHops(self):
"""
:returns: number of software hops
:returns: number of software hops
"""
return self.hops

Expand All@@ -189,7 +222,7 @@ def setSource(self, addr):
"""
Set the source host address. This address can be a hostname
or an IP Address.

:param addr: source address
:type addr: string
"""
Expand DownExpand Up@@ -234,9 +267,9 @@ def setID(self, id):
def addHop(self):
"""
Increments the hop count for the :class:`Message`. A hop is
defined as a software hop not a physical network hop.
defined as a software hop not a physical network hop.
Every time an application receives and retransmits a message the
hop should be incremented.
hop should be incremented.
This value is used to debugging.
"""
self.hops += 1
Expand DownExpand Up@@ -289,12 +322,12 @@ def unsubscribe(self, channel):
:type channel: string
"""
self.sub.setsockopt_string(zmq.UNSUBSCRIBE, channel)

def run(self):
while True:
try:
channel, payload = self.sub.recv_multipart()
msg = Message(message=payload.decode(),
msg = Message(message=payload.decode(),
channel=channel.decode())
except:
continue
Expand DownExpand Up@@ -341,10 +374,10 @@ def run(self):
#
# Note the callback() always pushes data as
# stack.mq.Message objects. This is the only
# part of the code where we handle receiving
# part of the code where we handle receiving
# unstructured data.
#
# Design point here was to keep the clients
# Design point here was to keep the clients
# simple so we don't need an API to write to
# the message queue.

Expand Down
5 changes: 5 additions & 0 deletions common/src/stack/pylib/stack/settings.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,11 @@
# these settings control the starting points for discover-nodes (nee insert ethers)
discovery.base.rack: '0'
discovery.base.rank: '0'

# smq ports
smq.pub.port: '5000'
smq.sub.port: '5001'
smq.control.port: '5002'
'''

def get_settings():
Expand Down
11 changes: 9 additions & 2 deletions redhat/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ for o in stack.api.Call('list cart'):
</stack:eval>
</stack:native>

<!-- give me some status -->
<!-- give me some status -->

<stack:script stack:stage="install-pre">
/opt/stack/bin/stacki-status.py Running preinstall
Expand All@@ -52,9 +52,16 @@ include ld.so.conf.d/*.conf
/opt/stack/bin/stacki-status.py install complete rebooting
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>

<stack:script stack:cond="release == 'redhat7'" stack:stage="install-post">
cp /run/install/tmp/stack.conf /tmp/stack.conf
</stack:script>

</stack:stack>
</stack:stack>

7 changes: 7 additions & 0 deletions sles/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,13 @@ rm -f /etc/zypp/repos.d/*
<stack:report stack:name="host.repo">&hostname;</stack:report>
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>


<stack:script stack:stage="install-post" stack:cond="release == 'sles12'">
<stack:report stack:name="host.interface">&hostname;</stack:report>
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/src/foundation/python-packages/pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,5 +108,5 @@ cryptography = { appliances = ["server"] }
jinja2 = { appliances = ["server"], bootstrap = true }
markupsafe = { appliances = ["server"] }
pycparser = { appliances = ["server"] }
pyyaml = { appliances = ["server"], bootstrap = true }
pyyaml = { appliances = ["server", "client"], bootstrap = true }
six = { appliances = ["server"] }
69 changes: 51 additions & 18 deletions common/src/stack/mq/pylib/mq/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,8 @@
import socket
import sys
import os
import yaml
from pathlib import Path

# We need the "ports" class when we are inside the installer, but don't need to
# setup and zmq based services. The alternative is to add zmq and dependencies
Expand All@@ -23,26 +25,57 @@



class ports:
class PortsMeta(type):
"""
Socket port numbers used by the Stack Message Queue daemons.

:var publish: UDP socket service for publishing a message
:var subscribe: zmq.SUB socket for subscribing to a channel
:var control: TCP socket service for enabling/disabling channel propagation
:publish: UDP socket service for publishing a message
:subscribe: zmq.SUB socket for subscribing to a channel
:control: TCP socket service for enabling/disabling channel propagation
"""
publish = 5000
subscribe = 5001
control = 5002

# Stacki settings file location
# and default ports
SETTINGS = Path('/opt/stack/etc/stacki.yml')
pub_port = 5000
sub_port = 5001
con_port = 5002

def load_settings(cls):
config = {}
if cls.SETTINGS.is_file():
with cls.SETTINGS.open() as f:
config = yaml.safe_load(f)
return config

@property
def publish(cls):
config = cls.load_settings()
port = int(config.get('smq.pub.port', cls.pub_port))
return port

@property
def subscribe(cls):
config = cls.load_settings()
port = int(config.get('smq.sub.port', cls.sub_port))
return port

@property
def control(cls):
config = cls.load_settings()
port = int(config.get('smq.control.port', cls.con_port))
return port

class ports(metaclass=PortsMeta):
pass

class Message():
"""
Stack Message Queue Message

A Message is composed of header fields and the *message* text body. For many
applications only body is manipulated and other fields are controlled by
lower software levels.
lower software levels.

For simple Messages the *message* body can be a string. For more complex Messages
the body should be a json encoded python dictionary.
Expand DownExpand Up@@ -87,7 +120,7 @@ def __init__(self, payload=None, *, message=None, channel=None, hops=None, ttl=N

# JSON does not override parameters, this allows loading an
# existing Message and overwriting some of the fields

self.channel = channel if channel else msg.get('channel')
self.id = id if id else msg.get('id')
self.payload = payload if payload else msg.get('payload')
Expand DownExpand Up@@ -160,7 +193,7 @@ def getPayload(self):
def setPayload(self, payload):
"""
Sets the payload text

:param payload: text
:type payload: string
"""
Expand All@@ -169,7 +202,7 @@ def setPayload(self, payload):

def getHops(self):
"""
:returns: number of software hops
:returns: number of software hops
"""
return self.hops

Expand All@@ -189,7 +222,7 @@ def setSource(self, addr):
"""
Set the source host address. This address can be a hostname
or an IP Address.

:param addr: source address
:type addr: string
"""
Expand DownExpand Up@@ -234,9 +267,9 @@ def setID(self, id):
def addHop(self):
"""
Increments the hop count for the :class:`Message`. A hop is
defined as a software hop not a physical network hop.
defined as a software hop not a physical network hop.
Every time an application receives and retransmits a message the
hop should be incremented.
hop should be incremented.
This value is used to debugging.
"""
self.hops += 1
Expand DownExpand Up@@ -289,12 +322,12 @@ def unsubscribe(self, channel):
:type channel: string
"""
self.sub.setsockopt_string(zmq.UNSUBSCRIBE, channel)

def run(self):
while True:
try:
channel, payload = self.sub.recv_multipart()
msg = Message(message=payload.decode(),
msg = Message(message=payload.decode(),
channel=channel.decode())
except:
continue
Expand DownExpand Up@@ -341,10 +374,10 @@ def run(self):
#
# Note the callback() always pushes data as
# stack.mq.Message objects. This is the only
# part of the code where we handle receiving
# part of the code where we handle receiving
# unstructured data.
#
# Design point here was to keep the clients
# Design point here was to keep the clients
# simple so we don't need an API to write to
# the message queue.

Expand Down
5 changes: 5 additions & 0 deletions common/src/stack/pylib/stack/settings.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,11 @@
# these settings control the starting points for discover-nodes (nee insert ethers)
discovery.base.rack: '0'
discovery.base.rank: '0'

# smq ports
smq.pub.port: '5000'
smq.sub.port: '5001'
smq.control.port: '5002'
'''

def get_settings():
Expand Down
11 changes: 9 additions & 2 deletions redhat/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ for o in stack.api.Call('list cart'):
</stack:eval>
</stack:native>

<!-- give me some status -->
<!-- give me some status -->

<stack:script stack:stage="install-pre">
/opt/stack/bin/stacki-status.py Running preinstall
Expand All@@ -52,9 +52,16 @@ include ld.so.conf.d/*.conf
/opt/stack/bin/stacki-status.py install complete rebooting
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>

<stack:script stack:cond="release == 'redhat7'" stack:stage="install-post">
cp /run/install/tmp/stack.conf /tmp/stack.conf
</stack:script>

</stack:stack>
</stack:stack>

7 changes: 7 additions & 0 deletions sles/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,13 @@ rm -f /etc/zypp/repos.d/*
<stack:report stack:name="host.repo">&hostname;</stack:report>
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>


<stack:script stack:stage="install-post" stack:cond="release == 'sles12'">
<stack:report stack:name="host.interface">&hostname;</stack:report>
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/src/foundation/python-packages/pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,5 +108,5 @@ cryptography = { appliances = ["server"] }
jinja2 = { appliances = ["server"], bootstrap = true }
markupsafe = { appliances = ["server"] }
pycparser = { appliances = ["server"] }
pyyaml = { appliances = ["server"], bootstrap = true }
pyyaml = { appliances = ["server", "client"], bootstrap = true }
six = { appliances = ["server"] }
69 changes: 51 additions & 18 deletions common/src/stack/mq/pylib/mq/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,8 @@
import socket
import sys
import os
import yaml
from pathlib import Path

# We need the "ports" class when we are inside the installer, but don't need to
# setup and zmq based services. The alternative is to add zmq and dependencies
Expand All@@ -23,26 +25,57 @@



class ports:
class PortsMeta(type):
"""
Socket port numbers used by the Stack Message Queue daemons.

:var publish: UDP socket service for publishing a message
:var subscribe: zmq.SUB socket for subscribing to a channel
:var control: TCP socket service for enabling/disabling channel propagation
:publish: UDP socket service for publishing a message
:subscribe: zmq.SUB socket for subscribing to a channel
:control: TCP socket service for enabling/disabling channel propagation
"""
publish = 5000
subscribe = 5001
control = 5002

# Stacki settings file location
# and default ports
SETTINGS = Path('/opt/stack/etc/stacki.yml')
pub_port = 5000
sub_port = 5001
con_port = 5002

def load_settings(cls):
config = {}
if cls.SETTINGS.is_file():
with cls.SETTINGS.open() as f:
config = yaml.safe_load(f)
return config

@property
def publish(cls):
config = cls.load_settings()
port = int(config.get('smq.pub.port', cls.pub_port))
return port

@property
def subscribe(cls):
config = cls.load_settings()
port = int(config.get('smq.sub.port', cls.sub_port))
return port

@property
def control(cls):
config = cls.load_settings()
port = int(config.get('smq.control.port', cls.con_port))
return port

class ports(metaclass=PortsMeta):
pass

class Message():
"""
Stack Message Queue Message

A Message is composed of header fields and the *message* text body. For many
applications only body is manipulated and other fields are controlled by
lower software levels.
lower software levels.

For simple Messages the *message* body can be a string. For more complex Messages
the body should be a json encoded python dictionary.
Expand DownExpand Up@@ -87,7 +120,7 @@ def __init__(self, payload=None, *, message=None, channel=None, hops=None, ttl=N

# JSON does not override parameters, this allows loading an
# existing Message and overwriting some of the fields

self.channel = channel if channel else msg.get('channel')
self.id = id if id else msg.get('id')
self.payload = payload if payload else msg.get('payload')
Expand DownExpand Up@@ -160,7 +193,7 @@ def getPayload(self):
def setPayload(self, payload):
"""
Sets the payload text

:param payload: text
:type payload: string
"""
Expand All@@ -169,7 +202,7 @@ def setPayload(self, payload):

def getHops(self):
"""
:returns: number of software hops
:returns: number of software hops
"""
return self.hops

Expand All@@ -189,7 +222,7 @@ def setSource(self, addr):
"""
Set the source host address. This address can be a hostname
or an IP Address.

:param addr: source address
:type addr: string
"""
Expand DownExpand Up@@ -234,9 +267,9 @@ def setID(self, id):
def addHop(self):
"""
Increments the hop count for the :class:`Message`. A hop is
defined as a software hop not a physical network hop.
defined as a software hop not a physical network hop.
Every time an application receives and retransmits a message the
hop should be incremented.
hop should be incremented.
This value is used to debugging.
"""
self.hops += 1
Expand DownExpand Up@@ -289,12 +322,12 @@ def unsubscribe(self, channel):
:type channel: string
"""
self.sub.setsockopt_string(zmq.UNSUBSCRIBE, channel)

def run(self):
while True:
try:
channel, payload = self.sub.recv_multipart()
msg = Message(message=payload.decode(),
msg = Message(message=payload.decode(),
channel=channel.decode())
except:
continue
Expand DownExpand Up@@ -341,10 +374,10 @@ def run(self):
#
# Note the callback() always pushes data as
# stack.mq.Message objects. This is the only
# part of the code where we handle receiving
# part of the code where we handle receiving
# unstructured data.
#
# Design point here was to keep the clients
# Design point here was to keep the clients
# simple so we don't need an API to write to
# the message queue.

Expand Down
5 changes: 5 additions & 0 deletions common/src/stack/pylib/stack/settings.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,11 @@
# these settings control the starting points for discover-nodes (nee insert ethers)
discovery.base.rack: '0'
discovery.base.rank: '0'

# smq ports
smq.pub.port: '5000'
smq.sub.port: '5001'
smq.control.port: '5002'
'''

def get_settings():
Expand Down
11 changes: 9 additions & 2 deletions redhat/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ for o in stack.api.Call('list cart'):
</stack:eval>
</stack:native>

<!-- give me some status -->
<!-- give me some status -->

<stack:script stack:stage="install-pre">
/opt/stack/bin/stacki-status.py Running preinstall
Expand All@@ -52,9 +52,16 @@ include ld.so.conf.d/*.conf
/opt/stack/bin/stacki-status.py install complete rebooting
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>

<stack:script stack:cond="release == 'redhat7'" stack:stage="install-post">
cp /run/install/tmp/stack.conf /tmp/stack.conf
</stack:script>

</stack:stack>
</stack:stack>

7 changes: 7 additions & 0 deletions sles/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,13 @@ rm -f /etc/zypp/repos.d/*
<stack:report stack:name="host.repo">&hostname;</stack:report>
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>


<stack:script stack:stage="install-post" stack:cond="release == 'sles12'">
<stack:report stack:name="host.interface">&hostname;</stack:report>
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/src/foundation/python-packages/pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,5 +108,5 @@ cryptography = { appliances = ["server"] }
jinja2 = { appliances = ["server"], bootstrap = true }
markupsafe = { appliances = ["server"] }
pycparser = { appliances = ["server"] }
pyyaml = { appliances = ["server"], bootstrap = true }
pyyaml = { appliances = ["server", "client"], bootstrap = true }
six = { appliances = ["server"] }
69 changes: 51 additions & 18 deletions common/src/stack/mq/pylib/mq/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,8 @@
import socket
import sys
import os
import yaml
from pathlib import Path

# We need the "ports" class when we are inside the installer, but don't need to
# setup and zmq based services. The alternative is to add zmq and dependencies
Expand All@@ -23,26 +25,57 @@



class ports:
class PortsMeta(type):
"""
Socket port numbers used by the Stack Message Queue daemons.

:var publish: UDP socket service for publishing a message
:var subscribe: zmq.SUB socket for subscribing to a channel
:var control: TCP socket service for enabling/disabling channel propagation
:publish: UDP socket service for publishing a message
:subscribe: zmq.SUB socket for subscribing to a channel
:control: TCP socket service for enabling/disabling channel propagation
"""
publish = 5000
subscribe = 5001
control = 5002

# Stacki settings file location
# and default ports
SETTINGS = Path('/opt/stack/etc/stacki.yml')
pub_port = 5000
sub_port = 5001
con_port = 5002

def load_settings(cls):
config = {}
if cls.SETTINGS.is_file():
with cls.SETTINGS.open() as f:
config = yaml.safe_load(f)
return config

@property
def publish(cls):
config = cls.load_settings()
port = int(config.get('smq.pub.port', cls.pub_port))
return port

@property
def subscribe(cls):
config = cls.load_settings()
port = int(config.get('smq.sub.port', cls.sub_port))
return port

@property
def control(cls):
config = cls.load_settings()
port = int(config.get('smq.control.port', cls.con_port))
return port

class ports(metaclass=PortsMeta):
pass

class Message():
"""
Stack Message Queue Message

A Message is composed of header fields and the *message* text body. For many
applications only body is manipulated and other fields are controlled by
lower software levels.
lower software levels.

For simple Messages the *message* body can be a string. For more complex Messages
the body should be a json encoded python dictionary.
Expand DownExpand Up@@ -87,7 +120,7 @@ def __init__(self, payload=None, *, message=None, channel=None, hops=None, ttl=N

# JSON does not override parameters, this allows loading an
# existing Message and overwriting some of the fields

self.channel = channel if channel else msg.get('channel')
self.id = id if id else msg.get('id')
self.payload = payload if payload else msg.get('payload')
Expand DownExpand Up@@ -160,7 +193,7 @@ def getPayload(self):
def setPayload(self, payload):
"""
Sets the payload text

:param payload: text
:type payload: string
"""
Expand All@@ -169,7 +202,7 @@ def setPayload(self, payload):

def getHops(self):
"""
:returns: number of software hops
:returns: number of software hops
"""
return self.hops

Expand All@@ -189,7 +222,7 @@ def setSource(self, addr):
"""
Set the source host address. This address can be a hostname
or an IP Address.

:param addr: source address
:type addr: string
"""
Expand DownExpand Up@@ -234,9 +267,9 @@ def setID(self, id):
def addHop(self):
"""
Increments the hop count for the :class:`Message`. A hop is
defined as a software hop not a physical network hop.
defined as a software hop not a physical network hop.
Every time an application receives and retransmits a message the
hop should be incremented.
hop should be incremented.
This value is used to debugging.
"""
self.hops += 1
Expand DownExpand Up@@ -289,12 +322,12 @@ def unsubscribe(self, channel):
:type channel: string
"""
self.sub.setsockopt_string(zmq.UNSUBSCRIBE, channel)

def run(self):
while True:
try:
channel, payload = self.sub.recv_multipart()
msg = Message(message=payload.decode(),
msg = Message(message=payload.decode(),
channel=channel.decode())
except:
continue
Expand DownExpand Up@@ -341,10 +374,10 @@ def run(self):
#
# Note the callback() always pushes data as
# stack.mq.Message objects. This is the only
# part of the code where we handle receiving
# part of the code where we handle receiving
# unstructured data.
#
# Design point here was to keep the clients
# Design point here was to keep the clients
# simple so we don't need an API to write to
# the message queue.

Expand Down
5 changes: 5 additions & 0 deletions common/src/stack/pylib/stack/settings.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,11 @@
# these settings control the starting points for discover-nodes (nee insert ethers)
discovery.base.rack: '0'
discovery.base.rank: '0'

# smq ports
smq.pub.port: '5000'
smq.sub.port: '5001'
smq.control.port: '5002'
'''

def get_settings():
Expand Down
11 changes: 9 additions & 2 deletions redhat/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ for o in stack.api.Call('list cart'):
</stack:eval>
</stack:native>

<!-- give me some status -->
<!-- give me some status -->

<stack:script stack:stage="install-pre">
/opt/stack/bin/stacki-status.py Running preinstall
Expand All@@ -52,9 +52,16 @@ include ld.so.conf.d/*.conf
/opt/stack/bin/stacki-status.py install complete rebooting
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>

<stack:script stack:cond="release == 'redhat7'" stack:stage="install-post">
cp /run/install/tmp/stack.conf /tmp/stack.conf
</stack:script>

</stack:stack>
</stack:stack>

7 changes: 7 additions & 0 deletions sles/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,13 @@ rm -f /etc/zypp/repos.d/*
<stack:report stack:name="host.repo">&hostname;</stack:report>
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>


<stack:script stack:stage="install-post" stack:cond="release == 'sles12'">
<stack:report stack:name="host.interface">&hostname;</stack:report>
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/src/foundation/python-packages/pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,5 +108,5 @@ cryptography = { appliances = ["server"] }
jinja2 = { appliances = ["server"], bootstrap = true }
markupsafe = { appliances = ["server"] }
pycparser = { appliances = ["server"] }
pyyaml = { appliances = ["server"], bootstrap = true }
pyyaml = { appliances = ["server", "client"], bootstrap = true }
six = { appliances = ["server"] }
69 changes: 51 additions & 18 deletions common/src/stack/mq/pylib/mq/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,8 @@
import socket
import sys
import os
import yaml
from pathlib import Path

# We need the "ports" class when we are inside the installer, but don't need to
# setup and zmq based services. The alternative is to add zmq and dependencies
Expand All@@ -23,26 +25,57 @@



class ports:
class PortsMeta(type):
"""
Socket port numbers used by the Stack Message Queue daemons.

:var publish: UDP socket service for publishing a message
:var subscribe: zmq.SUB socket for subscribing to a channel
:var control: TCP socket service for enabling/disabling channel propagation
:publish: UDP socket service for publishing a message
:subscribe: zmq.SUB socket for subscribing to a channel
:control: TCP socket service for enabling/disabling channel propagation
"""
publish = 5000
subscribe = 5001
control = 5002

# Stacki settings file location
# and default ports
SETTINGS = Path('/opt/stack/etc/stacki.yml')
pub_port = 5000
sub_port = 5001
con_port = 5002

def load_settings(cls):
config = {}
if cls.SETTINGS.is_file():
with cls.SETTINGS.open() as f:
config = yaml.safe_load(f)
return config

@property
def publish(cls):
config = cls.load_settings()
port = int(config.get('smq.pub.port', cls.pub_port))
return port

@property
def subscribe(cls):
config = cls.load_settings()
port = int(config.get('smq.sub.port', cls.sub_port))
return port

@property
def control(cls):
config = cls.load_settings()
port = int(config.get('smq.control.port', cls.con_port))
return port

class ports(metaclass=PortsMeta):
pass

class Message():
"""
Stack Message Queue Message

A Message is composed of header fields and the *message* text body. For many
applications only body is manipulated and other fields are controlled by
lower software levels.
lower software levels.

For simple Messages the *message* body can be a string. For more complex Messages
the body should be a json encoded python dictionary.
Expand DownExpand Up@@ -87,7 +120,7 @@ def __init__(self, payload=None, *, message=None, channel=None, hops=None, ttl=N

# JSON does not override parameters, this allows loading an
# existing Message and overwriting some of the fields

self.channel = channel if channel else msg.get('channel')
self.id = id if id else msg.get('id')
self.payload = payload if payload else msg.get('payload')
Expand DownExpand Up@@ -160,7 +193,7 @@ def getPayload(self):
def setPayload(self, payload):
"""
Sets the payload text

:param payload: text
:type payload: string
"""
Expand All@@ -169,7 +202,7 @@ def setPayload(self, payload):

def getHops(self):
"""
:returns: number of software hops
:returns: number of software hops
"""
return self.hops

Expand All@@ -189,7 +222,7 @@ def setSource(self, addr):
"""
Set the source host address. This address can be a hostname
or an IP Address.

:param addr: source address
:type addr: string
"""
Expand DownExpand Up@@ -234,9 +267,9 @@ def setID(self, id):
def addHop(self):
"""
Increments the hop count for the :class:`Message`. A hop is
defined as a software hop not a physical network hop.
defined as a software hop not a physical network hop.
Every time an application receives and retransmits a message the
hop should be incremented.
hop should be incremented.
This value is used to debugging.
"""
self.hops += 1
Expand DownExpand Up@@ -289,12 +322,12 @@ def unsubscribe(self, channel):
:type channel: string
"""
self.sub.setsockopt_string(zmq.UNSUBSCRIBE, channel)

def run(self):
while True:
try:
channel, payload = self.sub.recv_multipart()
msg = Message(message=payload.decode(),
msg = Message(message=payload.decode(),
channel=channel.decode())
except:
continue
Expand DownExpand Up@@ -341,10 +374,10 @@ def run(self):
#
# Note the callback() always pushes data as
# stack.mq.Message objects. This is the only
# part of the code where we handle receiving
# part of the code where we handle receiving
# unstructured data.
#
# Design point here was to keep the clients
# Design point here was to keep the clients
# simple so we don't need an API to write to
# the message queue.

Expand Down
5 changes: 5 additions & 0 deletions common/src/stack/pylib/stack/settings.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,11 @@
# these settings control the starting points for discover-nodes (nee insert ethers)
discovery.base.rack: '0'
discovery.base.rank: '0'

# smq ports
smq.pub.port: '5000'
smq.sub.port: '5001'
smq.control.port: '5002'
'''

def get_settings():
Expand Down
11 changes: 9 additions & 2 deletions redhat/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ for o in stack.api.Call('list cart'):
</stack:eval>
</stack:native>

<!-- give me some status -->
<!-- give me some status -->

<stack:script stack:stage="install-pre">
/opt/stack/bin/stacki-status.py Running preinstall
Expand All@@ -52,9 +52,16 @@ include ld.so.conf.d/*.conf
/opt/stack/bin/stacki-status.py install complete rebooting
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>

<stack:script stack:cond="release == 'redhat7'" stack:stage="install-post">
cp /run/install/tmp/stack.conf /tmp/stack.conf
</stack:script>

</stack:stack>
</stack:stack>

7 changes: 7 additions & 0 deletions sles/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,13 @@ rm -f /etc/zypp/repos.d/*
<stack:report stack:name="host.repo">&hostname;</stack:report>
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>


<stack:script stack:stage="install-post" stack:cond="release == 'sles12'">
<stack:report stack:name="host.interface">&hostname;</stack:report>
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/src/foundation/python-packages/pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,5 +108,5 @@ cryptography = { appliances = ["server"] }
jinja2 = { appliances = ["server"], bootstrap = true }
markupsafe = { appliances = ["server"] }
pycparser = { appliances = ["server"] }
pyyaml = { appliances = ["server"], bootstrap = true }
pyyaml = { appliances = ["server", "client"], bootstrap = true }
six = { appliances = ["server"] }
69 changes: 51 additions & 18 deletions common/src/stack/mq/pylib/mq/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,8 @@
import socket
import sys
import os
import yaml
from pathlib import Path

# We need the "ports" class when we are inside the installer, but don't need to
# setup and zmq based services. The alternative is to add zmq and dependencies
Expand All@@ -23,26 +25,57 @@



class ports:
class PortsMeta(type):
"""
Socket port numbers used by the Stack Message Queue daemons.

:var publish: UDP socket service for publishing a message
:var subscribe: zmq.SUB socket for subscribing to a channel
:var control: TCP socket service for enabling/disabling channel propagation
:publish: UDP socket service for publishing a message
:subscribe: zmq.SUB socket for subscribing to a channel
:control: TCP socket service for enabling/disabling channel propagation
"""
publish = 5000
subscribe = 5001
control = 5002

# Stacki settings file location
# and default ports
SETTINGS = Path('/opt/stack/etc/stacki.yml')
pub_port = 5000
sub_port = 5001
con_port = 5002

def load_settings(cls):
config = {}
if cls.SETTINGS.is_file():
with cls.SETTINGS.open() as f:
config = yaml.safe_load(f)
return config

@property
def publish(cls):
config = cls.load_settings()
port = int(config.get('smq.pub.port', cls.pub_port))
return port

@property
def subscribe(cls):
config = cls.load_settings()
port = int(config.get('smq.sub.port', cls.sub_port))
return port

@property
def control(cls):
config = cls.load_settings()
port = int(config.get('smq.control.port', cls.con_port))
return port

class ports(metaclass=PortsMeta):
pass

class Message():
"""
Stack Message Queue Message

A Message is composed of header fields and the *message* text body. For many
applications only body is manipulated and other fields are controlled by
lower software levels.
lower software levels.

For simple Messages the *message* body can be a string. For more complex Messages
the body should be a json encoded python dictionary.
Expand DownExpand Up@@ -87,7 +120,7 @@ def __init__(self, payload=None, *, message=None, channel=None, hops=None, ttl=N

# JSON does not override parameters, this allows loading an
# existing Message and overwriting some of the fields

self.channel = channel if channel else msg.get('channel')
self.id = id if id else msg.get('id')
self.payload = payload if payload else msg.get('payload')
Expand DownExpand Up@@ -160,7 +193,7 @@ def getPayload(self):
def setPayload(self, payload):
"""
Sets the payload text

:param payload: text
:type payload: string
"""
Expand All@@ -169,7 +202,7 @@ def setPayload(self, payload):

def getHops(self):
"""
:returns: number of software hops
:returns: number of software hops
"""
return self.hops

Expand All@@ -189,7 +222,7 @@ def setSource(self, addr):
"""
Set the source host address. This address can be a hostname
or an IP Address.

:param addr: source address
:type addr: string
"""
Expand DownExpand Up@@ -234,9 +267,9 @@ def setID(self, id):
def addHop(self):
"""
Increments the hop count for the :class:`Message`. A hop is
defined as a software hop not a physical network hop.
defined as a software hop not a physical network hop.
Every time an application receives and retransmits a message the
hop should be incremented.
hop should be incremented.
This value is used to debugging.
"""
self.hops += 1
Expand DownExpand Up@@ -289,12 +322,12 @@ def unsubscribe(self, channel):
:type channel: string
"""
self.sub.setsockopt_string(zmq.UNSUBSCRIBE, channel)

def run(self):
while True:
try:
channel, payload = self.sub.recv_multipart()
msg = Message(message=payload.decode(),
msg = Message(message=payload.decode(),
channel=channel.decode())
except:
continue
Expand DownExpand Up@@ -341,10 +374,10 @@ def run(self):
#
# Note the callback() always pushes data as
# stack.mq.Message objects. This is the only
# part of the code where we handle receiving
# part of the code where we handle receiving
# unstructured data.
#
# Design point here was to keep the clients
# Design point here was to keep the clients
# simple so we don't need an API to write to
# the message queue.

Expand Down
5 changes: 5 additions & 0 deletions common/src/stack/pylib/stack/settings.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,11 @@
# these settings control the starting points for discover-nodes (nee insert ethers)
discovery.base.rack: '0'
discovery.base.rank: '0'

# smq ports
smq.pub.port: '5000'
smq.sub.port: '5001'
smq.control.port: '5002'
'''

def get_settings():
Expand Down
11 changes: 9 additions & 2 deletions redhat/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ for o in stack.api.Call('list cart'):
</stack:eval>
</stack:native>

<!-- give me some status -->
<!-- give me some status -->

<stack:script stack:stage="install-pre">
/opt/stack/bin/stacki-status.py Running preinstall
Expand All@@ -52,9 +52,16 @@ include ld.so.conf.d/*.conf
/opt/stack/bin/stacki-status.py install complete rebooting
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>

<stack:script stack:cond="release == 'redhat7'" stack:stage="install-post">
cp /run/install/tmp/stack.conf /tmp/stack.conf
</stack:script>

</stack:stack>
</stack:stack>

7 changes: 7 additions & 0 deletions sles/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,13 @@ rm -f /etc/zypp/repos.d/*
<stack:report stack:name="host.repo">&hostname;</stack:report>
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>


<stack:script stack:stage="install-post" stack:cond="release == 'sles12'">
<stack:report stack:name="host.interface">&hostname;</stack:report>
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/src/foundation/python-packages/pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,5 +108,5 @@ cryptography = { appliances = ["server"] }
jinja2 = { appliances = ["server"], bootstrap = true }
markupsafe = { appliances = ["server"] }
pycparser = { appliances = ["server"] }
pyyaml = { appliances = ["server"], bootstrap = true }
pyyaml = { appliances = ["server", "client"], bootstrap = true }
six = { appliances = ["server"] }
69 changes: 51 additions & 18 deletions common/src/stack/mq/pylib/mq/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,8 @@
import socket
import sys
import os
import yaml
from pathlib import Path

# We need the "ports" class when we are inside the installer, but don't need to
# setup and zmq based services. The alternative is to add zmq and dependencies
Expand All@@ -23,26 +25,57 @@



class ports:
class PortsMeta(type):
"""
Socket port numbers used by the Stack Message Queue daemons.

:var publish: UDP socket service for publishing a message
:var subscribe: zmq.SUB socket for subscribing to a channel
:var control: TCP socket service for enabling/disabling channel propagation
:publish: UDP socket service for publishing a message
:subscribe: zmq.SUB socket for subscribing to a channel
:control: TCP socket service for enabling/disabling channel propagation
"""
publish = 5000
subscribe = 5001
control = 5002

# Stacki settings file location
# and default ports
SETTINGS = Path('/opt/stack/etc/stacki.yml')
pub_port = 5000
sub_port = 5001
con_port = 5002

def load_settings(cls):
config = {}
if cls.SETTINGS.is_file():
with cls.SETTINGS.open() as f:
config = yaml.safe_load(f)
return config

@property
def publish(cls):
config = cls.load_settings()
port = int(config.get('smq.pub.port', cls.pub_port))
return port

@property
def subscribe(cls):
config = cls.load_settings()
port = int(config.get('smq.sub.port', cls.sub_port))
return port

@property
def control(cls):
config = cls.load_settings()
port = int(config.get('smq.control.port', cls.con_port))
return port

class ports(metaclass=PortsMeta):
pass

class Message():
"""
Stack Message Queue Message

A Message is composed of header fields and the *message* text body. For many
applications only body is manipulated and other fields are controlled by
lower software levels.
lower software levels.

For simple Messages the *message* body can be a string. For more complex Messages
the body should be a json encoded python dictionary.
Expand DownExpand Up@@ -87,7 +120,7 @@ def __init__(self, payload=None, *, message=None, channel=None, hops=None, ttl=N

# JSON does not override parameters, this allows loading an
# existing Message and overwriting some of the fields

self.channel = channel if channel else msg.get('channel')
self.id = id if id else msg.get('id')
self.payload = payload if payload else msg.get('payload')
Expand DownExpand Up@@ -160,7 +193,7 @@ def getPayload(self):
def setPayload(self, payload):
"""
Sets the payload text

:param payload: text
:type payload: string
"""
Expand All@@ -169,7 +202,7 @@ def setPayload(self, payload):

def getHops(self):
"""
:returns: number of software hops
:returns: number of software hops
"""
return self.hops

Expand All@@ -189,7 +222,7 @@ def setSource(self, addr):
"""
Set the source host address. This address can be a hostname
or an IP Address.

:param addr: source address
:type addr: string
"""
Expand DownExpand Up@@ -234,9 +267,9 @@ def setID(self, id):
def addHop(self):
"""
Increments the hop count for the :class:`Message`. A hop is
defined as a software hop not a physical network hop.
defined as a software hop not a physical network hop.
Every time an application receives and retransmits a message the
hop should be incremented.
hop should be incremented.
This value is used to debugging.
"""
self.hops += 1
Expand DownExpand Up@@ -289,12 +322,12 @@ def unsubscribe(self, channel):
:type channel: string
"""
self.sub.setsockopt_string(zmq.UNSUBSCRIBE, channel)

def run(self):
while True:
try:
channel, payload = self.sub.recv_multipart()
msg = Message(message=payload.decode(),
msg = Message(message=payload.decode(),
channel=channel.decode())
except:
continue
Expand DownExpand Up@@ -341,10 +374,10 @@ def run(self):
#
# Note the callback() always pushes data as
# stack.mq.Message objects. This is the only
# part of the code where we handle receiving
# part of the code where we handle receiving
# unstructured data.
#
# Design point here was to keep the clients
# Design point here was to keep the clients
# simple so we don't need an API to write to
# the message queue.

Expand Down
5 changes: 5 additions & 0 deletions common/src/stack/pylib/stack/settings.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,11 @@
# these settings control the starting points for discover-nodes (nee insert ethers)
discovery.base.rack: '0'
discovery.base.rank: '0'

# smq ports
smq.pub.port: '5000'
smq.sub.port: '5001'
smq.control.port: '5002'
'''

def get_settings():
Expand Down
11 changes: 9 additions & 2 deletions redhat/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ for o in stack.api.Call('list cart'):
</stack:eval>
</stack:native>

<!-- give me some status -->
<!-- give me some status -->

<stack:script stack:stage="install-pre">
/opt/stack/bin/stacki-status.py Running preinstall
Expand All@@ -52,9 +52,16 @@ include ld.so.conf.d/*.conf
/opt/stack/bin/stacki-status.py install complete rebooting
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>

<stack:script stack:cond="release == 'redhat7'" stack:stage="install-post">
cp /run/install/tmp/stack.conf /tmp/stack.conf
</stack:script>

</stack:stack>
</stack:stack>

7 changes: 7 additions & 0 deletions sles/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,13 @@ rm -f /etc/zypp/repos.d/*
<stack:report stack:name="host.repo">&hostname;</stack:report>
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>


<stack:script stack:stage="install-post" stack:cond="release == 'sles12'">
<stack:report stack:name="host.interface">&hostname;</stack:report>
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/src/foundation/python-packages/pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,5 +108,5 @@ cryptography = { appliances = ["server"] }
jinja2 = { appliances = ["server"], bootstrap = true }
markupsafe = { appliances = ["server"] }
pycparser = { appliances = ["server"] }
pyyaml = { appliances = ["server"], bootstrap = true }
pyyaml = { appliances = ["server", "client"], bootstrap = true }
six = { appliances = ["server"] }
69 changes: 51 additions & 18 deletions common/src/stack/mq/pylib/mq/__init__.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,8 @@
import socket
import sys
import os
import yaml
from pathlib import Path

# We need the "ports" class when we are inside the installer, but don't need to
# setup and zmq based services. The alternative is to add zmq and dependencies
Expand All@@ -23,26 +25,57 @@



class ports:
class PortsMeta(type):
"""
Socket port numbers used by the Stack Message Queue daemons.

:var publish: UDP socket service for publishing a message
:var subscribe: zmq.SUB socket for subscribing to a channel
:var control: TCP socket service for enabling/disabling channel propagation
:publish: UDP socket service for publishing a message
:subscribe: zmq.SUB socket for subscribing to a channel
:control: TCP socket service for enabling/disabling channel propagation
"""
publish = 5000
subscribe = 5001
control = 5002

# Stacki settings file location
# and default ports
SETTINGS = Path('/opt/stack/etc/stacki.yml')
pub_port = 5000
sub_port = 5001
con_port = 5002

def load_settings(cls):
config = {}
if cls.SETTINGS.is_file():
with cls.SETTINGS.open() as f:
config = yaml.safe_load(f)
return config

@property
def publish(cls):
config = cls.load_settings()
port = int(config.get('smq.pub.port', cls.pub_port))
return port

@property
def subscribe(cls):
config = cls.load_settings()
port = int(config.get('smq.sub.port', cls.sub_port))
return port

@property
def control(cls):
config = cls.load_settings()
port = int(config.get('smq.control.port', cls.con_port))
return port

class ports(metaclass=PortsMeta):
pass

class Message():
"""
Stack Message Queue Message

A Message is composed of header fields and the *message* text body. For many
applications only body is manipulated and other fields are controlled by
lower software levels.
lower software levels.

For simple Messages the *message* body can be a string. For more complex Messages
the body should be a json encoded python dictionary.
Expand DownExpand Up@@ -87,7 +120,7 @@ def __init__(self, payload=None, *, message=None, channel=None, hops=None, ttl=N

# JSON does not override parameters, this allows loading an
# existing Message and overwriting some of the fields

self.channel = channel if channel else msg.get('channel')
self.id = id if id else msg.get('id')
self.payload = payload if payload else msg.get('payload')
Expand DownExpand Up@@ -160,7 +193,7 @@ def getPayload(self):
def setPayload(self, payload):
"""
Sets the payload text

:param payload: text
:type payload: string
"""
Expand All@@ -169,7 +202,7 @@ def setPayload(self, payload):

def getHops(self):
"""
:returns: number of software hops
:returns: number of software hops
"""
return self.hops

Expand All@@ -189,7 +222,7 @@ def setSource(self, addr):
"""
Set the source host address. This address can be a hostname
or an IP Address.

:param addr: source address
:type addr: string
"""
Expand DownExpand Up@@ -234,9 +267,9 @@ def setID(self, id):
def addHop(self):
"""
Increments the hop count for the :class:`Message`. A hop is
defined as a software hop not a physical network hop.
defined as a software hop not a physical network hop.
Every time an application receives and retransmits a message the
hop should be incremented.
hop should be incremented.
This value is used to debugging.
"""
self.hops += 1
Expand DownExpand Up@@ -289,12 +322,12 @@ def unsubscribe(self, channel):
:type channel: string
"""
self.sub.setsockopt_string(zmq.UNSUBSCRIBE, channel)

def run(self):
while True:
try:
channel, payload = self.sub.recv_multipart()
msg = Message(message=payload.decode(),
msg = Message(message=payload.decode(),
channel=channel.decode())
except:
continue
Expand DownExpand Up@@ -341,10 +374,10 @@ def run(self):
#
# Note the callback() always pushes data as
# stack.mq.Message objects. This is the only
# part of the code where we handle receiving
# part of the code where we handle receiving
# unstructured data.
#
# Design point here was to keep the clients
# Design point here was to keep the clients
# simple so we don't need an API to write to
# the message queue.

Expand Down
5 changes: 5 additions & 0 deletions common/src/stack/pylib/stack/settings.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,11 @@
# these settings control the starting points for discover-nodes (nee insert ethers)
discovery.base.rack: '0'
discovery.base.rank: '0'

# smq ports
smq.pub.port: '5000'
smq.sub.port: '5001'
smq.control.port: '5002'
'''

def get_settings():
Expand Down
11 changes: 9 additions & 2 deletions redhat/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ for o in stack.api.Call('list cart'):
</stack:eval>
</stack:native>

<!-- give me some status -->
<!-- give me some status -->

<stack:script stack:stage="install-pre">
/opt/stack/bin/stacki-status.py Running preinstall
Expand All@@ -52,9 +52,16 @@ include ld.so.conf.d/*.conf
/opt/stack/bin/stacki-status.py install complete rebooting
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>

<stack:script stack:cond="release == 'redhat7'" stack:stage="install-post">
cp /run/install/tmp/stack.conf /tmp/stack.conf
</stack:script>

</stack:stack>
</stack:stack>

7 changes: 7 additions & 0 deletions sles/nodes/backend.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,13 @@ rm -f /etc/zypp/repos.d/*
<stack:report stack:name="host.repo">&hostname;</stack:report>
</stack:script>

<!-- create the stack.yml -->
<stack:script stack:shell="/opt/stack/bin/python3" stack:stage="install-post">
import stack.settings

stack.settings.write_default_settings_file(overwrite=True)
</stack:script>


<stack:script stack:stage="install-post" stack:cond="release == 'sles12'">
<stack:report stack:name="host.interface">&hostname;</stack:report>
Expand Down