github.com/vmware/govmomi@v0.37.1/govc/storage/policy/info.go (about)

     1  /*
     2  Copyright (c) 2020-2023 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package policy
    18  
    19  import (
    20  	"context"
    21  	"flag"
    22  	"fmt"
    23  	"io"
    24  	"os"
    25  	"strings"
    26  	"text/tabwriter"
    27  
    28  	"github.com/vmware/govmomi/govc/cli"
    29  	"github.com/vmware/govmomi/govc/flags"
    30  	"github.com/vmware/govmomi/pbm/types"
    31  	"github.com/vmware/govmomi/property"
    32  	"github.com/vmware/govmomi/view"
    33  	vim "github.com/vmware/govmomi/vim25/types"
    34  )
    35  
    36  type info struct {
    37  	*flags.ClientFlag
    38  	*flags.OutputFlag
    39  
    40  	compliance bool
    41  	storage    bool
    42  }
    43  
    44  func init() {
    45  	cli.Register("storage.policy.info", &info{})
    46  }
    47  
    48  func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) {
    49  	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
    50  	cmd.ClientFlag.Register(ctx, f)
    51  
    52  	cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
    53  	cmd.OutputFlag.Register(ctx, f)
    54  
    55  	f.BoolVar(&cmd.storage, "s", false, "Check Storage Compatibility")
    56  	f.BoolVar(&cmd.compliance, "c", false, "Check VM Compliance")
    57  }
    58  
    59  func (cmd *info) Process(ctx context.Context) error {
    60  	if err := cmd.ClientFlag.Process(ctx); err != nil {
    61  		return err
    62  	}
    63  	if err := cmd.OutputFlag.Process(ctx); err != nil {
    64  		return err
    65  	}
    66  	return nil
    67  }
    68  
    69  func (cmd *info) Usage() string {
    70  	return "[NAME]"
    71  }
    72  
    73  func (cmd *info) Description() string {
    74  	return `VM Storage Policy info.
    75  
    76  Examples:
    77    govc storage.policy.info
    78    govc storage.policy.info "vSAN Default Storage Policy"
    79    govc storage.policy.info -c -s`
    80  }
    81  
    82  type Policy struct {
    83  	Profile              types.BasePbmProfile `json:"profile"`
    84  	CompliantVM          []string             `json:"compliantVM"`
    85  	CompatibleDatastores []string             `json:"compatibleDatastores"`
    86  }
    87  
    88  type infoResult struct {
    89  	Policies []Policy `json:"policies"`
    90  	cmd      *info
    91  }
    92  
    93  func (r *infoResult) Write(w io.Writer) error {
    94  	tw := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0)
    95  
    96  	for _, policy := range r.Policies {
    97  		p := policy.Profile.GetPbmProfile()
    98  		_, _ = fmt.Fprintf(tw, "Name:\t%s\n", p.Name)
    99  		_, _ = fmt.Fprintf(tw, "  ID:\t%s\n", p.ProfileId.UniqueId)
   100  		_, _ = fmt.Fprintf(tw, "  Description:\t%s\n", p.Description)
   101  		if r.cmd.compliance {
   102  			_, _ = fmt.Fprintf(tw, "  Compliant VMs:\t%s\n", strings.Join(policy.CompliantVM, ","))
   103  		}
   104  		if r.cmd.storage {
   105  			_, _ = fmt.Fprintf(tw, "  Compatible Datastores:\t%s\n", strings.Join(policy.CompatibleDatastores, ","))
   106  		}
   107  	}
   108  
   109  	return tw.Flush()
   110  }
   111  
   112  func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error {
   113  	vc, err := cmd.Client()
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	c, err := cmd.PbmClient()
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	profiles, err := ListProfiles(ctx, c, f.Arg(0))
   124  	if err != nil {
   125  		return err
   126  	}
   127  
   128  	pc := property.DefaultCollector(vc)
   129  	kind := []string{"Datastore"}
   130  	m := view.NewManager(vc)
   131  
   132  	v, err := m.CreateContainerView(ctx, vc.ServiceContent.RootFolder, kind, true)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	var content []vim.ObjectContent
   138  	err = v.Retrieve(ctx, kind, []string{"name"}, &content)
   139  	_ = v.Destroy(ctx)
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	dsmap := make(map[string]string)
   145  	var hubs []types.PbmPlacementHub
   146  
   147  	for _, ds := range content {
   148  		hubs = append(hubs, types.PbmPlacementHub{
   149  			HubType: ds.Obj.Type,
   150  			HubId:   ds.Obj.Value,
   151  		})
   152  		dsmap[ds.Obj.Value] = ds.PropSet[0].Val.(string)
   153  	}
   154  
   155  	var policies []Policy
   156  
   157  	for _, profile := range profiles {
   158  		p := profile.GetPbmProfile()
   159  
   160  		policy := Policy{
   161  			Profile: profile,
   162  		}
   163  
   164  		if cmd.compliance {
   165  			entities, err := c.QueryAssociatedEntity(ctx, p.ProfileId, string(types.PbmObjectTypeVirtualMachine))
   166  			if err != nil {
   167  				return err
   168  			}
   169  
   170  			if len(entities) == 0 {
   171  				continue
   172  			}
   173  
   174  			res, err := c.FetchComplianceResult(ctx, entities)
   175  			if err != nil {
   176  				return err
   177  			}
   178  
   179  			var refs []vim.ManagedObjectReference
   180  			for _, r := range res {
   181  				if r.ComplianceStatus == string(types.PbmComplianceStatusCompliant) {
   182  					refs = append(refs, vim.ManagedObjectReference{Type: "VirtualMachine", Value: r.Entity.Key})
   183  				}
   184  			}
   185  
   186  			err = pc.Retrieve(ctx, refs, []string{"name"}, &content)
   187  			if err != nil {
   188  				return err
   189  			}
   190  
   191  			for _, c := range content {
   192  				policy.CompliantVM = append(policy.CompliantVM, c.PropSet[0].Val.(string))
   193  			}
   194  		}
   195  
   196  		if cmd.storage {
   197  			req := []types.BasePbmPlacementRequirement{
   198  				&types.PbmPlacementCapabilityProfileRequirement{
   199  					ProfileId: p.ProfileId,
   200  				},
   201  			}
   202  
   203  			res, err := c.CheckRequirements(ctx, hubs, nil, req)
   204  			if err != nil {
   205  				return err
   206  			}
   207  
   208  			for _, hub := range res.CompatibleDatastores() {
   209  				policy.CompatibleDatastores = append(policy.CompatibleDatastores, dsmap[hub.HubId])
   210  			}
   211  		}
   212  
   213  		policies = append(policies, policy)
   214  	}
   215  
   216  	return cmd.WriteResult(&infoResult{policies, cmd})
   217  }