Beispiel #1
0
    public static async Async.Task <OneFuzzResult <T> > ParseRequest <T>(HttpRequestData req)
    {
        Exception?exception = null;

        try {
            var t = await req.ReadFromJsonAsync <T>();

            if (t != null)
            {
                var validationContext = new ValidationContext(t);
                var validationResults = new List <ValidationResult>();
                if (Validator.TryValidateObject(t, validationContext, validationResults, true))
                {
                    return(OneFuzzResult.Ok(t));
                }
                else
                {
                    return(new Error(
                               Code: ErrorCode.INVALID_REQUEST,
                               Errors: validationResults.Select(vr => vr.ToString()).ToArray()));
                }
            }
        } catch (Exception e) {
            exception = e;
        }

        if (exception != null)
        {
            return(OneFuzzResult <T> .Error(ConvertError(exception)));
        }
        return(OneFuzzResult <T> .Error(
                   ErrorCode.INVALID_REQUEST,
                   $"Failed to deserialize message into type: {typeof(T)} - {await req.ReadAsStringAsync()}"
                   ));
    }
Beispiel #2
0
    private async Async.Task <OneFuzzResult <DiagnosticSettingsResource> > SetupAutoScaleDiagnostics(string autoScaleResourceUri, string autoScaleResourceName, string logAnalyticsWorkspaceId)
    {
        var logSettings = new LogSettings(true)
        {
            Category = "allLogs", RetentionPolicy = new RetentionPolicy(true, 30)
        };

        try {
            var parameters = new DiagnosticSettingsData {
                WorkspaceId = logAnalyticsWorkspaceId
            };
            parameters.Logs.Add(logSettings);
            var diagnostics = await _context.Creds.GetResourceGroupResource().GetDiagnosticSettings().CreateOrUpdateAsync(WaitUntil.Completed, $"{autoScaleResourceName}-diagnostics", parameters);

            if (diagnostics != null && diagnostics.HasValue)
            {
                return(OneFuzzResult.Ok(diagnostics.Value));
            }
            return(OneFuzzResult <DiagnosticSettingsResource> .Error(
                       ErrorCode.UNABLE_TO_CREATE,
                       $"The resulting diagnostics settings resource was null when attempting to create for {autoScaleResourceUri}"
                       ));
        } catch (Exception ex) {
            _logTracer.Exception(ex);
            return(OneFuzzResult <DiagnosticSettingsResource> .Error(
                       ErrorCode.UNABLE_TO_CREATE,
                       $"unable to setup diagnostics for auto-scale resource: {autoScaleResourceUri}"
                       ));
        }
    }
Beispiel #3
0
    private async Async.Task <OneFuzzResult <AutoscaleSettingResource> > CreateAutoScaleResourceFor(Guid resourceId, string location, AutoscaleProfile profile)
    {
        _logTracer.Info($"Creating auto-scale resource for: {resourceId}");

        var resourceGroup = _context.Creds.GetBaseResourceGroup();
        var subscription  = _context.Creds.GetSubscription();

        var scalesetUri = $"/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachineScaleSets/{resourceId}";
        var parameters  = new AutoscaleSettingData(location, new[] { profile })
        {
            TargetResourceId = scalesetUri,
            Enabled          = true
        };

        try {
            var autoScaleResource = await _context.Creds.GetResourceGroupResource().GetAutoscaleSettings()
                                    .CreateOrUpdateAsync(WaitUntil.Completed, Guid.NewGuid().ToString(), parameters);

            if (autoScaleResource != null && autoScaleResource.HasValue)
            {
                _logTracer.Info($"Successfully created auto scale resource {autoScaleResource.Id} for {resourceId}");
                return(OneFuzzResult <AutoscaleSettingResource> .Ok(autoScaleResource.Value));
            }

            return(OneFuzzResult <AutoscaleSettingResource> .Error(
                       ErrorCode.UNABLE_TO_CREATE,
                       $"Could not get auto scale resource value after creating for {resourceId}"
                       ));
        } catch (Exception ex) {
            _logTracer.Exception(ex);
            return(OneFuzzResult <AutoscaleSettingResource> .Error(
                       ErrorCode.UNABLE_TO_CREATE,
                       $"unable to create auto scale resource for resource: {resourceId} with profile: {profile}"));
        }
    }
Beispiel #4
0
    public async Async.Task <OneFuzzResult <VirtualMachineScaleSetVmResource> > GetInstanceVm(Guid name, Guid vmId)
    {
        _log.Info($"get instance ID for scaleset node: {name}:{vmId}");
        var scaleSet = GetVmssResource(name);

        try {
            await foreach (var vm in scaleSet.GetVirtualMachineScaleSetVms().AsAsyncEnumerable())
            {
                var response = await vm.GetAsync();

                if (!response.Value.HasData)
                {
                    return(OneFuzzResult <VirtualMachineScaleSetVmResource> .Error(ErrorCode.UNABLE_TO_FIND, $"failed to get vm data"));
                }

                if (response.Value.Data.VmId == vmId.ToString())
                {
                    return(OneFuzzResult <VirtualMachineScaleSetVmResource> .Ok(response));
                }
            }
        } catch (Exception ex) when(ex is RequestFailedException || ex is CloudException)
        {
            _log.Exception(ex, $"unable to find vm instance: {name}:{vmId}");
            return(OneFuzzResult <VirtualMachineScaleSetVmResource> .Error(ErrorCode.UNABLE_TO_FIND, $"unable to find vm instance: {name}:{vmId}"));
        }
        return(OneFuzzResult <VirtualMachineScaleSetVmResource> .Error(ErrorCode.UNABLE_TO_FIND, $"unable to find scaleset machine: {name}:{vmId}"));
    }
Beispiel #5
0
    public async Task <OneFuzzResult <ProxyForward> > UpdateOrCreate(string region, Guid scalesetId, Guid machineId, int dstPort, int duration)
    {
        var privateIp = await _context.IpOperations.GetScalesetInstanceIp(scalesetId, machineId);

        if (privateIp == null)
        {
            return(OneFuzzResult <ProxyForward> .Error(ErrorCode.UNABLE_TO_PORT_FORWARD, "no private ip for node"));
        }

        var entries =
            await this.SearchForward(scalesetId : scalesetId, region : region, machineId : machineId, dstPort : dstPort).ToListAsync();

        var firstEntry = entries.FirstOrDefault();

        if (firstEntry != null)
        {
            var updated = firstEntry with {
                EndTime = DateTimeOffset.UtcNow + TimeSpan.FromHours(duration)
            };
            await this.Update(updated);

            return(OneFuzzResult.Ok(updated));
        }

        var exisiting = entries.Select(x => x.Port).ToHashSet();

        foreach (var port in PORT_RANGES)
        {
            if (exisiting.Contains(port))
            {
                continue;
            }

            var entry = new ProxyForward(
                Region: region,
                Port: port,
                ScalesetId: scalesetId,
                MachineId: machineId,
                DstIp: privateIp,
                DstPort: dstPort,
                EndTime: DateTimeOffset.UtcNow + TimeSpan.FromHours(duration),
                ProxyId: null
                );

            var result = await Insert(entry);

            if (!result.IsOk)
            {
                _logTracer.Info($"port is already used {entry}");
            }

            return(OneFuzzResult.Ok(entry));
        }

        return(OneFuzzResult <ProxyForward> .Error(ErrorCode.UNABLE_TO_PORT_FORWARD, "all forward ports used"));
    }
Beispiel #6
0
    public async Task <OneFuzzResult <bool> > AddExtensions(Vm vm, Dictionary <string, VirtualMachineExtensionData> extensions)
    {
        var status   = new List <string>();
        var toCreate = new List <KeyValuePair <string, VirtualMachineExtensionData> >();

        foreach (var extensionConfig in extensions)
        {
            var extensionName = extensionConfig.Key;
            var extensionData = extensionConfig.Value;

            var extension = await GetExtension(vm.Name, extensionName);

            if (extension != null)
            {
                _logTracer.Info(
                    $"vm extension state: {vm.Name} - {extensionName} - {extension.ProvisioningState}"
                    );
                status.Add(extension.ProvisioningState);
            }
            else
            {
                toCreate.Add(extensionConfig);
            }
        }

        if (toCreate.Any())
        {
            foreach (var config in toCreate)
            {
                await CreateExtension(vm.Name, config.Key, config.Value);
            }
        }
        else
        {
            if (status.All(s => string.Equals(s, "Succeeded", StringComparison.Ordinal)))
            {
                return(OneFuzzResult <bool> .Ok(true));
            }
            else if (status.Any(s => string.Equals(s, "Failed", StringComparison.Ordinal)))
            {
                return(OneFuzzResult <bool> .Error(
                           ErrorCode.VM_CREATE_FAILED,
                           "failed to launch extension"
                           ));
            }
            else if (!(status.Contains("Creating") || status.Contains("Updating")))
            {
                _logTracer.Error($"vm agent - unknown state {vm.Name}: {JsonConvert.SerializeObject(status)}");
            }
        }

        return(OneFuzzResult <bool> .Ok(false));
    }
Beispiel #7
0
    public async Async.Task <OneFuzzResult <VirtualMachineScaleSetData> > CheckCanUpdate(Guid name)
    {
        var vmss = await GetVmss(name);

        if (vmss is null)
        {
            return(OneFuzzResult <VirtualMachineScaleSetData> .Error(ErrorCode.UNABLE_TO_UPDATE, $"vmss not found: {name}"));
        }
        if (vmss.ProvisioningState == "Updating")
        {
            return(OneFuzzResult <VirtualMachineScaleSetData> .Error(ErrorCode.UNABLE_TO_UPDATE, $"vmss is in updating state: {name}"));
        }
        return(OneFuzzResult <VirtualMachineScaleSetData> .Ok(vmss));
    }
Beispiel #8
0
    public async Async.Task <OneFuzzResult <Pool> > GetByName(string poolName)
    {
        var pools = QueryAsync(filter: $"PartitionKey eq '{poolName}'");

        if (pools == null || await pools.CountAsync() == 0)
        {
            return(OneFuzzResult <Pool> .Error(ErrorCode.INVALID_REQUEST, "unable to find pool"));
        }

        if (await pools.CountAsync() != 1)
        {
            return(OneFuzzResult <Pool> .Error(ErrorCode.INVALID_REQUEST, "error identifying pool"));
        }

        return(OneFuzzResult <Pool> .Ok(await pools.SingleAsync()));
    }
Beispiel #9
0
    public async Task <OneFuzzResult <bool> > AddSshPublicKey(Node node, string publicKey)
    {
        if (publicKey == null)
        {
            throw new ArgumentNullException(nameof(publicKey));
        }

        if (node.ScalesetId == null)
        {
            return(OneFuzzResult <bool> .Error(ErrorCode.INVALID_REQUEST, "only able to add ssh keys to scaleset nodes"));
        }

        var key = publicKey.EndsWith('\n') ? publicKey : $"{publicKey}\n";

        await SendMessage(node, new NodeCommand { AddSshKey = new NodeCommandAddSshKey(key) });

        return(OneFuzzResult.Ok <bool>(true));
    }
Beispiel #10
0
    public async Async.Task <OneFuzzResult <Pool> > GetByName(PoolName poolName)
    {
        var pools = QueryAsync(Query.PartitionKey(poolName.String));

        var result = await pools.ToListAsync();

        if (result.Count == 0)
        {
            return(OneFuzzResult <Pool> .Error(ErrorCode.INVALID_REQUEST, "unable to find pool"));
        }

        if (result.Count != 1)
        {
            return(OneFuzzResult <Pool> .Error(ErrorCode.INVALID_REQUEST, "error identifying pool"));
        }

        return(OneFuzzResult <Pool> .Ok(result.Single()));
    }
Beispiel #11
0
    public async Async.Task <OneFuzzResult <Pool> > GetById(Guid poolId)
    {
        var pools = QueryAsync(Query.RowKey(poolId.ToString()));

        var result = await pools.ToListAsync();

        if (result.Count == 0)
        {
            return(OneFuzzResult <Pool> .Error(ErrorCode.INVALID_REQUEST, "unable to find pool"));
        }

        if (result.Count != 1)
        {
            return(OneFuzzResult <Pool> .Error(ErrorCode.INVALID_REQUEST, "error identifying pool"));
        }

        return(OneFuzzResult <Pool> .Ok(result.Single()));
    }
Beispiel #12
0
    public static async Async.Task <OneFuzzResult <T> > ParseUri <T>(HttpRequestData req)
    {
        var query = System.Web.HttpUtility.ParseQueryString(req.Url.Query);
        var doc   = new JsonObject();

        foreach (var key in query.AllKeys.WhereNotNull())
        {
            doc[key] = JsonValue.Create(query[key]);
        }

        try {
            var result = doc.Deserialize <T>(EntityConverter.GetJsonSerializerOptions());
            return(result switch {
                null => OneFuzzResult <T> .Error(
                    ErrorCode.INVALID_REQUEST,
                    $"Failed to deserialize message into type: {typeof(T)} - {await req.ReadAsStringAsync()}"
                    ),
                var r => OneFuzzResult <T> .Ok(r),
            });
        } catch (JsonException exception) {
Beispiel #13
0
    static OneFuzzResult <Scaleset> TrySetIdentity(Scaleset scaleset, VirtualMachineScaleSetData vmss)
    {
        if (scaleset.ClientObjectId is null)
        {
            return(OneFuzzResult.Ok(scaleset));
        }

        if (vmss.Identity is not null && vmss.Identity.UserAssignedIdentities is not null)
        {
            if (vmss.Identity.UserAssignedIdentities.Count != 1)
            {
                return(OneFuzzResult <Scaleset> .Error(ErrorCode.VM_CREATE_FAILED, "The scaleset is expected to have exactly 1 user assigned identity"));
            }
            var principalId = vmss.Identity.UserAssignedIdentities.First().Value.PrincipalId;
            if (principalId is null)
            {
                return(OneFuzzResult <Scaleset> .Error(ErrorCode.VM_CREATE_FAILED, "The scaleset principal ID is null"));
            }
            return(OneFuzzResult <Scaleset> .Ok(scaleset with {
                ClientObjectId = principalId
            }));
        }
Beispiel #14
0
    public OneFuzzResult <AutoscaleSettingResource?> GetAutoscaleSettings(Guid vmss)
    {
        _logTracer.Info($"Checking scaleset {vmss} for existing auto scale resource");
        var monitorManagementClient = _context.LogAnalytics.GetMonitorManagementClient();
        var resourceGroup           = _context.Creds.GetBaseResourceGroup();

        try {
            var autoscale = _context.Creds.GetResourceGroupResource().GetAutoscaleSettings()
                            .ToEnumerable()
                            .Where(autoScale => autoScale.Data.TargetResourceId.EndsWith(vmss.ToString()))
                            .FirstOrDefault();

            if (autoscale != null)
            {
                _logTracer.Info($"Found autoscale settings for {vmss}");
                return(OneFuzzResult.Ok <AutoscaleSettingResource?>(autoscale));
            }
        } catch (Exception ex) {
            _logTracer.Exception(ex);
            return(OneFuzzResult <AutoscaleSettingResource?> .Error(ErrorCode.INVALID_CONFIGURATION, $"Failed to check if scaleset {vmss} already has an autoscale resource"));
        }
        return(OneFuzzResult.Ok <AutoscaleSettingResource?>(null));
    }
Beispiel #15
0
    public static async Async.Task <OneFuzzResult <T> > ParseRequest <T>(HttpRequestData req)
    {
        Exception?exception = null;

        try {
            var t = await req.ReadFromJsonAsync <T>();

            if (t != null)
            {
                return(OneFuzzResult <T> .Ok(t));
            }
        } catch (Exception e) {
            exception = e;
        }

        if (exception != null)
        {
            return(OneFuzzResult <T> .Error(ConvertError(exception)));
        }
        return(OneFuzzResult <T> .Error(
                   ErrorCode.INVALID_REQUEST,
                   $"Failed to deserialize message into type: {typeof(T)} - {await req.ReadAsStringAsync()}"
                   ));
    }
Beispiel #16
0
    public async Task <OneFuzzResult <Os> > GetOs(string region, string image)
    {
        string?name = null;

        try {
            var parsed = _context.Creds.ParseResourceId(image);
            parsed = await _context.Creds.GetData(parsed);

            if (string.Equals(parsed.Id.ResourceType, "galleries", StringComparison.OrdinalIgnoreCase))
            {
                try {
                    // This is not _exactly_ the same as the python code
                    // because in C# we don't have access to child_name_1
                    var gallery = await _context.Creds.GetResourceGroupResource().GetGalleries().GetAsync(
                        parsed.Data.Name
                        );

                    var galleryImage = gallery.Value.GetGalleryImages()
                                       .ToEnumerable()
                                       .Where(galleryImage => string.Equals(galleryImage.Id, parsed.Id, StringComparison.OrdinalIgnoreCase))
                                       .First();

                    galleryImage = await galleryImage.GetAsync();

                    name = galleryImage.Data?.OSType?.ToString().ToLowerInvariant() !;
                } catch (Exception ex) when(
                    ex is RequestFailedException ||
                    ex is NullReferenceException
                    )
                {
                    return(OneFuzzResult <Os> .Error(
                               ErrorCode.INVALID_IMAGE,
                               ex.ToString()
                               ));
                }
            }
            else
            {
                try {
                    name = (await _context.Creds.GetResourceGroupResource().GetImages().GetAsync(
                                parsed.Data.Name
                                )).Value.Data.StorageProfile.OSDisk.OSType.ToString().ToLowerInvariant();
                } catch (Exception ex) when(
                    ex is RequestFailedException ||
                    ex is NullReferenceException
                    )
                {
                    return(OneFuzzResult <Os> .Error(
                               ErrorCode.INVALID_IMAGE,
                               ex.ToString()
                               ));
                }
            }
        } catch (FormatException) {
            var imageInfo = IImageOperations.GetImageInfo(image);
            try {
                var subscription = await _context.Creds.ArmClient.GetDefaultSubscriptionAsync();

                string version;
                if (string.Equals(imageInfo.Version, "latest", StringComparison.Ordinal))
                {
                    version =
                        (await subscription.GetVirtualMachineImagesAsync(
                             region,
                             imageInfo.Publisher,
                             imageInfo.Offer,
                             imageInfo.Sku,
                             top: 1
                             ).FirstAsync()).Name;
                }
                else
                {
                    version = imageInfo.Version;
                }

                name = (await subscription.GetVirtualMachineImageAsync(
                            region,
                            imageInfo.Publisher,
                            imageInfo.Offer,
                            imageInfo.Sku
                            , version
                            )).Value.OSDiskImageOperatingSystem.ToString().ToLower();
            } catch (RequestFailedException ex) {
                return(OneFuzzResult <Os> .Error(
                           ErrorCode.INVALID_IMAGE,
                           ex.ToString()
                           ));
            }
        }

        if (name != null)
        {
            name = string.Concat(name[0].ToString().ToUpper(), name.AsSpan(1));
            if (Enum.TryParse(name, out Os os))
            {
                return(OneFuzzResult <Os> .Ok(os));
            }
        }

        return(OneFuzzResult <Os> .Error(
                   ErrorCode.INVALID_IMAGE,
                   $"Unexpected image os type: {name}"
                   ));
    }
Beispiel #17
0
    public async Async.Task RequiresAdmin(string method)
    {
        // config must be found
        await Context.InsertAll(
            new InstanceConfig(Context.ServiceConfiguration.OneFuzzInstanceName !));

        // must be a user to auth
        var auth = new TestEndpointAuthorization(RequestType.User, Logger, Context);

        // override the found user credentials
        var userInfo = new UserInfo(ApplicationId: Guid.NewGuid(), ObjectId: Guid.NewGuid(), "upn");

        Context.UserCredentials = new TestUserCredentials(Logger, Context.ConfigOperations, OneFuzzResult <UserInfo> .Ok(userInfo));

        var req    = new NodeGet(MachineId: _machineId);
        var func   = new NodeFunction(Logger, auth, Context);
        var result = await func.Run(TestHttpRequestData.FromJson(method, req));

        Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode);

        var err = BodyAs <Error>(result);

        Assert.Equal(ErrorCode.UNAUTHORIZED, err.Code);
        Assert.Contains("pool modification disabled", err.Errors?.Single());
    }
Beispiel #18
0
 public static OneFuzzResult <T> Ok <T>(T val) => OneFuzzResult <T> .Ok(val);