func main()

in cmd/appgw-ingress/main.go [67:243]


func main() {
	// Log output is buffered... Calling Flush before exiting guarantees all log output is written.
	klog.InitFlags(nil)
	defer klog.Flush()
	if err := flags.Parse(os.Args); err != nil {
		klog.Fatal("Error parsing command line arguments:", err)
	}

	env := environment.GetEnv()
	verbosity = to.IntPtr(getVerbosity(*verbosity, env.VerbosityLevel))
	if *versionInfo {
		version.PrintVersionAndExit()
	}

	// get the details from Cloud Provider Config
	// Reference: https://github.com/kubernetes-sigs/cloud-provider-azure/blob/master/docs/cloud-provider-config.md#cloud-provider-config
	cpConfig, err := azure.NewCloudProviderConfig(env.CloudProviderConfigLocation)
	if err != nil {
		klog.Infof("Unable to load cloud provider config '%s'. Error: %s", env.CloudProviderConfigLocation, err.Error())
	}

	env.Consolidate(cpConfig)

	// Workaround for "ERROR: logging before flag.Parse"
	// See: https://github.com/kubernetes/kubernetes/issues/17162#issuecomment-225596212
	_ = flag.CommandLine.Parse([]string{})
	_ = flag.Lookup("logtostderr").Value.Set("true")
	_ = flag.Set("v", strconv.Itoa(*verbosity))

	apiConfig := getKubeClientConfig()
	scheme, err := k8s.NewScheme()
	if err != nil {
		klog.Fatalf("Failed to create k8s scheme: %v", err)
	}

	ctrlClient, err := ctrl_client.New(apiConfig, ctrl_client.Options{
		Scheme: scheme,
	})
	if err != nil {
		klog.Fatalf("Failed to create controller-runtime client: %v", err)
	}

	if *cleanupOEC {
		if err := cni.CleanupOverlayExtensionConfigs(ctrlClient, env.AGICPodNamespace, env.AddonMode); err != nil {
			klog.Fatalf("Failed to cleanup OverlayExtensionConfig resources: %v", err)
		}
		klog.Info("Successfully cleaned up OverlayExtensionConfig resources")
		return
	}

	kubeClient := kubernetes.NewForConfigOrDie(apiConfig)
	k8scontext.IsNetworkingV1PackageSupported = k8scontext.SupportsNetworkingPackage(kubeClient)
	k8scontext.IsInMultiClusterMode = env.MultiClusterMode
	crdClient := versioned.NewForConfigOrDie(apiConfig)
	istioCrdClient := istio.NewForConfigOrDie(apiConfig)
	multiClusterCrdClient := multicluster.NewForConfigOrDie(apiConfig)
	recorder := getEventRecorder(kubeClient, env.IngressClassControllerName)
	namespaces := getNamespacesToWatch(env.WatchNamespace)
	metricStore := metricstore.NewMetricStore(env)
	metricStore.Start()
	k8sContext := k8scontext.NewContext(kubeClient, crdClient, multiClusterCrdClient, istioCrdClient, namespaces, *resyncPeriod, metricStore, env)
	agicPod := k8sContext.GetAGICPod(env)

	if err := environment.ValidateEnv(env); err != nil {
		errorLine := fmt.Sprint("Error while initializing values from environment. Please check helm configuration for missing values: ", err)
		if agicPod != nil {
			recorder.Event(agicPod, v1.EventTypeWarning, events.ReasonValidatonError, errorLine)
		}
		klog.Fatal(errorLine)
	}

	uniqueUserAgentSuffix := utils.RandStringRunes(10)
	if agicPod != nil {
		uniqueUserAgentSuffix = agicPod.Name
	}
	klog.Infof("Using User Agent Suffix='%s' when communicating with ARM", uniqueUserAgentSuffix)

	azClient := azure.NewAzClient(azure.SubscriptionID(env.SubscriptionID), azure.ResourceGroup(env.ResourceGroupName), azure.ResourceName(env.AppGwName), uniqueUserAgentSuffix, env.ClientID)
	appGwIdentifier := appgw.Identifier{
		SubscriptionID: env.SubscriptionID,
		ResourceGroup:  env.ResourceGroupName,
		AppGwName:      env.AppGwName,
	}

	klog.V(3).Infof("Application Gateway Details: Subscription=\"%s\" Resource Group=\"%s\" Name=\"%s\"", env.SubscriptionID, env.ResourceGroupName, env.AppGwName)

	var authorizer autorest.Authorizer
	if authorizer, err = azure.GetAuthorizerWithRetry(env.AuthLocation, env.UseManagedIdentityForPod, cpConfig, maxRetryCount, retryPause); err != nil {
		errorLine := fmt.Sprint("Failed obtaining authentication token for Azure Resource Manager: ", err)
		if agicPod != nil {
			recorder.Event(agicPod, v1.EventTypeWarning, events.ReasonARMAuthFailure, errorLine)
		}
		klog.Fatal(errorLine)
	} else {
		azClient.SetAuthorizer(authorizer)
	}

	// Check if Application Gateway exists/have get access
	// If AGIC's service principal or managed identity doesn't have read access to the Application Gateway's resource group,
	// then AGIC can't read it's role assignments to look for the needed permission.
	// Instead we perform a simple GET request to check both that the Application Gateway exists as well as implicitly make sure that AGIC has read access to it.
	err = azClient.WaitForGetAccessOnGateway(maxRetryCount)
	if err != nil {
		if controllererrors.IsErrorCode(err, controllererrors.ErrorApplicationGatewayNotFound) && env.EnableDeployAppGateway {
			if env.AppGwSubnetID != "" {
				err = azClient.DeployGatewayWithSubnet(env.AppGwSubnetID, env.AppGwSkuName)
			} else if cpConfig != nil {
				err = azClient.DeployGatewayWithVnet(azure.ResourceGroup(cpConfig.VNetResourceGroup), azure.ResourceName(cpConfig.VNetName), azure.ResourceName(env.AppGwSubnetName), env.AppGwSubnetPrefix, env.AppGwSkuName)
			}

			if err != nil {
				errorLine := fmt.Sprint("Failed in deploying Application Gateway", err)
				if agicPod != nil {
					recorder.Event(agicPod, v1.EventTypeWarning, events.ReasonFailedDeployingAppGw, errorLine)
				}
				klog.Fatal(errorLine)
			}
		} else {
			errorLine := fmt.Sprint("Failed getting Application Gateway: ", err)
			if agicPod != nil {
				recorder.Event(agicPod, v1.EventTypeWarning, events.ReasonARMAuthFailure, errorLine)
			}
			klog.Fatal(errorLine)
		}
	}

	// namespace validations
	if err := validateNamespaces(namespaces, kubeClient); err != nil {
		klog.Fatal(err) // side-effect: will panic on non-existent namespace
	}
	if len(namespaces) == 0 {
		klog.Info("Ingress Controller will observe all namespaces.")
	} else {
		klog.Info("Ingress Controller will observe the following namespaces:", strings.Join(namespaces, ","))
	}

	// fatal config validations
	appGw, _ := azClient.GetGateway()
	if _, exists := allowedSkus[appGw.Sku.Tier]; !exists {
		errorLine := fmt.Sprintf("App Gateway SKU Tier %s is not supported by AGIC version %s; (v0.10.0 supports App Gwy v1)", appGw.Sku.Tier, appgw.GetVersion())
		if agicPod != nil {
			recorder.Event(agicPod, v1.EventTypeWarning, events.UnsupportedAppGatewaySKUTier, errorLine)
		}

		// Slow down the cycling of the AGIC pod.
		time.Sleep(5 * time.Second)
		klog.Fatal(errorLine)
	}

	cniReconciler := cni.NewReconciler(azClient, ctrlClient, recorder, cpConfig, appGw, agicPod, env.AGICPodNamespace, env.AddonMode)

	// create a new agic controller
	appGwIngressController := controller.NewAppGwIngressController(azClient, appGwIdentifier, k8sContext, recorder, metricStore, cniReconciler, agicPod, env.HostedOnUnderlay)

	// initialize the http server and start it
	httpServer := httpserver.NewHTTPServer(
		appGwIngressController,
		metricStore,
		env.HTTPServicePort)
	httpServer.Start()

	if err := appGwIngressController.Start(env); err != nil {
		errorLine := fmt.Sprint("Could not start AGIC: ", err)
		if agicPod != nil {
			recorder.Event(agicPod, v1.EventTypeWarning, events.ReasonARMAuthFailure, errorLine)
		}
		klog.Fatal(errorLine)
	}

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
	<-sigChan

	appGwIngressController.Stop()
	httpServer.Stop()
	klog.Info("Goodbye!")
}