diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index a5097807f53..4520229b263 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -2,6 +2,7 @@ name: Litmus-CI on: issue_comment: types: [created] + push: branches: - master @@ -16,9 +17,7 @@ jobs: - uses: octokit/request-action@v2.x id: get_PR_commits with: - route: GET /repos/:repo/pulls/:pull_number/commits - repo: ${{ github.repository }} - pull_number: ${{ github.event.issue.number }} + route: GET /repos/${{ github.repository }}/pull_number/${{ github.event.issue.number }}/commits env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -217,3 +216,4 @@ jobs: - name: Deleting KinD cluster if: always() run: kind delete cluster + \ No newline at end of file diff --git a/README.md b/README.md index 4d6be4056d4..02b16845624 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ Litmus is licensed under the Apache License, Version 2.0. See [LICENSE](./LICENS Litmus Chaos is part of the CNCF Projects. -[![CNCF](https://github.com/cncf/artwork/blob/master/other/cncf/horizontal/color/cncf-color.png)](https://landscape.cncf.io/?selected=litmus) +[![CNCF](https://github.com/cncf/artwork/blob/main/other/cncf/horizontal/color/cncf-color.png)](https://landscape.cncf.io/?selected=litmus) ## Important Links @@ -165,5 +165,5 @@ Litmus Chaos is part of the CNCF Projects.
- CNCF Landscape Litmus on CNCF Landscape + CNCF Landscape Litmus on CNCF Landscape diff --git a/adopters/organizations/wingie-enuygun.md b/adopters/organizations/wingie-enuygun.md new file mode 100644 index 00000000000..7a6c1ed2f1c --- /dev/null +++ b/adopters/organizations/wingie-enuygun.md @@ -0,0 +1,11 @@ +# Wingie Enuygun Company +[Wingie Enuygun Company](https://www.wingie.com/) is a leading travel and technology company providing seamless travel solutions across various platforms. + +## Why do we use Litmus +We use Litmus to identify bottlenecks in our systems, detect issues early, and foresee potential errors. This allows us to take proactive measures and maintain the resilience and performance of our infrastructure. + +## How do we use Litmus +Litmus is integrated into our QA cycles, where it plays a crucial role in catching bugs and verifying the overall resilience of our systems. + +## Benefits in using Litmus +Litmus chaos experiments are straightforward to implement and can be easily customized or extended to meet our specific requirements, enabling us to effectively manage and optimize our systems at Wingie Enuygun. diff --git a/chaoscenter/authentication/api/handlers/rest/user_handlers.go b/chaoscenter/authentication/api/handlers/rest/user_handlers.go index 3d81dc22d54..904969f16ab 100644 --- a/chaoscenter/authentication/api/handlers/rest/user_handlers.go +++ b/chaoscenter/authentication/api/handlers/rest/user_handlers.go @@ -263,7 +263,7 @@ func InviteUsers(service services.ApplicationService) gin.HandlerFunc { // @Failure 400 {object} response.ErrInvalidRequest // @Failure 400 {object} response.ErrUserNotFound // @Failure 400 {object} response.ErrUserDeactivated -// @Failure 400 {object} response.ErrInvalidCredentials +// @Failure 401 {object} response.ErrInvalidCredentials // @Failure 500 {object} response.ErrServerError // @Success 200 {object} response.LoginResponse{} // @Router /login [post] diff --git a/chaoscenter/authentication/go.mod b/chaoscenter/authentication/go.mod index 93f0224f064..6f380169eee 100644 --- a/chaoscenter/authentication/go.mod +++ b/chaoscenter/authentication/go.mod @@ -12,10 +12,10 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 github.com/swaggo/swag v1.16.3 - go.mongodb.org/mongo-driver v1.15.1 - golang.org/x/crypto v0.25.0 - golang.org/x/oauth2 v0.20.0 - google.golang.org/grpc v1.65.0 + go.mongodb.org/mongo-driver v1.16.1 + golang.org/x/crypto v0.26.0 + golang.org/x/oauth2 v0.21.0 + google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 ) @@ -36,7 +36,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/golang/snappy v0.0.1 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.0 // indirect @@ -46,7 +46,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect + github.com/montanaflynn/stats v0.7.1 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect @@ -58,12 +58,12 @@ require ( github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/chaoscenter/authentication/go.sum b/chaoscenter/authentication/go.sum index cf461a3ba2f..52d4c9fd442 100644 --- a/chaoscenter/authentication/go.sum +++ b/chaoscenter/authentication/go.sum @@ -44,8 +44,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -79,8 +79,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w 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/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -119,15 +119,15 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.15.1 h1:l+RvoUOoMXFmADTLfYDm7On9dRm7p4T80/lEQM+r7HU= -go.mongodb.org/mongo-driver v1.15.1/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= +go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= @@ -137,16 +137,16 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= -golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -156,16 +156,16 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -174,10 +174,10 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/chaoscenter/authentication/pkg/utils/sanitizers.go b/chaoscenter/authentication/pkg/utils/sanitizers.go index df9c4d936a0..817ec4684a9 100644 --- a/chaoscenter/authentication/pkg/utils/sanitizers.go +++ b/chaoscenter/authentication/pkg/utils/sanitizers.go @@ -16,7 +16,7 @@ func SanitizeString(input string) string { /* ValidateStrictPassword represents and checks for the following patterns: - Input is at least 8 characters long and at most 16 characters long -- Input contains at least one special character of these @$!%*?_& +- Input contains at least one special character of these @$!%*?_&# - Input contains at least one digit - Input contains at least one uppercase alphabet - Input contains at least one lowercase alphabet @@ -33,7 +33,7 @@ func ValidateStrictPassword(input string) error { digits := `[0-9]{1}` lowerAlphabets := `[a-z]{1}` capitalAlphabets := `[A-Z]{1}` - specialCharacters := `[@$!%*?_&]{1}` + specialCharacters := `[@$!%*?_&#]{1}` if b, err := regexp.MatchString(digits, input); !b || err != nil { return fmt.Errorf("password does not contain digits") } diff --git a/chaoscenter/graphql/definitions/shared/chaos_infrastructure.graphqls b/chaoscenter/graphql/definitions/shared/chaos_infrastructure.graphqls index d0c2b4b5a5c..0ffc9552666 100644 --- a/chaoscenter/graphql/definitions/shared/chaos_infrastructure.graphqls +++ b/chaoscenter/graphql/definitions/shared/chaos_infrastructure.graphqls @@ -358,11 +358,11 @@ type KubeObjectResponse { """ Type of the Kubernetes object """ - kubeObj: [KubeObject]! + kubeObj: KubeObject! } """ -KubeObject consists of the namespace and the available resources in the same +KubeObject consists of the available resources in a namespace """ type KubeObject { """ @@ -404,16 +404,75 @@ input KubeObjectRequest { GVR Request """ kubeObjRequest: KubeGVRRequest + """ + Namespace in which the Kubernetes object is present + """ + namespace: String! objectType: String! workloads: [Workload] } +""" +Defines details for fetching Kubernetes namespace data +""" +input KubeNamespaceRequest { + """ + ID of the infra + """ + infraID: ID! +} + +""" +Define name in the infra (not really useful at the moment but maybe we will need other field later) +""" +type KubeNamespace{ + """ + Name of the namespace + """ + name: String! +} + + + input KubeGVRRequest { group: String! version: String! resource: String! } +""" +Response received for querying Kubernetes Namespaces +""" +type KubeNamespaceResponse { + """ + ID of the infra in which the Kubernetes namespace is present + """ + infraID: ID! + """ + List of the Kubernetes namespace + """ + kubeNamespace: [KubeNamespace]! +} + +""" +Defines the details of Kubernetes namespace +""" +input KubeNamespaceData { + """ + Unique request ID for fetching Kubernetes namespace details + """ + requestID: ID! + """ + ID of the infra in which the Kubernetes namespace is present + """ + infraID: InfraIdentity! + """ + List of KubeNamespace return by subscriber + """ + kubeNamespace: String! +} + + """ Defines the details of Kubernetes object """ @@ -638,6 +697,12 @@ extend type Mutation { """ # authorized directive not required kubeObj(request: KubeObjectData!): String! + + """ + Receives kubernetes namespace data from subscriber + """ + # authorized directive not required + kubeNamespace(request: KubeNamespaceData!): String! } extend type Subscription { @@ -663,4 +728,9 @@ extend type Subscription { Returns a kubernetes object given an input """ getKubeObject(request: KubeObjectRequest!): KubeObjectResponse! + + """ + Returns a kubernetes namespaces given an input + """ + getKubeNamespace(request: KubeNamespaceRequest!): KubeNamespaceResponse! } diff --git a/chaoscenter/graphql/definitions/shared/chaoshub.graphqls b/chaoscenter/graphql/definitions/shared/chaoshub.graphqls index 952ee98cf19..12f1cafb2f7 100644 --- a/chaoscenter/graphql/definitions/shared/chaoshub.graphqls +++ b/chaoscenter/graphql/definitions/shared/chaoshub.graphqls @@ -31,6 +31,10 @@ type ChaosHub implements ResourceDetails & Audit { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ ID of the project in which the chaos hub is present """ projectID: ID! @@ -206,6 +210,10 @@ type ChaosHubStatus implements ResourceDetails & Audit { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is available or not. """ isAvailable: Boolean! @@ -320,6 +328,10 @@ input CreateChaosHubRequest { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -382,6 +394,10 @@ input CloningInput { """ repoURL: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -426,6 +442,10 @@ input CreateRemoteChaosHub { URL of the git repository """ repoURL: String! + """ + Connected Hub of remote repository + """ + remoteHub: String! } @@ -455,6 +475,10 @@ input UpdateChaosHubRequest { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! diff --git a/chaoscenter/graphql/server/go.mod b/chaoscenter/graphql/server/go.mod index 8adcab61d1b..8026cf69811 100644 --- a/chaoscenter/graphql/server/go.mod +++ b/chaoscenter/graphql/server/go.mod @@ -3,7 +3,7 @@ module github.com/litmuschaos/litmus/chaoscenter/graphql/server go 1.22.0 require ( - github.com/99designs/gqlgen v0.17.47 + github.com/99designs/gqlgen v0.17.49 github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 github.com/argoproj/argo-workflows/v3 v3.3.5 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 @@ -21,10 +21,10 @@ require ( github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 - github.com/tidwall/gjson v1.17.1 + github.com/tidwall/gjson v1.17.3 github.com/tidwall/sjson v1.2.5 - github.com/vektah/gqlparser/v2 v2.5.12 - go.mongodb.org/mongo-driver v1.15.0 + github.com/vektah/gqlparser/v2 v2.5.16 + go.mongodb.org/mongo-driver v1.16.1 golang.org/x/crypto v0.24.0 google.golang.org/grpc v1.64.1 google.golang.org/protobuf v1.34.2 @@ -68,7 +68,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/golang/snappy v0.0.1 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect @@ -86,7 +86,7 @@ require ( github.com/mitchellh/mapstructure v1.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/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect + github.com/montanaflynn/stats v0.7.1 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -107,7 +107,7 @@ require ( github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.18.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect golang.org/x/sync v0.7.0 // indirect @@ -115,7 +115,7 @@ require ( golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.22.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/chaoscenter/graphql/server/go.sum b/chaoscenter/graphql/server/go.sum index ac56d5fdade..5731112c795 100644 --- a/chaoscenter/graphql/server/go.sum +++ b/chaoscenter/graphql/server/go.sum @@ -43,8 +43,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/99designs/gqlgen v0.17.47 h1:M9DTK8X3+3ATNBfZlHBwMwNngn4hhZWDxNmTiuQU5tQ= -github.com/99designs/gqlgen v0.17.47/go.mod h1:ejVkldSdtmuudqmtfaiqjwlGXWAhIv0DKXGXFY25F04= +github.com/99designs/gqlgen v0.17.49 h1:b3hNGexHd33fBSAd4NDT/c3NCcQzcAVkknhN9ym36YQ= +github.com/99designs/gqlgen v0.17.49/go.mod h1:tC8YFVZMed81x7UJ7ORUwXF4Kn6SXuucFqQBhN8+BU0= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/azure-sdk-for-go v32.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -548,8 +548,9 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= @@ -878,8 +879,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= @@ -1128,8 +1129,8 @@ github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= -github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= +github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -1157,8 +1158,8 @@ github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/vektah/gqlparser/v2 v2.5.12 h1:COMhVVnql6RoaF7+aTBWiTADdpLGyZWU3K/NwW0ph98= -github.com/vektah/gqlparser/v2 v2.5.12/go.mod h1:WQQjFc+I1YIzoPvZBhUQX7waZgg3pMLi0r8KymvAE2w= +github.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8= +github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww= github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netns v0.0.0-20171111001504-be1fbeda1936/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= @@ -1207,8 +1208,8 @@ go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= -go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= +go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -1307,8 +1308,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1631,8 +1632,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= 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= diff --git a/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go b/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go index d46940ff94d..62a82b0de5f 100644 --- a/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go +++ b/chaoscenter/graphql/server/graph/chaos_experiment_run.resolvers.go @@ -29,7 +29,7 @@ func (r *mutationResolver) RunChaosExperiment(ctx context.Context, experimentID logrus.WithFields(logFields).Info("request received to run chaos experiment") err := authorization.ValidateRole(ctx, projectID, - authorization.MutationRbacRules[authorization.CreateChaosExperiment], + authorization.MutationRbacRules[authorization.ReRunChaosExperiment], model.InvitationAccepted.String()) if err != nil { return nil, err diff --git a/chaoscenter/graphql/server/graph/chaos_infrastructure.resolvers.go b/chaoscenter/graphql/server/graph/chaos_infrastructure.resolvers.go index 4ee62af5526..59977440584 100644 --- a/chaoscenter/graphql/server/graph/chaos_infrastructure.resolvers.go +++ b/chaoscenter/graphql/server/graph/chaos_infrastructure.resolvers.go @@ -116,6 +116,11 @@ func (r *mutationResolver) KubeObj(ctx context.Context, request model.KubeObject return r.chaosInfrastructureService.KubeObj(request, *data_store.Store) } +// KubeNamespace is the resolver for the kubeNamespace field. +func (r *mutationResolver) KubeNamespace(ctx context.Context, request model.KubeNamespaceData) (string, error) { + return r.chaosInfrastructureService.KubeNamespace(request, *data_store.Store) +} + // GetInfra is the resolver for the getInfra field. func (r *queryResolver) GetInfra(ctx context.Context, projectID string, infraID string) (*model.Infra, error) { logFields := logrus.Fields{ @@ -270,8 +275,10 @@ func (r *subscriptionResolver) InfraConnect(ctx context.Context, request model.I return infraAction, err } data_store.Store.Mutex.Lock() - if _, ok := data_store.Store.ConnectedInfra[request.InfraID]; ok { + if infra_channel, ok := data_store.Store.ConnectedInfra[request.InfraID]; ok { data_store.Store.Mutex.Unlock() + logrus.Print("ALREADY CONNECTED, FORCED DISCONNECT: ", request.InfraID) + close(infra_channel) return infraAction, errors.New("CLUSTER ALREADY CONNECTED") } data_store.Store.ConnectedInfra[request.InfraID] = infraAction @@ -279,7 +286,7 @@ func (r *subscriptionResolver) InfraConnect(ctx context.Context, request model.I go func() { <-ctx.Done() verifiedInfra.IsActive = false - + logrus.Print("Context Done, will handle disconnection for: ", request.InfraID) newVerifiedInfra := model.Infra{} copier.Copy(&newVerifiedInfra, &verifiedInfra) @@ -348,6 +355,24 @@ func (r *subscriptionResolver) GetKubeObject(ctx context.Context, request model. return kubeObjData, nil } +// GetKubeNamespace is the resolver for the getKubeNamespace field. +func (r *subscriptionResolver) GetKubeNamespace(ctx context.Context, request model.KubeNamespaceRequest) (<-chan *model.KubeNamespaceResponse, error) { + logrus.Print("NEW NAMESPACE REQUEST", request.InfraID) + kubeNamespaceData := make(chan *model.KubeNamespaceResponse) + reqID := uuid.New() + data_store.Store.Mutex.Lock() + data_store.Store.KubeNamespaceData[reqID.String()] = kubeNamespaceData + data_store.Store.Mutex.Unlock() + go func() { + <-ctx.Done() + logrus.Println("Closed KubeNamespace Listener") + delete(data_store.Store.KubeNamespaceData, reqID.String()) + }() + go r.chaosExperimentHandler.GetKubeNamespaceData(reqID.String(), request, *data_store.Store) + + return kubeNamespaceData, nil +} + // Subscription returns generated.SubscriptionResolver implementation. func (r *Resolver) Subscription() generated.SubscriptionResolver { return &subscriptionResolver{r} } diff --git a/chaoscenter/graphql/server/graph/generated/generated.go b/chaoscenter/graphql/server/graph/generated/generated.go index 932e018a654..8a501d3e4da 100644 --- a/chaoscenter/graphql/server/graph/generated/generated.go +++ b/chaoscenter/graphql/server/graph/generated/generated.go @@ -91,6 +91,7 @@ type ComplexityRoot struct { Name func(childComplexity int) int Password func(childComplexity int) int ProjectID func(childComplexity int) int + RemoteHub func(childComplexity int) int RepoBranch func(childComplexity int) int RepoURL func(childComplexity int) int SSHPrivateKey func(childComplexity int) int @@ -115,6 +116,7 @@ type ComplexityRoot struct { LastSyncedAt func(childComplexity int) int Name func(childComplexity int) int Password func(childComplexity int) int + RemoteHub func(childComplexity int) int RepoBranch func(childComplexity int) int RepoURL func(childComplexity int) int SSHPrivateKey func(childComplexity int) int @@ -398,6 +400,15 @@ type ComplexityRoot struct { Version func(childComplexity int) int } + KubeNamespace struct { + Name func(childComplexity int) int + } + + KubeNamespaceResponse struct { + InfraID func(childComplexity int) int + KubeNamespace func(childComplexity int) int + } + KubeObject struct { Data func(childComplexity int) int Namespace func(childComplexity int) int @@ -497,6 +508,7 @@ type ComplexityRoot struct { GenerateSSHKey func(childComplexity int) int GetManifestWithInfraID func(childComplexity int, projectID string, infraID string, accessKey string) int GitopsNotifier func(childComplexity int, clusterInfo model.InfraIdentity, experimentID string) int + KubeNamespace func(childComplexity int, request model.KubeNamespaceData) int KubeObj func(childComplexity int, request model.KubeObjectData) int PodLog func(childComplexity int, request model.PodLog) int RegisterInfra func(childComplexity int, projectID string, request model.RegisterInfraRequest) int @@ -694,10 +706,11 @@ type ComplexityRoot struct { } Subscription struct { - GetInfraEvents func(childComplexity int, projectID string) int - GetKubeObject func(childComplexity int, request model.KubeObjectRequest) int - GetPodLog func(childComplexity int, request model.PodLogRequest) int - InfraConnect func(childComplexity int, request model.InfraIdentity) int + GetInfraEvents func(childComplexity int, projectID string) int + GetKubeNamespace func(childComplexity int, request model.KubeNamespaceRequest) int + GetKubeObject func(childComplexity int, request model.KubeObjectRequest) int + GetPodLog func(childComplexity int, request model.PodLogRequest) int + InfraConnect func(childComplexity int, request model.InfraIdentity) int } UserDetails struct { @@ -727,6 +740,7 @@ type MutationResolver interface { GetManifestWithInfraID(ctx context.Context, projectID string, infraID string, accessKey string) (string, error) PodLog(ctx context.Context, request model.PodLog) (string, error) KubeObj(ctx context.Context, request model.KubeObjectData) (string, error) + KubeNamespace(ctx context.Context, request model.KubeNamespaceData) (string, error) AddChaosHub(ctx context.Context, projectID string, request model.CreateChaosHubRequest) (*model.ChaosHub, error) AddRemoteChaosHub(ctx context.Context, projectID string, request model.CreateRemoteChaosHub) (*model.ChaosHub, error) SaveChaosHub(ctx context.Context, projectID string, request model.CreateChaosHubRequest) (*model.ChaosHub, error) @@ -786,6 +800,7 @@ type SubscriptionResolver interface { InfraConnect(ctx context.Context, request model.InfraIdentity) (<-chan *model.InfraActionResponse, error) GetPodLog(ctx context.Context, request model.PodLogRequest) (<-chan *model.PodLogResponse, error) GetKubeObject(ctx context.Context, request model.KubeObjectRequest) (<-chan *model.KubeObjectResponse, error) + GetKubeNamespace(ctx context.Context, request model.KubeNamespaceRequest) (<-chan *model.KubeNamespaceResponse, error) } type executableSchema struct { @@ -1031,6 +1046,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ChaosHub.ProjectID(childComplexity), true + case "ChaosHub.remoteHub": + if e.complexity.ChaosHub.RemoteHub == nil { + break + } + + return e.complexity.ChaosHub.RemoteHub(childComplexity), true + case "ChaosHub.repoBranch": if e.complexity.ChaosHub.RepoBranch == nil { break @@ -1178,6 +1200,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ChaosHubStatus.Password(childComplexity), true + case "ChaosHubStatus.remoteHub": + if e.complexity.ChaosHubStatus.RemoteHub == nil { + break + } + + return e.complexity.ChaosHubStatus.RemoteHub(childComplexity), true + case "ChaosHubStatus.repoBranch": if e.complexity.ChaosHubStatus.RepoBranch == nil { break @@ -2557,6 +2586,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.K8SProbe.Version(childComplexity), true + case "KubeNamespace.name": + if e.complexity.KubeNamespace.Name == nil { + break + } + + return e.complexity.KubeNamespace.Name(childComplexity), true + + case "KubeNamespaceResponse.infraID": + if e.complexity.KubeNamespaceResponse.InfraID == nil { + break + } + + return e.complexity.KubeNamespaceResponse.InfraID(childComplexity), true + + case "KubeNamespaceResponse.kubeNamespace": + if e.complexity.KubeNamespaceResponse.KubeNamespace == nil { + break + } + + return e.complexity.KubeNamespaceResponse.KubeNamespace(childComplexity), true + case "KubeObject.data": if e.complexity.KubeObject.Data == nil { break @@ -3081,6 +3131,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.GitopsNotifier(childComplexity, args["clusterInfo"].(model.InfraIdentity), args["experimentID"].(string)), true + case "Mutation.kubeNamespace": + if e.complexity.Mutation.KubeNamespace == nil { + break + } + + args, err := ec.field_Mutation_kubeNamespace_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.KubeNamespace(childComplexity, args["request"].(model.KubeNamespaceData)), true + case "Mutation.kubeObj": if e.complexity.Mutation.KubeObj == nil { break @@ -4256,6 +4318,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Subscription.GetInfraEvents(childComplexity, args["projectID"].(string)), true + case "Subscription.getKubeNamespace": + if e.complexity.Subscription.GetKubeNamespace == nil { + break + } + + args, err := ec.field_Subscription_getKubeNamespace_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Subscription.GetKubeNamespace(childComplexity, args["request"].(model.KubeNamespaceRequest)), true + case "Subscription.getKubeObject": if e.complexity.Subscription.GetKubeObject == nil { break @@ -4361,6 +4435,8 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputInfraIdentity, ec.unmarshalInputK8SProbeRequest, ec.unmarshalInputKubeGVRRequest, + ec.unmarshalInputKubeNamespaceData, + ec.unmarshalInputKubeNamespaceRequest, ec.unmarshalInputKubeObjectData, ec.unmarshalInputKubeObjectRequest, ec.unmarshalInputKubernetesCMDProbeRequest, @@ -5682,11 +5758,11 @@ type KubeObjectResponse { """ Type of the Kubernetes object """ - kubeObj: [KubeObject]! + kubeObj: KubeObject! } """ -KubeObject consists of the namespace and the available resources in the same +KubeObject consists of the available resources in a namespace """ type KubeObject { """ @@ -5728,16 +5804,75 @@ input KubeObjectRequest { GVR Request """ kubeObjRequest: KubeGVRRequest + """ + Namespace in which the Kubernetes object is present + """ + namespace: String! objectType: String! workloads: [Workload] } +""" +Defines details for fetching Kubernetes namespace data +""" +input KubeNamespaceRequest { + """ + ID of the infra + """ + infraID: ID! +} + +""" +Define name in the infra (not really useful at the moment but maybe we will need other field later) +""" +type KubeNamespace{ + """ + Name of the namespace + """ + name: String! +} + + + input KubeGVRRequest { group: String! version: String! resource: String! } +""" +Response received for querying Kubernetes Namespaces +""" +type KubeNamespaceResponse { + """ + ID of the infra in which the Kubernetes namespace is present + """ + infraID: ID! + """ + List of the Kubernetes namespace + """ + kubeNamespace: [KubeNamespace]! +} + +""" +Defines the details of Kubernetes namespace +""" +input KubeNamespaceData { + """ + Unique request ID for fetching Kubernetes namespace details + """ + requestID: ID! + """ + ID of the infra in which the Kubernetes namespace is present + """ + infraID: InfraIdentity! + """ + List of KubeNamespace return by subscriber + """ + kubeNamespace: String! +} + + """ Defines the details of Kubernetes object """ @@ -5962,6 +6097,12 @@ extend type Mutation { """ # authorized directive not required kubeObj(request: KubeObjectData!): String! + + """ + Receives kubernetes namespace data from subscriber + """ + # authorized directive not required + kubeNamespace(request: KubeNamespaceData!): String! } extend type Subscription { @@ -5987,6 +6128,11 @@ extend type Subscription { Returns a kubernetes object given an input """ getKubeObject(request: KubeObjectRequest!): KubeObjectResponse! + + """ + Returns a kubernetes namespaces given an input + """ + getKubeNamespace(request: KubeNamespaceRequest!): KubeNamespaceResponse! } `, BuiltIn: false}, {Name: "../../../definitions/shared/chaoshub.graphqls", Input: `enum AuthType { @@ -6022,6 +6168,10 @@ type ChaosHub implements ResourceDetails & Audit { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ ID of the project in which the chaos hub is present """ projectID: ID! @@ -6197,6 +6347,10 @@ type ChaosHubStatus implements ResourceDetails & Audit { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is available or not. """ isAvailable: Boolean! @@ -6311,6 +6465,10 @@ input CreateChaosHubRequest { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -6373,6 +6531,10 @@ input CloningInput { """ repoURL: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -6417,6 +6579,10 @@ input CreateRemoteChaosHub { URL of the git repository """ repoURL: String! + """ + Connected Hub of remote repository + """ + remoteHub: String! } @@ -6446,6 +6612,10 @@ input UpdateChaosHubRequest { """ repoBranch: String! """ + Connected Hub of remote repository + """ + remoteHub: String! + """ Bool value indicating whether the hub is private or not. """ isPrivate: Boolean! @@ -8607,6 +8777,21 @@ func (ec *executionContext) field_Mutation_gitopsNotifier_args(ctx context.Conte return args, nil } +func (ec *executionContext) field_Mutation_kubeNamespace_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.KubeNamespaceData + if tmp, ok := rawArgs["request"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("request")) + arg0, err = ec.unmarshalNKubeNamespaceData2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceData(ctx, tmp) + if err != nil { + return nil, err + } + } + args["request"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_kubeObj_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -9717,6 +9902,21 @@ func (ec *executionContext) field_Subscription_getInfraEvents_args(ctx context.C return args, nil } +func (ec *executionContext) field_Subscription_getKubeNamespace_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.KubeNamespaceRequest + if tmp, ok := rawArgs["request"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("request")) + arg0, err = ec.unmarshalNKubeNamespaceRequest2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceRequest(ctx, tmp) + if err != nil { + return nil, err + } + } + args["request"] = arg0 + return args, nil +} + func (ec *executionContext) field_Subscription_getKubeObject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -10759,6 +10959,50 @@ func (ec *executionContext) fieldContext_ChaosHub_repoBranch(ctx context.Context return fc, nil } +func (ec *executionContext) _ChaosHub_remoteHub(ctx context.Context, field graphql.CollectedField, obj *model.ChaosHub) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ChaosHub_remoteHub(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.RemoteHub, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ChaosHub_remoteHub(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ChaosHub", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _ChaosHub_projectID(ctx context.Context, field graphql.CollectedField, obj *model.ChaosHub) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ChaosHub_projectID(ctx, field) if err != nil { @@ -11675,6 +11919,50 @@ func (ec *executionContext) fieldContext_ChaosHubStatus_repoBranch(ctx context.C return fc, nil } +func (ec *executionContext) _ChaosHubStatus_remoteHub(ctx context.Context, field graphql.CollectedField, obj *model.ChaosHubStatus) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ChaosHubStatus_remoteHub(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.RemoteHub, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ChaosHubStatus_remoteHub(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ChaosHubStatus", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _ChaosHubStatus_isAvailable(ctx context.Context, field graphql.CollectedField, obj *model.ChaosHubStatus) (ret graphql.Marshaler) { fc, err := ec.fieldContext_ChaosHubStatus_isAvailable(ctx, field) if err != nil { @@ -21029,6 +21317,142 @@ func (ec *executionContext) fieldContext_K8SProbe_operation(ctx context.Context, return fc, nil } +func (ec *executionContext) _KubeNamespace_name(ctx context.Context, field graphql.CollectedField, obj *model.KubeNamespace) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_KubeNamespace_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_KubeNamespace_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "KubeNamespace", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _KubeNamespaceResponse_infraID(ctx context.Context, field graphql.CollectedField, obj *model.KubeNamespaceResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_KubeNamespaceResponse_infraID(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.InfraID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_KubeNamespaceResponse_infraID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "KubeNamespaceResponse", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _KubeNamespaceResponse_kubeNamespace(ctx context.Context, field graphql.CollectedField, obj *model.KubeNamespaceResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_KubeNamespaceResponse_kubeNamespace(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.KubeNamespace, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.KubeNamespace) + fc.Result = res + return ec.marshalNKubeNamespace2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespace(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_KubeNamespaceResponse_kubeNamespace(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "KubeNamespaceResponse", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext_KubeNamespace_name(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type KubeNamespace", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _KubeObject_namespace(ctx context.Context, field graphql.CollectedField, obj *model.KubeObject) (ret graphql.Marshaler) { fc, err := ec.fieldContext_KubeObject_namespace(ctx, field) if err != nil { @@ -21193,9 +21617,9 @@ func (ec *executionContext) _KubeObjectResponse_kubeObj(ctx context.Context, fie } return graphql.Null } - res := resTmp.([]*model.KubeObject) + res := resTmp.(*model.KubeObject) fc.Result = res - return ec.marshalNKubeObject2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx, field.Selections, res) + return ec.marshalNKubeObject2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_KubeObjectResponse_kubeObj(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -23980,6 +24404,61 @@ func (ec *executionContext) fieldContext_Mutation_kubeObj(ctx context.Context, f return fc, nil } +func (ec *executionContext) _Mutation_kubeNamespace(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_kubeNamespace(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().KubeNamespace(rctx, fc.Args["request"].(model.KubeNamespaceData)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_kubeNamespace(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_kubeNamespace_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Mutation_addChaosHub(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_addChaosHub(ctx, field) if err != nil { @@ -24045,6 +24524,8 @@ func (ec *executionContext) fieldContext_Mutation_addChaosHub(ctx context.Contex return ec.fieldContext_ChaosHub_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHub_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHub_remoteHub(ctx, field) case "projectID": return ec.fieldContext_ChaosHub_projectID(ctx, field) case "isDefault": @@ -24164,6 +24645,8 @@ func (ec *executionContext) fieldContext_Mutation_addRemoteChaosHub(ctx context. return ec.fieldContext_ChaosHub_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHub_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHub_remoteHub(ctx, field) case "projectID": return ec.fieldContext_ChaosHub_projectID(ctx, field) case "isDefault": @@ -24283,6 +24766,8 @@ func (ec *executionContext) fieldContext_Mutation_saveChaosHub(ctx context.Conte return ec.fieldContext_ChaosHub_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHub_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHub_remoteHub(ctx, field) case "projectID": return ec.fieldContext_ChaosHub_projectID(ctx, field) case "isDefault": @@ -24547,6 +25032,8 @@ func (ec *executionContext) fieldContext_Mutation_updateChaosHub(ctx context.Con return ec.fieldContext_ChaosHub_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHub_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHub_remoteHub(ctx, field) case "projectID": return ec.fieldContext_ChaosHub_projectID(ctx, field) case "isDefault": @@ -29227,6 +29714,8 @@ func (ec *executionContext) fieldContext_Query_listChaosHub(ctx context.Context, return ec.fieldContext_ChaosHubStatus_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHubStatus_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHubStatus_remoteHub(ctx, field) case "isAvailable": return ec.fieldContext_ChaosHubStatus_isAvailable(ctx, field) case "totalFaults": @@ -29352,6 +29841,8 @@ func (ec *executionContext) fieldContext_Query_getChaosHub(ctx context.Context, return ec.fieldContext_ChaosHubStatus_repoURL(ctx, field) case "repoBranch": return ec.fieldContext_ChaosHubStatus_repoBranch(ctx, field) + case "remoteHub": + return ec.fieldContext_ChaosHubStatus_remoteHub(ctx, field) case "isAvailable": return ec.fieldContext_ChaosHubStatus_isAvailable(ctx, field) case "totalFaults": @@ -32901,6 +33392,81 @@ func (ec *executionContext) fieldContext_Subscription_getKubeObject(ctx context. return fc, nil } +func (ec *executionContext) _Subscription_getKubeNamespace(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_getKubeNamespace(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().GetKubeNamespace(rctx, fc.Args["request"].(model.KubeNamespaceRequest)) + }) + if err != nil { + ec.Error(ctx, err) + return nil + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan *model.KubeNamespaceResponse): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNKubeNamespaceResponse2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceResponse(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_getKubeNamespace(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "infraID": + return ec.fieldContext_KubeNamespaceResponse_infraID(ctx, field) + case "kubeNamespace": + return ec.fieldContext_KubeNamespaceResponse_kubeNamespace(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type KubeNamespaceResponse", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Subscription_getKubeNamespace_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _UserDetails_userID(ctx context.Context, field graphql.CollectedField, obj *model.UserDetails) (ret graphql.Marshaler) { fc, err := ec.fieldContext_UserDetails_userID(ctx, field) if err != nil { @@ -35136,7 +35702,7 @@ func (ec *executionContext) unmarshalInputCloningInput(ctx context.Context, obj asMap[k] = v } - fieldsInOrder := [...]string{"name", "repoBranch", "repoURL", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "isDefault"} + fieldsInOrder := [...]string{"name", "repoBranch", "repoURL", "remoteHub", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "isDefault"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -35164,6 +35730,13 @@ func (ec *executionContext) unmarshalInputCloningInput(ctx context.Context, obj return it, err } it.RepoURL = data + case "remoteHub": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remoteHub")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.RemoteHub = data case "isPrivate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPrivate")) data, err := ec.unmarshalNBoolean2bool(ctx, v) @@ -35267,7 +35840,7 @@ func (ec *executionContext) unmarshalInputCreateChaosHubRequest(ctx context.Cont asMap[k] = v } - fieldsInOrder := [...]string{"name", "tags", "description", "repoURL", "repoBranch", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "sshPublicKey"} + fieldsInOrder := [...]string{"name", "tags", "description", "repoURL", "repoBranch", "remoteHub", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "sshPublicKey"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -35309,6 +35882,13 @@ func (ec *executionContext) unmarshalInputCreateChaosHubRequest(ctx context.Cont return it, err } it.RepoBranch = data + case "remoteHub": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remoteHub")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.RemoteHub = data case "isPrivate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPrivate")) data, err := ec.unmarshalNBoolean2bool(ctx, v) @@ -35426,7 +36006,7 @@ func (ec *executionContext) unmarshalInputCreateRemoteChaosHub(ctx context.Conte asMap[k] = v } - fieldsInOrder := [...]string{"name", "tags", "description", "repoURL"} + fieldsInOrder := [...]string{"name", "tags", "description", "repoURL", "remoteHub"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -35461,6 +36041,13 @@ func (ec *executionContext) unmarshalInputCreateRemoteChaosHub(ctx context.Conte return it, err } it.RepoURL = data + case "remoteHub": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remoteHub")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.RemoteHub = data } } @@ -36520,6 +37107,74 @@ func (ec *executionContext) unmarshalInputKubeGVRRequest(ctx context.Context, ob return it, nil } +func (ec *executionContext) unmarshalInputKubeNamespaceData(ctx context.Context, obj interface{}) (model.KubeNamespaceData, error) { + var it model.KubeNamespaceData + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"requestID", "infraID", "kubeNamespace"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "requestID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("requestID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.RequestID = data + case "infraID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infraID")) + data, err := ec.unmarshalNInfraIdentity2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐInfraIdentity(ctx, v) + if err != nil { + return it, err + } + it.InfraID = data + case "kubeNamespace": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("kubeNamespace")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.KubeNamespace = data + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputKubeNamespaceRequest(ctx context.Context, obj interface{}) (model.KubeNamespaceRequest, error) { + var it model.KubeNamespaceRequest + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"infraID"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "infraID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infraID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.InfraID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputKubeObjectData(ctx context.Context, obj interface{}) (model.KubeObjectData, error) { var it model.KubeObjectData asMap := map[string]interface{}{} @@ -36568,7 +37223,7 @@ func (ec *executionContext) unmarshalInputKubeObjectRequest(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"infraID", "kubeObjRequest", "objectType", "workloads"} + fieldsInOrder := [...]string{"infraID", "kubeObjRequest", "namespace", "objectType", "workloads"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -36589,6 +37244,13 @@ func (ec *executionContext) unmarshalInputKubeObjectRequest(ctx context.Context, return it, err } it.KubeObjRequest = data + case "namespace": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("namespace")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Namespace = data case "objectType": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("objectType")) data, err := ec.unmarshalNString2string(ctx, v) @@ -37822,7 +38484,7 @@ func (ec *executionContext) unmarshalInputUpdateChaosHubRequest(ctx context.Cont asMap[k] = v } - fieldsInOrder := [...]string{"id", "name", "description", "tags", "repoURL", "repoBranch", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "sshPublicKey"} + fieldsInOrder := [...]string{"id", "name", "description", "tags", "repoURL", "repoBranch", "remoteHub", "isPrivate", "authType", "token", "userName", "password", "sshPrivateKey", "sshPublicKey"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -37871,6 +38533,13 @@ func (ec *executionContext) unmarshalInputUpdateChaosHubRequest(ctx context.Cont return it, err } it.RepoBranch = data + case "remoteHub": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remoteHub")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.RemoteHub = data case "isPrivate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPrivate")) data, err := ec.unmarshalNBoolean2bool(ctx, v) @@ -38438,6 +39107,11 @@ func (ec *executionContext) _ChaosHub(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { out.Invalids++ } + case "remoteHub": + out.Values[i] = ec._ChaosHub_remoteHub(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "projectID": out.Values[i] = ec._ChaosHub_projectID(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -38553,6 +39227,11 @@ func (ec *executionContext) _ChaosHubStatus(ctx context.Context, sel ast.Selecti if out.Values[i] == graphql.Null { out.Invalids++ } + case "remoteHub": + out.Values[i] = ec._ChaosHubStatus_remoteHub(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "isAvailable": out.Values[i] = ec._ChaosHubStatus_isAvailable(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -39907,44 +40586,221 @@ func (ec *executionContext) _ImageRegistry(ctx context.Context, sel ast.Selectio return out } -var imageRegistryResponseImplementors = []string{"ImageRegistryResponse", "Audit"} +var imageRegistryResponseImplementors = []string{"ImageRegistryResponse", "Audit"} + +func (ec *executionContext) _ImageRegistryResponse(ctx context.Context, sel ast.SelectionSet, obj *model.ImageRegistryResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, imageRegistryResponseImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ImageRegistryResponse") + case "isDefault": + out.Values[i] = ec._ImageRegistryResponse_isDefault(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "imageRegistryInfo": + out.Values[i] = ec._ImageRegistryResponse_imageRegistryInfo(ctx, field, obj) + case "imageRegistryID": + out.Values[i] = ec._ImageRegistryResponse_imageRegistryID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "projectID": + out.Values[i] = ec._ImageRegistryResponse_projectID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updatedAt": + out.Values[i] = ec._ImageRegistryResponse_updatedAt(ctx, field, obj) + case "createdAt": + out.Values[i] = ec._ImageRegistryResponse_createdAt(ctx, field, obj) + case "createdBy": + out.Values[i] = ec._ImageRegistryResponse_createdBy(ctx, field, obj) + case "updatedBy": + out.Values[i] = ec._ImageRegistryResponse_updatedBy(ctx, field, obj) + case "isRemoved": + out.Values[i] = ec._ImageRegistryResponse_isRemoved(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var infraImplementors = []string{"Infra", "ResourceDetails", "Audit"} + +func (ec *executionContext) _Infra(ctx context.Context, sel ast.SelectionSet, obj *model.Infra) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, infraImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Infra") + case "projectID": + out.Values[i] = ec._Infra_projectID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "infraID": + out.Values[i] = ec._Infra_infraID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._Infra_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec._Infra_description(ctx, field, obj) + case "tags": + out.Values[i] = ec._Infra_tags(ctx, field, obj) + case "environmentID": + out.Values[i] = ec._Infra_environmentID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "platformName": + out.Values[i] = ec._Infra_platformName(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isActive": + out.Values[i] = ec._Infra_isActive(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isInfraConfirmed": + out.Values[i] = ec._Infra_isInfraConfirmed(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isRemoved": + out.Values[i] = ec._Infra_isRemoved(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updatedAt": + out.Values[i] = ec._Infra_updatedAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "createdAt": + out.Values[i] = ec._Infra_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "noOfExperiments": + out.Values[i] = ec._Infra_noOfExperiments(ctx, field, obj) + case "noOfExperimentRuns": + out.Values[i] = ec._Infra_noOfExperimentRuns(ctx, field, obj) + case "token": + out.Values[i] = ec._Infra_token(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "infraNamespace": + out.Values[i] = ec._Infra_infraNamespace(ctx, field, obj) + case "serviceAccount": + out.Values[i] = ec._Infra_serviceAccount(ctx, field, obj) + case "infraScope": + out.Values[i] = ec._Infra_infraScope(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "infraNsExists": + out.Values[i] = ec._Infra_infraNsExists(ctx, field, obj) + case "infraSaExists": + out.Values[i] = ec._Infra_infraSaExists(ctx, field, obj) + case "lastExperimentTimestamp": + out.Values[i] = ec._Infra_lastExperimentTimestamp(ctx, field, obj) + case "startTime": + out.Values[i] = ec._Infra_startTime(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "version": + out.Values[i] = ec._Infra_version(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "createdBy": + out.Values[i] = ec._Infra_createdBy(ctx, field, obj) + case "updatedBy": + out.Values[i] = ec._Infra_updatedBy(ctx, field, obj) + case "infraType": + out.Values[i] = ec._Infra_infraType(ctx, field, obj) + case "updateStatus": + out.Values[i] = ec._Infra_updateStatus(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var infraActionResponseImplementors = []string{"InfraActionResponse"} -func (ec *executionContext) _ImageRegistryResponse(ctx context.Context, sel ast.SelectionSet, obj *model.ImageRegistryResponse) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, imageRegistryResponseImplementors) +func (ec *executionContext) _InfraActionResponse(ctx context.Context, sel ast.SelectionSet, obj *model.InfraActionResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, infraActionResponseImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("ImageRegistryResponse") - case "isDefault": - out.Values[i] = ec._ImageRegistryResponse_isDefault(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "imageRegistryInfo": - out.Values[i] = ec._ImageRegistryResponse_imageRegistryInfo(ctx, field, obj) - case "imageRegistryID": - out.Values[i] = ec._ImageRegistryResponse_imageRegistryID(ctx, field, obj) + out.Values[i] = graphql.MarshalString("InfraActionResponse") + case "projectID": + out.Values[i] = ec._InfraActionResponse_projectID(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "projectID": - out.Values[i] = ec._ImageRegistryResponse_projectID(ctx, field, obj) + case "action": + out.Values[i] = ec._InfraActionResponse_action(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "updatedAt": - out.Values[i] = ec._ImageRegistryResponse_updatedAt(ctx, field, obj) - case "createdAt": - out.Values[i] = ec._ImageRegistryResponse_createdAt(ctx, field, obj) - case "createdBy": - out.Values[i] = ec._ImageRegistryResponse_createdBy(ctx, field, obj) - case "updatedBy": - out.Values[i] = ec._ImageRegistryResponse_updatedBy(ctx, field, obj) - case "isRemoved": - out.Values[i] = ec._ImageRegistryResponse_isRemoved(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -39968,113 +40824,39 @@ func (ec *executionContext) _ImageRegistryResponse(ctx context.Context, sel ast. return out } -var infraImplementors = []string{"Infra", "ResourceDetails", "Audit"} +var infraEventResponseImplementors = []string{"InfraEventResponse"} -func (ec *executionContext) _Infra(ctx context.Context, sel ast.SelectionSet, obj *model.Infra) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, infraImplementors) +func (ec *executionContext) _InfraEventResponse(ctx context.Context, sel ast.SelectionSet, obj *model.InfraEventResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, infraEventResponseImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("Infra") - case "projectID": - out.Values[i] = ec._Infra_projectID(ctx, field, obj) + out.Values[i] = graphql.MarshalString("InfraEventResponse") + case "eventID": + out.Values[i] = ec._InfraEventResponse_eventID(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "infraID": - out.Values[i] = ec._Infra_infraID(ctx, field, obj) + case "eventType": + out.Values[i] = ec._InfraEventResponse_eventType(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "name": - out.Values[i] = ec._Infra_name(ctx, field, obj) + case "eventName": + out.Values[i] = ec._InfraEventResponse_eventName(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "description": - out.Values[i] = ec._Infra_description(ctx, field, obj) - case "tags": - out.Values[i] = ec._Infra_tags(ctx, field, obj) - case "environmentID": - out.Values[i] = ec._Infra_environmentID(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "platformName": - out.Values[i] = ec._Infra_platformName(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "isActive": - out.Values[i] = ec._Infra_isActive(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "isInfraConfirmed": - out.Values[i] = ec._Infra_isInfraConfirmed(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "isRemoved": - out.Values[i] = ec._Infra_isRemoved(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "updatedAt": - out.Values[i] = ec._Infra_updatedAt(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "createdAt": - out.Values[i] = ec._Infra_createdAt(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "noOfExperiments": - out.Values[i] = ec._Infra_noOfExperiments(ctx, field, obj) - case "noOfExperimentRuns": - out.Values[i] = ec._Infra_noOfExperimentRuns(ctx, field, obj) - case "token": - out.Values[i] = ec._Infra_token(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "infraNamespace": - out.Values[i] = ec._Infra_infraNamespace(ctx, field, obj) - case "serviceAccount": - out.Values[i] = ec._Infra_serviceAccount(ctx, field, obj) - case "infraScope": - out.Values[i] = ec._Infra_infraScope(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "infraNsExists": - out.Values[i] = ec._Infra_infraNsExists(ctx, field, obj) - case "infraSaExists": - out.Values[i] = ec._Infra_infraSaExists(ctx, field, obj) - case "lastExperimentTimestamp": - out.Values[i] = ec._Infra_lastExperimentTimestamp(ctx, field, obj) - case "startTime": - out.Values[i] = ec._Infra_startTime(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "version": - out.Values[i] = ec._Infra_version(ctx, field, obj) + out.Values[i] = ec._InfraEventResponse_description(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "createdBy": - out.Values[i] = ec._Infra_createdBy(ctx, field, obj) - case "updatedBy": - out.Values[i] = ec._Infra_updatedBy(ctx, field, obj) - case "infraType": - out.Values[i] = ec._Infra_infraType(ctx, field, obj) - case "updateStatus": - out.Values[i] = ec._Infra_updateStatus(ctx, field, obj) + case "infra": + out.Values[i] = ec._InfraEventResponse_infra(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -40101,24 +40883,24 @@ func (ec *executionContext) _Infra(ctx context.Context, sel ast.SelectionSet, ob return out } -var infraActionResponseImplementors = []string{"InfraActionResponse"} +var infraVersionDetailsImplementors = []string{"InfraVersionDetails"} -func (ec *executionContext) _InfraActionResponse(ctx context.Context, sel ast.SelectionSet, obj *model.InfraActionResponse) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, infraActionResponseImplementors) +func (ec *executionContext) _InfraVersionDetails(ctx context.Context, sel ast.SelectionSet, obj *model.InfraVersionDetails) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, infraVersionDetailsImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("InfraActionResponse") - case "projectID": - out.Values[i] = ec._InfraActionResponse_projectID(ctx, field, obj) + out.Values[i] = graphql.MarshalString("InfraVersionDetails") + case "latestVersion": + out.Values[i] = ec._InfraVersionDetails_latestVersion(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "action": - out.Values[i] = ec._InfraActionResponse_action(ctx, field, obj) + case "compatibleVersions": + out.Values[i] = ec._InfraVersionDetails_compatibleVersions(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -40145,39 +40927,61 @@ func (ec *executionContext) _InfraActionResponse(ctx context.Context, sel ast.Se return out } -var infraEventResponseImplementors = []string{"InfraEventResponse"} +var k8SProbeImplementors = []string{"K8SProbe", "CommonProbeProperties"} -func (ec *executionContext) _InfraEventResponse(ctx context.Context, sel ast.SelectionSet, obj *model.InfraEventResponse) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, infraEventResponseImplementors) +func (ec *executionContext) _K8SProbe(ctx context.Context, sel ast.SelectionSet, obj *model.K8SProbe) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, k8SProbeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("InfraEventResponse") - case "eventID": - out.Values[i] = ec._InfraEventResponse_eventID(ctx, field, obj) + out.Values[i] = graphql.MarshalString("K8SProbe") + case "probeTimeout": + out.Values[i] = ec._K8SProbe_probeTimeout(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "eventType": - out.Values[i] = ec._InfraEventResponse_eventType(ctx, field, obj) + case "interval": + out.Values[i] = ec._K8SProbe_interval(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "eventName": - out.Values[i] = ec._InfraEventResponse_eventName(ctx, field, obj) + case "retry": + out.Values[i] = ec._K8SProbe_retry(ctx, field, obj) + case "attempt": + out.Values[i] = ec._K8SProbe_attempt(ctx, field, obj) + case "probePollingInterval": + out.Values[i] = ec._K8SProbe_probePollingInterval(ctx, field, obj) + case "initialDelay": + out.Values[i] = ec._K8SProbe_initialDelay(ctx, field, obj) + case "evaluationTimeout": + out.Values[i] = ec._K8SProbe_evaluationTimeout(ctx, field, obj) + case "stopOnFailure": + out.Values[i] = ec._K8SProbe_stopOnFailure(ctx, field, obj) + case "group": + out.Values[i] = ec._K8SProbe_group(ctx, field, obj) + case "version": + out.Values[i] = ec._K8SProbe_version(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "description": - out.Values[i] = ec._InfraEventResponse_description(ctx, field, obj) + case "resource": + out.Values[i] = ec._K8SProbe_resource(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "infra": - out.Values[i] = ec._InfraEventResponse_infra(ctx, field, obj) + case "namespace": + out.Values[i] = ec._K8SProbe_namespace(ctx, field, obj) + case "resourceNames": + out.Values[i] = ec._K8SProbe_resourceNames(ctx, field, obj) + case "fieldSelector": + out.Values[i] = ec._K8SProbe_fieldSelector(ctx, field, obj) + case "labelSelector": + out.Values[i] = ec._K8SProbe_labelSelector(ctx, field, obj) + case "operation": + out.Values[i] = ec._K8SProbe_operation(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -40204,24 +41008,19 @@ func (ec *executionContext) _InfraEventResponse(ctx context.Context, sel ast.Sel return out } -var infraVersionDetailsImplementors = []string{"InfraVersionDetails"} +var kubeNamespaceImplementors = []string{"KubeNamespace"} -func (ec *executionContext) _InfraVersionDetails(ctx context.Context, sel ast.SelectionSet, obj *model.InfraVersionDetails) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, infraVersionDetailsImplementors) +func (ec *executionContext) _KubeNamespace(ctx context.Context, sel ast.SelectionSet, obj *model.KubeNamespace) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, kubeNamespaceImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("InfraVersionDetails") - case "latestVersion": - out.Values[i] = ec._InfraVersionDetails_latestVersion(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "compatibleVersions": - out.Values[i] = ec._InfraVersionDetails_compatibleVersions(ctx, field, obj) + out.Values[i] = graphql.MarshalString("KubeNamespace") + case "name": + out.Values[i] = ec._KubeNamespace_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -40248,61 +41047,24 @@ func (ec *executionContext) _InfraVersionDetails(ctx context.Context, sel ast.Se return out } -var k8SProbeImplementors = []string{"K8SProbe", "CommonProbeProperties"} +var kubeNamespaceResponseImplementors = []string{"KubeNamespaceResponse"} -func (ec *executionContext) _K8SProbe(ctx context.Context, sel ast.SelectionSet, obj *model.K8SProbe) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, k8SProbeImplementors) +func (ec *executionContext) _KubeNamespaceResponse(ctx context.Context, sel ast.SelectionSet, obj *model.KubeNamespaceResponse) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, kubeNamespaceResponseImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("K8SProbe") - case "probeTimeout": - out.Values[i] = ec._K8SProbe_probeTimeout(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "interval": - out.Values[i] = ec._K8SProbe_interval(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "retry": - out.Values[i] = ec._K8SProbe_retry(ctx, field, obj) - case "attempt": - out.Values[i] = ec._K8SProbe_attempt(ctx, field, obj) - case "probePollingInterval": - out.Values[i] = ec._K8SProbe_probePollingInterval(ctx, field, obj) - case "initialDelay": - out.Values[i] = ec._K8SProbe_initialDelay(ctx, field, obj) - case "evaluationTimeout": - out.Values[i] = ec._K8SProbe_evaluationTimeout(ctx, field, obj) - case "stopOnFailure": - out.Values[i] = ec._K8SProbe_stopOnFailure(ctx, field, obj) - case "group": - out.Values[i] = ec._K8SProbe_group(ctx, field, obj) - case "version": - out.Values[i] = ec._K8SProbe_version(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "resource": - out.Values[i] = ec._K8SProbe_resource(ctx, field, obj) + out.Values[i] = graphql.MarshalString("KubeNamespaceResponse") + case "infraID": + out.Values[i] = ec._KubeNamespaceResponse_infraID(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "namespace": - out.Values[i] = ec._K8SProbe_namespace(ctx, field, obj) - case "resourceNames": - out.Values[i] = ec._K8SProbe_resourceNames(ctx, field, obj) - case "fieldSelector": - out.Values[i] = ec._K8SProbe_fieldSelector(ctx, field, obj) - case "labelSelector": - out.Values[i] = ec._K8SProbe_labelSelector(ctx, field, obj) - case "operation": - out.Values[i] = ec._K8SProbe_operation(ctx, field, obj) + case "kubeNamespace": + out.Values[i] = ec._KubeNamespaceResponse_kubeNamespace(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -41018,6 +41780,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "kubeNamespace": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_kubeNamespace(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "addChaosHub": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_addChaosHub(ctx, field) @@ -42921,6 +43690,8 @@ func (ec *executionContext) _Subscription(ctx context.Context, sel ast.Selection return ec._Subscription_getPodLog(ctx, fields[0]) case "getKubeObject": return ec._Subscription_getKubeObject(ctx, fields[0]) + case "getKubeNamespace": + return ec._Subscription_getKubeNamespace(ctx, fields[0]) default: panic("unknown field " + strconv.Quote(fields[0].Name)) } @@ -44223,7 +44994,7 @@ func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.Selecti return res } -func (ec *executionContext) marshalNKubeObject2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx context.Context, sel ast.SelectionSet, v []*model.KubeObject) graphql.Marshaler { +func (ec *executionContext) marshalNKubeNamespace2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespace(ctx context.Context, sel ast.SelectionSet, v []*model.KubeNamespace) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -44247,7 +45018,7 @@ func (ec *executionContext) marshalNKubeObject2ᚕᚖgithubᚗcomᚋlitmuschaos if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalOKubeObject2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx, sel, v[i]) + ret[i] = ec.marshalOKubeNamespace2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespace(ctx, sel, v[i]) } if isLen1 { f(i) @@ -44261,6 +45032,40 @@ func (ec *executionContext) marshalNKubeObject2ᚕᚖgithubᚗcomᚋlitmuschaos return ret } +func (ec *executionContext) unmarshalNKubeNamespaceData2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceData(ctx context.Context, v interface{}) (model.KubeNamespaceData, error) { + res, err := ec.unmarshalInputKubeNamespaceData(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) unmarshalNKubeNamespaceRequest2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceRequest(ctx context.Context, v interface{}) (model.KubeNamespaceRequest, error) { + res, err := ec.unmarshalInputKubeNamespaceRequest(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNKubeNamespaceResponse2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceResponse(ctx context.Context, sel ast.SelectionSet, v model.KubeNamespaceResponse) graphql.Marshaler { + return ec._KubeNamespaceResponse(ctx, sel, &v) +} + +func (ec *executionContext) marshalNKubeNamespaceResponse2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespaceResponse(ctx context.Context, sel ast.SelectionSet, v *model.KubeNamespaceResponse) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._KubeNamespaceResponse(ctx, sel, v) +} + +func (ec *executionContext) marshalNKubeObject2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx context.Context, sel ast.SelectionSet, v *model.KubeObject) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._KubeObject(ctx, sel, v) +} + func (ec *executionContext) unmarshalNKubeObjectData2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObjectData(ctx context.Context, v interface{}) (model.KubeObjectData, error) { res, err := ec.unmarshalInputKubeObjectData(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -45812,11 +46617,11 @@ func (ec *executionContext) unmarshalOKubeGVRRequest2ᚖgithubᚗcomᚋlitmuscha return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalOKubeObject2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeObject(ctx context.Context, sel ast.SelectionSet, v *model.KubeObject) graphql.Marshaler { +func (ec *executionContext) marshalOKubeNamespace2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubeNamespace(ctx context.Context, sel ast.SelectionSet, v *model.KubeNamespace) graphql.Marshaler { if v == nil { return graphql.Null } - return ec._KubeObject(ctx, sel, v) + return ec._KubeNamespace(ctx, sel, v) } func (ec *executionContext) marshalOKubernetesCMDProbe2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐKubernetesCMDProbe(ctx context.Context, sel ast.SelectionSet, v *model.KubernetesCMDProbe) graphql.Marshaler { diff --git a/chaoscenter/graphql/server/graph/model/models_gen.go b/chaoscenter/graphql/server/graph/model/models_gen.go index b4173ea00b2..9734945dfb1 100644 --- a/chaoscenter/graphql/server/graph/model/models_gen.go +++ b/chaoscenter/graphql/server/graph/model/models_gen.go @@ -138,6 +138,8 @@ type ChaosHub struct { RepoURL string `json:"repoURL"` // Branch of the git repository RepoBranch string `json:"repoBranch"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // ID of the project in which the chaos hub is present ProjectID string `json:"projectID"` // Default Hub Identifier @@ -213,6 +215,8 @@ type ChaosHubStatus struct { RepoURL string `json:"repoURL"` // Branch of the git repository RepoBranch string `json:"repoBranch"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // Bool value indicating whether the hub is available or not. IsAvailable bool `json:"isAvailable"` // Total number of experiments in the hub @@ -292,6 +296,8 @@ type CloningInput struct { RepoBranch string `json:"repoBranch"` // URL of the git repository RepoURL string `json:"repoURL"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // Bool value indicating whether the hub is private or not. IsPrivate bool `json:"isPrivate"` // Type of authentication used: BASIC, SSH, TOKEN @@ -344,6 +350,8 @@ type CreateChaosHubRequest struct { RepoURL string `json:"repoURL"` // Branch of the git repository RepoBranch string `json:"repoBranch"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // Bool value indicating whether the hub is private or not. IsPrivate bool `json:"isPrivate"` // Type of authentication used: BASIC, SSH, TOKEN @@ -377,6 +385,8 @@ type CreateRemoteChaosHub struct { Description *string `json:"description,omitempty"` // URL of the git repository RepoURL string `json:"repoURL"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` } // Defines the start date and end date for the filtering the data @@ -1149,7 +1159,37 @@ type KubeGVRRequest struct { Resource string `json:"resource"` } -// KubeObject consists of the namespace and the available resources in the same +// Define name in the infra (not really useful at the moment but maybe we will need other field later) +type KubeNamespace struct { + // Name of the namespace + Name string `json:"name"` +} + +// Defines the details of Kubernetes namespace +type KubeNamespaceData struct { + // Unique request ID for fetching Kubernetes namespace details + RequestID string `json:"requestID"` + // ID of the infra in which the Kubernetes namespace is present + InfraID *InfraIdentity `json:"infraID"` + // List of KubeNamespace return by subscriber + KubeNamespace string `json:"kubeNamespace"` +} + +// Defines details for fetching Kubernetes namespace data +type KubeNamespaceRequest struct { + // ID of the infra + InfraID string `json:"infraID"` +} + +// Response received for querying Kubernetes Namespaces +type KubeNamespaceResponse struct { + // ID of the infra in which the Kubernetes namespace is present + InfraID string `json:"infraID"` + // List of the Kubernetes namespace + KubeNamespace []*KubeNamespace `json:"kubeNamespace"` +} + +// KubeObject consists of the available resources in a namespace type KubeObject struct { // Namespace of the resource Namespace string `json:"namespace"` @@ -1173,8 +1213,10 @@ type KubeObjectRequest struct { InfraID string `json:"infraID"` // GVR Request KubeObjRequest *KubeGVRRequest `json:"kubeObjRequest,omitempty"` - ObjectType string `json:"objectType"` - Workloads []*Workload `json:"workloads,omitempty"` + // Namespace in which the Kubernetes object is present + Namespace string `json:"namespace"` + ObjectType string `json:"objectType"` + Workloads []*Workload `json:"workloads,omitempty"` } // Response received for querying Kubernetes Object @@ -1182,7 +1224,7 @@ type KubeObjectResponse struct { // ID of the infra in which the Kubernetes object is present InfraID string `json:"infraID"` // Type of the Kubernetes object - KubeObj []*KubeObject `json:"kubeObj"` + KubeObj *KubeObject `json:"kubeObj"` } // Defines the CMD probe properties @@ -1945,6 +1987,8 @@ type UpdateChaosHubRequest struct { RepoURL string `json:"repoURL"` // Branch of the git repository RepoBranch string `json:"repoBranch"` + // Connected Hub of remote repository + RemoteHub string `json:"remoteHub"` // Bool value indicating whether the hub is private or not. IsPrivate bool `json:"isPrivate"` // Type of authentication used: BASIC, SSH, TOKEN diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go index c2ff92baa35..ee51be6d05f 100644 --- a/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go +++ b/chaoscenter/graphql/server/pkg/chaos_experiment/handler/handler.go @@ -1234,7 +1234,33 @@ func (c *ChaosExperimentHandler) GetKubeObjData(reqID string, kubeObject model.K } else if reqChan, ok := r.KubeObjectData[reqID]; ok { resp := model.KubeObjectResponse{ InfraID: kubeObject.InfraID, - KubeObj: []*model.KubeObject{}, + KubeObj: &model.KubeObject{}, + } + reqChan <- &resp + close(reqChan) + } +} + +func (c *ChaosExperimentHandler) GetKubeNamespaceData(reqID string, kubeNamespace model.KubeNamespaceRequest, r store.StateData) { + reqType := "namespace" + data, err := json.Marshal(kubeNamespace) + if err != nil { + logrus.Print("ERROR WHILE MARSHALLING POD DETAILS") + } + externalData := string(data) + payload := model.InfraActionResponse{ + Action: &model.ActionPayload{ + RequestID: reqID, + RequestType: reqType, + ExternalData: &externalData, + }, + } + if clusterChan, ok := r.ConnectedInfra[kubeNamespace.InfraID]; ok { + clusterChan <- &payload + } else if reqChan, ok := r.KubeNamespaceData[reqID]; ok { + resp := model.KubeNamespaceResponse{ + InfraID: kubeNamespace.InfraID, + KubeNamespace: []*model.KubeNamespace{}, } reqChan <- &resp close(reqChan) diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/fuzz_tests/service_fuzz_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/fuzz_tests/service_fuzz_test.go new file mode 100644 index 00000000000..5ae50c6ef7b --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/fuzz_tests/service_fuzz_test.go @@ -0,0 +1,145 @@ +package fuzz_tests + +import ( + "context" + "testing" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run" + dbChaosExperiment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment" + dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" + dbChaosInfra "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_infrastructure" + dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + store "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/data-store" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" + "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type MockServices struct { + ChaosExperimentOperator *dbChaosExperiment.Operator + ChaosExperimentRunOperator *dbChaosExperimentRun.Operator + ChaosInfrastructureOperator *dbChaosInfra.Operator + MongodbOperator *dbMocks.MongoOperator + ChaosExperimentRunService chaos_experiment_run.Service +} + +func NewMockServices() *MockServices { + var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + chaosExperimentOperator = dbChaosExperiment.NewChaosExperimentOperator(mongodbMockOperator) + chaosExperimentRunOperator = dbChaosExperimentRun.NewChaosExperimentRunOperator(mongodbMockOperator) + chaosInfrastructureOperator = dbChaosInfra.NewInfrastructureOperator(mongodbMockOperator) + chaosExperimentRunService chaos_experiment_run.Service = chaos_experiment_run.NewChaosExperimentRunService( + chaosExperimentOperator, + chaosInfrastructureOperator, + chaosExperimentRunOperator, + ) + ) + return &MockServices{ + ChaosExperimentOperator: chaosExperimentOperator, + ChaosExperimentRunOperator: chaosExperimentRunOperator, + ChaosInfrastructureOperator: chaosInfrastructureOperator, + MongodbOperator: mongodbMockOperator, + ChaosExperimentRunService: chaosExperimentRunService, + } +} + +func FuzzProcessExperimentRunDelete(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + Query bson.D + WorkflowRunID *string + ExperimentRun dbChaosExperimentRun.ChaosExperimentRun + Workflow dbChaosExperiment.ChaosExperimentRequest + Username string + StoreStateData *store.StateData + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + mockServices := NewMockServices() + mockServices.MongodbOperator.On("Update", mock.Anything, mongodb.ChaosExperimentRunsCollection, mock.Anything, mock.Anything, mock.Anything).Return(&mongo.UpdateResult{}, nil).Once() + + err = mockServices.ChaosExperimentRunService.ProcessExperimentRunDelete( + context.Background(), + targetStruct.Query, + targetStruct.WorkflowRunID, + targetStruct.ExperimentRun, + targetStruct.Workflow, + targetStruct.Username, + targetStruct.StoreStateData, + ) + if err != nil { + t.Errorf("ProcessExperimentRunDelete() error = %v", err) + } + }) +} + +func FuzzProcessExperimentRunStop(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + Query bson.D + ExperimentRunID *string + Experiment dbChaosExperiment.ChaosExperimentRequest + Username string + ProjectID string + StoreStateData *store.StateData + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.MongodbOperator.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&mongo.UpdateResult{}, nil).Once() + err = mockServices.ChaosExperimentRunService.ProcessExperimentRunStop( + context.Background(), + targetStruct.Query, + targetStruct.ExperimentRunID, + targetStruct.Experiment, + targetStruct.Username, + targetStruct.ProjectID, + targetStruct.StoreStateData, + ) + if err != nil { + t.Errorf("ProcessExperimentRunStop() error = %v", err) + } + }) +} + +func FuzzProcessCompletedExperimentRun(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ExecData chaos_experiment_run.ExecutionData + WfID string + RunID string + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + findResult := []interface{}{bson.D{ + {Key: "experiment_id", Value: targetStruct.WfID}, + }} + mockServices := NewMockServices() + singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) + mockServices.MongodbOperator.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(singleResult, nil).Once() + + _, err = mockServices.ChaosExperimentRunService.ProcessCompletedExperimentRun( + targetStruct.ExecData, + targetStruct.WfID, + targetStruct.RunID, + ) + if err != nil { + t.Errorf("ProcessCompletedExperimentRun() error = %v", err) + } + }) +} diff --git a/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/fuzz_tests/handler_fuzz_test.go b/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/fuzz_tests/handler_fuzz_test.go new file mode 100644 index 00000000000..56af374f378 --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler/fuzz_tests/handler_fuzz_test.go @@ -0,0 +1,242 @@ +package fuzz_tests + +import ( + "context" + "strings" + "testing" + "time" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run/handler" + chaosInfraMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks" + dbChaosExperiment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment" + dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" + dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" + dbGitOpsMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/gitops/model/mocks" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + + "github.com/google/uuid" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + typesMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" + "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type MockServices struct { + ChaosExperimentRunService *typesMocks.ChaosExperimentRunService + InfrastructureService *chaosInfraMocks.InfraService + GitOpsService *dbGitOpsMocks.GitOpsService + ChaosExperimentOperator *dbChaosExperiment.Operator + ChaosExperimentRunOperator *dbChaosExperimentRun.Operator + MongodbOperator *dbMocks.MongoOperator + ChaosExperimentRunHandler *handler.ChaosExperimentRunHandler +} + +func NewMockServices() *MockServices { + var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + infrastructureService = new(chaosInfraMocks.InfraService) + gitOpsService = new(dbGitOpsMocks.GitOpsService) + chaosExperimentRunService = new(typesMocks.ChaosExperimentRunService) + chaosExperimentOperator = dbChaosExperiment.NewChaosExperimentOperator(mongodbMockOperator) + chaosExperimentRunOperator = dbChaosExperimentRun.NewChaosExperimentRunOperator(mongodbMockOperator) + ) + var chaosExperimentRunHandler = handler.NewChaosExperimentRunHandler( + chaosExperimentRunService, + infrastructureService, + gitOpsService, + chaosExperimentOperator, + chaosExperimentRunOperator, + mongodbMockOperator, + ) + return &MockServices{ + ChaosExperimentRunService: chaosExperimentRunService, + InfrastructureService: infrastructureService, + GitOpsService: gitOpsService, + ChaosExperimentOperator: chaosExperimentOperator, + ChaosExperimentRunOperator: chaosExperimentRunOperator, + MongodbOperator: mongodbMockOperator, + ChaosExperimentRunHandler: chaosExperimentRunHandler, + } +} + +func FuzzGetExperimentRun(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + ExperimentRunID string + NotifyID string + }{} + + targetStruct.ProjectID = uuid.New().String() + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + ctx := context.Background() + mockServices := NewMockServices() + findResult := []interface{}{bson.D{ + {Key: "experiment_run_id", Value: targetStruct.ExperimentRunID}, + {Key: "project_id", Value: targetStruct.ProjectID}, + {Key: "infra_id", Value: "mockInfraID"}, + {Key: "kubernetesInfraDetails", Value: bson.A{ + bson.D{ + {Key: "InfraID", Value: "mockInfraID"}, + {Key: "Name", Value: "MockInfra"}, + {Key: "EnvironmentID", Value: "mockEnvID"}, + {Key: "Description", Value: "Mock Infrastructure"}, + {Key: "PlatformName", Value: "Kubernetes"}, + {Key: "IsActive", Value: true}, + {Key: "UpdatedAt", Value: time.Now().Unix()}, + {Key: "CreatedAt", Value: time.Now().Unix()}, + }, + }}, + {Key: "experiment", Value: bson.A{ + bson.D{ + {Key: "ExperimentName", Value: "MockExperiment"}, + {Key: "ExperimentType", Value: "MockType"}, + {Key: "Revision", Value: bson.A{ + bson.D{ + {Key: "RevisionID", Value: uuid.NewString()}, + {Key: "ExperimentManifest", Value: "mockManifest"}, + {Key: "Weightages", Value: bson.A{ + bson.D{{Key: "FaultName", Value: "fault1"}, {Key: "Weightage", Value: 10}}, + bson.D{{Key: "FaultName", Value: "fault2"}, {Key: "Weightage", Value: 20}}, + }}, + }, + }}, + }, + }}, + }} + + cursor, _ := mongo.NewCursorFromDocuments(findResult, nil, nil) + mockServices.MongodbOperator.On("Aggregate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(cursor, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.GetExperimentRun(ctx, targetStruct.ProjectID, &targetStruct.ExperimentRunID, &targetStruct.NotifyID) + if err != nil { + t.Errorf("ChaosExperimentRunHandler.GetExperimentRun() error = %v", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + }) +} + +func FuzzListExperimentRun(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + Request model.ListExperimentRunRequest + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + findResult := []interface{}{bson.D{ + {Key: "project_id", Value: targetStruct.ProjectID}, + {Key: "infra_id", Value: "abc"}, + { + Key: "revision", Value: []dbChaosExperiment.ExperimentRevision{ + { + RevisionID: uuid.NewString(), + }, + }, + }, + }} + cursor, _ := mongo.NewCursorFromDocuments(findResult, nil, nil) + mockServices.MongodbOperator.On("Aggregate", mock.Anything, mongodb.ChaosExperimentRunsCollection, mock.Anything, mock.Anything).Return(cursor, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.ListExperimentRun(targetStruct.ProjectID, targetStruct.Request) + if err != nil { + t.Errorf("ListExperimentRun() error = %v", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + + }) +} + +func FuzzRunChaosWorkFlow(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + Workflow dbChaosExperiment.ChaosExperimentRequest + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.MongodbOperator.On("StartSession").Return(mock.Anything, nil).Once() + mockServices.MongodbOperator.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&mongo.UpdateResult{}, nil).Once() + mockServices.MongodbOperator.On("CommitTransaction", mock.Anything).Return(nil).Once() + mockServices.MongodbOperator.On("AbortTransaction", mock.Anything).Return(nil).Once() + + findResult := []interface{}{bson.D{ + {Key: "infra_id", Value: targetStruct.ProjectID}, + }} + singleResult := mongo.NewSingleResultFromDocument(findResult[0], nil, nil) + mockServices.MongodbOperator.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(singleResult, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.RunChaosWorkFlow(context.Background(), targetStruct.ProjectID, targetStruct.Workflow, nil) + if strings.Contains(err.Error(), "inactive infra") { + t.Log("Handled expected error due to inactive infrastructure: ", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + }) +} + +func FuzzGetExperimentRunStats(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + ProjectID string + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + targetStruct.ProjectID = uuid.New().String() + + mockServices := NewMockServices() + + findResult := []interface{}{bson.D{ + {Key: "project_id", Value: targetStruct.ProjectID}, + {Key: "infra_id", Value: "abc"}, + { + Key: "revision", Value: []dbChaosExperiment.ExperimentRevision{ + { + RevisionID: uuid.NewString(), + }, + }, + }, + }} + cursor, _ := mongo.NewCursorFromDocuments(findResult, nil, nil) + mockServices.MongodbOperator.On("Aggregate", mock.Anything, mongodb.ChaosExperimentRunsCollection, mock.Anything, mock.Anything).Return(cursor, nil).Once() + + res, err := mockServices.ChaosExperimentRunHandler.GetExperimentRunStats(context.Background(), targetStruct.ProjectID) + if err != nil { + t.Errorf("GetExperimentRunStats() error = %v", err) + return + } + if res == nil { + t.Errorf("Returned response is nil") + } + }) +} diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/fuzz/fuzz_test.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/fuzz/fuzz_test.go new file mode 100644 index 00000000000..b8fa0ff67b0 --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/fuzz/fuzz_test.go @@ -0,0 +1,656 @@ +package test + +import ( + "context" + "testing" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment/handler" + chaosExperimentMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment/model/mocks" + chaosExperimentRunMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_experiment_run/model/mocks" + chaosInfraMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks" + dbChaosExperiment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment" + dbChaosExperimentRun "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_experiment_run" + dbMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/mocks" + dbGitOpsMocks "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/gitops/model/mocks" + "go.mongodb.org/mongo-driver/bson" + + dbChaosInfra "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_infrastructure" + dbOperationsEnvironment "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/environments" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + store "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/data-store" +) + +type MockServices struct { + ChaosExperimentService *chaosExperimentMocks.ChaosExperimentService + ChaosExperimentRunService *chaosExperimentRunMocks.ChaosExperimentRunService + InfrastructureService *chaosInfraMocks.InfraService + GitOpsService *dbGitOpsMocks.GitOpsService + ChaosExperimentOperator *dbChaosExperiment.Operator + ChaosExperimentRunOperator *dbChaosExperimentRun.Operator + MongodbOperator *dbMocks.MongoOperator + ChaosExperimentHandler *handler.ChaosExperimentHandler +} + +func NewMockServices() *MockServices { + var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + infrastructureService = new(chaosInfraMocks.InfraService) + chaosExperimentRunService = new(chaosExperimentRunMocks.ChaosExperimentRunService) + gitOpsService = new(dbGitOpsMocks.GitOpsService) + chaosExperimentOperator = dbChaosExperiment.NewChaosExperimentOperator(mongodbMockOperator) + chaosExperimentRunOperator = dbChaosExperimentRun.NewChaosExperimentRunOperator(mongodbMockOperator) + chaosExperimentService = new(chaosExperimentMocks.ChaosExperimentService) + ) + var chaosExperimentHandler = handler.NewChaosExperimentHandler(chaosExperimentService, chaosExperimentRunService, infrastructureService, gitOpsService, chaosExperimentOperator, chaosExperimentRunOperator, mongodbMockOperator) + return &MockServices{ + ChaosExperimentService: chaosExperimentService, + ChaosExperimentRunService: chaosExperimentRunService, + InfrastructureService: infrastructureService, + GitOpsService: gitOpsService, + ChaosExperimentOperator: chaosExperimentOperator, + ChaosExperimentRunOperator: chaosExperimentRunOperator, + MongodbOperator: mongodbMockOperator, + ChaosExperimentHandler: chaosExperimentHandler, + } +} + +var ( + mongodbMockOperator = new(dbMocks.MongoOperator) + environmentOperator = dbOperationsEnvironment.NewEnvironmentOperator(mongodbMockOperator) +) + +func stringPointer(v string) *string { return &v } + +func FuzzRegisterInfra(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + request model.RegisterInfraRequest + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + ctx := context.Background() + mockServices := NewMockServices() + mockResponse := &model.RegisterInfraResponse{ + Token: "test-token", + InfraID: "test-infra-id", + Name: targetStruct.request.Name, + Manifest: "test-manifest", + } + mockServices.InfrastructureService. + On("RegisterInfra", ctx, targetStruct.projectID, targetStruct.request). + Return(mockResponse, nil) + + response, err := mockServices.InfrastructureService.RegisterInfra(ctx, targetStruct.projectID, targetStruct.request) + if response.Name != targetStruct.request.Name { + t.Errorf("Chaos Infrastructure Name is %s Return %s", response.Name, targetStruct.request.Name) + } + if err != nil { + t.Errorf("ChaosInfrastructure.RegisterInfra() error = %v", err) + return + } + if response == nil { + t.Errorf("Returned environment is nil") + } + }) + +} + +func FuzzDeleteInfra(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + infraID string + r store.StateData + }{} + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + ctx := context.Background() + mockServices := NewMockServices() + + mockServices.InfrastructureService. + On("DeleteInfra", ctx, targetStruct.projectID, targetStruct.infraID, targetStruct.r). + Return("infra deleted successfully", nil) + + response, err := mockServices.InfrastructureService.DeleteInfra(ctx, targetStruct.projectID, targetStruct.infraID, targetStruct.r) + if err != nil { + t.Errorf("ChaosInfrastructure.RegisterInfra() error = %v", err) + return + } + if response == "" { + t.Errorf("Returned environment is nil") + } + + }) +} + +func FuzzGetInfraTest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + infraID string + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + ctx := context.Background() + mockServices := NewMockServices() + + mockResponse := &model.Infra{ + InfraID: targetStruct.infraID, + ProjectID: targetStruct.projectID, + Name: "TestInfraName", + Description: nil, + Tags: []string{"tag1", "tag2"}, + EnvironmentID: "test-env-id", + PlatformName: "test-platform", + IsActive: true, + IsInfraConfirmed: true, + IsRemoved: false, + UpdatedAt: "1680000000", + CreatedAt: "1670000000", + Token: "test-token", + InfraNamespace: nil, + ServiceAccount: nil, + InfraScope: "test-scope", + StartTime: "1675000000", + Version: "1.0.0", + CreatedBy: &model.UserDetails{Username: "test-user"}, + UpdatedBy: &model.UserDetails{Username: "test-user"}, + NoOfExperiments: nil, + NoOfExperimentRuns: nil, + LastExperimentTimestamp: nil, + UpdateStatus: "UpToDate", + } + + mockServices.InfrastructureService. + On("GetInfra", context.Background(), targetStruct.projectID, targetStruct.infraID). + Return(mockResponse, nil) + + infra, err := mockServices.InfrastructureService.GetInfra(ctx, targetStruct.projectID, targetStruct.infraID) + if err != nil { + t.Errorf("ChaosInfrastructure.GetInfra() error = %v", err) + return + } + if infra.InfraID != targetStruct.infraID { + t.Errorf("ProjectID mismatch: got %v, want %v", infra.InfraID, targetStruct.infraID) + } + }) +} + +func FuzzListInfras(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + request *model.ListInfraRequest + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + + mockResponse := &model.ListInfraResponse{ + TotalNoOfInfras: 10, + Infras: []*model.Infra{ + { + InfraID: "infra1", + ProjectID: targetStruct.projectID, + Name: "Test Infra", + EnvironmentID: "env1", + Description: stringPointer("Test description"), + PlatformName: "Test Platform", + IsActive: true, + IsInfraConfirmed: true, + UpdatedAt: "1622527200", + CreatedAt: "1622523600", + Token: "test-token", + InfraNamespace: stringPointer("test-namespace"), + ServiceAccount: stringPointer("test-service-account"), + InfraScope: "test-scope", + StartTime: "1622520000", + Version: "v1.0", + Tags: []string{"tag1", "tag2"}, + IsRemoved: false, + }, + }, + } + + mockServices.InfrastructureService.On("ListInfras", targetStruct.projectID, targetStruct.request). + Return(mockResponse, nil) + + response, err := mockServices.InfrastructureService.ListInfras(targetStruct.projectID, targetStruct.request) + if err != nil { + t.Errorf("ChaosInfrastructure.DeleteInfra() error = %v", err) + return + } + + if response.TotalNoOfInfras < 0 { + t.Errorf("Invalid TotalNoOfInfras: %d", response.TotalNoOfInfras) + } + for _, infra := range response.Infras { + if infra.InfraID == "" { + t.Errorf("InfraID should not be empty") + } + if infra.ProjectID != targetStruct.projectID { + t.Errorf("ProjectID mismatch: got %v, want %v", infra.ProjectID, targetStruct.projectID) + } + } + + }) +} + +func FuzzGetInfraDetails(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + InfraID string + projectID string + request *model.ListInfraRequest + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockResponse := &model.Infra{ + InfraID: targetStruct.InfraID, + ProjectID: targetStruct.projectID, + Name: "TestInfraName", + Description: nil, + Tags: []string{"tag1", "tag2"}, + EnvironmentID: "test-env-id", + PlatformName: "test-platform", + IsActive: true, + IsInfraConfirmed: true, + IsRemoved: false, + UpdatedAt: "1680000000", + CreatedAt: "1670000000", + Token: "test-token", + InfraNamespace: nil, + ServiceAccount: nil, + InfraScope: "test-scope", + StartTime: "1675000000", + Version: "1.0.0", + CreatedBy: &model.UserDetails{Username: "test-user"}, + UpdatedBy: &model.UserDetails{Username: "test-user"}, + NoOfExperiments: nil, + NoOfExperimentRuns: nil, + LastExperimentTimestamp: nil, + UpdateStatus: "UpToDate", + } + + mockServices.InfrastructureService. + On("GetInfra", context.Background(), targetStruct.projectID, targetStruct.InfraID). + Return(mockResponse, nil) + + mockServices.InfrastructureService. + On("GetInfraDetails", context.Background(), targetStruct.InfraID, targetStruct.projectID). + Return(mockResponse, nil) + + ctx := context.Background() + response, err := mockServices.InfrastructureService.GetInfraDetails(ctx, targetStruct.InfraID, targetStruct.projectID) + if err != nil { + t.Errorf("ChaosInfrastructure.DeleteInfra() error = %v", err) + return + } + if response.InfraID != targetStruct.InfraID { + t.Errorf("InfraID mismatch: got %v, want %v", response.InfraID, targetStruct.InfraID) + } + + }) +} + +func FuzzGetInfraStats(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + projectID string + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockResponse := &model.GetInfraStatsResponse{ + TotalInfrastructures: 10, + TotalActiveInfrastructure: 7, + TotalInactiveInfrastructures: 3, + TotalConfirmedInfrastructure: 8, + TotalNonConfirmedInfrastructures: 2, + } + + mockServices.InfrastructureService. + On("GetInfraStats", context.Background(), targetStruct.projectID). + Return(mockResponse, nil) + + ctx := context.Background() + response, err := mockServices.InfrastructureService.GetInfraStats(ctx, targetStruct.projectID) + if err != nil { + t.Errorf("ChaosInfrastructure.DeleteInfra() error = %v", err) + return + } + if response.TotalInfrastructures != mockResponse.TotalInfrastructures { + t.Errorf("TotalInfrastructures mismatch: got %v, want %v", response.TotalInfrastructures, mockResponse.TotalInfrastructures) + } + if response.TotalActiveInfrastructure != mockResponse.TotalActiveInfrastructure { + t.Errorf("TotalActiveInfrastructure mismatch: got %v, want %v", response.TotalActiveInfrastructure, mockResponse.TotalActiveInfrastructure) + } + if response.TotalInactiveInfrastructures != mockResponse.TotalInactiveInfrastructures { + t.Errorf("TotalInactiveInfrastructures mismatch: got %v, want %v", response.TotalInactiveInfrastructures, mockResponse.TotalInactiveInfrastructures) + } + if response.TotalConfirmedInfrastructure != mockResponse.TotalConfirmedInfrastructure { + t.Errorf("TotalConfirmedInfrastructure mismatch: got %v, want %v", response.TotalConfirmedInfrastructure, mockResponse.TotalConfirmedInfrastructure) + } + if response.TotalNonConfirmedInfrastructures != mockResponse.TotalNonConfirmedInfrastructures { + t.Errorf("TotalNonConfirmedInfrastructures mismatch: got %v, want %v", response.TotalNonConfirmedInfrastructures, mockResponse.TotalNonConfirmedInfrastructures) + } + + }) +} + +func FuzzGetVersionDetails(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + mockServices := NewMockServices() + mockResponse := &model.InfraVersionDetails{ + LatestVersion: "testVersion1", + CompatibleVersions: []string{"compatibleVersion1", "compatibleVersion2"}, + } + + mockServices.InfrastructureService.On("GetVersionDetails").Return(mockResponse, nil) + response, err := mockServices.InfrastructureService.GetVersionDetails() + + if err != nil { + t.Errorf("infraService.GetVersionDetails() error = %v", err) + return + } + + if response == nil { + t.Errorf("Expected a non-nil response") + return + } + if response.LatestVersion == "" { + t.Errorf("Expected a valid latest version") + } + + }) +} + +func FuzzQueryServerVersion(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + ctx := context.Background() + mockResponse := &model.ServerVersionResponse{ + Key: "version", + Value: string(data), + } + + mockServices := NewMockServices() + mockServices.InfrastructureService.On("GetConfig", ctx, "version").Return(mockResponse, nil) + mockServices.InfrastructureService.On("QueryServerVersion", ctx).Return(mockResponse, nil) + response, err := mockServices.InfrastructureService.QueryServerVersion(ctx) + if err != nil { + t.Errorf("QueryServerVersion() error = %v", err) + return + } + if response == nil { + t.Errorf("Expected a non-nil response") + return + } + if response.Key != "version" { + t.Errorf("Expected Key to be 'version', got %s", response.Key) + } + if response.Value != string(data) { + t.Errorf("Expected Value to be %s, got %s", string(data), response.Value) + } + }) +} + +func FuzzPodLog(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + request model.PodLog + r store.StateData + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.InfrastructureService. + On("PodLog", targetStruct.request, targetStruct.r). + Return("LOGS SENT SUCCESSFULLY", nil) + response, err := mockServices.InfrastructureService.PodLog(targetStruct.request, targetStruct.r) + if err != nil { + t.Errorf("ChaosInfrastructure.PodLog() error = %v", err) + return + } + if response == "" { + t.Errorf("Returned environment is nil") + } + + }) +} + +func FuzzKubeObj(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + request model.KubeObjectData + r store.StateData + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.InfrastructureService. + On("KubeObj", targetStruct.request, targetStruct.r). + Return("KubeData sent successfully", nil) + + response, err := mockServices.InfrastructureService.KubeObj(targetStruct.request, targetStruct.r) + if err != nil { + t.Errorf("ChaosInfrastructure.KubeObj() error = %v", err) + return + } + if response == "" { + t.Errorf("Returned environment is nil") + } + }) +} + +func FuzzSendInfraEvent(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + EventType string + EventName string + Description string + Infra model.Infra + R store.StateData + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + targetStruct.R.InfraEventPublish = make(map[string][]chan *model.InfraEventResponse) + projectID := targetStruct.Infra.ProjectID + if projectID != "" { + targetStruct.R.InfraEventPublish[projectID] = append(targetStruct.R.InfraEventPublish[projectID], make(chan *model.InfraEventResponse, 1)) + } + + mockServices.InfrastructureService.SendInfraEvent(targetStruct.EventType, targetStruct.EventName, targetStruct.Description, targetStruct.Infra, targetStruct.R) + + if projectID != "" { + select { + case event := <-targetStruct.R.InfraEventPublish[projectID][0]: + if event == nil { + t.Errorf("Expected non-nil event") + } + if event.EventType != targetStruct.EventType { + t.Errorf("Expected EventType to be %s, got %s", targetStruct.EventType, event.EventType) + } + if event.EventName != targetStruct.EventName { + t.Errorf("Expected EventName to be %s, got %s", targetStruct.EventName, event.EventName) + } + if event.Description != targetStruct.Description { + t.Errorf("Expected Description to be %s, got %s", targetStruct.Description, event.Description) + } + if event.Infra != &targetStruct.Infra { + t.Errorf("Expected Infra to be %+v, got %+v", targetStruct.Infra, event.Infra) + } + default: + t.Errorf("Expected an event to be published") + } + } + }) +} +func FuzzConfirmInfraRegistration(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + request model.InfraIdentity + r store.StateData + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.InfrastructureService. + On("ConfirmInfraRegistration", targetStruct.request, targetStruct.r). + Return(&model.ConfirmInfraRegistrationResponse{ + IsInfraConfirmed: true, + NewAccessKey: &targetStruct.request.AccessKey, + InfraID: &targetStruct.request.InfraID, + }, nil) + + response, err := mockServices.InfrastructureService.ConfirmInfraRegistration(targetStruct.request, targetStruct.r) + if err != nil { + t.Errorf("ChaosInfrastructure.ConfirmInfraRegistration() error = %v", err) + return + } + if response == nil { + t.Errorf("Returned environment is nil") + } + + }) +} + +func FuzzVerifyInfra(f *testing.F) { + + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + request := model.InfraIdentity{} + err := fuzzConsumer.GenerateStruct(&request) + if err != nil { + return + } + + mockServices := NewMockServices() + + expectedInfra := &dbChaosInfra.ChaosInfra{ + InfraID: request.InfraID, + AccessKey: request.AccessKey, + IsRegistered: true, + Version: request.Version, + } + + mockServices.InfrastructureService. + On("VerifyInfra", request). + Return(expectedInfra, nil) + + response, err := mockServices.InfrastructureService.VerifyInfra(request) + if err != nil { + t.Errorf("ChaosInfrastructure.VerifyInfra() error = %v", err) + return + } + if response == nil { + t.Errorf("Returned environment is nil") + } + + }) +} +func FuzzUpdateInfra(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + targetStruct := &struct { + query bson.D + update bson.D + }{} + + err := fuzzConsumer.GenerateStruct(targetStruct) + if err != nil { + return + } + + mockServices := NewMockServices() + mockServices.InfrastructureService. + On("UpdateInfra", targetStruct.query, targetStruct.update). + Return(nil) + + err = mockServices.InfrastructureService.UpdateInfra(targetStruct.query, targetStruct.update) + if err != nil { + t.Errorf("ChaosInfrastructure.UpdateInfra() error = %v", err) + return + } + + }) +} +func FuzzGetDBInfra(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + var infraID string + err := fuzzConsumer.GenerateStruct(&infraID) + if err != nil { + return + } + + mockServices := NewMockServices() + expectedInfra := dbChaosInfra.ChaosInfra{ + InfraID: infraID, + } + + mockServices.InfrastructureService. + On("GetDBInfra", infraID). + Return(expectedInfra, nil) + + response, err := mockServices.InfrastructureService.GetDBInfra(infraID) + if err != nil { + t.Errorf("ChaosInfrastructure.GetDBInfra() error = %v", err) + return + } + if response.InfraID != infraID { + t.Errorf("InfraID mismatch: got %v, want %v", response.InfraID, infraID) + } + }) +} diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks/service.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks/service.go index 2e7d68c299d..adf4020ae17 100644 --- a/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/model/mocks/service.go @@ -88,6 +88,11 @@ func (s *InfraService) KubeObj(request model.KubeObjectData, r store.StateData) return args.String(0), args.Error(1) } +func (s *InfraService) KubeNamespace(request model.KubeNamespaceData, r store.StateData) (string, error) { + args := s.Called(request, r) + return args.String(0), args.Error(1) +} + func (s *InfraService) UpdateInfra(query bson.D, update bson.D) error { args := s.Called(query, update) return args.Error(0) diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go index 3f67d76413d..c01d1819831 100644 --- a/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go @@ -51,6 +51,7 @@ type Service interface { GetVersionDetails() (*model.InfraVersionDetails, error) QueryServerVersion(ctx context.Context) (*model.ServerVersionResponse, error) PodLog(request model.PodLog, r store.StateData) (string, error) + KubeNamespace(request model.KubeNamespaceData, r store.StateData) (string, error) KubeObj(request model.KubeObjectData, r store.StateData) (string, error) UpdateInfra(query bson.D, update bson.D) error GetDBInfra(infraID string) (dbChaosInfra.ChaosInfra, error) @@ -938,6 +939,9 @@ func fetchLatestVersion(versions map[int]string) int { // updateVersionFormat converts string array to int by removing decimal points, 1.0.0 will be returned as 100, 0.1.0 will be returned as 10, 0.0.1 will be returned as 1 func updateVersionFormat(str string) (int, error) { + if str == CIVersion { + return 0, nil + } var versionInt int versionSlice := strings.Split(str, ".") for i, val := range versionSlice { @@ -991,7 +995,7 @@ func (in *infraService) KubeObj(request model.KubeObjectData, r store.StateData) return "", err } if reqChan, ok := r.KubeObjectData[request.RequestID]; ok { - var kubeObjData []*model.KubeObject + var kubeObjData *model.KubeObject err = json.Unmarshal([]byte(request.KubeObj), &kubeObjData) if err != nil { return "", fmt.Errorf("failed to unmarshal kubeObj data %w", err) @@ -1008,6 +1012,31 @@ func (in *infraService) KubeObj(request model.KubeObjectData, r store.StateData) return "KubeData sent successfully", nil } +// KubeNamespace receives Kubernetes Namespace data from subscriber +func (in *infraService) KubeNamespace(request model.KubeNamespaceData, r store.StateData) (string, error) { + _, err := in.VerifyInfra(*request.InfraID) + if err != nil { + log.Print("Error", err) + return "", err + } + if reqChan, ok := r.KubeNamespaceData[request.RequestID]; ok { + var kubeNamespaceData []*model.KubeNamespace + err = json.Unmarshal([]byte(request.KubeNamespace), &kubeNamespaceData) + if err != nil { + return "", fmt.Errorf("failed to unmarshal kubeNamespace data %w", err) + } + + resp := model.KubeNamespaceResponse{ + InfraID: request.InfraID.InfraID, + KubeNamespace: kubeNamespaceData, + } + reqChan <- &resp + close(reqChan) + return "KubeData sent successfully", nil + } + return "KubeData sent successfully", nil +} + // SendInfraEvent sends events from the infras to the appropriate users listening for the events func (in *infraService) SendInfraEvent(eventType, eventName, description string, infra model.Infra, r store.StateData) { newEvent := model.InfraEventResponse{ @@ -1077,8 +1106,8 @@ func (in *infraService) VerifyInfra(identity model.InfraIdentity) (*dbChaosInfra } else { splitCPVersion := strings.Split(currentVersion, ".") splitSubVersion := strings.Split(identity.Version, ".") - if len(splitSubVersion) != 3 || splitSubVersion[0] != splitCPVersion[0] || splitSubVersion[1] != splitCPVersion[1] { - return nil, fmt.Errorf("ERROR: infra VERSION MISMATCH (need %v.%v.x got %v)", splitCPVersion[0], splitCPVersion[1], identity.Version) + if len(splitSubVersion) != 3 || splitSubVersion[0] != splitCPVersion[0] { + return nil, fmt.Errorf("ERROR: infra VERSION MISMATCH (need %v.x.x got %v)", splitCPVersion[0], identity.Version) } } infra, err := in.infraOperator.GetInfra(identity.InfraID) diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/types.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/types.go index 8a3d8ead071..64c90cc5328 100644 --- a/chaoscenter/graphql/server/pkg/chaos_infrastructure/types.go +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/types.go @@ -11,6 +11,10 @@ type KubeObjData struct { Data []ObjectData `json:"data"` } +type KubeNamespace struct { + Name string `json:"Name"` +} + type ObjectData struct { Name string `json:"name"` UID types.UID `json:"uid"` diff --git a/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_fuzz_test.go b/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_fuzz_test.go new file mode 100644 index 00000000000..5a83fe5c04b --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_fuzz_test.go @@ -0,0 +1,291 @@ +package handler + +import ( + "archive/zip" + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + "github.com/google/uuid" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" +) + +func FuzzGetChartsPath(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzzConsumer := fuzz.NewConsumer(data) + + chartsInput := model.CloningInput{} + err := fuzzConsumer.GenerateStruct(&chartsInput) + if err != nil { + return + } + projectID, _ := fuzzConsumer.GetString() + isDefault, _ := fuzzConsumer.GetBool() + + result := GetChartsPath(chartsInput, projectID, isDefault) + + if isDefault { + expected := DefaultPath + "default/" + chartsInput.Name + "/faults/" + if result != expected { + t.Errorf("Expected %s, got %s", expected, result) + } + } else { + expected := DefaultPath + projectID + "/" + chartsInput.Name + "/faults/" + if result != expected { + t.Errorf("Expected %s, got %s", expected, result) + } + } + }) +} + +func FuzzReadExperimentFile(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte, filename string) { + fuzzConsumer := fuzz.NewConsumer(data) + + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.yaml" + } + filePath := filepath.Join(tmpDir, safeFilename) + content := ChaosChart{} + err = fuzzConsumer.GenerateStruct(&content) + if err != nil { + return + } + + jsonContent, _ := json.Marshal(content) + err = os.WriteFile(filePath, jsonContent, 0644) + if err != nil { + t.Fatal(err) + } + + _, err = ReadExperimentFile(filePath) + + if err != nil && !isInvalidYAML(jsonContent) { + t.Errorf("UnExpected error for valid YAML, got error: %v", err) + } + if err == nil && isInvalidYAML(jsonContent) { + t.Errorf("Expected error for invalid YAML, got nil") + } + + _, err = ReadExperimentFile("./not_exist_file.yaml") + if err == nil { + t.Errorf("Expected error for file does not exist, got nil") + } + }) +} + +func FuzzGetExperimentData(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte, filename string) { + fuzzConsumer := fuzz.NewConsumer(data) + + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.yaml" + } + filePath := filepath.Join(tmpDir, safeFilename) + content := ChaosChart{} + err = fuzzConsumer.GenerateStruct(&content) + if err != nil { + return + } + + jsonContent, _ := json.Marshal(content) + err = os.WriteFile(filePath, jsonContent, 0644) + if err != nil { + t.Fatal(err) + } + + _, err = GetExperimentData(filePath) + + if err != nil && !isInvalidYAML(jsonContent) && json.Valid(jsonContent) { + t.Errorf("UnExpected error for valid YAML, got error: %v", err) + } + if err == nil && isInvalidYAML(jsonContent) { + t.Errorf("Expected error for invalid YAML, got nil") + } + + _, err = ReadExperimentFile("./not_exist_file.yaml") + if err == nil { + t.Errorf("Expected error for file does not exist, got nil") + } + }) +} + +func FuzzReadExperimentYAMLFile(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte, filename string) { + fuzzConsumer := fuzz.NewConsumer(data) + + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.yaml" + } + filePath := filepath.Join(tmpDir, safeFilename) + content := ChaosChart{} + err = fuzzConsumer.GenerateStruct(&content) + if err != nil { + return + } + + jsonContent, _ := json.Marshal(content) + err = os.WriteFile(filePath, jsonContent, 0644) + if err != nil { + t.Fatal(err) + } + + _, err = ReadExperimentYAMLFile(filePath) + + if err != nil { + t.Errorf("UnExpected error for valid YAML, got error: %v", err) + } + + _, err = ReadExperimentFile("./not_exist_file.yaml") + if err == nil { + t.Errorf("Expected error for file does not exist, got nil") + } + }) +} + +func FuzzUnzipRemoteHub(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte, filename string, projectID string) { + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.zip" + } + if !strings.HasSuffix(safeFilename, ".zip") { + safeFilename += ".zip" + } + if isInvalidFilename(projectID) { + projectID = uuid.New().String() + } + + filePath := filepath.Join(tmpDir, safeFilename) + // Create a valid zip file + err = createValidZipFile(filePath, data) + if err != nil { + t.Fatal(err) + } + + err = UnzipRemoteHub(filePath, projectID) + + if err != nil { + t.Errorf("UnExpected error for valid zip, got error: %v", err) + } + + // Test with non-existent file + err = UnzipRemoteHub("./not_exist_file.zip", projectID) + if err == nil { + t.Errorf("Expected error for file does not exist, got nil") + } + + // Test with non-zip file + nonZipPath := filepath.Join(tmpDir, "no_zip") + err = os.WriteFile(nonZipPath, []byte("not a zip file"), 0644) + if err != nil { + t.Fatal(err) + } + err = UnzipRemoteHub(nonZipPath, projectID) + if err == nil { + t.Errorf("Expected error for no zip, got nil") + } + }) +} + +func FuzzIsFileExisting(f *testing.F) { + f.Fuzz(func(t *testing.T, filename string) { + // Create a temporary directory + tmpDir, err := os.MkdirTemp("", "*-fuzztest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) // clean up + + // Ensure the filename is valid and unique + safeFilename := filepath.Clean(filepath.Base(filename)) + if isInvalidFilename(safeFilename) { + safeFilename = "test.yaml" + } + filePath := filepath.Join(tmpDir, safeFilename) + _, _ = os.Create(filePath) + + result, err := IsFileExisting(filePath) + if !result { + t.Errorf("Expected true for existing file, got false") + } + + result, err = IsFileExisting("./not_exist_file.yaml") + if result { + t.Errorf("Expected false for not existing file, got true") + } + }) +} + +func isInvalidFilename(filename string) bool { + return strings.IndexByte(filename, 0) != -1 || filename == "" || filename == "." || filename == ".." || filename == "/" || len(filename) > 255 +} + +func isInvalidYAML(data []byte) bool { + for _, b := range data { + if b < 32 || b == 127 { + return true + } + } + return false +} + +func createValidZipFile(filename string, data []byte) error { + zipFile, err := os.Create(filename) + if err != nil { + return err + } + defer zipFile.Close() + + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + f, err := zipWriter.Create("test.txt") + if err != nil { + return err + } + _, err = f.Write(data) + if err != nil { + return err + } + + return nil +} diff --git a/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_test.go b/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_test.go index ffcd2106ac3..1a30b1e012a 100644 --- a/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_test.go +++ b/chaoscenter/graphql/server/pkg/chaoshub/handler/handler_test.go @@ -72,11 +72,6 @@ func TestReadExperimentFile(t *testing.T) { filePath: "./temp1.yaml", isError: true, }, - { - name: "failure: file is not a yaml", - filePath: "./types.go", - isError: true, - }, } for _, tc := range testcases { // when diff --git a/chaoscenter/graphql/server/pkg/chaoshub/models_factory.go b/chaoscenter/graphql/server/pkg/chaoshub/models_factory.go index 0034aad025e..de8d3335a57 100644 --- a/chaoscenter/graphql/server/pkg/chaoshub/models_factory.go +++ b/chaoscenter/graphql/server/pkg/chaoshub/models_factory.go @@ -6,6 +6,7 @@ func NewCloningInputFrom(chaosHub model.CreateChaosHubRequest) model.CloningInpu return model.CloningInput{ RepoBranch: chaosHub.RepoBranch, RepoURL: chaosHub.RepoURL, + RemoteHub: chaosHub.RemoteHub, Name: chaosHub.Name, IsPrivate: chaosHub.IsPrivate, UserName: chaosHub.UserName, diff --git a/chaoscenter/graphql/server/pkg/chaoshub/ops/gitops.go b/chaoscenter/graphql/server/pkg/chaoshub/ops/gitops.go index 0f166030645..0a4950efef4 100644 --- a/chaoscenter/graphql/server/pkg/chaoshub/ops/gitops.go +++ b/chaoscenter/graphql/server/pkg/chaoshub/ops/gitops.go @@ -9,6 +9,7 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/protocol/packp/capability" "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/go-git/go-git/v5/plumbing/transport/ssh" @@ -276,6 +277,10 @@ func (c ChaosHubConfig) gitPullPrivateRepo() error { // generateAuthMethod creates AuthMethod for private repos func (c ChaosHubConfig) generateAuthMethod() (transport.AuthMethod, error) { + transport.UnsupportedCapabilities = []capability.Capability{ + capability.ThinPack, + } + var auth transport.AuthMethod if c.AuthType == model.AuthTypeToken { auth = &http.BasicAuth{ diff --git a/chaoscenter/graphql/server/pkg/chaoshub/service.go b/chaoscenter/graphql/server/pkg/chaoshub/service.go index 2c933363179..53f46cc975f 100644 --- a/chaoscenter/graphql/server/pkg/chaoshub/service.go +++ b/chaoscenter/graphql/server/pkg/chaoshub/service.go @@ -86,6 +86,7 @@ func (c *chaosHubService) AddChaosHub(ctx context.Context, chaosHub model.Create ProjectID: projectID, RepoURL: chaosHub.RepoURL, RepoBranch: chaosHub.RepoBranch, + RemoteHub: chaosHub.RemoteHub, ResourceDetails: mongodb.ResourceDetails{ Name: chaosHub.Name, Description: description, @@ -155,6 +156,7 @@ func (c *chaosHubService) AddRemoteChaosHub(ctx context.Context, chaosHub model. ProjectID: projectID, RepoURL: chaosHub.RepoURL, RepoBranch: "", + RemoteHub: chaosHub.RemoteHub, ResourceDetails: mongodb.ResourceDetails{ Name: chaosHub.Name, Description: description, @@ -226,6 +228,7 @@ func (c *chaosHubService) SaveChaosHub(ctx context.Context, chaosHub model.Creat ProjectID: projectID, RepoURL: chaosHub.RepoURL, RepoBranch: chaosHub.RepoBranch, + RemoteHub: chaosHub.RemoteHub, ResourceDetails: mongodb.ResourceDetails{ Name: chaosHub.Name, Description: description, @@ -273,6 +276,7 @@ func (c *chaosHubService) SyncChaosHub(ctx context.Context, hubID string, projec Name: chaosHub.Name, RepoURL: chaosHub.RepoURL, RepoBranch: chaosHub.RepoBranch, + RemoteHub: chaosHub.RemoteHub, IsPrivate: chaosHub.IsPrivate, UserName: chaosHub.UserName, Password: chaosHub.Password, @@ -311,6 +315,7 @@ func (c *chaosHubService) UpdateChaosHub(ctx context.Context, chaosHub model.Upd cloneHub := model.CloningInput{ RepoBranch: chaosHub.RepoBranch, RepoURL: chaosHub.RepoURL, + RemoteHub: chaosHub.RemoteHub, Name: chaosHub.Name, IsPrivate: chaosHub.IsPrivate, UserName: chaosHub.UserName, @@ -326,10 +331,11 @@ func (c *chaosHubService) UpdateChaosHub(ctx context.Context, chaosHub model.Upd } clonePath := DefaultPath + prevChaosHub.ProjectID + "/" + prevChaosHub.Name if prevChaosHub.HubType == string(model.HubTypeRemote) { - if prevChaosHub.Name != chaosHub.Name || prevChaosHub.RepoURL != chaosHub.RepoURL { + if prevChaosHub.Name != chaosHub.Name || prevChaosHub.RepoURL != chaosHub.RepoURL || prevChaosHub.RemoteHub != chaosHub.RemoteHub { remoteHub := model.CreateRemoteChaosHub{ - Name: chaosHub.Name, - RepoURL: chaosHub.RepoURL, + Name: chaosHub.Name, + RepoURL: chaosHub.RepoURL, + RemoteHub: chaosHub.RemoteHub, } err = os.RemoveAll(clonePath) if err != nil { @@ -342,7 +348,7 @@ func (c *chaosHubService) UpdateChaosHub(ctx context.Context, chaosHub model.Upd } } else { // Syncing/Cloning the repository at a path from ChaosHub link structure. - if prevChaosHub.Name != chaosHub.Name || prevChaosHub.RepoURL != chaosHub.RepoURL || prevChaosHub.RepoBranch != chaosHub.RepoBranch || prevChaosHub.IsPrivate != chaosHub.IsPrivate || prevChaosHub.AuthType != chaosHub.AuthType.String() { + if prevChaosHub.Name != chaosHub.Name || prevChaosHub.RepoURL != chaosHub.RepoURL || prevChaosHub.RepoBranch != chaosHub.RepoBranch || prevChaosHub.IsPrivate != chaosHub.IsPrivate || prevChaosHub.AuthType != chaosHub.AuthType.String() || prevChaosHub.RemoteHub != chaosHub.RemoteHub { err = os.RemoveAll(clonePath) if err != nil { return nil, err @@ -368,6 +374,7 @@ func (c *chaosHubService) UpdateChaosHub(ctx context.Context, chaosHub model.Upd {"$set", bson.D{ {"repo_url", chaosHub.RepoURL}, {"repo_branch", chaosHub.RepoBranch}, + {"remote_hub", chaosHub.RemoteHub}, {"name", chaosHub.Name}, {"description", chaosHub.Description}, {"tags", chaosHub.Tags}, @@ -454,6 +461,7 @@ func (c *chaosHubService) ListChaosFaults(ctx context.Context, hubID string, pro Name: hub.Name, RepoURL: hub.RepoURL, RepoBranch: hub.RepoBranch, + RemoteHub: hub.RemoteHub, } ChartsPath := handler.GetChartsPath(chartsInput, projectID, hub.IsDefault) @@ -516,6 +524,7 @@ func (c *chaosHubService) ListChaosHubs(ctx context.Context, projectID string, r }, RepoURL: defaultHub.RepoURL, RepoBranch: defaultHub.RepoBranch, + RemoteHub: defaultHub.RemoteHub, IsDefault: true, } @@ -651,6 +660,7 @@ func (c *chaosHubService) ListChaosHubs(ctx context.Context, projectID string, r UpdatedAt: strconv.Itoa(int(hub.UpdatedAt)), CreatedBy: &model.UserDetails{Username: hub.CreatedBy.Username}, UpdatedBy: &model.UserDetails{Username: hub.UpdatedBy.Username}, + RemoteHub: hub.RemoteHub, } hubDetails = append(hubDetails, hubDetail) } @@ -711,6 +721,7 @@ func (c *chaosHubService) GetChaosHub(ctx context.Context, chaosHubID string, pr UpdatedAt: strconv.Itoa(int(hub.UpdatedAt)), CreatedBy: &model.UserDetails{Username: hub.CreatedBy.Username}, UpdatedBy: &model.UserDetails{Username: hub.UpdatedBy.Username}, + RemoteHub: hub.RemoteHub, } return hubDetail, nil @@ -762,6 +773,7 @@ func (c *chaosHubService) getChaosHubDetails(ctx context.Context, hubID string, ProjectID: hub.ProjectID, RepoURL: hub.RepoURL, RepoBranch: hub.RepoBranch, + RemoteHub: hub.RemoteHub, AuthType: model.AuthType(hub.AuthType), Name: hub.Name, CreatedAt: strconv.Itoa(int(hub.CreatedAt)), @@ -879,6 +891,7 @@ func (c *chaosHubService) RecurringHubSync() { Name: chaosHub.Name, RepoURL: chaosHub.RepoURL, RepoBranch: chaosHub.RepoBranch, + RemoteHub: chaosHub.RemoteHub, IsPrivate: chaosHub.IsPrivate, AuthType: chaosHub.AuthType, Token: chaosHub.Token, diff --git a/chaoscenter/graphql/server/pkg/data-store/store.go b/chaoscenter/graphql/server/pkg/data-store/store.go index f101298ebe9..41336b021f7 100644 --- a/chaoscenter/graphql/server/pkg/data-store/store.go +++ b/chaoscenter/graphql/server/pkg/data-store/store.go @@ -13,6 +13,7 @@ type StateData struct { ExperimentEventPublish map[string][]chan *model.ExperimentRun ExperimentLog map[string]chan *model.PodLogResponse KubeObjectData map[string]chan *model.KubeObjectResponse + KubeNamespaceData map[string]chan *model.KubeNamespaceResponse Mutex *sync.Mutex } @@ -23,6 +24,7 @@ func NewStore() *StateData { ExperimentEventPublish: make(map[string][]chan *model.ExperimentRun), ExperimentLog: make(map[string]chan *model.PodLogResponse), KubeObjectData: make(map[string]chan *model.KubeObjectResponse), + KubeNamespaceData: make(map[string]chan *model.KubeNamespaceResponse), Mutex: &sync.Mutex{}, } } diff --git a/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub/schema.go b/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub/schema.go index 7e8205f1192..ed387474dcd 100644 --- a/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub/schema.go +++ b/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub/schema.go @@ -15,6 +15,7 @@ type ChaosHub struct { mongodb.Audit `bson:",inline"` RepoURL string `bson:"repo_url"` RepoBranch string `bson:"repo_branch"` + RemoteHub string `bson:"remote_hub"` IsPrivate bool `bson:"is_private"` AuthType string `bson:"auth_type"` HubType string `bson:"hub_type"` @@ -34,6 +35,7 @@ func (c *ChaosHub) GetOutputChaosHub() *model.ChaosHub { ProjectID: c.ProjectID, RepoURL: c.RepoURL, RepoBranch: c.RepoBranch, + RemoteHub: c.RemoteHub, Name: c.Name, Description: &c.Description, Tags: c.Tags, diff --git a/chaoscenter/graphql/server/server.go b/chaoscenter/graphql/server/server.go index e53ad36fdae..7aff0ddcf5e 100644 --- a/chaoscenter/graphql/server/server.go +++ b/chaoscenter/graphql/server/server.go @@ -1,46 +1,39 @@ package main import ( - "regexp" - "strconv" - - "google.golang.org/grpc/credentials" - - "github.com/gin-gonic/gin" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/api/middleware" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaoshub" - handler2 "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaoshub/handler" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" - dbSchemaChaosHub "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/projects" - "github.com/prometheus/client_golang/prometheus/promhttp" - "context" "fmt" "net" "net/http" + "regexp" "runtime" + "strconv" "time" - "github.com/kelseyhightower/envconfig" - - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/authorization" - - "github.com/99designs/gqlgen/graphql/handler/extension" - - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" - "github.com/99designs/gqlgen/graphql/handler" + "github.com/99designs/gqlgen/graphql/handler/extension" "github.com/99designs/gqlgen/graphql/handler/transport" + "github.com/gin-gonic/gin" "github.com/gorilla/websocket" + "github.com/kelseyhightower/envconfig" + log "github.com/sirupsen/logrus" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/api/middleware" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/generated" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/authorization" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaoshub" + handler2 "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/chaoshub/handler" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb" + dbSchemaChaosHub "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/chaos_hub" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/config" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/handlers" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/projects" + "github.com/prometheus/client_golang/prometheus/promhttp" pb "github.com/litmuschaos/litmus/chaoscenter/graphql/server/protos" - "github.com/sirupsen/logrus" - log "github.com/sirupsen/logrus" - "google.golang.org/grpc" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" ) func init() { @@ -53,7 +46,6 @@ func init() { if err != nil { log.Fatal(err) } - } func validateVersion() error { @@ -108,15 +100,14 @@ func main() { enableHTTPSConnection, err := strconv.ParseBool(utils.Config.EnableInternalTls) if err != nil { - logrus.Errorf("unable to parse boolean value %v", err) + log.Errorf("unable to parse boolean value %v", err) } if enableHTTPSConnection { - if utils.Config.TlsCertPath != "" && utils.Config.TlsKeyPath != "" { - go startGRPCServerWithTLS(mongodbOperator) // start GRPC serve - } else { + if utils.Config.TlsCertPath == "" || utils.Config.TlsKeyPath == "" { log.Fatalf("Failure to start chaoscenter authentication REST server due to empty TLS cert file path and TLS key path") } + go startGRPCServerWithTLS(mongodbOperator) // start GRPC serve } else { go startGRPCServer(utils.Config.GrpcPort, mongodbOperator) // start GRPC serve } @@ -146,7 +137,8 @@ func main() { enableIntrospection, err := strconv.ParseBool(utils.Config.EnableGQLIntrospection) if err != nil { log.Errorf("unable to parse boolean value %v", err) - } else if err == nil && enableIntrospection == true { + } + if enableIntrospection { srv.Use(extension.Introspection{}) } @@ -172,28 +164,26 @@ func main() { go projects.ProjectEvents(projectEventChannel, mongodb.MgoClient, mongodbOperator) if enableHTTPSConnection { - if utils.Config.TlsCertPath != "" && utils.Config.TlsKeyPath != "" { - log.Infof("graphql server running at https://localhost:%s", utils.Config.RestPort) - // configuring TLS config based on provided certificates & keys - conf := utils.GetTlsConfig(utils.Config.TlsCertPath, utils.Config.TlsKeyPath, true) - - server := http.Server{ - Addr: ":" + utils.Config.RestPort, - Handler: router, - TLSConfig: conf, - } - err := server.ListenAndServeTLS("", "") - if err != nil { - log.Fatalf("Failure to start litmus-portal graphql REST server due to %v", err) - } - } else { + if utils.Config.TlsCertPath == "" || utils.Config.TlsKeyPath == "" { log.Fatalf("Failure to start chaoscenter authentication GRPC server due to empty TLS cert file path and TLS key path") } + + log.Infof("graphql server running at https://localhost:%s", utils.Config.RestPort) + // configuring TLS config based on provided certificates & keys + conf := utils.GetTlsConfig(utils.Config.TlsCertPath, utils.Config.TlsKeyPath, true) + + server := http.Server{ + Addr: ":" + utils.Config.RestPort, + Handler: router, + TLSConfig: conf, + } + if err := server.ListenAndServeTLS("", ""); err != nil { + log.Fatalf("Failure to start litmus-portal graphql REST server due to %v", err) + } } else { log.Infof("graphql server running at http://localhost:%s", utils.Config.RestPort) log.Fatal(http.ListenAndServe(":"+utils.Config.RestPort, router)) } - } // startGRPCServer initializes, registers services to and starts the gRPC server for RPC calls diff --git a/chaoscenter/subscriber/pkg/k8s/defination.go b/chaoscenter/subscriber/pkg/k8s/defination.go index 68b2a24883f..2adac87f32c 100644 --- a/chaoscenter/subscriber/pkg/k8s/defination.go +++ b/chaoscenter/subscriber/pkg/k8s/defination.go @@ -18,10 +18,13 @@ type SubscriberK8s interface { CreatePodLog(podLog types.PodLogRequest) (types.PodLog, error) SendPodLogs(infraData map[string]string, podLog types.PodLogRequest) GenerateLogPayload(cid, accessKey, version string, podLog types.PodLogRequest) ([]byte, error) - GetKubernetesObjects(request types.KubeObjRequest) ([]*types.KubeObject, error) + GetKubernetesNamespaces(request types.KubeNamespaceRequest) ([]*types.KubeNamespace, error) + GetKubernetesObjects(request types.KubeObjRequest) (*types.KubeObject, error) GetObjectDataByNamespace(namespace string, dynamicClient dynamic.Interface, resourceType schema.GroupVersionResource) ([]types.ObjectData, error) GenerateKubeObject(cid string, accessKey, version string, kubeobjectrequest types.KubeObjRequest) ([]byte, error) + GenerateKubeNamespace(cid string, accessKey, version string, kubenamespacerequest types.KubeNamespaceRequest) ([]byte, error) SendKubeObjects(infraData map[string]string, kubeobjectrequest types.KubeObjRequest) error + SendKubeNamespaces(infraData map[string]string, kubenamespacerequest types.KubeNamespaceRequest) error CheckComponentStatus(componentEnv string) error IsAgentConfirmed() (bool, string, error) AgentRegister(accessKey string) (bool, error) diff --git a/chaoscenter/subscriber/pkg/k8s/objects.go b/chaoscenter/subscriber/pkg/k8s/objects.go index 143ea9f3785..d23bd51466f 100644 --- a/chaoscenter/subscriber/pkg/k8s/objects.go +++ b/chaoscenter/subscriber/pkg/k8s/objects.go @@ -23,63 +23,72 @@ var ( InfraScope = os.Getenv("INFRA_SCOPE") ) -// GetKubernetesObjects is used to get the Kubernetes Object details according to the request type -func (k8s *k8sSubscriber) GetKubernetesObjects(request types.KubeObjRequest) ([]*types.KubeObject, error) { - conf, err := k8s.GetKubeConfig() - if err != nil { - return nil, err - } - clientset, err := kubernetes.NewForConfig(conf) - if err != nil { - return nil, err - } +// GetKubernetesNamespaces is used to get the list of Kubernetes Namespaces +func (k8s *k8sSubscriber) GetKubernetesNamespaces(request types.KubeNamespaceRequest) ([]*types.KubeNamespace, error) { - resourceType := schema.GroupVersionResource{ - Group: request.KubeGVRRequest.Group, - Version: request.KubeGVRRequest.Version, - Resource: request.KubeGVRRequest.Resource, - } - _, dynamicClient, err := k8s.GetDynamicAndDiscoveryClient() - if err != nil { - return nil, err - } - var ObjData []*types.KubeObject + var namespaceData []*types.KubeNamespace if strings.ToLower(InfraScope) == "namespace" { - dataList, err := k8s.GetObjectDataByNamespace(InfraNamespace, dynamicClient, resourceType) + // In case of namespace scope, only one namespace is available + KubeNamespace := &types.KubeNamespace{ + Name: InfraNamespace, + } + namespaceData = append(namespaceData, KubeNamespace) + } else { + // In case of cluster scope, get all the namespaces + conf, err := k8s.GetKubeConfig() if err != nil { return nil, err } - KubeObj := &types.KubeObject{ - Namespace: InfraNamespace, - Data: dataList, + clientset, err := kubernetes.NewForConfig(conf) + if err != nil { + return nil, err } - ObjData = append(ObjData, KubeObj) - } else { + namespace, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) if err != nil { return nil, err } - if len(namespace.Items) > 0 { for _, namespace := range namespace.Items { - podList, err := k8s.GetObjectDataByNamespace(namespace.GetName(), dynamicClient, resourceType) - if err != nil { - return nil, err - } - KubeObj := &types.KubeObject{ - Namespace: namespace.GetName(), - Data: podList, + + KubeNamespace := &types.KubeNamespace{ + Name: namespace.GetName(), } - ObjData = append(ObjData, KubeObj) + + namespaceData = append(namespaceData, KubeNamespace) } } else { return nil, errors.New("No namespace available") } + } + //TODO Maybe add marshal/unmarshal here + return namespaceData, nil +} +// GetKubernetesObjects is used to get the Kubernetes Object details according to the request type +func (k8s *k8sSubscriber) GetKubernetesObjects(request types.KubeObjRequest) (*types.KubeObject, error) { + resourceType := schema.GroupVersionResource{ + Group: request.KubeGVRRequest.Group, + Version: request.KubeGVRRequest.Version, + Resource: request.KubeGVRRequest.Resource, } - kubeData, _ := json.Marshal(ObjData) - var kubeObjects []*types.KubeObject + _, dynamicClient, err := k8s.GetDynamicAndDiscoveryClient() + if err != nil { + return nil, err + } + + dataList, err := k8s.GetObjectDataByNamespace(request.Namespace, dynamicClient, resourceType) + if err != nil { + return nil, err + } + KubeObj := &types.KubeObject{ + Namespace: InfraNamespace, + Data: dataList, + } + + kubeData, _ := json.Marshal(KubeObj) + var kubeObjects *types.KubeObject err = json.Unmarshal(kubeData, &kubeObjects) if err != nil { return nil, err @@ -118,6 +127,22 @@ func (k8s *k8sSubscriber) updateLabels(labels map[string]string) []string { return updatedLabels } +func (k8s *k8sSubscriber) GenerateKubeNamespace(cid string, accessKey, version string, kubenamespacerequest types.KubeNamespaceRequest) ([]byte, error) { + infraID := `{infraID: \"` + cid + `\", version: \"` + version + `\", accessKey: \"` + accessKey + `\"}` + kubeObj, err := k8s.GetKubernetesNamespaces(kubenamespacerequest) + if err != nil { + return nil, err + } + processed, err := k8s.gqlSubscriberServer.MarshalGQLData(kubeObj) + if err != nil { + return nil, err + } + mutation := `{ infraID: ` + infraID + `, requestID:\"` + kubenamespacerequest.RequestID + `\", kubeNamespace:\"` + processed[1:len(processed)-1] + `\"}` + + var payload = []byte(`{"query":"mutation { kubeNamespace(request:` + mutation + ` )}"}`) + return payload, nil +} + func (k8s *k8sSubscriber) GenerateKubeObject(cid string, accessKey, version string, kubeobjectrequest types.KubeObjRequest) ([]byte, error) { infraID := `{infraID: \"` + cid + `\", version: \"` + version + `\", accessKey: \"` + accessKey + `\"}` kubeObj, err := k8s.GetKubernetesObjects(kubeobjectrequest) @@ -134,6 +159,25 @@ func (k8s *k8sSubscriber) GenerateKubeObject(cid string, accessKey, version stri return payload, nil } +// SendKubeNamespace generates graphql mutation to send kubernetes namespaces data to graphql server +func (k8s *k8sSubscriber) SendKubeNamespaces(infraData map[string]string, kubenamespacerequest types.KubeNamespaceRequest) error { + // generate graphql payload + payload, err := k8s.GenerateKubeNamespace(infraData["INFRA_ID"], infraData["ACCESS_KEY"], infraData["VERSION"], kubenamespacerequest) + if err != nil { + logrus.WithError(err).Print("Error while getting KubeObject Data") + return err + } + + body, err := k8s.gqlSubscriberServer.SendRequest(infraData["SERVER_ADDR"], payload) + if err != nil { + logrus.Print(err.Error()) + return err + } + + logrus.Println("Response", body) + return nil +} + // SendKubeObjects generates graphql mutation to send kubernetes objects data to graphql server func (k8s *k8sSubscriber) SendKubeObjects(infraData map[string]string, kubeobjectrequest types.KubeObjRequest) error { // generate graphql payload diff --git a/chaoscenter/subscriber/pkg/requests/webhook.go b/chaoscenter/subscriber/pkg/requests/webhook.go index e0ee2f0e900..cafea2d921a 100644 --- a/chaoscenter/subscriber/pkg/requests/webhook.go +++ b/chaoscenter/subscriber/pkg/requests/webhook.go @@ -69,7 +69,7 @@ func (req *subscriberRequests) AgentConnect(infraData map[string]string) { for { _, message, err := c.ReadMessage() if err != nil { - logrus.WithError(err).Fatal("Failed to read message") + logrus.WithError(err).Panic("Failed to read message") } var r types.RawData @@ -87,6 +87,7 @@ func (req *subscriberRequests) AgentConnect(infraData map[string]string) { } if r.Payload.Errors != nil { logrus.Error("Error response from the server : ", string(message)) + panicWhen("ALREADY CONNECTED", message) continue } @@ -97,6 +98,12 @@ func (req *subscriberRequests) AgentConnect(infraData map[string]string) { } } +func panicWhen(errorMessage string, message []byte) { + if strings.Contains(string(message), errorMessage) { + logrus.Panic("Server error: ", errorMessage) + } +} + func (req *subscriberRequests) RequestProcessor(infraData map[string]string, r types.RawData) error { if strings.Index("kubeobject kubeobjects", strings.ToLower(r.Payload.Data.InfraConnect.Action.RequestType)) >= 0 { KubeObjRequest := types.KubeObjRequest{ @@ -113,6 +120,21 @@ func (req *subscriberRequests) RequestProcessor(infraData map[string]string, r t return errors.New("error getting kubernetes object data: " + err.Error()) } } + if strings.Index("kubenamespace kubenamespaces", strings.ToLower(r.Payload.Data.InfraConnect.Action.RequestType)) >= 0 { + KubeNamespaceRequest := types.KubeNamespaceRequest{ + RequestID: r.Payload.Data.InfraConnect.Action.RequestID, + } + + err := json.Unmarshal([]byte(r.Payload.Data.InfraConnect.Action.ExternalData), &KubeNamespaceRequest) + if err != nil { + return errors.New("failed to json unmarshal: " + err.Error()) + } + + err = req.subscriberK8s.SendKubeNamespaces(infraData, KubeNamespaceRequest) + if err != nil { + return errors.New("error getting kubernetes namespace data: " + err.Error()) + } + } if strings.ToLower(r.Payload.Data.InfraConnect.Action.RequestType) == "logs" { podRequest := types.PodLogRequest{ RequestID: r.Payload.Data.InfraConnect.Action.RequestID, diff --git a/chaoscenter/subscriber/pkg/types/kubeobject.go b/chaoscenter/subscriber/pkg/types/kubeobject.go index e862cc0b875..baa917a76e5 100644 --- a/chaoscenter/subscriber/pkg/types/kubeobject.go +++ b/chaoscenter/subscriber/pkg/types/kubeobject.go @@ -14,6 +14,7 @@ type KubeObject struct { type KubeObjRequest struct { RequestID string InfraID string `json:"infraID"` + Namespace string `json:"namespace"` ObjectType string `json:"objectType"` KubeGVRRequest KubeGVRRequest `json:"kubeObjRequest"` } @@ -24,6 +25,16 @@ type KubeGVRRequest struct { Resource string `json:"resource"` } +// Not really useful at the moment but we might need other fields in the future +type KubeNamespace struct { + Name string `json:"name"` +} + +type KubeNamespaceRequest struct { + RequestID string + InfraID string `json:"infraID"` +} + type ObjectData struct { Name string `json:"name"` UID types.UID `json:"uid"` diff --git a/chaoscenter/web/Dockerfile b/chaoscenter/web/Dockerfile index 3c4c117f211..616d4e608a3 100644 --- a/chaoscenter/web/Dockerfile +++ b/chaoscenter/web/Dockerfile @@ -1,4 +1,4 @@ -FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8 +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.10 RUN microdnf module enable nginx:1.20 RUN microdnf install nginx RUN microdnf update --refresh --best --noplugins --setopt=install_weak_deps=0 diff --git a/chaoscenter/web/src/api/core/infrastructures/getKubeObject.ts b/chaoscenter/web/src/api/core/infrastructures/getKubeObject.ts index b3129ae1dff..54deef519fc 100644 --- a/chaoscenter/web/src/api/core/infrastructures/getKubeObject.ts +++ b/chaoscenter/web/src/api/core/infrastructures/getKubeObject.ts @@ -12,13 +12,14 @@ export interface KubeObjRequest { infraID: string; objectType: string; kubeObjRequest?: KubeGVRRequest; + namespace: string; }; } export interface KubeObjResponse { getKubeObject: { infraID: string; - kubeObj: Array; + kubeObj: KubeObj; }; } @@ -32,13 +33,30 @@ interface KubeObjData { name: string; } -export function kubeObjectSubscription({ +interface KubeNamespace { + name: string; +} + +export interface KubeNamespaceRequest { + request: { + infraID: string; + }; +} + +export interface KubeNamespaceResponse { + getKubeNamespace: { + infraID: string; + kubeNamespace: Array; + }; +} + +export const kubeObjectSubscription = ({ request, ...options }: GqlAPISubscriptionRequest): GqlAPISubscriptionResponse< KubeObjResponse, KubeObjRequest -> { +> => { const { data, loading, error } = useSubscription( gql` subscription getKubeObject($request: KubeObjectRequest!) { @@ -59,6 +77,7 @@ export function kubeObjectSubscription({ request: { infraID: request.infraID, kubeObjRequest: request.kubeObjRequest, + namespace: request.namespace, objectType: request.objectType } }, @@ -67,4 +86,35 @@ export function kubeObjectSubscription({ ); return { data, loading, error }; -} +}; + +export const kubeNamespaceSubscription = ({ + request, + ...options +}: GqlAPISubscriptionRequest): GqlAPISubscriptionResponse< + KubeNamespaceResponse, + KubeNamespaceRequest +> => { + const { data, loading, error } = useSubscription( + gql` + subscription getKubeNamespace($request: KubeNamespaceRequest!) { + getKubeNamespace(request: $request) { + infraID + kubeNamespace { + name + } + } + } + `, + { + variables: { + request: { + infraID: request.infraID + } + }, + ...options + } + ); + + return { data, loading, error }; +}; diff --git a/chaoscenter/web/src/api/entities/environment.ts b/chaoscenter/web/src/api/entities/environment.ts index 7341b84f50e..86fd89b41cf 100644 --- a/chaoscenter/web/src/api/entities/environment.ts +++ b/chaoscenter/web/src/api/entities/environment.ts @@ -23,3 +23,9 @@ export interface EnvironmentSortInput { field: SortType; ascending: boolean; } + +export interface EnvironmentDetail { + envName: string; + envID: string; + totalInfra?: number | null; +} diff --git a/chaoscenter/web/src/components/ProjectDashboardCardContainer/ProjectDashboardCardContainer.tsx b/chaoscenter/web/src/components/ProjectDashboardCardContainer/ProjectDashboardCardContainer.tsx index 1851b869388..4975608b2e6 100644 --- a/chaoscenter/web/src/components/ProjectDashboardCardContainer/ProjectDashboardCardContainer.tsx +++ b/chaoscenter/web/src/components/ProjectDashboardCardContainer/ProjectDashboardCardContainer.tsx @@ -10,7 +10,6 @@ import { useStrings } from '@strings'; import ProjectDashboardCardMenuController from '@controllers/ProjectDashboardCardMenu'; import { setUserDetails, toSentenceCase } from '@utils'; import { useAppStore } from '@context'; -import { useRouteWithBaseUrl } from '@hooks'; import css from './ProjectDashboardCardContainer.module.scss'; interface ProjectDashboardCardProps { @@ -25,16 +24,16 @@ export default function ProjectDashboardCardContainer(props: ProjectDashboardCar const [projectIdToDelete, setProjectIdToDelete] = useState(); const { getString } = useStrings(); const history = useHistory(); - const { updateAppStore } = useAppStore(); - - const paths = useRouteWithBaseUrl(); + const { updateAppStore, currentUserInfo } = useAppStore(); const handleProjectSelect = (project: Project): void => { + const projectRole = project.members?.find(member => member.userID === currentUserInfo?.ID)?.role; updateAppStore({ projectID: project.projectID, projectName: project.name }); setUserDetails({ + projectRole, projectID: project.projectID }); - history.push(paths.toRoot()); + history.replace(`/`); }; return ( diff --git a/chaoscenter/web/src/constants/validation.ts b/chaoscenter/web/src/constants/validation.ts index 39d68029c28..a03d51e26f5 100644 --- a/chaoscenter/web/src/constants/validation.ts +++ b/chaoscenter/web/src/constants/validation.ts @@ -6,7 +6,7 @@ export const USERNAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_-]{2,15}$/; // ^(?=.*[a-z]) # At least one lowercase letter // (?=.*[A-Z]) # At least one uppercase letter // (?=.*\d) # At least one digit -// (?=.*[@$!%*?_&]) # At least one special character @$!%*?_& -// [A-Za-z\d@$!%*?_&] # Allowed characters: letters, digits, special characters @$!%*?_& +// (?=.*[@$!%*?_&#]) # At least one special character @$!%*?_&# +// [A-Za-z\d@$!%*?_&#] # Allowed characters: letters, digits, special characters @$!%*?_&# // {8,16}$ # Length between 8 to 16 characters -export const PASSWORD_REGEX = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?_&])[A-Za-z\d@$!%*?_&]{8,16}$/; +export const PASSWORD_REGEX = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?_&#])[A-Za-z\d@$!%*?_&#]{8,16}$/; diff --git a/chaoscenter/web/src/controllers/Environments/Environment.tsx b/chaoscenter/web/src/controllers/Environments/Environment.tsx index 2abb02dfd08..3303ec29d48 100644 --- a/chaoscenter/web/src/controllers/Environments/Environment.tsx +++ b/chaoscenter/web/src/controllers/Environments/Environment.tsx @@ -64,8 +64,9 @@ const EnvironmentController: React.FC = () => { itemCount: totalEnvironments ?? 0, pageCount: totalEnvironments ? Math.ceil(totalEnvironments / limit) : 1, pageIndex: page, - pageSizeOptions: [...new Set([15, 30, limit])].sort(), + pageSizeOptions: [...new Set([5, 10, 15, 30, limit])].sort(), pageSize: limit, + showPagination: true, onPageSizeChange: event => setLimit(event) } }; diff --git a/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureReferenceField/KubernetesChaosInfrastructureReferenceField.tsx b/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureReferenceField/KubernetesChaosInfrastructureReferenceField.tsx index f7fe8c48d04..e4702f2d01f 100644 --- a/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureReferenceField/KubernetesChaosInfrastructureReferenceField.tsx +++ b/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureReferenceField/KubernetesChaosInfrastructureReferenceField.tsx @@ -3,31 +3,55 @@ import React from 'react'; import { listChaosInfra } from '@api/core'; import { getScope } from '@utils'; import ChaosInfrastructureReferenceFieldView from '@views/ChaosInfrastructureReferenceField'; -import type { ChaosInfrastructureReferenceFieldProps } from '@models'; +import { AllEnv, type ChaosInfrastructureReferenceFieldProps } from '@models'; import type { InfrastructureDetails } from '@views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField'; +import { listEnvironment } from '@api/core/environments'; function KubernetesChaosInfrastructureReferenceFieldController({ setFieldValue, - initialInfrastructureID + initialInfrastructureID, + initialEnvironmentID }: ChaosInfrastructureReferenceFieldProps): React.ReactElement { const scope = getScope(); const { showError } = useToaster(); const [searchInfrastructure, setSearchInfrastructure] = React.useState(''); - const [page, setPage] = React.useState(0); - const limit = 8; + const [limit, setLimit] = React.useState(5); + const [envID, setEnvID] = React.useState(AllEnv.AllEnv); + const [initialAllInfrastructureLength, setInitialAllInfrastructureLength] = React.useState(0); const { data: listChaosInfraData, loading: listChaosInfraLoading } = listChaosInfra({ ...scope, - filter: { name: searchInfrastructure, isActive: true }, + environmentIDs: envID === AllEnv.AllEnv ? undefined : [envID], + filter: { name: searchInfrastructure }, pagination: { page, limit }, options: { onError: error => showError(error.message) } }); + const { data: listEnvironmentData } = listEnvironment({ + ...scope, + options: { + onError: err => showError(err.message) + } + }); + + const environmentList = listEnvironmentData?.listEnvironments?.environments; + + React.useEffect(() => { + if (envID === AllEnv.AllEnv) { + setInitialAllInfrastructureLength(listChaosInfraData?.listInfras.totalNoOfInfras || 0); + } + }, [listChaosInfraData]); + + const preSelectedEnvironment = listEnvironmentData?.listEnvironments?.environments?.find( + ({ environmentID }) => environmentID === initialEnvironmentID + ); + // TODO: replace with get API as this becomes empty during edit const preSelectedInfrastructure = listChaosInfraData?.listInfras.infras.find( ({ infraID }) => infraID === initialInfrastructureID ); + const preSelectedInfrastructureDetails: InfrastructureDetails | undefined = preSelectedInfrastructure && { id: preSelectedInfrastructure?.infraID, name: preSelectedInfrastructure?.name, @@ -38,6 +62,16 @@ function KubernetesChaosInfrastructureReferenceFieldController({ environmentID: preSelectedInfrastructure?.environmentID }; + React.useEffect(() => { + setPage(0); + }, [envID]); + + React.useEffect(() => { + if (preSelectedEnvironment) { + setEnvID(preSelectedEnvironment?.environmentID); + } + }, [preSelectedEnvironment, setFieldValue]); + React.useEffect(() => { if (preSelectedInfrastructure) { setFieldValue('chaosInfrastructure.id', preSelectedInfrastructure.infraID, true); @@ -69,7 +103,10 @@ function KubernetesChaosInfrastructureReferenceFieldController({ pageSize={limit} pageCount={Math.ceil(totalNoOfInfras / limit)} pageIndex={page} - gotoPage={pageNumber => setPage(pageNumber)} + gotoPage={setPage} + showPagination={true} + pageSizeOptions={[5, 10, 15]} + onPageSizeChange={setLimit} /> ); }; @@ -87,6 +124,10 @@ function KubernetesChaosInfrastructureReferenceFieldController({ }} searchInfrastructure={searchInfrastructure} setSearchInfrastructure={setSearchInfrastructure} + allInfrastructureLength={initialAllInfrastructureLength} + environmentList={environmentList} + envID={envID} + setEnvID={setEnvID} loading={{ listChaosInfra: listChaosInfraLoading }} diff --git a/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureUpgrade/KubernetesChaosInfrastructureUpgrade.tsx b/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureUpgrade/KubernetesChaosInfrastructureUpgrade.tsx index 310f47cd602..6c3dad53c68 100644 --- a/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureUpgrade/KubernetesChaosInfrastructureUpgrade.tsx +++ b/chaoscenter/web/src/controllers/KubernetesChaosInfrastructureUpgrade/KubernetesChaosInfrastructureUpgrade.tsx @@ -22,7 +22,7 @@ export default function KubernetesChaosInfrastructureUpgradeController({ ...scope, options: { skip: !isUpgradeAvailable, - onError: err => showError(err) + onError: err => showError(err.message) } }); diff --git a/chaoscenter/web/src/controllers/TargetApplicationTab/TargetApplicationTab.tsx b/chaoscenter/web/src/controllers/TargetApplicationTab/TargetApplicationTab.tsx index bf7089b2add..059482d2e3b 100644 --- a/chaoscenter/web/src/controllers/TargetApplicationTab/TargetApplicationTab.tsx +++ b/chaoscenter/web/src/controllers/TargetApplicationTab/TargetApplicationTab.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { KubeGVRRequest, kubeObjectSubscription } from '@api/core'; +import { KubeGVRRequest, kubeObjectSubscription, kubeNamespaceSubscription } from '@api/core'; import type { ChaosEngine, FaultData } from '@models'; import { TargetApplicationTab } from '@views/ExperimentCreationFaultConfiguration/Tabs'; import type { AppInfoData, TargetApplicationData } from './types'; @@ -16,17 +16,26 @@ export default function TargetApplicationTabController({ infrastructureID, setFaultData }: TargetApplicationControllerProps): React.ReactElement { - const [appInfoData, setAppInfoData] = React.useState([]); + const [namespaceData, setNamespaceData] = React.useState([]); + const [appInfoData, setAppInfoData] = React.useState({ appLabel: [] }); const [targetApp, setTargetApp] = React.useState({ ...engineCR?.spec?.appinfo }); const [selectedGVR, setSelectedGVR] = React.useState(); - const { data: result, loading } = kubeObjectSubscription({ + const { data: resultNamespace, loading: loadingNamespace } = kubeNamespaceSubscription({ + request: { + infraID: infrastructureID ?? '' + }, + shouldResubscribe: true, + skip: targetApp?.appkind === undefined || selectedGVR === undefined + }); + const { data: resultObject, loading: loadingObject } = kubeObjectSubscription({ shouldResubscribe: true, - skip: targetApp?.appkind === undefined || selectedGVR === undefined, + skip: targetApp?.appns === undefined || targetApp?.appns === '', request: { infraID: infrastructureID ?? '', kubeObjRequest: selectedGVR, + namespace: targetApp?.appns ?? '', objectType: 'kubeobject' } }); @@ -37,51 +46,44 @@ export default function TargetApplicationTabController({ if (data.resource === targetApp?.appkind) { setSelectedGVR({ group: data.group, - version: data.version, - resource: `${data.resource}s` + resource: `${data.resource}s`, + version: data.version }); } }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [targetApp?.appkind]); - /** - * UseEffect to filter the labels according to the namespace provided - * Required to populate the appLabels dropdown - */ React.useEffect(() => { - if (result?.getKubeObject) { - const appInfo: AppInfoData[] = []; - const kubeData = result.getKubeObject.kubeObj; - kubeData.forEach(obj => { - const applabels: string[] = []; - obj.data.forEach(objData => { - if (objData.labels) { - applabels.push(...objData.labels.filter(() => obj.namespace === targetApp?.appns)); - } - }); - /** - * Push these labels corresponding to their namespaces - */ - appInfo.push({ - namespace: obj.namespace, - appLabel: applabels - }); - }); + if (resultNamespace?.getKubeNamespace) { + setNamespaceData(resultNamespace.getKubeNamespace.kubeNamespace.map(data => data.name)); + } + }, [resultNamespace?.getKubeNamespace, targetApp?.appkind]); + React.useEffect(() => { + if (resultObject?.getKubeObject) { + const applabels: string[] = []; + resultObject.getKubeObject.kubeObj.data.forEach(objData => { + if (objData.labels) { + applabels.push(...objData.labels); + } + }); + const appInfo: AppInfoData = { appLabel: applabels }; setAppInfoData(appInfo); } - }, [result?.getKubeObject, targetApp?.appns]); + }, [resultObject?.getKubeObject, targetApp?.appns]); return ( ); } diff --git a/chaoscenter/web/src/controllers/TargetApplicationTab/types.ts b/chaoscenter/web/src/controllers/TargetApplicationTab/types.ts index 85f3123fefc..3fd0c0819a8 100644 --- a/chaoscenter/web/src/controllers/TargetApplicationTab/types.ts +++ b/chaoscenter/web/src/controllers/TargetApplicationTab/types.ts @@ -4,7 +4,10 @@ export interface TargetApplicationData { applabel?: string; } +export interface NamespaceData { + namespace: string[]; +} + export interface AppInfoData { - namespace: string; appLabel: string[]; } diff --git a/chaoscenter/web/src/models/chaosInfrastructure.ts b/chaoscenter/web/src/models/chaosInfrastructure.ts index cc9d530c7aa..ab40a98aa76 100644 --- a/chaoscenter/web/src/models/chaosInfrastructure.ts +++ b/chaoscenter/web/src/models/chaosInfrastructure.ts @@ -31,6 +31,7 @@ export function getChaosInfrastructureStatus( export interface ChaosInfrastructureReferenceFieldProps { setFieldValue: FormikHelpers['setFieldValue']; initialInfrastructureID: string | undefined; + initialEnvironmentID: string | undefined; } export enum DeploymentScopeOptions { @@ -64,6 +65,10 @@ export interface InitialValueProps { tolerationValues?: Array; } +export enum AllEnv { + AllEnv = 'All' +} + export interface DeploymentScopeItem extends CollapsableSelectOptions { type: DeploymentScopeOptions; name: string; diff --git a/chaoscenter/web/src/strings/strings.en.yaml b/chaoscenter/web/src/strings/strings.en.yaml index bfe16f64f61..081e1458e7f 100644 --- a/chaoscenter/web/src/strings/strings.en.yaml +++ b/chaoscenter/web/src/strings/strings.en.yaml @@ -486,6 +486,7 @@ infrastructureRegistered: >- Environment -> Infrastructure list. infrastructureStates: Learn more about the states of Infrastructure infrastructureType: Infrastructure type +infrastructures: Infrastructures initialDelay: Initial Delay initialDelaySeconds: Initial Delay Seconds insecureSkipVerify: Insecure skip verify diff --git a/chaoscenter/web/src/strings/types.ts b/chaoscenter/web/src/strings/types.ts index 5d0470c5945..67b32c14278 100644 --- a/chaoscenter/web/src/strings/types.ts +++ b/chaoscenter/web/src/strings/types.ts @@ -409,6 +409,7 @@ export interface StringsMap { 'infrastructureRegistered': unknown 'infrastructureStates': unknown 'infrastructureType': unknown + 'infrastructures': unknown 'initialDelay': unknown 'initialDelaySeconds': unknown 'insecureSkipVerify': unknown diff --git a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss index e9ab159eed0..4e61d00ded7 100644 --- a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss +++ b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss @@ -2,7 +2,7 @@ padding: var(--spacing-xlarge) !important; &.dialog { - width: 833px; + width: 912px; height: 86vh; max-height: 989px; } @@ -60,14 +60,13 @@ background: #effbff; border: 1.5px solid #0278d5; box-shadow: 0px 0px 1px rgba(40, 41, 61, 0.04), 0px 2px 4px rgba(96, 97, 112, 0.16); - border-radius: 4px; + border-radius: 8px; } .notSelected { background: #fafbfc; - border: 1px solid rgba(40, 41, 61, 0.3); box-shadow: 0px 0px 1px rgba(40, 41, 61, 0.04), 0px 2px 4px rgba(96, 97, 112, 0.16); - border-radius: 4px; + border-radius: 8px; cursor: pointer; } @@ -78,14 +77,13 @@ .agentListInnerContainer { flex-grow: 1; - overflow: auto; gap: 1rem; - max-height: calc(100% - 48px); + overflow: auto; } .item { display: grid; - grid-template-columns: 5fr 4fr 25px; + grid-template-columns: 3fr 4fr 25px; align-items: center; gap: 0.5rem; @@ -95,7 +93,6 @@ } .iconCheck { - visibility: hidden; margin-right: var(--spacing-xsmall); margin-left: var(--spacing-xsmall); cursor: pointer; @@ -104,7 +101,15 @@ > svg { > path { stroke-width: 1; - stroke: var(--grey-500); + stroke: var(--grey-100); + } + } + } + .iconCheck:hover { + > svg { + > path { + stroke-width: 1; + stroke: var(--green-500); } } } @@ -134,7 +139,7 @@ .gitInfo { display: grid; grid-template-columns: 4fr 5fr; - padding: 6px 8px; + padding: 4px 8px; background: var(--grey-100) !important; border-radius: 8px !important; width: 100%; @@ -170,11 +175,6 @@ position: fixed; } -.gap-4 { - gap: 1rem; - overflow: auto; -} - .paginationContainer { padding-top: 8px; overflow: hidden; @@ -190,3 +190,37 @@ } } } + +.listEnvContainer { + background: var(--primary-1); + box-shadow: 0px 0px 1px rgba(40, 41, 61, 0.04), 0px 2px 4px rgba(96, 97, 112, 0.16); + border-radius: 8px; + cursor: pointer; +} + +.itemEnv { + width: 100%; + display: grid; + grid-template-columns: 1fr 25px; + align-items: center; + gap: 0.5rem; +} + +.activeEnv { + border: 1px solid var(--primary-7); +} + +.center { + display: flex; + flex-direction: column; + justify-content: center; + align-self: center; + + img { + width: 200px; + } +} + +.rounded { + border-radius: 999px; +} diff --git a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss.d.ts b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss.d.ts index db9d0abfa61..0f0a5adf7fa 100644 --- a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss.d.ts +++ b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.module.scss.d.ts @@ -1,24 +1,28 @@ declare namespace ChaosInfrastructureReferenceFieldModuleScssNamespace { export interface IChaosInfrastructureReferenceFieldModuleScss { + activeEnv: string; agentList: string; agentListInnerContainer: string; + center: string; container: string; dialog: string; editBtn: string; fixed: string; - gap4: string; gitBranchIcon: string; gitInfo: string; greenStatus: string; iconCheck: string; iconChecked: string; item: string; + itemEnv: string; leftInfo: string; + listEnvContainer: string; notSelected: string; paginationContainer: string; placeholder: string; redStatus: string; referenceSelect: string; + rounded: string; selected: string; status: string; } diff --git a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.tsx b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.tsx index 4b55ba44ecc..2a5efa9853b 100644 --- a/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.tsx +++ b/chaoscenter/web/src/views/ChaosInfrastructureReferenceField/ChaosInfrastructureReferenceField.tsx @@ -8,7 +8,8 @@ import { ExpandingSearchInput, Layout, Text, - useToaster + useToaster, + useToggleOpen } from '@harnessio/uicore'; import { Icon } from '@harnessio/icons'; import cx from 'classnames'; @@ -19,6 +20,7 @@ import FallbackBox from '@images/FallbackBox.svg'; import CustomTagsPopover from '@components/CustomTagsPopover'; import Loader from '@components/Loader'; import { useRouteWithBaseUrl } from '@hooks'; +import { Environment, EnvironmentDetail } from '@api/entities'; import css from './ChaosInfrastructureReferenceField.module.scss'; export interface InfrastructureDetails { @@ -34,10 +36,14 @@ export interface InfrastructureDetails { interface ChaosInfrastructureReferenceFieldViewProps { infrastructureList: InfrastructureDetails[] | undefined; + allInfrastructureLength: number | null; + environmentList: Environment[] | undefined; preSelectedInfrastructure?: InfrastructureDetails; setInfrastructureValue: (infrastructure: InfrastructureDetails | undefined) => void; searchInfrastructure: string; setSearchInfrastructure: React.Dispatch>; + setEnvID: (id: string) => void; + envID: string | undefined; loading: { listChaosInfra: boolean; }; @@ -46,32 +52,83 @@ interface ChaosInfrastructureReferenceFieldViewProps { function ChaosInfrastructureReferenceFieldView({ infrastructureList, + environmentList, + allInfrastructureLength, preSelectedInfrastructure, setInfrastructureValue, searchInfrastructure, setSearchInfrastructure, + envID, + setEnvID, loading, pagination }: ChaosInfrastructureReferenceFieldViewProps): JSX.Element { - const [isOpen, setOpen] = React.useState(false); const paths = useRouteWithBaseUrl(); const history = useHistory(); + const [selectedInfrastructure, setSelectedInfrastructure] = React.useState( preSelectedInfrastructure ); - // const searchParams = useSearchParams(); - // const infrastructureType = - // (searchParams.get('infrastructureType') as InfrastructureType | undefined) ?? InfrastructureType.KUBERNETES; + const { isOpen, open, close } = useToggleOpen(); + const { showError } = useToaster(); const { getString } = useStrings(); - const listItem = ({ infrastructure }: { infrastructure: InfrastructureDetails }): JSX.Element => { + const EnvListItem = ({ envDetail }: { envDetail: EnvironmentDetail }): JSX.Element => { + return ( + { + setEnvID(envDetail.envID); + }} + > +
+ + + {envDetail.envName} + + + + {envDetail.totalInfra ?? 0} + +
+
+ ); + }; + + const EnvironmentList = ({ env }: { env: Environment }): JSX.Element => { + return ( + + ); + }; + + const InfrastructureListItem = ({ infrastructure }: { infrastructure: InfrastructureDetails }): JSX.Element => { + const isSelected = + selectedInfrastructure?.id === infrastructure.id || preSelectedInfrastructure?.id === infrastructure.id; + return ( { infrastructure.isActive ? setSelectedInfrastructure(infrastructure) @@ -85,7 +142,6 @@ function ChaosInfrastructureReferenceFieldView({ size={12} name="pipeline-approval" /> - {/* */} {infrastructure.name} @@ -124,6 +180,26 @@ function ChaosInfrastructureReferenceFieldView({ ); }; + const NoInfraComponent = (): JSX.Element => { + return ( + + {getString('latestRun')} + + {searchInfrastructure === '' ? getString('newUserNoInfra.title') : getString('noFilteredActiveInfra')} + + {searchInfrastructure === '' && ( +