2020-06-18 16:13:24 +02:00
/ *
2020-09-22 12:13:00 +02:00
Copyright 2020 Docker Compose CLI authors
2020-06-18 16:13:24 +02:00
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 .
* /
2020-05-01 15:48:20 +02:00
package convert
import (
2020-08-14 17:01:35 +02:00
"context"
2020-05-01 15:48:20 +02:00
"encoding/base64"
"fmt"
"io/ioutil"
2020-06-30 07:44:45 +02:00
"math"
2020-07-06 23:25:01 +02:00
"os"
2020-06-24 09:44:47 +02:00
"strconv"
2020-05-01 15:48:20 +02:00
"strings"
2020-07-16 11:05:31 +02:00
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
2020-05-01 15:48:20 +02:00
"github.com/Azure/go-autorest/autorest/to"
"github.com/compose-spec/compose-go/types"
2020-08-14 16:24:43 +02:00
"github.com/pkg/errors"
2020-05-13 07:52:43 +02:00
2020-08-21 17:24:53 +02:00
"github.com/docker/compose-cli/aci/login"
2020-09-22 11:45:02 +02:00
"github.com/docker/compose-cli/api/compose"
2020-09-07 13:22:08 +02:00
"github.com/docker/compose-cli/api/containers"
2020-08-21 17:24:53 +02:00
"github.com/docker/compose-cli/context/store"
2020-09-22 11:45:02 +02:00
"github.com/docker/compose-cli/utils/formatter"
2020-05-01 15:48:20 +02:00
)
const (
2020-09-04 15:09:57 +02:00
// StatusRunning name of the ACI running status
StatusRunning = "Running"
2020-06-18 15:51:13 +02:00
// ComposeDNSSidecarName name of the dns sidecar container
ComposeDNSSidecarName = "aci--dns--sidecar"
2020-06-18 15:50:49 +02:00
2020-09-21 17:05:49 +02:00
dnsSidecarImage = "busybox:1.31.1"
2020-05-01 15:48:20 +02:00
azureFileDriverName = "azure_file"
volumeDriveroptsShareNameKey = "share_name"
volumeDriveroptsAccountNameKey = "storage_account_name"
2020-09-14 18:32:38 +02:00
volumeReadOnly = "read_only"
2020-05-01 15:48:20 +02:00
)
2020-05-04 23:00:21 +02:00
// ToContainerGroup converts a compose project into a ACI container group
2020-09-22 11:45:02 +02:00
func ToContainerGroup ( ctx context . Context , aciContext store . AciContext , p types . Project , storageHelper login . StorageLogin ) ( containerinstance . ContainerGroup , error ) {
2020-05-01 15:48:20 +02:00
project := projectAciHelper ( p )
containerGroupName := strings . ToLower ( project . Name )
2020-08-14 17:01:35 +02:00
volumesCache , volumesSlice , err := project . getAciFileVolumes ( ctx , storageHelper )
2020-05-01 15:48:20 +02:00
if err != nil {
return containerinstance . ContainerGroup { } , err
}
secretVolumes , err := project . getAciSecretVolumes ( )
if err != nil {
return containerinstance . ContainerGroup { } , err
}
allVolumes := append ( volumesSlice , secretVolumes ... )
var volumes * [ ] containerinstance . Volume
2020-09-14 18:32:38 +02:00
if len ( allVolumes ) > 0 {
2020-05-01 15:48:20 +02:00
volumes = & allVolumes
}
2020-06-02 15:29:16 +02:00
registryCreds , err := getRegistryCredentials ( p , newCliRegistryConfLoader ( ) )
if err != nil {
return containerinstance . ContainerGroup { } , err
}
2020-05-01 15:48:20 +02:00
var containers [ ] containerinstance . Container
2020-08-06 18:23:04 +02:00
restartPolicy , err := project . getRestartPolicy ( )
if err != nil {
return containerinstance . ContainerGroup { } , err
}
2020-05-01 15:48:20 +02:00
groupDefinition := containerinstance . ContainerGroup {
Name : & containerGroupName ,
Location : & aciContext . Location ,
ContainerGroupProperties : & containerinstance . ContainerGroupProperties {
2020-06-02 15:29:16 +02:00
OsType : containerinstance . Linux ,
Containers : & containers ,
Volumes : volumes ,
ImageRegistryCredentials : & registryCreds ,
2020-08-06 18:23:04 +02:00
RestartPolicy : restartPolicy ,
2020-05-01 15:48:20 +02:00
} ,
}
2020-06-23 15:54:47 +02:00
var groupPorts [ ] containerinstance . Port
2020-09-22 14:15:05 +02:00
var dnsLabelName * string
2020-05-01 15:48:20 +02:00
for _ , s := range project . Services {
service := serviceConfigAciHelper ( s )
containerDefinition , err := service . getAciContainer ( volumesCache )
if err != nil {
return containerinstance . ContainerGroup { } , err
}
2020-08-12 10:28:55 +02:00
if service . Labels != nil && len ( service . Labels ) > 0 {
return containerinstance . ContainerGroup { } , errors . New ( "ACI integration does not support labels in compose applications" )
}
2020-09-22 14:15:05 +02:00
containerPorts , serviceGroupPorts , serviceDomainName , err := convertPortsToAci ( service )
if err != nil {
return groupDefinition , err
}
containerDefinition . ContainerProperties . Ports = & containerPorts
groupPorts = append ( groupPorts , serviceGroupPorts ... )
if serviceDomainName != nil {
if dnsLabelName != nil && * serviceDomainName != * dnsLabelName {
return containerinstance . ContainerGroup { } , fmt . Errorf ( "ACI integration does not support specifying different domain names on services in the same compose application" )
2020-05-01 15:48:20 +02:00
}
2020-09-22 14:15:05 +02:00
dnsLabelName = serviceDomainName
2020-05-01 15:48:20 +02:00
}
containers = append ( containers , containerDefinition )
}
2020-09-22 14:15:05 +02:00
if len ( groupPorts ) > 0 {
groupDefinition . ContainerGroupProperties . IPAddress = & containerinstance . IPAddress {
Type : containerinstance . Public ,
Ports : & groupPorts ,
DNSNameLabel : dnsLabelName ,
}
}
2020-06-18 15:50:49 +02:00
if len ( containers ) > 1 {
2020-06-18 15:51:13 +02:00
dnsSideCar := getDNSSidecar ( containers )
2020-06-18 15:50:49 +02:00
containers = append ( containers , dnsSideCar )
}
2020-05-01 15:48:20 +02:00
groupDefinition . ContainerGroupProperties . Containers = & containers
2020-06-18 15:50:49 +02:00
2020-05-01 15:48:20 +02:00
return groupDefinition , nil
}
2020-09-22 14:15:05 +02:00
func convertPortsToAci ( service serviceConfigAciHelper ) ( [ ] containerinstance . ContainerPort , [ ] containerinstance . Port , * string , error ) {
2020-09-21 17:05:49 +02:00
var groupPorts [ ] containerinstance . Port
var containerPorts [ ] containerinstance . ContainerPort
for _ , portConfig := range service . Ports {
if portConfig . Published != 0 && portConfig . Published != portConfig . Target {
msg := fmt . Sprintf ( "Port mapping is not supported with ACI, cannot map port %d to %d for container %s" ,
portConfig . Published , portConfig . Target , service . Name )
return nil , nil , nil , errors . New ( msg )
}
portNumber := int32 ( portConfig . Target )
containerPorts = append ( containerPorts , containerinstance . ContainerPort {
Port : to . Int32Ptr ( portNumber ) ,
} )
groupPorts = append ( groupPorts , containerinstance . Port {
Port : to . Int32Ptr ( portNumber ) ,
Protocol : containerinstance . TCP ,
} )
}
var dnsLabelName * string = nil
2020-09-22 14:15:05 +02:00
if service . DomainName != "" {
dnsLabelName = & service . DomainName
2020-09-21 17:05:49 +02:00
}
return containerPorts , groupPorts , dnsLabelName , nil
}
2020-06-18 15:51:13 +02:00
func getDNSSidecar ( containers [ ] containerinstance . Container ) containerinstance . Container {
2020-06-18 15:50:49 +02:00
var commands [ ] string
for _ , container := range containers {
commands = append ( commands , fmt . Sprintf ( "echo 127.0.0.1 %s >> /etc/hosts" , * container . Name ) )
}
// ACI restart policy is currently at container group level, cannot let the sidecar terminate quietly once /etc/hosts has been edited
2020-06-18 17:55:56 +02:00
// Pricing is done at the container group level so letting the sidecar container "sleep" should not impact the price for the whole group
2020-06-18 15:50:49 +02:00
commands = append ( commands , "sleep infinity" )
alpineCmd := [ ] string { "sh" , "-c" , strings . Join ( commands , ";" ) }
dnsSideCar := containerinstance . Container {
2020-06-18 15:51:13 +02:00
Name : to . StringPtr ( ComposeDNSSidecarName ) ,
2020-06-18 15:50:49 +02:00
ContainerProperties : & containerinstance . ContainerProperties {
2020-06-18 16:44:56 +02:00
Image : to . StringPtr ( dnsSidecarImage ) ,
2020-06-18 15:50:49 +02:00
Command : & alpineCmd ,
Resources : & containerinstance . ResourceRequirements {
Requests : & containerinstance . ResourceRequests {
2020-06-18 17:55:56 +02:00
MemoryInGB : to . Float64Ptr ( 0.1 ) ,
CPU : to . Float64Ptr ( 0.01 ) ,
2020-06-18 15:50:49 +02:00
} ,
} ,
} ,
}
return dnsSideCar
}
2020-07-02 16:05:45 +02:00
type projectAciHelper types . Project
2020-05-01 15:48:20 +02:00
func ( p projectAciHelper ) getAciSecretVolumes ( ) ( [ ] containerinstance . Volume , error ) {
var secretVolumes [ ] containerinstance . Volume
for secretName , filepathToRead := range p . Secrets {
2020-10-09 06:12:35 +02:00
data , err := ioutil . ReadFile ( filepathToRead . File )
if err != nil {
return secretVolumes , err
2020-05-01 15:48:20 +02:00
}
if len ( data ) == 0 {
continue
}
dataStr := base64 . StdEncoding . EncodeToString ( data )
secretVolumes = append ( secretVolumes , containerinstance . Volume {
Name : to . StringPtr ( secretName ) ,
Secret : map [ string ] * string {
secretName : & dataStr ,
} ,
} )
}
return secretVolumes , nil
}
2020-09-08 10:11:02 +02:00
func ( p projectAciHelper ) getAciFileVolumes ( ctx context . Context , helper login . StorageLogin ) ( map [ string ] bool , [ ] containerinstance . Volume , error ) {
2020-05-01 15:48:20 +02:00
azureFileVolumesMap := make ( map [ string ] bool , len ( p . Volumes ) )
var azureFileVolumesSlice [ ] containerinstance . Volume
for name , v := range p . Volumes {
if v . Driver == azureFileDriverName {
shareName , ok := v . DriverOpts [ volumeDriveroptsShareNameKey ]
if ! ok {
2020-09-10 16:07:22 +02:00
return nil , nil , fmt . Errorf ( "cannot retrieve fileshare name for Azurefile" )
2020-05-01 15:48:20 +02:00
}
accountName , ok := v . DriverOpts [ volumeDriveroptsAccountNameKey ]
if ! ok {
return nil , nil , fmt . Errorf ( "cannot retrieve account name for Azurefile" )
}
2020-09-14 18:32:38 +02:00
readOnly , ok := v . DriverOpts [ volumeReadOnly ]
if ! ok {
readOnly = "false"
}
ro , err := strconv . ParseBool ( readOnly )
if err != nil {
return nil , nil , fmt . Errorf ( "invalid mode %q for volume" , readOnly )
}
2020-08-14 17:01:35 +02:00
accountKey , err := helper . GetAzureStorageAccountKey ( ctx , accountName )
2020-08-13 15:21:09 +02:00
if err != nil {
return nil , nil , err
2020-05-01 15:48:20 +02:00
}
aciVolume := containerinstance . Volume {
Name : to . StringPtr ( name ) ,
AzureFile : & containerinstance . AzureFileVolume {
ShareName : to . StringPtr ( shareName ) ,
StorageAccountName : to . StringPtr ( accountName ) ,
StorageAccountKey : to . StringPtr ( accountKey ) ,
2020-09-14 18:32:38 +02:00
ReadOnly : & ro ,
2020-05-01 15:48:20 +02:00
} ,
}
azureFileVolumesMap [ name ] = true
azureFileVolumesSlice = append ( azureFileVolumesSlice , aciVolume )
}
}
return azureFileVolumesMap , azureFileVolumesSlice , nil
}
2020-08-06 18:23:04 +02:00
func ( p projectAciHelper ) getRestartPolicy ( ) ( containerinstance . ContainerGroupRestartPolicy , error ) {
2020-08-04 10:22:07 +02:00
var restartPolicyCondition containerinstance . ContainerGroupRestartPolicy
2020-08-06 18:23:04 +02:00
if len ( p . Services ) >= 1 {
alreadySpecified := false
2020-08-04 10:22:07 +02:00
restartPolicyCondition = containerinstance . Always
2020-08-06 18:23:04 +02:00
for _ , service := range p . Services {
if service . Deploy != nil &&
service . Deploy . RestartPolicy != nil {
if ! alreadySpecified {
alreadySpecified = true
restartPolicyCondition = toAciRestartPolicy ( service . Deploy . RestartPolicy . Condition )
}
if alreadySpecified && restartPolicyCondition != toAciRestartPolicy ( service . Deploy . RestartPolicy . Condition ) {
2020-09-22 14:15:05 +02:00
return "" , errors . New ( "ACI integration does not support specifying different restart policies on services in the same compose application" )
2020-08-06 18:23:04 +02:00
}
}
}
2020-08-04 10:22:07 +02:00
}
2020-08-06 18:23:04 +02:00
return restartPolicyCondition , nil
2020-08-04 10:22:07 +02:00
}
func toAciRestartPolicy ( restartPolicy string ) containerinstance . ContainerGroupRestartPolicy {
switch restartPolicy {
case containers . RestartPolicyNone :
return containerinstance . Never
case containers . RestartPolicyAny :
return containerinstance . Always
case containers . RestartPolicyOnFailure :
return containerinstance . OnFailure
default :
return containerinstance . Always
}
}
func toContainerRestartPolicy ( aciRestartPolicy containerinstance . ContainerGroupRestartPolicy ) string {
switch aciRestartPolicy {
case containerinstance . Never :
return containers . RestartPolicyNone
case containerinstance . Always :
return containers . RestartPolicyAny
case containerinstance . OnFailure :
return containers . RestartPolicyOnFailure
default :
return containers . RestartPolicyAny
}
}
2020-05-01 15:48:20 +02:00
type serviceConfigAciHelper types . ServiceConfig
func ( s serviceConfigAciHelper ) getAciFileVolumeMounts ( volumesCache map [ string ] bool ) ( [ ] containerinstance . VolumeMount , error ) {
var aciServiceVolumes [ ] containerinstance . VolumeMount
for _ , sv := range s . Volumes {
if ! volumesCache [ sv . Source ] {
return [ ] containerinstance . VolumeMount { } , fmt . Errorf ( "could not find volume source %q" , sv . Source )
}
aciServiceVolumes = append ( aciServiceVolumes , containerinstance . VolumeMount {
Name : to . StringPtr ( sv . Source ) ,
MountPath : to . StringPtr ( sv . Target ) ,
} )
}
return aciServiceVolumes , nil
}
func ( s serviceConfigAciHelper ) getAciSecretsVolumeMounts ( ) [ ] containerinstance . VolumeMount {
var secretVolumeMounts [ ] containerinstance . VolumeMount
for _ , secret := range s . Secrets {
secretsMountPath := "/run/secrets"
if secret . Target == "" {
secret . Target = secret . Source
}
// Specifically use "/" here and not filepath.Join() to avoid windows path being sent and used inside containers
secretsMountPath = secretsMountPath + "/" + secret . Target
vmName := strings . Split ( secret . Source , "=" ) [ 0 ]
vm := containerinstance . VolumeMount {
Name : to . StringPtr ( vmName ) ,
MountPath : to . StringPtr ( secretsMountPath ) ,
ReadOnly : to . BoolPtr ( true ) , // TODO Confirm if the secrets are read only
}
secretVolumeMounts = append ( secretVolumeMounts , vm )
}
return secretVolumeMounts
}
func ( s serviceConfigAciHelper ) getAciContainer ( volumesCache map [ string ] bool ) ( containerinstance . Container , error ) {
secretVolumeMounts := s . getAciSecretsVolumeMounts ( )
aciServiceVolumes , err := s . getAciFileVolumeMounts ( volumesCache )
if err != nil {
return containerinstance . Container { } , err
}
allVolumes := append ( aciServiceVolumes , secretVolumeMounts ... )
var volumes * [ ] containerinstance . VolumeMount
if len ( allVolumes ) == 0 {
volumes = nil
} else {
volumes = & allVolumes
}
2020-06-24 09:44:47 +02:00
2020-10-05 17:23:08 +02:00
resource , err := s . getResourceRequestsLimits ( )
if err != nil {
return containerinstance . Container { } , err
2020-06-24 09:44:47 +02:00
}
2020-10-05 17:23:08 +02:00
2020-05-01 15:48:20 +02:00
return containerinstance . Container {
Name : to . StringPtr ( s . Name ) ,
ContainerProperties : & containerinstance . ContainerProperties {
2020-07-06 23:25:01 +02:00
Image : to . StringPtr ( s . Image ) ,
2020-08-24 18:41:16 +02:00
Command : to . StringSlicePtr ( s . Command ) ,
2020-07-06 23:25:01 +02:00
EnvironmentVariables : getEnvVariables ( s . Environment ) ,
2020-10-05 17:23:08 +02:00
Resources : resource ,
VolumeMounts : volumes ,
2020-05-01 15:48:20 +02:00
} ,
} , nil
2020-07-06 23:25:01 +02:00
}
2020-05-01 15:48:20 +02:00
2020-10-05 17:23:08 +02:00
func ( s serviceConfigAciHelper ) getResourceRequestsLimits ( ) ( * containerinstance . ResourceRequirements , error ) {
memRequest := 1. // Default 1 Gb
var cpuRequest float64 = 1
var err error
hasMemoryRequest := func ( ) bool {
return s . Deploy != nil && s . Deploy . Resources . Reservations != nil && s . Deploy . Resources . Reservations . MemoryBytes != 0
}
hasCPURequest := func ( ) bool {
return s . Deploy != nil && s . Deploy . Resources . Reservations != nil && s . Deploy . Resources . Reservations . NanoCPUs != ""
}
if hasMemoryRequest ( ) {
memRequest = bytesToGb ( s . Deploy . Resources . Reservations . MemoryBytes )
}
if hasCPURequest ( ) {
cpuRequest , err = strconv . ParseFloat ( s . Deploy . Resources . Reservations . NanoCPUs , 0 )
if err != nil {
return nil , err
}
}
memLimit := memRequest
cpuLimit := cpuRequest
if s . Deploy != nil && s . Deploy . Resources . Limits != nil {
if s . Deploy . Resources . Limits . MemoryBytes != 0 {
memLimit = bytesToGb ( s . Deploy . Resources . Limits . MemoryBytes )
if ! hasMemoryRequest ( ) {
memRequest = memLimit
}
}
if s . Deploy . Resources . Limits . NanoCPUs != "" {
cpuLimit , err = strconv . ParseFloat ( s . Deploy . Resources . Limits . NanoCPUs , 0 )
if err != nil {
return nil , err
}
if ! hasCPURequest ( ) {
cpuRequest = cpuLimit
}
}
}
resources := containerinstance . ResourceRequirements {
Requests : & containerinstance . ResourceRequests {
MemoryInGB : to . Float64Ptr ( memRequest ) ,
CPU : to . Float64Ptr ( cpuRequest ) ,
} ,
Limits : & containerinstance . ResourceLimits {
MemoryInGB : to . Float64Ptr ( memLimit ) ,
CPU : to . Float64Ptr ( cpuLimit ) ,
} ,
}
return & resources , nil
}
2020-07-06 23:25:01 +02:00
func getEnvVariables ( composeEnv types . MappingWithEquals ) * [ ] containerinstance . EnvironmentVariable {
result := [ ] containerinstance . EnvironmentVariable { }
for key , value := range composeEnv {
var strValue string
if value == nil {
strValue = os . Getenv ( key )
} else {
strValue = * value
}
result = append ( result , containerinstance . EnvironmentVariable {
Name : to . StringPtr ( key ) ,
Value : to . StringPtr ( strValue ) ,
} )
}
return & result
2020-05-01 15:48:20 +02:00
}
2020-06-15 10:38:37 +02:00
2020-06-30 07:44:45 +02:00
func bytesToGb ( b types . UnitBytes ) float64 {
f := float64 ( b ) / 1024 / 1024 / 1024 // from bytes to gigabytes
return math . Round ( f * 100 ) / 100
2020-06-24 09:44:47 +02:00
}
2020-10-09 11:48:06 +02:00
func gbToBytes ( memInBytes float64 ) uint64 {
return uint64 ( memInBytes * 1024 * 1024 * 1024 )
}
2020-08-28 14:38:51 +02:00
// ContainerGroupToServiceStatus convert from an ACI container definition to service status
2020-09-21 12:42:44 +02:00
func ContainerGroupToServiceStatus ( containerID string , group containerinstance . ContainerGroup , container containerinstance . Container , region string ) compose . ServiceStatus {
2020-08-28 14:38:51 +02:00
var replicas = 1
2020-09-04 15:09:57 +02:00
if GetStatus ( container , group ) != StatusRunning {
2020-08-28 14:38:51 +02:00
replicas = 0
}
return compose . ServiceStatus {
ID : containerID ,
Name : * container . Name ,
2020-09-21 12:42:44 +02:00
Ports : formatter . PortsToStrings ( ToPorts ( group . IPAddress , * container . Ports ) , fqdn ( group , region ) ) ,
2020-08-28 14:38:51 +02:00
Replicas : replicas ,
Desired : 1 ,
}
}
2020-09-21 12:42:44 +02:00
func fqdn ( group containerinstance . ContainerGroup , region string ) string {
fqdn := ""
if group . IPAddress != nil && group . IPAddress . DNSNameLabel != nil && * group . IPAddress . DNSNameLabel != "" {
fqdn = * group . IPAddress . DNSNameLabel + "." + region + ".azurecontainer.io"
}
return fqdn
}
2020-06-16 10:59:40 +02:00
// ContainerGroupToContainer composes a Container from an ACI container definition
2020-09-21 12:42:44 +02:00
func ContainerGroupToContainer ( containerID string , cg containerinstance . ContainerGroup , cc containerinstance . Container , region string ) containers . Container {
2020-10-09 11:48:06 +02:00
memLimits := uint64 ( 0 )
memRequest := uint64 ( 0 )
2020-06-24 09:59:53 +02:00
cpuLimit := 0.
2020-10-08 17:03:26 +02:00
cpuReservation := 0.
if cc . Resources != nil {
if cc . Resources . Limits != nil {
if cc . Resources . Limits . MemoryInGB != nil {
2020-10-09 11:48:06 +02:00
memLimits = gbToBytes ( * cc . Resources . Limits . MemoryInGB )
2020-10-08 17:03:26 +02:00
}
if cc . Resources . Limits . CPU != nil {
cpuLimit = * cc . Resources . Limits . CPU
}
}
if cc . Resources . Requests != nil {
if cc . Resources . Requests . MemoryInGB != nil {
2020-10-09 11:48:06 +02:00
memRequest = gbToBytes ( * cc . Resources . Requests . MemoryInGB )
2020-10-08 17:03:26 +02:00
}
if cc . Resources . Requests . CPU != nil {
cpuReservation = * cc . Resources . Requests . CPU
}
}
2020-06-24 09:59:53 +02:00
}
2020-06-15 10:38:37 +02:00
command := ""
if cc . Command != nil {
command = strings . Join ( * cc . Command , " " )
}
2020-08-18 10:50:56 +02:00
status := GetStatus ( cc , cg )
2020-07-06 12:15:07 +02:00
platform := string ( cg . OsType )
2020-06-15 10:38:37 +02:00
2020-09-10 11:59:49 +02:00
var envVars map [ string ] string = nil
if cc . EnvironmentVariables != nil && len ( * cc . EnvironmentVariables ) != 0 {
envVars = map [ string ] string { }
for _ , envVar := range * cc . EnvironmentVariables {
envVars [ * envVar . Name ] = * envVar . Value
}
}
2020-10-07 18:25:01 +02:00
config := & containers . RuntimeConfig {
FQDN : fqdn ( cg , region ) ,
Env : envVars ,
}
hostConfig := & containers . HostConfig {
2020-10-08 17:03:26 +02:00
CPULimit : cpuLimit ,
CPUReservation : cpuReservation ,
2020-10-09 11:48:06 +02:00
MemoryLimit : memLimits ,
MemoryReservation : memRequest ,
2020-10-08 17:03:26 +02:00
RestartPolicy : toContainerRestartPolicy ( cg . RestartPolicy ) ,
2020-09-10 11:59:49 +02:00
}
2020-06-15 10:38:37 +02:00
c := containers . Container {
2020-10-07 18:25:01 +02:00
ID : containerID ,
Status : status ,
Image : to . String ( cc . Image ) ,
Command : command ,
CPUTime : 0 ,
MemoryUsage : 0 ,
PidsCurrent : 0 ,
PidsLimit : 0 ,
Ports : ToPorts ( cg . IPAddress , * cc . Ports ) ,
Platform : platform ,
Config : config ,
HostConfig : hostConfig ,
2020-06-15 10:38:37 +02:00
}
2020-08-18 10:50:56 +02:00
return c
}
// GetStatus returns status for the specified container
func GetStatus ( container containerinstance . Container , group containerinstance . ContainerGroup ) string {
2020-09-04 18:11:02 +02:00
status := compose . UNKNOWN
2020-08-18 10:50:56 +02:00
if group . InstanceView != nil && group . InstanceView . State != nil {
status = "Node " + * group . InstanceView . State
}
if container . InstanceView != nil && container . InstanceView . CurrentState != nil {
status = * container . InstanceView . CurrentState . State
}
return status
2020-06-15 10:38:37 +02:00
}