Skip to content

Commit

Permalink
Set default time zone for WCOW UVM
Browse files Browse the repository at this point in the history
For the v2 hcs code paths it seems the only time a time zone is set is if
a new field on the guest connection settings is present (which we don't have)
while using the internal guest connection (shim -> hcs -> gcs). Otherwise
the guest is just left without a time zone set, so things like tzutil or
the get-timezone powershell cmdlet will return an invalid time zone set.
We swapped to always using the external guest connection we maintain in the
shim so we need to set a time zone explicitly.

This change issues a request to the gcs to set a timezone via the same method that
hcs uses internally. It sets the guests time zone to whatever is present on
the host which is the docker behavior, and then all containers in the vm
should inherit this. Additionally expose an option to override this behavior and
just set the time zone to GMT. If the container wants to change its timezone
to something else, it is free to on supported images.

See https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/virtual-time-zone

Signed-off-by: Daniel Canter <dcanter@microsoft.com>
  • Loading branch information
dcantah committed Oct 8, 2021
1 parent 8dacd23 commit 570cb77
Show file tree
Hide file tree
Showing 28 changed files with 782 additions and 169 deletions.
167 changes: 104 additions & 63 deletions cmd/containerd-shim-runhcs-v1/options/runhcs.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions cmd/containerd-shim-runhcs-v1/options/runhcs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ message Options {
// logrus log levels: "trace", "debug", "info", "warn", "error", "fatal", "panic". This setting will override
// the `debug` field if both are specified, unless the level specified is also "debug", as these are equivalent.
string log_level = 16;

// no_inherit_host_timezone specifies to skip inheriting the hosts time zone for WCOW UVMs and instead default to
// GMT.
bool no_inherit_host_timezone = 17;
}

// ProcessDetails contains additional information about a process. This is the additional
Expand Down
46 changes: 29 additions & 17 deletions internal/gcs/guestconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net"
Expand All @@ -16,9 +15,11 @@ import (
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/Microsoft/hcsshim/internal/cow"
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
"github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
Expand All @@ -45,6 +46,11 @@ func HvsockIoListen(vmID guid.GUID) IoListenFunc {
}
}

type InitialGuestState struct {
// Timezone is only honored for Windows guests.
Timezone *hcsschema.TimeZoneInformation
}

// GuestConnectionConfig contains options for creating a guest connection.
type GuestConnectionConfig struct {
// Conn specifies the connection to use for the bridge. It will be closed
Expand All @@ -54,6 +60,8 @@ type GuestConnectionConfig struct {
Log *logrus.Entry
// IoListen is the function to use to create listeners for the stdio connections.
IoListen IoListenFunc
// InitGuestState specifies settings to apply to the guest on creation/start. This includes things such as the timezone for the VM.
InitGuestState *InitialGuestState
}

// Connect establishes a GCS connection. `gcc.Conn` will be closed by this function.
Expand All @@ -63,9 +71,10 @@ func (gcc *GuestConnectionConfig) Connect(ctx context.Context, isColdStart bool)
defer func() { oc.SetSpanStatus(span, err) }()

gc := &GuestConnection{
nextPort: firstIoChannelVsockPort,
notifyChs: make(map[string]chan struct{}),
ioListenFn: gcc.IoListen,
nextPort: firstIoChannelVsockPort,
notifyChs: make(map[string]chan struct{}),
ioListenFn: gcc.IoListen,
initGuestState: gcc.InitGuestState,
}
gc.brdg = newBridge(gcc.Conn, gc.notify, gcc.Log)
gc.brdg.Start()
Expand All @@ -83,13 +92,14 @@ func (gcc *GuestConnectionConfig) Connect(ctx context.Context, isColdStart bool)

// GuestConnection represents a connection to the GCS.
type GuestConnection struct {
brdg *bridge
ioListenFn IoListenFunc
mu sync.Mutex
nextPort uint32
notifyChs map[string]chan struct{}
caps schema1.GuestDefinedCapabilities
os string
brdg *bridge
ioListenFn IoListenFunc
mu sync.Mutex
nextPort uint32
notifyChs map[string]chan struct{}
caps schema1.GuestDefinedCapabilities
os string
initGuestState *InitialGuestState
}

var _ cow.ProcessHost = &GuestConnection{}
Expand Down Expand Up @@ -127,11 +137,15 @@ func (gc *GuestConnection) connect(ctx context.Context, isColdStart bool) (err e
gc.os = "windows"
}
if isColdStart && resp.Capabilities.SendHostCreateMessage {
conf := &uvmConfig{
SystemType: "Container",
}
if gc.initGuestState != nil && gc.initGuestState.Timezone != nil {
conf.TimeZoneInformation = gc.initGuestState.Timezone
}
createReq := containerCreate{
requestBase: makeRequest(ctx, nullContainerID),
ContainerConfig: anyInString{&uvmConfig{
SystemType: "Container",
}},
requestBase: makeRequest(ctx, nullContainerID),
ContainerConfig: anyInString{conf},
}
var createResp responseBase
err = gc.brdg.RPC(ctx, rpcCreate, &createReq, &createResp, true)
Expand Down Expand Up @@ -173,9 +187,7 @@ func (gc *GuestConnection) DumpStacks(ctx context.Context) (response string, err
req := dumpStacksRequest{
requestBase: makeRequest(ctx, nullContainerID),
}

var resp dumpStacksResponse

err = gc.brdg.RPC(ctx, rpcDumpStacks, &req, &resp, false)
return resp.GuestStacks, err
}
Expand Down
3 changes: 2 additions & 1 deletion internal/gcs/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ type containerCreate struct {
}

type uvmConfig struct {
SystemType string // must be "Container"
SystemType string // must be "Container"
TimeZoneInformation *hcsschema.TimeZoneInformation
}

type containerNotification struct {
Expand Down
28 changes: 28 additions & 0 deletions internal/hcs/schema2/system_time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/

package hcsschema

type SystemTime struct {
Year int32 `json:"Year,omitempty"`

Month int32 `json:"Month,omitempty"`

DayOfWeek int32 `json:"DayOfWeek,omitempty"`

Day int32 `json:"Day,omitempty"`

Hour int32 `json:"Hour,omitempty"`

Minute int32 `json:"Minute,omitempty"`

Second int32 `json:"Second,omitempty"`

Milliseconds int32 `json:"Milliseconds,omitempty"`
}
Loading

0 comments on commit 570cb77

Please sign in to comment.