ZOS Manual
Introduction
This document explain the usage of ZOS
. ZOS
usually pronounced (zero OS), got it's name from the idea of zero configuration. Since after the initial minimal
configuration which only include which farm
to join and what network
(development
, testing
, or production
) the owner of the node does not has to do anything more, and the node work fully autonomous.
The farmer himself cannot control the node, or access it by any mean. The only way you can interact with a node is via it's public API.
Farm? Network? What are these?
Well, zos
is built to allow people to run workloads
around the world this simply is enabled by allowing 3rd party data-centers to run ZOS
on their hardware. Then a user can then find any nearby farm
(is what we call a cluster of nodes that belong to the same farmer
) and then they can choose to deploy capacity on that node/farm. A farm
can consist of one or more nodes.
So what is network
.Well, to allow developers to build and zos
itself and make it available during the early stages of development for testers and other enthusiastic people to try it out. To allow this we created 3 networks
development
: This is used mainly by developers to test their work. This is still available for users to deploy their capacity on (for really really cheap prices), but at the same time there is no grantee that it's stable or that data loss or corruption will happen. Also the entire network can be reset with no heads up.testing
: Once new features are developed and well tested ondevelopment
network they are released totesting
environment. This also available for users to use with a slightly higher price thandevelopment
network. But it's much more stable. In theory this network is stable, there should be no resets of the network, issues on this network usually are not fatal, but partial data loss can still occurs.production
: Well, as the name indicates this is the most stable network (also full price) once new features are fully tested ontesting
network they are released onproduction
.
Creating a farm
While this is outside the scope of this document here you are a link
Interaction
ZOS
provide a simple API
that can be used to:
- Query node runtime information
- Network information
- Free
wireguard
ports - Get public configuration
- Free
- System version
- Other (check client for details)
- Network information
- Deployment management (more on that later)
- Create
- Update
- Delete
Note that zos
API is available over rmb
protocol. rmb
which means reliable message bus
is a simple messaging protocol that enables peer to peer communication over yggdrasil
network. Please check rmb
for more information.
Simply put, RMB
allows 2 entities two communicate securely knowing only their id
an id is linked to a public key on the blockchain. Hence messages are verifiable via a signature.
To be able to contact the node directly you need to run
yggdrasil
rmb
(correctly configured)
Once you have those running you can now contact the node over rmb
. For a reference implementation (function names and parameters) please refer to RMB documentation
Here is a rough example of how low level creation of a deployment is done.
cl, err := rmb.Default()
if err != nil {
panic(err)
}
then create an instance of the node client
node := client.NewNodeClient(NodeTwinID, cl)
define your deployment object
dl := gridtypes.Deployment{
Version: Version,
TwinID: Twin, //LocalTwin,
// this contract id must match the one on substrate
Workloads: []gridtypes.Workload{
network(), // network workload definition
zmount(), // zmount workload definition
publicip(), // public ip definition
zmachine(), // zmachine definition
},
SignatureRequirement: gridtypes.SignatureRequirement{
WeightRequired: 1,
Requests: []gridtypes.SignatureRequest{
{
TwinID: Twin,
Weight: 1,
},
},
},
}
compute hash
hash, err := dl.ChallengeHash()
if err != nil {
panic("failed to create hash")
}
fmt.Printf("Hash: %x\n", hash)
create the contract on substrate
and get the contract id
then you can link the deployment to the contract, then send to the node.
dl.ContractID = 11 // from substrate
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err = node.DeploymentDeploy(ctx, dl)
if err != nil {
panic(err)
}
Once the node receives the deployment. It will then fetch the contract (using the contract id) from the node recompute the deployment hash and compare with the one set on the contract. If matches, the node proceeds to process the deployment.
Deployment
A deployment is a set of workloads that are contextually related. Workloads in the same deployment can reference to other workloads in the same deployment. But can't be referenced from another deployment. Well, except the network workload which can be referenced from a different deployment as long it belongs to the same user.
Workloads has unique IDs (per deployment) that are set by the user, hence he can create multiple workloads then reference to them with the given IDs (names
)
For example, a deployment can define
- A private network with id
net
- A disk with id
data
- A public IP with id
ip
- A container that uses:
- The container can mount the disk like
mount: {data: /mount/path}
. - The container can get assign the public IP to itself like by referencing the IP with id
ip
. - etc.
- The container can mount the disk like
Workload
Each workload has a type which is associated with some data. So minimal definition of a workload contains:
name
: unique per deployment (id)type
: workload typedata
: workload data that is proper for the selected type.
// Workload struct
type Workload struct {
// Version is version of reservation object. On deployment creation, version must be 0
// then only workloads that need to be updated must match the version of the deployment object.
// if a deployment update message is sent to a node it does the following:
// - validate deployment version
// - check workloads list, if a version is not matching the new deployment version, the workload is untouched
// - if a workload version is same as deployment, the workload is "updated"
// - if a workload is removed, the workload is deleted.
Version uint32 `json:"version"`
//Name is unique workload name per deployment (required)
Name Name `json:"name"`
// Type of the reservation (container, zdb, vm, etc...)
Type WorkloadType `json:"type"`
// Data is the reservation type arguments.
Data json.RawMessage `json:"data"`
// Metadata is user specific meta attached to deployment, can be used to link this
// deployment to other external systems for automation
Metadata string `json:"metadata"`
//Description human readale description of the workload
Description string `json:"description"`
// Result of reservation, set by the node
Result Result `json:"result"`
}
Types
- Virtual machine related
- Storage related
- Gateway related
API
Node is always connected to the RMB network with the node twin
. Means the node is always reachable over RMB with the node twin-id
as an address.
The node client should have a complete list of all available functions. documentations of the API can be found here
Raid Controller Configuration
0-OS goal is to expose raw capacity. So it is best to always try to give it access to the most raw access to the disks. In case of raid controllers, the best is to try to set it up in JBOD mode if available.