Signed-off-by: Nishant Totla <nishanttotla@gmail.com>
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
|
| 7 | 7 |
"github.com/docker/distribution/reference" |
| 8 | 8 |
"github.com/docker/docker/api/types" |
| 9 |
+ registrytypes "github.com/docker/docker/api/types/registry" |
|
| 9 | 10 |
"github.com/docker/docker/api/types/swarm" |
| 10 | 11 |
"github.com/opencontainers/go-digest" |
| 11 | 12 |
"golang.org/x/net/context" |
| ... | ... |
@@ -33,6 +34,8 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, |
| 33 | 33 |
if img != "" {
|
| 34 | 34 |
service.TaskTemplate.ContainerSpec.Image = img |
| 35 | 35 |
} |
| 36 |
+ // add platforms that are compatible with the service |
|
| 37 |
+ service.TaskTemplate.Placement = updateServicePlatforms(service.TaskTemplate.Placement, distributionInspect) |
|
| 36 | 38 |
} |
| 37 | 39 |
} |
| 38 | 40 |
var response types.ServiceCreateResponse |
| ... | ... |
@@ -71,6 +74,22 @@ func imageWithDigestString(image string, dgst digest.Digest) string {
|
| 71 | 71 |
return "" |
| 72 | 72 |
} |
| 73 | 73 |
|
| 74 |
+// updateServicePlatforms updates the Platforms in swarm.Placement to list |
|
| 75 |
+// all compatible platforms for the service, as found in distributionInspect |
|
| 76 |
+// and returns a pointer to the new or updated swarm.Placement struct |
|
| 77 |
+func updateServicePlatforms(placement *swarm.Placement, distributionInspect registrytypes.DistributionInspect) *swarm.Placement {
|
|
| 78 |
+ if placement == nil {
|
|
| 79 |
+ placement = &swarm.Placement{}
|
|
| 80 |
+ } |
|
| 81 |
+ for _, p := range distributionInspect.Platforms {
|
|
| 82 |
+ placement.Platforms = append(placement.Platforms, swarm.Platform{
|
|
| 83 |
+ Architecture: p.Architecture, |
|
| 84 |
+ OS: p.OS, |
|
| 85 |
+ }) |
|
| 86 |
+ } |
|
| 87 |
+ return placement |
|
| 88 |
+} |
|
| 89 |
+ |
|
| 74 | 90 |
// digestWarning constructs a formatted warning string using the |
| 75 | 91 |
// image name that could not be pinned by digest. The formatting |
| 76 | 92 |
// is hardcoded, but could me made smarter in the future |
| ... | ... |
@@ -10,7 +10,9 @@ import ( |
| 10 | 10 |
"testing" |
| 11 | 11 |
|
| 12 | 12 |
"github.com/docker/docker/api/types" |
| 13 |
+ registrytypes "github.com/docker/docker/api/types/registry" |
|
| 13 | 14 |
"github.com/docker/docker/api/types/swarm" |
| 15 |
+ "github.com/opencontainers/image-spec/specs-go/v1" |
|
| 14 | 16 |
"golang.org/x/net/context" |
| 15 | 17 |
) |
| 16 | 18 |
|
| ... | ... |
@@ -55,3 +57,55 @@ func TestServiceCreate(t *testing.T) {
|
| 55 | 55 |
t.Fatalf("expected `service_id`, got %s", r.ID)
|
| 56 | 56 |
} |
| 57 | 57 |
} |
| 58 |
+ |
|
| 59 |
+func TestServiceCreateCompatiblePlatforms(t *testing.T) {
|
|
| 60 |
+ var platforms []v1.Platform |
|
| 61 |
+ client := &Client{
|
|
| 62 |
+ client: newMockClient(func(req *http.Request) (*http.Response, error) {
|
|
| 63 |
+ if strings.HasPrefix(req.URL.Path, "/services/create") {
|
|
| 64 |
+ // platforms should have been resolved by now |
|
| 65 |
+ if len(platforms) != 1 || platforms[0].Architecture != "amd64" || platforms[0].OS != "linux" {
|
|
| 66 |
+ return nil, fmt.Errorf("incorrect platform information")
|
|
| 67 |
+ } |
|
| 68 |
+ b, err := json.Marshal(types.ServiceCreateResponse{
|
|
| 69 |
+ ID: "service_" + platforms[0].Architecture, |
|
| 70 |
+ }) |
|
| 71 |
+ if err != nil {
|
|
| 72 |
+ return nil, err |
|
| 73 |
+ } |
|
| 74 |
+ return &http.Response{
|
|
| 75 |
+ StatusCode: http.StatusOK, |
|
| 76 |
+ Body: ioutil.NopCloser(bytes.NewReader(b)), |
|
| 77 |
+ }, nil |
|
| 78 |
+ } else if strings.HasPrefix(req.URL.Path, "/distribution/") {
|
|
| 79 |
+ platforms = []v1.Platform{
|
|
| 80 |
+ {
|
|
| 81 |
+ Architecture: "amd64", |
|
| 82 |
+ OS: "linux", |
|
| 83 |
+ }, |
|
| 84 |
+ } |
|
| 85 |
+ b, err := json.Marshal(registrytypes.DistributionInspect{
|
|
| 86 |
+ Descriptor: v1.Descriptor{},
|
|
| 87 |
+ Platforms: platforms, |
|
| 88 |
+ }) |
|
| 89 |
+ if err != nil {
|
|
| 90 |
+ return nil, err |
|
| 91 |
+ } |
|
| 92 |
+ return &http.Response{
|
|
| 93 |
+ StatusCode: http.StatusOK, |
|
| 94 |
+ Body: ioutil.NopCloser(bytes.NewReader(b)), |
|
| 95 |
+ }, nil |
|
| 96 |
+ } else {
|
|
| 97 |
+ return nil, fmt.Errorf("unexpected URL '%s'", req.URL.Path)
|
|
| 98 |
+ } |
|
| 99 |
+ }), |
|
| 100 |
+ } |
|
| 101 |
+ |
|
| 102 |
+ r, err := client.ServiceCreate(context.Background(), swarm.ServiceSpec{}, types.ServiceCreateOptions{QueryRegistry: true})
|
|
| 103 |
+ if err != nil {
|
|
| 104 |
+ t.Fatal(err) |
|
| 105 |
+ } |
|
| 106 |
+ if r.ID != "service_amd64" {
|
|
| 107 |
+ t.Fatalf("expected `service_amd64`, got %s", r.ID)
|
|
| 108 |
+ } |
|
| 109 |
+} |
| ... | ... |
@@ -46,6 +46,8 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version |
| 46 | 46 |
if img != "" {
|
| 47 | 47 |
service.TaskTemplate.ContainerSpec.Image = img |
| 48 | 48 |
} |
| 49 |
+ // add platforms that are compatible with the service |
|
| 50 |
+ service.TaskTemplate.Placement = updateServicePlatforms(service.TaskTemplate.Placement, distributionInspect) |
|
| 49 | 51 |
} |
| 50 | 52 |
} |
| 51 | 53 |
|