• This repository has been archived on 25/Mar/2022
  • Stars
    star
    208
  • Rank 189,015 (Top 4 %)
  • Language
    Python
  • License
    Other
  • Created over 10 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Reliable Asynchronous Event Transport Protocol

RAET (Reliable Asynchronous Event Transport) Protocol

Motivation

Modern large scale distributed application architectures, wherein components are distributed across the internet on multiple hosts and multiple CPU cores, are often based on a messaging or event bus that allows the various distributed components to communicate asynchronously with each other. Typically the messaging bus is some form of messaging queue service such as AMQP or ZeroMQ. The message bus supports what is commonly referred to as a publish/subscribe methodology for information exchange.

While there are many advantages to a full featured message queuing service, one of the disadvantages is the inability to manage performance at scale.

A message queuing service performs two distinct but complementary functions.

  • The first is asynchronous transport of messages over the internet.
  • The second is message queue management, that is, the identification, tracking, storage, and distribution of messages between publishers and subscribers via queues.

One of the advantages of a message queuing service for many applications is that the service hides behind an API, the complexities of queue management from the clients. The disadvantage is that at scale, where the volume of messages, the timing of messages, and the associated demands on memory, network, and cpu capacity become critical, the client has little ability to tune the service for performance. Often MQ services become bottlenecks for the distributed application. The more complicated MQ services, like AMQP, tend to be unreliable under load.

Separating the function of network transport of asynchrounous event from the function of message queue management allows independant tuning at scale of each function.

Most if not all of the MQ services are based on TCP/IP for transport. TCP/IP adds significant latency to the network communications and is therefore not well suited for the asynchronous nature of distibuted event driven application communications. This is primarily due to the way TCP/IP handles connection setup and teardown as well as failed connections in order to support streams. Fundamentally TCP/IP is optimized for sending large contiguous data streams not many small asynchronous events or messages. While not a problem for small scale systems, the differences in the associated traffic characteristics can become problematic at scale.

Because UDP/IP has lower latency and is connectionless, it is much better suited to many small asynchronous messages and scales better. The drawback of bare UDP/IP is that it is not reliable. What is needed, therefore, is a tuned transport protocol that adds reliability to UDP/IP without sacrificing latency and scalability. A transactioned protocol, is much more appropriate for providing reliablity to asynchronous event transport than a streaming protocol.

Moreover, because most MQ services are based on TCP/IP they tend to also use HTTP and therefore TLS/SSL for secure communications. While using HTTP provides easy integration with web based systems, it can become problematic for high performant systems Furthermore, TLS is also problematic as a security system both from performance and vulnerabilty aspects.

Elliptic Curve Cryptography, on the other hand, provides increases in security with lower performance requirements relative to over other approaches. LibSodium provides an open source Elliptic Curve Cryptographic library with support for both authentication and encryption. The CurveCP protocol is based on LibSodium and provides a handshake protocol for bootstrapping secure network exchanges of information.

Finally, one of the best ways to manage and fine tune processor resources (cpu, memory, network) in distributed concurrent event driven applications is to use something called micro-threads. A microthread is typically an in-language feature that allows logical concurrency with no more overhead than a function call. Micro threading uses cooperative multi-tasking instead of threads and/or processes and avoids many of the complexities of resource contention, context switching, and interprocess communications while providing much higher total performance.

Because all the cooperative micro-threads run in one process, a simple micro-threaded application is limited to one CPU core. To enable full utilization of all CPU cores, the application needs to be able to run at least one process per CPU core. This requires same host inter-process communications. But unlike the conventional approach to multi-processing where there is of one process per logical concurrent function, a micro-threaded multi-process application has instead one micro-thread per logical concurrent function and the total number of micro-threads is distributed amoungst a minimal number of processes, no more than the number of cpu cores. This optimizes the use of the cpu power while minimizes the overhead of process context switching.

An example of a framework that uses this type of micro-threaded but multi-process architecture is Erlang. Indeed, the success of the Erlang model provided support for the viability of the RAET approach. Indeed, one might ask, why not use Erlang? Unfortunately, the Erlang ecosystem is somewhat limited in comparison to Python's and the language itself uses what one might describe as a very unfortunate syntax. One of the design objectives behind RAET was to leverage existing Python expertise and the richness of the Python ecosystem but still be able to develop distributed applications using a micro-threaded multi-process architectural model. The goal was to combine the best of both worlds.

RAET is designed to provide secure reliable scalable asynchronous message/event transport over the internet in a micro-threaded multi-process application framework that uses UDP for interhost communication and LibSodium for authentication, encryption and the CurveCP handshake for secure bootstrap.

The queue management and micro-threaded application support is provided by Ioflo. RAET is a complementary project to Ioflo in that RAET enables multiple Ioflo applications to work together over a network as part of a distributed application.

The primary use case and motivating problem that resulted in the development of RAET was the need to enable SaltStack to scale better. SaltStack is a remote execution and configuration management platform written in Python. SaltStack uses ZeroMQ (0MQ) as its message bus or message queuing service. ZeroMQ is based on TCP/IP so suffers from the aforementioned latency and non-asynchronicity issues of TCP/IP based architectures. Moreover because ZeroMQ integrates queue management and transport in a monolithic way with special "sockets", tuning the performance of the queuing independent of the transport at scale becomes problematic. Tracing down bugs can also be problematic.

Installation

Current raet is provided as a PyPi package. To install on a unix based system use pip.

$ pip install raet

on OS X

$ sudo pip install raet

Introduction

Currently RAET supports two types of communication.

  • Host to host communication over UDP/IP sockets
  • Same host interprocess communication over Unix Domain (UXD) Sockets

The architecture of a RAET based application is shown in the figure below:

Diagram 1

Naming Metaphor for Components

The following naming metaphor is designed to consistent but not conflicting with Ioflo

Road, Estates, Main Estate

  • The UDP channel is a “Road"
  • The members of a Road are “Estates” (as in real estate lots that front the road)
  • Each Estate has a unique UDP Host Port address “ha” , a unique string “name” and unique numerical ID “eid".
  • One Estate on the Road is the “Main” Estate
  • The Main Estate is responsible for allowing other estates to join the Road via the Join (Key Exchange) and Allow (CurveCP) transactions
  • The Main Estate is also responsible for routing messages between other Estates

Lane, Yards, Main Yard

  • Within each Estate may be a “Lane”. This is a UXD channel.
  • The members of a Lane are “Yards” (as in subdivision plots within the Estate)
  • Each Yard on a Lane has a unique UXD file name host address “ha’, and a unique string “name”. There is also a numerical Yard ID “yid" that the class uses to generate yard names but it is not an attribute of the Yard instance.
  • The Lane name is also used with the Yard Name to form a unique Filename that is the ha of the UXD
  • One Yard on a Lane is the “Main” Yard
  • The Main Yard is responsible for forming the Lane and permitting other Yards to be on the lane. There is yet no formal process for this. Currently there is a flag that will drop packets from any Yard that is not already in the list of Yards maintained by the Main yard. Also file permissions can be used to prevent spurious Yards from communicating with the Main Yard.
  • The Main Yard is responsible for routing messages between other yards on the Lane

IoFlo Execution

  • Each Estate UDP interface is run via a RoadStack (UDP sockets) which is run within the context of an IoFlo House (so think of the House that runs the UDP Stack as the Manor House of the Estate)
  • Each Yard UXD interface is run via a LaneStack (Unix domain socket) which is run within the context of an IoFlo House (so think of Houses that run UXD stacks as accessory Houses (Tents, Shacks) on the Estate)
  • The "Manor" House is special in that it runs both the UDP stack for the Estate and also runs the UXD Stack for the Main Yard
  • The House that runs the Main Estate UDP Stack can be thought of as Mayor’s House
  • Within the context of a House is a Data Store. Shares in the Store are Addressed by the unique Share Name which is a dotted path

Routing

Given the Ioflo execution architecture described above, routing is performed as follows:

  • In order to address a specific Estate, the Estate Name is required
  • In order to address a specific Yard within an Estate, the Yard Name is required
  • In order to address a specific Queue within a House, the Share Name is required

The UDP stack maps Estate Name to UDP HA and Estate ID The UXD stack maps Yard Name to UXD HA The Store of any IoFlo behavior maps Share Name to Share reference

Therefore Routing from: a source identified by a queue in a source Share, in a source Yard, in a source Estate to: a destination identified by a queue, in a destination Share, in a destination Yard, in a destination Estate

requires two Triples, one for Source and one for Destination

Source (Estate Name, Yard Name, Share Name)

Destination (Estate Name, Yard Name, Share Name)

If any element of the Triple is None or Empty then a Default is used.

Below is an example of a Message Body that has the Routing information it it.

    estate = 'minion1'
    stack0 = stacking.StackUxd(name='lord', lanename='cherry', yid=0)
    stack1 = stacking.StackUxd(name='serf', lanename='cherry', yid=1)
    yard = yarding.Yard( name=stack0.yard.name, prefix='cherry')
    stack1.addRemoteYard(yard)

    src = (estate, stack1.yard.name, None)
    dst = (estate, stack0.yard.name, None)
    route = odict(src=src, dst=dst)
    msg = odict(route=route, stuff="Serf to my lord. Feed me!")
    stack1.transmit(msg=msg)

    timer = Timer(duration=0.5)
    timer.restart()
    while not timer.expired:
        stack0.serviceAll()
        stack1.serviceAll()


    lord Received Message
    {
        'route':
        {
            'src': ['minion1', 'yard1', None],
            'dst': ['minion1', 'yard0', None]
        },
        'stuff': 'Serf to my lord. Feed me!'
    }

Details of UDP/IP Raet Protocol

The UDP Raet protocol is based on a coding metaphor naming convention, that is, of estates attached to a road. The core objects are provided in the following package: raet.road

Road Raet Production UDP/IP Ports

Manor Estate 4505 Other Estates 4510

Packet Data Format

The data used to initialize a packet is an ordered dict with several fields most of the fields are shared with the header data format below so only the unique fields are shown here.

Unique Packet data fields

sh: source host ip address (ipv4)
sp: source ip port
dh: destination host ip address (ipv4)
dp: destination host ip port

Header Data Format.

The .data in the packet header is an ordered dict which is used to either create a packet to transmit or holds the field from a received packet. What fields are included in a header is dependent on the header kind.

Header encoding

There are three header encoding formats currently supported.

  • RAET Native. This is an minimized ascii test format that optimizes the tradeoff between easy readability and size. This is the default.

  • JSON. This is the most verbose format but has the advantage of compatibility.

  • Binary. This is not yet implemented. Once the protocol reaches a more mature state and its not likely that there will be any header changes (or very infrequent) then a binary format that minimizes size will be provided.

When the head kind is json = 0, then certain optimizations are used to minimize the header length.

  • The header field keys are two bytes long
  • If a header field value is the default then the field is not included
  • Lengths are encoded as hex strings
  • The flags are encoded as a double char hex string in field 'fg'

Header Data Fields

ri: raet id Default 'RAET'
vn: Version (Version) Default 0
pk: Packet Kind (PcktKind)
pl: Packet Length (PcktLen)
hk: Header kind   (HeadKind) Default 0
hl: Header length (HeadLen) Default 0

se: Source Estate ID (SEID)
de: Destination Estate ID (DEID)
cf: Correspondent Flag (CrdtFlag) Default 0
bf: BroadCast Flag (BcstFlag)  Default 0

si: Session ID (SID) Default 0
ti: Transaction ID (TID) Default 0
tk: Transaction Kind (TrnsKind)

dt: Datetime Stamp  (Datetime) Default 0
oi: Order index (OrdrIndx)   Default 0

wf: Waiting Ack Flag    (WaitFlag) Default 0
    Next segment or ordered packet is waiting for ack to this packet
ml: Message Length (MsgLen)  Default 0
    Length of message only (unsegmented)
sn: Segment Number (SgmtNum) Default 0
sc: Segment Count  (SgmtCnt) Default 1
sf: Segment Flag  (SgmtFlag) Default 0
    This packet is part of a segmented message
af: All Flag (AllFlag) Default 0
    Resend all segments not just one

bk: Body kind   (BodyKind) Default 0
ck: Coat kind   (CoatKind) Default 0
fk: Footer kind   (FootKind) Default 0
fl: Footer length (FootLen) Default 0

fg: flags  packed (Flags) Default '00' hs
     2 char Hex string with bits (0, 0, af, sf, 0, wf, bf, cf)
     Zeros are TBD flags

Body Data Format

The Body .data is a Mapping that is serialized using either JSON or MSGPACK

Packet Parts

Each packet has 4 parts some of which may be empty. These are:

  • Head
  • Body
  • Coat
  • Tail

The Head is manditory and provides the header fields that are needed to process the packet.

The Tail provides the authentication signature that is used to verify the source of the packet and that its contents have not been tampered with.

The Body is the contents of the packet. Some packets such as Acks and Nacks don't need a body. The Body is a serialized Python dictionary typically and ordered dictionary so that parsing and debugging has a consistent view of the ordering of the fields in the body.

The Coat is the encrypted version of the body. The encryption type is CurveCP based. If the Coat is provided then the Body is encapsulated within the Coat Part.

Header Details

JSON Encoding

Header is the ASCII Safe JSON encoding of a Python ordered dictionary. Header termination is an empty line given by double pair of carriage-return linefeed characters.

/r/n/r/n 10 13 10 13 ADAD 1010 1101 1010 1101

Carriage-return and newline characters cannot appear in a JSON encoded string unless they are escaped with backslash, so the 4 byte combination is illegal in valid JSON that does not have multi-byte unicode characters so it makes it a uniquely identifiable header termination.

These means the header must be ascii safe so no multibyte utf-8 strings are allowed in the header.

Native Encoding

The header consists of newline delimited lines. Each header line consists of a two character field identifier followed by a space followed by the value of the field as ascii hex encoded binary followed by newline. The Header end is indicated by a blank line, that is, a double newline character. Example

Binary Encoding

The header consists of defined set of fixed length fields

Session

Session is important for security. Want one session opened and then multiple transactions within session.

Session ID SID sid si

Session Bootstrap

Layering:

OSI Layers

7: Application: Format: Data (Stack to Application interface buffering etc) 6: Presentation: Format: Data (Encrypt-Decrypt convert to machine independent format) 5: Session: Format: Data (Interhost communications. Authentication. Groups) 4: Transport: Format: Segments (Reliable delivery of Message, Transactions, Segmentation, Error checking) 3: Network: Format: Packets/Datagrams (Addressing Routing) 2: Link: Format: Frames ( Reliable per frame communications connection, Media access controller ) 1: Physical: Bits (Transciever communication connection not reliable)

  • Link is hidden from Raet

  • Network is IP host address and UDP Port

  • Transport is Raet transaction and packet authentication vis tail signature that provide reliable transport.

  • Session is session id key exchange for signing. Grouping is Road

  • Presentation is Encrypt-Decrypt Body and Serialize-Deserialize Body

  • Application is Body data dictionary

Packet signing could technically be in either the Transport or Session layers.

UXD Message

RAET UXD Messages are limited in size to the same maximum (pre segmented) RAET UDP message size (about 16 Mb)

UXD Messages have the following Format Header followed by serialized message body dict currently only JSON has been implemented.

  1. JSON Header: “RAET\njson\n\n” Followed by a jsonified message body dict

  2. msgpack Header: “RAET\npack\n\n” Followed by a msgpackified message body dict

More Repositories

1

kubeless

Kubernetes Native Serverless Framework
Go
6,867
star
2

clarity

Clarity is a scalable, accessible, customizable, open source design system built with web components. Works with any JavaScript framework, built for enterprises, and designed to be inclusive.
TypeScript
6,456
star
3

octant

Highly extensible platform for developers to better understand the complexity of Kubernetes clusters.
Go
6,247
star
4

kubewatch

Watch k8s events and trigger Handlers
Go
2,448
star
5

scripted

The Scripted code editor
JavaScript
1,564
star
6

eventrouter

A simple introspective kubernetes service that forwards events to a specified sink.
Go
873
star
7

tgik

Official repository for TGI Kubernetes (TGIK)!
Shell
828
star
8

kube-prod-runtime

A standard infrastructure environment for Kubernetes
Jsonnet
776
star
9

healthcheck

A library for implementing Kubernetes liveness and readiness probe handlers in your Go application.
Go
675
star
10

pivotal_workstation

A cookbook of recipes for an OSX workstation
662
star
11

cabin

The Mobile Dashboard for Kubernetes
JavaScript
659
star
12

dispatch

Dispatch is a framework for deploying and managing serverless style applications.
Go
535
star
13

buildkit-cli-for-kubectl

BuildKit CLI for kubectl is a tool for building container images with your Kubernetes cluster
Go
491
star
14

haret

A strongly consistent distributed coordination system, built using proven protocols & implemented in Rust.
Rust
462
star
15

concourse-pipeline-samples

Sample code and recipes for Concourse CI pipelines and deployments.
Shell
447
star
16

cascade

A Just-In-Time Compiler for Verilog from VMware Research
C++
430
star
17

projectmonitor

Big Visible Chart CI aggregator
Ruby
427
star
18

kubeless-ui

Graphical User Interface for Kubeless
JavaScript
417
star
19

halite

DEPRECATED: A client-side web application interface to a running Salt infrastructure
Python
413
star
20

gangway

An application that can be used to easily enable authentication flows via OIDC for a kubernetes cluster.
Go
407
star
21

salty-vagrant

Use Salt as a Vagrant provisioner.
Shell
373
star
22

liota

Python
336
star
23

lightwave

Identity services for traditional infrastructure, applications and containers.
C
321
star
24

rbvmomi

Ruby interface to the VMware vSphere API.
Ruby
302
star
25

git_scripts

Developer workflow convenience scripts
Ruby
279
star
26

pcfdev

This is the depricated version of PCF Dev - please visit the current Github repository https://github.com/cloudfoundry-incubator/cfdev for the latest updates
Go
273
star
27

springsource-cloudfoundry-samples

Samples for Cloud Foundry
Java
259
star
28

admiral

Container management solution with an accent on modeling containerized applications and provide placement based on dynamic policy allocation
Java
254
star
29

vsphere-storage-for-docker

vSphere Storage for Docker
Python
254
star
30

salt-vim

Vim files for editing Salt files
Vim Script
246
star
31

rvc

RVC is a Linux console UI for vSphere, built on the RbVmomi bindings to the vSphere API.
Ruby
238
star
32

xenon

Xenon - Decentralized Control Plane Framework
Java
226
star
33

database-stream-processor

Streaming and Incremental Computation Framework
Rust
222
star
34

salt-cloud

Salt Cloud Working group.
200
star
35

vsphere-automation-sdk-rest

REST (Postman and JavaScript) samples and API reference documentation for vSphere using the VMware REST API
197
star
36

cloud-init-vmware-guestinfo

A cloud-init datasource for VMware vSphere's GuestInfo interface
Python
192
star
37

jsunit

The original unit-testing framework for JavaScript. These days we use Jasmine (http://github.com/pivotal/jasmine) by default for JS testing; JsUnit is not actively developed or supported.
Java
173
star
38

sql_magic

Magic functions for using Jupyter Notebook with Apache Spark and a variety of SQL databases.
Jupyter Notebook
171
star
39

purser

Kubernetes Cloud Native Applications visibility
Go
171
star
40

pyvcloud

Python SDK for VMware vCloud Director
Python
170
star
41

salt-contrib

Salt Module Contributions
Python
170
star
42

powernsx

PowerShell module that abstracts the VMware NSX-v API to a set of easily used PowerShell functions
PowerShell
170
star
43

p4c-xdp

Backend for the P4 compiler targeting XDP
C
166
star
44

webcommander

Powerful, flexible, intuitive and most importantly simple. That is what a real automation solution should be. No matter how complicated the task is, we'd like to turn it into a single click. Is that possible? Not without webcommander :)
PowerShell
166
star
45

vcd-cli

Command Line Interface for VMware vCloud Director
Python
164
star
46

wardroom

A tool for creating Kubernetes-ready base operating system images.
Python
162
star
47

pcf-pipelines

PCF Pipelines
Shell
158
star
48

spring-boot-cities

A Spring Boot + Spring Data + Spring Cloud Connectors demo app
Java
149
star
49

kube-manifests

A collection of misc Kubernetes configs for various jobs, as used in Bitnami's production clusters.
Jsonnet
136
star
50

ktx

manage kubernetes cluster configs
Shell
133
star
51

pg_rewind

Tool for resynchronizing a Postgres database after failover
125
star
52

AndroidIntelliJStarter

An IntelliJ template project for android developers, pre-configured to work with Robolectric, Roboguice, an other common, useful Android libraries.
Java
125
star
53

vctl-docs

VMware vctl Docs
124
star
54

cimonitor

This project has been renamed to ProjectMonitor - http://github.com/pivotal/projectmonitor
121
star
55

tmux-config

Configuration and tools for tmux. Can be used as a Vim plugin.
Shell
121
star
56

PivotalMySQLWeb

PivotalMySQL*Web is a free Pivotal open source project, intended to handle the administration of a Pivotal MySQL Service Instance over the Web
JavaScript
120
star
57

salt-api

RETIRED: Generic, modular network access system
Python
112
star
58

atc

old - now lives in https://github.com/concourse/concourse
111
star
59

nsxansible

A set of example Ansible Modules using the above two projects as the basis
Python
110
star
60

pg2mysql

Tool for safely migrating from PostgreSQL to MySQL
Go
107
star
61

clarity-seed

This is a repository for a seed project that includes Clarity Design System's dependencies.
TypeScript
104
star
62

helm-crd

Experimental CRD controller for managing Helm releases
Go
103
star
63

fly

old - now lives in https://github.com/concourse/concourse
100
star
64

declarative-cluster-management

Declarative cluster management using constraint programming, where constraints are described using SQL.
Java
99
star
65

hillview

Big data spreadsheet
Java
99
star
66

cbapi

Carbon Black API Resources
Python
94
star
67

vmware-vcenter

VMware vCenter Module
Ruby
87
star
68

ModSecurity-envoy

ModSecurity V3 Envoy Filter
C++
86
star
69

springtrader

JavaScript
83
star
70

tic

Bit9 + Carbon Black Threat Intelligence
Python
80
star
71

runtimes

Kubeless function runtimes: https://kubeless.io/docs/runtimes/
C#
79
star
72

pyvmomi-tools

Additional community developed python packages to help you work with pyvmomi
Python
77
star
73

gpdb-sandbox-tutorials

76
star
74

salt-windows-install

Open source installer for Windows
75
star
75

vagrant-vmware-appcatalyst

Vagrant provider for VMware AppCatalyst®
Ruby
73
star
76

transport-go

Transport is a full stack, simple, fast, expandable application event bus for your applications. It provides a standardized and simple API, implemented in multiple languages, to allow any individual component inside your applications to talk to one another. This is the Golang implementation of the Transport library.
Go
72
star
77

concord

🧱⛓️ A scalable decentralized blockchain
C++
71
star
78

terraforming-gcp

use terraform, deploy yourself a pcf
HCL
71
star
79

functions

Functions Repository for Kubeless
Python
70
star
80

Pivotal-Preferences-RubyMine

This repo is deprecated. Use the "Pivotal IDE Prefs" repo instead.
70
star
81

IoT-ConnectedCar

HTML
69
star
82

ironclad

Web Application Firewall (WAF) on Kubernetes
Go
69
star
83

vsphere-automation-sdk-.net

[DEPRECATED] Please see README. C# samples, language bindings, and API reference documentation for vSphere, VMC, and NSX-T using the VMware REST API
C#
67
star
84

pymadlib

A Python wrapper for MADlib(http://madlib.net) - an open source library for scalable in-database machine learning algorithms
Jupyter Notebook
65
star
85

chaperone

Python
64
star
86

bin

old - now lives in https://github.com/concourse/concourse
64
star
87

terraforming-aws

Templates to deploy PCF and PKS
HCL
64
star
88

legacy-terraform-provider-vra7

Terraform provider for vRealize Automation 7
Go
62
star
89

tutorials

PHP
59
star
90

nsxraml

A RAML Specification Describing the NSX for vSphere API
HTML
59
star
91

vra-api-samples-for-postman

API use case samples in Postman Rest Client collection format.
58
star
92

simple-k8s-test-env

For developers building and testing Kubernetes and core Kubernetes components
Shell
58
star
93

vm-operator-api

A client API for the VM Operator project, designed to allow for integration with vSphere 7 with Kubernetes
Go
58
star
94

gcp-pcf-quickstart

Install Pivotal Cloud Foundry on Google Cloud Platform With One Command
Go
56
star
95

sunspot_matchers

RSpec matchers for testing Sunspot searches
Ruby
56
star
96

ansible-security-hardening

ansible playbooks for linux distro security hardening
56
star
97

lobot

This project has been renamed to ciborg. Please visit the ciborg page for more info.
Ruby
56
star
98

salt-pack

Salt Package Builder
Shell
55
star
99

sublime-text

Salt-related syntax highlighting and snippets for Sublime Text
JavaScript
54
star
100

pynsxv

PyNSXv is a high level python based library and CLI tool to control NSX for vSphere
Python
54
star