Skip to content

Commit 1f6b26d

Browse files
committed
buildx: Support connectivity test
Adds a connectivity check to `nsc docker buildx status` that actually prints helpful messages. The same connectivity check is performed when using remote builders in ns build(-binary). While we're here, perform some clean up.
1 parent febd401 commit 1f6b26d

File tree

4 files changed

+229
-72
lines changed

4 files changed

+229
-72
lines changed

internal/build/buildkit/client.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,17 @@ func (c *clientInstance) Compute(ctx context.Context, _ compute.Resolved) (*Gate
197197
return nil, fnerrors.InternalError("expected one builder config, got %d", len(builderConfigs))
198198
}
199199

200-
fmt.Fprintf(console.Info(ctx), "buildkit: using server-side build proxy (endpoint: %s)\n", builderConfigs[0].ServerConfig.FullBuildkitEndpoint)
200+
endpoint := builderConfigs[0].FullBuildkitEndpoint
201+
fmt.Fprintf(console.Info(ctx), "buildkit: using server-side build proxy (endpoint: %s)\n", endpoint)
202+
203+
isServerSideProxy, err := cluster.TestServerSideBuildxProxyConnectivity(ctx, builderConfigs[0])
204+
if err != nil {
205+
fmt.Fprintf(console.Warnings(ctx), "buildkit: connectivity check to '%s' failed: %v\n", endpoint, err)
206+
}
207+
208+
if !isServerSideProxy {
209+
fmt.Fprintf(console.Warnings(ctx), "buildkit: '%s' has connectivity but doesn't seem to be Namespace Build Ingress\n", endpoint)
210+
}
201211

202212
return useRemoteClusterViaMtls(ctx, builderConfigs[0])
203213
}
@@ -294,7 +304,7 @@ func useRemoteClusterViaEndpoint(ctx context.Context, endpoint string) (*Gateway
294304

295305
func useRemoteClusterViaMtls(ctx context.Context, bc cluster.BuilderConfig) (*GatewayClient, error) {
296306
return waitAndConnect(ctx, func(ctx context.Context) (*client.Client, error) {
297-
return client.New(ctx, bc.ServerConfig.FullBuildkitEndpoint, client.WithCredentials(bc.ClientCertPath, bc.ClientKeyPath), client.WithServerConfig("", bc.ServerCAPath))
307+
return client.New(ctx, bc.FullBuildkitEndpoint, client.WithCredentials(bc.ClientCertPath, bc.ClientKeyPath), client.WithServerConfig("", bc.ServerCAPath))
298308

299309
})
300310
}

internal/cli/cmd/cluster/buildproxy.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ import (
3434
type ProxyStatus string
3535

3636
const (
37-
ProxyStatus_Starting ProxyStatus = "Starting"
38-
ProxyStatus_Running ProxyStatus = "Running"
39-
ProxyStatus_Failing ProxyStatus = "Failing"
40-
ProxyStatus_ServerSide ProxyStatus = "ServerSideProxy"
37+
ProxyStatus_Starting ProxyStatus = "Starting"
38+
ProxyStatus_Running ProxyStatus = "Running"
39+
ProxyStatus_Failing ProxyStatus = "Failing"
40+
ProxyStatus_ServerSide ProxyStatus = "ServerSideProxy"
41+
ProxyStatus_ServerSideUnreachable ProxyStatus = "ServerSideProxyUnreachable"
4142
)
4243

4344
const (
@@ -176,13 +177,14 @@ type proxyStatusDesc struct {
176177
}
177178

178179
type StatusData struct {
179-
Platform string
180-
Status ProxyStatus
181-
LastError string
182-
LogPath string
183-
LastInstanceID string
184-
LastUpdate time.Time
185-
Requests int
180+
Platform string
181+
IsServerSideProxy bool
182+
Status ProxyStatus
183+
LastError string
184+
LogPath string
185+
LastInstanceID string
186+
LastUpdate time.Time
187+
Requests int
186188
}
187189

188190
func (p *proxyStatusDesc) setLastInstanceID(builderID string) {

internal/cli/cmd/cluster/buildx.go

Lines changed: 105 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ const (
4646
BuildkitProxyPath = "buildkit/" + proxyDir
4747
)
4848

49+
var ErrBuildxNodeGroupNotFound = errors.New("buildx node group not found")
50+
var ErrIsNotRemoteDriver = errors.New("buildx node group does not have 'remote' driver")
51+
4952
func newSetupBuildxCmd() *cobra.Command {
5053
cmd := &cobra.Command{
5154
Use: "setup",
@@ -503,34 +506,23 @@ type ServerProxyEndpoint struct {
503506
Endpoint string
504507
}
505508

506-
func getServerSideProxyEndpoints(txn *store.Txn, name string) []ServerProxyEndpoint {
507-
var endpoints []ServerProxyEndpoint
509+
func isNamespaceBuildkitEndpoint(endpoint string) bool {
510+
return strings.Contains(endpoint, "namespaceapis.com")
511+
}
508512

509-
ng, err := txn.NodeGroupByName(name)
513+
func isServerSideProxy(txn *store.Txn, name string) bool {
514+
configs, err := readRemoteBuilderConfigsTxn(txn, name)
510515
if err != nil {
511-
return endpoints
516+
return false
512517
}
513518

514-
if ng.Driver != "remote" {
515-
return endpoints
516-
}
517-
518-
for _, node := range ng.Nodes {
519-
for _, plat := range node.Platforms {
520-
if strings.Contains(node.Endpoint, "namespaceapis.com") {
521-
endpoints = append(endpoints, ServerProxyEndpoint{
522-
Platform: plat.OS + "/" + plat.Architecture,
523-
Endpoint: node.Endpoint,
524-
})
525-
}
519+
for _, cfg := range configs {
520+
if isNamespaceBuildkitEndpoint(cfg.FullBuildkitEndpoint) {
521+
return true
526522
}
527523
}
528524

529-
return endpoints
530-
}
531-
532-
func isServerSideProxy(txn *store.Txn, name string) bool {
533-
return len(getServerSideProxyEndpoints(txn, name)) != 0
525+
return false
534526
}
535527

536528
func doClientSideProxyCleanup(ctx context.Context, state string, txn *store.Txn) error {
@@ -731,7 +723,7 @@ func newStatusBuildxCommand() *cobra.Command {
731723
return err
732724
}
733725

734-
sspDescs, err := determineServerSideProxyConfig(dockerCli, *name)
726+
sspDescs, err := determineServerSideProxyStatus(ctx, dockerCli, *name)
735727
if err != nil {
736728
return err
737729
}
@@ -765,12 +757,20 @@ func newStatusBuildxCommand() *cobra.Command {
765757
for _, desc := range descs {
766758
fmt.Fprintf(stdout, "Platform: %s\n", desc.Platform)
767759
fmt.Fprintf(stdout, " Status: %s\n", desc.Status)
768-
fmt.Fprintf(stdout, " Last Instance ID: %s\n", desc.LastInstanceID)
769-
fmt.Fprintf(stdout, " Last Update: %v\n", desc.LastUpdate)
770-
fmt.Fprintf(stdout, " Last Error: %v\n", desc.LastError)
771-
fmt.Fprintf(stdout, " Requests Handled: %v\n", desc.Requests)
772-
fmt.Fprintf(stdout, " Log Path: %v\n", desc.LogPath)
773-
fmt.Fprintf(stdout, "\n")
760+
if desc.IsServerSideProxy {
761+
if desc.LastError == "" {
762+
fmt.Fprintf(stdout, " Connectivity check successful\n")
763+
} else {
764+
fmt.Fprintf(stdout, " Connectivity error: %s\n", desc.LastError)
765+
}
766+
} else {
767+
fmt.Fprintf(stdout, " Last Instance ID: %s\n", desc.LastInstanceID)
768+
fmt.Fprintf(stdout, " Last Error: %v\n", desc.LastError)
769+
fmt.Fprintf(stdout, " Last Update: %v\n", desc.LastUpdate)
770+
fmt.Fprintf(stdout, " Requests Handled: %v\n", desc.Requests)
771+
fmt.Fprintf(stdout, " Log Path: %v\n", desc.LogPath)
772+
fmt.Fprintf(stdout, "\n")
773+
}
774774
}
775775
}
776776

@@ -780,21 +780,90 @@ func newStatusBuildxCommand() *cobra.Command {
780780
return cmd
781781
}
782782

783-
func determineServerSideProxyConfig(dockerCli *command.DockerCli, name string) ([]StatusData, error) {
784-
descs := []StatusData{}
783+
func readRemoteBuilderConfigs(dockerCli *command.DockerCli, name string) ([]BuilderConfig, error) {
784+
var res []BuilderConfig
785785

786786
err := withStore(dockerCli, func(txn *store.Txn) error {
787-
endpoints := getServerSideProxyEndpoints(txn, name)
788-
for _, e := range endpoints {
789-
descs = append(descs, StatusData{
790-
Platform: e.Platform,
791-
Status: ProxyStatus_ServerSide,
792-
})
787+
r, err := readRemoteBuilderConfigsTxn(txn, name)
788+
if err != nil {
789+
return err
793790
}
794791

792+
res = r
795793
return nil
796794
})
797795

796+
return res, err
797+
}
798+
799+
func readRemoteBuilderConfigsTxn(txn *store.Txn, name string) ([]BuilderConfig, error) {
800+
var configs []BuilderConfig
801+
802+
ng, err := txn.NodeGroupByName(name)
803+
if err != nil {
804+
if os.IsNotExist(errors.Cause(err)) {
805+
return configs, ErrBuildxNodeGroupNotFound
806+
}
807+
808+
return configs, fmt.Errorf("can not query buildx node group '%s': %v", name, err)
809+
}
810+
811+
if ng.Driver != "remote" {
812+
return configs, ErrIsNotRemoteDriver
813+
}
814+
815+
for _, node := range ng.Nodes {
816+
for _, plat := range node.Platforms {
817+
endpoint := BuilderConfig{
818+
Platform: plat.OS + "/" + plat.Architecture,
819+
Arch: plat.Architecture,
820+
FullBuildkitEndpoint: node.Endpoint,
821+
}
822+
823+
if node.DriverOpts != nil {
824+
endpoint.ServerCAPath = node.DriverOpts["cacert"]
825+
endpoint.ClientCertPath = node.DriverOpts["cert"]
826+
endpoint.ClientKeyPath = node.DriverOpts["key"]
827+
}
828+
829+
configs = append(configs, endpoint)
830+
}
831+
}
832+
833+
return configs, nil
834+
}
835+
836+
func determineServerSideProxyStatus(ctx context.Context, dockerCli *command.DockerCli, name string) ([]StatusData, error) {
837+
descs := []StatusData{}
838+
839+
configs, err := readRemoteBuilderConfigs(dockerCli, name)
840+
if err != nil {
841+
if err == ErrBuildxNodeGroupNotFound || err == ErrIsNotRemoteDriver {
842+
return nil, nil
843+
}
844+
845+
return nil, err
846+
}
847+
848+
for _, cfg := range configs {
849+
if !isNamespaceBuildkitEndpoint(cfg.FullBuildkitEndpoint) {
850+
continue
851+
}
852+
853+
status := StatusData{
854+
Platform: cfg.Platform,
855+
IsServerSideProxy: true,
856+
Status: ProxyStatus_ServerSide,
857+
}
858+
859+
if _, err := TestServerSideBuildxProxyConnectivity(ctx, cfg); err != nil {
860+
status.Status = ProxyStatus_ServerSideUnreachable
861+
status.LastError = err.Error()
862+
}
863+
864+
descs = append(descs, status)
865+
}
866+
798867
return descs, err
799868
}
800869

0 commit comments

Comments
 (0)