Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[full-ci][tests-only]Add support to stop and start service in ociswrapper #10776

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions tests/acceptance/TestHelpers/OcisConfigHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,19 @@ public static function startOcis(): ResponseInterface {
$url = self::getWrapperUrl() . "/start";
return self::sendRequest($url, "POST");
}

/**
* this method stops the running oCIS instance,
* restarts it while excluding specific services,
* and then starts the excluded services separately.
*
* @param string $service
*
* @return ResponseInterface
* @throws GuzzleException
*/
public static function startService(string $service): ResponseInterface {
$url = self::getWrapperUrl() . "/services/" . $service;
return self::sendRequest($url, "POST");
}
}
18 changes: 18 additions & 0 deletions tests/acceptance/bootstrap/OcisConfigContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,24 @@ public function theConfigHasBeenSetToValue(TableNode $table): void {
);
}

/**
* @Given the ocis server has started service :service separately
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @Given the ocis server has started service :service separately
* @Given the administrator has started service :service separately

*
* @param string $service
*
* @return void
* @throws GuzzleException
*/
public function theOcisServerHasStartedServiceSeparately(string $service) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public function theOcisServerHasStartedServiceSeparately(string $service) {
public function theAdministratorHasStartedServiceSeparately(string $service) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public function theOcisServerHasStartedServiceSeparately(string $service) {
public function theOcisServerHasStartedServiceSeparately(string $service): void {

$response = OcisConfigHelper::startService($service);

Assert::assertEquals(
200,
$response->getStatusCode(),
"Failed to start service $service."
);
}

/**
* @AfterScenario @env-config
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Feature: service health check
Then the HTTP status code of responses on all endpoints should be "200"

@issue-10661
Scenario: check default services readiness
Scenario: check default services readiness (graph, idp, proxy)
When a user requests these URLs with "GET" and no authentication
| endpoint | service |
| http://%base_url_hostname%:9124/readyz | graph |
Expand All @@ -122,7 +122,7 @@ Feature: service health check
Then the HTTP status code of responses on all endpoints should be "200"

@env-config @issue-10661
Scenario: check extra services readiness
Scenario: check auth-bearer service readiness
Given the following configs have been set:
| config | value |
| OCIS_ADD_RUN_SERVICES | auth-bearer |
Expand All @@ -131,3 +131,11 @@ Feature: service health check
| endpoint | service |
| http://%base_url_hostname%:9149/readyz | auth-bearer |
Then the HTTP status code of responses on all endpoints should be "200"

@env-config
Scenario: check services health while running separately
Given the ocis server has started service "storage-users" separately
When a user requests these URLs with "GET" and no authentication
| endpoint | service |
| http://%base_url_hostname%:9159/healthz | storage-users |
Then the HTTP status code of responses on all endpoints should be "200"
Comment on lines +135 to +141
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a debug scenario?

Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ Feature: backup consistency
And the administrator has started the server
When user "Alice" gets the number of versions of file "/textfile0.txt"
Then the HTTP status code should be "207"
And the number of versions should be "2"
And the number of versions should be "2"
28 changes: 28 additions & 0 deletions tests/ociswrapper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,31 @@ Also, see `./bin/ociswrapper help` for more information.

- `200 OK` - oCIS server is stopped
- `500 Internal Server Error` - Unable to stop oCIS server

6. `POST /services/{service-name}`

Restart oCIS with service excluded and start excluded oCIS service individually, not covered by the oCIS supervisor.

Body of the request should be a JSON object with the following structure:

```json
{
"ENV_KEY1": "value1",
"ENV_KEY2": "value2"
}
```

Returns:

- `200 OK` - oCIS server is stopped
- `500 Internal Server Error` - Unable to stop oCIS server

7. `DELETE /services/{service-name}`

Stop individually running oCIS service

Returns:

- `200 OK` - command is successfully executed
- `400 Bad Request` - request body is not a valid JSON object
- `500 Internal Server Error`
239 changes: 142 additions & 97 deletions tests/ociswrapper/ocis/ocis.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,110 +26,21 @@ var cmd *exec.Cmd
var retryCount = 0
var stopSignal = false
var EnvConfigs = []string{}
var runningServices = make(map[string]int)

func Start(envMap []string) {
// wait for the log scanner to finish
var wg sync.WaitGroup
wg.Add(2)

stopSignal = false
if retryCount == 0 {
defer common.Wg.Done()
}

cmd = exec.Command(config.Get("bin"), "server")
if envMap == nil {
cmd.Env = append(os.Environ(), EnvConfigs...)
} else {
cmd.Env = append(os.Environ(), envMap...)
}

logs, err := cmd.StderrPipe()
if err != nil {
log.Panic(err)
}
output, err := cmd.StdoutPipe()
if err != nil {
log.Panic(err)
}

err = cmd.Start()
if err != nil {
log.Panic(err)
}

logScanner := bufio.NewScanner(logs)
outputScanner := bufio.NewScanner(output)
outChan := make(chan string)

// Read the logs when the 'ocis server' command is running
go func() {
defer wg.Done()
for logScanner.Scan() {
outChan <- logScanner.Text()
}
}()

go func() {
defer wg.Done()
for outputScanner.Scan() {
outChan <- outputScanner.Text()
}
}()

// Fetch logs from the channel and print them
go func() {
for s := range outChan {
fmt.Println(s)
}
}()

if err := cmd.Wait(); err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
status := exitErr.Sys().(syscall.WaitStatus)
// retry only if oCIS server exited with code > 0
// -1 exit code means that the process was killed by a signal (syscall.SIGINT)
if status.ExitStatus() > 0 && !stopSignal {
waitUntilCompleteShutdown()

log.Println(fmt.Sprintf("oCIS server exited with code %v", status.ExitStatus()))

// retry to start oCIS server
retryCount++
maxRetry, _ := strconv.Atoi(config.Get("retry"))
if retryCount <= maxRetry {
wg.Wait()
close(outChan)
log.Println(fmt.Sprintf("Retry starting oCIS server... (retry %v)", retryCount))
// wait 500 milliseconds before retrying
time.Sleep(500 * time.Millisecond)
Start(envMap)
return
}
}
}
}
wg.Wait()
close(outChan)
log.Println("Starting oCIS service........\n")
StartService("", envMap)
}

func Stop() (bool, string) {
log.Println("Stopping oCIS server...")
stopSignal = true

if cmd == nil {
return true, "oCIS server is not running"
for service := range runningServices {
go StopService(service)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be waited

}

err := cmd.Process.Signal(syscall.SIGINT)
if err != nil {
if !strings.HasSuffix(err.Error(), "process already finished") {
log.Fatalln(err)
} else {
return true, "oCIS server is already stopped"
}
}
cmd.Process.Wait()
success, message := waitUntilCompleteShutdown()

cmd = nil
Expand All @@ -147,10 +58,16 @@ func Restart(envMap []string) (bool, string) {
}

func IsOcisRunning() bool {
if cmd != nil {
return cmd.Process.Pid > 0
if runningServices["ocis"] == 0 {
return false
}
return false

_, err := os.FindProcess(runningServices["ocis"])
if err != nil {
delete(runningServices, "ocis")
return false
}
return true
}

func waitAllServices(startTime time.Time, timeout time.Duration) {
Expand Down Expand Up @@ -271,3 +188,131 @@ func RunCommand(command string, inputs []string) (int, string) {

return c.ProcessState.ExitCode(), cmdOutput
}

func StartService(service string, envMap []string) {
// Initialize command args based on service presence
cmdArgs := []string{"server"} // Default command args

if service != "" {
cmdArgs = append([]string{service}, cmdArgs...)
}

var wg sync.WaitGroup
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var wg sync.WaitGroup
// wait for the log scanner to finish
var wg sync.WaitGroup

wg.Add(2)

stopSignal = false
if retryCount == 0 {
defer common.Wg.Done()
}

cmd = exec.Command(config.Get("bin"), cmdArgs...)

if len(envMap) == 0 {
cmd.Env = append(os.Environ(), EnvConfigs...)
} else {
cmd.Env = append(os.Environ(), envMap...)
}

logs, err := cmd.StderrPipe()
if err != nil {
log.Panic(err)
}
output, err := cmd.StdoutPipe()
if err != nil {
log.Panic(err)
}

err = cmd.Start()

if err != nil {
log.Panic(err)
}

logScanner := bufio.NewScanner(logs)
outputScanner := bufio.NewScanner(output)
outChan := make(chan string)

if service == "" {
runningServices["ocis"] = cmd.Process.Pid
} else {
runningServices[service] = cmd.Process.Pid
}

for listService, pid := range runningServices {
log.Println(fmt.Sprintf("%s service started with process id %v\n", listService, pid))
}

// Read the logs when the 'ocis server' command is running
go func() {
defer wg.Done()
for logScanner.Scan() {
outChan <- logScanner.Text()
}
}()

go func() {
defer wg.Done()
for outputScanner.Scan() {
outChan <- outputScanner.Text()
}
}()

// Fetch logs from the channel and print them
go func() {
for s := range outChan {
fmt.Println(s)
}
}()

if err := cmd.Wait(); err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
status := exitErr.Sys().(syscall.WaitStatus)
// retry only if oCIS server exited with code > 0
// -1 exit code means that the process was killed by a signal (syscall.SIGINT)
if status.ExitStatus() > 0 && !stopSignal {
waitUntilCompleteShutdown()

log.Println(fmt.Sprintf("oCIS server exited with code %v", status.ExitStatus()))

// retry to start oCIS server
retryCount++
maxRetry, _ := strconv.Atoi(config.Get("retry"))
if retryCount <= maxRetry {
wg.Wait()
close(outChan)
log.Println(fmt.Sprintf("Retry starting oCIS server... (retry %v)", retryCount))
// wait 500 milliseconds before retrying
time.Sleep(500 * time.Millisecond)
StartService(service, envMap)
return
}
}
}
}
wg.Wait()
close(outChan)
}

// Stop oCIS service or a specific service by its unique identifier
func StopService(service string) (bool, string) {
pid, exists := runningServices[service]
if !exists {
return false, fmt.Sprintf("Running service doesn't not include %s service", service)
}

process, err := os.FindProcess(pid)
if err != nil {
return false, fmt.Sprintf("Failed to find service %s process running with ID %d", service, pid)
}

pKillError := process.Signal(syscall.SIGINT)
if pKillError != nil {
return false, fmt.Sprintf("Failed to stop service with process id %d", pid)
} else {
delete(runningServices, service)

log.Println(fmt.Sprintf("oCIS service %s has been stopped successfully", service))
}

return true, fmt.Sprintf("Service %s stopped successfully", service)
}
Loading