Skip to content

AvitalTamir/cyphernetes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Cyphernetes Logo (3 5 x 1 2 in)

Go Report Card Go Reference License Artifact Hub

Cyphernetes turns this: 😣

# Select all zero-scaled Deployments in all namespaces,
# find all Ingresses routing to these deployments -
# for each Ingress change it's ingress class to 'inactive':

kubectl get deployments -A -o json | jq -r '.items[] | select(.spec.replicas == 0) | \
[.metadata.namespace, .metadata.name, (.spec.selector | to_entries | map("\(.key)=\(.value)") | \
join(","))] | @tsv' | while read -r ns dep selector; do kubectl get services -n "$ns" -o json | \
jq -r --arg selector "$selector" '.items[] | select((.spec.selector | to_entries | \
map("\(.key)=\(.value)") | join(",")) == $selector) | .metadata.name' | \
while read -r svc; do kubectl get ingresses -n "$ns" -o json | jq -r --arg svc "$svc" '.items[] | \
select(.spec.rules[].http.paths[].backend.service.name == $svc) | .metadata.name' | \
xargs -I {} kubectl patch ingress {} -n "$ns" --type=json -p \
'[{"op": "replace", "path": "/spec/ingressClassName", "value": "inactive"}]'; done; done

Into this: 🀩

# Do the same thing!

MATCH (d:Deployment)->(s:Service)->(i:Ingress)
WHERE d.spec.replicas=0
SET i.spec.ingressClassName="inactive";

How?

Cyphernetes is a Cypher-inspired query language for Kubernetes. It is a mixture of ASCII-art, SQL and JSON and it lets us express Kubernetes operations in an efficeint way that is also fun and creative.

There are multiple ways to run Cyphernetes queries:

  1. Using the interactive shell by running cyphernetes shell in your terminal
  2. Running a single query from the command line by running cyphernetes query "your query" - great for scripting and CI/CD pipelines
  3. Creating a Cyphernetes DynamicOperator using the cyphernetes-operator which lets you define powerful Kubernetes workflows on-the-fly
  4. Using the Cyphernetes API in your own Go programs

To learn more about how to use Cyphernetes, refer to these documents:

  • LANGUAGE.md - a crash-course in Cyphernetes language syntax
  • CLI.md - a guide to using Cyphernetes shell, query command and macros
  • OPERATOR.md - a guide to using Cyphernetes DynamicOperator

Some examples from the shell

# Get the desired and running replicas for all deployments
MATCH (d:Deployment)
RETURN d.spec.replicas AS desiredReplicas, 
       d.status.availableReplicas AS runningReplicas;

{
  "d": [
    {
      "desiredReplicas": 2,
      "name": "coredns",
      "runningReplicas": 2
    }
  ]
}

Query executed in 9.081292ms

Cyphernetes' superpower is understanding the relationships between Kubernetes resource kinds. This feature is expressed using the arrows (->) you see in the example queries. Relationships let us express connected operations in a natural way, and without having to worry about the underlying Kubernetes API:

# This is similar to `kubectl expose`
> MATCH (d:Deployment {name: "nginx"})
  CREATE (d)->(s:Service);

Created services/nginx

Query executed in 30.692208ms

It has macros and graphs too

Macros are minimalistic, user-extensible & batteries included stored procedures. They turn the Cyphernetes shell into a handy kubectl alternative. Many useful macros are included - and it's easy to define your own.

# This macro creates a service and public ingress for a deployment.
# It's defined like this:
# :exposepublic deploymentName hostname # Expose a deployment as a service and ingress
# MATCH (deployment:Deployment {name: "$deploymentName"})
# CREATE (deployment)->(service:Service);
# MATCH (services:Service {name: "$deploymentName"})
# CREATE (services)->(i:ingress {"spec":{"rules": [{"host": "$hostname"}]}});
# MATCH (deployments:Deployment {name: "$deploymentName"})->(services:Service)->(ingresses:Ingress)
# RETURN services.metadata.name, services.spec.type AS Type, services.spec.clusterIP AS ClusterIP, ingresses.spec.rules[0].host AS Host, ingresses.spec.rules[0].http.paths[0].path AS Path, ingresses.spec.rules[0].http.paths[0].backend.service.name AS Service;

# Cyphernetes can optionally draw a graph of affected nodes as ASCII-art!

> :expose_public nginx foo.com
Created services/nginx
Created ingresses/nginx

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ *Ingress* nginx β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  β”‚
  β”‚ :ROUTE
  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ *Service* nginx β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

{
  "ingresses": [
    {
      "Host": "foo.com",
      "Path": "/",
      "Service": "nginx",
      "name": "nginx"
    }
  ],
  "services": [
    {
      "ClusterIP": "10.96.164.152",
      "Type": "ClusterIP",
      "name": "nginx"
    }
  ]
}

Macro executed in 50.305083ms

Get Cyphernetes

Using Homebrew:

brew install cyphernetes

Using go:

go install github.com/avitaltamir/cyphernetes/cmd/cyphernetes@latest

Alternatively, grab a binary from the Releases page.

Development

Cyphernetes is written in Go and utilizes a parser generated by goyacc to interpret the custom query language.

Prerequisites

  • Go (Latest)
  • goyacc (for generating the parser)
  • Make (for running make commands)

Getting Started

To get started with development:

Clone the repository:

git clone https://github.com/avitaltamir/cyphernetes.git

Navigate to the project directory:

cd cyphernetes

Building the Project

Use the Makefile commands to build the project:

  • Build & Test:
make
  • To build the binary:
make build
  • To run tests:
make test
  • To generate the grammar parser:
make gen-parser
  • To clean up the build:
make clean

Contributing

Contributions are welcome! Please feel free to submit pull requests, open issues, and provide feedback.

License

Cyphernetes is open-sourced under the MIT license. See the LICENSE file for details.

Acknowledgments

Authors