Skip to content

Commit

Permalink
Merge pull request #4 from grycap/devel
Browse files Browse the repository at this point in the history
Devel
  • Loading branch information
srisco authored Jul 16, 2021
2 parents 9b87599 + c85928f commit c626d6b
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 33 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ go get github.com/grycap/oscar-cli
- [get](#get)
- [list](#list-1)
- [remove](#remove-1)
- [run](#run)
- [logs list](#logs-list)
- [logs get](#logs-get)
- [logs remove](#logs-remove)
Expand Down Expand Up @@ -222,6 +223,28 @@ Global Flags:
--config string set the location of the config file (YAML or JSON)
```

##### run

Invoke a service synchronously (a Serverless backend in the cluster is required).

```
Usage:
oscar-cli service run SERVICE_NAME {--input | --text-input} [flags]
Aliases:
run, invoke, r
Flags:
-c, --cluster string set the cluster
-h, --help help for run
-i, --input string input file for the request
-o, --output string file path to store the output
-t, --text-input string text input string for the request
Global Flags:
--config string set the location of the config file (YAML or JSON)
```

##### logs list

List the logs from a service.
Expand Down
1 change: 1 addition & 0 deletions cmd/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func makeServiceCmd() *cobra.Command {
serviceCmd.AddCommand(makeServiceGetFileCmd())
serviceCmd.AddCommand(makeServicePutFileCmd())
serviceCmd.AddCommand(makeServiceListFilesCmd())
serviceCmd.AddCommand(makeServiceRunCmd())

return serviceCmd
}
129 changes: 129 additions & 0 deletions cmd/service_run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
Copyright (C) GRyCAP - I3M - UPV
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"io"
"os"

"github.com/grycap/oscar-cli/pkg/config"
"github.com/grycap/oscar-cli/pkg/service"
"github.com/spf13/cobra"
)

func serviceRunFunc(cmd *cobra.Command, args []string) error {
// Read the config file
conf, err := config.ReadConfig(configPath)
if err != nil {
return err
}

cluster, err := getCluster(cmd, conf)
if err != nil {
return err
}

// Parse input (only --input or --text-input are allowed) (AND one of them is required)
inputFile, _ := cmd.Flags().GetString("input")
textInput, _ := cmd.Flags().GetString("text-input")
outputFile, _ := cmd.Flags().GetString("output")
if inputFile == "" && textInput == "" {
return errors.New("you must specify \"--input\" or \"--text-input\" flag")
}
if inputFile != "" && textInput != "" {
return errors.New("you only can specify one of \"--input\" or \"--text-input\" flags")
}

var inputReader io.Reader = bytes.NewBufferString(textInput)

if inputFile != "" {
// Open the file
file, err := os.Open(inputFile)
defer file.Close()
if err != nil {
return fmt.Errorf("unable to read the file \"%s\"", inputFile)
}
// Set the file as the inputReader
inputReader = file
}

// Make pipe to encode file stream
reader, writer := io.Pipe()
encoder := base64.NewEncoder(base64.StdEncoding, writer)

// Copy the file to the encoder in a goroutine to avoid blocking the execution
go func() {
_, err := io.Copy(encoder, inputReader)
encoder.Close()
if err != nil {
writer.CloseWithError(err)
}
writer.Close()
}()

// Make the request
resBody, err := service.RunService(conf.Oscar[cluster], args[0], reader)
if err != nil {
return err
}
defer resBody.Close()

// Decode the result body
decoder := base64.NewDecoder(base64.StdEncoding, resBody)

// Parse output (store file if --output is set)
var out io.Writer = os.Stdout

// Create the file if --output is set
if outputFile != "" {
outFile, err := os.Create(outputFile)
if err != nil {
return fmt.Errorf("unable to create the file \"%s\"", outputFile)
}
defer outFile.Close()
out = outFile
}

// Copy the decoder stream into out
_, err = io.Copy(out, decoder)
if err != nil {
return errors.New("unable to copy the response")
}

return nil
}

func makeServiceRunCmd() *cobra.Command {
serviceRunCmd := &cobra.Command{
Use: "run SERVICE_NAME {--input | --text-input}",
Short: "Invoke a service synchronously (a Serverless backend in the cluster is required)",
Args: cobra.ExactArgs(1),
Aliases: []string{"invoke", "r"},
RunE: serviceRunFunc,
}

serviceRunCmd.Flags().StringP("cluster", "c", "", "set the cluster")
serviceRunCmd.Flags().StringP("input", "i", "", "input file for the request")
serviceRunCmd.Flags().StringP("text-input", "t", "", "text input string for the request")
serviceRunCmd.Flags().StringP("output", "o", "", "file path to store the output")

return serviceRunCmd
}
6 changes: 3 additions & 3 deletions pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ func (cluster *Cluster) GetClient() *http.Client {

// GetClusterInfo returns info from an OSCAR cluster
func (cluster *Cluster) GetClusterInfo() (info types.Info, err error) {
getInfoUrl, err := url.Parse(cluster.Endpoint)
getInfoURL, err := url.Parse(cluster.Endpoint)
if err != nil {
return info, ErrParsingEndpoint
}
getInfoUrl.Path = path.Join(getInfoUrl.Path, infoPath)
getInfoURL.Path = path.Join(getInfoURL.Path, infoPath)

req, err := http.NewRequest(http.MethodGet, getInfoUrl.String(), nil)
req, err := http.NewRequest(http.MethodGet, getInfoURL.String(), nil)
if err != nil {
return info, ErrMakingRequest
}
Expand Down
32 changes: 16 additions & 16 deletions pkg/service/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ const logsPath = "/system/logs"

// ListLogs returns a map with all the available logs from the given service
func ListLogs(c *cluster.Cluster, name string) (logMap map[string]*types.JobInfo, err error) {
listLogsUrl, err := url.Parse(c.Endpoint)
listLogsURL, err := url.Parse(c.Endpoint)
if err != nil {
return logMap, cluster.ErrParsingEndpoint
}
listLogsUrl.Path = path.Join(listLogsUrl.Path, logsPath, name)
listLogsURL.Path = path.Join(listLogsURL.Path, logsPath, name)

req, err := http.NewRequest(http.MethodGet, listLogsUrl.String(), nil)
req, err := http.NewRequest(http.MethodGet, listLogsURL.String(), nil)
if err != nil {
return logMap, cluster.ErrMakingRequest
}
Expand All @@ -63,19 +63,19 @@ func ListLogs(c *cluster.Cluster, name string) (logMap map[string]*types.JobInfo

// GetLogs get the logs from a service's job
func GetLogs(c *cluster.Cluster, svcName string, jobName string, timestamps bool) (logs string, err error) {
getLogsUrl, err := url.Parse(c.Endpoint)
getLogsURL, err := url.Parse(c.Endpoint)
if err != nil {
return logs, cluster.ErrParsingEndpoint
}
getLogsUrl.Path = path.Join(getLogsUrl.Path, logsPath, svcName, jobName)
getLogsURL.Path = path.Join(getLogsURL.Path, logsPath, svcName, jobName)

if timestamps {
q := getLogsUrl.Query()
q := getLogsURL.Query()
q.Set("timestamps", "true")
getLogsUrl.RawQuery = q.Encode()
getLogsURL.RawQuery = q.Encode()
}

req, err := http.NewRequest(http.MethodGet, getLogsUrl.String(), nil)
req, err := http.NewRequest(http.MethodGet, getLogsURL.String(), nil)
if err != nil {
return logs, cluster.ErrMakingRequest
}
Expand All @@ -101,13 +101,13 @@ func GetLogs(c *cluster.Cluster, svcName string, jobName string, timestamps bool

// RemoveLog removes the specified log (jobName) from a service in the cluster
func RemoveLog(c *cluster.Cluster, svcName, jobName string) error {
removeLogUrl, err := url.Parse(c.Endpoint)
removeLogURL, err := url.Parse(c.Endpoint)
if err != nil {
return cluster.ErrParsingEndpoint
}
removeLogUrl.Path = path.Join(removeLogUrl.Path, logsPath, svcName, jobName)
removeLogURL.Path = path.Join(removeLogURL.Path, logsPath, svcName, jobName)

req, err := http.NewRequest(http.MethodDelete, removeLogUrl.String(), nil)
req, err := http.NewRequest(http.MethodDelete, removeLogURL.String(), nil)
if err != nil {
return cluster.ErrMakingRequest
}
Expand All @@ -127,19 +127,19 @@ func RemoveLog(c *cluster.Cluster, svcName, jobName string) error {

// RemoveLogs removes completed or all logs (jobs) from a service in the cluster
func RemoveLogs(c *cluster.Cluster, svcName string, all bool) error {
removeLogsUrl, err := url.Parse(c.Endpoint)
removeLogsURL, err := url.Parse(c.Endpoint)
if err != nil {
return cluster.ErrParsingEndpoint
}
removeLogsUrl.Path = path.Join(removeLogsUrl.Path, logsPath, svcName)
removeLogsURL.Path = path.Join(removeLogsURL.Path, logsPath, svcName)

if all {
q := removeLogsUrl.Query()
q := removeLogsURL.Query()
q.Set("all", "true")
removeLogsUrl.RawQuery = q.Encode()
removeLogsURL.RawQuery = q.Encode()
}

req, err := http.NewRequest(http.MethodDelete, removeLogsUrl.String(), nil)
req, err := http.NewRequest(http.MethodDelete, removeLogsURL.String(), nil)
if err != nil {
return cluster.ErrMakingRequest
}
Expand Down
Loading

0 comments on commit c626d6b

Please sign in to comment.