github.com/projectriff/riff-cli@v0.0.5-0.20180301104501-5db7a3bd9fc1/cmd/publish.go (about) 1 /* 2 * Copyright 2018 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "strings" 21 "fmt" 22 "net/http" 23 "io/ioutil" 24 "time" 25 26 "github.com/spf13/cobra" 27 "github.com/projectriff/riff-cli/pkg/kubectl" 28 "github.com/projectriff/riff-cli/pkg/ioutils" 29 "github.com/projectriff/riff-cli/pkg/minikube" 30 "github.com/projectriff/riff-cli/pkg/jsonpath" 31 "github.com/projectriff/riff-cli/pkg/osutils" 32 "github.com/projectriff/riff-cli/cmd/utils" 33 "github.com/spf13/viper" 34 ) 35 36 type PublishOptions struct { 37 namespace string 38 input string 39 data string 40 reply bool 41 count int 42 pause int 43 } 44 45 var publishOptions PublishOptions 46 47 // publishCmd represents the publish command 48 var publishCmd = &cobra.Command{ 49 Use: "publish", 50 Short: "Publish data to a topic using the http-gateway", 51 Long: `Publish data to a topic using the http-gateway. For example: 52 53 riff publish -i greetings -d hello -r 54 55 will post 'hello' to the 'greetings' topic and wait for a reply. 56 `, 57 Run: func(cmd *cobra.Command, args []string) { 58 59 // get the viper value from env var, config file or flag option 60 publishOptions.namespace = utils.GetStringValueWithOverride("namespace", *cmd.Flags()) 61 62 // look for PUBLISH_NAMESPACE 63 if !cmd.Flags().Changed("namespace") && viper.GetString("PUBLISH_NAMESPACE") != "" { 64 publishOptions.namespace = viper.GetString("PUBLISH_NAMESPACE") 65 fmt.Printf("Using namespace: %s\n", publishOptions.namespace) 66 } else { 67 // look for publishNamespace 68 if !cmd.Flags().Changed("namespace") && viper.GetString("publishNamespace") != "" { 69 publishOptions.namespace = viper.GetString("publishNamespace") 70 fmt.Printf("Using namespace: %s\n", publishOptions.namespace) 71 } 72 } 73 74 cmdArgs := []string{"get", "--namespace", publishOptions.namespace, "svc", "-l", "component=http-gateway", "-o", "json"} 75 output, err := kubectl.ExecForBytes(cmdArgs) 76 77 if err != nil { 78 ioutils.Errorf("Error querying http-gateway %v\n %v\n", err, output) 79 return 80 } 81 82 parser := jsonpath.NewParser(output) 83 84 portType := parser.Value(`$.items[0].spec.type+`) 85 86 if portType == "" { 87 ioutils.Errorf("Unable to locate http-gateway in namespace %v\n", publishOptions.namespace) 88 return 89 } 90 91 var ipAddress string 92 var port string 93 94 switch portType { 95 case "NodePort": 96 ipAddress, err = minikube.QueryIp() 97 if err != nil || strings.Contains(ipAddress, "Error getting IP") { 98 ipAddress = "127.0.0.1" 99 } 100 port = parser.Value(`$.items[0].spec.ports[*]?(@.name == "http").nodePort+`) 101 case "LoadBalancer": 102 ipAddress = parser.Value(`$.items[0].status.loadBalancer.ingress[0].ip+`) 103 if ipAddress == "" { 104 ioutils.Error("unable to determine http-gateway ip address") 105 return 106 } 107 port = parser.Value(`$.items[0].spec.ports[*]?(@.name == "http").port+`) 108 109 default: 110 ioutils.Errorf("Unkown port type %s", portType) 111 return 112 } 113 114 if port == "" { 115 ioutils.Error("Unable to determine gateway port") 116 return 117 } 118 119 publish(ipAddress, port) 120 121 }, 122 } 123 124 func publish(ipAddress string, port string) { 125 resource := "messages" 126 if publishOptions.reply { 127 resource = "requests" 128 } 129 130 url := fmt.Sprintf("http://%s:%s/%s/%s", ipAddress, port, resource, publishOptions.input) 131 132 fmt.Printf("Posting to %s\n", url) 133 134 for i := 0; i < publishOptions.count; i++ { 135 136 resp, err := http.Post(url, "text/plain", strings.NewReader(publishOptions.data)) 137 if err != nil { 138 panic(err) 139 } 140 141 defer resp.Body.Close() 142 body, err := ioutil.ReadAll(resp.Body) 143 if err != nil { 144 panic(err) 145 } 146 fmt.Println(string(body)) 147 148 if (publishOptions.pause > 0) { 149 time.Sleep(time.Duration(publishOptions.pause) * time.Second) 150 } 151 } 152 } 153 154 func init() { 155 rootCmd.AddCommand(publishCmd) 156 157 // Here you will define your flags and configuration settings. 158 159 // Cobra supports Persistent Flags which will work for this command 160 // and all subcommands, e.g.: 161 // publishCmd.PersistentFlags().String("foo", "", "A help for foo") 162 163 // Cobra supports local flags which will only run when this command 164 // is called directly, e.g.: 165 // publishCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") 166 167 publishCmd.Flags().StringVarP(&publishOptions.data, "data", "d", "", "the data to post to the http-gateway using the input topic") 168 publishCmd.Flags().StringVarP(&publishOptions.input, "input", "i", osutils.GetCWDBasePath(), "the name of the input topic, defaults to name of current directory") 169 publishCmd.Flags().BoolVarP(&publishOptions.reply, "reply", "r", false, "wait for a reply containing the results of the function execution") 170 publishCmd.Flags().IntVarP(&publishOptions.count, "count", "c", 1, "the number of times to post the data") 171 publishCmd.Flags().IntVarP(&publishOptions.pause, "pause", "p", 0, "the number of seconds to wait between postings") 172 173 publishCmd.Flags().StringP("namespace", "", "default", "the namespace of the http-gateway") 174 175 publishCmd.MarkFlagRequired("data") 176 177 }