Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Vr00mm authored Oct 17, 2023
2 parents 8eb7154 + 49fc5b0 commit 35789e4
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 53 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
- name: Get tag
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF##*/})"
run: echo "branch=$(echo ${GITHUB_REF##*/})" >> $GITHUB_OUTPUT
id: tag

- name: Building litmusctl
Expand All @@ -55,4 +55,4 @@ jobs:

- name: Copy binaries to the litmusctl s3 bucket
run: |
aws s3 sync platforms-${{ steps.tag.outputs.branch }} s3://${{ secrets.AWS_S3_BUCKET }}
aws s3 sync platforms-${{ steps.tag.outputs.branch }} s3://${{ secrets.AWS_S3_BUCKET }}
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ For more information including a complete list of litmusctl operations, see the
* For v0.12.0 or latest:
* Non-Interactive mode: <a href="https://github.com/litmuschaos/litmusctl/blob/master/Usage.md">Click here</a>
* Interactive mode: <a href="https://github.com/litmuschaos/litmusctl/blob/master/Usage_interactive.md">Click here</a>
* For 0.23.0: <a href="https://github.com/litmuschaos/litmusctl/blob/master/Usage_0.23.0.md">Click here</a>
* For v0.2.0 or earlier && compatible with Litmus-2.0.0-Beta8 or earlier: <a href="https://github.com/litmuschaos/litmusctl/blob/master/Usage_v0.2.0.md">Click here</a>

## Requirements
Expand Down Expand Up @@ -108,7 +109,12 @@ To check compatibility of litmusctl with Chaos Center
<tr>
<td>0.23.0</td>
<td>3.0.0-beta9</td>
<td>3.0.0-beta11</td>
<td>3.0.0-beta12</td>
</tr>
<tr>
<td>0.24.0</td>
<td>3.0.0-beta9</td>
<td>3.0.0-beta12</td>
</tr>
</table>

Expand All @@ -118,109 +124,109 @@ To install the latest version of litmusctl follow the below steps:

<table>
<th>Platforms</th>
<th>0.24.0</th>
<th>0.23.0</th>
<th>0.22.0</th>
<th>0.21.0</th>
<th>0.20.0</th>
<th>0.19.0</th>
<th>0.18.0</th>
<th>0.17.0</th>
<th>0.16.0</th>
<th>master(Unreleased)</th>
<tr>
<td>litmusctl-darwin-amd64 (MacOS)</td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-0.24.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-0.23.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-0.22.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-0.21.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-0.20.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-0.19.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-0.18.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-0.17.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-0.16.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-master.tar.gz">Click here</a></td>
</tr>
<tr>
<td>litmusctl-linux-386</td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-0.24.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-0.23.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-0.22.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-0.21.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-0.20.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-0.19.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-0.18.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-0.17.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-0.16.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-master.tar.gz">Click here</a></td>
</tr>
<tr>
<td>litmusctl-linux-amd64</td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-0.24.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-0.23.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-0.22.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-0.21.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-0.20.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-0.19.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-0.18.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-0.17.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-0.16.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-master.tar.gz">Click here</a></td>
</tr>
<tr>
<td>litmusctl-linux-arm</td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-0.24.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-0.23.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-0.22.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-0.21.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-0.20.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-0.19.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-0.18.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-0.17.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-0.16.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-master.tar.gz">Click here</a></td>
</tr>
<tr>
<td>litmusctl-linux-arm64</td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-0.24.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-0.23.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-0.22.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-0.21.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-0.20.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-0.19.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-0.18.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-0.17.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-0.16.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-master.tar.gz">Click here</a></td>
</tr>
<tr>
<td>litmusctl-windows-386</td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-0.24.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-0.23.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-0.22.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-0.21.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-0.20.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-0.19.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-0.18.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-0.17.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-0.16.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-master.tar.gz">Click here</a></td>
</tr>
<tr>
<td>litmusctl-windows-amd64</td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-0.24.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-0.23.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-0.22.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-0.21.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-0.20.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-0.19.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-0.18.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-0.17.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-0.16.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-master.tar.gz">Click here</a></td>
</tr>
<tr>
<td>litmusctl-windows-arm</td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-0.24.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-0.23.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-0.22.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-0.21.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-0.20.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-0.19.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-0.18.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-0.17.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-0.16.0.tar.gz">Click here</a></td>
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-master.tar.gz">Click here</a></td>
</tr>
</table>
Expand Down
40 changes: 20 additions & 20 deletions pkg/apis/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,29 @@ type manifestData struct {
}

type data struct {
GetManifest string `json:"getManifest"`
GetManifest string `json:"getInfraManifest"`
}

type InfrasData struct {
Data GetInfraDetails `json:"data"`
type GetInfraResponse struct {
Data GetInfraData `json:"data"`
Errors []struct {
Message string `json:"message"`
Path []string `json:"path"`
} `json:"errors"`
}

type GetInfraDetails struct {
GetInfraDetails InfrasDetails `json:"getAgentDetails"`
type GetInfraData struct {
GetInfraDetails InfraDetails `json:"getInfraDetails"`
}

type InfrasDetails struct {
type InfraDetails struct {
InfraID string `json:"infraID"`
InfraNamespace *string `json:"infraNamespace"`
}

func UpgradeInfra(c context.Context, cred types.Credentials, projectID string, infraID string, kubeconfig string) (string, error) {

// Query to fetch agent details from server
// Query to fetch Infra details from server
query := `{"query":"query {\n getInfraDetails(infraID : \"` + infraID + `\", \n projectID : \"` + projectID + `\"){\n infraNamespace infraID \n}}"}`
resp, err := SendRequest(SendRequestParams{Endpoint: cred.Endpoint + utils.GQLAPIPath, Token: cred.Token}, []byte(query), string(types.Post))
if err != nil {
Expand All @@ -61,7 +61,7 @@ func UpgradeInfra(c context.Context, cred types.Credentials, projectID string, i
}

defer resp.Body.Close()
var infra InfrasData
var infra GetInfraResponse

if resp.StatusCode == http.StatusOK {
err = json.Unmarshal(bodyBytes, &infra)
Expand Down Expand Up @@ -102,27 +102,27 @@ func UpgradeInfra(c context.Context, cred types.Credentials, projectID string, i
}

// To write the manifest data into a temporary file
err = ioutil.WriteFile("chaos-delegate-manifest.yaml", []byte(manifest.Data.GetManifest), 0644)
err = ioutil.WriteFile("chaos-infra-manifest.yaml", []byte(manifest.Data.GetManifest), 0644)
if err != nil {
return "", err
}

// Fetching agent-config from the subscriber
configData, err := k8s.GetConfigMap(c, "agent-config", *infra.Data.GetInfraDetails.InfraNamespace)
// Fetching subscriber-config from the subscriber
configData, err := k8s.GetConfigMap(c, "subscriber-config", *infra.Data.GetInfraDetails.InfraNamespace)
if err != nil {
return "", err
}
var configMapString string

metadata := new(bytes.Buffer)
fmt.Fprintf(metadata, "\n%s: %s\n%s: %s\n%s: \n %s: %s\n %s: %s\n%s:\n", "apiVersion", "v1",
"kind", "ConfigMap", "metadata", "name", "agent-config", "namespace", *infra.Data.GetInfraDetails.InfraNamespace, "data")
"kind", "ConfigMap", "metadata", "name", "subscriber-config", "namespace", *infra.Data.GetInfraDetails.InfraNamespace, "data")

for k, v := range configData {
b := new(bytes.Buffer)
if k == "COMPONENTS" {
fmt.Fprintf(b, " %s: |\n %s", k, v)
} else if k == "START_TIME" || k == "IS_CLUSTER_CONFIRMED" {
} else if k == "START_TIME" || k == "IS_INFRA_CONFIRMED" {
fmt.Fprintf(b, " %s: \"%s\"\n", k, v)
} else {
fmt.Fprintf(b, " %s: %s\n", k, v)
Expand All @@ -134,30 +134,30 @@ func UpgradeInfra(c context.Context, cred types.Credentials, projectID string, i
yamlOutput, err := k8s.ApplyYaml(k8s.ApplyYamlPrams{
Token: cred.Token,
Endpoint: cred.Endpoint,
YamlPath: "chaos-delegate-manifest.yaml",
YamlPath: "chaos-infra-manifest.yaml",
}, kubeconfig, true)

if err != nil {
return "", err
}
utils.White.Print("\n", yamlOutput)

err = os.Remove("chaos-delegate-manifest.yaml")
err = os.Remove("chaos-infra-manifest.yaml")
if err != nil {
return "Error removing Chaos Delegate manifest: ", err
return "Error removing Chaos Infrastructure manifest: ", err
}

// Creating a backup for current agent-config in the SUBSCRIBER
// Creating a backup for current subscriber-config in the SUBSCRIBER
home, err := homedir.Dir()
cobra.CheckErr(err)

configMapString = metadata.String() + configMapString
err = ioutil.WriteFile(home+"/backupAgentConfig.yaml", []byte(configMapString), 0644)
err = ioutil.WriteFile(home+"/backupSubscriberConfig.yaml", []byte(configMapString), 0644)
if err != nil {
return "Error creating backup for agent config: ", err
return "Error creating backup for subscriber config: ", err
}

utils.White_B.Print("\n ** A backup of agent-config configmap has been saved in your system's home directory as backupAgentConfig.yaml **\n")
utils.White_B.Print("\n ** A backup of subscriber-config configmap has been saved in your system's home directory as backupSubscriberConfig.yaml **\n")

return "Manifest applied successfully", nil
} else {
Expand Down
24 changes: 12 additions & 12 deletions pkg/cmd/connect/infra.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import (
"github.com/litmuschaos/litmusctl/pkg/completion"

"github.com/litmuschaos/litmusctl/pkg/apis"
"github.com/litmuschaos/litmusctl/pkg/infra_ops"
"github.com/litmuschaos/litmusctl/pkg/k8s"
"github.com/litmuschaos/litmusctl/pkg/ops"
"github.com/litmuschaos/litmusctl/pkg/types"
"github.com/litmuschaos/litmusctl/pkg/utils"

Expand Down Expand Up @@ -81,7 +81,7 @@ var infraCmd = &cobra.Command{

if !projectExists {
utils.White_B.Print("Creating a random project...")
newInfra.ProjectId = ops.CreateRandomProject(credentials)
newInfra.ProjectId = infra_ops.CreateRandomProject(credentials)
}
}

Expand Down Expand Up @@ -168,14 +168,14 @@ var infraCmd = &cobra.Command{

// Check if user has sufficient permissions based on mode
utils.White_B.Print("\n🏃 Running prerequisites check....")
ops.ValidateSAPermissions(newInfra.Namespace, newInfra.Mode, &kubeconfig)
infra_ops.ValidateSAPermissions(newInfra.Namespace, newInfra.Mode, &kubeconfig)

// Check if infra already exists
isInfraExist, err, infraList := ops.ValidateInfraNameExists(newInfra.InfraName, newInfra.ProjectId, credentials)
isInfraExist, err, infraList := infra_ops.ValidateInfraNameExists(newInfra.InfraName, newInfra.ProjectId, credentials)
utils.PrintError(err)

if isInfraExist {
ops.PrintExistingInfra(infraList)
infra_ops.PrintExistingInfra(infraList)
os.Exit(1)
}
envIDs, err := environment.GetEnvironmentList(newInfra.ProjectId, credentials)
Expand All @@ -192,7 +192,7 @@ var infraCmd = &cobra.Command{
}
if !isEnvExist {
utils.Red.Println("\nChaos Environment with the given ID doesn't exists.")
ops.PrintExistingEnvironments(envIDs)
infra_ops.PrintExistingEnvironments(envIDs)
utils.White_B.Println("\n❗ Please enter a name from the List or Create a new environment using `litmusctl create chaos-environment`")
os.Exit(1)
}
Expand All @@ -203,25 +203,25 @@ var infraCmd = &cobra.Command{

if newInfra.ProjectId == "" {
// Fetch project id
newInfra.ProjectId = ops.GetProjectID(userDetails)
newInfra.ProjectId = infra_ops.GetProjectID(userDetails)
}

modeType := ops.GetModeType()
modeType := infra_ops.GetModeType()

// Check if user has sufficient permissions based on mode
utils.White_B.Print("\n🏃 Running prerequisites check....")
ops.ValidateSAPermissions(newInfra.Namespace, modeType, &kubeconfig)
newInfra, err = ops.GetInfraDetails(modeType, newInfra.ProjectId, credentials, &kubeconfig)
infra_ops.ValidateSAPermissions(newInfra.Namespace, modeType, &kubeconfig)
newInfra, err = infra_ops.GetInfraDetails(modeType, newInfra.ProjectId, credentials, &kubeconfig)
utils.PrintError(err)

newInfra.ServiceAccount, newInfra.SAExists = k8s.ValidSA(newInfra.Namespace, &kubeconfig)
newInfra.Mode = modeType
}

ops.Summary(newInfra, &kubeconfig)
infra_ops.Summary(newInfra, &kubeconfig)

if !nonInteractive {
ops.ConfirmInstallation()
infra_ops.ConfirmInstallation()
}

infra, err := infrastructure.ConnectInfra(newInfra, credentials)
Expand Down
Loading

0 comments on commit 35789e4

Please sign in to comment.