drop kubectl-pg plugin (#3107)
Co-authored-by: Ida Novindasari <idanovinda@gmail.com>
This commit is contained in:
parent
a71e6bdf7f
commit
ebf48667f1
|
|
@ -26,7 +26,6 @@ _testmain.go
|
|||
*.test
|
||||
*.prof
|
||||
/vendor/
|
||||
/kubectl-pg/vendor/
|
||||
/build/
|
||||
/docker/build/
|
||||
/github.com/
|
||||
|
|
|
|||
|
|
@ -1,137 +0,0 @@
|
|||
# Kubectl Plugin for Zalando's Postgres Operator
|
||||
|
||||
This plugin is a prototype developed as a part of **Google Summer of Code 2019** under the [Postgres Operator](https://summerofcode.withgoogle.com/archive/2019/organizations/6187982082539520/) organization.
|
||||
|
||||
## Installation of kubectl pg plugin
|
||||
|
||||
This project uses Go Modules for dependency management to build locally.
|
||||
Install go and enable go modules with ```export GO111MODULE=on```.
|
||||
From Go >=1.13 Go modules will be enabled by default.
|
||||
|
||||
```bash
|
||||
# Assumes you have a working KUBECONFIG
|
||||
$ GO111MODULE="on"
|
||||
$ GOPATH/src/github.com/zalando/postgres-operator/kubectl-pg go mod vendor
|
||||
# This generate a vendor directory with all dependencies needed by the plugin.
|
||||
$ $GOPATH/src/github.com/zalando/postgres-operator/kubectl-pg go install
|
||||
# This will place the kubectl-pg binary in your $GOPATH/bin
|
||||
```
|
||||
|
||||
## Before using the kubectl pg plugin make sure to set KUBECONFIG env variable
|
||||
|
||||
Ideally KUBECONFIG is found in $HOME/.kube/config else specify the KUBECONFIG path here.
|
||||
```export KUBECONFIG=$HOME/.kube/config```
|
||||
|
||||
## List all commands available in kubectl pg
|
||||
|
||||
```kubectl pg --help``` (or) ```kubectl pg```
|
||||
|
||||
## Check if Postgres Operator is installed and running
|
||||
|
||||
```kubectl pg check```
|
||||
|
||||
## Create a new cluster using manifest file
|
||||
|
||||
```kubectl pg create -f acid-minimal-cluster.yaml```
|
||||
|
||||
## List postgres resources
|
||||
|
||||
```kubectl pg list```
|
||||
|
||||
List clusters across namespaces
|
||||
```kubectl pg list all```
|
||||
|
||||
## Update existing cluster using manifest file
|
||||
|
||||
```kubectl pg update -f acid-minimal-cluster.yaml```
|
||||
|
||||
## Delete existing cluster
|
||||
|
||||
Using the manifest file:
|
||||
```kubectl pg delete -f acid-minimal-cluster.yaml```
|
||||
|
||||
Or by specifying the cluster name:
|
||||
```kubectl pg delete acid-minimal-cluster```
|
||||
|
||||
Use `--namespace` or `-n` flag if your cluster is in a different namespace to where your current context is pointing to:
|
||||
```kubectl pg delete acid-minimal-cluster -n namespace01```
|
||||
|
||||
## Adding manifest roles to an existing cluster
|
||||
|
||||
```kubectl pg add-user USER01 -p CREATEDB,LOGIN -c acid-minimal-cluster```
|
||||
|
||||
Privileges can only be [SUPERUSER, REPLICATION, INHERIT, LOGIN, NOLOGIN, CREATEROLE, CREATEDB, BYPASSRLS]
|
||||
Note: By default, a LOGIN user is created (unless NOLOGIN is specified).
|
||||
|
||||
## Adding databases to an existing cluster
|
||||
|
||||
You have to specify an owner of the new database and this role must already exist in the cluster:
|
||||
```kubectl pg add-db DB01 -o OWNER01 -c acid-minimal-cluster```
|
||||
|
||||
## Extend the volume of an existing pg cluster
|
||||
|
||||
```kubectl pg ext-volume 2Gi -c acid-minimal-cluster```
|
||||
|
||||
## Print the version of Postgres Operator and kubectl pg plugin
|
||||
|
||||
```kubectl pg version```
|
||||
|
||||
## Connect to the shell of a postgres pod
|
||||
|
||||
Connect to the master pod:
|
||||
```kubectl pg connect -c CLUSTER -m```
|
||||
|
||||
Connect to a random replica pod:
|
||||
```kubectl pg connect -c CLUSTER```
|
||||
|
||||
Connect to a certain replica pod:
|
||||
```kubectl pg connect -c CLUSTER -r 0```
|
||||
|
||||
## Connect to a database via psql
|
||||
|
||||
Adding the `-p` flag allows you to directly connect to a given database with the psql client.
|
||||
With `-u` you specify the user. If left out the name of the current OS user is taken.
|
||||
`-d` lets you specify the database. If no database is specified, it will be the same as the user name.
|
||||
|
||||
Connect to `app_db` database on the master with role `app_user`:
|
||||
```kubectl pg connect -c CLUSTER -m -p -u app_user -d app_db```
|
||||
|
||||
Connect to the `postgres` database on a random replica with role `postgres`:
|
||||
```kubectl pg connect -c CLUSTER -p -u postgres```
|
||||
|
||||
Connect to a certain replica assuming name of OS user, database role and name are all the same:
|
||||
```kubectl pg connect -c CLUSTER -r 0 -p```
|
||||
|
||||
|
||||
## Access Postgres Operator logs
|
||||
|
||||
```kubectl pg logs -o```
|
||||
|
||||
## Access Patroni logs of different database pods
|
||||
|
||||
Fetch logs of master:
|
||||
```kubectl pg logs -c CLUSTER -m```
|
||||
|
||||
Fetch logs of a random replica pod:
|
||||
```kubectl pg logs -c CLUSTER```
|
||||
|
||||
Fetch logs of specified replica
|
||||
```kubectl pg logs -c CLUSTER -r 2```
|
||||
|
||||
## Development
|
||||
|
||||
When making changes to the plugin make sure to change the (major/patch) version of plugin in `build.sh` script and run `./build.sh`.
|
||||
|
||||
## Google Summer of Code 2019
|
||||
|
||||
### GSoC Proposal
|
||||
|
||||
[kubectl pg proposal](https://docs.google.com/document/d/1-WMy9HkfZ1XnnMbzplMe9rCzKrRMGaMz4owLVXXPb7w/edit)
|
||||
|
||||
### Weekly Reports
|
||||
|
||||
https://github.com/VineethReddy02/GSoC-Kubectl-Plugin-for-Postgres-Operator-tracker
|
||||
|
||||
### Final Project Report
|
||||
|
||||
https://gist.github.com/VineethReddy02/159283bd368a710379eaf0f6bd60a40a
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
VERSION=1.0
|
||||
sed -i "s/KubectlPgVersion string = \"[^\"]*\"/KubectlPgVersion string = \"${VERSION}\"/" cmd/version.go
|
||||
go install
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// addDbCmd represents the addDb command
|
||||
var addDbCmd = &cobra.Command{
|
||||
Use: "add-db",
|
||||
Short: "Adds a DB and its owner to a Postgres cluster. The owner role is created if it does not exist",
|
||||
Long: `Adds a new DB to the Postgres cluster. Owner needs to be specified by the -o flag, cluster with -c flag.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) > 0 {
|
||||
dbName := args[0]
|
||||
dbOwner, _ := cmd.Flags().GetString("owner")
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
addDb(dbName, dbOwner, clusterName)
|
||||
} else {
|
||||
fmt.Println("database name can't be empty. Use kubectl pg add-db [-h | --help] for more info")
|
||||
}
|
||||
|
||||
},
|
||||
Example: `
|
||||
kubectl pg add-db db01 -o owner01 -c cluster01
|
||||
`,
|
||||
}
|
||||
|
||||
// add db and it's owner to the cluster
|
||||
func addDb(dbName string, dbOwner string, clusterName string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
namespace := getCurrentNamespace()
|
||||
postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var dbOwnerExists bool
|
||||
dbUsers := postgresql.Spec.Users
|
||||
for key := range dbUsers {
|
||||
if key == dbOwner {
|
||||
dbOwnerExists = true
|
||||
}
|
||||
}
|
||||
var patch []byte
|
||||
// validating reserved DB names
|
||||
if dbOwnerExists && dbName != "postgres" && dbName != "template0" && dbName != "template1" {
|
||||
patch = dbPatch(dbName, dbOwner)
|
||||
} else if !dbOwnerExists {
|
||||
log.Fatal("The provided db-owner doesn't exist")
|
||||
} else {
|
||||
log.Fatal("The provided db-name is reserved by postgres")
|
||||
}
|
||||
|
||||
updatedPostgres, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patch, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if updatedPostgres.ResourceVersion != postgresql.ResourceVersion {
|
||||
fmt.Printf("Created new database %s with owner %s in PostgreSQL cluster %s.\n", dbName, dbOwner, updatedPostgres.Name)
|
||||
} else {
|
||||
fmt.Printf("postgresql %s is unchanged.\n", updatedPostgres.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func dbPatch(dbname string, owner string) []byte {
|
||||
ins := map[string]map[string]map[string]string{"spec": {"databases": {dbname: owner}}}
|
||||
patchInstances, err := json.Marshal(ins)
|
||||
if err != nil {
|
||||
log.Fatal(err, "unable to parse patch for add-db")
|
||||
}
|
||||
return patchInstances
|
||||
}
|
||||
|
||||
func init() {
|
||||
addDbCmd.Flags().StringP("owner", "o", "", "provide owner of the database.")
|
||||
addDbCmd.Flags().StringP("cluster", "c", "", "provide a postgres cluster name.")
|
||||
rootCmd.AddCommand(addDbCmd)
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var allowedPrivileges = []string{"SUPERUSER", "REPLICATION", "INHERIT", "LOGIN", "NOLOGIN", "CREATEROLE", "CREATEDB", "BYPASSRLS"}
|
||||
|
||||
// addUserCmd represents the addUser command
|
||||
var addUserCmd = &cobra.Command{
|
||||
Use: "add-user",
|
||||
Short: "Adds a user to the postgres cluster with given privileges",
|
||||
Long: `Adds a user to the postgres cluster. You can add privileges as well with -p flag.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
privileges, _ := cmd.Flags().GetString("privileges")
|
||||
|
||||
if len(args) > 0 {
|
||||
user := args[0]
|
||||
var permissions []string
|
||||
var perms []string
|
||||
|
||||
if privileges != "" {
|
||||
parsedRoles := strings.Replace(privileges, ",", " ", -1)
|
||||
parsedRoles = strings.ToUpper(parsedRoles)
|
||||
permissions = strings.Fields(parsedRoles)
|
||||
var invalidPerms []string
|
||||
|
||||
for _, userPrivilege := range permissions {
|
||||
validPerm := false
|
||||
for _, privilege := range allowedPrivileges {
|
||||
if privilege == userPrivilege {
|
||||
perms = append(perms, userPrivilege)
|
||||
validPerm = true
|
||||
}
|
||||
}
|
||||
if !validPerm {
|
||||
invalidPerms = append(invalidPerms, userPrivilege)
|
||||
}
|
||||
}
|
||||
|
||||
if len(invalidPerms) > 0 {
|
||||
fmt.Printf("Invalid privileges %s\n", invalidPerms)
|
||||
return
|
||||
}
|
||||
}
|
||||
addUser(user, clusterName, perms)
|
||||
}
|
||||
},
|
||||
Example: `
|
||||
kubectl pg add-user user01 -p login,createdb -c cluster01
|
||||
`,
|
||||
}
|
||||
|
||||
// add user to the cluster with provided permissions
|
||||
func addUser(user string, clusterName string, permissions []string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
namespace := getCurrentNamespace()
|
||||
postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
setUsers := make(map[string]bool)
|
||||
for _, k := range permissions {
|
||||
setUsers[k] = true
|
||||
}
|
||||
|
||||
if existingRoles, key := postgresql.Spec.Users[user]; key {
|
||||
for _, k := range existingRoles {
|
||||
setUsers[k] = true
|
||||
}
|
||||
}
|
||||
|
||||
Privileges := []string{}
|
||||
for keys, values := range setUsers {
|
||||
if values {
|
||||
Privileges = append(Privileges, keys)
|
||||
}
|
||||
}
|
||||
|
||||
patch := applyUserPatch(user, Privileges)
|
||||
updatedPostgresql, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patch, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if updatedPostgresql.ResourceVersion != postgresql.ResourceVersion {
|
||||
fmt.Printf("postgresql %s is updated with new user %s and with privileges %s.\n", updatedPostgresql.Name, user, permissions)
|
||||
} else {
|
||||
fmt.Printf("postgresql %s is unchanged.\n", updatedPostgresql.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func applyUserPatch(user string, value []string) []byte {
|
||||
ins := map[string]map[string]map[string][]string{"spec": {"users": {user: value}}}
|
||||
patchInstances, err := json.Marshal(ins)
|
||||
if err != nil {
|
||||
log.Fatal(err, "unable to parse number of instances json")
|
||||
}
|
||||
return patchInstances
|
||||
}
|
||||
|
||||
func init() {
|
||||
addUserCmd.Flags().StringP("cluster", "c", "", "add user to the provided cluster.")
|
||||
addUserCmd.Flags().StringP("privileges", "p", "", "add privileges separated by commas without spaces")
|
||||
rootCmd.AddCommand(addUserCmd)
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
postgresConstants "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
||||
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// checkCmd represent kubectl pg check.
|
||||
var checkCmd = &cobra.Command{
|
||||
Use: "check",
|
||||
Short: "Checks the Postgres operator is installed in the k8s cluster",
|
||||
Long: `Checks that the Postgres CRD is registered in a k8s cluster.
|
||||
This means that the operator pod was able to start normally.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
check()
|
||||
},
|
||||
Example: `
|
||||
kubectl pg check
|
||||
`,
|
||||
}
|
||||
|
||||
// check validates postgresql CRD registered or not.
|
||||
func check() *v1.CustomResourceDefinition {
|
||||
config := getConfig()
|
||||
apiExtClient, err := apiextv1.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
crdInfo, err := apiExtClient.CustomResourceDefinitions().Get(context.TODO(), postgresConstants.PostgresCRDResouceName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if crdInfo.Name == postgresConstants.PostgresCRDResouceName {
|
||||
fmt.Printf("Postgres Operator is installed in the k8s cluster.\n")
|
||||
} else {
|
||||
fmt.Printf("Postgres Operator is not installed in the k8s cluster.\n")
|
||||
}
|
||||
return crdInfo
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(checkCmd)
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
user "os/user"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
// connectCmd represents the kubectl pg connect command
|
||||
var connectCmd = &cobra.Command{
|
||||
Use: "connect",
|
||||
Short: "Connects to the shell prompt, psql prompt of postgres cluster",
|
||||
Long: `Connects to the shell prompt, psql prompt of postgres cluster and also to specified replica or master.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
master, _ := cmd.Flags().GetBool("master")
|
||||
replica, _ := cmd.Flags().GetString("replica")
|
||||
psql, _ := cmd.Flags().GetBool("psql")
|
||||
userName, _ := cmd.Flags().GetString("user")
|
||||
dbName, _ := cmd.Flags().GetString("database")
|
||||
|
||||
if psql {
|
||||
if userName == "" {
|
||||
userInfo, err := user.Current()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
userName = userInfo.Username
|
||||
}
|
||||
}
|
||||
if dbName == "" {
|
||||
dbName = userName
|
||||
}
|
||||
|
||||
connect(clusterName, master, replica, psql, userName, dbName)
|
||||
},
|
||||
Example: `
|
||||
#connects to the master of postgres cluster
|
||||
kubectl pg connect -c cluster -m
|
||||
|
||||
#connects to the random replica of postgres cluster
|
||||
kubectl pg connect -c cluster
|
||||
|
||||
#connects to the provided replica number of postgres cluster
|
||||
kubectl pg connect -c cluster -r 2
|
||||
|
||||
#connects to psql prompt of master for provided postgres cluster with current shell user
|
||||
kubectl pg connect -c cluster -p -m
|
||||
|
||||
#connects to psql prompt of random replica for provided postgres cluster with provided user and db
|
||||
kubectl pg connect -c cluster -p -u user01 -d db01
|
||||
`,
|
||||
}
|
||||
|
||||
func connect(clusterName string, master bool, replica string, psql bool, user string, dbName string) {
|
||||
config := getConfig()
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
podName := getPodName(clusterName, master, replica)
|
||||
var execRequest *rest.Request
|
||||
|
||||
if psql {
|
||||
execRequest = client.CoreV1().RESTClient().Post().Resource("pods").
|
||||
Name(podName).
|
||||
Namespace(getCurrentNamespace()).
|
||||
SubResource("exec").
|
||||
Param("container", "postgres").
|
||||
Param("command", "psql").
|
||||
Param("command", dbName).
|
||||
Param("command", user).
|
||||
Param("stdin", "true").
|
||||
Param("stdout", "true").
|
||||
Param("stderr", "true").
|
||||
Param("tty", "true")
|
||||
} else {
|
||||
execRequest = client.CoreV1().RESTClient().Post().Resource("pods").
|
||||
Name(podName).
|
||||
Namespace(getCurrentNamespace()).
|
||||
SubResource("exec").
|
||||
Param("container", "postgres").
|
||||
Param("command", "su").
|
||||
Param("command", "postgres").
|
||||
Param("stdin", "true").
|
||||
Param("stdout", "true").
|
||||
Param("stderr", "true").
|
||||
Param("tty", "true")
|
||||
}
|
||||
|
||||
exec, err := remotecommand.NewSPDYExecutor(config, "POST", execRequest.URL())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = exec.StreamWithContext(context.TODO(), remotecommand.StreamOptions{
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
Tty: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
connectCmd.Flags().StringP("cluster", "c", "", "provide the cluster name.")
|
||||
connectCmd.Flags().BoolP("master", "m", false, "connect to master.")
|
||||
connectCmd.Flags().StringP("replica", "r", "", "connect to replica. Specify replica number.")
|
||||
connectCmd.Flags().BoolP("psql", "p", false, "connect to psql prompt.")
|
||||
connectCmd.Flags().StringP("user", "u", "", "provide user.")
|
||||
connectCmd.Flags().StringP("database", "d", "", "provide database name.")
|
||||
rootCmd.AddCommand(connectCmd)
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
v1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
||||
PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// createCmd kubectl pg create.
|
||||
var createCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Creates postgres object using manifest file",
|
||||
Long: `Creates postgres custom resource objects from a manifest file.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fileName, _ := cmd.Flags().GetString("file")
|
||||
create(fileName)
|
||||
},
|
||||
Example: `
|
||||
kubectl pg create -f cluster-manifest.yaml
|
||||
`,
|
||||
}
|
||||
|
||||
// Create postgresql resources.
|
||||
func create(fileName string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ymlFile, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, _, err := decode([]byte(ymlFile), nil, &v1.Postgresql{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
postgresSql := obj.(*v1.Postgresql)
|
||||
_, err = postgresConfig.Postgresqls(postgresSql.Namespace).Create(context.TODO(), postgresSql, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("postgresql %s created.\n", postgresSql.Name)
|
||||
}
|
||||
|
||||
func init() {
|
||||
createCmd.Flags().StringP("file", "f", "", "manifest file with the cluster definition.")
|
||||
rootCmd.AddCommand(createCmd)
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
v1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
||||
PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// deleteCmd represents kubectl pg delete.
|
||||
var deleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Deletes postgresql object by cluster-name/manifest file",
|
||||
Long: `Deletes the postgres objects identified by a manifest file or cluster-name.
|
||||
Deleting the manifest is sufficient to delete the cluster.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
namespace, _ := cmd.Flags().GetString("namespace")
|
||||
file, _ := cmd.Flags().GetString("file")
|
||||
|
||||
if file != "" {
|
||||
deleteByFile(file)
|
||||
} else if namespace != "" {
|
||||
if len(args) != 0 {
|
||||
clusterName := args[0]
|
||||
deleteByName(clusterName, namespace)
|
||||
} else {
|
||||
fmt.Println("cluster name can't be empty")
|
||||
}
|
||||
} else {
|
||||
fmt.Println("use the flag either -n or -f to delete a resource.")
|
||||
}
|
||||
},
|
||||
Example: `
|
||||
#Deleting the postgres cluster using manifest file
|
||||
kubectl pg delete -f cluster-manifest.yaml
|
||||
|
||||
#Deleting the postgres cluster using cluster name in current namespace.
|
||||
kubectl pg delete cluster01
|
||||
|
||||
#Deleting the postgres cluster using cluster name in provided namespace
|
||||
kubectl pg delete cluster01 -n namespace01
|
||||
`,
|
||||
}
|
||||
|
||||
func deleteByFile(file string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ymlFile, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, _, err := decode([]byte(ymlFile), nil, &v1.Postgresql{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
postgresSql := obj.(*v1.Postgresql)
|
||||
_, err = postgresConfig.Postgresqls(postgresSql.Namespace).Get(context.TODO(), postgresSql.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
fmt.Printf("Postgresql %s not found with the provided namespace %s : %s \n", postgresSql.Name, postgresSql.Namespace, err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Are you sure you want to remove this PostgreSQL cluster? If so, please type (%s/%s) and hit Enter\n", postgresSql.Namespace, postgresSql.Name)
|
||||
|
||||
confirmAction(postgresSql.Name, postgresSql.Namespace)
|
||||
err = postgresConfig.Postgresqls(postgresSql.Namespace).Delete(context.TODO(), postgresSql.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("Postgresql %s deleted from %s.\n", postgresSql.Name, postgresSql.Namespace)
|
||||
}
|
||||
|
||||
func deleteByName(clusterName string, namespace string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
fmt.Printf("Postgresql %s not found with the provided namespace %s : %s \n", clusterName, namespace, err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Are you sure you want to remove this PostgreSQL cluster? If so, please type (%s/%s) and hit Enter\n", namespace, clusterName)
|
||||
|
||||
confirmAction(clusterName, namespace)
|
||||
err = postgresConfig.Postgresqls(namespace).Delete(context.TODO(), clusterName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("Postgresql %s deleted from %s.\n", clusterName, namespace)
|
||||
}
|
||||
|
||||
func init() {
|
||||
namespace := getCurrentNamespace()
|
||||
deleteCmd.Flags().StringP("namespace", "n", namespace, "namespace of the cluster to be deleted.")
|
||||
deleteCmd.Flags().StringP("file", "f", "", "manifest file with the cluster definition.")
|
||||
rootCmd.AddCommand(deleteCmd)
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// extVolumeCmd represents the extVolume command
|
||||
var extVolumeCmd = &cobra.Command{
|
||||
Use: "ext-volume",
|
||||
Short: "Increases the volume size of a given Postgres cluster",
|
||||
Long: `Extends the volume of the postgres cluster. But volume cannot be shrinked.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
if len(args) > 0 {
|
||||
volume := args[0]
|
||||
extVolume(volume, clusterName)
|
||||
} else {
|
||||
fmt.Println("please enter the cluster name with -c flag & volume in desired units")
|
||||
}
|
||||
},
|
||||
Example: `
|
||||
#Extending the volume size of provided cluster
|
||||
kubectl pg ext-volume 2Gi -c cluster01
|
||||
`,
|
||||
}
|
||||
|
||||
// extend volume with provided size & cluster name
|
||||
func extVolume(increasedVolumeSize string, clusterName string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
namespace := getCurrentNamespace()
|
||||
postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
oldSize, err := resource.ParseQuantity(postgresql.Spec.Volume.Size)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
newSize, err := resource.ParseQuantity(increasedVolumeSize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = strconv.Atoi(newSize.String())
|
||||
if err == nil {
|
||||
fmt.Println("provide the valid volume size with respective units i.e Ki, Mi, Gi")
|
||||
return
|
||||
}
|
||||
|
||||
if newSize.Value() > oldSize.Value() {
|
||||
patchInstances := volumePatch(newSize)
|
||||
response, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patchInstances, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if postgresql.ResourceVersion != response.ResourceVersion {
|
||||
fmt.Printf("%s volume is extended to %s.\n", response.Name, increasedVolumeSize)
|
||||
} else {
|
||||
fmt.Printf("%s volume %s is unchanged.\n", response.Name, postgresql.Spec.Volume.Size)
|
||||
}
|
||||
} else if newSize.Value() == oldSize.Value() {
|
||||
fmt.Println("volume already has the desired size.")
|
||||
} else {
|
||||
fmt.Printf("volume %s size cannot be shrinked.\n", postgresql.Spec.Volume.Size)
|
||||
}
|
||||
}
|
||||
|
||||
func volumePatch(volume resource.Quantity) []byte {
|
||||
patchData := map[string]map[string]map[string]resource.Quantity{"spec": {"volume": {"size": volume}}}
|
||||
patch, err := json.Marshal(patchData)
|
||||
if err != nil {
|
||||
log.Fatal(err, "unable to parse patch to extend volume")
|
||||
}
|
||||
return patch
|
||||
}
|
||||
|
||||
func init() {
|
||||
extVolumeCmd.Flags().StringP("cluster", "c", "", "provide cluster name.")
|
||||
rootCmd.AddCommand(extVolumeCmd)
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
v1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
||||
PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
TrimCreateTimestamp = 6000000000
|
||||
)
|
||||
|
||||
// listCmd represents kubectl pg list.
|
||||
var listCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "Lists all the resources of kind postgresql",
|
||||
Long: `Lists all the info specific to postgresql objects.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
allNamespaces, _ := cmd.Flags().GetBool("all-namespaces")
|
||||
namespace, _ := cmd.Flags().GetString("namespace")
|
||||
if allNamespaces {
|
||||
list(allNamespaces, "")
|
||||
} else {
|
||||
list(allNamespaces, namespace)
|
||||
}
|
||||
|
||||
},
|
||||
Example: `
|
||||
#Lists postgres cluster in current namespace
|
||||
kubectl pg list
|
||||
|
||||
#Lists postgres clusters in all namespaces
|
||||
kubectl pg list -A
|
||||
`,
|
||||
}
|
||||
|
||||
// list command to list postgres.
|
||||
func list(allNamespaces bool, namespace string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
listPostgres, err := postgresConfig.Postgresqls(namespace).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(listPostgres.Items) == 0 {
|
||||
if namespace != "" {
|
||||
fmt.Printf("No Postgresql clusters found in namespace: %v\n", namespace)
|
||||
} else {
|
||||
fmt.Println("No Postgresql clusters found in all namespaces")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if allNamespaces {
|
||||
listAll(listPostgres)
|
||||
} else {
|
||||
listWithNamespace(listPostgres)
|
||||
}
|
||||
}
|
||||
|
||||
func listAll(listPostgres *v1.PostgresqlList) {
|
||||
template := "%-32s%-16s%-12s%-12s%-12s%-12s%-12s\n"
|
||||
fmt.Printf(template, "NAME", "STATUS", "INSTANCES", "VERSION", "AGE", "VOLUME", "NAMESPACE")
|
||||
for _, pgObjs := range listPostgres.Items {
|
||||
fmt.Printf(template, pgObjs.Name,
|
||||
pgObjs.Status.PostgresClusterStatus,
|
||||
strconv.Itoa(int(pgObjs.Spec.NumberOfInstances)),
|
||||
pgObjs.Spec.PostgresqlParam.PgVersion,
|
||||
time.Since(pgObjs.CreationTimestamp.Time).Truncate(TrimCreateTimestamp),
|
||||
pgObjs.Spec.Size, pgObjs.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
func listWithNamespace(listPostgres *v1.PostgresqlList) {
|
||||
template := "%-32s%-16s%-12s%-12s%-12s%-12s\n"
|
||||
fmt.Printf(template, "NAME", "STATUS", "INSTANCES", "VERSION", "AGE", "VOLUME")
|
||||
for _, pgObjs := range listPostgres.Items {
|
||||
fmt.Printf(template, pgObjs.Name,
|
||||
pgObjs.Status.PostgresClusterStatus,
|
||||
strconv.Itoa(int(pgObjs.Spec.NumberOfInstances)),
|
||||
pgObjs.Spec.PostgresqlParam.PgVersion,
|
||||
time.Since(pgObjs.CreationTimestamp.Time).Truncate(TrimCreateTimestamp),
|
||||
pgObjs.Spec.Size)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
listCmd.Flags().BoolP("all-namespaces", "A", false, "list pg resources across all namespaces.")
|
||||
listCmd.Flags().StringP("namespace", "n", getCurrentNamespace(), "provide the namespace")
|
||||
rootCmd.AddCommand(listCmd)
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// logsCmd represents the logs command
|
||||
var logsCmd = &cobra.Command{
|
||||
Use: "logs",
|
||||
Short: "This will fetch the logs of the specified postgres cluster & postgres operator",
|
||||
Long: `Fetches the logs of the postgres cluster (i.e master( with -m flag) & replica with (-r 1 pod number) and without -m or -r connects to random replica`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
opLogs, _ := cmd.Flags().GetBool("operator")
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
master, _ := cmd.Flags().GetBool("master")
|
||||
replica, _ := cmd.Flags().GetString("replica")
|
||||
|
||||
if opLogs {
|
||||
operatorLogs()
|
||||
} else {
|
||||
clusterLogs(clusterName, master, replica)
|
||||
}
|
||||
},
|
||||
Example: `
|
||||
#Fetch the logs of the postgres operator
|
||||
kubectl pg logs -o
|
||||
|
||||
#Fetch the logs of the master for provided cluster
|
||||
kubectl pg logs -c cluster01 -m
|
||||
|
||||
#Fetch the logs of the random replica for provided cluster
|
||||
kubectl pg logs -c cluster01
|
||||
|
||||
#Fetch the logs of the provided replica number of the cluster
|
||||
kubectl pg logs -c cluster01 -r 3
|
||||
`,
|
||||
}
|
||||
|
||||
func operatorLogs() {
|
||||
config := getConfig()
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
operator := getPostgresOperator(client)
|
||||
allPods, err := client.CoreV1().Pods(operator.Namespace).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var operatorPodName string
|
||||
for _, pod := range allPods.Items {
|
||||
for key, value := range pod.Labels {
|
||||
if (key == "name" && value == OperatorName) || (key == "app.kubernetes.io/name" && value == OperatorName) {
|
||||
operatorPodName = pod.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
execRequest := client.CoreV1().RESTClient().Get().Namespace(operator.Namespace).
|
||||
Name(operatorPodName).
|
||||
Resource("pods").
|
||||
SubResource("log").
|
||||
Param("follow", "--follow").
|
||||
Param("container", OperatorName)
|
||||
|
||||
readCloser, err := execRequest.Stream(context.TODO())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer readCloser.Close()
|
||||
_, err = io.Copy(os.Stdout, readCloser)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func clusterLogs(clusterName string, master bool, replica string) {
|
||||
config := getConfig()
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
podName := getPodName(clusterName, master, replica)
|
||||
execRequest := client.CoreV1().RESTClient().Get().Namespace(getCurrentNamespace()).
|
||||
Name(podName).
|
||||
Resource("pods").
|
||||
SubResource("log").
|
||||
Param("follow", "--follow").
|
||||
Param("container", "postgres")
|
||||
|
||||
readCloser, err := execRequest.Stream(context.TODO())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer readCloser.Close()
|
||||
_, err = io.Copy(os.Stdout, readCloser)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(logsCmd)
|
||||
logsCmd.Flags().BoolP("operator", "o", false, "logs of operator")
|
||||
logsCmd.Flags().StringP("cluster", "c", "", "logs for the provided cluster")
|
||||
logsCmd.Flags().BoolP("master", "m", false, "Patroni logs of master")
|
||||
logsCmd.Flags().StringP("replica", "r", "", "Patroni logs of replica. Specify replica number.")
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "kubectl-pg",
|
||||
Short: "kubectl plugin for the Zalando Postgres operator.",
|
||||
Long: `kubectl pg plugin for interaction with Zalando postgres operator.`,
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
viper.SetDefault("author", "Vineeth Pothulapati <vineethpothulapati@outlook.com>")
|
||||
viper.SetDefault("license", "mit")
|
||||
}
|
||||
|
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// scaleCmd represents the scale command
|
||||
var scaleCmd = &cobra.Command{
|
||||
Use: "scale",
|
||||
Short: "Add/remove pods to a Postgres cluster",
|
||||
Long: `Scales the postgres objects using cluster-name.
|
||||
Scaling to 0 leads to down time.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
clusterName, err := cmd.Flags().GetString("cluster")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
namespace, err := cmd.Flags().GetString("namespace")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
numberOfInstances, err := strconv.Atoi(args[0])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
scale(int32(numberOfInstances), clusterName, namespace)
|
||||
} else {
|
||||
fmt.Println("Please enter number of instances to scale.")
|
||||
}
|
||||
|
||||
},
|
||||
Example: `
|
||||
#Usage
|
||||
kubectl pg scale [NUMBER-OF-INSTANCES] -c [CLUSTER-NAME] -n [NAMESPACE]
|
||||
|
||||
#Scales the number of instances of the provided cluster
|
||||
kubectl pg scale 5 -c cluster01
|
||||
`,
|
||||
}
|
||||
|
||||
func scale(numberOfInstances int32, clusterName string, namespace string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
minInstances, maxInstances := allowedMinMaxInstances(config)
|
||||
|
||||
if minInstances == -1 && maxInstances == -1 {
|
||||
postgresql.Spec.NumberOfInstances = numberOfInstances
|
||||
} else if numberOfInstances <= maxInstances && numberOfInstances >= minInstances {
|
||||
postgresql.Spec.NumberOfInstances = numberOfInstances
|
||||
} else if minInstances == -1 && numberOfInstances < postgresql.Spec.NumberOfInstances ||
|
||||
maxInstances == -1 && numberOfInstances > postgresql.Spec.NumberOfInstances {
|
||||
postgresql.Spec.NumberOfInstances = numberOfInstances
|
||||
} else {
|
||||
log.Fatalf("cannot scale to the provided instances as they don't adhere to MIN_INSTANCES: %v and MAX_INSTANCES: %v provided in configmap or operatorconfiguration", maxInstances, minInstances)
|
||||
}
|
||||
|
||||
if numberOfInstances == 0 {
|
||||
fmt.Printf("Scaling to zero leads to down time. please type %s/%s and hit Enter this serves to confirm the action\n", namespace, clusterName)
|
||||
confirmAction(clusterName, namespace)
|
||||
}
|
||||
|
||||
patchInstances := scalePatch(numberOfInstances)
|
||||
UpdatedPostgres, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patchInstances, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if UpdatedPostgres.ResourceVersion != postgresql.ResourceVersion {
|
||||
fmt.Printf("scaled postgresql %s/%s to %d instances\n", UpdatedPostgres.Namespace, UpdatedPostgres.Name, UpdatedPostgres.Spec.NumberOfInstances)
|
||||
return
|
||||
}
|
||||
fmt.Printf("postgresql %s is unchanged.\n", postgresql.Name)
|
||||
}
|
||||
|
||||
func scalePatch(value int32) []byte {
|
||||
instances := map[string]map[string]int32{"spec": {"numberOfInstances": value}}
|
||||
patchInstances, err := json.Marshal(instances)
|
||||
if err != nil {
|
||||
log.Fatal(err, "unable to parse patch for scale")
|
||||
}
|
||||
return patchInstances
|
||||
}
|
||||
|
||||
func allowedMinMaxInstances(config *rest.Config) (int32, int32) {
|
||||
k8sClient, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
operator := getPostgresOperator(k8sClient)
|
||||
|
||||
operatorContainer := operator.Spec.Template.Spec.Containers
|
||||
var configMapName, operatorConfigName string
|
||||
// -1 indicates no limitations for min/max instances
|
||||
minInstances := -1
|
||||
maxInstances := -1
|
||||
for _, envData := range operatorContainer[0].Env {
|
||||
if envData.Name == "CONFIG_MAP_NAME" {
|
||||
configMapName = envData.Value
|
||||
}
|
||||
if envData.Name == "POSTGRES_OPERATOR_CONFIGURATION_OBJECT" {
|
||||
operatorConfigName = envData.Value
|
||||
}
|
||||
}
|
||||
|
||||
if operatorConfigName == "" {
|
||||
configMap, err := k8sClient.CoreV1().ConfigMaps(operator.Namespace).Get(context.TODO(), configMapName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
configMapData := configMap.Data
|
||||
for key, value := range configMapData {
|
||||
if key == "min_instances" {
|
||||
minInstances, err = strconv.Atoi(value)
|
||||
if err != nil {
|
||||
log.Fatalf("invalid min instances in configmap %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if key == "max_instances" {
|
||||
maxInstances, err = strconv.Atoi(value)
|
||||
if err != nil {
|
||||
log.Fatalf("invalid max instances in configmap %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if configMapName == "" {
|
||||
pgClient, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
operatorConfig, err := pgClient.OperatorConfigurations(operator.Namespace).Get(context.TODO(), operatorConfigName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatalf("unable to read operator configuration %v", err)
|
||||
}
|
||||
|
||||
minInstances = int(operatorConfig.Configuration.MinInstances)
|
||||
maxInstances = int(operatorConfig.Configuration.MaxInstances)
|
||||
}
|
||||
return int32(minInstances), int32(maxInstances)
|
||||
}
|
||||
|
||||
func init() {
|
||||
namespace := getCurrentNamespace()
|
||||
scaleCmd.Flags().StringP("namespace", "n", namespace, "namespace of the cluster to be scaled")
|
||||
scaleCmd.Flags().StringP("cluster", "c", "", "provide the cluster name.")
|
||||
rootCmd.AddCommand(scaleCmd)
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
v1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
||||
PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// updateCmd represents kubectl pg update
|
||||
var updateCmd = &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "Updates postgresql object using manifest file",
|
||||
Long: `Updates the state of cluster using manifest file to reflect the changes on the cluster.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fileName, _ := cmd.Flags().GetString("file")
|
||||
updatePgResources(fileName)
|
||||
},
|
||||
Example: `
|
||||
#usage
|
||||
kubectl pg update -f [File-NAME]
|
||||
|
||||
#update the postgres cluster with updated manifest file
|
||||
kubectl pg update -f cluster-manifest.yaml
|
||||
`,
|
||||
}
|
||||
|
||||
// Update postgresql resources.
|
||||
func updatePgResources(fileName string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ymlFile, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, _, err := decode([]byte(ymlFile), nil, &v1.Postgresql{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
newPostgresObj := obj.(*v1.Postgresql)
|
||||
oldPostgresObj, err := postgresConfig.Postgresqls(newPostgresObj.Namespace).Get(context.TODO(), newPostgresObj.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
newPostgresObj.ResourceVersion = oldPostgresObj.ResourceVersion
|
||||
response, err := postgresConfig.Postgresqls(newPostgresObj.Namespace).Update(context.TODO(), newPostgresObj, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if newPostgresObj.ResourceVersion != response.ResourceVersion {
|
||||
fmt.Printf("postgresql %s updated.\n", response.Name)
|
||||
} else {
|
||||
fmt.Printf("postgresql %s is unchanged.\n", response.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
updateCmd.Flags().StringP("file", "f", "", "manifest file with the cluster definition.")
|
||||
rootCmd.AddCommand(updateCmd)
|
||||
}
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/util/homedir"
|
||||
)
|
||||
|
||||
const (
|
||||
OperatorName = "postgres-operator"
|
||||
DefaultNamespace = "default"
|
||||
)
|
||||
|
||||
func getConfig() *restclient.Config {
|
||||
var kubeconfig *string
|
||||
var config *restclient.Config
|
||||
envKube := os.Getenv("KUBECONFIG")
|
||||
if envKube != "" {
|
||||
kubeconfig = &envKube
|
||||
} else {
|
||||
if home := homedir.HomeDir(); home != "" {
|
||||
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
|
||||
} else {
|
||||
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
|
||||
}
|
||||
}
|
||||
flag.Parse()
|
||||
var err error
|
||||
config, err = clientcmd.BuildConfigFromFlags("", *kubeconfig)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func getCurrentNamespace() string {
|
||||
namespace, err := exec.Command("kubectl", "config", "view", "--minify", "--output", "jsonpath={..namespace}").CombinedOutput()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
currentNamespace := string(namespace)
|
||||
if currentNamespace == "" {
|
||||
currentNamespace = DefaultNamespace
|
||||
}
|
||||
return currentNamespace
|
||||
}
|
||||
|
||||
func confirmAction(clusterName string, namespace string) {
|
||||
for {
|
||||
confirmClusterDetails := ""
|
||||
_, err := fmt.Scan(&confirmClusterDetails)
|
||||
if err != nil {
|
||||
log.Fatalf("couldn't get confirmation from the user %v", err)
|
||||
}
|
||||
clusterDetails := strings.Split(confirmClusterDetails, "/")
|
||||
if clusterDetails[0] != namespace || clusterDetails[1] != clusterName {
|
||||
fmt.Printf("cluster name or namespace does not match. Please re-enter %s/%s\nHint: Press (ctrl+c) to exit\n", namespace, clusterName)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getPodName(clusterName string, master bool, replicaNumber string) string {
|
||||
config := getConfig()
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
postgresCluster, err := postgresConfig.Postgresqls(getCurrentNamespace()).Get(context.TODO(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
numOfInstances := postgresCluster.Spec.NumberOfInstances
|
||||
var podName string
|
||||
var podRole string
|
||||
replica := clusterName + "-" + replicaNumber
|
||||
|
||||
for ins := 0; ins < int(numOfInstances); ins++ {
|
||||
pod, err := client.CoreV1().Pods(getCurrentNamespace()).Get(context.TODO(), clusterName+"-"+strconv.Itoa(ins), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
podRole = pod.Labels["spilo-role"]
|
||||
if podRole == "master" && master {
|
||||
podName = pod.Name
|
||||
fmt.Printf("connected to %s with pod name as %s\n", podRole, podName)
|
||||
break
|
||||
} else if podRole == "replica" && !master && (pod.Name == replica || replicaNumber == "") {
|
||||
podName = pod.Name
|
||||
fmt.Printf("connected to %s with pod name as %s\n", podRole, podName)
|
||||
break
|
||||
}
|
||||
}
|
||||
if podName == "" {
|
||||
log.Fatal("Provided replica doesn't exist")
|
||||
}
|
||||
return podName
|
||||
}
|
||||
|
||||
func getPostgresOperator(k8sClient *kubernetes.Clientset) *v1.Deployment {
|
||||
var operator *v1.Deployment
|
||||
operator, err := k8sClient.AppsV1().Deployments(getCurrentNamespace()).Get(context.TODO(), OperatorName, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
return operator
|
||||
}
|
||||
|
||||
allDeployments := k8sClient.AppsV1().Deployments("")
|
||||
listDeployments, err := allDeployments.List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, deployment := range listDeployments.Items {
|
||||
if deployment.Name == OperatorName {
|
||||
operator = deployment.DeepCopy()
|
||||
break
|
||||
} else {
|
||||
for key, value := range deployment.Labels {
|
||||
if key == "app.kubernetes.io/name" && value == OperatorName {
|
||||
operator = deployment.DeepCopy()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return operator
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
var KubectlPgVersion string = "1.0"
|
||||
|
||||
// versionCmd represents the version command
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "version of kubectl-pg & postgres-operator",
|
||||
Long: `version of kubectl-pg and current running postgres-operator`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
namespace, err := cmd.Flags().GetString("namespace")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
version(namespace)
|
||||
},
|
||||
Example: `
|
||||
#Lists the version of kubectl pg plugin and postgres operator in current namespace
|
||||
kubectl pg version
|
||||
|
||||
#Lists the version of kubectl pg plugin and postgres operator in provided namespace
|
||||
kubectl pg version -n namespace01
|
||||
`,
|
||||
}
|
||||
|
||||
func version(namespace string) {
|
||||
fmt.Printf("kubectl-pg: %s\n", KubectlPgVersion)
|
||||
|
||||
config := getConfig()
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
operatorDeployment := getPostgresOperator(client)
|
||||
if operatorDeployment.Name == "" {
|
||||
log.Fatalf("make sure zalando's postgres operator is running in namespace %s", namespace)
|
||||
}
|
||||
operatorImage := operatorDeployment.Spec.Template.Spec.Containers[0].Image
|
||||
imageDetails := strings.Split(operatorImage, ":")
|
||||
imageSplit := len(imageDetails)
|
||||
imageVersion := imageDetails[imageSplit-1]
|
||||
fmt.Printf("Postgres-Operator: %s\n", imageVersion)
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
versionCmd.Flags().StringP("namespace", "n", DefaultNamespace, "provide the namespace.")
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
module github.com/zalando/postgres-operator/kubectl-pg
|
||||
|
||||
go 1.25.3
|
||||
|
||||
require (
|
||||
github.com/spf13/cobra v1.10.1
|
||||
github.com/spf13/viper v1.21.0
|
||||
github.com/zalando/postgres-operator v1.15.0
|
||||
k8s.io/api v0.32.9
|
||||
k8s.io/apiextensions-apiserver v0.25.9
|
||||
k8s.io/apimachinery v0.32.9
|
||||
k8s.io/client-go v0.32.9
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/moby/spdystream v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.27.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
|
|
@ -1,206 +0,0 @@
|
|||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
|
||||
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
|
||||
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d h1:LznySqW8MqVeFh+pW6rOkFdld9QQ7jRydBKKM6jyPVI=
|
||||
github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d/go.mod h1:u3hJ0kqCQu/cPpsu3RbCOPZ0d7V3IjPjv1adNRleM9I=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
|
||||
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/zalando/postgres-operator v1.15.0 h1:is/7cOrpuV7OwMiN7TG7GgiYHKvaWx8Ptw3hJruFO1I=
|
||||
github.com/zalando/postgres-operator v1.15.0/go.mod h1:1cSOA5dG2dEqdG0uami1RHTGYX92bgAKYASfAhuMtHE=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.32.9 h1:q/59kk8lnecgG0grJqzrmXC1Jcl2hPWp9ltz0FQuoLI=
|
||||
k8s.io/api v0.32.9/go.mod h1:jIfT3rwW4EU1IXZm9qjzSk/2j91k4CJL5vUULrxqp3Y=
|
||||
k8s.io/apiextensions-apiserver v0.25.9 h1:Pycd6lm2auABp9wKQHCFSEPG+NPdFSTJXPST6NJFzB8=
|
||||
k8s.io/apiextensions-apiserver v0.25.9/go.mod h1:ijGxmSG1GLOEaWhTuaEr0M7KUeia3mWCZa6FFQqpt1M=
|
||||
k8s.io/apimachinery v0.32.9 h1:fXk8ktfsxrdThaEOAQFgkhCK7iyoyvS8nbYJ83o/SSs=
|
||||
k8s.io/apimachinery v0.32.9/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/client-go v0.32.9 h1:ZMyIQ1TEpTDAQni3L2gH1NZzyOA/gHfNcAazzCxMJ0c=
|
||||
k8s.io/client-go v0.32.9/go.mod h1:2OT8aFSYvUjKGadaeT+AVbhkXQSpMAkiSb88Kz2WggI=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/zalando/postgres-operator/kubectl-pg/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
||||
Loading…
Reference in New Issue