diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1dfe28e..9e7483d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,20 @@
# Changelog
+## [0.3.3](https://github.com/kurtosis-tech/kardinal/compare/0.3.2...0.3.3) (2024-10-02)
+
+
+### Features
+
+* add the `id` flag in the kardinal flow create cmd ([#261](https://github.com/kurtosis-tech/kardinal/issues/261)) ([09309f1](https://github.com/kurtosis-tech/kardinal/commit/09309f173e11c6d4d2b7b8a80f55df759fb98406))
+
+## [0.3.2](https://github.com/kurtosis-tech/kardinal/compare/0.3.1...0.3.2) (2024-09-28)
+
+
+### Bug Fixes
+
+* add the --service flag in the kardinal flow telepresence intercept command ([#259](https://github.com/kurtosis-tech/kardinal/issues/259)) ([5d22282](https://github.com/kurtosis-tech/kardinal/commit/5d222824139e0b9597f94cb0b4cd0663e948e413))
+* fix broken website CSS by refactoring styled-components SSR logic ([#257](https://github.com/kurtosis-tech/kardinal/issues/257)) ([505e885](https://github.com/kurtosis-tech/kardinal/commit/505e88504d020ed1c53ae6f4d018db85b86d1e1c))
+
## [0.3.1](https://github.com/kurtosis-tech/kardinal/compare/0.3.0...0.3.1) (2024-09-27)
diff --git a/README.md b/README.md
index f1eaa158..b2263424 100644
--- a/README.md
+++ b/README.md
@@ -79,7 +79,7 @@ kardinal deploy -k ./obd-kardinal.yaml
You can view the frontend of the demo app by going to:
-`http://prod.app.localhost`
+`http://baseline.app.localhost`
Feel free to click around, add items to your cart, and shop!
diff --git a/kardinal-cli/cmd/root.go b/kardinal-cli/cmd/root.go
index c465e953..a22e80b1 100644
--- a/kardinal-cli/cmd/root.go
+++ b/kardinal-cli/cmd/root.go
@@ -82,6 +82,7 @@ var (
templateYamlFile string
templateDescription string
templateArgsFile string
+ flowID string
)
var rootCmd = &cobra.Command{
@@ -389,9 +390,9 @@ var telepresenceInterceptCmd = &cobra.Command{
}
logrus.Infof("Telepresence has been successfully connected to namespace '%s'...", namespaceName)
- logrus.Infof("Executing Telepresence intercept to flow id '%s'...", namespaceName)
+ logrus.Infof("Executing Telepresence intercept to flow id '%s'...", flowId)
- telepresenceInterceptCmdArgs := []string{"intercept", interceptBaseName, "--port", fmt.Sprintf("%s:http", localPort)}
+ telepresenceInterceptCmdArgs := []string{"intercept", "--port", fmt.Sprintf("%s:http", localPort), "--service", interceptBaseName, interceptBaseName}
telepresenceInterceptCmd := exec.Command(telepresenceCmdName, telepresenceInterceptCmdArgs...)
telepresenceInterceptOutput, err := telepresenceInterceptCmd.CombinedOutput()
logrus.Infof("Telepresence intercept command output: %s", string(telepresenceInterceptOutput))
@@ -642,6 +643,7 @@ func init() {
createCmd.Flags().StringSliceVarP(&serviceImagePairs, "service-image", "s", []string{}, "Extra service and respective image to include in the same flow (can be used multiple times)")
createCmd.Flags().StringVarP(&templateName, "template", "t", "", "Template name to use for the flow creation")
createCmd.Flags().StringVarP(&templateArgsFile, "template-args", "a", "", "JSON with the template arguments or path to YAML file containing template arguments")
+ createCmd.Flags().StringVarP(&flowID, "ID", "i", "", "Set the flow id")
deployCmd.PersistentFlags().StringVarP(&kubernetesManifestFile, "k8s-manifest", "k", "", "Path to the K8S manifest file")
deployCmd.MarkPersistentFlagRequired("k8s-manifest")
@@ -859,6 +861,7 @@ func createDevFlow(tenantUuid api_types.Uuid, pairsMap map[string]string, templa
}
resp, err := client.PostTenantUuidFlowCreateWithResponse(ctx, tenantUuid, api_types.PostTenantUuidFlowCreateJSONRequestBody{
+ FlowId: &flowID,
FlowSpec: devSpec,
TemplateSpec: templateSpec,
})
diff --git a/libs/cli-kontrol-api/api/golang/client/client.gen.go b/libs/cli-kontrol-api/api/golang/client/client.gen.go
index af1911b1..fea9dfbb 100644
--- a/libs/cli-kontrol-api/api/golang/client/client.gen.go
+++ b/libs/cli-kontrol-api/api/golang/client/client.gen.go
@@ -755,6 +755,7 @@ type GetHealthResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *string
+ JSON400 *RequestError
JSON500 *Error
}
@@ -778,6 +779,7 @@ type PostTenantUuidDeployResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *Flow
+ JSON400 *RequestError
JSON404 *NotFound
JSON500 *Error
}
@@ -802,6 +804,7 @@ type PostTenantUuidFlowCreateResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *Flow
+ JSON400 *RequestError
JSON404 *NotFound
JSON500 *Error
}
@@ -825,6 +828,7 @@ func (r PostTenantUuidFlowCreateResponse) StatusCode() int {
type DeleteTenantUuidFlowFlowIdResponse struct {
Body []byte
HTTPResponse *http.Response
+ JSON400 *RequestError
JSON404 *NotFound
JSON500 *Error
}
@@ -849,6 +853,7 @@ type GetTenantUuidFlowsResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *[]Flow
+ JSON400 *RequestError
JSON404 *NotFound
JSON500 *Error
}
@@ -873,6 +878,7 @@ type GetTenantUuidManifestResponse struct {
Body []byte
HTTPResponse *http.Response
YAML200 *string
+ JSON400 *RequestError
JSON404 *NotFound
JSON500 *Error
}
@@ -897,6 +903,7 @@ type GetTenantUuidTemplatesResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *[]Template
+ JSON400 *RequestError
JSON404 *NotFound
JSON500 *Error
}
@@ -921,6 +928,7 @@ type PostTenantUuidTemplatesCreateResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *Template
+ JSON400 *RequestError
JSON404 *NotFound
JSON500 *Error
}
@@ -944,6 +952,7 @@ func (r PostTenantUuidTemplatesCreateResponse) StatusCode() int {
type DeleteTenantUuidTemplatesTemplateNameResponse struct {
Body []byte
HTTPResponse *http.Response
+ JSON400 *RequestError
JSON404 *NotFound
JSON500 *Error
}
@@ -968,6 +977,7 @@ type GetTenantUuidTopologyResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *ClusterTopology
+ JSON400 *RequestError
JSON404 *NotFound
JSON500 *Error
}
@@ -1123,6 +1133,13 @@ func ParseGetHealthResponse(rsp *http.Response) (*GetHealthResponse, error) {
}
response.JSON200 = &dest
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500:
var dest Error
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -1156,6 +1173,13 @@ func ParsePostTenantUuidDeployResponse(rsp *http.Response) (*PostTenantUuidDeplo
}
response.JSON200 = &dest
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest NotFound
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -1196,6 +1220,13 @@ func ParsePostTenantUuidFlowCreateResponse(rsp *http.Response) (*PostTenantUuidF
}
response.JSON200 = &dest
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest NotFound
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -1229,6 +1260,13 @@ func ParseDeleteTenantUuidFlowFlowIdResponse(rsp *http.Response) (*DeleteTenantU
}
switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest NotFound
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -1269,6 +1307,13 @@ func ParseGetTenantUuidFlowsResponse(rsp *http.Response) (*GetTenantUuidFlowsRes
}
response.JSON200 = &dest
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest NotFound
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -1302,6 +1347,13 @@ func ParseGetTenantUuidManifestResponse(rsp *http.Response) (*GetTenantUuidManif
}
switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest NotFound
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -1349,6 +1401,13 @@ func ParseGetTenantUuidTemplatesResponse(rsp *http.Response) (*GetTenantUuidTemp
}
response.JSON200 = &dest
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest NotFound
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -1389,6 +1448,13 @@ func ParsePostTenantUuidTemplatesCreateResponse(rsp *http.Response) (*PostTenant
}
response.JSON200 = &dest
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest NotFound
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -1422,6 +1488,13 @@ func ParseDeleteTenantUuidTemplatesTemplateNameResponse(rsp *http.Response) (*De
}
switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest NotFound
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -1462,6 +1535,13 @@ func ParseGetTenantUuidTopologyResponse(rsp *http.Response) (*GetTenantUuidTopol
}
response.JSON200 = &dest
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest RequestError
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest NotFound
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
diff --git a/libs/cli-kontrol-api/api/golang/server/server.gen.go b/libs/cli-kontrol-api/api/golang/server/server.gen.go
index 0a38f38b..99fbcd88 100644
--- a/libs/cli-kontrol-api/api/golang/server/server.gen.go
+++ b/libs/cli-kontrol-api/api/golang/server/server.gen.go
@@ -288,6 +288,14 @@ type NotFoundJSONResponse struct {
ResourceType string `json:"resource-type"`
}
+type RequestErrorJSONResponse struct {
+ // Error Error type
+ Error string `json:"error"`
+
+ // Msg Error message
+ Msg *string `json:"msg,omitempty"`
+}
+
type GetHealthRequestObject struct {
}
@@ -304,6 +312,15 @@ func (response GetHealth200JSONResponse) VisitGetHealthResponse(w http.ResponseW
return json.NewEncoder(w).Encode(response)
}
+type GetHealth400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response GetHealth400JSONResponse) VisitGetHealthResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type GetHealth500JSONResponse struct{ ErrorJSONResponse }
func (response GetHealth500JSONResponse) VisitGetHealthResponse(w http.ResponseWriter) error {
@@ -331,6 +348,15 @@ func (response PostTenantUuidDeploy200JSONResponse) VisitPostTenantUuidDeployRes
return json.NewEncoder(w).Encode(response)
}
+type PostTenantUuidDeploy400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response PostTenantUuidDeploy400JSONResponse) VisitPostTenantUuidDeployResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type PostTenantUuidDeploy404JSONResponse struct{ NotFoundJSONResponse }
func (response PostTenantUuidDeploy404JSONResponse) VisitPostTenantUuidDeployResponse(w http.ResponseWriter) error {
@@ -367,6 +393,15 @@ func (response PostTenantUuidFlowCreate200JSONResponse) VisitPostTenantUuidFlowC
return json.NewEncoder(w).Encode(response)
}
+type PostTenantUuidFlowCreate400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response PostTenantUuidFlowCreate400JSONResponse) VisitPostTenantUuidFlowCreateResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type PostTenantUuidFlowCreate404JSONResponse struct{ NotFoundJSONResponse }
func (response PostTenantUuidFlowCreate404JSONResponse) VisitPostTenantUuidFlowCreateResponse(w http.ResponseWriter) error {
@@ -403,6 +438,15 @@ func (response DeleteTenantUuidFlowFlowId2xxResponse) VisitDeleteTenantUuidFlowF
return nil
}
+type DeleteTenantUuidFlowFlowId400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response DeleteTenantUuidFlowFlowId400JSONResponse) VisitDeleteTenantUuidFlowFlowIdResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type DeleteTenantUuidFlowFlowId404JSONResponse struct{ NotFoundJSONResponse }
func (response DeleteTenantUuidFlowFlowId404JSONResponse) VisitDeleteTenantUuidFlowFlowIdResponse(w http.ResponseWriter) error {
@@ -438,6 +482,15 @@ func (response GetTenantUuidFlows200JSONResponse) VisitGetTenantUuidFlowsRespons
return json.NewEncoder(w).Encode(response)
}
+type GetTenantUuidFlows400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response GetTenantUuidFlows400JSONResponse) VisitGetTenantUuidFlowsResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type GetTenantUuidFlows404JSONResponse struct{ NotFoundJSONResponse }
func (response GetTenantUuidFlows404JSONResponse) VisitGetTenantUuidFlowsResponse(w http.ResponseWriter) error {
@@ -483,6 +536,15 @@ func (response GetTenantUuidManifest200ApplicationxYamlResponse) VisitGetTenantU
return err
}
+type GetTenantUuidManifest400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response GetTenantUuidManifest400JSONResponse) VisitGetTenantUuidManifestResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type GetTenantUuidManifest404JSONResponse struct{ NotFoundJSONResponse }
func (response GetTenantUuidManifest404JSONResponse) VisitGetTenantUuidManifestResponse(w http.ResponseWriter) error {
@@ -518,6 +580,15 @@ func (response GetTenantUuidTemplates200JSONResponse) VisitGetTenantUuidTemplate
return json.NewEncoder(w).Encode(response)
}
+type GetTenantUuidTemplates400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response GetTenantUuidTemplates400JSONResponse) VisitGetTenantUuidTemplatesResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type GetTenantUuidTemplates404JSONResponse struct{ NotFoundJSONResponse }
func (response GetTenantUuidTemplates404JSONResponse) VisitGetTenantUuidTemplatesResponse(w http.ResponseWriter) error {
@@ -554,6 +625,15 @@ func (response PostTenantUuidTemplatesCreate200JSONResponse) VisitPostTenantUuid
return json.NewEncoder(w).Encode(response)
}
+type PostTenantUuidTemplatesCreate400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response PostTenantUuidTemplatesCreate400JSONResponse) VisitPostTenantUuidTemplatesCreateResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type PostTenantUuidTemplatesCreate404JSONResponse struct{ NotFoundJSONResponse }
func (response PostTenantUuidTemplatesCreate404JSONResponse) VisitPostTenantUuidTemplatesCreateResponse(w http.ResponseWriter) error {
@@ -590,6 +670,15 @@ func (response DeleteTenantUuidTemplatesTemplateName2xxResponse) VisitDeleteTena
return nil
}
+type DeleteTenantUuidTemplatesTemplateName400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response DeleteTenantUuidTemplatesTemplateName400JSONResponse) VisitDeleteTenantUuidTemplatesTemplateNameResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type DeleteTenantUuidTemplatesTemplateName404JSONResponse struct{ NotFoundJSONResponse }
func (response DeleteTenantUuidTemplatesTemplateName404JSONResponse) VisitDeleteTenantUuidTemplatesTemplateNameResponse(w http.ResponseWriter) error {
@@ -625,6 +714,15 @@ func (response GetTenantUuidTopology200JSONResponse) VisitGetTenantUuidTopologyR
return json.NewEncoder(w).Encode(response)
}
+type GetTenantUuidTopology400JSONResponse struct{ RequestErrorJSONResponse }
+
+func (response GetTenantUuidTopology400JSONResponse) VisitGetTenantUuidTopologyResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
type GetTenantUuidTopology404JSONResponse struct{ NotFoundJSONResponse }
func (response GetTenantUuidTopology404JSONResponse) VisitGetTenantUuidTopologyResponse(w http.ResponseWriter) error {
@@ -960,36 +1058,37 @@ func (sh *strictHandler) GetTenantUuidTopology(ctx echo.Context, uuid Uuid) erro
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "H4sIAAAAAAAC/8wa2W7buPZXCN77KNvJvR1g4Lc2adqgaRE0zgCDIigY6VhmI5EqSTkxAv/7gJsWi5Ll",
- "SZPmTRbPvvNYjzjmecEZMCXx/BEXRJAcFAjza5nx+wlN9GMCMha0UJQzPMdnGb9HNAGm6JKCwBGm+nVB",
- "1ApHmJEc8LzCjrCAnyUVkOC5EiVEWMYryIkmqzaFBpVKUJbi7TbCCvIiIwomlsouZ/0W8SVSK0AeNMy+",
- "TegwIcoypPX19fmp5y1A8lLEPbwN/iEstxpYFpxJMJZ/LwQX+iHmTAFT+pEURUZjooWZ/ZBaoscGxULw",
- "AoSiFh88flsDQxYZ5tGuDBHOZdqHkoOUJA1gbZtafnN8byowfvsDYmUVDNDVXL9wdcZLljxB25CzvjoH",
- "ofPTkK7efxN70osdttWO1m1ikZZnjAkqJowrtDQ20EBWS6PYSVZKBWLBC57xdBPwc5I6EyjIzcN/BSzx",
- "HP9nVif2zFGcvU9S0Mo7yYgQZKN/M54cQOULTwJUdkxiSUZOwK41InwKRcY3OTB1wtmSpl3lkgpC/3qY",
- "pHzieRbF+nhaU8BRfTyhecGFQXHZaKBxZHN0ju/+lFPKZ6SgM1IUcrY+9glYi99gHZLdGLIjb0ZuIevG",
- "0oV+jZY68VaAtEGmoYh09aSDvlhBo9T6+lNFTlKVw17KiogU1FjKFnoM5R2bVQXR8QsZTjeOruFIHIOU",
- "E2BKbEaH4TlLBUj51uC+N6iB0G60sI5dqJzcEgkZZdA4v+U8A8I66tXtrCVun5ZXBcQtXXZKVk5SmGQ8",
- "JsoWanggeZEZAUh8ByyZkLluX1IFgwXEmsZ1k+xiewiy129tUXZoh9TbtfEHouCebPrSOLXHuznsXk8d",
- "9nAKpxWQS2JJUzl1mewOJzajaTijPYWQQoFQ6mgxFEjmTEsqCxJDEGTFpfLO6hwOozp/BM989xr2cB26",
- "O5I25Kr5NOVxHAaM1ud1ao93vc5A3XNxR1m6Pp46EsOub2IEi3gNEHS8FySkw2dCmeux+5vQJDYg4xtl",
- "p8MFcsfH7qG02zkXIOzUPphw262hYWEwWAUvFRzM9KvG6mfpK9KhZK8s3gBhRRQsy2wi4XD3XjnkK+j1",
- "7zYQc2Z8GjXCXjP6s2y1aD9E6OYcbPWjRpBe7PAsvNgU1SSgUfVUx8q8WVSbxQMeFAhGskbC1RzWICTl",
- "THa5aLOg6jgaP4r+ZXH2TqSm/rkB3Zrppsc7nmKwB5z3zBK6iS5I2jNovDtszjjXsjawQpI2c6Yj6Uqp",
- "wgD0dd2Pi8WlBXjmvltLElKinaEdNRqtr6lEzAWsj6dXVcwNaGBhg41DHwVl9myDEneyvit1o6qEby4N",
- "Ir/86tLiHtJg4dcmgV7XyMieOSU8hvhdS3BA2hGwCexoDonZ35hbwnavNo03gY1Rr3JdQmbnpDhK6Rr2",
- "kmmEbFXCnjV295S99lQ3aGl/Zdm5nIm0zP1+kCQJ1ZYh2WUDyG63uvcER/f7Qau8ccHzvUebrRl9ltyE",
- "IVXmSnRycT77xJkSPENvL89x1YbwHB9Pj6ZHWlheACMFxXP8f/PKGt0oPVsBybQDOmtQLpA9Q/EK4jsU",
- "Wy44wu7CrW1kdli6beAPoD5aUjvrvv8dHR20/gqsD9uSXZXmLrMsM+QZaSX/sHxCLbWSZ+Y2c4bqTAEj",
- "TM0ey5Im25kdhk2McBlQ8JJLtTAY1yVN7PxrLFlvlb+F2dcgM7M83d5Yv4NU73iyOcg6QxNDd+IPWM8K",
- "jggqBE8QZ9kGxRans9TdPtGTQ7KaZUlQvDXSUwKKBRi6SNf8UmoPvzl6s9/D1cr1F4SEFmRmBIGxcaH1",
- "OrEYLx4b3YHuu3Rlb58rTHlslrUxiK3aGhr1LJUx62JrMkRQ4v1fSspS5GWLEC9sbc426J6qFSKoxf41",
- "xO7Zq4rbR7cZ2dranoEN4nbwnpr37fA980P6vwnfaC+cX9jYSG+66OGh24aqemA0eAV2tWu/ng7YNqR8",
- "Sgl4QuyOul7aIO4MWK+7IOeE0SXYKtyz9qcSAUsKTplCAlQpmEQky8wk9qm8BcFAgaz+46wWB64JIuX+",
- "j0KUIc4A5WWm6KQC9xLUo0c0FAafvcAvEQkPkw3Js18zTT2vayMsyzwnYqNLvzN8ZeIElpSZSVz7gNQm",
- "//vt54um3RVJpZ2btblxhKvwuAnEjm9tIxN4UYG/4iSurrsjEvmCSmWuJF6xKvT13Y8hZ8XfkdaVSAcO",
- "W5WPftfENcY3/aN4NfQwuG/eEl9ukqnjpyudP3sVhb+OkMfWty8HDTdVuPiHL/bPoeeZc9rf6Iybdiqb",
- "v4ZpRzW+zBhRLz307ymXQ1G++6VJKNjrrr/kIjdcXsLo2+0/AQAA//99kO4apiYAAA==",
+ "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",
+ "1Hb7dwAAAP//1z52lM4pAAA=",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/libs/cli-kontrol-api/api/golang/types/types.gen.go b/libs/cli-kontrol-api/api/golang/types/types.gen.go
index dc723f86..4806affd 100644
--- a/libs/cli-kontrol-api/api/golang/types/types.gen.go
+++ b/libs/cli-kontrol-api/api/golang/types/types.gen.go
@@ -176,8 +176,18 @@ type NotFound struct {
ResourceType string `json:"resource-type"`
}
+// RequestError defines model for RequestError.
+type RequestError struct {
+ // Error Error type
+ Error string `json:"error"`
+
+ // Msg Error message
+ Msg *string `json:"msg,omitempty"`
+}
+
// PostTenantUuidFlowCreateJSONBody defines parameters for PostTenantUuidFlowCreate.
type PostTenantUuidFlowCreateJSONBody struct {
+ FlowId *string `json:"flow-id,omitempty"`
FlowSpec FlowSpec `json:"flow_spec"`
TemplateSpec *TemplateSpec `json:"template_spec,omitempty"`
}
diff --git a/libs/cli-kontrol-api/api/typescript/client/types.d.ts b/libs/cli-kontrol-api/api/typescript/client/types.d.ts
index e55bfcd8..9fd0c18a 100644
--- a/libs/cli-kontrol-api/api/typescript/client/types.d.ts
+++ b/libs/cli-kontrol-api/api/typescript/client/types.d.ts
@@ -14,6 +14,7 @@ export interface paths {
"application/json": string;
};
};
+ 400: components["responses"]["RequestError"];
500: components["responses"]["Error"];
};
};
@@ -29,6 +30,7 @@ export interface paths {
requestBody: {
content: {
"application/json": {
+ "flow-id"?: string;
flow_spec: components["schemas"]["FlowSpec"];
template_spec?: components["schemas"]["TemplateSpec"];
};
@@ -41,6 +43,7 @@ export interface paths {
"application/json": components["schemas"]["Flow"];
};
};
+ 400: components["responses"]["RequestError"];
404: components["responses"]["NotFound"];
500: components["responses"]["Error"];
};
@@ -60,6 +63,7 @@ export interface paths {
"application/json": components["schemas"]["Flow"][];
};
};
+ 400: components["responses"]["RequestError"];
404: components["responses"]["NotFound"];
500: components["responses"]["Error"];
};
@@ -74,6 +78,7 @@ export interface paths {
};
};
responses: {
+ 400: components["responses"]["RequestError"];
404: components["responses"]["NotFound"];
500: components["responses"]["Error"];
/** @description Dev flow deletion status */
@@ -103,6 +108,7 @@ export interface paths {
"application/json": components["schemas"]["Flow"];
};
};
+ 400: components["responses"]["RequestError"];
404: components["responses"]["NotFound"];
500: components["responses"]["Error"];
};
@@ -122,6 +128,7 @@ export interface paths {
"application/json": components["schemas"]["ClusterTopology"];
};
};
+ 400: components["responses"]["RequestError"];
404: components["responses"]["NotFound"];
500: components["responses"]["Error"];
};
@@ -147,6 +154,7 @@ export interface paths {
"application/json": components["schemas"]["Template"];
};
};
+ 400: components["responses"]["RequestError"];
404: components["responses"]["NotFound"];
500: components["responses"]["Error"];
};
@@ -166,6 +174,7 @@ export interface paths {
"application/json": components["schemas"]["Template"][];
};
};
+ 400: components["responses"]["RequestError"];
404: components["responses"]["NotFound"];
500: components["responses"]["Error"];
};
@@ -180,6 +189,7 @@ export interface paths {
};
};
responses: {
+ 400: components["responses"]["RequestError"];
404: components["responses"]["NotFound"];
500: components["responses"]["Error"];
/** @description Template deletion status */
@@ -207,6 +217,7 @@ export interface paths {
"application/x-yaml": string;
};
};
+ 400: components["responses"]["RequestError"];
404: components["responses"]["NotFound"];
500: components["responses"]["Error"];
};
@@ -326,6 +337,17 @@ export interface components {
};
};
};
+ /** @description Request error */
+ RequestError: {
+ content: {
+ "application/json": {
+ /** @description Error type */
+ error: string;
+ /** @description Error message */
+ msg?: string;
+ };
+ };
+ };
/** @description Resource not found */
NotFound: {
content: {
diff --git a/libs/cli-kontrol-api/specs/api.yaml b/libs/cli-kontrol-api/specs/api.yaml
index fb2ae9cd..422e1271 100644
--- a/libs/cli-kontrol-api/specs/api.yaml
+++ b/libs/cli-kontrol-api/specs/api.yaml
@@ -11,6 +11,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"200":
description: Successful response
content:
@@ -30,6 +32,8 @@ paths:
schema:
type: object
properties:
+ flow-id:
+ type: string
flow_spec:
$ref: "#/components/schemas/FlowSpec"
template_spec:
@@ -39,6 +43,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"404":
$ref: "#/components/responses/NotFound"
"200":
@@ -55,6 +61,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"404":
$ref: "#/components/responses/NotFound"
"200":
@@ -74,6 +82,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"404":
$ref: "#/components/responses/NotFound"
"2xx":
@@ -93,6 +103,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"404":
$ref: "#/components/responses/NotFound"
"200":
@@ -109,6 +121,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"404":
$ref: "#/components/responses/NotFound"
"200":
@@ -132,6 +146,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"404":
$ref: "#/components/responses/NotFound"
"200":
@@ -148,6 +164,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"404":
$ref: "#/components/responses/NotFound"
"200":
@@ -167,6 +185,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"404":
$ref: "#/components/responses/NotFound"
"2xx":
@@ -184,6 +204,8 @@ paths:
responses:
"500":
$ref: "#/components/responses/Error"
+ "400":
+ $ref: "#/components/responses/RequestError"
"404":
$ref: "#/components/responses/NotFound"
"200":
@@ -211,6 +233,22 @@ components:
required:
- error
+ RequestError:
+ description: Request error
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ error:
+ type: string
+ description: Error type
+ msg:
+ type: string
+ description: Error message
+ required:
+ - error
+
NotFound:
description: Resource not found
content:
diff --git a/version.txt b/version.txt
index 9e11b32f..1c09c74e 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-0.3.1
+0.3.3
diff --git a/website/app/GlobalStyles.ts b/website/app/GlobalStyles.ts
new file mode 100644
index 00000000..fd8fb4ea
--- /dev/null
+++ b/website/app/GlobalStyles.ts
@@ -0,0 +1,184 @@
+"use client";
+
+import { createGlobalStyle, css } from "styled-components";
+
+const styles = css`
+ :root {
+ color-scheme: only light;
+
+ --max-width: 1248px;
+ --border-radius: 4px;
+
+ /* --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", */
+ /* "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", */
+ /* "Fira Mono", "Droid Sans Mono", "Courier New", monospace; */
+
+ /* color vars */
+ --brand-primary: #ff602c;
+ --brand-primary-dark: rgba(168, 50, 5, 0.4);
+ --brand-secondary: #fca061;
+ --gradient-from-bg: linear-gradient(84deg, transparent 0%, white 100%);
+ --gradient-to-bg: linear-gradient(180deg, transparent 0%, white 100%);
+
+ --gradient-brand: linear-gradient(
+ to right,
+ var(--brand-primary),
+ var(--brand-secondary)
+ );
+ --gradient-brand-reverse: linear-gradient(
+ to right,
+ var(--brand-secondary),
+ var(--brand-primary)
+ );
+
+ --gradient-brand-dark: linear-gradient(
+ 90deg,
+ #fca061,
+ rgba(168, 50, 5, 0.4)
+ );
+ --white-10: rgba(255, 255, 255, 0.1);
+ --white-20: rgba(255, 255, 255, 0.2);
+ --white-40: rgba(255, 255, 255, 0.4);
+ --white-60: rgba(255, 255, 255, 0.6);
+ --white-70: rgba(255, 255, 255, 0.7);
+ --white-90: rgba(255, 255, 255, 0.9);
+ --white-100: #ffffff;
+
+ /* TODO: too many grays... consolidate */
+ --gray-100: #f3f4f6;
+ --gray-200: #e5e7eb;
+ --gray-400: #9ca3af;
+ --gray-600: #4b5563;
+ --gray-bg-light: #212121;
+ --gray-bg: #1f232a;
+ --gray-dark: #21262d;
+ --gray-diagramlines: #666a6f;
+ --gray-icon: #8b949e;
+ --gray-light: #aaa;
+ --gray-lighter: #f2f2f2;
+ --gray-lightest: #fafafa;
+ --gray: #525157;
+
+ --blue: #1f56a5;
+ --blue-light: #58a6ff;
+
+ --black: #000330;
+ --white: #ffffff;
+
+ /* semantic vars */
+ --foreground: var(--gray);
+ --foreground-dark: var(--black);
+ --foreground-light: var(--gray-light);
+
+ --foreground-inverted: var(--gray-light);
+ --foreground-dark-inverted: var(--gray-lighter);
+
+ --background: var(--white);
+ --background-light: var(--gray-bg-light, #212121);
+ --background-dark: var(--gray-bg-dark, #21262d);
+
+ --background-contrast: #fff9f2;
+ --background-inverted: var(--gray-bg);
+
+ --gray-border: #ddd;
+ }
+
+ * {
+ -moz-font-feature-settings: "liga" on;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ box-sizing: border-box;
+ font-smooth: always;
+ margin: 0;
+ padding: 0;
+ text-rendering: optimizeLegibility;
+ }
+
+ html,
+ body {
+ background: var(--background);
+ overflow-x: hidden;
+ scroll-behavior: smooth;
+ }
+
+ body {
+ color: var(--foreground);
+ }
+
+ a {
+ color: inherit;
+ text-decoration: none;
+ }
+
+ em {
+ font-weight: 500;
+ background: var(--gradient-brand-reverse);
+ background-size: auto;
+ background-clip: border-box;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ font-style: normal;
+ }
+
+ s {
+ text-decoration: none;
+ position: relative;
+ display: inline-block;
+ }
+
+ s:after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-image: url("/scribble-animated.svg");
+ background-size: 100%;
+ background-repeat: no-repeat;
+ }
+
+ hr {
+ border: 0;
+ border-bottom: 1px solid var(--gray-border);
+ }
+
+ br[data-mobile="true"] {
+ display: none;
+ }
+
+ @media (max-width: 768px) {
+ br[data-desktop="true"] {
+ display: none;
+ }
+ br[data-mobile="true"] {
+ display: block;
+ }
+ }
+
+ html {
+ color-scheme: light;
+ }
+
+ pre {
+ background-color: var(--gray-bg) !important;
+ padding: 12px !important;
+ }
+
+ code {
+ line-height: 1.6;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ }
+
+ @media (max-width: 768px) {
+ code {
+ font-size: 14px;
+ }
+ }
+`;
+
+const GlobalStyles = createGlobalStyle`${styles}`;
+
+export default GlobalStyles;
diff --git a/website/app/Providers.tsx b/website/app/Providers.tsx
new file mode 100644
index 00000000..1c784f1f
--- /dev/null
+++ b/website/app/Providers.tsx
@@ -0,0 +1,25 @@
+import { ReactNode } from "react";
+
+import { CalculatorProvider } from "@/context/CalculatorContext";
+import { ModalProvider } from "@/context/ModalContext";
+import { VotingProvider } from "@/context/VotingContext";
+
+import StyledComponentsRegistry from "../lib/registry";
+
+interface Props {
+ children: ReactNode;
+}
+
+const Providers = ({ children }: Props) => {
+ return (
+
+
+
+ {children}
+
+
+
+ );
+};
+
+export default Providers;
diff --git a/website/app/docs/concepts/flows/page.mdx b/website/app/docs/concepts/flows/page.mdx
index 01dd8254..3a3a8e12 100644
--- a/website/app/docs/concepts/flows/page.mdx
+++ b/website/app/docs/concepts/flows/page.mdx
@@ -6,11 +6,11 @@ export const metadata = {
In Kardinal, a flow is an ephemeral environment that developers can use for development, testing, or QA.
-The default flow in Kardinal is called `stable`, and typically contains the latest versions of each service that you have in your staging cluster, i.e. the latest changes that are about to be promoted to production.
+The default flow in Kardinal is called `baseline`, and typically contains the latest versions of each service that you have in your staging cluster, i.e. the latest changes that are about to be promoted to production.
When Kardinal creates a flow, it will deploy the set of services that encompass the changes being made for a given feature. Kardinal will also create an ingress point for the developer to use.
-Any communication made through the ingress point will be routed to the versions of the services that are a part of the flow. Any services that are a part of the application, but aren't being changed as a part of the feature, will still be available from the `stable` flow.
+Any communication made through the ingress point will be routed to the versions of the services that are a part of the flow. Any services that are a part of the application, but aren't being changed as a part of the feature, will still be available from the `baseline` flow.
As your team onboards to Kardinal, you will be able to create flows with escalating levels of configurability:
@@ -30,4 +30,4 @@ Getting more advanced flows requires defining more of your application's topolog
The cost savings of the final two use cases (isolating state between flows) can reach into the millions of dollars for large organizations who use isolated dev sandboxes for ephemeral environments.
-To see how, and to calculate savings for your own organization, check out our [cost savings dashboard](https://kardinal.streamlit.app) hosted on Streamlit. (If the dashboard is "sleeping", just click to wake it up!)
\ No newline at end of file
+To see how, and to calculate savings for your own organization, check out our [cost savings dashboard](https://kardinal.streamlit.app) hosted on Streamlit. (If the dashboard is "sleeping", just click to wake it up!)
diff --git a/website/app/docs/concepts/plugins/page.mdx b/website/app/docs/concepts/plugins/page.mdx
index 29913ac8..ebae4a7d 100644
--- a/website/app/docs/concepts/plugins/page.mdx
+++ b/website/app/docs/concepts/plugins/page.mdx
@@ -183,7 +183,7 @@ In order for Kardinal to guarantee data isolation and safety, Kardinal needs to
The level of data isolation and semantics of "dev" version will be highly dependent on your service, application, and development needs.
This is where we can leverage a plugin to encode this information.
-For example, say we have a `postgres` database in our cluster. When creating dev flows, we'll avoid touching the "prod" postgres database by using the [`postgres-seed-plugin`](https://github.com/kurtosis-tech/postgres-seed-plugin) like so:
+For example, say we have a `postgres` database in our cluster. When creating dev flows, we'll avoid touching the "baseline" postgres database by using the [`postgres-seed-plugin`](https://github.com/kurtosis-tech/postgres-seed-plugin) like so:
```
...
@@ -282,7 +282,7 @@ Using plugins to handle dev versions of external services works very similarly.
The difference is that the plugin annotation gets added to the service spec of the service that depends on the external service. Accordingly, when writing the plugin, the plugin will be modifying the deployment spec of the dependent service.
-For example, say we have a `cartservice` in our app that depends on an external [Neon](neon.tech) DB. When creating dev flows, we'll avoid touching the "prod" Neon database by using the [`neondb-plugin`](https://github.com/kurtosis-tech/neondb-plugin) like so:
+For example, say we have a `cartservice` in our app that depends on an external [Neon](neon.tech) DB. When creating dev flows, we'll avoid touching the "baseline" Neon database by using the [`neondb-plugin`](https://github.com/kurtosis-tech/neondb-plugin) like so:
```
...
diff --git a/website/app/docs/getting-started/fundamentals/page.mdx b/website/app/docs/getting-started/fundamentals/page.mdx
index 3f3ede63..8a5bf15e 100644
--- a/website/app/docs/getting-started/fundamentals/page.mdx
+++ b/website/app/docs/getting-started/fundamentals/page.mdx
@@ -9,7 +9,7 @@ Once Kardinal is installed and an application is deployed, developers can create
kardinal flow create
```
-Kardinal will deploy the `` image alongside the stable version of the service, and that developer will be able to interact with the application as if it was using their version of their service.
+Kardinal will deploy the `` image alongside the baseline version of the service, and that developer will be able to interact with the application as if it was using their version of their service.
As your team onboards to Kardinal, you will be able to create flows with escalating levels of configurability:
diff --git a/website/app/docs/getting-started/own-app/page.mdx b/website/app/docs/getting-started/own-app/page.mdx
index acc1bfe3..30d7ab85 100644
--- a/website/app/docs/getting-started/own-app/page.mdx
+++ b/website/app/docs/getting-started/own-app/page.mdx
@@ -12,9 +12,9 @@ Getting started takes just a few minutes, assuming you have [installed Kardinal]
To use Kardinal with your application, you will need a development Kubernetes cluster with Istio installed.
-It's not important that your production cluster uses Istio. Kardinal will manage everything related to Istio on your development cluster, and your application should work just fine.
+It's not important that your cluster uses Istio. Kardinal will manage everything related to Istio on your development cluster, and your application should work just fine.
-Then, you'll need to install the Kardinal CLI and deploy the Kardinal Manager on your application, as described in the [install Kardinal guide](./getting-started/install)
+Then, you'll need to install the Kardinal CLI and deploy the Kardinal Manager on your application, as described in the [install Kardinal guide](./getting-started/install)
Then, make sure your application is using distributed tracing. Kardinal uses your trace IDs to route requests between different development versions of services to implement logical environment isolation.
@@ -36,16 +36,16 @@ If you want to use a tracing system that isn't listed here, you can submit an [i
### Step 1: Annotate the application entrypoint
-Kardinal can manage multiple entrypoints in your Kubernetes manifest that routes traffic into the cluster. You
+Kardinal can manage multiple entrypoints in your Kubernetes manifest that routes traffic into the cluster. You
can leverage access to your services either through the Kubernetes Ingress API or the Gateway API.
-To get started, you just need to add the *`kardinal.dev.service/ingress`* or *`kardinal.dev.service/gateway`*
-annotations to your Ingress or Gateway manifest to mark this entrypoint. The annotation should be set to `true`
+To get started, you just need to add the *`kardinal.dev.service/ingress`* or *`kardinal.dev.service/gateway`*
+annotations to your Ingress or Gateway manifest to mark this entrypoint. The annotation should be set to `true`
for whichever Ingress or Gateway resource is the entrypoint into the cluster.
### Example using Kubernetes Ingress
-Here’s an example using an Ingress resource to handle traffic, with Kardinal annotations to mark it as the
+Here’s an example using an Ingress resource to handle traffic, with Kardinal annotations to mark it as the
cluster entrypoint:
```yaml
@@ -70,12 +70,12 @@ spec:
number: 80
```
-In this example, traffic to `web.admin.localhost` is routed to the `frontend` service on port 80 via the
+In this example, traffic to `web.admin.localhost` is routed to the `frontend` service on port 80 via the
Ingress resource.
### Example using Gateway API
-Alternatively, you can use the Gateway API, which provides more flexibility and control over traffic routing.
+Alternatively, you can use the Gateway API, which provides more flexibility and control over traffic routing.
Here’s how the Gateway and HTTPRoute manifests would look, with Kardinal annotations:
```yaml
@@ -97,7 +97,7 @@ spec:
from: All
```
-In this example, the `Gateway` resource defines a listener on port 80, routing traffic for any subdomain
+In this example, the `Gateway` resource defines a listener on port 80, routing traffic for any subdomain
of `app.localhost`.
```yaml
@@ -121,29 +121,29 @@ spec:
port: 80
```
-The `HTTPRoute` resource specifies that traffic to `baseline.app.localhost` should be routed to the `frontend`
+The `HTTPRoute` resource specifies that traffic to `baseline.app.localhost` should be routed to the `frontend`
service on port 80.
### Step 2: Deploy the main version of your application
Okay, now that we've got Kardinal integrated, let's deploy our application. Run:
-
+
```bash
kardinal deploy -k
```
-
+
You should now be able to view your application in the Kardinal dashboard with:
-
+
```bash
kardinal dashboard
```
### Step 3: Create a dev flow
-
+
First, create a flow. Pick a service in your application to test a dev image on and run:
-
+
```bash
kardinal flow create
```
@@ -151,8 +151,8 @@ kardinal flow create
You should see some output like:
```bash
kardinal flow create frontend kurtosistech/frontend:demo-frontend
-INFO[0000] Using tenant UUID 483e3371-ec18-40ca-aaee-54df597d1fd2
-INFO[0000] Creating service frontend with image kurtosistech/frontend:demo-frontend in development mode...
+INFO[0000] Using tenant UUID 483e3371-ec18-40ca-aaee-54df597d1fd2
+INFO[0000] Creating service frontend with image kurtosistech/frontend:demo-frontend in development mode...
Flow "dev-qlm1214pgt" created. Access it on:
🌐 http://dev-qlm1214pgt.app.localhost
```
@@ -161,14 +161,14 @@ You can view all the flows in your cluster in the Kardinal dashboard:
```bash
kardinal dashboard
-```
+```
If you run `kardinal gateway `, Kardinal will open a gateway to the entrypoint of the flow - whatever service of your application was annotated with the `kardinal.dev.service/ingress` annotation. Whether the service is a frontend or a backend service, you will be able to access the dev flow by making requests to the returned endpoint.
-
+
```bash
$ kardinal gateway dev-qlm1214pgt
-INFO[0000] Using tenant UUID 483e3371-ec18-40ca-aaee-54df597d1fd2
+INFO[0000] Using tenant UUID 483e3371-ec18-40ca-aaee-54df597d1fd2
2024/08/07 13:50:52 Starting gateway for host: dev-qlm1214pgt.app.localhost
-2024/08/07 13:50:52 All pods in namespace prod are ready and flowId dev-qlm1214pgt found
+2024/08/07 13:50:52 All pods in namespace baseline are ready and flowId dev-qlm1214pgt found
2024/08/07 13:50:52 Proxy server for host dev-qlm1214pgt.app.localhost started on http://localhost:9060
```
diff --git a/website/app/docs/references/comparisons/page.mdx b/website/app/docs/references/comparisons/page.mdx
index 8f3a8278..ce23f64e 100644
--- a/website/app/docs/references/comparisons/page.mdx
+++ b/website/app/docs/references/comparisons/page.mdx
@@ -29,7 +29,7 @@ Devcontainers can connect your coding workflow into your Kardinal [flows](./conc
Some teams create ephemeral development environments by deploying changed services into a new namespace into their Kubernetes cluster.
-Then, they configure rules per namespace that defines what is shared between that development namespace, and the "stable" shared namespace. These shared resources include the state that backs the applciation (dbs, queues, caches), as well as shared microservices.
+Then, they configure rules per namespace that defines what is shared between that development namespace, and the "baseline" shared namespace. These shared resources include the state that backs the applciation (dbs, queues, caches), as well as shared microservices.
This is a sophisticated approach that can be very effective. Using this approach is similar to using Kardinal in "single-service" and "multi-service" mode, in the sense of creating flows that can contain one or more development versions of services.
@@ -70,4 +70,4 @@ If you want to test custom CRDs, or other Kubernetes-specific things like oeprat
However if you're just testing application-level changes, Kardinal will provide the deploys you need in an lighter-weight way.
You could use vclusters alongside Kardinal - vclusters would provision virtual Kubernetes clusters, and then within those virtual clusters, you could use Kardinal to further do multiple application deploys for dev or test purposes.
-
\ No newline at end of file
+
diff --git a/website/app/globals.css b/website/app/globals.css
deleted file mode 100644
index 1ea4ebf3..00000000
--- a/website/app/globals.css
+++ /dev/null
@@ -1,162 +0,0 @@
-:root {
- color-scheme: only light;
-
- --max-width: 1248px;
- --border-radius: 4px;
-
- /* --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", */
- /* "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", */
- /* "Fira Mono", "Droid Sans Mono", "Courier New", monospace; */
-
- /* color vars */
- --brand-primary: #ff602C;
- --brand-primary-dark: rgba(168, 50, 5, 0.4);
- --brand-secondary: #FCA061;
- --gradient-from-bg: linear-gradient(84deg, transparent 0%, white 100%);
- --gradient-to-bg: linear-gradient(180deg, transparent 0%, white 100%);
-
- --gradient-brand: linear-gradient(to right, var(--brand-primary), var(--brand-secondary));
- --gradient-brand-reverse: linear-gradient(to right, var(--brand-secondary), var(--brand-primary));
-
- --gradient-brand-dark: linear-gradient(90deg, #fCA061, rgba(168, 50, 5, 0.4));
- --white-10: rgba(255, 255, 255, 0.1);
- --white-20: rgba(255, 255, 255, 0.2);
- --white-40: rgba(255, 255, 255, 0.4);
- --white-60: rgba(255, 255, 255, 0.6);
- --white-70: rgba(255, 255, 255, 0.7);
- --white-90: rgba(255, 255, 255, 0.9);
- --white-100: #ffffff;
-
- /* TODO: too many grays... consolidate */
- --gray-100: #F3F4F6;
- --gray-200: #E5E7EB;
- --gray-400: #9CA3AF;
- --gray-600: #4b5563;
- --gray-bg-light: #212121;
- --gray-bg: #1f232a;
- --gray-dark: #21262d;
- --gray-diagramlines: #666a6f;
- --gray-icon: #8b949e;
- --gray-light: #aaa;
- --gray-lighter: #f2f2f2;
- --gray-lightest: #fafafa;
- --gray: #525157;
-
- --blue: #1F56A5;
- --blue-light: #58A6FF;
-
- --black: #000330;
- --white: #ffffff;
-
- /* semantic vars */
- --foreground: var(--gray);
- --foreground-dark: var(--black);
- --foreground-light: var(--gray-light);
-
- --foreground-inverted: var(--gray-light);
- --foreground-dark-inverted: var(--gray-lighter);
-
- --background: var(--white);
- --background-light: var(--gray-bg-light, #212121);
- --background-dark: var(--gray-bg-dark, #21262d);
-
- --background-contrast: #fff9f2;
- --background-inverted: var(--gray-bg);
-
- --gray-border: #ddd;
-}
-
-* {
- -moz-font-feature-settings: "liga" on;
- -moz-osx-font-smoothing: grayscale;
- -webkit-font-smoothing: antialiased;
- box-sizing: border-box;
- font-smooth: always;
- margin: 0;
- padding: 0;
- text-rendering: optimizeLegibility;
-}
-
-html,
-body {
- background: var(--background);
- overflow-x: hidden;
- scroll-behavior: smooth;
-}
-
-body {
- color: var(--foreground);
-}
-
-a {
- color: inherit;
- text-decoration: none;
-}
-
-em {
- font-weight: 500;
- background: var(--gradient-brand-reverse);
- background-size: auto;
- background-clip: border-box;
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- font-style: normal;
-}
-
-s {
- text-decoration: none;
- position: relative;
- display: inline-block;
-}
-
-s:after {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-image: url("/scribble-animated.svg");
- background-size: 100%;
- background-repeat: no-repeat;
-}
-
-hr {
- border: 0;
- border-bottom: 1px solid var(--gray-border);
-}
-
-br[data-mobile="true"] {
- display: none;
-}
-
-@media (max-width: 768px) {
- br[data-desktop="true"] {
- display: none;
- }
- br[data-mobile="true"] {
- display: block;
- }
-}
-
-html {
- color-scheme: light;
-}
-
-pre {
- background-color: var(--gray-bg) !important;
- padding: 12px !important;
-}
-
-code {
- line-height: 1.6;
- font-size: 14px;
- font-style: normal;
- font-weight: 400;
-}
-
-@media (max-width: 768px) {
- code {
- font-size: 14px;
- }
-}
diff --git a/website/app/layout.tsx b/website/app/layout.tsx
index 178655ea..506fcc22 100644
--- a/website/app/layout.tsx
+++ b/website/app/layout.tsx
@@ -2,21 +2,15 @@ import { GoogleTagManager } from "@next/third-parties/google";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { ReactNode } from "react";
-import { Suspense } from "react";
import Footer from "@/components/Footer";
import Main from "@/components/Main";
import Modal from "@/components/Modal";
import Nav from "@/components/Nav";
import SegmentAnalytics from "@/components/SegmentAnalytics";
-import { CalculatorProvider } from "@/context/CalculatorContext";
-import { ModalProvider } from "@/context/ModalContext";
-import { VotingProvider } from "@/context/VotingContext";
-import StyledComponentsRegistry from "../lib/registry";
-
-import "react-responsive-carousel/lib/styles/carousel.min.css";
-import "./globals.css";
+import GlobalStyles from "./GlobalStyles";
+import Providers from "./Providers";
const inter = Inter({
subsets: ["latin"],
@@ -37,7 +31,7 @@ export default function RootLayout({
children: ReactNode;
}>) {
return (
-
+
-
-
-
-
-
-
- {children}
-
-
-
-
-
-
-
+
+
+
+ {children}
+
+
+
);
diff --git a/website/context/CalculatorContext.tsx b/website/context/CalculatorContext.tsx
index 6ce3971d..bd979574 100644
--- a/website/context/CalculatorContext.tsx
+++ b/website/context/CalculatorContext.tsx
@@ -1,6 +1,5 @@
"use client";
-import { useSearchParams } from "next/navigation";
import {
createContext,
Dispatch,
@@ -43,7 +42,9 @@ const HOURLY_COST_PER_RESOURCE_REQUIREMENT: Record<
};
export const CalculatorProvider = ({ children }: PropsWithChildren) => {
- const searchParams = useSearchParams();
+ const searchParams = new URLSearchParams(
+ typeof window !== "undefined" ? window.location.search : "",
+ );
const initialEngineers: number =
searchParams.get("engineers") != null
diff --git a/website/next.config.mjs b/website/next.config.mjs
index d27228be..df1c20f5 100644
--- a/website/next.config.mjs
+++ b/website/next.config.mjs
@@ -6,13 +6,13 @@ const config = {
distDir: "out",
pageExtensions: ["mdx", "ts", "tsx"],
compiler: {
- styledComponents: true,
+ styledComponents: {
+ ssr: true,
+ displayName: true,
+ },
},
- ...(process.env.NODE_ENV === "production"
- ? {
- output: "export", // static export for production build
- }
- : {}),
+ output: "export",
+
// If localhost proxy is required (e.g. for CORS), uncomment this
// async rewrites() {
// return [