mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-06-06 00:13:36 +00:00
Compare commits
3 Commits
30.0-dev8
...
30.0-dev10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7893b4596d | ||
|
|
774f07fccd | ||
|
|
482e5c8b69 |
@@ -77,8 +77,8 @@ RUN go build -ldflags="-extldflags=-static -s -w \
|
|||||||
-X 'github.com/up9inc/mizu/agent/pkg/version.Ver=${VER}'" -o mizuagent .
|
-X 'github.com/up9inc/mizu/agent/pkg/version.Ver=${VER}'" -o mizuagent .
|
||||||
|
|
||||||
# Download Basenine executable, verify the sha1sum
|
# Download Basenine executable, verify the sha1sum
|
||||||
ADD https://github.com/up9inc/basenine/releases/download/v0.6.3/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH}
|
ADD https://github.com/up9inc/basenine/releases/download/v0.6.5/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH}
|
||||||
ADD https://github.com/up9inc/basenine/releases/download/v0.6.3/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256
|
ADD https://github.com/up9inc/basenine/releases/download/v0.6.5/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256
|
||||||
RUN shasum -a 256 -c basenine_linux_${GOARCH}.sha256
|
RUN shasum -a 256 -c basenine_linux_${GOARCH}.sha256
|
||||||
RUN chmod +x ./basenine_linux_${GOARCH}
|
RUN chmod +x ./basenine_linux_${GOARCH}
|
||||||
RUN mv ./basenine_linux_${GOARCH} ./basenine
|
RUN mv ./basenine_linux_${GOARCH} ./basenine
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ require (
|
|||||||
github.com/orcaman/concurrent-map v1.0.0
|
github.com/orcaman/concurrent-map v1.0.0
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20220315070758-3a76cfc4378e
|
github.com/up9inc/basenine/client/go v0.0.0-20220317230530-8472d80307f6
|
||||||
github.com/up9inc/mizu/shared v0.0.0
|
github.com/up9inc/mizu/shared v0.0.0
|
||||||
github.com/up9inc/mizu/tap v0.0.0
|
github.com/up9inc/mizu/tap v0.0.0
|
||||||
github.com/up9inc/mizu/tap/api v0.0.0
|
github.com/up9inc/mizu/tap/api v0.0.0
|
||||||
|
|||||||
@@ -655,8 +655,8 @@ github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn
|
|||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
||||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20220315070758-3a76cfc4378e h1:/9dFXqvRDHcwPQdIGHP6iz6M0iAWBPOxYf6C+Ntq5w0=
|
github.com/up9inc/basenine/client/go v0.0.0-20220317230530-8472d80307f6 h1:c0aVbLKYeFDAg246+NDgie2y484bsc20NaKLo8ODV3E=
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20220315070758-3a76cfc4378e/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
|
github.com/up9inc/basenine/client/go v0.0.0-20220317230530-8472d80307f6/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
github.com/wI2L/jsondiff v0.1.1 h1:r2TkoEet7E4JMO5+s1RCY2R0LrNPNHY6hbDeow2hRHw=
|
github.com/wI2L/jsondiff v0.1.1 h1:r2TkoEet7E4JMO5+s1RCY2R0LrNPNHY6hbDeow2hRHw=
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ var apiServerAddress = flag.String("api-server-address", "", "Address of mizu AP
|
|||||||
var namespace = flag.String("namespace", "", "Resolve IPs if they belong to resources in this namespace (default is all)")
|
var namespace = flag.String("namespace", "", "Resolve IPs if they belong to resources in this namespace (default is all)")
|
||||||
var harsReaderMode = flag.Bool("hars-read", false, "Run in hars-read mode")
|
var harsReaderMode = flag.Bool("hars-read", false, "Run in hars-read mode")
|
||||||
var harsDir = flag.String("hars-dir", "", "Directory to read hars from")
|
var harsDir = flag.String("hars-dir", "", "Directory to read hars from")
|
||||||
var startTime int64
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
socketConnectionRetries = 30
|
socketConnectionRetries = 30
|
||||||
@@ -110,7 +109,7 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
|
|||||||
|
|
||||||
app.Use(middlewares.CORSMiddleware()) // This has to be called after the static middleware, does not work if its called before
|
app.Use(middlewares.CORSMiddleware()) // This has to be called after the static middleware, does not work if its called before
|
||||||
|
|
||||||
api.WebSocketRoutes(app, &eventHandlers, startTime)
|
api.WebSocketRoutes(app, &eventHandlers)
|
||||||
|
|
||||||
if config.Config.OAS {
|
if config.Config.OAS {
|
||||||
routes.OASRoutes(app)
|
routes.OASRoutes(app)
|
||||||
@@ -124,6 +123,7 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
|
|||||||
routes.EntriesRoutes(app)
|
routes.EntriesRoutes(app)
|
||||||
routes.MetadataRoutes(app)
|
routes.MetadataRoutes(app)
|
||||||
routes.StatusRoutes(app)
|
routes.StatusRoutes(app)
|
||||||
|
routes.DbRoutes(app)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,6 @@ func runInApiServerMode(namespace string) *gin.Engine {
|
|||||||
logger.Log.Fatalf("Error loading config file %v", err)
|
logger.Log.Fatalf("Error loading config file %v", err)
|
||||||
}
|
}
|
||||||
app.ConfigureBasenineServer(shared.BasenineHost, shared.BaseninePort, config.Config.MaxDBSizeBytes, config.Config.LogLevel, config.Config.InsertionFilter)
|
app.ConfigureBasenineServer(shared.BasenineHost, shared.BaseninePort, config.Config.MaxDBSizeBytes, config.Config.LogLevel, config.Config.InsertionFilter)
|
||||||
startTime = time.Now().UnixNano() / int64(time.Millisecond)
|
|
||||||
api.StartResolving(namespace)
|
api.StartResolving(namespace)
|
||||||
|
|
||||||
enableExpFeatureIfNeeded()
|
enableExpFeatureIfNeeded()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/utils"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
@@ -59,13 +60,13 @@ func init() {
|
|||||||
connectedWebsockets = make(map[int]*SocketConnection)
|
connectedWebsockets = make(map[int]*SocketConnection)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WebSocketRoutes(app *gin.Engine, eventHandlers EventHandlers, startTime int64) {
|
func WebSocketRoutes(app *gin.Engine, eventHandlers EventHandlers) {
|
||||||
SocketGetBrowserHandler = func(c *gin.Context) {
|
SocketGetBrowserHandler = func(c *gin.Context) {
|
||||||
websocketHandler(c.Writer, c.Request, eventHandlers, false, startTime)
|
websocketHandler(c.Writer, c.Request, eventHandlers, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
SocketGetTapperHandler = func(c *gin.Context) {
|
SocketGetTapperHandler = func(c *gin.Context) {
|
||||||
websocketHandler(c.Writer, c.Request, eventHandlers, true, startTime)
|
websocketHandler(c.Writer, c.Request, eventHandlers, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.GET("/ws", func(c *gin.Context) {
|
app.GET("/ws", func(c *gin.Context) {
|
||||||
@@ -77,7 +78,7 @@ func WebSocketRoutes(app *gin.Engine, eventHandlers EventHandlers, startTime int
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers EventHandlers, isTapper bool, startTime int64) {
|
func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers EventHandlers, isTapper bool) {
|
||||||
ws, err := websocketUpgrader.Upgrade(w, r, nil)
|
ws, err := websocketUpgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Errorf("Failed to set websocket upgrade: %v", err)
|
logger.Log.Errorf("Failed to set websocket upgrade: %v", err)
|
||||||
@@ -99,7 +100,9 @@ func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers Even
|
|||||||
if !isTapper {
|
if !isTapper {
|
||||||
connection, err = basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
|
connection, err = basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
logger.Log.Errorf("Failed to establish a connection to Basenine: %v", err)
|
||||||
|
socketCleanup(socketId, connectedWebsockets[socketId])
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +118,7 @@ func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers Even
|
|||||||
|
|
||||||
eventHandlers.WebSocketConnect(socketId, isTapper)
|
eventHandlers.WebSocketConnect(socketId, isTapper)
|
||||||
|
|
||||||
startTimeBytes, _ := models.CreateWebsocketStartTimeMessage(startTime)
|
startTimeBytes, _ := models.CreateWebsocketStartTimeMessage(utils.StartTime)
|
||||||
|
|
||||||
if err = SendToSocket(socketId, startTimeBytes); err != nil {
|
if err = SendToSocket(socketId, startTimeBytes); err != nil {
|
||||||
logger.Log.Error(err)
|
logger.Log.Error(err)
|
||||||
@@ -137,7 +140,8 @@ func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers Even
|
|||||||
|
|
||||||
if !isTapper && !isQuerySet {
|
if !isTapper && !isQuerySet {
|
||||||
if err := json.Unmarshal(msg, ¶ms); err != nil {
|
if err := json.Unmarshal(msg, ¶ms); err != nil {
|
||||||
logger.Log.Errorf("Error: %v", socketId, err)
|
logger.Log.Errorf("Error unmarshalling parameters: %v", socketId, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
query := params.Query
|
query := params.Query
|
||||||
@@ -166,6 +170,10 @@ func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers Even
|
|||||||
|
|
||||||
var entry *tapApi.Entry
|
var entry *tapApi.Entry
|
||||||
err = json.Unmarshal(bytes, &entry)
|
err = json.Unmarshal(bytes, &entry)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Debugf("Error unmarshalling entry: %v", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
var message []byte
|
var message []byte
|
||||||
if params.EnableFullEntries {
|
if params.EnableFullEntries {
|
||||||
@@ -193,7 +201,8 @@ func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers Even
|
|||||||
var metadata *basenine.Metadata
|
var metadata *basenine.Metadata
|
||||||
err = json.Unmarshal(bytes, &metadata)
|
err = json.Unmarshal(bytes, &metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Debugf("Error recieving metadata: %v", err.Error())
|
logger.Log.Debugf("Error unmarshalling metadata: %v", err.Error())
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
metadataBytes, _ := models.CreateWebsocketQueryMetadataMessage(metadata)
|
metadataBytes, _ := models.CreateWebsocketQueryMetadataMessage(metadata)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/op/go-logging"
|
"github.com/op/go-logging"
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
"github.com/up9inc/mizu/agent/pkg/api"
|
"github.com/up9inc/mizu/agent/pkg/api"
|
||||||
"github.com/up9inc/mizu/agent/pkg/controllers"
|
"github.com/up9inc/mizu/agent/pkg/utils"
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
amqpExt "github.com/up9inc/mizu/tap/extensions/amqp"
|
amqpExt "github.com/up9inc/mizu/tap/extensions/amqp"
|
||||||
@@ -59,7 +59,6 @@ func LoadExtensions() {
|
|||||||
return Extensions[i].Protocol.Priority < Extensions[j].Protocol.Priority
|
return Extensions[i].Protocol.Priority < Extensions[j].Protocol.Priority
|
||||||
})
|
})
|
||||||
|
|
||||||
controllers.InitExtensionsMap(ExtensionsMap)
|
|
||||||
api.InitExtensionsMap(ExtensionsMap)
|
api.InitExtensionsMap(ExtensionsMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +91,8 @@ func ConfigureBasenineServer(host string, port string, dbSize int64, logLevel lo
|
|||||||
if err := basenine.InsertionFilter(host, port, insertionFilter); err != nil {
|
if err := basenine.InsertionFilter(host, port, insertionFilter); err != nil {
|
||||||
logger.Log.Errorf("Error while setting the insertion filter: %v", err)
|
logger.Log.Errorf("Error while setting the insertion filter: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.StartTime = time.Now().UnixNano() / int64(time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetEntryInputChannel() chan *tapApi.OutputChannelItem {
|
func GetEntryInputChannel() chan *tapApi.OutputChannelItem {
|
||||||
|
|||||||
28
agent/pkg/controllers/db_controller.go
Normal file
28
agent/pkg/controllers/db_controller.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/app"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/config"
|
||||||
|
"github.com/up9inc/mizu/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Flush(c *gin.Context) {
|
||||||
|
if err := basenine.Flush(shared.BasenineHost, shared.BaseninePort); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, err)
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, "Flushed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Reset(c *gin.Context) {
|
||||||
|
if err := basenine.Reset(shared.BasenineHost, shared.BaseninePort); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, err)
|
||||||
|
} else {
|
||||||
|
app.ConfigureBasenineServer(shared.BasenineHost, shared.BaseninePort, config.Config.MaxDBSizeBytes, config.Config.LogLevel, config.Config.InsertionFilter)
|
||||||
|
c.JSON(http.StatusOK, "Resetted.")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/app"
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
"github.com/up9inc/mizu/agent/pkg/har"
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
"github.com/up9inc/mizu/agent/pkg/validation"
|
"github.com/up9inc/mizu/agent/pkg/validation"
|
||||||
@@ -18,12 +19,6 @@ import (
|
|||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
var extensionsMap map[string]*tapApi.Extension // global
|
|
||||||
|
|
||||||
func InitExtensionsMap(ref map[string]*tapApi.Extension) {
|
|
||||||
extensionsMap = ref
|
|
||||||
}
|
|
||||||
|
|
||||||
func Error(c *gin.Context, err error) bool {
|
func Error(c *gin.Context, err error) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Errorf("Error getting entry: %v", err)
|
logger.Log.Errorf("Error getting entry: %v", err)
|
||||||
@@ -77,7 +72,7 @@ func GetEntries(c *gin.Context) {
|
|||||||
return // exit
|
return // exit
|
||||||
}
|
}
|
||||||
|
|
||||||
extension := extensionsMap[entry.Protocol.Name]
|
extension := app.ExtensionsMap[entry.Protocol.Name]
|
||||||
base := extension.Dissector.Summarize(entry)
|
base := extension.Dissector.Summarize(entry)
|
||||||
|
|
||||||
dataSlice = append(dataSlice, base)
|
dataSlice = append(dataSlice, base)
|
||||||
@@ -123,7 +118,7 @@ func GetEntry(c *gin.Context) {
|
|||||||
return // exit
|
return // exit
|
||||||
}
|
}
|
||||||
|
|
||||||
extension := extensionsMap[entry.Protocol.Name]
|
extension := app.ExtensionsMap[entry.Protocol.Name]
|
||||||
base := extension.Dissector.Summarize(entry)
|
base := extension.Dissector.Summarize(entry)
|
||||||
representation, bodySize, _ := extension.Dissector.Represent(entry.Request, entry.Response)
|
representation, bodySize, _ := extension.Dissector.Represent(entry.Request, entry.Response)
|
||||||
|
|
||||||
|
|||||||
15
agent/pkg/routes/db_routes.go
Normal file
15
agent/pkg/routes/db_routes.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/controllers"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DdRoutes defines the group of database routes.
|
||||||
|
func DbRoutes(app *gin.Engine) {
|
||||||
|
routeGroup := app.Group("/db")
|
||||||
|
|
||||||
|
routeGroup.GET("/flush", controllers.Flush)
|
||||||
|
routeGroup.GET("/reset", controllers.Reset)
|
||||||
|
}
|
||||||
@@ -17,6 +17,10 @@ import (
|
|||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
StartTime int64 // global
|
||||||
|
)
|
||||||
|
|
||||||
// StartServer starts the server with a graceful shutdown
|
// StartServer starts the server with a graceful shutdown
|
||||||
func StartServer(app *gin.Engine) {
|
func StartServer(app *gin.Engine) {
|
||||||
signals := make(chan os.Signal, 2)
|
signals := make(chan os.Signal, 2)
|
||||||
|
|||||||
@@ -27,4 +27,5 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkCmd.Flags().Bool(configStructs.PreTapCheckName, defaultCheckConfig.PreTap, "Check pre-tap Mizu installation for potential problems")
|
checkCmd.Flags().Bool(configStructs.PreTapCheckName, defaultCheckConfig.PreTap, "Check pre-tap Mizu installation for potential problems")
|
||||||
|
checkCmd.Flags().Bool(configStructs.ImagePullCheckName, defaultCheckConfig.ImagePull, "Test connectivity to container image registry by creating and removing a temporary pod in 'default' namespace")
|
||||||
}
|
}
|
||||||
|
|||||||
102
cli/cmd/check/imagePullInCluster.go
Normal file
102
cli/cmd/check/imagePullInCluster.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ImagePullInCluster(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
logger.Log.Infof("\nimage-pull-in-cluster\n--------------------")
|
||||||
|
|
||||||
|
namespace := "default"
|
||||||
|
podName := "mizu-test"
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := kubernetesProvider.RemovePod(ctx, namespace, podName); err != nil {
|
||||||
|
logger.Log.Errorf("%v error while removing test pod in cluster, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := createImagePullInClusterPod(ctx, kubernetesProvider, namespace, podName); err != nil {
|
||||||
|
logger.Log.Errorf("%v error while creating test pod in cluster, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkImagePulled(ctx, kubernetesProvider, namespace, podName); err != nil {
|
||||||
|
logger.Log.Errorf("%v cluster is not able to pull mizu containers from docker hub, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v cluster is able to pull mizu containers from docker hub", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkImagePulled(ctx context.Context, kubernetesProvider *kubernetes.Provider, namespace string, podName string) error {
|
||||||
|
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", podName))
|
||||||
|
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
|
||||||
|
eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{namespace}, podWatchHelper)
|
||||||
|
|
||||||
|
timeAfter := time.After(30 * time.Second)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case wEvent, ok := <-eventChan:
|
||||||
|
if !ok {
|
||||||
|
eventChan = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pod, err := wEvent.ToPod()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if pod.Status.Phase == core.PodRunning {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case err, ok := <-errorChan:
|
||||||
|
if !ok {
|
||||||
|
errorChan = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
case <-timeAfter:
|
||||||
|
return fmt.Errorf("image not pulled in time")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createImagePullInClusterPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, namespace string, podName string) error {
|
||||||
|
var zero int64
|
||||||
|
pod := &core.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: podName,
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{
|
||||||
|
{
|
||||||
|
Name: "probe",
|
||||||
|
Image: "up9inc/busybox",
|
||||||
|
ImagePullPolicy: "Always",
|
||||||
|
Command: []string{"cat"},
|
||||||
|
Stdin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TerminationGracePeriodSeconds: &zero,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := kubernetesProvider.CreatePod(ctx, namespace, pod); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
31
cli/cmd/check/kubernetesApi.go
Normal file
31
cli/cmd/check/kubernetesApi.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/config"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
"github.com/up9inc/mizu/shared/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func KubernetesApi() (*kubernetes.Provider, *semver.SemVersion, bool) {
|
||||||
|
logger.Log.Infof("\nkubernetes-api\n--------------------")
|
||||||
|
|
||||||
|
kubernetesProvider, err := kubernetes.NewProvider(config.Config.KubeConfigPath(), config.Config.KubeContext)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v can't initialize the client, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return nil, nil, false
|
||||||
|
}
|
||||||
|
logger.Log.Infof("%v can initialize the client", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
|
||||||
|
kubernetesVersion, err := kubernetesProvider.GetKubernetesVersion()
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v can't query the Kubernetes API, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return nil, nil, false
|
||||||
|
}
|
||||||
|
logger.Log.Infof("%v can query the Kubernetes API", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
|
||||||
|
return kubernetesProvider, kubernetesVersion, true
|
||||||
|
}
|
||||||
87
cli/cmd/check/kubernetesPermissions.go
Normal file
87
cli/cmd/check/kubernetesPermissions.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/config"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
rbac "k8s.io/api/rbac/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TapKubernetesPermissions(ctx context.Context, embedFS embed.FS, kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
logger.Log.Infof("\nkubernetes-permissions\n--------------------")
|
||||||
|
|
||||||
|
var filePath string
|
||||||
|
if config.Config.IsNsRestrictedMode() {
|
||||||
|
filePath = "permissionFiles/permissions-ns-tap.yaml"
|
||||||
|
} else {
|
||||||
|
filePath = "permissionFiles/permissions-all-namespaces-tap.yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := embedFS.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
obj, err := getDecodedObject(data)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var rules []rbac.PolicyRule
|
||||||
|
if config.Config.IsNsRestrictedMode() {
|
||||||
|
rules = obj.(*rbac.Role).Rules
|
||||||
|
} else {
|
||||||
|
rules = obj.(*rbac.ClusterRole).Rules
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkPermissions(ctx, kubernetesProvider, rules)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDecodedObject(data []byte) (runtime.Object, error) {
|
||||||
|
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||||
|
|
||||||
|
obj, _, err := decode(data, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider, rules []rbac.PolicyRule) bool {
|
||||||
|
permissionsExist := true
|
||||||
|
|
||||||
|
for _, rule := range rules {
|
||||||
|
for _, group := range rule.APIGroups {
|
||||||
|
for _, resource := range rule.Resources {
|
||||||
|
for _, verb := range rule.Verbs {
|
||||||
|
exist, err := kubernetesProvider.CanI(ctx, config.Config.MizuResourcesNamespace, resource, verb, group)
|
||||||
|
permissionsExist = checkPermissionExist(group, resource, verb, exist, err) && permissionsExist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissionsExist
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPermissionExist(group string, resource string, verb string, exist bool, err error) bool {
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error checking permission for %v %v in group '%v', err: %v", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, group, err)
|
||||||
|
return false
|
||||||
|
} else if !exist {
|
||||||
|
logger.Log.Errorf("%v can't %v %v in group '%v'", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, group)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v can %v %v in group '%v'", fmt.Sprintf(uiUtils.Green, "√"), verb, resource, group)
|
||||||
|
return true
|
||||||
|
}
|
||||||
95
cli/cmd/check/kubernetesResources.go
Normal file
95
cli/cmd/check/kubernetesResources.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/config"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func KubernetesResources(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
logger.Log.Infof("\nk8s-components\n--------------------")
|
||||||
|
|
||||||
|
exist, err := kubernetesProvider.DoesNamespaceExist(ctx, config.Config.MizuResourcesNamespace)
|
||||||
|
allResourcesExist := checkResourceExist(config.Config.MizuResourcesNamespace, "namespace", exist, err)
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesConfigMapExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ConfigMapName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ConfigMapName, "config map", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesServiceAccountExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ServiceAccountName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ServiceAccountName, "service account", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
if config.Config.IsNsRestrictedMode() {
|
||||||
|
exist, err = kubernetesProvider.DoesRoleExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.RoleName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.RoleName, "role", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesRoleBindingExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.RoleBindingName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.RoleBindingName, "role binding", exist, err) && allResourcesExist
|
||||||
|
} else {
|
||||||
|
exist, err = kubernetesProvider.DoesClusterRoleExist(ctx, kubernetes.ClusterRoleName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ClusterRoleName, "cluster role", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesClusterRoleBindingExist(ctx, kubernetes.ClusterRoleBindingName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ClusterRoleBindingName, "cluster role binding", exist, err) && allResourcesExist
|
||||||
|
}
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesServiceExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ApiServerPodName, "service", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
allResourcesExist = checkPodResourcesExist(ctx, kubernetesProvider) && allResourcesExist
|
||||||
|
|
||||||
|
return allResourcesExist
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPodResourcesExist(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName); err != nil {
|
||||||
|
logger.Log.Errorf("%v error checking if '%v' pod is running, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName, err)
|
||||||
|
return false
|
||||||
|
} else if len(pods) == 0 {
|
||||||
|
logger.Log.Errorf("%v '%v' pod doesn't exist", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName)
|
||||||
|
return false
|
||||||
|
} else if !kubernetes.IsPodRunning(&pods[0]) {
|
||||||
|
logger.Log.Errorf("%v '%v' pod not running", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v '%v' pod running", fmt.Sprintf(uiUtils.Green, "√"), kubernetes.ApiServerPodName)
|
||||||
|
|
||||||
|
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.MizuResourcesNamespace, kubernetes.TapperPodName); err != nil {
|
||||||
|
logger.Log.Errorf("%v error checking if '%v' pods are running, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.TapperPodName, err)
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
tappers := 0
|
||||||
|
notRunningTappers := 0
|
||||||
|
|
||||||
|
for _, pod := range pods {
|
||||||
|
tappers += 1
|
||||||
|
if !kubernetes.IsPodRunning(&pod) {
|
||||||
|
notRunningTappers += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if notRunningTappers > 0 {
|
||||||
|
logger.Log.Errorf("%v '%v' %v/%v pods are not running", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.TapperPodName, notRunningTappers, tappers)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v '%v' %v pods running", fmt.Sprintf(uiUtils.Green, "√"), kubernetes.TapperPodName, tappers)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkResourceExist(resourceName string, resourceType string, exist bool, err error) bool {
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error checking if '%v' %v exists, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), resourceName, resourceType, err)
|
||||||
|
return false
|
||||||
|
} else if !exist {
|
||||||
|
logger.Log.Errorf("%v '%v' %v doesn't exist", fmt.Sprintf(uiUtils.Red, "✗"), resourceName, resourceType)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v '%v' %v exists", fmt.Sprintf(uiUtils.Green, "√"), resourceName, resourceType)
|
||||||
|
return true
|
||||||
|
}
|
||||||
21
cli/cmd/check/kubernetesVersion.go
Normal file
21
cli/cmd/check/kubernetesVersion.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
"github.com/up9inc/mizu/shared/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func KubernetesVersion(kubernetesVersion *semver.SemVersion) bool {
|
||||||
|
logger.Log.Infof("\nkubernetes-version\n--------------------")
|
||||||
|
|
||||||
|
if err := kubernetes.ValidateKubernetesVersion(kubernetesVersion); err != nil {
|
||||||
|
logger.Log.Errorf("%v not running the minimum Kubernetes API version, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v is running the minimum Kubernetes API version", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
83
cli/cmd/check/serverConnection.go
Normal file
83
cli/cmd/check/serverConnection.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/apiserver"
|
||||||
|
"github.com/up9inc/mizu/cli/config"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ServerConnection(kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
logger.Log.Infof("\nAPI-server-connectivity\n--------------------")
|
||||||
|
|
||||||
|
serverUrl := fmt.Sprintf("http://%s", kubernetes.GetMizuApiServerProxiedHostAndPath(config.Config.Tap.GuiPort))
|
||||||
|
|
||||||
|
apiServerProvider := apiserver.NewProvider(serverUrl, 1, apiserver.DefaultTimeout)
|
||||||
|
if err := apiServerProvider.TestConnection(); err == nil {
|
||||||
|
logger.Log.Infof("%v found Mizu server tunnel available and connected successfully to API server", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedToApiServer := false
|
||||||
|
|
||||||
|
if err := checkProxy(serverUrl, kubernetesProvider); err != nil {
|
||||||
|
logger.Log.Errorf("%v couldn't connect to API server using proxy, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
} else {
|
||||||
|
connectedToApiServer = true
|
||||||
|
logger.Log.Infof("%v connected successfully to API server using proxy", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkPortForward(serverUrl, kubernetesProvider); err != nil {
|
||||||
|
logger.Log.Errorf("%v couldn't connect to API server using port-forward, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
} else {
|
||||||
|
connectedToApiServer = true
|
||||||
|
logger.Log.Infof("%v connected successfully to API server using port-forward", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return connectedToApiServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkProxy(serverUrl string, kubernetesProvider *kubernetes.Provider) error {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
httpServer, err := kubernetes.StartProxy(kubernetesProvider, config.Config.Tap.ProxyHost, config.Config.Tap.GuiPort, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName, cancel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
apiServerProvider := apiserver.NewProvider(serverUrl, apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
||||||
|
if err := apiServerProvider.TestConnection(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := httpServer.Shutdown(ctx); err != nil {
|
||||||
|
logger.Log.Debugf("Error occurred while stopping proxy, err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPortForward(serverUrl string, kubernetesProvider *kubernetes.Provider) error {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
podRegex, _ := regexp.Compile(kubernetes.ApiServerPodName)
|
||||||
|
forwarder, err := kubernetes.NewPortForward(kubernetesProvider, config.Config.MizuResourcesNamespace, podRegex, config.Config.Tap.GuiPort, ctx, cancel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
apiServerProvider := apiserver.NewProvider(serverUrl, apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
||||||
|
if err := apiServerProvider.TestConnection(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
forwarder.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -4,20 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
core "k8s.io/api/core/v1"
|
"github.com/up9inc/mizu/cli/cmd/check"
|
||||||
rbac "k8s.io/api/rbac/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
|
||||||
"regexp"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/cli/apiserver"
|
|
||||||
"github.com/up9inc/mizu/cli/config"
|
"github.com/up9inc/mizu/cli/config"
|
||||||
"github.com/up9inc/mizu/cli/uiUtils"
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
"github.com/up9inc/mizu/shared/kubernetes"
|
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
"github.com/up9inc/mizu/shared/semver"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -31,27 +21,29 @@ func runMizuCheck() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel() // cancel will be called when this function exits
|
defer cancel() // cancel will be called when this function exits
|
||||||
|
|
||||||
kubernetesProvider, kubernetesVersion, checkPassed := checkKubernetesApi()
|
kubernetesProvider, kubernetesVersion, checkPassed := check.KubernetesApi()
|
||||||
|
|
||||||
if checkPassed {
|
if checkPassed {
|
||||||
checkPassed = checkKubernetesVersion(kubernetesVersion)
|
checkPassed = check.KubernetesVersion(kubernetesVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Config.Check.PreTap {
|
if config.Config.Check.PreTap {
|
||||||
if checkPassed {
|
if checkPassed {
|
||||||
checkPassed = checkK8sTapPermissions(ctx, kubernetesProvider)
|
checkPassed = check.TapKubernetesPermissions(ctx, embedFS, kubernetesProvider)
|
||||||
}
|
|
||||||
|
|
||||||
if checkPassed {
|
|
||||||
checkPassed = checkImagePullInCluster(ctx, kubernetesProvider)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if checkPassed {
|
if checkPassed {
|
||||||
checkPassed = checkK8sResources(ctx, kubernetesProvider)
|
checkPassed = check.KubernetesResources(ctx, kubernetesProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkPassed {
|
if checkPassed {
|
||||||
checkPassed = checkServerConnection(kubernetesProvider)
|
checkPassed = check.ServerConnection(kubernetesProvider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Config.Check.ImagePull {
|
||||||
|
if checkPassed {
|
||||||
|
checkPassed = check.ImagePullInCluster(ctx, kubernetesProvider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,365 +53,3 @@ func runMizuCheck() {
|
|||||||
logger.Log.Errorf("\nStatus check results are %v", fmt.Sprintf(uiUtils.Red, "✗"))
|
logger.Log.Errorf("\nStatus check results are %v", fmt.Sprintf(uiUtils.Red, "✗"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkKubernetesApi() (*kubernetes.Provider, *semver.SemVersion, bool) {
|
|
||||||
logger.Log.Infof("\nkubernetes-api\n--------------------")
|
|
||||||
|
|
||||||
kubernetesProvider, err := kubernetes.NewProvider(config.Config.KubeConfigPath(), config.Config.KubeContext)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v can't initialize the client, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return nil, nil, false
|
|
||||||
}
|
|
||||||
logger.Log.Infof("%v can initialize the client", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
|
|
||||||
kubernetesVersion, err := kubernetesProvider.GetKubernetesVersion()
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v can't query the Kubernetes API, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return nil, nil, false
|
|
||||||
}
|
|
||||||
logger.Log.Infof("%v can query the Kubernetes API", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
|
|
||||||
return kubernetesProvider, kubernetesVersion, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkKubernetesVersion(kubernetesVersion *semver.SemVersion) bool {
|
|
||||||
logger.Log.Infof("\nkubernetes-version\n--------------------")
|
|
||||||
|
|
||||||
if err := kubernetes.ValidateKubernetesVersion(kubernetesVersion); err != nil {
|
|
||||||
logger.Log.Errorf("%v not running the minimum Kubernetes API version, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v is running the minimum Kubernetes API version", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkServerConnection(kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
logger.Log.Infof("\nAPI-server-connectivity\n--------------------")
|
|
||||||
|
|
||||||
serverUrl := GetApiServerUrl(config.Config.Tap.GuiPort)
|
|
||||||
|
|
||||||
apiServerProvider := apiserver.NewProvider(serverUrl, 1, apiserver.DefaultTimeout)
|
|
||||||
if err := apiServerProvider.TestConnection(); err == nil {
|
|
||||||
logger.Log.Infof("%v found Mizu server tunnel available and connected successfully to API server", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedToApiServer := false
|
|
||||||
|
|
||||||
if err := checkProxy(serverUrl, kubernetesProvider); err != nil {
|
|
||||||
logger.Log.Errorf("%v couldn't connect to API server using proxy, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
} else {
|
|
||||||
connectedToApiServer = true
|
|
||||||
logger.Log.Infof("%v connected successfully to API server using proxy", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := checkPortForward(serverUrl, kubernetesProvider); err != nil {
|
|
||||||
logger.Log.Errorf("%v couldn't connect to API server using port-forward, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
} else {
|
|
||||||
connectedToApiServer = true
|
|
||||||
logger.Log.Infof("%v connected successfully to API server using port-forward", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return connectedToApiServer
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkProxy(serverUrl string, kubernetesProvider *kubernetes.Provider) error {
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
httpServer, err := kubernetes.StartProxy(kubernetesProvider, config.Config.Tap.ProxyHost, config.Config.Tap.GuiPort, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName, cancel)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
apiServerProvider := apiserver.NewProvider(serverUrl, apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
|
||||||
if err := apiServerProvider.TestConnection(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := httpServer.Shutdown(ctx); err != nil {
|
|
||||||
logger.Log.Debugf("Error occurred while stopping proxy, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPortForward(serverUrl string, kubernetesProvider *kubernetes.Provider) error {
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
podRegex, _ := regexp.Compile(kubernetes.ApiServerPodName)
|
|
||||||
forwarder, err := kubernetes.NewPortForward(kubernetesProvider, config.Config.MizuResourcesNamespace, podRegex, config.Config.Tap.GuiPort, ctx, cancel)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
apiServerProvider := apiserver.NewProvider(serverUrl, apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
|
||||||
if err := apiServerProvider.TestConnection(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
forwarder.Close()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkK8sResources(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
logger.Log.Infof("\nk8s-components\n--------------------")
|
|
||||||
|
|
||||||
exist, err := kubernetesProvider.DoesNamespaceExist(ctx, config.Config.MizuResourcesNamespace)
|
|
||||||
allResourcesExist := checkResourceExist(config.Config.MizuResourcesNamespace, "namespace", exist, err)
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesConfigMapExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ConfigMapName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ConfigMapName, "config map", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesServiceAccountExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ServiceAccountName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ServiceAccountName, "service account", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
if config.Config.IsNsRestrictedMode() {
|
|
||||||
exist, err = kubernetesProvider.DoesRoleExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.RoleName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.RoleName, "role", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesRoleBindingExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.RoleBindingName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.RoleBindingName, "role binding", exist, err) && allResourcesExist
|
|
||||||
} else {
|
|
||||||
exist, err = kubernetesProvider.DoesClusterRoleExist(ctx, kubernetes.ClusterRoleName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ClusterRoleName, "cluster role", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesClusterRoleBindingExist(ctx, kubernetes.ClusterRoleBindingName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ClusterRoleBindingName, "cluster role binding", exist, err) && allResourcesExist
|
|
||||||
}
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesServiceExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ApiServerPodName, "service", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
allResourcesExist = checkPodResourcesExist(ctx, kubernetesProvider) && allResourcesExist
|
|
||||||
|
|
||||||
return allResourcesExist
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPodResourcesExist(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName); err != nil {
|
|
||||||
logger.Log.Errorf("%v error checking if '%v' pod is running, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName, err)
|
|
||||||
return false
|
|
||||||
} else if len(pods) == 0 {
|
|
||||||
logger.Log.Errorf("%v '%v' pod doesn't exist", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName)
|
|
||||||
return false
|
|
||||||
} else if !kubernetes.IsPodRunning(&pods[0]) {
|
|
||||||
logger.Log.Errorf("%v '%v' pod not running", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v '%v' pod running", fmt.Sprintf(uiUtils.Green, "√"), kubernetes.ApiServerPodName)
|
|
||||||
|
|
||||||
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.MizuResourcesNamespace, kubernetes.TapperPodName); err != nil {
|
|
||||||
logger.Log.Errorf("%v error checking if '%v' pods are running, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.TapperPodName, err)
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
tappers := 0
|
|
||||||
notRunningTappers := 0
|
|
||||||
|
|
||||||
for _, pod := range pods {
|
|
||||||
tappers += 1
|
|
||||||
if !kubernetes.IsPodRunning(&pod) {
|
|
||||||
notRunningTappers += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if notRunningTappers > 0 {
|
|
||||||
logger.Log.Errorf("%v '%v' %v/%v pods are not running", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.TapperPodName, notRunningTappers, tappers)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v '%v' %v pods running", fmt.Sprintf(uiUtils.Green, "√"), kubernetes.TapperPodName, tappers)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkResourceExist(resourceName string, resourceType string, exist bool, err error) bool {
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v error checking if '%v' %v exists, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), resourceName, resourceType, err)
|
|
||||||
return false
|
|
||||||
} else if !exist {
|
|
||||||
logger.Log.Errorf("%v '%v' %v doesn't exist", fmt.Sprintf(uiUtils.Red, "✗"), resourceName, resourceType)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v '%v' %v exists", fmt.Sprintf(uiUtils.Green, "√"), resourceName, resourceType)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkK8sTapPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
logger.Log.Infof("\nkubernetes-permissions\n--------------------")
|
|
||||||
|
|
||||||
var filePath string
|
|
||||||
if config.Config.IsNsRestrictedMode() {
|
|
||||||
filePath = "permissionFiles/permissions-ns-tap.yaml"
|
|
||||||
} else {
|
|
||||||
filePath = "permissionFiles/permissions-all-namespaces-tap.yaml"
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := embedFS.ReadFile(filePath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
obj, err := getDecodedObject(data)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var rules []rbac.PolicyRule
|
|
||||||
if config.Config.IsNsRestrictedMode() {
|
|
||||||
rules = obj.(*rbac.Role).Rules
|
|
||||||
} else {
|
|
||||||
rules = obj.(*rbac.ClusterRole).Rules
|
|
||||||
}
|
|
||||||
|
|
||||||
return checkPermissions(ctx, kubernetesProvider, rules)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDecodedObject(data []byte) (runtime.Object, error) {
|
|
||||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
|
||||||
|
|
||||||
obj, _, err := decode(data, nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider, rules []rbac.PolicyRule) bool {
|
|
||||||
permissionsExist := true
|
|
||||||
|
|
||||||
for _, rule := range rules {
|
|
||||||
for _, group := range rule.APIGroups {
|
|
||||||
for _, resource := range rule.Resources {
|
|
||||||
for _, verb := range rule.Verbs {
|
|
||||||
exist, err := kubernetesProvider.CanI(ctx, config.Config.MizuResourcesNamespace, resource, verb, group)
|
|
||||||
permissionsExist = checkPermissionExist(group, resource, verb, exist, err) && permissionsExist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return permissionsExist
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPermissionExist(group string, resource string, verb string, exist bool, err error) bool {
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v error checking permission for %v %v in group '%v', err: %v", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, group, err)
|
|
||||||
return false
|
|
||||||
} else if !exist {
|
|
||||||
logger.Log.Errorf("%v can't %v %v in group '%v'", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, group)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v can %v %v in group '%v'", fmt.Sprintf(uiUtils.Green, "√"), verb, resource, group)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkImagePullInCluster(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
logger.Log.Infof("\nimage-pull-in-cluster\n--------------------")
|
|
||||||
|
|
||||||
podName := "image-pull-in-cluster"
|
|
||||||
|
|
||||||
defer removeImagePullInClusterResources(ctx, kubernetesProvider, podName)
|
|
||||||
if err := createImagePullInClusterResources(ctx, kubernetesProvider, podName); err != nil {
|
|
||||||
logger.Log.Errorf("%v error while creating image pull in cluster resources, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := checkImagePulled(ctx, kubernetesProvider, podName); err != nil {
|
|
||||||
logger.Log.Errorf("%v cluster is not able to pull mizu containers from docker hub, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v cluster is able to pull mizu containers from docker hub", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkImagePulled(ctx context.Context, kubernetesProvider *kubernetes.Provider, podName string) error {
|
|
||||||
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", podName))
|
|
||||||
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
|
|
||||||
eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{config.Config.MizuResourcesNamespace}, podWatchHelper)
|
|
||||||
|
|
||||||
timeAfter := time.After(30 * time.Second)
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case wEvent, ok := <-eventChan:
|
|
||||||
if !ok {
|
|
||||||
eventChan = nil
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pod, err := wEvent.ToPod()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if pod.Status.Phase == core.PodRunning {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
case err, ok := <-errorChan:
|
|
||||||
if !ok {
|
|
||||||
errorChan = nil
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
case <-timeAfter:
|
|
||||||
return fmt.Errorf("image not pulled in time")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeImagePullInClusterResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, podName string) {
|
|
||||||
if err := kubernetesProvider.RemovePod(ctx, config.Config.MizuResourcesNamespace, podName); err != nil {
|
|
||||||
logger.Log.Debugf("error while removing image pull in cluster resources, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !config.Config.IsNsRestrictedMode() {
|
|
||||||
if err := kubernetesProvider.RemoveNamespace(ctx, config.Config.MizuResourcesNamespace); err != nil {
|
|
||||||
logger.Log.Debugf("error while removing image pull in cluster resources, err: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createImagePullInClusterResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, podName string) error {
|
|
||||||
if !config.Config.IsNsRestrictedMode() {
|
|
||||||
if _, err := kubernetesProvider.CreateNamespace(ctx, config.Config.MizuResourcesNamespace); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var zero int64
|
|
||||||
pod := &core.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: podName,
|
|
||||||
},
|
|
||||||
Spec: core.PodSpec{
|
|
||||||
Containers: []core.Container{
|
|
||||||
{
|
|
||||||
Name: "probe",
|
|
||||||
Image: "up9inc/busybox",
|
|
||||||
ImagePullPolicy: "Always",
|
|
||||||
Command: []string{"cat"},
|
|
||||||
Stdin: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TerminationGracePeriodSeconds: &zero,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := kubernetesProvider.CreatePod(ctx, config.Config.MizuResourcesNamespace, pod); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package configStructs
|
package configStructs
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PreTapCheckName = "pre-tap"
|
PreTapCheckName = "pre-tap"
|
||||||
|
ImagePullCheckName = "image-pull"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CheckConfig struct {
|
type CheckConfig struct {
|
||||||
PreTap bool `yaml:"pre-tap"`
|
PreTap bool `yaml:"pre-tap"`
|
||||||
|
ImagePull bool `yaml:"image-pull"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ require (
|
|||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
github.com/spf13/cobra v1.3.0
|
github.com/spf13/cobra v1.3.0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/up9inc/basenine/server/lib v0.0.0-20220315070758-3a76cfc4378e
|
github.com/up9inc/basenine/server/lib v0.0.0-20220317230530-8472d80307f6
|
||||||
github.com/up9inc/mizu/shared v0.0.0
|
github.com/up9inc/mizu/shared v0.0.0
|
||||||
github.com/up9inc/mizu/tap/api v0.0.0
|
github.com/up9inc/mizu/tap/api v0.0.0
|
||||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||||
|
|||||||
@@ -600,8 +600,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
|||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/up9inc/basenine/server/lib v0.0.0-20220315070758-3a76cfc4378e h1:reG/QwyxdfvGObfdrae7DZc3rTMiGwQ6S/4PRkwtBoE=
|
github.com/up9inc/basenine/server/lib v0.0.0-20220317230530-8472d80307f6 h1:+RZTD+HdfIW2SMbc65yWkruTY+g5/1Av074m62A74ls=
|
||||||
github.com/up9inc/basenine/server/lib v0.0.0-20220315070758-3a76cfc4378e/go.mod h1:ZIkxWiJm65jYQIso9k+OZKhR7gQ1we2jNyE2kQX9IQI=
|
github.com/up9inc/basenine/server/lib v0.0.0-20220317230530-8472d80307f6/go.mod h1:ZIkxWiJm65jYQIso9k+OZKhR7gQ1we2jNyE2kQX9IQI=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||||
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
|
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@up9/mizu-common",
|
"name": "@up9/mizu-common",
|
||||||
"version": "1.0.128",
|
"version": "1.0.129",
|
||||||
"description": "Made with create-react-library",
|
"description": "Made with create-react-library",
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -48,10 +48,13 @@ interface TrafficViewerProps {
|
|||||||
trafficViewerApiProp: TrafficViewerApi,
|
trafficViewerApiProp: TrafficViewerApi,
|
||||||
actionButtons?: JSX.Element,
|
actionButtons?: JSX.Element,
|
||||||
isShowStatusBar?: boolean,
|
isShowStatusBar?: boolean,
|
||||||
webSocketUrl : string
|
webSocketUrl : string,
|
||||||
|
isCloseWebSocket : boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus, trafficViewerApiProp, actionButtons,isShowStatusBar,webSocketUrl}) => {
|
export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus, trafficViewerApiProp,
|
||||||
|
actionButtons,isShowStatusBar,webSocketUrl,
|
||||||
|
isCloseWebSocket}) => {
|
||||||
|
|
||||||
const classes = useLayoutStyles();
|
const classes = useLayoutStyles();
|
||||||
|
|
||||||
@@ -103,6 +106,10 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
|
|||||||
handleQueryChange(query);
|
handleQueryChange(query);
|
||||||
}, [query, handleQueryChange]);
|
}, [query, handleQueryChange]);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
isCloseWebSocket && closeWebSocket()
|
||||||
|
},[isCloseWebSocket])
|
||||||
|
|
||||||
const ws = useRef(null);
|
const ws = useRef(null);
|
||||||
|
|
||||||
const listEntry = useRef(null);
|
const listEntry = useRef(null);
|
||||||
@@ -142,6 +149,10 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
|
|||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const closeWebSocket = () => {
|
||||||
|
ws.current && ws.current.close()
|
||||||
|
}
|
||||||
|
|
||||||
if (ws.current) {
|
if (ws.current) {
|
||||||
ws.current.onmessage = (e) => {
|
ws.current.onmessage = (e) => {
|
||||||
if (!e?.data) return;
|
if (!e?.data) return;
|
||||||
@@ -200,7 +211,7 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTrafficViewerApiState({...trafficViewerApiProp, webSocket : {close : () => ws.current.close()}});
|
setTrafficViewerApiState({...trafficViewerApiProp, webSocket : {close : closeWebSocket}});
|
||||||
(async () => {
|
(async () => {
|
||||||
openWebSocket("leftOff(-1)", true);
|
openWebSocket("leftOff(-1)", true);
|
||||||
try{
|
try{
|
||||||
@@ -330,10 +341,13 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MemoiedTrafficViewer = React.memo(TrafficViewer)
|
const MemoiedTrafficViewer = React.memo(TrafficViewer)
|
||||||
const TrafficViewerContainer: React.FC<TrafficViewerProps> = ({ setAnalyzeStatus, trafficViewerApiProp, actionButtons, isShowStatusBar = true ,webSocketUrl}) => {
|
const TrafficViewerContainer: React.FC<TrafficViewerProps> = ({ setAnalyzeStatus, trafficViewerApiProp,
|
||||||
|
actionButtons, isShowStatusBar = true ,
|
||||||
|
webSocketUrl, isCloseWebSocket}) => {
|
||||||
return <RecoilRoot>
|
return <RecoilRoot>
|
||||||
<MemoiedTrafficViewer actionButtons={actionButtons} isShowStatusBar={isShowStatusBar} webSocketUrl={webSocketUrl}
|
<MemoiedTrafficViewer actionButtons={actionButtons} isShowStatusBar={isShowStatusBar} webSocketUrl={webSocketUrl}
|
||||||
trafficViewerApiProp={trafficViewerApiProp} setAnalyzeStatus={setAnalyzeStatus} />
|
isCloseWebSocket={isCloseWebSocket} trafficViewerApiProp={trafficViewerApiProp}
|
||||||
|
setAnalyzeStatus={setAnalyzeStatus} />
|
||||||
</RecoilRoot>
|
</RecoilRoot>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
type TrafficViewerApi = {
|
type TrafficViewerApi = {
|
||||||
validateQuery : (query: any) => any
|
validateQuery: (query: any) => any
|
||||||
tapStatus : () => any
|
tapStatus: () => any
|
||||||
analyzeStatus : () => any
|
analyzeStatus: () => any
|
||||||
fetchEntries : (leftOff: any, direction: number, query: any, limit: number, timeoutMs: number) => any
|
fetchEntries: (leftOff: any, direction: number, query: any, limit: number, timeoutMs: number) => any
|
||||||
getEntry : (entryId : any, query:string) => any
|
getEntry: (entryId: any, query: string) => any
|
||||||
getRecentTLSLinks : () => any,
|
getRecentTLSLinks: () => any,
|
||||||
webSocket : {
|
webSocket: {
|
||||||
close : () => {}
|
close: () => void
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default TrafficViewerApi
|
export default TrafficViewerApi
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"@types/jest": "^26.0.22",
|
"@types/jest": "^26.0.22",
|
||||||
"@types/node": "^12.20.10",
|
"@types/node": "^12.20.10",
|
||||||
"@uiw/react-textarea-code-editor": "^1.4.12",
|
"@uiw/react-textarea-code-editor": "^1.4.12",
|
||||||
"@up9/mizu-common": "^1.0.128",
|
"@up9/mizu-common": "^1.0.129",
|
||||||
"axios": "^0.25.0",
|
"axios": "^0.25.0",
|
||||||
"core-js": "^3.20.2",
|
"core-js": "^3.20.2",
|
||||||
"craco-babel-loader": "^1.0.3",
|
"craco-babel-loader": "^1.0.3",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {useEffect} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import { Button } from "@material-ui/core";
|
import { Button } from "@material-ui/core";
|
||||||
import Api,{getWebsocketUrl} from "../../../helpers/api";
|
import Api,{getWebsocketUrl} from "../../../helpers/api";
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
@@ -8,8 +8,8 @@ import serviceMapModalOpenAtom from "../../../recoil/serviceMapModalOpen";
|
|||||||
import TrafficViewer from "@up9/mizu-common"
|
import TrafficViewer from "@up9/mizu-common"
|
||||||
import "@up9/mizu-common/dist/index.css"
|
import "@up9/mizu-common/dist/index.css"
|
||||||
import oasModalOpenAtom from "../../../recoil/oasModalOpen/atom";
|
import oasModalOpenAtom from "../../../recoil/oasModalOpen/atom";
|
||||||
import serviceMap from "../../assets/serviceMap.svg";
|
import serviceMap from "../../assets/serviceMap.svg";
|
||||||
import services from "../../assets/services.svg";
|
import services from "../../assets/services.svg";
|
||||||
|
|
||||||
interface TrafficPageProps {
|
interface TrafficPageProps {
|
||||||
setAnalyzeStatus?: (status: any) => void;
|
setAnalyzeStatus?: (status: any) => void;
|
||||||
@@ -21,38 +21,40 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
|||||||
const commonClasses = useCommonStyles();
|
const commonClasses = useCommonStyles();
|
||||||
const setServiceMapModalOpen = useSetRecoilState(serviceMapModalOpenAtom);
|
const setServiceMapModalOpen = useSetRecoilState(serviceMapModalOpenAtom);
|
||||||
const [openOasModal, setOpenOasModal] = useRecoilState(oasModalOpenAtom);
|
const [openOasModal, setOpenOasModal] = useRecoilState(oasModalOpenAtom);
|
||||||
|
const [openWebSocket, setOpenWebSocket] = useState(true);
|
||||||
|
|
||||||
const trafficViewerApi = {...api}
|
const trafficViewerApi = {...api}
|
||||||
|
|
||||||
const handleOpenOasModal = () => {
|
const handleOpenOasModal = () => {
|
||||||
//closeSocket() -- Todo: Add Close webSocket
|
setOpenWebSocket(false)
|
||||||
setOpenOasModal(true);
|
setOpenOasModal(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const openServiceMapModalDebounce = debounce(() => {
|
const openServiceMapModalDebounce = debounce(() => {
|
||||||
|
setOpenWebSocket(false)
|
||||||
setServiceMapModalOpen(true)
|
setServiceMapModalOpen(true)
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
const actionButtons = (window["isOasEnabled"] || window["isServiceMapEnabled"]) &&
|
const actionButtons = (window["isOasEnabled"] || window["isServiceMapEnabled"]) &&
|
||||||
<div style={{ display: 'flex', height: "100%" }}>
|
<div style={{ display: 'flex', height: "100%" }}>
|
||||||
{window["isOasEnabled"] && <Button
|
{window["isOasEnabled"] && <Button
|
||||||
startIcon={<img className="custom" src={services} alt="services"></img>}
|
startIcon={<img className="custom" src={services} alt="services"></img>}
|
||||||
size="large"
|
size="large"
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||||
style={{ marginRight: 25 }}
|
style={{ marginRight: 25 }}
|
||||||
onClick={handleOpenOasModal}>
|
onClick={handleOpenOasModal}>
|
||||||
Show OAS
|
Show OAS
|
||||||
</Button>}
|
</Button>}
|
||||||
{window["isServiceMapEnabled"] && <Button
|
{window["isServiceMapEnabled"] && <Button
|
||||||
startIcon={<img src={serviceMap} className="custom" alt="service-map" style={{marginRight:"8%"}}></img>}
|
startIcon={<img src={serviceMap} className="custom" alt="service-map" style={{marginRight:"8%"}}></img>}
|
||||||
size="large"
|
size="large"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||||
onClick={openServiceMapModalDebounce}>
|
onClick={openServiceMapModalDebounce}>
|
||||||
Service Map
|
Service Map
|
||||||
</Button>}
|
</Button>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -61,9 +63,9 @@ const trafficViewerApi = {...api}
|
|||||||
}
|
}
|
||||||
},[])
|
},[])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TrafficViewer setAnalyzeStatus={setAnalyzeStatus} webSocketUrl={getWebsocketUrl()}
|
<TrafficViewer setAnalyzeStatus={setAnalyzeStatus} webSocketUrl={getWebsocketUrl()} isCloseWebSocket={!openWebSocket}
|
||||||
trafficViewerApiProp={trafficViewerApi} actionButtons={actionButtons} isShowStatusBar={!openOasModal}/>
|
trafficViewerApiProp={trafficViewerApi} actionButtons={actionButtons} isShowStatusBar={!openOasModal}/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user