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!")
}