Added curd operation and private hub support in myhub

Signed-off-by: Amit Kumar Das <amitkumar.das@mayadata.io>
This commit is contained in:
Amit Kumar Das 2021-01-11 18:31:37 +05:30
parent c5723964aa
commit b9cf1bad41
12 changed files with 2695 additions and 707 deletions

View File

@ -19,7 +19,7 @@ require (
github.com/tidwall/sjson v1.1.1
github.com/vektah/gqlparser/v2 v2.0.1
go.mongodb.org/mongo-driver v1.3.5
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect

File diff suppressed because it is too large Load Diff

View File

@ -62,6 +62,12 @@ type CloningInput struct {
ProjectID string `json:"ProjectID"`
RepoBranch string `json:"RepoBranch"`
RepoURL string `json:"RepoURL"`
IsPrivate bool `json:"IsPrivate"`
AuthType AuthType `json:"AuthType"`
Token *string `json:"Token"`
UserName *string `json:"UserName"`
Password *string `json:"Password"`
SSHPrivateKey *string `json:"SSHPrivateKey"`
}
type Cluster struct {
@ -140,6 +146,13 @@ type CreateMyHub struct {
HubName string `json:"HubName"`
RepoURL string `json:"RepoURL"`
RepoBranch string `json:"RepoBranch"`
IsPrivate bool `json:"IsPrivate"`
AuthType AuthType `json:"AuthType"`
Token *string `json:"Token"`
UserName *string `json:"UserName"`
Password *string `json:"Password"`
SSHPrivateKey *string `json:"SSHPrivateKey"`
SSHPublicKey *string `json:"SSHPublicKey"`
}
type CreateUserInput struct {
@ -202,8 +215,16 @@ type MyHub struct {
RepoBranch string `json:"RepoBranch"`
ProjectID string `json:"ProjectID"`
HubName string `json:"HubName"`
IsPrivate bool `json:"IsPrivate"`
AuthType AuthType `json:"AuthType"`
Token *string `json:"Token"`
UserName *string `json:"UserName"`
Password *string `json:"Password"`
SSHPrivateKey *string `json:"SSHPrivateKey"`
IsRemoved bool `json:"IsRemoved"`
CreatedAt string `json:"CreatedAt"`
UpdatedAt string `json:"UpdatedAt"`
LastSyncedAt string `json:"LastSyncedAt"`
}
type MyHubStatus struct {
@ -213,6 +234,15 @@ type MyHubStatus struct {
IsAvailable bool `json:"IsAvailable"`
TotalExp string `json:"TotalExp"`
HubName string `json:"HubName"`
IsPrivate bool `json:"IsPrivate"`
AuthType AuthType `json:"AuthType"`
Token *string `json:"Token"`
UserName *string `json:"UserName"`
Password *string `json:"Password"`
IsRemoved bool `json:"IsRemoved"`
SSHPrivateKey *string `json:"SSHPrivateKey"`
SSHPublicKey *string `json:"SSHPublicKey"`
LastSyncedAt string `json:"LastSyncedAt"`
}
type PackageInformation struct {
@ -261,6 +291,11 @@ type Provider struct {
Name string `json:"Name"`
}
type SSHKey struct {
PublicKey string `json:"publicKey"`
PrivateKey string `json:"privateKey"`
}
type ScheduledWorkflows struct {
WorkflowID string `json:"workflow_id"`
WorkflowManifest string `json:"workflow_manifest"`
@ -293,6 +328,20 @@ type Spec struct {
ChaosType *string `json:"ChaosType"`
}
type UpdateMyHub struct {
ID string `json:"id"`
HubName string `json:"HubName"`
RepoURL string `json:"RepoURL"`
RepoBranch string `json:"RepoBranch"`
IsPrivate bool `json:"IsPrivate"`
AuthType AuthType `json:"AuthType"`
Token *string `json:"Token"`
UserName *string `json:"UserName"`
Password *string `json:"Password"`
SSHPrivateKey *string `json:"SSHPrivateKey"`
SSHPublicKey *string `json:"SSHPublicKey"`
}
type UpdateUserInput struct {
ID string `json:"id"`
Name *string `json:"name"`
@ -376,6 +425,49 @@ type Weightages struct {
Weightage int `json:"weightage"`
}
type AuthType string
const (
AuthTypeBasic AuthType = "basic"
AuthTypeToken AuthType = "token"
AuthTypeSSH AuthType = "ssh"
)
var AllAuthType = []AuthType{
AuthTypeBasic,
AuthTypeToken,
AuthTypeSSH,
}
func (e AuthType) IsValid() bool {
switch e {
case AuthTypeBasic, AuthTypeToken, AuthTypeSSH:
return true
}
return false
}
func (e AuthType) String() string {
return string(e)
}
func (e *AuthType) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}
*e = AuthType(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid AuthType", str)
}
return nil
}
func (e AuthType) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
type MemberRole string
const (

View File

@ -1,11 +1,29 @@
enum AuthType {
basic
token
ssh
}
type MyHub {
id: ID!
RepoURL: String!
RepoBranch: String!
ProjectID: String!
HubName: String!
IsPrivate: Boolean!
# Auth Types-
# token: Token based authentication
# basic: Username/Password based authentication
# ssh: SSH based authentication
AuthType: AuthType!
Token: String
UserName: String
Password: String
SSHPrivateKey: String
IsRemoved: Boolean!
CreatedAt: String!
UpdatedAt: String!
LastSyncedAt: String!
}
type Charts {
@ -83,12 +101,36 @@ type MyHubStatus {
IsAvailable: Boolean!
TotalExp: String!
HubName: String!
IsPrivate: Boolean!
# Auth Types-
# token: Token based authentication
# basic: Username/Password based authentication
# ssh: SSH based authentication
AuthType: AuthType!
Token: String
UserName: String
Password: String
IsRemoved: Boolean!
SSHPrivateKey: String
SSHPublicKey: String
LastSyncedAt: String!
}
input CreateMyHub {
HubName: String!
RepoURL: String!
RepoBranch: String!
IsPrivate: Boolean!
# Auth Types-
# token: Token based authentication
# basic: Username/Password based authentication
# ssh: SSH based authentication
AuthType: AuthType!
Token: String
UserName: String
Password: String
SSHPrivateKey: String
SSHPublicKey: String
}
input ExperimentInput {
@ -104,4 +146,28 @@ input CloningInput {
ProjectID: String!
RepoBranch: String!
RepoURL: String!
IsPrivate: Boolean!
# Auth Types-
# token: Token based authentication
# basic: Username/Password based authentication
# ssh: SSH based authentication
AuthType: AuthType!
Token: String
UserName: String
Password: String
SSHPrivateKey: String
}
input UpdateMyHub {
id: String!
HubName: String!
RepoURL: String!
RepoBranch: String!
IsPrivate: Boolean!
AuthType: AuthType!
Token: String
UserName: String
Password: String
SSHPrivateKey: String
SSHPublicKey: String
}

View File

@ -208,6 +208,11 @@ type clusterRegResponse {
cluster_name: String!
}
type SSHKey {
publicKey: String!
privateKey: String!
}
type Query {
# [Deprecated soon]
getWorkFlowRuns(project_id: String!): [WorkflowRun!]! @authorized
@ -268,12 +273,20 @@ type Mutation {
addMyHub(myhubInput: CreateMyHub!, projectID: String!): MyHub! @authorized
syncHub(projectID: String!, HubName: String!): [MyHubStatus!]! @authorized
saveMyHub(myhubInput: CreateMyHub!, projectID: String!): MyHub! @authorized
syncHub(id: ID!): [MyHubStatus!]! @authorized
updateChaosWorkflow(input: ChaosWorkFlowInput): ChaosWorkFlowResponse!
@authorized
deleteClusterReg(cluster_id: String!): String! @authorized
generaterSSHKey: SSHKey! @authorized
updateMyHub(myhubInput: UpdateMyHub!, projectID: String!): MyHub! @authorized
deleteMyHub(hub_id: String!): Boolean! @authorized
}
type Subscription {

View File

@ -6,6 +6,7 @@ package graph
import (
"context"
"errors"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/myhub/gitops"
"log"
"strconv"
"time"
@ -81,8 +82,12 @@ func (r *mutationResolver) AddMyHub(ctx context.Context, myhubInput model.Create
return myhub.AddMyHub(ctx, myhubInput, projectID)
}
func (r *mutationResolver) SyncHub(ctx context.Context, projectID string, hubName string) ([]*model.MyHubStatus, error) {
return myhub.SyncHub(ctx, projectID, hubName)
func (r *mutationResolver) SaveMyHub(ctx context.Context, myhubInput model.CreateMyHub, projectID string) (*model.MyHub, error) {
return myhub.SaveMyHub(ctx, myhubInput, projectID)
}
func (r *mutationResolver) SyncHub(ctx context.Context, id string) ([]*model.MyHubStatus, error) {
return myhub.SyncHub(ctx, id)
}
func (r *mutationResolver) UpdateChaosWorkflow(ctx context.Context, input *model.ChaosWorkFlowInput) (*model.ChaosWorkFlowResponse, error) {
@ -93,6 +98,26 @@ func (r *mutationResolver) DeleteClusterReg(ctx context.Context, clusterID strin
return mutations.DeleteCluster(clusterID, *store)
}
func (r *mutationResolver) GeneraterSSHKey(ctx context.Context) (*model.SSHKey, error) {
publicKey, privateKey, err := gitops.GenerateKeys()
if err != nil {
return nil, err
}
return &model.SSHKey{
PrivateKey: privateKey,
PublicKey: publicKey,
}, nil
}
func (r *mutationResolver) UpdateMyHub(ctx context.Context, myhubInput model.UpdateMyHub, projectID string) (*model.MyHub, error) {
return myhub.UpdateMyHub(ctx, myhubInput, projectID)
}
func (r *mutationResolver) DeleteMyHub(ctx context.Context, hubID string) (bool, error) {
return myhub.DeleteMyHub(ctx, hubID)
}
func (r *queryResolver) GetWorkFlowRuns(ctx context.Context, projectID string) ([]*model.WorkflowRun, error) {
return queries.QueryWorkflowRuns(projectID)
}

View File

@ -2,6 +2,7 @@ package operations
import (
"context"
"errors"
"log"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
@ -60,3 +61,27 @@ func GetHubs(ctx context.Context) ([]dbSchema.MyHub, error) {
}
return MyHubs, nil
}
//GetHubByID
func GetHubByID(ctx context.Context, hubID string) (dbSchema.MyHub, error) {
var myHub dbSchema.MyHub
err := myhubCollection.FindOne(ctx, bson.M{"myhub_id": hubID}).Decode(&myHub)
if err != nil {
return dbSchema.MyHub{}, err
}
return myHub, nil
}
func UpdateMyHub(ctx context.Context, query bson.D, update bson.D) error {
updateResult, err := myhubCollection.UpdateOne(ctx, query, update)
if err != nil {
return err
}
if updateResult.MatchedCount == 0 {
return errors.New("Myhub collection query didn't matched")
}
return nil
}

View File

@ -9,8 +9,17 @@ type MyHub struct {
RepoURL string `bson:"repo_url"`
RepoBranch string `bson:"repo_branch"`
HubName string `bson:"hub_name"`
IsPrivate bool `bson:"IsPrivate"`
AuthType string `bson:"AuthType"`
Token *string `bson:"Token"`
UserName *string `bson:"UserName"`
Password *string `bson:"Password"`
SSHPrivateKey *string `bson:"SSHPrivateKey"`
SSHPublicKey *string `bson:"SSHPublicKey"`
IsRemoved bool `bson:"IsRemoved"`
CreatedAt string `bson:"created_at"`
UpdatedAt string `bson:"updated_at"`
LastSyncedAt string `bson:"last_synced_at"`
}
//GetOutputMyHub ...
@ -22,7 +31,15 @@ func (myhub *MyHub) GetOutputMyHub() *model.MyHub {
RepoURL: myhub.RepoURL,
RepoBranch: myhub.RepoBranch,
HubName: myhub.HubName,
IsPrivate: myhub.IsPrivate,
UserName: myhub.UserName,
Password: myhub.Password,
AuthType: model.AuthType(myhub.AuthType),
Token: myhub.Token,
IsRemoved: myhub.IsRemoved,
SSHPrivateKey: myhub.SSHPrivateKey,
CreatedAt: myhub.CreatedAt,
UpdatedAt: myhub.UpdatedAt,
LastSyncedAt: myhub.LastSyncedAt,
}
}

View File

@ -2,6 +2,10 @@ package gitops
import (
"fmt"
ssh2 "golang.org/x/crypto/ssh"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/plumbing/transport/http"
"gopkg.in/src-d/go-git.v4/plumbing/transport/ssh"
"os"
"strings"
@ -11,8 +15,8 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing"
)
//GitConfig ...
type GitConfig struct {
//MyHubConfig ...
type MyHubConfig struct {
ProjectID string
RepositoryURL string
RemoteName string
@ -20,34 +24,38 @@ type GitConfig struct {
RemoteCommit string
HubName string
Branch string
IsPrivate bool
UserName *string
Password *string
AuthType model.AuthType
Token *string
SSHPrivateKey *string
}
var (
repository *git.Repository
workTree *git.Worktree
plumbingRef *plumbing.Reference
status *git.Status
err error
)
const (
defaultPath = "/tmp/version/"
)
//GetClonePath is used to construct path for Repository.
func GetClonePath(c GitConfig) string {
func GetClonePath(c MyHubConfig) string {
RepoPath := defaultPath + c.ProjectID + "/" + c.HubName
return RepoPath
}
//GitConfigConstruct is used for constructing the gitconfig
func GitConfigConstruct(repoData model.CloningInput) GitConfig {
gitConfig := GitConfig{
func GitConfigConstruct(repoData model.CloningInput) MyHubConfig {
gitConfig := MyHubConfig{
ProjectID: repoData.ProjectID,
HubName: repoData.HubName,
RepositoryURL: repoData.RepoURL,
RemoteName: "origin",
Branch: repoData.RepoBranch,
IsPrivate: repoData.IsPrivate,
UserName: repoData.UserName,
Password: repoData.Password,
AuthType: repoData.AuthType,
Token: repoData.Token,
SSHPrivateKey: repoData.SSHPrivateKey,
}
return gitConfig
@ -56,18 +64,56 @@ func GitConfigConstruct(repoData model.CloningInput) GitConfig {
//GitClone Trigger is reponsible for setting off the go routine for git-op
func GitClone(repoData model.CloningInput) error {
gitConfig := GitConfigConstruct(repoData)
if repoData.IsPrivate {
_, err := gitConfig.getPrivateChaosChartRepo()
if err != nil {
fmt.Print("Error in cloning")
return err
}
} else {
_, err := gitConfig.getChaosChartRepo()
if err != nil {
fmt.Print("Error in cloning")
return err
}
}
//Successfully Cloned
return nil
}
//getChaosChartVersion is responsible for plain cloning the repository
func (c MyHubConfig) getChaosChartRepo() (string, error) {
ClonePath := GetClonePath(c)
os.RemoveAll(ClonePath)
_, err := git.PlainClone(ClonePath, false, &git.CloneOptions{
URL: c.RepositoryURL, Progress: os.Stdout,
ReferenceName: plumbing.NewBranchReferenceName(c.Branch),
})
return c.Branch, err
}
//getPrivateChaosChartVersion is responsible for plain cloning the private repository
func (c MyHubConfig) getPrivateChaosChartRepo() (string, error) {
ClonePath := GetClonePath(c)
os.RemoveAll(ClonePath)
auth, err := c.generateAuthMethod()
if err != nil {
return "", err
}
_, err = git.PlainClone(ClonePath, false, &git.CloneOptions{
Auth: auth,
URL: c.RepositoryURL,
Progress: os.Stdout,
ReferenceName: plumbing.NewBranchReferenceName(c.Branch),
})
return c.Branch, err
}
//GitSyncHandlerForProjects ...
func GitSyncHandlerForProjects(repoData model.CloningInput) error {
gitConfig := GitConfigConstruct(repoData)
if err := gitConfig.chaosChartSyncHandler(); err != nil {
log.Error(err)
@ -78,32 +124,33 @@ func GitSyncHandlerForProjects(repoData model.CloningInput) error {
return nil
}
//getChaosChartVersion is responsible for plain cloning the repository
func (c GitConfig) getChaosChartRepo() (string, error) {
ClonePath := GetClonePath(c)
os.RemoveAll(ClonePath)
_, err := git.PlainClone(ClonePath, false, &git.CloneOptions{
URL: c.RepositoryURL, Progress: os.Stdout,
ReferenceName: plumbing.NewBranchReferenceName(c.Branch),
})
return c.Branch, err
}
// chaosChartSyncHandler is responsible for all the handler functions
func (c GitConfig) chaosChartSyncHandler() error {
func (c MyHubConfig) chaosChartSyncHandler() error {
repositoryExists, err := c.isRepositoryExists()
if err != nil {
return fmt.Errorf("Error while checking repo exists, err: %s", err)
}
log.WithFields(log.Fields{"repositoryExists": repositoryExists}).Info("Executed isRepositoryExists()... ")
if !repositoryExists {
return c.HandlerForNonExistingRepository()
return GitClone(model.CloningInput{
HubName: c.HubName,
ProjectID: c.ProjectID,
RepoURL: c.RepositoryURL,
RepoBranch: c.Branch,
IsPrivate: c.IsPrivate,
AuthType: c.AuthType,
Token: c.Token,
UserName: c.UserName,
Password: c.Password,
SSHPrivateKey: c.SSHPrivateKey,
})
}
return c.HandlerForExistingRepository()
return c.GitPull()
}
// isRepositoryExists checks for the existence of this past existence of this repository
func (c GitConfig) isRepositoryExists() (bool, error) {
func (c MyHubConfig) isRepositoryExists() (bool, error) {
RepoPath := GetClonePath(c)
_, err := os.Stat(RepoPath)
if err != nil {
@ -115,90 +162,25 @@ func (c GitConfig) isRepositoryExists() (bool, error) {
return true, nil
}
// HandlerForNonExistingRepository calls function GitPlainClone, which is called only when the repository exists
func (c GitConfig) HandlerForNonExistingRepository() error {
func (c MyHubConfig) setterRepositoryWorktreeReference() (*git.Repository, *git.Worktree, *plumbing.Reference, error) {
RepoPath := GetClonePath(c)
var referenceName plumbing.ReferenceName
referenceName = plumbing.NewBranchReferenceName(c.Branch)
_, err := git.PlainClone(RepoPath, false, &git.CloneOptions{
URL: c.RepositoryURL, Progress: os.Stdout,
ReferenceName: referenceName,
})
repository, err := git.PlainOpen(RepoPath)
if err != nil {
return fmt.Errorf("unable to clone '%s' reference of chaos-chart, err: %+v", c.Branch, err)
return nil, nil, nil, fmt.Errorf("error in executing PlainOpen: %s", err)
}
return nil
}
// HandlerForExistingRepository relative functions if the isRepositoryExists fails
func (c GitConfig) HandlerForExistingRepository() error {
dirtyStatus, err := c.GitGetStatus()
workTree, err := repository.Worktree()
if err != nil {
return err
return nil, nil, nil, fmt.Errorf("error in executing Worktree: %s", err)
}
log.WithFields(log.Fields{"DirtyStatus": dirtyStatus}).Info("Executed GitGetStatus()... ")
if dirtyStatus {
return c.HandlerForDirtyStatus()
}
return c.HandlerForCleanStatus()
}
// GitGetStatus excutes "git get status --porcelain" for the provided Repository Path,
// returns false if the repository is clean
// and true if the repository is dirtygitConfig
func (c GitConfig) GitGetStatus() (bool, error) {
err := c.setterRepositoryWorktreeReference()
plumbingRef, err := repository.Head()
if err != nil {
return true, err
return nil, nil, nil, fmt.Errorf("error in executing Head: %s", err)
}
// git status --porcelain
len, _ := getListofFilesChanged()
return !(len == 0), nil
}
func (c GitConfig) setterRepositoryWorktreeReference() error {
RepoPath := GetClonePath(c)
if repository, err = git.PlainOpen(RepoPath); err != nil {
return fmt.Errorf("error in executing PlainOpen: %s", err)
}
if workTree, err = repository.Worktree(); err != nil {
return fmt.Errorf("error in executing Worktree: %s", err)
}
plumbingRef, err = repository.Head()
if err != nil {
return fmt.Errorf("error in executing Head: %s", err)
}
return nil
}
// HandlerForDirtyStatus calls relative functions if the GitGetStatus gives a clean status as a result
func (c GitConfig) HandlerForDirtyStatus() error {
if err := c.GitHardReset(); err != nil {
return err
}
MatchValue, err := c.CompareLocalandRemoteCommit()
if err != nil {
return err
}
log.WithFields(log.Fields{"MatchValue": MatchValue}).Info("Executed CompareLocalandRemoteCommit()... ")
if !MatchValue {
return c.HandlerForMismatchCommits()
}
return nil
}
func getListofFilesChanged() (int, error) {
status, err := workTree.Status()
if err != nil {
return 0, fmt.Errorf("error in executing Status: %s", err)
}
var listOfFilesChanged []string
for file := range status {
listOfFilesChanged = append(listOfFilesChanged, file)
}
return len(listOfFilesChanged), nil
return repository, workTree, plumbingRef, nil
}
// GitHardReset executes "git reset --hard HEAD" in provided Repository Path
func (c GitConfig) GitHardReset() error {
func (c MyHubConfig) GitHardReset() error {
RepoPath := GetClonePath(c)
repository, err := git.PlainOpen(RepoPath)
if err != nil {
@ -215,7 +197,7 @@ func (c GitConfig) GitHardReset() error {
}
// CompareLocalandRemoteCommit compares local and remote latest commit
func (c GitConfig) CompareLocalandRemoteCommit() (bool, error) {
func (c MyHubConfig) CompareLocalandRemoteCommit() (bool, error) {
RepoPath := GetClonePath(c)
repository, err := git.PlainOpen(RepoPath)
if err != nil {
@ -230,36 +212,55 @@ func (c GitConfig) CompareLocalandRemoteCommit() (bool, error) {
}
// GitPull updates the repository in provided Path
func (c GitConfig) GitPull() error {
err := c.setterRepositoryWorktreeReference()
func (c MyHubConfig) GitPull() error {
_, workTree, plumbingRef, err := c.setterRepositoryWorktreeReference()
if err != nil {
return err
}
var referenceName plumbing.ReferenceName
referenceName = plumbing.NewBranchReferenceName(c.Branch)
if !c.IsPrivate {
err = workTree.Pull(&git.PullOptions{RemoteName: c.RemoteName, ReferenceName: referenceName})
if err == git.NoErrAlreadyUpToDate {
log.Print("Already up-to-date")
return nil
} else if err != nil {
return err
}
c.LocalCommit = strings.Split(plumbingRef.String(), " ")[0]
return nil
}
err = c.gitPullPrivateRepo()
if err == git.NoErrAlreadyUpToDate {
log.Print("Already up-to-date")
return nil
} else if err != nil {
return err
}
return nil
}
// HandlerForCleanStatus calls relative functions if the GitGetStatus gives a clean status as a result
func (c GitConfig) HandlerForCleanStatus() error {
MatchValue, err := c.CompareLocalandRemoteCommit()
// gitPullPrivateRepo updates the repository of private hubs
func (c MyHubConfig) gitPullPrivateRepo() error {
_, workTree, _, err := c.setterRepositoryWorktreeReference()
if err != nil {
return err
}
log.WithFields(log.Fields{"MatchValue": MatchValue}).Info("Executed CompareLocalandRemoteCommit()... ")
if !MatchValue {
err := c.GitPull()
var referenceName plumbing.ReferenceName
referenceName = plumbing.NewBranchReferenceName(c.Branch)
auth, err := c.generateAuthMethod()
if err != nil {
return nil
}
err = workTree.Pull(&git.PullOptions{RemoteName: c.RemoteName, ReferenceName: referenceName, Auth: auth})
if err != nil {
return err
}
}
return nil
}
// HandlerForMismatchCommits calls relative functions if the Local and Remote Commits do not match
func (c GitConfig) HandlerForMismatchCommits() error {
func (c MyHubConfig) HandlerForMismatchCommits() error {
err := c.GitPull()
if err != nil {
return err
@ -267,3 +268,28 @@ func (c GitConfig) HandlerForMismatchCommits() error {
log.WithFields(log.Fields{"execution": "complete"}).Info("Executed GitPull()... ")
return nil
}
// generateAuthMethod creates AuthMethod for private repos
func (c MyHubConfig) generateAuthMethod() (transport.AuthMethod, error) {
var auth transport.AuthMethod
if c.AuthType == model.AuthTypeToken {
auth = &http.BasicAuth{
Username: "kubera", // this can be anything except an empty string
Password: *c.Token,
}
} else if c.AuthType == model.AuthTypeBasic {
auth = &http.BasicAuth{
Username: *c.UserName,
Password: *c.Password,
}
} else if c.AuthType == model.AuthTypeSSH {
publicKey, err := ssh.NewPublicKeys("git", []byte(*c.SSHPrivateKey), "")
if err != nil {
return nil, err
}
auth = publicKey
auth.(*ssh.PublicKeys).HostKeyCallback = ssh2.InsecureIgnoreHostKey()
}
return auth, nil
}

View File

@ -0,0 +1,80 @@
package gitops
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"log"
"golang.org/x/crypto/ssh"
)
// GenerateKeys ...
func GenerateKeys() (string, string, error) {
bitSize := 4096
privateKey, err := generatePrivateKey(bitSize)
if err != nil {
return "", "", err
}
publicKeyBytes, err := generatePublicKey(&privateKey.PublicKey)
if err != nil {
return "", "", err
}
privateKeyBytes := encodePrivateKeyToPEM(privateKey)
return string(publicKeyBytes), string(privateKeyBytes), nil
}
// generatePrivateKey creates a RSA Private Key of specified byte size
func generatePrivateKey(bitSize int) (*rsa.PrivateKey, error) {
// Private Key generation
privateKey, err := rsa.GenerateKey(rand.Reader, bitSize)
if err != nil {
return nil, err
}
// Validate Private Key
err = privateKey.Validate()
if err != nil {
return nil, err
}
log.Println("Private Key generated")
return privateKey, nil
}
// encodePrivateKeyToPEM encodes Private Key from RSA to PEM format
func encodePrivateKeyToPEM(privateKey *rsa.PrivateKey) []byte {
// Get ASN.1 DER format
privDER := x509.MarshalPKCS1PrivateKey(privateKey)
// pem.Block
privBlock := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: privDER,
}
// Private key in PEM format
privatePEM := pem.EncodeToMemory(&privBlock)
return privatePEM
}
// generatePublicKey take a rsa.PublicKey and return bytes suitable for writing to .pub file
// returns in the format "ssh-rsa ..."
func generatePublicKey(privatekey *rsa.PublicKey) ([]byte, error) {
publicRsaKey, err := ssh.NewPublicKey(privatekey)
if err != nil {
return nil, err
}
pubKeyBytes := ssh.MarshalAuthorizedKey(publicRsaKey)
log.Println("Public key generated")
return pubKeyBytes, nil
}

View File

@ -3,12 +3,15 @@ package myhub
import (
"context"
"errors"
"fmt"
"github.com/google/uuid"
"github.com/jinzhu/copier"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/graph/model"
database "github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb/operations"
dbSchema "github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb/schema"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/myhub/gitops"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/myhub/handler"
"go.mongodb.org/mongo-driver/bson"
"log"
"strconv"
"time"
@ -30,6 +33,12 @@ func AddMyHub(ctx context.Context, myhub model.CreateMyHub, projectID string) (*
RepoBranch: myhub.RepoBranch,
RepoURL: myhub.RepoURL,
HubName: myhub.HubName,
IsPrivate: myhub.IsPrivate,
UserName: myhub.UserName,
Password: myhub.Password,
AuthType: myhub.AuthType,
Token: myhub.Token,
SSHPrivateKey: myhub.SSHPrivateKey,
}
//Cloning the repository at a path from myhub link structure.
@ -46,8 +55,17 @@ func AddMyHub(ctx context.Context, myhub model.CreateMyHub, projectID string) (*
RepoURL: myhub.RepoURL,
RepoBranch: myhub.RepoBranch,
HubName: myhub.HubName,
IsPrivate: myhub.IsPrivate,
AuthType: string(myhub.AuthType),
Token: myhub.Token,
UserName: myhub.UserName,
Password: myhub.Password,
SSHPrivateKey: myhub.SSHPrivateKey,
SSHPublicKey: myhub.SSHPublicKey,
IsRemoved: false,
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
LastSyncedAt: strconv.FormatInt(time.Now().Unix(), 10),
}
//Adding the new hub into database with the given username.
@ -60,6 +78,48 @@ func AddMyHub(ctx context.Context, myhub model.CreateMyHub, projectID string) (*
return newHub.GetOutputMyHub(), nil
}
//SaveMyHub is used for Adding a new MyHub
func SaveMyHub(ctx context.Context, myhub model.CreateMyHub, projectID string) (*model.MyHub, error) {
IsExist, err := IsMyHubAvailable(ctx, myhub.HubName, projectID)
if err != nil {
return nil, err
}
if IsExist == true {
return nil, errors.New("HubName Already exists")
}
//Initialize a UID for new Hub.
uuid := uuid.New()
newHub := &dbSchema.MyHub{
ID: uuid.String(),
ProjectID: projectID,
RepoURL: myhub.RepoURL,
RepoBranch: myhub.RepoBranch,
HubName: myhub.HubName,
IsPrivate: myhub.IsPrivate,
AuthType: string(myhub.AuthType),
Token: myhub.Token,
UserName: myhub.UserName,
Password: myhub.Password,
SSHPrivateKey: myhub.SSHPrivateKey,
SSHPublicKey: myhub.SSHPublicKey,
IsRemoved: false,
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
LastSyncedAt: strconv.FormatInt(time.Now().Unix(), 10),
}
//Adding the new hub into database with the given username without cloning.
err = database.CreateMyHub(ctx, newHub)
if err != nil {
log.Print("ERROR", err)
return nil, err
}
return newHub.GetOutputMyHub(), nil
}
//HubStatus returns the array of hubdetails with their current status.
func HubStatus(ctx context.Context, projectID string) ([]*model.MyHubStatus, error) {
@ -95,6 +155,15 @@ func HubStatus(ctx context.Context, projectID string) ([]*model.MyHubStatus, err
RepoURL: hub.RepoURL,
HubName: hub.HubName,
RepoBranch: hub.RepoBranch,
IsPrivate: hub.IsPrivate,
AuthType: model.AuthType(hub.AuthType),
Token: hub.Token,
UserName: hub.UserName,
Password: hub.Password,
SSHPrivateKey: hub.SSHPrivateKey,
SSHPublicKey: hub.SSHPublicKey,
IsRemoved: hub.IsRemoved,
LastSyncedAt: hub.LastSyncedAt,
TotalExp: strconv.Itoa(sum),
}
hubDetails = append(hubDetails, hubDetail)
@ -163,23 +232,39 @@ func GetExperiment(ctx context.Context, experimentInput model.ExperimentInput) (
}
//SyncHub is used for syncing the hub again if some not present or some error happens.
func SyncHub(ctx context.Context, projectID string, hubName string) ([]*model.MyHubStatus, error) {
syncHubInput := model.CloningInput{}
myhubs, err := database.GetMyHubByProjectID(ctx, projectID)
for _, n := range myhubs {
if n.HubName == hubName {
syncHubInput = model.CloningInput{
HubName: hubName,
ProjectID: projectID,
RepoURL: n.RepoURL,
RepoBranch: n.RepoBranch,
}
func SyncHub(ctx context.Context, hubID string) ([]*model.MyHubStatus, error) {
myhub, err := database.GetHubByID(ctx, hubID)
if err != nil {
return nil, err
}
syncHubInput := model.CloningInput{
HubName: myhub.HubName,
ProjectID: myhub.ProjectID,
RepoURL: myhub.RepoURL,
RepoBranch: myhub.RepoBranch,
IsPrivate: myhub.IsPrivate,
UserName: myhub.UserName,
Password: myhub.Password,
AuthType: model.AuthType(myhub.AuthType),
Token: myhub.Token,
SSHPrivateKey: myhub.SSHPrivateKey,
}
time := strconv.FormatInt(time.Now().Unix(), 10)
query := bson.D{{"myhub_id", hubID}, {"IsRemoved", false}}
update := bson.D{{"$set", bson.D{{"last_synced_at", time}}}}
err = gitops.GitSyncHandlerForProjects(syncHubInput)
if err != nil {
return nil, err
}
//Updating the last_synced_at time using hubID
err = database.UpdateMyHub(ctx, query, update)
if err != nil {
log.Print("ERROR", err)
return nil, err
}
return HubStatus(ctx, syncHubInput.ProjectID)
}
@ -208,3 +293,72 @@ func GetAllHubs(ctx context.Context) ([]*model.MyHub, error) {
return outputMyHubs, nil
}
func UpdateMyHub(ctx context.Context, myhub model.UpdateMyHub, projectID string) (*model.MyHub, error) {
cloneHub := model.CloningInput{
ProjectID: projectID,
RepoBranch: myhub.RepoBranch,
RepoURL: myhub.RepoURL,
HubName: myhub.HubName,
IsPrivate: myhub.IsPrivate,
UserName: myhub.UserName,
Password: myhub.Password,
AuthType: myhub.AuthType,
Token: myhub.Token,
SSHPrivateKey: myhub.SSHPrivateKey,
}
prevMyHub, err := database.GetHubByID(ctx, myhub.ID)
if err != nil {
return nil, err
}
// Syncing/Cloning the repository at a path from myhub link structure.
if prevMyHub.RepoURL != myhub.RepoURL || prevMyHub.RepoBranch != myhub.RepoBranch || prevMyHub.IsPrivate != myhub.IsPrivate || prevMyHub.AuthType != myhub.AuthType.String() {
fmt.Println(myhub.AuthType.String())
err := gitops.GitClone(cloneHub)
if err != nil {
return nil, err
}
} else {
err := gitops.GitSyncHandlerForProjects(cloneHub)
if err != nil {
return nil, err
}
}
time := strconv.FormatInt(time.Now().Unix(), 10)
query := bson.D{{"myhub_id", myhub.ID}, {"IsRemoved", false}}
update := bson.D{{"$set", bson.D{{"repo_url", myhub.RepoURL}, {"repo_branch", myhub.RepoBranch},
{"hub_name", myhub.HubName}, {"IsPrivate", myhub.IsPrivate}, {"AuthType", myhub.AuthType},
{"Token", myhub.Token}, {"UserName", myhub.UserName}, {"Password", myhub.Password},
{"SSHPrivateKey", myhub.SSHPrivateKey}, {"SSHPublicKey", myhub.SSHPublicKey}, {"updated_at", time}}}}
//Updating the new hub into database with the given username.
err = database.UpdateMyHub(ctx, query, update)
if err != nil {
log.Print("ERROR", err)
return nil, err
}
var newMyhub model.MyHub
copier.Copy(&newMyhub, &myhub)
newMyhub.UpdatedAt = time
return &newMyhub, nil
}
func DeleteMyHub(ctx context.Context, hubID string) (bool, error) {
query := bson.D{{"myhub_id", hubID}}
update := bson.D{{"$set", bson.D{{"IsRemoved", true}, {"updated_at", strconv.FormatInt(time.Now().Unix(), 10)}}}}
err := database.UpdateMyHub(ctx, query, update)
if err != nil {
log.Print("ERROR", err)
return false, err
}
return true, nil
}

View File

@ -26,6 +26,12 @@ func RecurringHubSync() {
ProjectID: myhub.ProjectID,
RepoURL: myhub.RepoURL,
RepoBranch: myhub.RepoBranch,
IsPrivate: myhub.IsPrivate,
AuthType: myhub.AuthType,
Token: myhub.Token,
UserName: myhub.UserName,
Password: myhub.Password,
SSHPrivateKey: myhub.SSHPrivateKey,
}
gitops.GitSyncHandlerForProjects(chartsInput)