cmd/bicepCmd.go (144 lines of code) (raw):

// MIT License // // Copyright (c) Microsoft Corporation. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE package main import ( "context" "fmt" "os" "os/exec" "path/filepath" "strings" "github.com/Azure/mpf/pkg/domain" "github.com/Azure/mpf/pkg/infrastructure/ARMTemplateShared" "github.com/Azure/mpf/pkg/infrastructure/authorizationCheckers/ARMTemplateWhatIf" "github.com/Azure/mpf/pkg/infrastructure/mpfSharedUtils" resourceGroupManager "github.com/Azure/mpf/pkg/infrastructure/resourceGroupManager" sproleassignmentmanager "github.com/Azure/mpf/pkg/infrastructure/spRoleAssignmentManager" "github.com/Azure/mpf/pkg/usecase" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) var flgBicepFilePath string var flgBicepExecPath string // armCmd represents the arm command func NewBicepCommand() *cobra.Command { bicepCmd := &cobra.Command{ Use: "bicep", Short: "A brief description of your command", Long: `A longer description that spans multiple lines and likely contains examples and usage of using your command. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.`, Run: getMPFBicep, } bicepCmd.Flags().StringVarP(&flgResourceGroupNamePfx, "resourceGroupNamePfx", "", "testdeployrg", "Resource Group Name Prefix") bicepCmd.Flags().StringVarP(&flgDeploymentNamePfx, "deploymentNamePfx", "", "testDeploy", "Deployment Name Prefix") bicepCmd.Flags().StringVarP(&flgBicepFilePath, "bicepFilePath", "", "", "Path to bicep File") err := bicepCmd.MarkFlagRequired("bicepFilePath") if err != nil { log.Errorf("Error marking flag required for Bicep file path: %v\n", err) } bicepCmd.Flags().StringVarP(&flgParametersFilePath, "parametersFilePath", "", "", "Path to bicep Parameters File") err = bicepCmd.MarkFlagRequired("parametersFilePath") if err != nil { log.Errorf("Error marking flag required for Bicep parameters file path: %v\n", err) } bicepCmd.Flags().StringVarP(&flgBicepExecPath, "bicepExecPath", "", "", "Bicep Executable Path") err = bicepCmd.MarkFlagRequired("bicepExecPath") if err != nil { log.Errorf("Error marking flag required for Bicep executable path: %v\n", err) } bicepCmd.Flags().StringVarP(&flgLocation, "location", "", "eastus2", "Location") bicepCmd.Flags().BoolVarP(&flgSubscriptionScoped, "subscriptionScoped", "", false, "Is Deployment Subscription Scoped") // bicepCmd.Flags().BoolVarP(&flgFullDeployment, "fullDeployment", "", false, "Full Deployment") return bicepCmd } func getMPFBicep(cmd *cobra.Command, args []string) { setLogLevel() log.Info("Executing MPF for Bicep") log.Debugf("ResourceGroupNamePfx: %s\n", flgResourceGroupNamePfx) log.Debugf("DeploymentNamePfx: %s\n", flgDeploymentNamePfx) log.Infof("BicepFilePath: %s\n", flgBicepFilePath) log.Infof("ParametersFilePath: %s\n", flgParametersFilePath) log.Infof("BicepExecPath: %s\n", flgBicepExecPath) log.Infof("SubscriptionScoped: %t\n", flgSubscriptionScoped) log.Infof("Location: %s\n", flgLocation) // validate if template and parameters files exists if _, err := os.Stat(flgBicepFilePath); os.IsNotExist(err) { log.Fatal("Bicep File does not exist") } if _, err := os.Stat(flgBicepExecPath); os.IsNotExist(err) { log.Fatal("Bicep Executable does not exist") } if _, err := os.Stat(flgParametersFilePath); os.IsNotExist(err) { log.Fatal("Parameters File does not exist") } flgBicepExecPath, err := getAbsolutePath(flgBicepExecPath) if err != nil { log.Errorf("Error getting absolute path for bicep executable: %v\n", err) } flgBicepFilePath, err := getAbsolutePath(flgBicepFilePath) if err != nil { log.Errorf("Error getting absolute path for bicep file: %v\n", err) } flgParametersFilePath, err := getAbsolutePath(flgParametersFilePath) if err != nil { log.Errorf("Error getting absolute path for parameters file: %v\n", err) } armTemplatePath := strings.TrimSuffix(flgBicepFilePath, ".bicep") + ".json" bicepCmd := exec.Command(flgBicepExecPath, "build", flgBicepFilePath, "--outfile", armTemplatePath) bicepCmd.Dir = filepath.Dir(flgBicepFilePath) _, err = bicepCmd.CombinedOutput() if err != nil { log.Errorf("error running bicep build: %s", err) } log.Infoln("Bicep build successful, ARM Template created at:", armTemplatePath) ctx := context.Background() mpfConfig := getRootMPFConfig() mpfRG := domain.ResourceGroup{} mpfRG.ResourceGroupName = fmt.Sprintf("%s-%s", flgResourceGroupNamePfx, mpfSharedUtils.GenerateRandomString(7)) mpfRG.ResourceGroupResourceID = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s", flgSubscriptionID, mpfRG.ResourceGroupName) mpfRG.Location = flgLocation mpfConfig.ResourceGroup = mpfRG deploymentName := fmt.Sprintf("%s-%s", flgDeploymentNamePfx, mpfSharedUtils.GenerateRandomString(7)) armConfig := &ARMTemplateShared.ArmTemplateAdditionalConfig{ TemplateFilePath: armTemplatePath, ParametersFilePath: flgParametersFilePath, DeploymentName: deploymentName, SubscriptionScoped: flgSubscriptionScoped, Location: flgLocation, } var rgManager usecase.ResourceGroupManager var spRoleAssignmentManager usecase.ServicePrincipalRolemAssignmentManager rgManager = resourceGroupManager.NewResourceGroupManager(flgSubscriptionID) spRoleAssignmentManager = sproleassignmentmanager.NewSPRoleAssignmentManager(flgSubscriptionID) var deploymentAuthorizationCheckerCleaner usecase.DeploymentAuthorizationCheckerCleaner var mpfService *usecase.MPFService var initialPermissionsToAdd []string var permissionsToAddToResult []string deploymentAuthorizationCheckerCleaner = ARMTemplateWhatIf.NewARMTemplateWhatIfAuthorizationChecker(flgSubscriptionID, *armConfig) initialPermissionsToAdd = []string{"Microsoft.Resources/deployments/*", "Microsoft.Resources/subscriptions/operationresults/read"} permissionsToAddToResult = []string{"Microsoft.Resources/deployments/read", "Microsoft.Resources/deployments/write"} var autoCreateResourceGroup bool = true if flgSubscriptionScoped { autoCreateResourceGroup = false } mpfService = usecase.NewMPFService(ctx, rgManager, spRoleAssignmentManager, deploymentAuthorizationCheckerCleaner, mpfConfig, initialPermissionsToAdd, permissionsToAddToResult, true, false, autoCreateResourceGroup) mpfResult, err := mpfService.GetMinimumPermissionsRequired() if err != nil { log.Fatal(err) } log.Infoln("Deleting Generated ARM Template file...") // delete generated ARM template file err = os.Remove(armTemplatePath) if err != nil { log.Errorf("Error deleting Generated ARM template file: %v\n", err) } // log.Infof("Displaying MPF Result: %v\n", mpfResult) log.Infof("Show Detailed Output: %t\n", flgShowDetailedOutput) log.Infof("JSON Output: %t\n", flgJSONOutput) log.Infof("Subscription ID: %s\n", mpfConfig.SubscriptionID) displayOptions := getDislayOptions(flgShowDetailedOutput, flgJSONOutput, mpfConfig.SubscriptionID) if err != nil { if len(mpfResult.RequiredPermissions) > 0 { fmt.Println("Error occurred while getting minimum permissions required. However, some permissions were identified prior to the error.") displayResult(mpfResult, displayOptions) } log.Fatal(err) } displayResult(mpfResult, displayOptions) }