github.phpd.cn/hashicorp/packer@v1.3.2/packer/rpc/builder.go (about)

     1  package rpc
     2  
     3  import (
     4  	"log"
     5  	"net/rpc"
     6  
     7  	"github.com/hashicorp/packer/packer"
     8  )
     9  
    10  // An implementation of packer.Builder where the builder is actually executed
    11  // over an RPC connection.
    12  type builder struct {
    13  	client *rpc.Client
    14  	mux    *muxBroker
    15  }
    16  
    17  // BuilderServer wraps a packer.Builder implementation and makes it exportable
    18  // as part of a Golang RPC server.
    19  type BuilderServer struct {
    20  	builder packer.Builder
    21  	mux     *muxBroker
    22  }
    23  
    24  type BuilderPrepareArgs struct {
    25  	Configs []interface{}
    26  }
    27  
    28  type BuilderPrepareResponse struct {
    29  	Warnings []string
    30  	Error    *BasicError
    31  }
    32  
    33  func (b *builder) Prepare(config ...interface{}) ([]string, error) {
    34  	var resp BuilderPrepareResponse
    35  	cerr := b.client.Call("Builder.Prepare", &BuilderPrepareArgs{config}, &resp)
    36  	if cerr != nil {
    37  		return nil, cerr
    38  	}
    39  	var err error = nil
    40  	if resp.Error != nil {
    41  		err = resp.Error
    42  	}
    43  
    44  	return resp.Warnings, err
    45  }
    46  
    47  func (b *builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
    48  	nextId := b.mux.NextId()
    49  	server := newServerWithMux(b.mux, nextId)
    50  	server.RegisterCache(cache)
    51  	server.RegisterHook(hook)
    52  	server.RegisterUi(ui)
    53  	go server.Serve()
    54  
    55  	var responseId uint32
    56  	if err := b.client.Call("Builder.Run", nextId, &responseId); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	if responseId == 0 {
    61  		return nil, nil
    62  	}
    63  
    64  	client, err := newClientWithMux(b.mux, responseId)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	return client.Artifact(), nil
    70  }
    71  
    72  func (b *builder) Cancel() {
    73  	if err := b.client.Call("Builder.Cancel", new(interface{}), new(interface{})); err != nil {
    74  		log.Printf("Error cancelling builder: %s", err)
    75  	}
    76  }
    77  
    78  func (b *BuilderServer) Prepare(args *BuilderPrepareArgs, reply *BuilderPrepareResponse) error {
    79  	warnings, err := b.builder.Prepare(args.Configs...)
    80  	*reply = BuilderPrepareResponse{
    81  		Warnings: warnings,
    82  		Error:    NewBasicError(err),
    83  	}
    84  	return nil
    85  }
    86  
    87  func (b *BuilderServer) Run(streamId uint32, reply *uint32) error {
    88  	client, err := newClientWithMux(b.mux, streamId)
    89  	if err != nil {
    90  		return NewBasicError(err)
    91  	}
    92  	defer client.Close()
    93  
    94  	artifact, err := b.builder.Run(client.Ui(), client.Hook(), client.Cache())
    95  	if err != nil {
    96  		return NewBasicError(err)
    97  	}
    98  
    99  	*reply = 0
   100  	if artifact != nil {
   101  		streamId = b.mux.NextId()
   102  		server := newServerWithMux(b.mux, streamId)
   103  		server.RegisterArtifact(artifact)
   104  		go server.Serve()
   105  		*reply = streamId
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  func (b *BuilderServer) Cancel(args *interface{}, reply *interface{}) error {
   112  	b.builder.Cancel()
   113  	return nil
   114  }