Example #1
0
// listPorts returns the slice of port ranges (network.PortRange)
// that this machine has opened. The returned list does not contain
// the "initial port ranges" (i.e. the port ranges every instance
// shoud have opened).
func (azInstance *azureInstance) listPorts(api *gwacl.ManagementAPI) ([]network.PortRange, error) {
	endpoints, err := api.ListRoleEndpoints(&gwacl.ListRoleEndpointsRequest{
		ServiceName:    azInstance.serviceName(),
		DeploymentName: azInstance.deploymentName,
		RoleName:       azInstance.roleName,
	})
	if err != nil {
		return nil, err
	}
	ports := convertAndFilterEndpoints(endpoints, azInstance.environ, azInstance.maskStateServerPorts)
	return ports, nil
}
Example #2
0
// newHostedService creates a hosted service.  It will make up a unique name,
// starting with the given prefix.
func newHostedService(azure *gwacl.ManagementAPI, prefix, affinityGroupName, label string) (*gwacl.HostedService, error) {
	var err error
	var createdService *gwacl.CreateHostedService
	for tries := 10; tries > 0 && err == nil && createdService == nil; tries-- {
		createdService, err = attemptCreateService(azure, prefix, affinityGroupName, label)
	}
	if err != nil {
		return nil, errors.Annotate(err, "could not create hosted service")
	}
	if createdService == nil {
		return nil, fmt.Errorf("could not come up with a unique hosted service name - is your randomizer initialized?")
	}
	return azure.GetHostedServiceProperties(createdService.ServiceName, true)
}
Example #3
0
// attemptCreateService tries to create a new hosted service on Azure, with a
// name it chooses (based on the given prefix), but recognizes that the name
// may not be available.  If the name is not available, it does not treat that
// as an error but just returns nil.
func attemptCreateService(azure *gwacl.ManagementAPI, prefix string, affinityGroupName string, location string) (*gwacl.CreateHostedService, error) {
	var err error
	name := gwacl.MakeRandomHostedServiceName(prefix)
	err = azure.CheckHostedServiceNameAvailability(name)
	if err != nil {
		// The calling function should retry.
		return nil, nil
	}
	req := gwacl.NewCreateHostedServiceWithLocation(name, name, location)
	req.AffinityGroup = affinityGroupName
	err = azure.AddHostedService(req)
	if err != nil {
		return nil, err
	}
	return req, nil
}
Example #4
0
// attemptCreateService tries to create a new hosted service on Azure, with a
// name it chooses (based on the given prefix), but recognizes that the name
// may not be available.  If the name is not available, it does not treat that
// as an error but just returns nil.
func attemptCreateService(azure *gwacl.ManagementAPI, prefix string, affinityGroupName string) (*gwacl.CreateHostedService, error) {
	name := gwacl.MakeRandomHostedServiceName(prefix)
	req := gwacl.NewCreateHostedServiceWithLocation(name, name, serviceLocation)
	req.AffinityGroup = affinityGroupName
	err := azure.AddHostedService(req)
	azErr, isAzureError := err.(*gwacl.AzureError)
	if isAzureError && azErr.HTTPStatus == http.StatusConflict {
		// Conflict.  As far as we can see, this only happens if the
		// name was already in use.  It's still dangerous to assume
		// that we know it can't be anything else, but there's nothing
		// else in the error that we can use for closer identifcation.
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	return req, nil
}
Example #5
0
// closeEndpoints closes the endpoints in the Azure deployment.
func (azInstance *azureInstance) closeEndpoints(api *gwacl.ManagementAPI, portRanges []network.PortRange) error {
	request := &gwacl.RemoveRoleEndpointsRequest{
		ServiceName:    azInstance.serviceName(),
		DeploymentName: azInstance.deploymentName,
		RoleName:       azInstance.roleName,
	}
	for _, portRange := range portRanges {
		name := fmt.Sprintf("%s%d-%d", portRange.Protocol, portRange.FromPort, portRange.ToPort)
		for port := portRange.FromPort; port <= portRange.ToPort; port++ {
			request.InputEndpoints = append(request.InputEndpoints, gwacl.InputEndpoint{
				LocalPort:                   port,
				Name:                        fmt.Sprintf("%s_%d", name, port),
				Port:                        port,
				Protocol:                    portRange.Protocol,
				LoadBalancedEndpointSetName: name,
			})
		}
	}
	return api.RemoveRoleEndpoints(request)
}
Example #6
0
// openEndpoints opens the endpoints in the Azure deployment.
func (azInstance *azureInstance) openEndpoints(api *gwacl.ManagementAPI, portRanges []network.PortRange) error {
	request := &gwacl.AddRoleEndpointsRequest{
		ServiceName:    azInstance.serviceName(),
		DeploymentName: azInstance.deploymentName,
		RoleName:       azInstance.roleName,
	}
	for _, portRange := range portRanges {
		name := fmt.Sprintf("%s%d-%d", portRange.Protocol, portRange.FromPort, portRange.ToPort)
		for port := portRange.FromPort; port <= portRange.ToPort; port++ {
			endpoint := gwacl.InputEndpoint{
				LocalPort: port,
				Name:      fmt.Sprintf("%s_range_%d", name, port),
				Port:      port,
				Protocol:  portRange.Protocol,
			}
			if azInstance.supportsLoadBalancing() {
				probePort := port
				if strings.ToUpper(endpoint.Protocol) == "UDP" {
					// Load balancing needs a TCP port to probe, or an HTTP
					// server port & path to query. For UDP, we just use the
					// machine's SSH agent port to test machine liveness.
					//
					// It probably doesn't make sense to load balance most UDP
					// protocols transparently, but that's an application level
					// concern.
					probePort = 22
				}
				endpoint.LoadBalancedEndpointSetName = name
				endpoint.LoadBalancerProbe = &gwacl.LoadBalancerProbe{
					Port:     probePort,
					Protocol: "TCP",
				}
			}
			request.InputEndpoints = append(request.InputEndpoints, endpoint)
		}
	}
	return api.AddRoleEndpoints(request)
}
Example #7
0
// createInstance creates all of the Azure entities necessary for a
// new instance. This includes Cloud Service, Deployment and Role.
//
// If serviceName is non-empty, then createInstance will assign to
// the Cloud Service with that name. Otherwise, a new Cloud Service
// will be created.
func (env *azureEnviron) createInstance(azure *gwacl.ManagementAPI, role *gwacl.Role, serviceName string, stateServer bool) (resultInst instance.Instance, resultErr error) {
	var inst instance.Instance
	defer func() {
		if inst != nil && resultErr != nil {
			if err := env.StopInstances(inst.Id()); err != nil {
				// Failure upon failure. Log it, but return the original error.
				logger.Errorf("error releasing failed instance: %v", err)
			}
		}
	}()
	var err error
	var service *gwacl.HostedService
	if serviceName != "" {
		logger.Debugf("creating instance in existing cloud service %q", serviceName)
		service, err = azure.GetHostedServiceProperties(serviceName, true)
	} else {
		logger.Debugf("creating instance in new cloud service")
		// If we're creating a cloud service for state servers,
		// we will want to open additional ports. We need to
		// record this against the cloud service, so we use a
		// special label for the purpose.
		var label string
		if stateServer {
			label = stateServerLabel
		}
		service, err = newHostedService(azure, env.getEnvPrefix(), env.getAffinityGroupName(), label)
	}
	if err != nil {
		return nil, err
	}
	if len(service.Deployments) == 0 {
		// This is a newly created cloud service, so we
		// should destroy it if anything below fails.
		defer func() {
			if resultErr != nil {
				azure.DeleteHostedService(service.ServiceName)
				// Destroying the hosted service destroys the instance,
				// so ensure StopInstances isn't called.
				inst = nil
			}
		}()
		// Create an initial deployment.
		deployment := gwacl.NewDeploymentForCreateVMDeployment(
			deploymentNameV2(service.ServiceName),
			deploymentSlot,
			deploymentNameV2(service.ServiceName),
			[]gwacl.Role{*role},
			env.getVirtualNetworkName(),
		)
		if err := azure.AddDeployment(deployment, service.ServiceName); err != nil {
			return nil, errors.Annotate(err, "error creating VM deployment")
		}
		service.Deployments = append(service.Deployments, *deployment)
	} else {
		// Update the deployment.
		deployment := &service.Deployments[0]
		if err := azure.AddRole(&gwacl.AddRoleRequest{
			ServiceName:      service.ServiceName,
			DeploymentName:   deployment.Name,
			PersistentVMRole: (*gwacl.PersistentVMRole)(role),
		}); err != nil {
			return nil, err
		}
		deployment.RoleList = append(deployment.RoleList, *role)
	}
	return env.getInstance(service, role.RoleName)
}