예제 #1
0
파일: response.go 프로젝트: mistifyio/acomm
// sendHTTP sends the Response via HTTP/HTTPS
func sendHTTP(addr *url.URL, payload interface{}) error {
	payloadJSON, err := json.Marshal(payload)
	if err != nil {
		log.WithFields(log.Fields{
			"error":   err,
			"payload": payload,
		}).Error("failed to marshal payload json")
		return err
	}

	httpResp, err := http.Post(addr.String(), "application/json", bytes.NewReader(payloadJSON))
	if err != nil {
		log.WithFields(log.Fields{
			"error":   err,
			"addr":    addr,
			"payload": payload,
		}).Error("failed to send payload")
		return err
	}
	defer logx.LogReturnedErr(httpResp.Body.Close, nil, "failed to close http body")

	body, _ := ioutil.ReadAll(httpResp.Body)
	resp := &Response{}
	if err := json.Unmarshal(body, resp); err != nil {
		log.WithFields(log.Fields{
			"error": err,
			"body":  string(body),
		}).Error(err)
		return err
	}

	return resp.Error
}
예제 #2
0
// request is the generic way to hit an agent endpoint with minimal response
// checking. It returns the body string for later parsing and an optional jobID.
// Generally don't use directly; other, more convenient methods will wrap this
func (agent *MistifyAgent) request(url, httpMethod string, expectedCode int, dataObj interface{}) ([]byte, string, error) {
	httpClient := &http.Client{
		Timeout: 15 * time.Second,
	}

	// Make the request. POST sends JSON data, GET doesn't
	var resp *http.Response
	var reqErr error
	if httpMethod == "POST" {
		dataJSON, err := json.Marshal(dataObj)
		if err != nil {
			return nil, "", err
		}
		resp, reqErr = httpClient.Post(url, "application/json", bytes.NewReader(dataJSON))
	} else {
		resp, reqErr = httpClient.Get(url)
	}
	if reqErr != nil {
		return nil, "", reqErr
	}
	defer logx.LogReturnedErr(resp.Body.Close, nil, "failed to close response body")

	if resp.StatusCode != expectedCode {
		return nil, "", ErrorHTTPCode{expectedCode, resp.StatusCode}
	}

	body, err := ioutil.ReadAll(resp.Body)
	return body, resp.Header.Get("X-Guest-Job-ID"), err
}
예제 #3
0
// Notify sends a message to the init daemon. It is common to ignore the error.
func Notify(state string) error {
	socketAddr := &net.UnixAddr{
		Name: os.Getenv("NOTIFY_SOCKET"),
		Net:  "unixgram",
	}

	if socketAddr.Name == "" {
		return ErrNotifyNoSocket
	}
	switch socketAddr.Name[0] {
	case '@', '/':
	default:
		return ErrNotifyNoSocket
	}

	conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
	if err != nil {
		return err
	}
	defer logx.LogReturnedErr(conn.Close, nil, "failed to close connection")

	_, err = conn.Write([]byte(state))
	if err != nil {
		return err
	}

	return nil
}
예제 #4
0
파일: response.go 프로젝트: mistifyio/acomm
// sendUnix sends a request or response via a Unix socket.
func sendUnix(addr *url.URL, payload interface{}) error {
	conn, err := net.Dial("unix", addr.RequestURI())
	if err != nil {
		log.WithFields(log.Fields{
			"error":   err,
			"addr":    addr,
			"payload": payload,
		}).Error("failed to connect to unix socket")
		return err
	}
	defer logx.LogReturnedErr(conn.Close,
		log.Fields{"addr": addr},
		"failed to close unix connection",
	)

	if err := SendConnData(conn, payload); err != nil {
		return err
	}

	resp := &Response{}
	if err := UnmarshalConnData(conn, resp); err != nil {
		return err
	}

	return resp.Error
}
예제 #5
0
func ExampleSplit() {
	examples := []string{
		"localhost",
		"localhost:1234",
		"[localhost]",
		"[localhost]:1234",
		"2001:db8:85a3:8d3:1319:8a2e:370:7348",
		"[2001:db8:85a3:8d3:1319:8a2e:370:7348]",
		"[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443",
		"2001:db8:85a3:8d3:1319:8a2e:370:7348:443",
		":1234",
		"",
		":::",
		"foo:1234:bar",
		"[2001:db8:85a3:8d3:1319:8a2e:370:7348",
		"[localhost",
		"2001:db8:85a3:8d3:1319:8a2e:370:7348]",
		"localhost]",
		"[loca[lhost]:1234",
		"[loca]lhost]:1234",
		"[localhost]:1234]",
	}

	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 0, 8, 0, '\t', 0)
	fmt.Fprintln(w, "HOSTPORT\tHOST\tPORT\tERR")
	fmt.Fprintln(w, "========\t====\t====\t===")

	for _, hp := range examples {
		host, port, err := hostport.Split(hp)

		fmt.Fprintf(w, "%s\t%s\t%s\t%v\n", hp, host, port, err)
	}
	logx.LogReturnedErr(w.Flush, nil, "failed to flush tabwriter")

	// Output:
	// HOSTPORT					HOST					PORT	ERR
	// ========					====					====	===
	// localhost					localhost					<nil>
	// localhost:1234					localhost				1234	<nil>
	// [localhost]					localhost					<nil>
	// [localhost]:1234				localhost				1234	<nil>
	// 2001:db8:85a3:8d3:1319:8a2e:370:7348		2001:db8:85a3:8d3:1319:8a2e:370		7348	<nil>
	// [2001:db8:85a3:8d3:1319:8a2e:370:7348]		2001:db8:85a3:8d3:1319:8a2e:370:7348		<nil>
	// [2001:db8:85a3:8d3:1319:8a2e:370:7348]:443	2001:db8:85a3:8d3:1319:8a2e:370:7348	443	<nil>
	// 2001:db8:85a3:8d3:1319:8a2e:370:7348:443	2001:db8:85a3:8d3:1319:8a2e:370:7348	443	<nil>
	// :1234											1234	<nil>
	// 												<nil>
	// :::						::						<nil>
	// foo:1234:bar					foo:1234				bar	<nil>
	// [2001:db8:85a3:8d3:1319:8a2e:370:7348								missing ']'
	// [localhost											missing ']'
	// 2001:db8:85a3:8d3:1319:8a2e:370:7348]								missing '['
	// localhost]											missing '['
	// [loca[lhost]:1234										too many '['
	// [loca]lhost]:1234										too many ']'
	// [localhost]:1234]										too many ']'
}
예제 #6
0
// DoneConn completes the handling of a connection.
func (ul *UnixListener) DoneConn(conn net.Conn) {
	if conn == nil {
		return
	}

	defer ul.waitgroup.Done()
	defer logx.LogReturnedErr(conn.Close,
		log.Fields{
			"addr": ul.addr,
		}, "failed to close unix connection",
	)
}
예제 #7
0
// listen continuously listens and accepts new connections up to the accept
// limit.
func (ul *UnixListener) listen() {
	defer ul.waitgroup.Done()
	defer logx.LogReturnedErr(ul.listener.Close, log.Fields{
		"addr": ul.Addr(),
	}, "failed to close listener")

	for i := ul.acceptLimit; i != 0; {
		select {
		case <-ul.stopChan:
			log.WithFields(log.Fields{
				"addr": ul.Addr(),
			}).Info("stop listening")
			return
		default:
		}

		if err := ul.listener.SetDeadline(time.Now().Add(time.Second)); err != nil {
			log.WithFields(log.Fields{
				"addr":  ul.Addr(),
				"error": err,
			}).Error("failed to set listener deadline")
		}

		conn, err := ul.listener.Accept()
		if nil != err {
			// Don't worry about a timeout
			if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
				continue
			}

			log.WithFields(log.Fields{
				"addr":  ul.Addr(),
				"error": err,
			}).Error("failed to accept new connection")
			continue
		}

		ul.waitgroup.Add(1)
		ul.connChan <- conn

		// Only decrement i when there's a limit it is counting down
		if i > 0 {
			i--
		}
	}
}
예제 #8
0
파일: stream.go 프로젝트: mistifyio/acomm
// streamHTTP streams data from an http connection to a destination writer.
func streamHTTP(dest io.Writer, addr *url.URL) error {
	httpResp, err := http.Get(addr.String())
	if err != nil {
		log.WithFields(log.Fields{
			"addr":  addr,
			"error": err,
		}).Error("failed to GET stream")
		return err
	}
	defer logx.LogReturnedErr(httpResp.Body.Close,
		log.Fields{"addr": addr},
		"failed to close stream response body",
	)

	if _, err := io.Copy(dest, httpResp.Body); err != nil {
		log.WithFields(log.Fields{
			"addr":  addr,
			"error": err,
		}).Error("failed to stream data")
		return err
	}
	return nil
}
예제 #9
0
파일: stream.go 프로젝트: mistifyio/acomm
// streamUnix streams data from a unix socket to a destination writer.
func streamUnix(dest io.Writer, addr *url.URL) error {
	conn, err := net.Dial("unix", addr.RequestURI())
	if err != nil {
		log.WithFields(log.Fields{
			"addr":  addr,
			"error": err,
		}).Error("failed to connect to stream socket")
		return err
	}
	defer logx.LogReturnedErr(conn.Close,
		log.Fields{"addr": addr},
		"failed to close stream connection",
	)

	if _, err := io.Copy(dest, conn); err != nil {
		log.WithFields(log.Fields{
			"addr":  addr,
			"error": err,
		}).Error("failed to stream data")
		return err
	}
	return nil
}
예제 #10
0
파일: main.go 프로젝트: joshie/lochness
func upload(cmd *cobra.Command, specs []string) {
	if len(specs) == 0 {
		specs = cli.Read(os.Stdin)
	}

	uploadURL := getServerURL() + "/images"
	for _, spec := range specs {
		uploadImage := &metadata.Image{}
		if err := json.Unmarshal([]byte(spec), uploadImage); err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"json":  spec,
				"func":  "json.Unmarshal",
			}).Fatal("invalid spec")
		}

		sourcePath, err := filepath.Abs(uploadImage.Source)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"image": uploadImage,
				"func":  "filepath.Abs",
			}).Fatal("failed determine absolute source path")
		}
		file, err := os.Open(sourcePath)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"path":  sourcePath,
				"func":  "os.Open",
			}).Fatal("failed to open file")
		}
		// File remains open until function exit
		defer logx.LogReturnedErr(file.Close, log.Fields{
			"filename": sourcePath,
		}, "failed to close image source file")

		info, err := file.Stat()
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"file":  file.Name(),
				"func":  "file.Stat",
			}).Fatal("failed to stat file")
		}

		req, err := http.NewRequest("PUT", uploadURL, file)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"url":   uploadURL,
				"file":  file.Name(),
				"func":  "http.NewRequest",
			}).Fatal("failed to create request")
		}
		req.Header.Add("Content-Length", fmt.Sprintf("%d", info.Size()))
		req.Header.Add("X-Image-Type", uploadImage.Type)
		req.Header.Add("X-Image-Comment", uploadImage.Comment)
		req.Header.Add("Content-Type", "application/octet-stream")
		res, err := http.DefaultClient.Do(req)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"url":   uploadURL,
				"file":  file.Name(),
				"func":  "http.DefaultClient.Do",
			}).Fatal("request error")
		}
		image := &cli.JMap{}
		cli.ProcessResponse(res, "image", "upload", []int{http.StatusOK}, image)
		image.Print(jsonout)
	}
}
예제 #11
0
파일: main.go 프로젝트: joshie/lochness
func download(cmd *cobra.Command, ids []string) {
	if len(ids) == 0 {
		ids = cli.Read(os.Stdin)
	}

	for _, id := range ids {
		success := false
		tempDest, err := ioutil.TempFile(downloadDir, "incompleteImage-")
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"dir":   downloadDir,
				"func":  "ioutil.TempFile",
			}).Fatal("could not create temporary file")
		}
		defer func() {
			if !success {
				if err := os.Remove(tempDest.Name()); err != nil {
					log.WithFields(log.Fields{
						"error":    err,
						"tempfile": tempDest.Name(),
						"func":     "os.Remove",
					}).Error("failed to remove temporary file")
				}
			}
		}()
		defer logx.LogReturnedErr(tempDest.Close, log.Fields{
			"filename": tempDest.Name(),
		}, "failed to close temp dest")

		sourceURL := fmt.Sprintf("%s/images/%s/download", getServerURL(), id)
		resp, err := http.Get(sourceURL)
		if err != nil {
			log.WithFields(log.Fields{
				"error":     err,
				"sourceURL": sourceURL,
				"func":      "http.Get",
			}).Error("request error")
			return
		}
		defer logx.LogReturnedErr(resp.Body.Close, nil, "failed to close response body")

		if resp.StatusCode != http.StatusOK {
			log.WithFields(log.Fields{
				"sourceURL":  sourceURL,
				"statusCode": resp.StatusCode,
				"func":       "http.Get",
			}).Error("bad response code")
			return
		}

		if _, err := io.Copy(tempDest, resp.Body); err != nil {
			log.WithFields(log.Fields{
				"error":     err,
				"sourceURL": sourceURL,
				"tempFile":  tempDest.Name(),
				"func":      "io.Copy",
			}).Error("failed to download image")
			return
		}

		if _, err := tempDest.Seek(0, 0); err != nil {
			log.WithFields(log.Fields{
				"error":    err,
				"tempFile": tempDest.Name(),
				"func":     "tempDest.Seek",
			}).Error("failed to seek to beginning of file")
		}
		fileBuffer := bufio.NewReader(tempDest)
		filetypeBytes, err := fileBuffer.Peek(512)
		if err != nil {
			log.WithFields(log.Fields{
				"error":    err,
				"tempFile": tempDest.Name(),
				"func":     "tempDest.Peek",
			}).Error("failed to read image filetype bytes")
			return
		}
		extension := ".tar"
		if http.DetectContentType(filetypeBytes) == "application/x-gzip" {
			extension = extension + ".gz"
		}

		imagePath := filepath.Join(downloadDir, id+extension)
		if err := os.Rename(tempDest.Name(), imagePath); err != nil {
			log.WithFields(log.Fields{
				"tempFile":  tempDest.Name(),
				"imagePath": imagePath,
				"func":      "os.Rename",
			}).Error("failed to rename image file")
			return
		}
		fmt.Println(imagePath)
		success = true
	}
}